Guest User

variadic.inc

a guest
May 29th, 2017
279
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Pawn 11.25 KB | None | 0 0
  1. // Variadic functions in PAWN.
  2.  
  3. /*
  4.     native GetVariadicAddress(argument);
  5.     native GetVariadicString(address, dest[] = "", size = sizeof(dest));
  6.     native SetVariadicString(address, str[]);
  7.  
  8.     native PushArguments(start, end);
  9.     native VariadicFormat(output[], len, const str[], bool:pack = false);
  10.     native CallLocalVariadic(function[], const specifiers[]);
  11.     native CallRemoteVariadic(function[], const specifiers[]);
  12.  
  13.     native IsArgumentPacked(address);
  14.     native GetVariadicLength(address);
  15.     native UnpackArgument(address);
  16.  
  17.     native DeleteArgument(address);
  18.     native PopArguments();
  19. */
  20.  
  21. #define var%0(%1) \
  22.     variadic%0(%1)
  23.  
  24. #define variadic%0(%1) \
  25.     stock%0(%1, {Float,_}:...)
  26.  
  27. #define @variadic[%0] \
  28.     #VARIADIC_FORMAT_%0
  29.  
  30. #if !defined MAX_VARIADIC_STRING
  31.     #define MAX_VARIADIC_STRING (512)
  32. #endif
  33.  
  34. static stock
  35.     g_PushedAddress[24];
  36.  
  37. native org_format(output[], len, const str[], {Float,_}:...) = format;
  38. native org_CallLocalFunction(func[], specifiers[], {Float,_}:...) = CallLocalFunction;
  39. native org_CallRemoteFunction(func[], specifiers[], {Float,_}:...) = CallRemoteFunction;
  40.  
  41. forward _variadic_fix_();
  42. public _variadic_fix_()
  43. {
  44.     strcat("", "");
  45.     strlen("");
  46.     strdel("", 0, 1);
  47.     strunpack("", "");
  48.     strpack("", "");
  49.     ispacked("");
  50.     memcpy("", "", 0, 0, 0);
  51.     CallLocalFunction("", "");
  52.     CallRemoteFunction("", "");
  53.  
  54.     format("", 1, "");
  55.     org_format("", 1, "");
  56.  
  57.     org_CallLocalFunction("", "");
  58.     org_CallRemoteFunction("", "");
  59. }
  60.  
  61. stock GetVariadicAddress(argument)
  62. {
  63.     #emit LOAD.S.pri argument
  64.     #emit SHL.C.pri 2
  65.  
  66.     #emit LOAD.S.alt 0
  67.     #emit ADD
  68.  
  69.     #emit ADD.C 12
  70.     #emit LOAD.I
  71.  
  72.     #emit RETN
  73.  
  74.     return 0;
  75. }
  76.  
  77. stock GetVariadicString(address, dest[] = "", size = sizeof(dest))
  78. {
  79.     new string[MAX_VARIADIC_STRING];
  80.  
  81.     #emit LOAD.S.pri address
  82.     //#emit LOAD.I
  83.  
  84.     #emit PUSH.C 512
  85.     #emit PUSH.pri
  86.     #emit PUSH.adr string
  87.  
  88.     #emit PUSH.C 12
  89.     #emit SYSREQ.C strunpack
  90.  
  91.     #emit STACK 16
  92.  
  93.     if (numargs() > 1)
  94.     {
  95.         dest[0] = '\0';
  96.         strcat(dest, string, size);
  97.     }
  98.     return string;
  99. }
  100.  
  101. stock SetVariadicString(address, str[])
  102. {
  103.     new length = 0;
  104.  
  105.     #emit LOAD.S.pri address
  106.  
  107.     #emit PUSH.pri
  108.     #emit PUSH.C 4
  109.     #emit LOAD.S.pri length
  110.  
  111.     #emit SYSREQ.C strlen
  112.     #emit STOR.S.pri length
  113.  
  114.     #emit STACK 8
  115.  
  116.     if (length > 0)
  117.     {
  118.         #emit PUSH.adr length
  119.         #emit PUSH.C 0
  120.         #emit PUSH.S address
  121.  
  122.         #emit PUSH.C 12
  123.         #emit SYSREQ.C strdel
  124.  
  125.         #emit STACK 16
  126.     }
  127.     #emit PUSH.C 512
  128.     #emit PUSH.S str
  129.     #emit PUSH.S address
  130.  
  131.     #emit PUSH.C 12
  132.     #emit SYSREQ.C strcat
  133.  
  134.     #emit STACK 16
  135.     return 1;
  136. }
  137.  
  138. stock PushArguments(start, end)
  139. {
  140.     new idx, addr;
  141.  
  142.     for (new i = 0; i < sizeof(g_PushedAddress); i ++) {
  143.         g_PushedAddress[i] = -1;
  144.     }
  145.     while (start != end)
  146.     {
  147.         #emit LOAD.S.pri start
  148.         #emit SMUL.C 4
  149.  
  150.         #emit LOAD.S.alt 0
  151.         #emit ADD
  152.  
  153.         #emit ADD.C 12
  154.         #emit LOAD.I
  155.         #emit STOR.S.pri addr
  156.  
  157.         #emit CONST.pri g_PushedAddress
  158.         #emit LOAD.S.alt idx
  159.         #emit SHL.C.alt 2
  160.         #emit ADD
  161.         #emit LOAD.I
  162.         #emit LOAD.S.pri addr
  163.         #emit STOR.I
  164.  
  165.         idx++;
  166.         start++;
  167.     }
  168.     return 1;
  169. }
  170.  
  171. stock VariadicFormat(output[], len, const str[], bool:pack = false)
  172. {
  173.     new i, string[MAX_VARIADIC_STRING * 4], args = 12;
  174.  
  175.     for (i = sizeof(g_PushedAddress); --i >= 0; )
  176.     {
  177.         if (g_PushedAddress[i] != -1)
  178.         {
  179.             #emit CONST.pri g_PushedAddress
  180.             #emit LOAD.S.alt i
  181.             #emit SHL.C.alt 2
  182.             #emit ADD
  183.             #emit LOAD.I
  184.             #emit PUSH.pri
  185.  
  186.             args += 4;
  187.         }
  188.     }
  189.     #emit PUSH.S str
  190.     #emit PUSH.S len
  191.     #emit PUSH.adr string
  192.  
  193.     #emit PUSH.S args
  194.     #emit SYSREQ.C format
  195.  
  196.     #emit STACK 16
  197.  
  198.     for (i = 0; i < sizeof(g_PushedAddress); i ++)
  199.     {
  200.         if (g_PushedAddress[i] != -1)
  201.         {
  202.             #emit CONST.pri g_PushedAddress
  203.             #emit LOAD.S.alt i
  204.             #emit SHL.c.alt 2
  205.             #emit ADD
  206.             #emit LOAD.I
  207.             #emit CONST.pri 1
  208.             #emit NEG
  209.             #emit STOR.I
  210.             #emit STACK 4
  211.         }
  212.     }
  213.     if (pack || output[0] > 255) {
  214.         strpack(output, string, len);
  215.     }
  216.     else strcat((output[0] = '\0', output), string, len);
  217.     return 1;
  218. }
  219.  
  220. stock CallLocalVariadic(function[], const specifiers[])
  221. {
  222.     new i, args = 8;
  223.  
  224.     for (i = sizeof(g_PushedAddress); --i >= 0; )
  225.     {
  226.         if (g_PushedAddress[i] != -1)
  227.         {
  228.             #emit CONST.pri g_PushedAddress
  229.             #emit LOAD.S.alt i
  230.             #emit SHL.C.alt 2
  231.             #emit ADD
  232.             #emit LOAD.I
  233.             #emit PUSH.pri
  234.  
  235.             args += 4;
  236.         }
  237.     }
  238.     #emit PUSH.S specifiers
  239.     #emit PUSH.S function
  240.  
  241.     #emit PUSH.S args
  242.     #emit SYSREQ.C CallLocalFunction
  243.  
  244.     #emit STACK 12
  245.  
  246.     for (i = 0; i < sizeof(g_PushedAddress); i ++)
  247.     {
  248.         if (g_PushedAddress[i] != -1)
  249.         {
  250.             #emit CONST.pri g_PushedAddress
  251.             #emit LOAD.S.alt i
  252.             #emit SHL.c.alt 2
  253.             #emit ADD
  254.             #emit LOAD.I
  255.             #emit CONST.pri 1
  256.             #emit NEG
  257.             #emit STOR.I
  258.             #emit STACK 4
  259.         }
  260.     }
  261.     return 1;
  262. }
  263.  
  264. stock CallRemoteVariadic(function[], const specifiers[])
  265. {
  266.     new i, args = 8;
  267.  
  268.     for (i = sizeof(g_PushedAddress); --i >= 0; )
  269.     {
  270.         if (g_PushedAddress[i] != -1)
  271.         {
  272.             #emit CONST.pri g_PushedAddress
  273.             #emit LOAD.S.alt i
  274.             #emit SHL.C.alt 2
  275.             #emit ADD
  276.             #emit LOAD.I
  277.             #emit PUSH.pri
  278.  
  279.             args += 4;
  280.         }
  281.     }
  282.     #emit PUSH.S specifiers
  283.     #emit PUSH.S function
  284.  
  285.     #emit PUSH.S args
  286.     #emit SYSREQ.C CallRemoteFunction
  287.  
  288.     #emit STACK 12
  289.  
  290.     for (i = 0; i < sizeof(g_PushedAddress); i ++)
  291.     {
  292.         if (g_PushedAddress[i] != -1)
  293.         {
  294.             #emit CONST.pri g_PushedAddress
  295.             #emit LOAD.S.alt i
  296.             #emit SHL.c.alt 2
  297.             #emit ADD
  298.             #emit LOAD.I
  299.             #emit CONST.pri 1
  300.             #emit NEG
  301.             #emit STOR.I
  302.             #emit STACK 4
  303.         }
  304.     }
  305.     return 1;
  306. }
  307.  
  308. stock DeleteArgument(address)
  309. {
  310.     new length;
  311.  
  312.     #emit PUSH.S address
  313.     #emit PUSH.C 4
  314.  
  315.     #emit LOAD.S.pri length
  316.     #emit SYSREQ.C strlen
  317.  
  318.     #emit STOR.S.pri length
  319.     #emit STACK 8
  320.  
  321.     #emit PUSH.alt
  322.     #emit PUSH.C 0
  323.     #emit PUSH.S address
  324.     #emit PUSH.C 12
  325.  
  326.     #emit SYSREQ.C strdel
  327.     #emit STACK 16
  328.  
  329.     return 1;
  330. }
  331.  
  332. stock PopArguments()
  333. {
  334.     for (new i = 0; i < sizeof(g_PushedAddress); i ++) {
  335.         if (g_PushedAddress[i] != -1) g_PushedAddress[i] = -1;
  336.     }
  337.     return 1;
  338. }
  339.  
  340. stock IsArgumentPacked(address)
  341. {
  342.     new result;
  343.  
  344.     #emit PUSH.S address
  345.     #emit PUSH.C 4
  346.  
  347.     #emit LOAD.S.pri result
  348.     #emit SYSREQ.C ispacked
  349.  
  350.     #emit STOR.S.pri result
  351.     #emit STACK 8
  352.  
  353.     return result;
  354. }
  355.  
  356. stock GetVariadicLength(address)
  357. {
  358.     new length;
  359.  
  360.     #emit PUSH.S address
  361.     #emit PUSH.C 4
  362.  
  363.     #emit LOAD.S.pri length
  364.     #emit SYSREQ.C strlen
  365.  
  366.     #emit STOR.S.pri length
  367.     #emit STACK 8
  368.  
  369.     return length;
  370. }
  371.  
  372. stock var_Format(output[], len, const str[], {Float,_}:...)
  373. {
  374.     new
  375.         start,
  376.         end,
  377.         argument,
  378.         string[128],
  379.         args = numargs() * 4;
  380.  
  381.     GetVariadicString(GetVariadicAddress(3), string, sizeof(string));
  382.     if (!strfind(string, "VARIADIC_FORMAT_", false))
  383.     {
  384.         start = strval(string[16]);
  385.  
  386.         #emit LOAD.S.pri 0
  387.         #emit ADD.C 8
  388.  
  389.         #emit LOAD.I
  390.         #emit STOR.S.pri args
  391.  
  392.         argument = (args / 4);
  393.  
  394.         while (--argument >= start)
  395.         {
  396.             #emit LOAD.S.pri argument
  397.             #emit SMUL.C 4
  398.  
  399.             #emit LOAD.S.alt 0
  400.             #emit ADD
  401.  
  402.             #emit ADD.C 12
  403.             #emit LOAD.I
  404.             #emit PUSH.pri
  405.         }
  406.         #emit LOAD.S.pri args
  407.         #emit ADD.C 12
  408.         #emit STOR.S.pri args
  409.  
  410.         #emit PUSH.S str
  411.         #emit PUSH.S len
  412.         #emit PUSH.S output
  413.  
  414.         #emit PUSH.S args
  415.         #emit SYSREQ.C org_format
  416.  
  417.         #emit STACK 16
  418.  
  419.         for (argument = (args / 4) - 4; argument >= start; argument --)
  420.         {
  421.             #emit STACK 4
  422.         }
  423.     }
  424.     else
  425.     {
  426.         #emit ADDR.PRI str
  427.         #emit STOR.S.pri start
  428.  
  429.         for (end = start + (args - 12); end > start; end -= 4)
  430.         {
  431.             #emit LOAD.S.pri end
  432.             #emit LOAD.I
  433.             #emit PUSH.pri
  434.         }
  435.         #emit PUSH.S str
  436.         #emit PUSH.S len
  437.         #emit PUSH.S output
  438.  
  439.         #emit PUSH.S args
  440.         #emit SYSREQ.C org_format
  441.  
  442.         #emit STACK 16
  443.  
  444.         for (end = start + (args - 12); end > start; end -= 4)
  445.         {
  446.             #emit STACK 4
  447.         }
  448.     }
  449.     return 1;
  450. }
  451.  
  452. stock var_CallLocalFunction(func[], const specifiers[], {Float,_}:...)
  453. {
  454.     new
  455.         start,
  456.         end,
  457.         argument,
  458.         string[128],
  459.         args = numargs() * 4;
  460.  
  461.     GetVariadicString(GetVariadicAddress(2), string, sizeof(string));
  462.     if (!strfind(string, "VARIADIC_FORMAT_", false))
  463.     {
  464.         start = strval(string[16]);
  465.  
  466.         #emit LOAD.S.pri 0
  467.         #emit ADD.C 8
  468.  
  469.         #emit LOAD.I
  470.         #emit STOR.S.pri args
  471.  
  472.         argument = (args / 4);
  473.  
  474.         while (--argument >= start)
  475.         {
  476.             #emit LOAD.S.pri argument
  477.             #emit SMUL.C 4
  478.  
  479.             #emit LOAD.S.alt 0
  480.             #emit ADD
  481.  
  482.             #emit ADD.C 12
  483.             #emit LOAD.I
  484.             #emit PUSH.pri
  485.         }
  486.         #emit LOAD.S.pri args
  487.         #emit ADD.C 8
  488.         #emit STOR.S.pri args
  489.  
  490.         #emit PUSH.S specifiers
  491.         #emit PUSH.S func
  492.  
  493.         #emit PUSH.S args
  494.         #emit SYSREQ.C org_CallLocalFunction
  495.  
  496.         #emit STACK 12
  497.  
  498.         for (argument = (args / 4) - 3; argument >= start; argument --)
  499.         {
  500.             #emit STACK 4
  501.         }
  502.     }
  503.     else
  504.     {
  505.         #emit ADDR.PRI specifiers
  506.         #emit STOR.S.pri start
  507.  
  508.         for (end = start + (args - 8); end > start; end -= 4)
  509.         {
  510.             #emit LOAD.S.pri end
  511.             #emit LOAD.I
  512.             #emit PUSH.pri
  513.         }
  514.         #emit PUSH.S specifiers
  515.         #emit PUSH.S func
  516.  
  517.         #emit PUSH.S args
  518.         #emit SYSREQ.C org_CallLocalFunction
  519.  
  520.         #emit STACK 12
  521.  
  522.         for (end = start + (args - 8); end > start; end -= 4)
  523.         {
  524.             #emit STACK 4
  525.         }
  526.     }
  527.     return 1;
  528. }
  529.  
  530. stock var_CallRemoteFunction(func[], const specifiers[], {Float,_}:...)
  531. {
  532.     new
  533.         start,
  534.         end,
  535.         argument,
  536.         string[128],
  537.         args = numargs() * 4;
  538.  
  539.     GetVariadicString(GetVariadicAddress(2), string, sizeof(string));
  540.     if (!strfind(string, "VARIADIC_FORMAT_", false))
  541.     {
  542.         start = strval(string[16]);
  543.  
  544.         #emit LOAD.S.pri 0
  545.         #emit ADD.C 8
  546.  
  547.         #emit LOAD.I
  548.         #emit STOR.S.pri args
  549.  
  550.         argument = (args / 4);
  551.  
  552.         while (--argument >= start)
  553.         {
  554.             #emit LOAD.S.pri argument
  555.             #emit SMUL.C 4
  556.  
  557.             #emit LOAD.S.alt 0
  558.             #emit ADD
  559.  
  560.             #emit ADD.C 12
  561.             #emit LOAD.I
  562.             #emit PUSH.pri
  563.         }
  564.         #emit LOAD.S.pri args
  565.         #emit ADD.C 8
  566.         #emit STOR.S.pri args
  567.  
  568.         #emit PUSH.S specifiers
  569.         #emit PUSH.S func
  570.  
  571.         #emit PUSH.S args
  572.         #emit SYSREQ.C org_CallRemoteFunction
  573.  
  574.         #emit STACK 12
  575.  
  576.         for (argument = (args / 4) - 3; argument >= start; argument --)
  577.         {
  578.             #emit STACK 4
  579.         }
  580.     }
  581.     else
  582.     {
  583.         #emit ADDR.PRI specifiers
  584.         #emit STOR.S.pri start
  585.  
  586.         for (end = start + (args - 8); end > start; end -= 4)
  587.         {
  588.             #emit LOAD.S.pri end
  589.             #emit LOAD.I
  590.             #emit PUSH.pri
  591.         }
  592.         #emit PUSH.S specifiers
  593.         #emit PUSH.S func
  594.  
  595.         #emit PUSH.S args
  596.         #emit SYSREQ.C org_CallRemoteFunction
  597.  
  598.         #emit STACK 12
  599.  
  600.         for (end = start + (args - 8); end > start; end -= 4)
  601.         {
  602.             #emit STACK 4
  603.         }
  604.     }
  605.     return 1;
  606. }
  607.  
  608. #if defined _ALS_format
  609.     #undef format
  610. #else
  611.     #define _ALS_format
  612. #endif
  613.  
  614. #if defined _ALS_CallLocalFunction
  615.     #undef CallLocalFunction
  616. #else
  617.     #define _ALS_CallLocalFunction
  618. #endif
  619.  
  620. #if defined _ALS_CallRemoteFunction
  621.     #undef CallRemoteFunction
  622. #else
  623.     #define _ALS_CallRemoteFunction
  624. #endif
  625.  
  626. #define format(%0) \
  627.     (var_Format(%0))
  628.    
  629. #define CallLocalFunction(%0) \
  630.     (var_CallLocalFunction(%0))
  631.  
  632. #define CallRemoteFunction(%0) \
  633.     (var_CallRemoteFunction(%0))
Advertisement
Add Comment
Please, Sign In to add comment