Slice's formatex because it doesn't have a GitHub repo.
Original thread: http://forum.sa-mp.com/showthread.php?t=313488
All credits to Slice/oscar-broman
The original library wasn't shipped with an explicit license but I'm sure, in the spirit of Open Source, Slice is happy to have this redistributed via GitHub - if not, let me know!
Simply install to your project:
sampctl package install Southclaws/formatex
Include in your code and begin using the library:
#include <formatex>
Hey,
After seeing a great new feature in sscanf that allows you to create custom specifiers, I figured it was only right to do the same to format and printf!
For example, the following code could be made a lot shorter:
// This will put into "msg" the weapon you were given by a player, and the color of the player's name will match the player's color.
new msg[128], name[MAX_PLAYER_NAME], color;
color = GetPlayerColor(playerid);
GetPlayerName(playerid, name, sizeof(name));
format(msg, sizeof(msg), "You were given a %s by {%06x}%s", g_WeaponNameArray[weapon], color >>> 8, name);
This will do the same thing:
new msg[128];
format(msg, _, "You were given %w by %P", weapon, playerid);
// msg is for example: You were given an M4 by Slice
Specifier | Description |
---|---|
%p | Name of the player ID given. |
%P | Name of the player ID given, with the player's color before it. |
%C | Inline color (ex. {FFFFFF}) from a normal color (ex. colors you get from GetPlayerColor). |
%v | Vehicle model name from the model given (not vehicle ID, vehicle model). |
%w | Weapon name, lower-case singular (to be used in sentences). Example: "an M4", "a combat shotgun", "a knife". |
%W | Weapon's name. |
%X | 8-byte, unsigned hex string (ex. FFFFFFFF). |
%u | Unsigned integer. |
You can do this very easily; example of one that puts an upper-case string at %S: Add this anywhere outside of a function:
// Upper-case string
FormatSpecifier<'S'>(output[], const param[]) {
for (new i = 0, l = min(sizeof(output), strlen(param)); i < l; i++)
output[i] = toupper(param[i]);
}
You can now do this:
printf("hello %S!", "world");
// prints: hello WORLD!
If you want an integer, float, or anything else instead of a string you just change it:
// You can call the argument whatever you like, and it can be a string/array:
FormatSpecifier<'A'>(output[], Float:health) { ... }
FormatSpecifier<'B'>(output[], objectid) { ... }
FormatSpecifier<'C'>(output[], playerid) { ... }
FormatSpecifier<'D'>(output[], Text:td) { ... }
FormatSpecifier<'D'>(output[], const string[]) { ... }
formatex allows you to customize the fallback return value of the following specifiers; %P
, %p
, %W
, %w
, and %v
:
#define FORMAT_FALLBACK_P "No player found"
#define FORMAT_FALLBACK_p "{ABCDEF}void!!!"
#define FORMAT_FALLBACK_W "Tis aint murica"
#define FORMAT_FALLBACK_w "Ammunation"
#define FORMAT_FALLBACK_v "Vrum Vrum much?"
#include "formatex.inc"
main() {
// Passing an invalid playerid
printf("%%P: %P", INVALID_PLAYER_ID);
// Passing an invalid playerid
printf("%%p: %p", -59);
// Passing an invalid weaponid
printf("%%W: %W", 9250);
// Passing an invalid weaponid
printf("%%w: %w", -560);
// Passing an invalid vehicleid
printf("%%v: %v", 10);
}
Output:
%P: No player found
%p: {ABCDEF}void!!!
%W: Tis aint murica
%w: Ammunation
%v: Vrum Vrum much?
In the default format specifiers you can add with and precision using %5.2i
, or make them dynamic with %*.*i
. You can also left-pad with -
or naught-pad with 0
: %-7i
, %03.*i
. These options are all supported as additional parameters to the custom specifiers:
// Upper-case string
FormatSpecifier<'S'>(output[], const param[], width, precision, E_FORMATEX_FLAGS:flags) {
for (new i = 0, l = min(sizeof(output), strlen(param)); i < l; i++)
output[i] = toupper(param[i]);
FormatFlags(output, width, precision, flags);
}
Using FormatFlags
will apply standard paddings to the string, more custom code will have to use the parameters directly. FormatFlags
also takes an extra reverse
parameter. With padding %5i
pads to the left, but %5s
pads to the right, so the former will give 5
while the latter will give hi
. reverse
replicates the string padding method (and -
switches either one).
Worth mentioning is this is a superset of format, meaning it has exactly all the features of format and those behave like always (the only exception is it's a bit friendlier to packed strings, though %s still doesn't support it).
It actually uses the original native "format" function to do the heavy lifting.