sscanf quiet specifiers -
GoldenLion - 21.06.2017
Hi, I made a trunk system a few days ago like this:
Код:
new action[6], extra[32];
if (sscanf(params, "s[6]S()[32]", action, extra))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk [open/close/view/store/get]");
And when the action was store then it was like this:
Код:
new item[10], amount;
if (sscanf(extra, "s[10]D(0)", item, amount))
{
SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk store [item]");
SendClientMessage(playerid, COLOR_GREY, "ITEMS: marijuana, cocaine, crack, ecstasy, heroin, weapon, armor.");
return 1;
}
Today I thought that "extra" thing doesn't look too nice so I found sscanf's quiet specifiers and I made this command:
Код:
CMD:trunk(playerid, params[])
{
new action[7];
if (sscanf(params, "s[7]", action))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk [action]");
if (!strcmp(action, "store", true))
{
new item[10];
if (sscanf(params, "{s[7]}s[10]", item))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk store [item]");
if (!strcmp(item, "apple", true))
{
new quantity;
if (sscanf(params, "{s[7]s[10]}d", quantity))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk store apple [quantity]");
new message[24];
format(message, sizeof(message), "quantity: %d", quantity);
SendClientMessage(playerid, -1, message);
}
else if (!strcmp(item, "weapon", true))
{
SendClientMessage(playerid, -1, "done");
}
else SendClientMessage(playerid, -1, "invalid item");
}
return 1;
}
So basically when you store an apple you need to specifiy the quantity, but when you store a weapon you don't. The problem is that when you store for example 5 apples into the trunk it stores "apple 5" into item here
Код:
if (sscanf(params, "{s[7]}s[10]", item))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk store [item]");
so that's an invalid item name and I also get a string buffer overflow when the size of item is smaller.
Is it possible to ignore the number after the item at this line so I could use it later for quantity or is the first way better? Hopefully it's understandable what I just explained.
Re: sscanf quiet specifiers -
Konstantinos - 21.06.2017
Use the optional length parameter:
pawn Код:
if (!strcmp(item, "apple ", true, 6))
About string buffer overflow, it expects 6 characters but you specify the rest of the parameters so ignore them:
pawn Код:
if (sscanf(params, "s[7]{s[50]}", action))
Just for your information, the string size is ignored in quite specifiers.
Re: sscanf quiet specifiers -
GoldenLion - 21.06.2017
Quote:
Originally Posted by Konstantinos
Use the optional length parameter:
pawn Код:
if (!strcmp(item, "apple ", true, 6))
About string buffer overflow, it expects 6 characters but you specify the rest of the parameters so ignore them:
pawn Код:
if (sscanf(params, "s[7]{s[50]}", action))
Just for your information, the string size is ignored in quite specifiers.
|
Thanks, but when I do it like this
Код:
if (!strcmp(item, "apple", true, 5))
I can do /trunk store apples 5 and it will work. Anything that contains "apple" will work.
And your way
Код:
if (!strcmp(item, "apple ", true, 6))
When I do /trunk store apple it won't give me that usage message, it will say "invalid item" instead. Only "apple " with a space gives me the usage message.
Re: sscanf quiet specifiers -
GoldenLion - 21.06.2017
Quote:
Originally Posted by ******
OK...
1) There is never a reason to use "sscanf" with only "s" - anyone who does this is doing it wrong. In your code:
PHP код:
if (sscanf(params, "s[7]", action))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk [action]");
if (!strcmp(action, "store", true))
That will never work because "s" is the last specifier, and if it is the last specifier it is NOT space delimited - it consumes all the remaining text. So instead of what you think this is doing, it is actually just trying to copy all of "params" in to a smaller array (hence warnings you may have got in the console about the string not being able to fit). Fortunately, the solution to both is an extra specifier - nothing:
PHP код:
if (sscanf(params, "s[7] ", action))
return SendClientMessage(playerid, COLOR_GREY, "USAGE: /trunk [action]");
if (!strcmp(action, "store", true))
A very simple change - from "s[7]" to "s[7] ". This is a little trick that means that "s" is no longer the last specifier and so won't consume all the string, but there is no real specifier after it.
2) Use sscanf searches:
PHP код:
new quantity;
if (!sscanf(params[5], "'apple'd", quantity))
{
}
else if (!sscanf(params[5], "'orange'd", quantity))
{
}
There "[5]" is the length of "store", so just skips right over the first word in the string - no need for more complex specifiers, just use normal language features.
|
Thank you!