Y_Less

sscanf.cpp

Dec 12th, 2012
291
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 31.19 KB | None | 0 0
  1. /*  
  2.  *  Version: MPL 1.1
  3.  *  
  4.  *  The contents of this file are subject to the Mozilla Public License Version
  5.  *  1.1 (the "License"); you may not use this file except in compliance with
  6.  *  the License. You may obtain a copy of the License at
  7.  *  http://www.mozilla.org/MPL/
  8.  *  
  9.  *  Software distributed under the License is distributed on an "AS IS" basis,
  10.  *  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  *  for the specific language governing rights and limitations under the
  12.  *  License.
  13.  *  
  14.  *  The Original Code is the sscanf 2.0 SA:MP plugin.
  15.  *  
  16.  *  The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  17.  *  Portions created by the Initial Developer are Copyright (C) 2010
  18.  *  the Initial Developer. All Rights Reserved.
  19.  *  
  20.  *  Contributor(s):
  21.  *
  22.  *  SA:MP team - plugin framework.
  23.  *  
  24.  *  Special Thanks to:
  25.  *  
  26.  *  SA:MP Team past, present and future
  27.  */
  28.  
  29. #include <malloc.h>
  30. #include <string.h>
  31.  
  32. #include "sscanf.h"
  33. #include "specifiers.h"
  34. #include "utils.h"
  35. #include "data.h"
  36. #include "array.h"
  37. #include "enum.h"
  38.  
  39. #include "SDK/amx/amx.h"
  40. #include "SDK/plugincommon.h"
  41.  
  42. //----------------------------------------------------------
  43.  
  44. logprintf_t
  45.     logprintf;
  46.  
  47. AMX_NATIVE
  48.     SetPlayerName;
  49.  
  50. //GetServer_t
  51. //  GetServer;
  52.  
  53. extern void *
  54.     pAMXFunctions;
  55.  
  56. //extern int
  57. //  g_iServerVersion;
  58.  
  59. extern unsigned int
  60.     g_iTrueMax,
  61.     g_iInvalid,
  62.     g_iMaxPlayerName;
  63.  
  64. extern int *
  65.     g_iConnected;
  66.  
  67. extern int *
  68.     g_iNPC;
  69.  
  70. extern char *
  71.     g_szPlayerNames;
  72.  
  73. //extern char
  74. //  ** g_pServer;
  75.  
  76. #define SAVE_VALUE(m)       \
  77.     if (doSave)             \
  78.         amx_GetAddr(amx, params[paramPos++], &cptr), *cptr = m
  79.  
  80. #define SAVE_VALUE_F(m)     \
  81.     if (doSave) {           \
  82.         float f = (float)m; \
  83.         amx_GetAddr(amx, params[paramPos++], &cptr), *cptr = amx_ftoc(f); }
  84.  
  85. // Based on amx_StrParam but using 0 length strings.  This can't be inline as
  86. // it uses alloca - it could be written to use malloc instead, but that would
  87. // require memory free code all over the place!
  88. #define STR_PARAM(amx,param,result)                                                          \
  89.     do {                                                                                     \
  90.         cell * amx_cstr_; int amx_length_;                                                   \
  91.         amx_GetAddr((amx), (param), &amx_cstr_);                                             \
  92.         amx_StrLen(amx_cstr_, &amx_length_);                                                 \
  93.         if (amx_length_ > 0) {                                                               \
  94.             if (((result) = (char *)alloca((amx_length_ + 1) * sizeof (*(result)))) != NULL) \
  95.                 amx_GetString((result), amx_cstr_, sizeof (*(result)) > 1, amx_length_ + 1); \
  96.             else {                                                                           \
  97.                 logprintf("sscanf error: Unable to allocate memory.");                       \
  98.                 return SSCANF_FAIL_RETURN; } }                                               \
  99.         else (result) = ""; }                                                                \
  100.     while (false)
  101.  
  102. // Macros for the regular values.
  103. #define DO(m,n)                  \
  104.     {m b;                        \
  105.     if (Do##n(&string, &b)) {    \
  106.         SAVE_VALUE((cell)b);     \
  107.         break; }                 \
  108.     return SSCANF_FAIL_RETURN; }
  109.  
  110. #define DOV(m,n)                 \
  111.     {m b;                        \
  112.     Do##n(&string, &b);          \
  113.     SAVE_VALUE((cell)b); }
  114.  
  115. #define DOF(m,n)                 \
  116.     {m b;                        \
  117.     if (Do##n(&string, &b)) {    \
  118.         SAVE_VALUE_F(b)          \
  119.         break; }                 \
  120.     return SSCANF_FAIL_RETURN; }
  121.  
  122. // Macros for the default values.  None of these have ifs as the return value
  123. // of GetReturnDefault is always true - we don't penalise users for the
  124. // mistakes of the coder - they will get warning messages if they get the
  125. // format wrong, and I don't know of any mistkes which aren't warned about
  126. // (admittedly a silly statement as if I did I would have fixed them).
  127. #define DE(m,n)                  \
  128.     {m b;                        \
  129.     Do##n##D(&format, &b);       \
  130.     SAVE_VALUE((cell)b);         \
  131.     break; }
  132.  
  133. #define DEF(m,n)                 \
  134.     {m b;                        \
  135.     Do##n##D(&format, &b);       \
  136.     SAVE_VALUE_F(b)              \
  137.     break; }
  138.  
  139. // Macros for the default values in the middle of a string so you can do:
  140. //
  141. // sscanf("hello, , 10", "p<,>sI(42)i", str, var0, var1);
  142. //
  143. // Note that optional parameters in the middle of a string only work with
  144. // explicit (i.e. not whitespace) delimiters.
  145. #define DX(m,n)                  \
  146.     if (IsDelimiter(*string)) {  \
  147.         m b;                     \
  148.         Do##n##D(&format, &b);   \
  149.         SAVE_VALUE((cell)b);     \
  150.         break; }                 \
  151.     SkipDefault(&format);
  152.  
  153. #define DXF(m,n)                 \
  154.     if (IsDelimiter(*string)) {  \
  155.         m b;                     \
  156.         Do##n##D(&format, &b);   \
  157.         SAVE_VALUE_F(b)          \
  158.         break; }                 \
  159.     SkipDefault(&format);
  160.  
  161. bool
  162.     DoK(AMX * amx, char ** defaults, char ** input, cell * cptr, bool optional);
  163.  
  164. // native sscanf(const data[], const format[], (Float,_}:...);
  165. static cell AMX_NATIVE_CALL
  166.     n_sscanf(AMX * amx, cell * params)
  167. {
  168.     if (g_iTrueMax == 0)
  169.     {
  170.         logprintf("sscanf error: System not initialised.");
  171.         return SSCANF_FAIL_RETURN;
  172.     }
  173.     // Friendly note, the most complex set of specifier additions is:
  174.     //
  175.     //  A<i>(10, 11)[5]
  176.     //
  177.     // In that exact order - type, default, size.  It's very opposite to how
  178.     // it's done in code, where you would do the eqivalent to:
  179.     //
  180.     //  <i>[5] = {10, 11}
  181.     //
  182.     // But this method is vastly simpler to parse in this context!  Technically
  183.     // you can, due to legacy support for 'p', do:
  184.     //
  185.     //  Ai(10, 11)[5]
  186.     //
  187.     // But you will get an sscanf warning, and I may remove that ability from
  188.     // the start - that will mean a new function, but an easy to write one.
  189.     // In fact the most complex will probably be something like:
  190.     //
  191.     //  E<ifs[32]s[8]d>(10, 12.3, Hello there, Hi, 42)
  192.     //
  193.     // Get the number of parameters passed.  We add one as the indexes are out
  194.     // by one (OBOE - Out By One Error) due to params[0] being the parameter
  195.     // count, not an actual parameter.
  196.     const int
  197.         paramCount = ((int)params[0] / 4) + 1;
  198.     // Could add a check for only 3 parameters here - I can't think of a time
  199.     // when you would not want any return values at all, but that doesn't mean
  200.     // they don't exist - you could just want to check but not save the format.
  201.     // Update - that is now a possibility with the '{...}' specifiers.
  202.     if (paramCount < (2 + 1))
  203.     {
  204.         logprintf("sscanf error: Missing required parameters.");
  205.         return SSCANF_FAIL_RETURN;
  206.     }
  207.     //else if (paramCount == (2 + 1))
  208.     //{
  209.         // Only have an input and a specifier - better hope the whole specifier
  210.         // is quite (i.e. enclosed in '{...}').
  211.     //}
  212.     // Set up function wide values.
  213.     // Get and check the main data.
  214.     // Pointer to the current input data.
  215.     char *
  216.         string;
  217.     STR_PARAM(amx, params[1], string);
  218.     // Pointer to the current format specifier.
  219.     char *
  220.         format;
  221.     STR_PARAM(amx, params[2], format);
  222.     // Check for CallRemoteFunction style null strings and correct.
  223.     if (string[0] == '\1' && string[1] == '\0')
  224.     {
  225.         string[0] = '\0';
  226.     }
  227.     // Current parameter to save data to.
  228.     int
  229.         paramPos = 3;
  230.     cell *
  231.         cptr;
  232.     InitialiseDelimiter();
  233.     // Skip leading space.
  234.     SkipWhitespace(&string);
  235.     bool
  236.         doSave;
  237.     // Code for the rare cases where the WHOLE format is quiet.
  238.     if (*format == '{')
  239.     {
  240.         ++format;
  241.         doSave = false;
  242.     }
  243.     else
  244.     {
  245.         doSave = true;
  246.     }
  247.     // Now do the main loop as long as there are variables to store the data in
  248.     // and input string remaining to get the data from.
  249.     while (*string && (paramPos < paramCount || !doSave))
  250.     {
  251.         if (!*format)
  252.         {
  253.             // End of the format string - if we're here we've got all the
  254.             // parameters but there is extra string or variables, which may
  255.             // indicate their code needs fixing, for example:
  256.             // sscanf(data, "ii", var0, var1, var3, var4);
  257.             // There is only two format specifiers, but four returns.  This may
  258.             // also be reached if there is too much input data, but that is
  259.             // considered OK as that is likely a user's fault.
  260.             if (paramPos < paramCount)
  261.             {
  262.                 logprintf("sscanf warning: Format specifier does not match parameter count.");
  263.             }
  264.             if (!doSave)
  265.             {
  266.                 // Started a quiet section but never explicitly ended it.
  267.                 logprintf("sscanf warning: Unclosed quiet section.");
  268.             }
  269.             return SSCANF_TRUE_RETURN;
  270.         }
  271.         else if (IsWhitespace(*format))
  272.         {
  273.             ++format;
  274.         }
  275.         else
  276.         {
  277.             switch (*format++)
  278.             {
  279.                 case 'L':
  280.                     DX(bool, L)
  281.                     // FALLTHROUGH
  282.                 case 'l':
  283.                     DOV(bool, L)
  284.                     break;
  285.                 case 'B':
  286.                     DX(int, B)
  287.                     // FALLTHROUGH
  288.                 case 'b':
  289.                     DO(int, B)
  290.                 case 'N':
  291.                     DX(int, N)
  292.                     // FALLTHROUGH
  293.                 case 'n':
  294.                     DO(int, N)
  295.                 case 'C':
  296.                     DX(char, C)
  297.                     // FALLTHROUGH
  298.                 case 'c':
  299.                     DO(char, C)
  300.                 case 'I':
  301.                 case 'D':
  302.                     DX(int, I)
  303.                     // FALLTHROUGH
  304.                 case 'i':
  305.                 case 'd':
  306.                     DO(int, I)
  307.                 case 'H':
  308.                 case 'X':
  309.                     DX(int, H)
  310.                     // FALLTHROUGH
  311.                 case 'h':
  312.                 case 'x':
  313.                     DO(int, H)
  314.                 case 'O':
  315.                     DX(int, O)
  316.                     // FALLTHROUGH
  317.                 case 'o':
  318.                     DO(int, O)
  319.                 case 'F':
  320.                     DXF(double, F)
  321.                     // FALLTHROUGH
  322.                 case 'f':
  323.                     DOF(double, F)
  324.                 case 'G':
  325.                     DXF(double, G)
  326.                     // FALLTHROUGH
  327.                 case 'g':
  328.                     DOF(double, G)
  329.                 case '{':
  330.                     if (doSave)
  331.                     {
  332.                         doSave = false;
  333.                     }
  334.                     else
  335.                     {
  336.                         // Already in a quiet section.
  337.                         logprintf("sscanf warning: Can't have nestled quiet sections.");
  338.                     }
  339.                     continue;
  340.                 case '}':
  341.                     if (doSave)
  342.                     {
  343.                         logprintf("sscanf warning: Not in a quiet section.");
  344.                     }
  345.                     else
  346.                     {
  347.                         doSave = true;
  348.                     }
  349.                     continue;
  350.                 case 'P':
  351.                     logprintf("sscanf warning: You can't have an optional delimiter.");
  352.                     // FALLTHROUGH
  353.                 case 'p':
  354.                     // 'P' doesn't exist.
  355.                     // Theoretically, for compatibility, this should be:
  356.                     // p<delimiter>, but that will break backwards
  357.                     // compatibility with anyone doing "p<" to use '<' as a
  358.                     // delimiter (doesn't matter how rare that may be).  Also,
  359.                     // writing deprecation code and both the new and old code
  360.                     // is more trouble than it's worth, and it's slow.
  361.                     // UPDATE: I wrote the "GetSingleType" code for 'a' and
  362.                     // figured out a way to support legacy and new code, while
  363.                     // still maintaining support for the legacy "p<" separator,
  364.                     // so here it is:
  365.                     ResetDelimiter();
  366.                     AddDelimiter(GetSingleType(&format));
  367.                     continue;
  368.                 case 'Z':
  369.                     logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
  370.                     // FALLTHROUGH
  371.                 case 'z':
  372.                     logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
  373.                     // FALLTHROUGH
  374.                 case 'S':
  375.                     if (IsDelimiter(*string))
  376.                     {
  377.                         char *
  378.                             dest;
  379.                         int
  380.                             length;
  381.                         if (DoSD(&format, &dest, &length))
  382.                         {
  383.                             // Send the string to PAWN.
  384.                             if (doSave)
  385.                             {
  386.                                 amx_GetAddr(amx, params[paramPos++], &cptr);
  387.                                 amx_SetString(cptr, dest, 0, 0, length);
  388.                             }
  389.                         }
  390.                         break;
  391.                     }
  392.                     // Implicit "else".
  393.                     SkipDefaultEx(&format);
  394.                     // FALLTHROUGH
  395.                 case 's':
  396.                     {
  397.                         // Get the length.
  398.                         int
  399.                             length = GetLength(&format, false);
  400.                         char *
  401.                             dest;
  402.                         DoS(&string, &dest, length, IsEnd(*format));
  403.                         // Send the string to PAWN.
  404.                         if (doSave)
  405.                         {
  406.                             amx_GetAddr(amx, params[paramPos++], &cptr);
  407.                             amx_SetString(cptr, dest, 0, 0, length);
  408.                         }
  409.                     }
  410.                     break;
  411.                 case 'U':
  412.                     DX(int, U)
  413.                     // FALLTHROUGH
  414.                 case 'u':
  415.                     DOV(int, U)
  416.                     break;
  417.                 case 'Q':
  418.                     DX(int, Q)
  419.                     // FALLTHROUGH
  420.                 case 'q':
  421.                     DOV(int, Q)
  422.                     break;
  423.                 case 'R':
  424.                     DX(int, R)
  425.                     // FALLTHROUGH
  426.                 case 'r':
  427.                     DOV(int, R)
  428.                     break;
  429.                 case 'A':
  430.                     // We need the default values here.
  431.                     if (doSave)
  432.                     {
  433.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  434.                         if (DoA(&format, &string, cptr, true))
  435.                         {
  436.                             break;
  437.                         }
  438.                     }
  439.                     else
  440.                     {
  441.                         // Pass a NULL pointer so data isn't saved anywhere.
  442.                         if (DoA(&format, &string, NULL, true))
  443.                         {
  444.                             break;
  445.                         }
  446.                     }
  447.                     return SSCANF_FAIL_RETURN;
  448.                 case 'a':
  449.                     if (doSave)
  450.                     {
  451.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  452.                         if (DoA(&format, &string, cptr, false))
  453.                         {
  454.                             break;
  455.                         }
  456.                     }
  457.                     else
  458.                     {
  459.                         // Pass a NULL pointer so data isn't saved anywhere.
  460.                         if (DoA(&format, &string, NULL, false))
  461.                         {
  462.                             break;
  463.                         }
  464.                     }
  465.                     return SSCANF_FAIL_RETURN;
  466.                 case 'E':
  467.                     // We need the default values here.
  468.                     if (doSave)
  469.                     {
  470.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  471.                         if (DoE(&format, &string, cptr, true))
  472.                         {
  473.                             break;
  474.                         }
  475.                     }
  476.                     else
  477.                     {
  478.                         // Pass a NULL pointer so data isn't saved anywhere.
  479.                         if (DoE(&format, &string, NULL, true))
  480.                         {
  481.                             break;
  482.                         }
  483.                     }
  484.                     return SSCANF_FAIL_RETURN;
  485.                 case 'e':
  486.                     if (doSave)
  487.                     {
  488.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  489.                         if (DoE(&format, &string, cptr, false))
  490.                         {
  491.                             break;
  492.                         }
  493.                     }
  494.                     else
  495.                     {
  496.                         // Pass a NULL pointer so data isn't saved anywhere.
  497.                         if (DoE(&format, &string, NULL, false))
  498.                         {
  499.                             break;
  500.                         }
  501.                     }
  502.                     return SSCANF_FAIL_RETURN;
  503.                 case 'K':
  504.                     // We need the default values here.
  505.                     if (doSave)
  506.                     {
  507.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  508.                         if (DoK(amx, &format, &string, cptr, true))
  509.                         {
  510.                             break;
  511.                         }
  512.                     }
  513.                     else
  514.                     {
  515.                         // Pass a NULL pointer so data isn't saved anywhere.
  516.                         if (DoK(amx, &format, &string, NULL, true))
  517.                         {
  518.                             break;
  519.                         }
  520.                     }
  521.                     return SSCANF_FAIL_RETURN;
  522.                 case 'k':
  523.                     if (doSave)
  524.                     {
  525.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  526.                         if (DoK(amx, &format, &string, cptr, false))
  527.                         {
  528.                             break;
  529.                         }
  530.                     }
  531.                     else
  532.                     {
  533.                         // Pass a NULL pointer so data isn't saved anywhere.
  534.                         if (DoK(amx, &format, &string, NULL, false))
  535.                         {
  536.                             break;
  537.                         }
  538.                     }
  539.                     return SSCANF_FAIL_RETURN;
  540.                 case '\'':
  541.                     // Find the end of the literal.
  542.                     {
  543.                         char
  544.                             * str = format,
  545.                             * write = format;
  546.                         bool
  547.                             escape = false;
  548.                         while (!IsEnd(*str) && (escape || *str != '\''))
  549.                         {
  550.                             if (*str == '\\')
  551.                             {
  552.                                 if (escape)
  553.                                 {
  554.                                     // "\\" - Go back a step to write this
  555.                                     // character over the last character (which
  556.                                     // just happens to be the same character).
  557.                                     --write;
  558.                                 }
  559.                                 escape = !escape;
  560.                             }
  561.                             else
  562.                             {
  563.                                 if (*str == '\'')
  564.                                 {
  565.                                     // Overwrite the escape character with the
  566.                                     // quote character.  Must have been
  567.                                     // preceeded by a slash or it wouldn't have
  568.                                     // got to here in the loop.
  569.                                     --write;
  570.                                 }
  571.                                 escape = false;
  572.                             }
  573.                             // Copy the string over itself to get rid of excess
  574.                             // escape characters.
  575.                             // Not sure if it's faster in the average case to
  576.                             // always do the copy or check if it's needed.
  577.                             // This write is always safe as it makes the string
  578.                             // shorter, so we'll never run out of space.  It
  579.                             // will also not overwrite the original string.
  580.                             *write++ = *str++;
  581.                         }
  582.                         if (*str == '\'')
  583.                         {
  584.                             // Correct end.  Make a shorter string to search
  585.                             // for.
  586.                             *write = '\0';
  587.                             // Find the current section of format in string.
  588.                             char *
  589.                                 find = strstr(string, format);
  590.                             if (!find)
  591.                             {
  592.                                 // Didn't find the string
  593.                                 return SSCANF_FAIL_RETURN;
  594.                             }
  595.                             // Found the string.  Update the current string
  596.                             // position to the length of the search term
  597.                             // further along from the start of the term.  Use
  598.                             // "write" here as we want the escaped string
  599.                             // length.
  600.                             string = find + (write - format);
  601.                             // Move to after the end of the search string.  Use
  602.                             // "str" here as we want the unescaped string
  603.                             // length.
  604.                             format = str + 1;
  605.                         }
  606.                         else
  607.                         {
  608.                             logprintf("sscanf warning: Unclosed string literal.");
  609.                             char *
  610.                                 find = strstr(string, format);
  611.                             if (!find)
  612.                             {
  613.                                 return SSCANF_FAIL_RETURN;
  614.                             }
  615.                             string = find + (write - format);
  616.                             format = str;
  617.                         }
  618.                     }
  619.                     break;
  620.                 case '%':
  621.                     logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
  622.                     continue;
  623.                 default:
  624.                     logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
  625.                     continue;
  626.             }
  627.             // Loop cleanup - only skip one spacer so that we can detect
  628.             // multiple explicit delimiters in a row, for example:
  629.             //
  630.             // hi     there
  631.             //
  632.             // is NOT multiple explicit delimiters in a row (they're
  633.             // whitespace).  This however is:
  634.             //
  635.             // hi , , , there
  636.             //
  637.             SkipOneSpacer(&string);
  638.         }
  639.     }
  640.     // Temporary to the end of the code.
  641.     ResetDelimiter();
  642.     AddDelimiter(')');
  643.     // We don't need code here to handle the case where paramPos was reached,
  644.     // but the end of the string wasn't - if that's the case there's no
  645.     // problem as we just ignore excess string data.
  646.     while (paramPos < paramCount || !doSave)
  647.     {
  648.         // Loop through if there's still parameters remaining.
  649.         if (!*format)
  650.         {
  651.             logprintf("sscanf warning: Format specifier does not match parameter count.");
  652.             if (!doSave)
  653.             {
  654.                 // Started a quiet section but never explicitly ended it.
  655.                 logprintf("sscanf warning: Unclosed quiet section.");
  656.             }
  657.             return SSCANF_TRUE_RETURN;
  658.         }
  659.         else if (IsWhitespace(*format))
  660.         {
  661.             ++format;
  662.         }
  663.         else
  664.         {
  665.             // Do the main switch again.
  666.             switch (*format++)
  667.             {
  668.                 case 'L':
  669.                     DE(bool, L)
  670.                 case 'B':
  671.                     DE(int, B)
  672.                 case 'N':
  673.                     DE(int, N)
  674.                 case 'C':
  675.                     DE(char, C)
  676.                 case 'I':
  677.                 case 'D':
  678.                     DE(int, I)
  679.                 case 'H':
  680.                 case 'X':
  681.                     DE(int, H)
  682.                 case 'O':
  683.                     DE(int, O)
  684.                 case 'F':
  685.                     DEF(double, F)
  686.                 case 'G':
  687.                     DEF(double, G)
  688.                 case 'U':
  689.                     DE(int, U)
  690.                 case 'Q':
  691.                     DE(int, Q)
  692.                 case 'R':
  693.                     DE(int, R)
  694.                 case 'A':
  695.                     if (doSave)
  696.                     {
  697.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  698.                         if (DoA(&format, NULL, cptr, true))
  699.                         {
  700.                             break;
  701.                         }
  702.                     }
  703.                     else
  704.                     {
  705.                         // Pass a NULL pointer so data isn't saved anywhere.
  706.                         // Also pass NULL data so it knows to only collect the
  707.                         // default values.
  708.                         if (DoA(&format, NULL, NULL, true))
  709.                         {
  710.                             break;
  711.                         }
  712.                     }
  713.                     return SSCANF_FAIL_RETURN;
  714.                 case 'E':
  715.                     if (doSave)
  716.                     {
  717.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  718.                         if (DoE(&format, NULL, cptr, true))
  719.                         {
  720.                             break;
  721.                         }
  722.                     }
  723.                     else
  724.                     {
  725.                         // Pass a NULL pointer so data isn't saved anywhere.
  726.                         // Also pass NULL data so it knows to only collect the
  727.                         // default values.
  728.                         if (DoE(&format, NULL, NULL, true))
  729.                         {
  730.                             break;
  731.                         }
  732.                     }
  733.                     return SSCANF_FAIL_RETURN;
  734.                 case 'K':
  735.                     if (doSave)
  736.                     {
  737.                         amx_GetAddr(amx, params[paramPos++], &cptr);
  738.                         if (DoK(amx, &format, NULL, cptr, true))
  739.                         {
  740.                             break;
  741.                         }
  742.                     }
  743.                     else
  744.                     {
  745.                         // Pass a NULL pointer so data isn't saved anywhere.
  746.                         // Also pass NULL data so it knows to only collect the
  747.                         // default values.
  748.                         if (DoK(amx, &format, NULL, NULL, true))
  749.                         {
  750.                             break;
  751.                         }
  752.                     }
  753.                     return SSCANF_FAIL_RETURN;
  754.                 case '{':
  755.                     if (doSave)
  756.                     {
  757.                         doSave = false;
  758.                     }
  759.                     else
  760.                     {
  761.                         // Already in a quiet section.
  762.                         logprintf("sscanf warning: Can't have nestled quiet sections.");
  763.                     }
  764.                     break;
  765.                 case '}':
  766.                     if (doSave)
  767.                     {
  768.                         logprintf("sscanf warning: Not in a quiet section.");
  769.                     }
  770.                     else
  771.                     {
  772.                         doSave = true;
  773.                     }
  774.                     break;
  775.                 case 'Z':
  776.                     logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
  777.                     // FALLTHROUGH
  778.                 case 'z':
  779.                     logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
  780.                     // FALLTHROUGH
  781.                 case 'S':
  782.                     {
  783.                         char *
  784.                             dest;
  785.                         int
  786.                             length;
  787.                         if (DoSD(&format, &dest, &length))
  788.                         {
  789.                             // Send the string to PAWN.
  790.                             if (doSave)
  791.                             {
  792.                                 amx_GetAddr(amx, params[paramPos++], &cptr);
  793.                                 amx_SetString(cptr, dest, 0, 0, length);
  794.                             }
  795.                         }
  796.                     }
  797.                     break;
  798.                 case 'P':
  799.                     logprintf("sscanf warning: You can't have an optional delimiter.");
  800.                     // FALLTHROUGH
  801.                 case 'p':
  802.                     // Discard delimiter.  This only matters when they have
  803.                     // real inputs, not the default ones used here.
  804.                     GetSingleType(&format);
  805.                     continue;
  806.                 case '\'':
  807.                     // Implicitly optional if the specifiers after it are
  808.                     // optional.
  809.                     {
  810.                         bool
  811.                             escape = false;
  812.                         while (!IsEnd(*format) && (escape || *format != '\''))
  813.                         {
  814.                             if (*format == '\\')
  815.                             {
  816.                                 escape = !escape;
  817.                             }
  818.                             else
  819.                             {
  820.                                 escape = false;
  821.                             }
  822.                             ++format;
  823.                         }
  824.                         if (*format == '\'')
  825.                         {
  826.                             ++format;
  827.                         }
  828.                         else
  829.                         {
  830.                             logprintf("sscanf warning: Unclosed string literal.");
  831.                         }
  832.                     }
  833.                     break;
  834.                     // Large block of specifiers all together.
  835.                 case 'a':
  836.                 case 'b':
  837.                 case 'c':
  838.                 case 'd':
  839.                 case 'e':
  840.                 case 'f':
  841.                 case 'g':
  842.                 case 'h':
  843.                 case 'i':
  844.                 case 'k':
  845.                 case 'l':
  846.                 case 'n':
  847.                 case 'o':
  848.                 case 'q':
  849.                 case 'r':
  850.                 case 's':
  851.                 case 'u':
  852.                 case 'x':
  853.                     // These are non optional items, but the input string
  854.                     // didn't include them, so we fail - this is in fact the
  855.                     // most basic definition of a fail (the original)!  We
  856.                     // don't need any text warnings here - admittedly we don't
  857.                     // know if the format specifier is well formed (there may
  858.                     // not be enough return variables for example), but it
  859.                     // doesn't matter - the coder should have tested for those
  860.                     // things, and the more important thing is that the user
  861.                     // didn't enter the correct data.
  862.                     return SSCANF_FAIL_RETURN;
  863.                 case '%':
  864.                     logprintf("sscanf warning: sscanf specifiers do not require '%' before them.");
  865.                     break;
  866.                 default:
  867.                     logprintf("sscanf warning: Unknown format specifier '%c', skipping.", *(format - 1));
  868.                     break;
  869.             }
  870.             // Don't need any cleanup here.
  871.         }
  872.     }
  873.     if (*format)
  874.     {
  875.         do
  876.         {
  877.             if (!IsWhitespace(*format))
  878.             {
  879.                 // Only print this warning if the remaining characters are not
  880.                 // spaces - spaces are allowed, and sometimes required, on the
  881.                 // ends of formats (e.g. to stop the final 's' specifier
  882.                 // collecting all remaining characters and only get one word).
  883.                 // We could check that the remaining specifier is a valid one,
  884.                 // but this is only a guide - they shouldn't even have other
  885.                 // characters IN the specifier so it doesn't matter - it will
  886.                 // point to a bug, which is the important thing.
  887.                 if (doSave)
  888.                 {
  889.                     if (*format == '}')
  890.                     {
  891.                         logprintf("sscanf warning: Not in a quiet section.");
  892.                     }
  893.                     else if (*format != '{')
  894.                     {
  895.                         // Fix the bad display bug.
  896.                         logprintf("sscanf warning: Format specifier does not match parameter count.");
  897.                     }
  898.                     // Only display it once.
  899.                     break;
  900.                 }
  901.                 else
  902.                 {
  903.                     if (*format == '}')
  904.                     {
  905.                         doSave = true;
  906.                     }
  907.                     else
  908.                     {
  909.                         logprintf("sscanf warning: Format specifier does not match parameter count.");
  910.                         break;
  911.                     }
  912.                 }
  913.             }
  914.             ++format;
  915.         }
  916.         while (*format);
  917.     }
  918.     if (!doSave)
  919.     {
  920.         // Started a quiet section but never explicitly ended it.
  921.         logprintf("sscanf warning: Unclosed quiet section.");
  922.     }
  923.     // No more parameters and no more format specifiers which could be read
  924.     // from - this is a valid return!
  925.     return SSCANF_TRUE_RETURN;
  926. }
  927.  
  928. #if SSCANF_QUIET
  929.     void
  930.         qlog(char * str, ...)
  931.     {
  932.         // Do nothing
  933.     }
  934. #endif
  935.  
  936. //----------------------------------------------------------
  937. // The Support() function indicates what possibilities this
  938. // plugin has. The SUPPORTS_VERSION flag is required to check
  939. // for compatibility with the server.
  940.  
  941. PLUGIN_EXPORT unsigned int PLUGIN_CALL
  942.     Supports()
  943. {
  944.     return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
  945. }
  946.  
  947. //----------------------------------------------------------
  948. // The Load() function gets passed on exported functions from
  949. // the SA-MP Server, like the AMX Functions and logprintf().
  950. // Should return true if loading the plugin has succeeded.
  951.  
  952. PLUGIN_EXPORT bool PLUGIN_CALL
  953.     Load(void ** ppData)
  954. {
  955.     pAMXFunctions = ppData[PLUGIN_DATA_AMX_EXPORTS];
  956.     logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
  957.     //GetServer = (GetServer_t)ppData[0xE1];
  958.    
  959.     //logprintf("0x%08X\n", (int)logprintf);
  960.     logprintf("\n");
  961.     logprintf(" ===============================\n");
  962.     logprintf("      sscanf plugin loaded.     \n");
  963.     logprintf("   (c) 2009 Alex \"Y_Less\" Cole\n");
  964.     logprintf("   0.3d-R2 500 Players \"dnee\"\n");
  965.     logprintf(" ===============================\n");
  966.    
  967.     // Determine server version.  Ideally we would use a feature check, such as
  968.     // checking wether ConnectNPC exists, doing away with the need for any
  969.     // memory addresses, unfortunately if the native isn't used in the current
  970.     // amx, then amx_FindNative won't find it, despite the fact that it does
  971.     // exist.  I need to find a more reliable and more portable way of checking
  972.     // the current server version.
  973.     /*if (logprintf == LOGPRINTF_0221 || logprintf == LOGPRINTF_0222 || logprintf == LOGPRINTF_0223 || logprintf == LOGPRINTF_0224)
  974.     {
  975.         g_iServerVersion = SERVER_VERSION_0200;
  976.         g_iTrueMax = MAX_PLAYERS_0200;
  977.         g_iInvalid = INVALID_PLAYER_ID_0200;
  978.     }
  979.     else if (logprintf == LOGPRINTF_0300)
  980.     {
  981.         g_iServerVersion = SERVER_VERSION_0300;
  982.         g_iTrueMax = MAX_PLAYERS_0300;
  983.         g_iInvalid = INVALID_PLAYER_ID_0300;
  984.     }
  985.     else *//*if (logprintf == LOGPRINTF_0340)
  986.     {
  987.         g_iServerVersion = SERVER_VERSION_0340;
  988.         g_iTrueMax = MAX_PLAYERS_0300;
  989.         g_iInvalid = INVALID_PLAYER_ID_0300;
  990.     }
  991.     else if (logprintf == LOGPRINTF_0342)
  992.     {
  993.         g_iServerVersion = SERVER_VERSION_0342;
  994.         g_iTrueMax = MAX_PLAYERS_0300;
  995.         g_iInvalid = INVALID_PLAYER_ID_0300;
  996.     }
  997.     else
  998.     {
  999.         logprintf("sscanf error: The current build ONLY supports 0.3d");
  1000.     }*/
  1001.     #if SSCANF_QUIET
  1002.         logprintf = qlog;
  1003.     #endif
  1004.     return true;
  1005. }
  1006.  
  1007. //----------------------------------------------------------
  1008. // The Unload() function is called when the server shuts down,
  1009. // meaning this plugin gets shut down with it.
  1010.  
  1011. PLUGIN_EXPORT void PLUGIN_CALL
  1012.     Unload()
  1013. {
  1014.     logprintf("\n");
  1015.     logprintf(" ===============================\n");
  1016.     logprintf("     sscanf plugin unloaded.    \n");
  1017.     logprintf(" ===============================\n");
  1018. }
  1019.  
  1020. static cell AMX_NATIVE_CALL
  1021.     n_SSCANF_Init(AMX * amx, cell * params)
  1022. {
  1023.     if (params[0] != 3 * sizeof (cell))
  1024.     {
  1025.         logprintf("sscanf error: SSCANF_Init has incorrect parameters.");
  1026.         g_iTrueMax = 0;
  1027.         return 0;
  1028.     }
  1029.     if (g_iTrueMax != 0)
  1030.     {
  1031.         // Already initialised.
  1032.         return 1;
  1033.     }
  1034.     g_iTrueMax = (int)params[1];
  1035.     g_iInvalid = (int)params[2];
  1036.     g_iMaxPlayerName = (int)params[3];
  1037.     g_szPlayerNames = new char [g_iTrueMax * g_iMaxPlayerName];
  1038.     g_iConnected = new int [g_iTrueMax];
  1039.     // FINALLY fixed this bug - I didn't know "new []" didn't initialise...
  1040.     memset(g_iConnected, 0, sizeof (int) * g_iTrueMax);
  1041.     g_iNPC = new int [g_iTrueMax];
  1042.     return 1;
  1043. }
  1044.  
  1045. static void
  1046.     DoName(AMX * amx, cell playerid, cell name)
  1047. {
  1048.     cell *
  1049.         str;
  1050.     int
  1051.         len;
  1052.     amx_GetAddr(amx, name, &str);
  1053.     amx_StrLen(str, &len);
  1054.     if ((unsigned int)len >= g_iMaxPlayerName)
  1055.     {
  1056.         len = (int)g_iMaxPlayerName - 1;
  1057.     }
  1058.     amx_GetString(g_szPlayerNames + (g_iMaxPlayerName * playerid), str, 0, len + 1);
  1059. }
  1060.  
  1061. static cell AMX_NATIVE_CALL
  1062.     n_SSCANF_Join(AMX * amx, cell * params)
  1063. {
  1064.     if (params[0] != 3 * sizeof (cell))
  1065.     {
  1066.         logprintf("sscanf error: SSCANF_Join has incorrect parameters.");
  1067.         return 0;
  1068.     }
  1069.     cell
  1070.         playerid = params[1];
  1071.     ++g_iConnected[playerid];
  1072.     DoName(amx, playerid, params[2]);
  1073.     g_iNPC[playerid] = params[3];
  1074.     return 1;
  1075. }
  1076.  
  1077. static cell AMX_NATIVE_CALL
  1078.     n_SSCANF_Leave(AMX * amx, cell * params)
  1079. {
  1080.     if (params[0] != 1 * sizeof (cell))
  1081.     {
  1082.         logprintf("sscanf error: SSCANF_Leave has incorrect parameters.");
  1083.         return 0;
  1084.     }
  1085.     // To be correct for multiple scripts with loads and unloads (unloadfs).
  1086.     --g_iConnected[params[1]];
  1087.     return 1;
  1088. }
  1089.  
  1090. static cell AMX_NATIVE_CALL
  1091.     n_SSCANF_SetPlayerName(AMX * amx, cell * params)
  1092. {
  1093.     // Hook ALL AMXs, even if they don't use sscanf, by working at the plugin
  1094.     // level.  This allows us to intercept name changes.
  1095.     //cell
  1096.     //  result;
  1097.     //amx_Callback(amx, 0, &result, params);
  1098.     if (params[0] != 2 * sizeof (cell))
  1099.     {
  1100.         logprintf("sscanf error: SSCANF_SetPlayerName has incorrect parameters.");
  1101.         return 0;
  1102.     }
  1103.     DoName(amx, params[1], params[2]);
  1104.     return SetPlayerName(amx, params);
  1105. }
  1106.  
  1107. //----------------------------------------------------------
  1108. // The AmxLoad() function gets called when a new gamemode or
  1109. // filterscript gets loaded with the server. In here we register
  1110. // the native functions we like to add to the scripts.
  1111.  
  1112. AMX_NATIVE_INFO
  1113.     sscanfNatives[] =
  1114.         {
  1115.             {"sscanf", n_sscanf},
  1116.             {"SSCANF_Init", n_SSCANF_Init},
  1117.             {"SSCANF_Join", n_SSCANF_Join},
  1118.             {"SSCANF_Leave", n_SSCANF_Leave},
  1119.             {0,        0}
  1120.         };
  1121.  
  1122. // From "amx.c", part of the PAWN language runtime:
  1123. // http://code.google.com/p/pawnscript/source/browse/trunk/amx/amx.c
  1124.  
  1125. #define USENAMETABLE(hdr) \
  1126.     ((hdr)->defsize==sizeof(AMX_FUNCSTUBNT))
  1127.  
  1128. #define NUMENTRIES(hdr,field,nextfield) \
  1129.     (unsigned)(((hdr)->nextfield - (hdr)->field) / (hdr)->defsize)
  1130.  
  1131. #define GETENTRY(hdr,table,index) \
  1132.     (AMX_FUNCSTUB *)((unsigned char*)(hdr) + (unsigned)(hdr)->table + (unsigned)index*(hdr)->defsize)
  1133.  
  1134. #define GETENTRYNAME(hdr,entry) \
  1135.     (USENAMETABLE(hdr) ? \
  1136.         (char *)((unsigned char*)(hdr) + (unsigned)((AMX_FUNCSTUBNT*)(entry))->nameofs) : \
  1137.         ((AMX_FUNCSTUB*)(entry))->name)
  1138.  
  1139. PLUGIN_EXPORT int PLUGIN_CALL
  1140.     AmxLoad(AMX * amx)
  1141. {
  1142.     int
  1143.         num,
  1144.         idx;
  1145.     // Operate on the raw AMX file, don't use the amx_ functions to avoid issues
  1146.     // with the fact that we've not actually finished initialisation yet.  Based
  1147.     // VERY heavilly on code from "amx.c" in the PAWN runtime library.
  1148.     AMX_HEADER *
  1149.         hdr = (AMX_HEADER *)amx->base;
  1150.     AMX_FUNCSTUB *
  1151.         func;
  1152.     num = NUMENTRIES(hdr, natives, libraries);
  1153.     for (idx = 0; idx != num; ++idx)
  1154.     {
  1155.         func = GETENTRY(hdr, natives, idx);
  1156.         if (!strcmp("SetPlayerName", GETENTRYNAME(hdr, func)))
  1157.         {
  1158.             // Intercept the call!
  1159.             SetPlayerName = (AMX_NATIVE)func->address;
  1160.             func->address = (ucell)n_SSCANF_SetPlayerName;
  1161.             break;
  1162.         }
  1163.     }
  1164.     return amx_Register(amx, sscanfNatives, -1);
  1165. }
  1166.  
  1167. //----------------------------------------------------------
  1168. // When a gamemode is over or a filterscript gets unloaded, this
  1169. // function gets called. No special actions needed in here.
  1170.  
  1171. PLUGIN_EXPORT int PLUGIN_CALL
  1172.     AmxUnload(AMX * amx)
  1173. {
  1174.     return AMX_ERR_NONE;
  1175. }
Advertisement
Add Comment
Please, Sign In to add comment