| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714 |
- /*
- * Version: MPL 1.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the sscanf 2.0 SA:MP plugin.
- *
- * The Initial Developer of the Original Code is Alex "Y_Less" Cole.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Special Thanks to:
- *
- * SA:MP Team past, present and future
- */
- #include <stdio.h>
- #include "SDK/amx/amx.h"
- #include "utils.h"
- #include "specifiers.h"
- #include "data.h"
- #include "sscanf.h"
- extern logprintf_t
- logprintf;
- #define SAVE_VALUE(m) \
- if (cptr) \
- *cptr++ = m
- #define SAVE_VALUE_F(m) \
- if (cptr) { \
- float f = (float)m; \
- *cptr++ = amx_ftoc(f); }
- #define UPDATE_VALUES(m) \
- if (defaults) { \
- if (count) { \
- diff.c = m - last.c; \
- last.c = m; \
- } else { \
- last.c = m; \
- diff.c = 0; } } \
- SkipOneSpacer(&string); \
- ++count
- #define UPDATE_VALUES_F(m) \
- if (defaults) { \
- if (count) { \
- diff.d = m - last.d; \
- last.d = m; \
- } else { \
- last.d = m; \
- diff.d = 0; } } \
- SkipOneSpacer(&string); \
- ++count
- #define DO_LOOP(n) \
- count < length && *string && Do##n(&string, &b)
- // Macros for the regular values.
- #define DO(m,n) \
- {m b; \
- while (DO_LOOP(n)) { \
- SAVE_VALUE((cell)b); \
- UPDATE_VALUES((cell)b); } } \
- break;
- #define DOV(m,n) \
- {m b; \
- while (count < length && *string) { \
- Do##n(&string, &b); \
- SAVE_VALUE((cell)b); \
- UPDATE_VALUES((cell)b); } } \
- break;
- #define DOF(m,n) \
- {m b; \
- while (DO_LOOP(n)) { \
- SAVE_VALUE_F(b) \
- UPDATE_VALUES_F(b); } } \
- break;
- #define OPTIONAL_INVALID \
- logprintf("sscanf warning: Optional types invalid in array specifiers, consider using 'A'.")
- #define DX(m,n) \
- OPTIONAL_INVALID;
- #define DXF(m,n) \
- OPTIONAL_INVALID;
- void
- GetJaggedSlot(cell *, int, int, int, cell **, int *);
- bool
- DoK(AMX * amx, char ** defaults, char ** input, cell * cptr, bool optional);
- extern AMX *
- g_aCurAMX;
- extern int
- gOptions;
- union update_u
- {
- cell
- c;
- double
- d;
- };
- int
- DoArrayValues(char * type, char ** input, cell * cptr, int length, bool defaults, bool wholeString)
- {
- int
- count = 0;
- union update_u
- last,
- diff;
- last.d = 0;
- diff.d = 0;
- char *
- string = *input;
- switch (*type++)
- {
- // Copied directly from the main loop, just with different macros.
- case 'L':
- DX(bool, L)
- // FALLTHROUGH
- case 'l':
- {
- // The only custom code here. If the result is either "true"
- // or "false" it makes no sense to alternate in defaults as we
- // will just end up with larger values of true.
- bool
- b;
- while (count < length && *string)
- {
- DoL(&string, &b);
- SAVE_VALUE((cell)b);
- if (defaults)
- {
- last.c = (cell)b;
- }
- SkipOneSpacer(&string);
- ++count;
- }
- }
- break;
- case 'B':
- DX(int, B)
- // FALLTHROUGH
- case 'b':
- DO(int, B)
- case 'N':
- DX(int, N)
- // FALLTHROUGH
- case 'n':
- DO(int, N)
- case 'C':
- DX(char, C)
- // FALLTHROUGH
- case 'c':
- DO(char, C)
- case 'I':
- case 'D':
- DX(int, I)
- // FALLTHROUGH
- case 'i':
- case 'd':
- DO(int, I)
- case 'H':
- case 'X':
- DX(int, H)
- // FALLTHROUGH
- case 'h':
- case 'x':
- DO(int, H)
- case 'O':
- DX(int, O)
- // FALLTHROUGH
- case 'o':
- DO(int, O)
- case 'F':
- DXF(double, F)
- // FALLTHROUGH
- case 'f':
- DOF(double, F)
- case 'G':
- DXF(double, G)
- // FALLTHROUGH
- case 'g':
- {
- double
- b;
- while (DO_LOOP(G))
- {
- float
- f = (float)b;
- if (cptr)
- {
- *cptr++ = amx_ftoc(f);
- }
- if (defaults)
- {
- switch (amx_ftoc(f))
- {
- default:
- if (count)
- {
- diff.d = b - last.d;
- last.d = b;
- break;
- }
- // FALLTHROUGH
- case FLOAT_NEG_INFINITY:
- case FLOAT_INFINITY:
- case FLOAT_NAN:
- case FLOAT_NAN_E:
- last.d = b;
- diff.d = 0;
- break;
- }
- }
- SkipOneSpacer(&string);
- ++count;
- }
- }
- break;
- case 'U':
- DX(int, U)
- // FALLTHROUGH
- case 'u':
- if (*type == '[')
- {
- logprintf("sscanf warning: User arrays are not supported in arrays.");
- }
- if (defaults)
- {
- if (gOptions & 1)
- {
- int
- b;
- while (count < length && *string)
- {
- DoU(&string, &b, 0);
- SAVE_VALUE((cell)b);
- last.c = b;
- diff.c = 0;
- SkipOneSpacer(&string);
- ++count;
- }
- }
- else
- {
- int
- b;
- while (count < length && *string)
- {
- DoI(&string, &b);
- SAVE_VALUE((cell)b);
- last.c = b;
- diff.c = 0;
- SkipOneSpacer(&string);
- ++count;
- }
- }
- }
- else
- #define DoU(m,n) DoU(m,n,0)
- {
- DOV(int, U)
- }
- #undef DoU
- break;
- case 'Q':
- DX(int, Q)
- // FALLTHROUGH
- case 'q':
- if (*type == '[')
- {
- logprintf("sscanf warning: User arrays are not supported in arrays.");
- }
- if (defaults)
- {
- if (gOptions & 1)
- {
- int
- b;
- while (count < length && *string)
- {
- DoQ(&string, &b, 0);
- SAVE_VALUE((cell)b);
- last.c = b;
- diff.c = 0;
- SkipOneSpacer(&string);
- ++count;
- }
- }
- else
- {
- int
- b;
- while (count < length && *string)
- {
- DoI(&string, &b);
- SAVE_VALUE((cell)b);
- last.c = b;
- diff.c = 0;
- SkipOneSpacer(&string);
- ++count;
- }
- }
- }
- else
- #define DoQ(m,n) DoQ(m,n,0)
- {
- DOV(int, Q)
- }
- #undef DoQ
- break;
- case 'R':
- DX(int, R)
- // FALLTHROUGH
- case 'r':
- if (*type == '[')
- {
- logprintf("sscanf warning: User arrays are not supported in arrays.");
- }
- if (defaults)
- {
- if (gOptions & 1)
- {
- int
- b;
- while (count < length && *string)
- {
- DoR(&string, &b, 0);
- SAVE_VALUE((cell)b);
- last.c = b;
- diff.c = 0;
- SkipOneSpacer(&string);
- ++count;
- }
- }
- else
- {
- int
- b;
- while (count < length && *string)
- {
- DoI(&string, &b);
- SAVE_VALUE((cell)b);
- last.c = b;
- diff.c = 0;
- SkipOneSpacer(&string);
- ++count;
- }
- }
- }
- else
- #define DoR(m,n) DoR(m,n,0)
- {
- DOV(int, R)
- }
- #undef DoR
- break;
- case 'A':
- case 'a':
- logprintf("sscanf error: Multi-dimensional arrays are not supported.");
- return SSCANF_FAIL_RETURN;
- case '\'':
- logprintf("sscanf error: Search strings are not supported in arrays.");
- return SSCANF_FAIL_RETURN;
- case 'P':
- case 'p':
- logprintf("sscanf error: Delimiters are not supported in arrays.");
- return SSCANF_FAIL_RETURN;
- case '?':
- logprintf("sscanf error: Options are not supported in arrays.");
- return SSCANF_FAIL_RETURN;
- case 'K':
- DX(double, K)
- // FALLTHROUGH
- case 'k':
- //DOF(double, K)
- if (defaults)
- {
- if (DoK(g_aCurAMX, &type, &string, cptr, false) && cptr)
- {
- while (++count < length)
- {
- *(cptr + 1) = *cptr;
- ++cptr;
- }
- }
- }
- else
- {
- char *
- f = type;
- while (count < length && *string && DoK(g_aCurAMX, &f, &string, cptr, false))
- {
- if (cptr) ++cptr;
- SkipOneSpacer(&string);
- ++count;
- *(f - 1) = '>';
- f = type;
- }
- }
- break;
- case 's':
- //logprintf("sscanf error: Strings are not supported in arrays.");
- // Now they are (or rather, now I would like them to be, I've not
- // actually WRITTEN the code yet...).
- // This code has to read the memory pointed to by "cptr", which for
- // a multi-dimensional array points to the array header and from
- // which we can actually read the array lengths. Note that this
- // actually means that we don't need to include the string length in
- // the array specifier, and can thus support jagged arrays!
- if (defaults)
- {
- //char *
- // lt = type + 1;
- int
- nl = GetLength(&type, false),
- sl;
- char *
- dest;
- // Parse the default string.
- DoS(&string, &dest, 0x7FFFFFFF, true);
- if (cptr)
- {
- cell *
- sptr;
- // Send the string to PAWN.
- while (count < length)
- {
- // Get the true address as offset from the array
- // base address, and its length.
- GetJaggedSlot(cptr, length, nl, count, &sptr, &sl);
- amx_SetString(sptr, dest, 0, 0, sl);
- ++count;
- }
- }
- break;
- }
- else
- {
- // Get the length.
- //char *
- // lt = type;
- int
- nl = GetLength(&type, false),
- sl;
- char *
- dest;
- while (count < length && *string)
- {
- if (cptr)
- {
- cell *
- sptr;
- // Get the true address as offset from the array
- // base address, and its length.
- GetJaggedSlot(cptr, length, nl, count, &sptr, &sl);
- //printf("%d %d\n", nl, sl);
- //printf("%d %d %d", cptr, sptr, sl);
- DoS(&string, &dest, sl, wholeString && count == length - 1);
- amx_SetString(sptr, dest, 0, 0, sl);
- }
- else
- {
- DoS(&string, &dest, 0x7FFFFFFF, wholeString && count == length - 1);
- }
- SkipOneSpacer(&string);
- ++count;
- }
- break;
- }
- //return SSCANF_FAIL_RETURN;
- case '{':
- case '}':
- logprintf("sscanf error: Quiet sections are not supported in arrays.");
- return SSCANF_FAIL_RETURN;
- default:
- logprintf("sscanf error: Unknown format specifier '%c'.", *(type - 1));
- return SSCANF_FAIL_RETURN;
- }
- // Save the end of the string.
- *input = string;
- if (defaults)
- {
- if (count < length)
- {
- if (*string)
- {
- // Error in format specifier.
- logprintf("sscanf warning: Invalid values in array defaults.");
- }
- else
- {
- switch (*(type - 1))
- {
- case 'F':
- case 'f':
- case 'G':
- case 'g':
- // Float type.
- do
- {
- last.d += diff.d;
- SAVE_VALUE_F(last.d);
- ++count;
- }
- while (count < length);
- break;
- case 'K':
- case 'k':
- case 's':
- // There is no "progression" in optional strings - you
- // specify one and JUST one!
- break;
- default:
- do
- {
- // Other type.
- while (count < length)
- {
- last.c += diff.c;
- SAVE_VALUE(last.c);
- ++count;
- }
- }
- while (count < length);
- break;
- }
- }
- }
- else if (*string)
- {
- logprintf("sscanf warning: Excess array defaults found.");
- }
- }
- else
- {
- if (count < length)
- {
- if (*string)
- {
- // Invalid value entered.
- return SSCANF_FAIL_RETURN;
- }
- else
- {
- // Ran out of values - check if this is an optional array at a
- // higher level.
- return SSCANF_CONT_RETURN;
- }
- }
- }
- return SSCANF_TRUE_RETURN;
- }
- bool
- DoA(char ** defaults, char ** input, cell * cptr, bool optional)
- {
- // First, get the type of the array.
- bool
- escape = false;
- char
- * type = GetMultiType(defaults),
- * opts = 0;
- if (!type) return false;
- switch (*type)
- {
- case 'Z':
- // Don't even THINK about using "Z" - you will get THREE error
- // messages telling you off, "z" will give you 2, and "S" just 1.
- logprintf("sscanf warning: 'Z' doesn't exist - that would be an optional, deprecated optional string!.");
- // FALLTHROUGH
- case 'z':
- logprintf("sscanf warning: 'z' is deprecated, consider using 'S' instead.");
- // FALLTHROUGH
- case 'S':
- OPTIONAL_INVALID;
- *type = 's';
- break;
- }
- if (optional)
- {
- // Optional parameters - just collect the data for
- // now and use it later.
- if (**defaults == '(')
- {
- // Find the end of the options. Based on
- // SkipDefaultEx, but saving the start point.
- ++(*defaults);
- SkipWhitespace(defaults);
- // Got the start of the values.
- opts = *defaults;
- // Skip the defaults for now, we don't know the length yet.
- //while (**defaults) // && **defaults != ')')
- for ( ; ; )
- {
- switch (**defaults)
- {
- case '\0':
- goto DoA_after_loop;
- case '\\':
- escape = !escape;
- break;
- case ')':
- if (!escape)
- {
- // End the loop after ")" if it isn't escaped.
- goto DoA_after_loop;
- }
- // FALLTHROUGH.
- default:
- escape = false;
- break;
- }
- // Don't need to check for escaped ")"s here as you can't have
- // arrays of strings, which is the only place that would be.
- // Only now we do...
- ++(*defaults);
- }
- DoA_after_loop:
- if (**defaults)
- {
- if (opts == *defaults && *type != 's')
- {
- // No defaults found.
- logprintf("sscanf warning: Empty default values.");
- optional = false;
- }
- // Found a valid end. Make it null for
- // later array getting (easy to detect a
- // null end and we'll never need to
- // backtrack to here in the specifiers).
- **defaults = '\0';
- ++(*defaults);
- }
- else
- {
- logprintf("sscanf warning: Unclosed default value.");
- }
- }
- else
- {
- logprintf("sscanf warning: No default value found.");
- optional = false;
- }
- }
- // GetLength has "true" as arrays, being new, MUST have lengths.
- int
- length = GetLength(defaults, true);
- if (length)
- {
- // Got the length of the array, it's all good.
- if (optional)
- {
- // Optional parameters are always separated by commans, not
- // whatever the coder may choose.
- if (*type == 's') TempDelimiter(")");
- else TempDelimiter(",)");
- if (DoArrayValues(type, &opts, cptr, length, true, false) == SSCANF_FAIL_RETURN)
- {
- RestoreDelimiter();
- return false;
- }
- RestoreDelimiter();
- }
- if (input)
- {
- switch (DoArrayValues(type, input, cptr, length, false, *type == 's' && (IsEnd(**defaults) || (!cptr && **defaults == '}' && IsEnd(*(*defaults + 1))))))
- {
- case SSCANF_CONT_RETURN:
- if (optional)
- {
- return true;
- }
- else
- {
- return false;
- }
- case SSCANF_TRUE_RETURN:
- return true;
- default:
- return false;
- }
- }
- else
- {
- return true;
- }
- }
- // Default fail - only gets here if there is no length.
- return false;
- }
|