formatex.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. // formatex.inc by Slice
  2. #include <a_samp>
  3. #if defined FORMAT_EXTRA_TAGS
  4. #define FORMAT_TAGS _, PlayerText3D, Text, Text3D, Menu, DB, DBResult, File, Float, FORMAT_EXTRA_TAGS
  5. #else
  6. #define FORMAT_TAGS _, PlayerText3D, Text, Text3D, Menu, DB, DBResult, File, Float
  7. #endif
  8. #if !defined FORMAT_BUFFER_SIZE
  9. #define FORMAT_BUFFER_SIZE 2048
  10. #endif
  11. #if !defined FORMAT_PRINT_BUFFER_SIZE
  12. #define FORMAT_PRINT_BUFFER_SIZE 512
  13. #endif
  14. #if !defined FORMAT_CUSTOM_SPEC_BUFFER_SIZE
  15. #define FORMAT_CUSTOM_SPEC_BUFFER_SIZE 512
  16. #endif
  17. #if !defined FORMAT_REPLACE_NATIVES
  18. #define FORMAT_REPLACE_NATIVES true
  19. #endif
  20. #define FormatSpecifier<'%1'>(%2[%3],%4) FMAT@1:F@%1(%2[FORMAT_CUSTOM_SPEC_BUFFER_SIZE],FMAT@2:___unused,%4)
  21. #define FMAT@2:___unused,%1[ %1[
  22. #define FMAT@1:%1(%2) forward %1(%2); public %1(%2)
  23. static stock
  24. gs_CustomFormatFunctions[127] = {-1, ...},
  25. bool:gs_bIsInitialized = false
  26. ;
  27. forward __fmt_funcinc();
  28. public __fmt_funcinc() {
  29. new szOutput[1];
  30. format(szOutput, 0, "");
  31. }
  32. static stock InitializeFormatSpecifiers() {
  33. new
  34. szFunctionName[4 char] = !"F@_",
  35. iIndex,
  36. iFunctionAddress
  37. ;
  38. gs_bIsInitialized = true;
  39. for (new c = '@'; c <= 'z'; c++) {
  40. // Skip the chars that can't be used in function names
  41. if (c == 'Z' + 1)
  42. c = '_';
  43. else if (c == '_' + 1)
  44. c = 'a';
  45. szFunctionName{2} = c;
  46. // Get the function's address if it exists
  47. if (-1 != (iIndex = funcidx(szFunctionName))) {
  48. #emit LCTRL 1
  49. #emit NEG
  50. #emit MOVE.alt
  51. #emit ADD.C 32
  52. #emit STOR.S.pri iFunctionAddress
  53. #emit LREF.S.pri iFunctionAddress
  54. #emit ADD
  55. #emit LOAD.S.alt iIndex
  56. #emit SHL.C.alt 3
  57. #emit ADD
  58. #emit STOR.S.pri iFunctionAddress
  59. #emit LREF.S.pri iFunctionAddress
  60. #emit STOR.S.pri iFunctionAddress
  61. gs_CustomFormatFunctions[c] = iFunctionAddress;
  62. }
  63. }
  64. }
  65. stock formatex(szOutput[], iLength = sizeof(szOutput), const szFormatString[], {FORMAT_TAGS}:...) {
  66. static
  67. s_szBuffer[FORMAT_BUFFER_SIZE],
  68. bool:s_bIsInCustomSpecifier = false
  69. ;
  70. // If formatex is called inside a custom specifier, the original "format" will be used
  71. // to prevent having s_szBuffer overwritten. Specifiers shouldn't depend on other specifiers, anyway.
  72. if (s_bIsInCustomSpecifier) {
  73. new
  74. iNumArgs,
  75. i
  76. ;
  77. #emit LOAD.S.pri 8
  78. #emit STOR.S.pri iNumArgs
  79. #emit SHR.C.pri 2
  80. #emit STOR.S.pri i
  81. while (--i >= 0) {
  82. #emit LOAD.S.pri i
  83. #emit SHL.C.pri 2
  84. #emit ADD.C 12
  85. #emit MOVE.alt
  86. #emit LCTRL 5
  87. #emit ADD
  88. #emit LOAD.I
  89. #emit PUSH.pri
  90. }
  91. #emit LOAD.S.pri iNumArgs
  92. #emit PUSH.pri
  93. #emit MOVE.alt
  94. #emit SYSREQ.C format
  95. #emit CONST.pri 4
  96. #emit ADD
  97. #emit MOVE.alt
  98. #emit LCTRL 4
  99. #emit ADD
  100. #emit SCTRL 4
  101. } else {
  102. new
  103. iPos = -1,
  104. iArg = 12 + (3 * 4),
  105. iArgCount,
  106. iAddress,
  107. iArgValue,
  108. aiArgs[128],
  109. i
  110. ;
  111. if (!gs_bIsInitialized)
  112. InitializeFormatSpecifiers();
  113. iLength = min(FORMAT_BUFFER_SIZE, iLength);
  114. s_szBuffer[0] = 0;
  115. strunpack(s_szBuffer, szFormatString);
  116. while (-1 != (iPos = strfind(s_szBuffer, !"%", _, ++iPos))) {
  117. while (s_szBuffer[++iPos]) {
  118. // Look for custom formats
  119. if (1 <= s_szBuffer[iPos] < sizeof(gs_CustomFormatFunctions) && gs_CustomFormatFunctions[s_szBuffer[iPos]] != -1) {
  120. new
  121. iFunc = gs_CustomFormatFunctions[s_szBuffer[iPos]]
  122. ;
  123. static
  124. s_szCustomFormatBuffer[FORMAT_CUSTOM_SPEC_BUFFER_SIZE]
  125. ;
  126. strdel(s_szBuffer, iPos - 1, iPos + 1);
  127. s_szCustomFormatBuffer[0] = 0;
  128. #emit LCTRL 5
  129. #emit LOAD.S.alt iArg
  130. #emit ADD
  131. #emit LOAD.I
  132. #emit MOVE.alt
  133. #emit LOAD.I
  134. #emit PUSH.pri
  135. #emit PUSH.alt
  136. iArg += 4;
  137. s_bIsInCustomSpecifier = true;
  138. #emit PUSH.C s_szCustomFormatBuffer
  139. #emit PUSH.C 12
  140. #emit LCTRL 6
  141. #emit ADD.C 28
  142. #emit PUSH.pri
  143. #emit LOAD.S.pri iFunc
  144. #emit SCTRL 6
  145. s_bIsInCustomSpecifier = false;
  146. strins(s_szBuffer, s_szCustomFormatBuffer, iPos - 1);
  147. break;
  148. }
  149. switch (s_szBuffer[iPos]) {
  150. // Handled by the original format function
  151. case '*', 'i', 'd', 'x', 'h', 'c', 's', 'f', 'b': {
  152. // Get the argument address and save it for later
  153. #emit LCTRL 5
  154. #emit LOAD.S.alt iArg
  155. #emit ADD
  156. #emit LOAD.I
  157. #emit STOR.S.pri iAddress
  158. #emit MOVE.pri
  159. #emit ADD.C 4
  160. #emit STOR.S.pri iArg
  161. aiArgs[iArgCount++] = iAddress;
  162. if (s_szBuffer[iPos] == '*')
  163. continue;
  164. break;
  165. }
  166. // Unsigned numbers
  167. case 'u': {
  168. new
  169. szBuffer[11]
  170. ;
  171. #emit LCTRL 5
  172. #emit LOAD.S.alt iArg
  173. #emit ADD
  174. #emit LOAD.I
  175. #emit LOAD.I
  176. #emit STOR.S.pri iArgValue
  177. #emit MOVE.pri
  178. #emit ADD.C 4
  179. #emit STOR.S.pri iArg
  180. strdel(s_szBuffer, iPos - 1, iPos + 1);
  181. if (!iArgValue) {
  182. strins(s_szBuffer, "0", iPos - 1);
  183. } else {
  184. new
  185. j = sizeof(szBuffer) - 1
  186. ;
  187. while (iArgValue) {
  188. // szBuffer[--i]
  189. #emit ADDR.alt szBuffer // alt = *szBuffer
  190. #emit LOAD.S.pri j // pri = i
  191. #emit DEC.pri // pri -= 1
  192. #emit STOR.S.pri j // i = pri
  193. #emit IDXADDR // pri = alt + i * 4
  194. #emit PUSH.pri // Store pri for later
  195. // Now do an unsigned divide on uValue then use both the quotient and remainder!
  196. #emit LOAD.S.pri iArgValue // pri = uValue
  197. #emit CONST.alt 10
  198. #emit UDIV // pri = uValue / 10; alt = uValue % 10
  199. #emit STOR.S.pri iArgValue // uValue = pri
  200. #emit CONST.pri '0'
  201. #emit ADD // pri = '0' + (uValue % 10)
  202. #emit POP.alt // alt = szBuffer[i]
  203. #emit STOR.I // szBuffer[i] = pri
  204. }
  205. strins(s_szBuffer, szBuffer[j], iPos - 1);
  206. }
  207. }
  208. case '0' .. '9', ' ', '.':
  209. continue;
  210. case '%':
  211. break;
  212. default: {
  213. break;
  214. }
  215. }
  216. }
  217. }
  218. i = iArgCount;
  219. // Push the arguments we stored above
  220. while (--i >= 0) {
  221. #emit ADDR.alt aiArgs
  222. #emit LOAD.S.pri i
  223. #emit LIDX
  224. #emit PUSH.pri
  225. #emit STOR.S.pri iAddress
  226. }
  227. // New format specifier
  228. #emit PUSH.C s_szBuffer
  229. // Max length
  230. #emit PUSH.S iLength
  231. // Output string
  232. #emit PUSH.S szOutput
  233. // Argument count
  234. #emit LOAD.S.pri iArgCount
  235. #emit SHL.C.pri 2
  236. #emit ADD.C 12
  237. #emit PUSH.pri
  238. // Save the argument count for later
  239. #emit MOVE.alt
  240. // Call format (duh)
  241. #emit SYSREQ.C format
  242. // Add 4 to the argument count
  243. #emit CONST.pri 4
  244. #emit ADD
  245. #emit MOVE.alt
  246. // Remove <argument count> from the stack
  247. #emit LCTRL 4
  248. #emit ADD
  249. #emit SCTRL 4
  250. }
  251. // Return in case anyone uses it
  252. return 1;
  253. }
  254. stock printfex(const szFormatString[], {FORMAT_TAGS}:...) {
  255. const
  256. iBufferSize = FORMAT_PRINT_BUFFER_SIZE
  257. ;
  258. static
  259. s_szBuffer[FORMAT_PRINT_BUFFER_SIZE]
  260. ;
  261. new
  262. iNumArgs = numargs(),
  263. i = iNumArgs - 1
  264. ;
  265. while (--i >= 0) {
  266. #emit LOAD.S.pri i
  267. #emit SHL.C.pri 2
  268. #emit ADD.C 16
  269. #emit MOVE.alt
  270. #emit LCTRL 5
  271. #emit ADD
  272. #emit LOAD.I
  273. #emit PUSH.pri
  274. }
  275. #emit PUSH.S szFormatString
  276. #emit PUSH.C iBufferSize
  277. #emit PUSH.C s_szBuffer
  278. #emit LOAD.S.pri iNumArgs
  279. #emit SHL.C.pri 2
  280. #emit ADD.C 8
  281. #emit PUSH.pri
  282. #emit LCTRL 6
  283. #emit ADD.C 28
  284. #emit PUSH.pri
  285. #emit CONST.pri formatex
  286. #emit SCTRL 6
  287. print(s_szBuffer);
  288. }
  289. // -----------------------------------------------------------------------------------------------------
  290. // Specifiers
  291. // -----------------------------------------------------------------------------------------------------
  292. // Inline color
  293. FormatSpecifier<'C'>(output[], color) {
  294. format(output, sizeof(output), "{%06x}", color >>> 8);
  295. }
  296. // Player name
  297. FormatSpecifier<'p'>(output[], playerid) {
  298. if (0 <= playerid < GetMaxPlayers() && IsPlayerConnected(playerid))
  299. GetPlayerName(playerid, output, sizeof(output));
  300. else
  301. strcat(output, "<UNKNOWN>");
  302. }
  303. // Player name and color
  304. FormatSpecifier<'P'>(output[], playerid) {
  305. if (0 <= playerid < GetMaxPlayers() && IsPlayerConnected(playerid)) {
  306. format(output, sizeof(output), "{%06x}", GetPlayerColor(playerid) >>> 8);
  307. GetPlayerName(playerid, output[8], sizeof(output) - 8);
  308. } else
  309. strcat(output, "{FFFFFF}<UNKNOWN>");
  310. }
  311. // Weapon name
  312. FormatSpecifier<'W'>(output[], weapon) {
  313. static const
  314. s_WeaponNames[][] = {
  315. {!"Fists" }, {!"Knuckles" }, {!"Golfclub" }, // 0, 1, 2
  316. {!"Nightstick" }, {!"Knife" }, {!"Bat" }, // 3, 4, 5
  317. {!"Shovel" }, {!"Pool Cue" }, {!"Katana" }, // 6, 7, 8
  318. {!"Chainsaw" }, {!"Dildo" }, {!"Vibrator" }, // 9, 10, 11
  319. {!"Vibrator" }, {!"Vibrator" }, {!"Flowers" }, // 12, 13, 14
  320. {!"Cane" }, {!"Grenade" }, {!"Teargas" }, // 15, 16, 17
  321. {!"Molotov" }, {!"" }, {!"" }, // 18, ,
  322. {!"" }, {!"9mm" }, {!"Silenced Pistol"}, // , 22, 23
  323. {!"Deagle" }, {!"Shotgun" }, {!"Sawnoffs" }, // 24, 25, 26
  324. {!"Combat Shotgun" }, {!"Mac-10" }, {!"MP5" }, // 27, 28, 29
  325. {!"AK-47" }, {!"M4" }, {!"Tec-9" }, // 30, 31, 32
  326. {!"Cuntgun" }, {!"Sniper" }, {!"Rocketlauncher" }, // 33, 34, 35
  327. {!"Heatseeking RPG"}, {!"Flamethrower"}, {!"Minigun" }, // 36, 37, 38
  328. {!"Satchel" }, {!"Detonator" }, {!"Spraycan" }, // 39, 40, 41
  329. {!"Extinguisher" }, {!"Camera" }, {!"Nightvision" }, // 42, 43, 44
  330. {!"Infrared" }, {!"Parachute" }, {!"Fake Pistol" }, // 45, 46, 47
  331. {!"" }, {!"Vehicle" }, {!"Helikill" }, // , 49, 50
  332. {!"Explosion" }, {!"" }, {!"Drown" }, // 51, , 53
  333. {!"Collision" }, {!"Splat" }, {!"Unknown" } // 54, 55, 56
  334. }
  335. ;
  336. if (0 <= weapon < sizeof(s_WeaponNames))
  337. strcat(output, s_WeaponNames[weapon]);
  338. else
  339. strcat(output, "Unknown");
  340. }
  341. // Weapon name, lower-case singular (for sentences)
  342. FormatSpecifier<'w'>(output[], weapon) {
  343. static const
  344. s_WeaponNamesLowercaseSingular[][] = {
  345. {!"fists" }, {!"knuckles" }, {!"a golfclub" }, // 0, 1, 2
  346. {!"a nightstick" }, {!"a knife" }, {!"a bat" }, // 3, 4, 5
  347. {!"a shovel" }, {!"a pool cue" }, {!"a katana" }, // 6, 7, 8
  348. {!"a chainsaw" }, {!"a dildo" }, {!"a vibrator" }, // 9, 10, 11
  349. {!"a vibrator" }, {!"a vibrator" }, {!"flowers" }, // 12, 13, 14
  350. {!"a cane" }, {!"a grenade" }, {!"teargas" }, // 15, 16, 17
  351. {!"a molotov" }, {!"" }, {!"" }, // 18, ,
  352. {!"" }, {!"a 9mm" }, {!"a silenced pistol"}, // , 22, 23
  353. {!"a deagle" }, {!"a shotgun" }, {!"sawnoffs" }, // 24, 25, 26
  354. {!"a combat shotgun" }, {!"a mac-10" }, {!"an mp5" }, // 27, 28, 29
  355. {!"an ak-47" }, {!"an m4" }, {!"a tec-9" }, // 30, 31, 32
  356. {!"a cuntgun" }, {!"a sniper" }, {!"a rocketlauncher" }, // 33, 34, 35
  357. {!"a heatseeking rpg" }, {!"a flamethrower"}, {!"a minigun" }, // 36, 37, 38
  358. {!"a satchel" }, {!"a detonator" }, {!"a spraycan" }, // 39, 40, 41
  359. {!"an extinguisher" }, {!"a camera" }, {!"nightvision" }, // 42, 43, 44
  360. {!"an infrared" }, {!"a parachute" }, {!"a fake pistol" }, // 45, 46, 47
  361. {!"" }, {!"a vehicle" }, {!"a helikill" }, // , 49, 50
  362. {!"an explosion" }, {!"" }, {!"drowning" }, // 51, , 53
  363. {!"a collision" }, {!"a splat" }, {!"something unknown"} // 54, 55, 56
  364. }
  365. ;
  366. if (0 <= weapon < sizeof(s_WeaponNamesLowercaseSingular))
  367. strcat(output, s_WeaponNamesLowercaseSingular[weapon]);
  368. else
  369. strcat(output, "something unknown");
  370. }
  371. // Vehicle name
  372. FormatSpecifier<'v'>(output[], modelid) {
  373. static const
  374. s_VehicleNames[][] = {
  375. {!"Landstalker" }, {!"Bravura" }, {!"Buffalo" }, {!"Linerunner" },
  376. {!"Perrenial" }, {!"Sentinel" }, {!"Dumper" }, {!"Firetruck" },
  377. {!"Trashmaster" }, {!"Stretch" }, {!"Manana" }, {!"Infernus" },
  378. {!"Voodoo" }, {!"Pony" }, {!"Mule" }, {!"Cheetah" },
  379. {!"Ambulance" }, {!"Leviathan" }, {!"Moonbeam" }, {!"Esperanto" },
  380. {!"Taxi" }, {!"Washington" }, {!"Bobcat" }, {!"Mr Whoopee" },
  381. {!"BF Injection" }, {!"Hunter" }, {!"Premier" }, {!"Enforcer" },
  382. {!"Securicar" }, {!"Banshee" }, {!"Predator" }, {!"Bus" },
  383. {!"Rhino" }, {!"Barracks" }, {!"Hotknife" }, {!"Trailer 1" },
  384. {!"Previon" }, {!"Coach" }, {!"Cabbie" }, {!"Stallion" },
  385. {!"Rumpo" }, {!"RC Bandit" }, {!"Romero" }, {!"Packer" },
  386. {!"Monster" }, {!"Admiral" }, {!"Squalo" }, {!"Seasparrow" },
  387. {!"Pizzaboy" }, {!"Tram" }, {!"Trailer 2" }, {!"Turismo" },
  388. {!"Speeder" }, {!"Reefer" }, {!"Tropic" }, {!"Flatbed" },
  389. {!"Yankee" }, {!"Caddy" }, {!"Solair" }, {!"Berkley's RC Van" },
  390. {!"Skimmer" }, {!"PCJ-600" }, {!"Faggio" }, {!"Freeway" },
  391. {!"RC Baron" }, {!"RC Raider" }, {!"Glendale" }, {!"Oceanic" },
  392. {!"Sanchez" }, {!"Sparrow" }, {!"Patriot" }, {!"Quad" },
  393. {!"Coastguard" }, {!"Dinghy" }, {!"Hermes" }, {!"Sabre" },
  394. {!"Rustler" }, {!"ZR-350" }, {!"Walton" }, {!"Regina" },
  395. {!"Comet" }, {!"BMX" }, {!"Burrito" }, {!"Camper" },
  396. {!"Marquis" }, {!"Baggage" }, {!"Dozer" }, {!"Maverick" },
  397. {!"News Chopper" }, {!"Rancher" }, {!"FBI Rancher" }, {!"Virgo" },
  398. {!"Greenwood" }, {!"Jetmax" }, {!"Hotring" }, {!"Sandking" },
  399. {!"Blista Compact" }, {!"Police Maverick" }, {!"Boxville" }, {!"Benson" },
  400. {!"Mesa" }, {!"RC Goblin" }, {!"Hotring Racer A" }, {!"Hotring Racer B" },
  401. {!"Bloodring Banger" }, {!"Rancher" }, {!"Super GT" }, {!"Elegant" },
  402. {!"Journey" }, {!"Bike" }, {!"Mountain Bike" }, {!"Beagle" },
  403. {!"Cropdust" }, {!"Stunt" }, {!"Tanker" }, {!"Roadtrain" },
  404. {!"Nebula" }, {!"Majestic" }, {!"Buccaneer" }, {!"Shamal" },
  405. {!"Hydra" }, {!"FCR-900" }, {!"NRG-500" }, {!"HPV1000" },
  406. {!"Cement Truck" }, {!"Tow Truck" }, {!"Fortune" }, {!"Cadrona" },
  407. {!"FBI Truck" }, {!"Willard" }, {!"Forklift" }, {!"Tractor" },
  408. {!"Combine" }, {!"Feltzer" }, {!"Remington" }, {!"Slamvan" },
  409. {!"Blade" }, {!"Freight" }, {!"Streak" }, {!"Vortex" },
  410. {!"Vincent" }, {!"Bullet" }, {!"Clover" }, {!"Sadler" },
  411. {!"Firetruck LA" }, {!"Hustler" }, {!"Intruder" }, {!"Primo" },
  412. {!"Cargobob" }, {!"Tampa" }, {!"Sunrise" }, {!"Merit" },
  413. {!"Utility" }, {!"Nevada" }, {!"Yosemite" }, {!"Windsor" },
  414. {!"Monster A" }, {!"Monster B" }, {!"Uranus" }, {!"Jester" },
  415. {!"Sultan" }, {!"Stratum" }, {!"Elegy" }, {!"Raindance" },
  416. {!"RC Tiger" }, {!"Flash" }, {!"Tahoma" }, {!"Savanna" },
  417. {!"Bandito" }, {!"Freight Flat" }, {!"Streak Carriage" }, {!"Kart" },
  418. {!"Mower" }, {!"Duneride" }, {!"Sweeper" }, {!"Broadway" },
  419. {!"Tornado" }, {!"AT-400" }, {!"DFT-30" }, {!"Huntley" },
  420. {!"Stafford" }, {!"BF-400" }, {!"Newsvan" }, {!"Tug" },
  421. {!"Trailer 3" }, {!"Emperor" }, {!"Wayfarer" }, {!"Euros" },
  422. {!"Hotdog" }, {!"Club" }, {!"Freight Carriage" }, {!"Trailer 3" },
  423. {!"Andromada" }, {!"Dodo" }, {!"RC Cam" }, {!"Launch" },
  424. {!"Police Car (LSPD)"}, {!"Police Car (SFPD)"}, {!"Police Car (LVPD)"}, {!"Police Ranger" },
  425. {!"Picador" }, {!"S.W.A.T. Van" }, {!"Alpha" }, {!"Phoenix" },
  426. {!"Glendale" }, {!"Sadler" }, {!"Luggage Trailer A"}, {!"Luggage Trailer B"},
  427. {!"Stair Trailer" }, {!"Boxville" }, {!"Farm Plow" }, {!"Utility Trailer" }
  428. }
  429. ;
  430. if (0 <= (modelid -= 400) < sizeof(s_VehicleNames))
  431. strcat(output, s_VehicleNames[modelid]);
  432. else
  433. strcat(output, "Unknown");
  434. }
  435. // Unsigned 4-byte hex
  436. FormatSpecifier<'X'>(output[], value) {
  437. format(output, sizeof(output), "%02x%06x", value >>> 24, value & 0xFFFFFF);
  438. }
  439. // Do this last so the specifiers always use the native function
  440. #if FORMAT_REPLACE_NATIVES
  441. #define format formatex
  442. #define printf printfex
  443. #endif