Advertisement
Guest User

Untitled

a guest
Jan 23rd, 2020
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 35.09 KB | None | 0 0
  1. // Clock System
  2.  
  3. enum string_edges {
  4. edge_left = 1,
  5. edge_right = 2,
  6. edge_both = edge_left | edge_right
  7. };
  8.  
  9. stock const MONTH_DAY[][] = {
  10. "January", "February", "March", "April",
  11. "May", "June", "July", "August", "September", "October",
  12. "November","December"
  13. }
  14. ;
  15.  
  16. stock const MONTH_DAY_SHORT[][] = {
  17. "Jan", "Feb", "Mar", "Apr",
  18. "May", "Jun", "Jul", "Aug", "Sep", "Oct",
  19. "Nov","Dec"
  20. }
  21. ;
  22.  
  23. stock const MONTH_DAY_TH[][] = {
  24. "มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน",
  25. "พฤษภาคม", "มิถุนายน", "กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม",
  26. "พฤศจิกายน","ธันวาคม"
  27. }
  28. ;
  29.  
  30. stock const MONTH_DAY_SHORT_TH[][] = {
  31. "ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.",
  32. "พ.ค.", "มิ.ย.", "ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.",
  33. "พ.ย.","ธ.ค."
  34. }
  35. ;
  36.  
  37. #if !defined STRLIB_USE_FORMATEX
  38. #if defined __fmt_funcinc
  39. #if !defined FormatSpecifier
  40. #error Please include formatex before strlib.
  41. #endif
  42.  
  43. #define STRLIB_USE_FORMATEX true
  44. #else
  45. #define STRLIB_USE_FORMATEX false
  46. #endif
  47. #endif
  48.  
  49. #if !defined STRLIB_RETURN_SIZE
  50. #define STRLIB_RETURN_SIZE 128
  51. #endif
  52.  
  53. // Clock System
  54. new Text:ui_clock;
  55.  
  56. public OnGameModeInit()
  57. {
  58. // Clock System
  59.  
  60. ui_clock = TextDrawCreate(618.000000, 6.000000, "~y~6 May ~w~18:50:07");
  61. TextDrawFont(ui_clock, 3);
  62. TextDrawLetterSize(ui_clock, 0.487497, 1.349997);
  63. TextDrawTextSize(ui_clock, 400.000000, 18.500000);
  64. TextDrawSetOutline(ui_clock, 2);
  65. TextDrawSetShadow(ui_clock, 0);
  66. TextDrawAlignment(ui_clock, 3);
  67. TextDrawColor(ui_clock, -1);
  68. TextDrawBackgroundColor(ui_clock, 255);
  69. TextDrawBoxColor(ui_clock, 50);
  70. TextDrawUseBox(ui_clock, 0);
  71. TextDrawSetProportional(ui_clock, 1);
  72. TextDrawSetSelectable(ui_clock, 0);
  73.  
  74. SetTimer("UI_UpdateTimerSetTimer", 1000, 1);
  75. }
  76.  
  77. public OnPlayerSpawn(playerid)
  78. {
  79. // Clock System
  80. TextDrawShowForPlayer(playerid, ui_clock);
  81. }
  82.  
  83. // Clock System
  84.  
  85. GetRealTime(&hours, &minutes, &seconds, timezone_offset = 0) {
  86. gettime(hours, minutes, seconds);
  87. hours += timezone_offset;
  88. hours = hours < 0 ? (hours + 24) : hours;
  89. hours = hours > 23 ? (hours - 24) : hours;
  90. }
  91.  
  92. stock sprintf(const fmat[], {Float, _}:...) {
  93. static output[STRLIB_RETURN_SIZE], frm_header[3], heap;
  94.  
  95. const output_size = sizeof(output);
  96.  
  97. if (ispacked(fmat)) {
  98. heap = CopyArgumentToHeap(0);
  99. } else {
  100. heap = 0;
  101. }{}
  102.  
  103. // Store current frame header
  104. #emit LCTRL 5
  105. #emit CONST.alt frm_header
  106. #emit MOVS 12
  107.  
  108. // Change the stack pointer to FRM + 12
  109. #emit ADD.C 12 // pri is FRM (see above)
  110. #emit SCTRL 4
  111.  
  112. // Push sizeof(output)
  113. #emit PUSH.C output_size
  114.  
  115. // Push output
  116. #emit PUSH.C output
  117.  
  118. // Push the argument count
  119. #emit LOAD.S.pri 8
  120. #emit ADD.C 8
  121. #emit PUSH.pri
  122.  
  123. #if !STRLIB_USE_FORMATEX
  124. const formatex = 0; // Dummy used to avoid "unknown symbol" error
  125.  
  126. goto do_sysreq;
  127. #endif
  128.  
  129. // Call formatex (unless this was skipped above)
  130. #emit LCTRL 6
  131. #emit ADD.C 36
  132. #emit PUSH.pri
  133. #emit CONST.pri formatex
  134. #emit SCTRL 6
  135.  
  136. #if !STRLIB_USE_FORMATEX
  137. do_sysreq:
  138. #endif
  139.  
  140. // Call format (unless formatex was called, in which case this is skipped)
  141. #emit SYSREQ.C format
  142.  
  143. // Restore the stack pointer to FRM
  144. #emit LCTRL 5
  145. #emit SCTRL 4
  146.  
  147. // Copy back the frame header
  148. #emit MOVE.alt
  149. #emit CONST.pri frm_header
  150. #emit MOVS 12
  151.  
  152. // Restore heap if needed
  153. if (heap) {
  154. RestoreHeapToAddress(heap);
  155. }{}
  156.  
  157. // IMPORTANT: Fix compiler bug (returning strings in variadic functions)
  158. #emit LOAD.S.pri 8
  159. #emit ADD.C 12
  160. #emit MOVE.alt
  161. #emit LCTRL 5
  162. #emit ADD
  163. #emit LOAD.I
  164. #emit STOR.S.pri 20 // 16 + (static_args * 4)
  165.  
  166. return output;
  167.  
  168. // It is actually used, just not by its symbol name
  169. #pragma unused fmat
  170. }
  171.  
  172. forward UI_UpdateTimer(playerid);
  173. public UI_UpdateTimer(playerid)
  174. {
  175. new hHours, hMins, hSecs;
  176. new year, month,day;
  177. getdate(year, month, day);
  178. GetRealTime(hHours, hMins, hSecs);
  179. TextDrawSetString(ui_clock, sprintf("~y~%d %s ~w~%02d:%02d:%02d", day, MONTH_DAY_SHORT[month-1], hHours, hMins, hSecs));
  180.  
  181. return 1;
  182. }
  183.  
  184. // Internal functions
  185. static stock RedirectArgument(arg, ...) {
  186. #emit LOAD.S.pri 0
  187. #emit ADD.C 12
  188. #emit LOAD.S.alt arg
  189. #emit SHL.C.alt 2
  190. #emit ADD
  191. #emit MOVE.alt
  192. #emit LOAD.S.pri 16
  193. #emit STOR.I
  194. }
  195.  
  196. static stock CopyArgumentToHeap(arg, bool:pack = false, const argptr[] = "") {
  197. new arg_address, address;
  198.  
  199. #emit LOAD.S.pri 0
  200. #emit ADD.C 12
  201. #emit LOAD.S.alt arg
  202. #emit SHL.C.alt 2
  203. #emit ADD
  204. #emit LOAD.I
  205. #emit STOR.S.pri arg_address
  206. #emit STOR.S.pri argptr
  207.  
  208. if (pack) {
  209. new bytes = ((strlen(argptr) + 1 + 3) / 4) * 4;
  210.  
  211. #emit LCTRL 2
  212. #emit STOR.S.pri address
  213. #emit LOAD.S.alt bytes
  214. #emit ADD
  215. #emit SCTRL 2
  216.  
  217. //strpack(dest[], const source[], maxlength = sizeof dest)
  218. #emit LOAD.S.pri bytes
  219. #emit SHR.C.pri 2
  220. #emit PUSH.pri
  221.  
  222. #emit PUSH.S arg_address
  223. #emit PUSH.S address
  224.  
  225. #emit PUSH.C 12
  226.  
  227. #emit SYSREQ.C strpack
  228. #emit STACK 16
  229. } else {
  230. new bytes = (strlen(argptr) + 1) * 4;
  231.  
  232. #emit LCTRL 2
  233. #emit STOR.S.pri address
  234. #emit LOAD.S.alt bytes
  235. #emit ADD
  236. #emit SCTRL 2
  237.  
  238. //strunpack(dest[], const source[], maxlength = sizeof dest)
  239. #emit LOAD.S.pri bytes
  240. #emit SHR.C.pri 2
  241. #emit PUSH.pri
  242.  
  243. #emit PUSH.S arg_address
  244. #emit PUSH.S address
  245.  
  246. #emit PUSH.C 12
  247.  
  248. #emit SYSREQ.C strunpack
  249. #emit STACK 16
  250. }
  251.  
  252. #emit LOAD.S.pri 0
  253. #emit ADD.C 12
  254. #emit LOAD.S.alt arg
  255. #emit SHL.C.alt 2
  256. #emit ADD
  257. #emit MOVE.alt
  258. #emit LOAD.S.pri address
  259. #emit STOR.I
  260.  
  261. return address;
  262. }
  263.  
  264. static stock RestoreHeapToAddress(address) {
  265. #emit LOAD.S.pri address
  266. #emit SCTRL 2
  267. }
  268.  
  269. static stock IsOverlapping(const str1[], size1 = sizeof(str1), const str2[], size2 = sizeof(str2)) {
  270. new addr1, addr2;
  271.  
  272. if (size1 == -1) {
  273. size1 = strsize(str1);
  274. } else {
  275. size1 *= 4;
  276. }
  277.  
  278. if (size2 == -1) {
  279. size2 = strsize(str2);
  280. } else {
  281. size2 *= 4;
  282. }
  283.  
  284. #emit LOAD.S.pri str1
  285. #emit STOR.S.pri addr1
  286. #emit LOAD.S.pri str2
  287. #emit STOR.S.pri addr2
  288.  
  289. return (addr1 < addr2 + size2) && (addr2 < addr1 + size1);
  290. }
  291.  
  292. // strlib functions
  293. #define ispacked(%1) \
  294. ((%1)[0] > 255)
  295.  
  296. stock strgetfirstc(const string[]) {
  297. return ispacked(string) ? string{0} : string[0];
  298. }
  299.  
  300. stock strgetc(const string[], index) {
  301. if (index < 0)
  302. return '\0';
  303.  
  304. new len = strlen(string);
  305.  
  306. if (index >= len)
  307. return '\0';
  308.  
  309. return ispacked(string) ? string{index} : string[index];
  310. }
  311.  
  312. stock strsize(const string[]) {
  313. new len = strlen(string);
  314.  
  315. if (ispacked(string))
  316. return len + 1;
  317.  
  318. return (len + 1) * 4;
  319. }
  320.  
  321. stock bool:isempty(const string[]) {
  322. if (ispacked(string))
  323. return string{0} == '\0';
  324. else
  325. return string[0] == '\0';
  326. }
  327.  
  328. stock bool:isequal(const str1[], const str2[], bool:ignorecase = false) {
  329. new
  330. c1 = (str1[0] > 255) ? str1{0} : str1[0],
  331. c2 = (str2[0] > 255) ? str2{0} : str2[0]
  332. ;
  333.  
  334. if (!c1 != !c2)
  335. return false;
  336.  
  337. return !strcmp(str1, str2, ignorecase);
  338. }
  339.  
  340. stock strdistance(const str1[], const str2[], bool:ignorecase = false) {
  341. // If they are equal, theres no distance anyways
  342. if(isequal(str1, str2, ignorecase))
  343. return 0;
  344.  
  345. static data[128][128];
  346.  
  347. new bool:pack1 = ispacked(str1),
  348. bool:pack2 = ispacked(str2);
  349.  
  350. new size1 = strlen(str1),
  351. size2 = strlen(str2);
  352.  
  353. // Zero-length strings would return the size of the other string, because it's that many insertions
  354. if (size1 == 0)
  355. return size2;
  356.  
  357. if (size2 == 0)
  358. return size1;
  359.  
  360. // Intitalize data array
  361. for (new i; i <= size1; i++)
  362. data[i][0] = i;
  363.  
  364. for (new j; j <= size2; j++)
  365. data[0][j] = j;
  366.  
  367. // Loop through both strings, comparing each character to each character in the other string (think matrix)
  368. for (new j = 1; j <= size2; j++) {
  369. for (new i = 1; i <= size1; i++) {
  370. new char1 = pack1 ? str1{i - 1} : str1[i - 1],
  371. char2 = pack2 ? str2{j - 1} : str2[j - 1];
  372.  
  373. // If ignorecase, make chars lower case.
  374. if(ignorecase) {
  375. if (65 <= char1 <= 90)
  376. char1 += 32;
  377.  
  378. if (65 <= char2 <= 90)
  379. char2 += 32;
  380. }
  381.  
  382. if (char1 == char2)
  383. data[i][j] = data[i - 1][j - 1];
  384. else {
  385. new l1 = data[i - 1][j] + 1,
  386. l2 = data[i][j - 1] + 1,
  387. l3 = data[i - 1][j - 1] + 1;
  388.  
  389. l2 = (l1 > l2 ? l2 : l1);
  390. data[i][j] = (l3 > l2 ? l2 : l3);
  391. }
  392. }
  393. }
  394.  
  395. return data[size1][size2];
  396. }
  397.  
  398. stock strimplode(const glue[], output[], maxlength = sizeof(output), ...) {
  399. new args = numargs();
  400.  
  401. // Null-out "output"
  402. output[0] = '\0';
  403.  
  404. // Loop the variable arguments (the ones after "maxlength").
  405. for (new arg = 3; arg < args; arg++) {
  406. // If this isn't the first string, append the glue.
  407. if (arg != 3)
  408. strcat(output, glue, maxlength);
  409.  
  410. // Wrap these in braces or they will be a part of the above if statement (compiler bug)
  411. {
  412. // Get the address of argument no. <arg>
  413. #emit LCTRL 5
  414. #emit ADD.C 12
  415. #emit LOAD.S.alt arg
  416. #emit SHL.C.alt 2
  417. #emit ADD
  418. #emit LOAD.I
  419.  
  420. // Push the maxlength, arg address, and output address
  421. #emit PUSH.S maxlength
  422. #emit PUSH.pri
  423. #emit PUSH.S output
  424.  
  425. // Push the argument count
  426. #emit PUSH.C 12
  427.  
  428. // call strcat
  429. #emit SYSREQ.C strcat
  430.  
  431. // Restore the stack
  432. #emit STACK 16
  433. }
  434. }
  435. }
  436.  
  437. stock strexplode(output[][], const input[], const delimiter[] = !",", limit = cellmax, bool:trim = true, bool:ignorecase = false, size1 = sizeof(output), size2 = sizeof(output[])) {
  438. if (!size1 || !size2) {
  439. printf("(strexplode) ERROR: size1 = %d, size2 = %d. Can't be 0.", size1, size2);
  440.  
  441. return 0;
  442. }
  443.  
  444. if (isempty(delimiter)) {
  445. print(!"(strexplode) ERROR: delimiter is empty.");
  446.  
  447. return 0;
  448. }
  449.  
  450. if (trim) {
  451. new i = -1;
  452.  
  453. if (ispacked(input)) {
  454. while (input{++i}) {
  455. if (input{i} > ' ') {
  456. i = -1;
  457.  
  458. break;
  459. }
  460. }
  461. } else {
  462. while (input[++i]) {
  463. if (input[i] > ' ') {
  464. i = -1;
  465.  
  466. break;
  467. }
  468. }
  469. }
  470.  
  471. if (i != -1)
  472. return 0;
  473. } else if (isempty(input)) {
  474. return 0;
  475. }
  476.  
  477. if (limit == 0) {
  478. return 0;
  479. } else if (limit == cellmax) {
  480. limit = 0;
  481. }
  482.  
  483. new
  484. pos = 0,
  485. next,
  486. bool:packed = ispacked(input),
  487. dlen = strlen(delimiter),
  488. count = 0,
  489. end
  490. ;
  491.  
  492. while (pos != -1) {
  493. ++count;
  494.  
  495. if (limit > 0 && count >= limit) {
  496. next = -1;
  497. } else {
  498. next = strfind(input, delimiter, ignorecase, pos);
  499. }
  500.  
  501. end = (next == -1) ? cellmax : next;
  502.  
  503. if (trim) {
  504. if (end == cellmax)
  505. end = strlen(input);
  506.  
  507. if (packed) {
  508. while (0 < input{pos} <= ' ') pos++;
  509. while (end > 0 && input{end - 1} <= ' ') end--;
  510. } else {
  511. while (0 < input[pos] <= ' ') pos++;
  512. while (end > 0 && input[end - 1] <= ' ') end--;
  513. }
  514. }
  515.  
  516. strmid(output[count - 1], input, pos, end, size2);
  517.  
  518. if (count >= size1 || next == -1 || (limit < 0 && count >= -limit))
  519. break;
  520.  
  521. pos = next + dlen;
  522. }
  523.  
  524. return count;
  525. }
  526.  
  527. stock strreplace(string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1, maxlength = sizeof(string)) {
  528. // No need to do anything if the limit is 0.
  529. if (limit == 0)
  530. return 0;
  531.  
  532. new
  533. sublen = strlen(search),
  534. replen = strlen(replacement),
  535. bool:packed = ispacked(string),
  536. maxlen = maxlength,
  537. len = strlen(string),
  538. count = 0
  539. ;
  540.  
  541.  
  542. // "maxlen" holds the max string length (not to be confused with "maxlength", which holds the max. array size).
  543. // Since packed strings hold 4 characters per array slot, we multiply "maxlen" by 4.
  544. if (packed)
  545. maxlen *= 4;
  546.  
  547. // If the length of the substring is 0, we have nothing to look for..
  548. if (!sublen)
  549. return 0;
  550.  
  551. // In this line we both assign the return value from "strfind" to "pos" then check if it's -1.
  552. while (-1 != (pos = strfind(string, search, ignorecase, pos))) {
  553. // Delete the string we found
  554. strdel(string, pos, pos + sublen);
  555.  
  556. len -= sublen;
  557.  
  558. // If there's anything to put as replacement, insert it. Make sure there's enough room first.
  559. if (replen && len + replen < maxlen) {
  560. strins(string, replacement, pos, maxlength);
  561.  
  562. pos += replen;
  563. len += replen;
  564. }
  565.  
  566. // Is there a limit of number of replacements, if so, did we break it?
  567. if (limit != -1 && ++count >= limit)
  568. break;
  569. }
  570.  
  571. return count;
  572. }
  573.  
  574. stock strtrim(string[], const chars[] = !"", string_edges:edge = edge_both) {
  575. new bool:packed = ispacked(string);
  576.  
  577. // If "chars" is empty, trim whitespace
  578. if (!strgetfirstc(chars)) {
  579. // Should the left side be trimmed?
  580. if (edge & edge_left) {
  581. new i = 0;
  582.  
  583. if (packed)
  584. while (0 < string{i} <= ' ') i++;
  585. else
  586. while (0 < string[i] <= ' ') i++;
  587.  
  588. if (i) {
  589. strdel(string, 0, i);
  590. }
  591. }
  592.  
  593. // Should the right side be trimmed?
  594. if (edge & edge_right) {
  595. new i = strlen(string);
  596.  
  597. if (i) {
  598. if (packed) {
  599. while (--i && 0 < string{i} <= ' ') {}
  600.  
  601. string{i + 1} = '\0';
  602. } else {
  603. while (--i && 0 < string[i] <= ' ') {}
  604.  
  605. string[i + 1] = '\0';
  606. }
  607. }
  608. }
  609. } else {
  610. // Should the left side be trimmed?
  611. if (edge & edge_left) {
  612. new i = 0, sub[2];
  613.  
  614. if (packed) {
  615. while ((sub[0] = string{i})) {
  616. if (strfind(chars, sub) == -1)
  617. break;
  618.  
  619. i++;
  620. }
  621.  
  622. if (i) {
  623. strdel(string, 0, i);
  624. }
  625. } else {
  626. while ((sub[0] = string[i])) {
  627. if (strfind(chars, sub) == -1)
  628. break;
  629.  
  630. i++;
  631. }
  632.  
  633. if (i) strdel(string, 0, i);
  634. }
  635. }
  636.  
  637. // Should the right side be trimmed?
  638. if (edge & edge_right) {
  639. new i = strlen(string), sub[2];
  640.  
  641. if (i >= 0) {
  642. if (packed) {
  643. while (i--) {
  644. sub[0] = string{i};
  645.  
  646. if (strfind(chars, sub) == -1)
  647. break;
  648. }
  649.  
  650. string{i + 1} = '\0';
  651. } else {
  652. while (i--) {
  653. sub[0] = string[i];
  654.  
  655. if (strfind(chars, sub) == -1)
  656. break;
  657. }
  658.  
  659. string[i + 1] = '\0';
  660. }
  661. }
  662. }
  663. }
  664. }
  665.  
  666. stock strpad(string[], length, const substr[] = !" ", string_edges:edge = edge_both, bool:trim_first = true, const trim_chars[] = !"", maxlength = sizeof(string), const input[] = !"") {
  667. if (trim_first) {
  668. strtrim(string, trim_chars, edge);
  669. }
  670.  
  671. new
  672. heap,
  673. length_left = 0,
  674. length_right = 0,
  675. len = strlen(string),
  676. sublen = strlen(substr),
  677. bool:packed,
  678. bool:subpacked = ispacked(substr)
  679. ;
  680.  
  681. if (len > length)
  682. return;
  683. else
  684. length -= len;
  685.  
  686. // Make "input" a pointer to "string"
  687. #emit LOAD.S.pri string
  688. #emit STOR.S.pri input
  689.  
  690. // Copy "input" to the heap so it won't be linked to "string" anymore.
  691. heap = CopyArgumentToHeap(7);
  692.  
  693. string[0] = '\0';
  694. len = 0;
  695.  
  696. switch (edge) {
  697. case edge_left:
  698. length_left = length;
  699. case edge_right:
  700. length_right = length;
  701. default:
  702. length_left = length / 2, length_right = length - length_left;
  703. }
  704.  
  705. if (length_left) {
  706. while (len < length_left) {
  707. if (subpacked)
  708. strcat(string, substr, length_left * 4);
  709. else
  710. strcat(string, substr, length_left + 1);
  711.  
  712. len += sublen;
  713. }
  714.  
  715. if (subpacked)
  716. string{length_left} = 0;
  717. }
  718.  
  719. strcat(string, input, maxlength);
  720.  
  721. if (length_right) {
  722. len = strlen(string);
  723. length_right += len;
  724. packed = ispacked(string);
  725.  
  726. while (len < length_right) {
  727. if (packed)
  728. strcat(string, substr, length_right / 4 + 1);
  729. else
  730. strcat(string, substr, length_right + 1);
  731.  
  732. len += sublen;
  733. }
  734.  
  735. if (packed)
  736. string{length_right + 1} = 0;
  737. }
  738.  
  739. RestoreHeapToAddress(heap);
  740. }
  741.  
  742. stock strwrap(const left[], string[], const right[], maxlength = sizeof(string)) {
  743. strins(string, left, 0, maxlength);
  744. strcat(string, right, maxlength);
  745. }
  746.  
  747. stock strcount(const string[], const sub[], bool:ignorecase = false, bool:count_overlapped = false) {
  748. new
  749. increment = count_overlapped ? 1 : strlen(sub),
  750. pos = -increment,
  751. count = 0
  752. ;
  753.  
  754.  
  755. while (-1 != (pos = strfind(string, sub, ignorecase, pos + increment)))
  756. count++;
  757.  
  758. return count;
  759. }
  760.  
  761. stock bool:strfromliteral(output[], const input[], &pos = 0, maxlength = sizeof(output)) {
  762. new
  763. length = strlen(input),
  764. c,
  765. outlen = 0,
  766. heap = 0
  767. ;
  768.  
  769. // No need to do anything else.
  770. if (!length)
  771. return true;
  772.  
  773. if (IsOverlapping(output, maxlength, input, -1))
  774. heap = CopyArgumentToHeap(1);
  775.  
  776. output[0] = '\0';
  777.  
  778. if (input[0] == '"')
  779. pos++;
  780.  
  781. for (;; pos++) {
  782. if (outlen >= maxlength - 1 || pos >= length)
  783. break;
  784.  
  785. c = input[pos];
  786.  
  787. switch (c) {
  788. // String ended
  789. case '"': break;
  790. case '\\': {}
  791. default: {
  792. output[outlen++] = c;
  793.  
  794. continue;
  795. }
  796. }
  797.  
  798. // String ends with a backslash - invalid.
  799. if (pos == length - 1)
  800. goto return_false;
  801.  
  802. // We're after a backslash now, let's see what's there.
  803. c = input[++pos];
  804.  
  805. switch (c) {
  806. case '"',
  807. '\'',
  808. '\\',
  809. '%': output[outlen++] = c;
  810. case 'a': output[outlen++] = '\a';
  811. case 'b': output[outlen++] = '\b';
  812. case 'e': output[outlen++] = '\e';
  813. case 'f': output[outlen++] = '\f';
  814. case 'r': output[outlen++] = '\r';
  815. case 'n': output[outlen++] = '\n';
  816. case 't': output[outlen++] = '\t';
  817. case 'v': output[outlen++] = '\v';
  818.  
  819. case 'x': {
  820. new val = 0;
  821.  
  822. // String ends with "\x" - invalid.
  823. if (c == length - 1)
  824. goto return_false;
  825.  
  826. while ((c = input[pos + 1])) {
  827. if ('a' <= c <= 'f' || 'A' <= c <= 'F') {
  828. val = (val << 4) + (tolower(c) - 'a' + 10);
  829. } else if ('0' <= c <= '9') {
  830. val = (val << 4) + (c - '0');
  831. } else {
  832. break;
  833. }
  834.  
  835. pos++;
  836. }
  837.  
  838. if (c == ';')
  839. pos++;
  840.  
  841. output[outlen++] = val;
  842. }
  843.  
  844. case '0' .. '9': {
  845. new val = 0;
  846.  
  847. while ((c = input[pos])) {
  848. if ('0' <= c <= '9') {
  849. val = val * 10 + (c - '0');
  850. } else {
  851. break;
  852. }
  853.  
  854. pos++;
  855. }
  856.  
  857. if (c != ';') pos--;
  858.  
  859. output[outlen++] = val;
  860. }
  861.  
  862. default: {
  863. goto return_false;
  864. }
  865. }
  866. }
  867.  
  868. output[outlen] = '\0';
  869.  
  870. pos++;
  871.  
  872. new bool:ret = true;
  873.  
  874. goto return_true;
  875. return_false:
  876. ret = false;
  877. return_true:
  878.  
  879. if (heap)
  880. RestoreHeapToAddress(heap);
  881.  
  882. return ret;
  883. }
  884.  
  885. stock strtoliteral(output[], const input[], maxlength = sizeof(output), bool:paranoid = true) {
  886. new i, c, outlen, heap = 0;
  887.  
  888. if (IsOverlapping(output, maxlength, input, -1))
  889. heap = CopyArgumentToHeap(1);
  890.  
  891. output[outlen++] = '"';
  892.  
  893. for (i = 0; (c = input[i]); i++) {
  894. if (maxlength - outlen <= 3) {
  895. outlen = min(outlen, maxlength - 2);
  896.  
  897. break;
  898. }
  899.  
  900. switch (c) {
  901. case ' ', '!', '#' .. '[', ']', '^' .. '~':
  902. output[outlen++] = c;
  903.  
  904. case '"': strunpack(output[outlen], !"\\\"", 3), outlen += 2;
  905. case '\a': strunpack(output[outlen], !"\\a" , 3), outlen += 2;
  906. case '\b': strunpack(output[outlen], !"\\b" , 3), outlen += 2;
  907. case '\e': strunpack(output[outlen], !"\\e" , 3), outlen += 2;
  908. case '\f': strunpack(output[outlen], !"\\f" , 3), outlen += 2;
  909. case '\r': strunpack(output[outlen], !"\\r" , 3), outlen += 2;
  910. case '\n': strunpack(output[outlen], !"\\n" , 3), outlen += 2;
  911. case '\t': strunpack(output[outlen], !"\\t" , 3), outlen += 2;
  912. case '\v': strunpack(output[outlen], !"\\v" , 3), outlen += 2;
  913. case '\\': strunpack(output[outlen], !"\\\\" , 3), outlen += 2;
  914.  
  915. default: {
  916. if (!paranoid && 0x80 <= c <= 0xFF) {
  917. output[outlen++] = c;
  918. continue;
  919. }
  920.  
  921. if (maxlength - outlen <= 8)
  922. break;
  923.  
  924. format(output[outlen], 7, "\\x%03x;", c);
  925.  
  926. outlen += 6;
  927. }
  928. }
  929. }
  930.  
  931. output[outlen++] = '"';
  932. output[outlen] = '\0';
  933.  
  934. if (heap)
  935. RestoreHeapToAddress(heap);
  936. }
  937.  
  938. stock strfrombin(output[], const input[], inputlength = sizeof(input), maxlength = sizeof(output)) {
  939. static const hex_chars[] = "0123456789ABCDEF";
  940. new outlen = 0, heap = 0;
  941.  
  942. if (IsOverlapping(output, maxlength, input, -1))
  943. heap = CopyArgumentToHeap(1);
  944.  
  945. for (new i = 0; i < inputlength; i++) {
  946. if (maxlength - outlen <= 7) {
  947. outlen = min(outlen, maxlength - 1);
  948.  
  949. break;
  950. }
  951.  
  952. new input_cell = input[i];
  953.  
  954. output[outlen++] = hex_chars[(input_cell ) >>> 28];
  955. output[outlen++] = hex_chars[(input_cell & 0x0F000000) >>> 24];
  956. output[outlen++] = hex_chars[(input_cell & 0x00F00000) >>> 20];
  957. output[outlen++] = hex_chars[(input_cell & 0x000F0000) >>> 16];
  958. output[outlen++] = hex_chars[(input_cell & 0x0000F000) >>> 12];
  959. output[outlen++] = hex_chars[(input_cell & 0x00000F00) >>> 8];
  960. output[outlen++] = hex_chars[(input_cell & 0x000000F0) >>> 4];
  961. output[outlen++] = hex_chars[(input_cell & 0x0000000F) ];
  962. }
  963.  
  964. output[outlen] = '\0';
  965.  
  966. if (heap)
  967. RestoreHeapToAddress(heap);
  968. }
  969.  
  970. stock strtobin(output[], const input[], maxlength = sizeof(output)) {
  971. new len = strlen(input), outlen = 0, heap = 0;
  972.  
  973. if (IsOverlapping(output, maxlength, input, -1))
  974. heap = CopyArgumentToHeap(1);
  975.  
  976. for (new i = 0; i < len;) {
  977. if (outlen >= maxlength || i > len - 8) {
  978. break;
  979. }
  980.  
  981. new c, out = 0;
  982.  
  983. #define ADD_OUT(%1) \
  984. c = input[i++]; out |= (('a' <= c <= 'f' || 'A' <= c <= 'F') ? (tolower(c) - 'a' + 10) : (c - '0')) << %1
  985.  
  986. ADD_OUT(28);
  987. ADD_OUT(24);
  988. ADD_OUT(20);
  989. ADD_OUT(16);
  990. ADD_OUT(12);
  991. ADD_OUT(8);
  992. ADD_OUT(4);
  993. ADD_OUT(0);
  994.  
  995. #undef ADD_OUT
  996.  
  997. output[outlen++] = out;
  998. }
  999.  
  1000. if (heap)
  1001. RestoreHeapToAddress(heap);
  1002.  
  1003. return outlen;
  1004. }
  1005.  
  1006. stock strurlencode(output[], const input[], maxlength = sizeof(output), bool:pack = false) {
  1007. static const hex_chars[] = "0123456789ABCDEF";
  1008.  
  1009. new
  1010. len = strlen(input),
  1011. bool:packed = ispacked(input),
  1012. outlen = 0,
  1013. heap = 0
  1014. ;
  1015.  
  1016. if (IsOverlapping(output, maxlength, input, -1))
  1017. heap = CopyArgumentToHeap(1, packed);
  1018.  
  1019. if (pack)
  1020. maxlength *= 4;
  1021.  
  1022. for (new i = 0; i < len; i++) {
  1023. if (maxlength - outlen <= 1)
  1024. break;
  1025.  
  1026. new c = packed ? input{i} : input[i];
  1027.  
  1028. switch (c) {
  1029. case 'a' .. 'z', 'A' .. 'Z', '0' .. '9', '_': {
  1030. if (pack)
  1031. output{outlen++} = c;
  1032. else
  1033. output[outlen++] = c;
  1034. }
  1035.  
  1036. case ' ': {
  1037. if (pack)
  1038. output{outlen++} = '+';
  1039. else
  1040. output[outlen++] = '+';
  1041. }
  1042.  
  1043. default: {
  1044. if (maxlength - outlen <= 3)
  1045. break;
  1046.  
  1047. if (pack) {
  1048. output{outlen++} = '%';
  1049. output{outlen++} = hex_chars[(c & 0xF0) >>> 4];
  1050. output{outlen++} = hex_chars[c & 0x0F];
  1051. } else {
  1052. output[outlen++] = '%';
  1053. output[outlen++] = hex_chars[(c & 0xF0) >>> 4];
  1054. output[outlen++] = hex_chars[c & 0x0F];
  1055. }
  1056. }
  1057. }
  1058. }
  1059.  
  1060. if (pack)
  1061. output{outlen} = '\0';
  1062. else
  1063. output[outlen] = '\0';
  1064.  
  1065. if (heap)
  1066. RestoreHeapToAddress(heap);
  1067. }
  1068.  
  1069. stock strurldecode(output[], const input[], maxlength = sizeof(output)) {
  1070. new prev_pos = 0, pos = 0, inputlen = strlen(input), len, heap = 0;
  1071.  
  1072. if (IsOverlapping(output, maxlength, input, -1))
  1073. heap = CopyArgumentToHeap(1);
  1074.  
  1075. output[0] = '\0';
  1076.  
  1077. while (-1 != (pos = strfind(input, "%", _, pos))) {
  1078. static str[2];
  1079. new c;
  1080.  
  1081. if (prev_pos != pos) {
  1082. len = strlen(output);
  1083.  
  1084. strcatmid(output, input, prev_pos, pos, maxlength);
  1085. strreplace(output, "+", " ", _, len, _, maxlength);
  1086. }
  1087.  
  1088. if (inputlen < pos + 3)
  1089. goto func_end;
  1090.  
  1091. str[0] = 0;
  1092.  
  1093. c = input[pos + 1]; str[0] |= (('a' <= c <= 'f' || 'A' <= c <= 'F') ? (tolower(c) - 'a' + 10) : (c - '0')) << 4;
  1094. c = input[pos + 2]; str[0] |= (('a' <= c <= 'f' || 'A' <= c <= 'F') ? (tolower(c) - 'a' + 10) : (c - '0'));
  1095.  
  1096. strcat(output, str, maxlength);
  1097.  
  1098. prev_pos = (pos += 3);
  1099. }
  1100.  
  1101. len = strlen(output);
  1102.  
  1103. strcatmid(output, input, prev_pos, _, maxlength);
  1104. strreplace(output, "+", " ", _, len, _, maxlength);
  1105.  
  1106. func_end:
  1107. if (heap)
  1108. RestoreHeapToAddress(heap);
  1109. }
  1110.  
  1111. stock strcatmid(dest[], const source[], start = 0, end = -1, maxlength = sizeof(dest)) {
  1112. new heap = 0;
  1113.  
  1114. if (IsOverlapping(dest, maxlength, source, -1))
  1115. heap = CopyArgumentToHeap(1);
  1116.  
  1117. if (start == 0 && end == -1) {
  1118. strcat(dest, source, maxlength);
  1119. } else {
  1120. if (end == -1)
  1121. end = strlen(source);
  1122.  
  1123. if (ispacked(dest)) {
  1124. new len = strlen(dest);
  1125.  
  1126. if (ispacked(source)) {
  1127. strunpack(g_StrlibBuffer, source);
  1128.  
  1129. strcat(dest, g_StrlibBuffer[start], min(maxlength, (len + end - start) / 4 + 1));
  1130. } else {
  1131. strcat(dest, source[start], min(maxlength, (len + end - start) / 4 + 1));
  1132. }
  1133.  
  1134. dest{len + end - start} = '\0';
  1135. } else {
  1136. if (ispacked(source)) {
  1137. strunpack(g_StrlibBuffer, source);
  1138.  
  1139. strcat(dest, g_StrlibBuffer[start], min(maxlength, strlen(dest) + end - start + 1));
  1140. } else {
  1141. strcat(dest, source[start], min(maxlength, strlen(dest) + end - start + 1));
  1142. }
  1143. }
  1144. }
  1145.  
  1146. if (heap)
  1147. RestoreHeapToAddress(heap);
  1148. }
  1149.  
  1150. stock utf8encode(dest[], const source[], maxlength = sizeof(dest)) {
  1151. new heap = 0;
  1152.  
  1153. if (IsOverlapping(dest, maxlength, source, -1)) {
  1154. heap = CopyArgumentToHeap(1);
  1155. }
  1156.  
  1157. new len = strlen(source);
  1158. new packed = ispacked(source);
  1159.  
  1160. dest[0] = '\0';
  1161.  
  1162. new idx = 0;
  1163.  
  1164. for (new i = 0; i < len; i++) {
  1165. new c = packed ? source{i} : source[i];
  1166.  
  1167. if (c >= 0x80) {
  1168. if (c > 0x4000000) {
  1169. // 6 byte
  1170. dest[idx++] = 0b11111100 | ((c >>> 30) & 0b00000001);
  1171. dest[idx++] = 0b10000000 | ((c >>> 24) & 0b00111111);
  1172. dest[idx++] = 0b10000000 | ((c >>> 18) & 0b00111111);
  1173. dest[idx++] = 0b10000000 | ((c >>> 12) & 0b00111111);
  1174. dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
  1175. dest[idx++] = 0b10000000 | (c & 0b00111111);
  1176. } else if (c > 0x200000) {
  1177. // 5 byte
  1178. dest[idx++] = 0b11111000 | ((c >>> 24) & 0b00000011);
  1179. dest[idx++] = 0b10000000 | ((c >>> 18) & 0b00111111);
  1180. dest[idx++] = 0b10000000 | ((c >>> 12) & 0b00111111);
  1181. dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
  1182. dest[idx++] = 0b10000000 | (c & 0b00111111);
  1183. } else if (c > 0x10000) {
  1184. // 4 byte
  1185. dest[idx++] = 0b11110000 | ((c >>> 18) & 0b00000111);
  1186. dest[idx++] = 0b10000000 | ((c >>> 12) & 0b00111111);
  1187. dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
  1188. dest[idx++] = 0b10000000 | (c & 0b00111111);
  1189. } else if (c > 0x800) {
  1190. // 3 byte
  1191. dest[idx++] = 0b11100000 | ((c >>> 12) & 0b00001111);
  1192. dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
  1193. dest[idx++] = 0b10000000 | (c & 0b00111111);
  1194. } else {
  1195. // 2 byte
  1196. dest[idx++] = 0b11000000 | ((c >>> 6) & 0b00011111);
  1197. dest[idx++] = 0b10000000 | (c & 0b00111111);
  1198.  
  1199. }
  1200. } else if (c > 0) {
  1201. dest[idx++] = c;
  1202. }
  1203. }
  1204.  
  1205. dest[idx++] = '\0';
  1206.  
  1207. if (heap) {
  1208. RestoreHeapToAddress(heap);
  1209. }
  1210. }
  1211.  
  1212. stock utf8decode(dest[], const source[], maxlength = sizeof(dest)) {
  1213. new heap = 0;
  1214.  
  1215. if (IsOverlapping(dest, maxlength, source, -1)) {
  1216. heap = CopyArgumentToHeap(1);
  1217. }
  1218.  
  1219. new len = strlen(source);
  1220.  
  1221. dest[0] = '\0';
  1222.  
  1223. new idx = 0;
  1224.  
  1225. for (new i = 0; i < len; i++) {
  1226. new c = source[i];
  1227.  
  1228. if (c & 0b10000000) {
  1229. if (c & 0b11100000 == 0b11000000) {
  1230. // 2 byte
  1231. if (i + 1 >= len) continue;
  1232.  
  1233. dest[idx++] = (c & 0b00011111) << 6 | (source[++i] & 0b00111111);
  1234. } else if (c & 0b11110000 == 0b11100000) {
  1235. // 3 byte
  1236. if (i + 2 >= len) continue;
  1237.  
  1238. dest[idx++] = (c & 0b00001111) << 12 |
  1239. (source[++i] & 0b00111111) << 6 |
  1240. (source[++i] & 0b00111111);
  1241. } else if (c & 0b11111000 == 0b11110000) {
  1242. // 4 byte
  1243. if (i + 3 >= len) continue;
  1244.  
  1245. dest[idx++] = (c & 0b00000111) << 18 |
  1246. (source[++i] & 0b00111111) << 12 |
  1247. (source[++i] & 0b00111111) << 6 |
  1248. (source[++i] & 0b00111111);
  1249. } else if (c & 0b11111100 == 0b11111000) {
  1250. // 5 byte
  1251. if (i + 4 >= len) continue;
  1252.  
  1253. dest[idx++] = (c & 0b00000011) << 24 |
  1254. (source[++i] & 0b00111111) << 18 |
  1255. (source[++i] & 0b00111111) << 12 |
  1256. (source[++i] & 0b00111111) << 6 |
  1257. (source[++i] & 0b00111111);
  1258. } else if (c & 0b11111110 == 0b11111100) {
  1259. // 6 byte
  1260. if (i + 5 >= len) continue;
  1261.  
  1262. dest[idx++] = (c & 0b00000001) << 30 |
  1263. (source[++i] & 0b00111111) << 24 |
  1264. (source[++i] & 0b00111111) << 18 |
  1265. (source[++i] & 0b00111111) << 12 |
  1266. (source[++i] & 0b00111111) << 6 |
  1267. (source[++i] & 0b00111111);
  1268. }
  1269. } else {
  1270. dest[idx++] = c;
  1271. }
  1272. }
  1273.  
  1274. dest[idx++] = 0;
  1275.  
  1276. if (heap) {
  1277. RestoreHeapToAddress(heap);
  1278. }
  1279. }
  1280.  
  1281.  
  1282. stock ret_strcatmid(const string[], const source[], start = 0, end = -1) {
  1283. new output[STRLIB_RETURN_SIZE];
  1284.  
  1285. strcat(output, string);
  1286.  
  1287. strcatmid(output, source, start, end);
  1288.  
  1289. return output;
  1290. }
  1291.  
  1292. stock ret_strfrombin(const input[], inputlength = sizeof(input)) {
  1293. new output[STRLIB_RETURN_SIZE];
  1294.  
  1295. strfrombin(output, input, inputlength);
  1296.  
  1297. return output;
  1298. }
  1299.  
  1300. stock ret_strimplode(const glue[], ...) {
  1301. new output[STRLIB_RETURN_SIZE];
  1302. const maxlength = sizeof(output);
  1303. new args = numargs();
  1304.  
  1305. // Loop the variable arguments (the ones after "maxlength").
  1306. for (new arg = 1; arg < args; arg++) {
  1307. // If this isn't the first string, append the glue.
  1308. if (arg != 1)
  1309. strcat(output, glue, maxlength);
  1310.  
  1311. // Wrap these in braces or they will be a part of the above if statement (compiler bug)
  1312. {
  1313. // Get the address of argument no. <arg>
  1314. #emit LCTRL 5
  1315. #emit ADD.C 12
  1316. #emit LOAD.S.alt arg
  1317. #emit SHL.C.alt 2
  1318. #emit ADD
  1319. #emit LOAD.I
  1320.  
  1321. // Push the maxlength, arg address, and output address
  1322. #emit PUSH.C maxlength
  1323. #emit PUSH.pri
  1324. #emit PUSH.ADR output
  1325.  
  1326. // Push the argument count
  1327. #emit PUSH.C 12
  1328.  
  1329. // call strcat
  1330. #emit SYSREQ.C strcat
  1331.  
  1332. // Restore the stack
  1333. #emit STACK 16
  1334. }
  1335. }
  1336.  
  1337. // Fix compiler bug (returning strings in variadic functions)
  1338. #emit LOAD.S.pri 8
  1339. #emit ADD.C 12
  1340. #emit MOVE.alt
  1341. #emit LCTRL 5
  1342. #emit ADD
  1343. #emit LOAD.I
  1344. #emit STOR.S.pri 20
  1345.  
  1346. return output;
  1347. }
  1348.  
  1349. stock ret_strreplace(const string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1) {
  1350. new output[STRLIB_RETURN_SIZE];
  1351.  
  1352. strcat(output, string);
  1353.  
  1354. strreplace(output, search, replacement, ignorecase, pos, limit);
  1355.  
  1356. return output;
  1357. }
  1358.  
  1359. stock ret_strfromliteral(const input[], &pos = 0) {
  1360. new output[STRLIB_RETURN_SIZE];
  1361.  
  1362. strcat(output, input);
  1363.  
  1364. strfromliteral(output, input, pos);
  1365.  
  1366. return output;
  1367. }
  1368.  
  1369. stock ret_strtoliteral(const input[], bool:paranoid = true) {
  1370. new output[STRLIB_RETURN_SIZE];
  1371.  
  1372. strcat(output, input);
  1373.  
  1374. strtoliteral(output, input, paranoid);
  1375.  
  1376. return output;
  1377. }
  1378.  
  1379. stock ret_strtrim(const string[], const chars[] = !"", string_edges:edge = edge_both) {
  1380. new output[STRLIB_RETURN_SIZE];
  1381.  
  1382. strcat(output, string);
  1383.  
  1384. strtrim(output, chars, edge);
  1385.  
  1386. return output;
  1387. }
  1388.  
  1389. stock ret_strpad(const string[], length, const substr[] = !" ", string_edges:edge = edge_both, bool:trim_first = true, const trim_chars[] = !"") {
  1390. new output[STRLIB_RETURN_SIZE];
  1391.  
  1392. strcat(output, string);
  1393.  
  1394. strpad(output, length, substr, edge, trim_first, trim_chars);
  1395.  
  1396. return output;
  1397. }
  1398.  
  1399. stock ret_strwrap(const left[], const string[], const right[]) {
  1400. new output[STRLIB_RETURN_SIZE];
  1401.  
  1402. strcat(output, left);
  1403. strcat(output, string);
  1404. strcat(output, right);
  1405.  
  1406. return output;
  1407. }
  1408.  
  1409. stock ret_strurldecode(const input[]) {
  1410. new output[STRLIB_RETURN_SIZE];
  1411.  
  1412. strcat(output, input);
  1413.  
  1414. strurldecode(output, input);
  1415.  
  1416. return output;
  1417. }
  1418.  
  1419. stock ret_strurlencode(const input[], bool:pack = false) {
  1420. new output[STRLIB_RETURN_SIZE];
  1421.  
  1422. strcat(output, input);
  1423.  
  1424. strurlencode(output, input, _, pack);
  1425.  
  1426. return output;
  1427. }
  1428.  
  1429. stock ret_utf8encode(const input[]) {
  1430. new output[STRLIB_RETURN_SIZE];
  1431.  
  1432. utf8encode(output, input);
  1433.  
  1434. return output;
  1435. }
  1436.  
  1437. stock ret_utf8decode(const input[]) {
  1438. new output[STRLIB_RETURN_SIZE];
  1439.  
  1440. utf8decode(output, input);
  1441.  
  1442. return output;
  1443. }
  1444.  
  1445. stock ret_strpack(const source[]) {
  1446. new output[STRLIB_RETURN_SIZE];
  1447.  
  1448. strpack(output, source);
  1449.  
  1450. return output;
  1451. }
  1452.  
  1453. stock ret_strunpack(const source[]) {
  1454. new output[STRLIB_RETURN_SIZE];
  1455.  
  1456. strunpack(output, source);
  1457.  
  1458. return output;
  1459. }
  1460.  
  1461. stock ret_strcat(const string1[], const string2[]) {
  1462. new output[STRLIB_RETURN_SIZE];
  1463.  
  1464. strcat(output, string1);
  1465. strcat(output, string2);
  1466.  
  1467. return output;
  1468. }
  1469.  
  1470. stock ret_strmid(const source[], start, end) {
  1471. new output[STRLIB_RETURN_SIZE];
  1472.  
  1473. strmid(output, source, start, end);
  1474.  
  1475. return output;
  1476. }
  1477.  
  1478. stock ret_strins(const string[], const substr[], pos, maxlength = sizeof(string)) {
  1479. new output[STRLIB_RETURN_SIZE];
  1480.  
  1481. strcat(output, string);
  1482. strins(output, substr, pos);
  1483.  
  1484. return output;
  1485. }
  1486.  
  1487. stock ret_strdel(const string[], start, end) {
  1488. new output[STRLIB_RETURN_SIZE];
  1489.  
  1490. strcat(output, string);
  1491. strdel(output, start, end);
  1492.  
  1493. return output;
  1494. }
  1495.  
  1496. stock ret_valstr(value, bool:pack = false) {
  1497. new output[STRLIB_RETURN_SIZE];
  1498.  
  1499. format(output, sizeof(output), "%d", value);
  1500.  
  1501. if (pack)
  1502. strpack(output, output);
  1503.  
  1504. return output;
  1505. }
  1506.  
  1507. stock ret_GetPlayerName(playerid, bool:pack = false) {
  1508. new output[MAX_PLAYER_NAME];
  1509.  
  1510. GetPlayerName(playerid, output, sizeof(output));
  1511.  
  1512. if (pack)
  1513. strpack(output, output);
  1514.  
  1515. return output;
  1516. }
  1517.  
  1518. stock sprintf(const fmat[], {Float, _}:...) {
  1519. static output[STRLIB_RETURN_SIZE], frm_header[3], heap;
  1520.  
  1521. const output_size = sizeof(output);
  1522.  
  1523. if (ispacked(fmat)) {
  1524. heap = CopyArgumentToHeap(0);
  1525. } else {
  1526. heap = 0;
  1527. }{}
  1528.  
  1529. // Store current frame header
  1530. #emit LCTRL 5
  1531. #emit CONST.alt frm_header
  1532. #emit MOVS 12
  1533.  
  1534. // Change the stack pointer to FRM + 12
  1535. #emit ADD.C 12 // pri is FRM (see above)
  1536. #emit SCTRL 4
  1537.  
  1538. // Push sizeof(output)
  1539. #emit PUSH.C output_size
  1540.  
  1541. // Push output
  1542. #emit PUSH.C output
  1543.  
  1544. // Push the argument count
  1545. #emit LOAD.S.pri 8
  1546. #emit ADD.C 8
  1547. #emit PUSH.pri
  1548.  
  1549. #if !STRLIB_USE_FORMATEX
  1550. const formatex = 0; // Dummy used to avoid "unknown symbol" error
  1551.  
  1552. goto do_sysreq;
  1553. #endif
  1554.  
  1555. // Call formatex (unless this was skipped above)
  1556. #emit LCTRL 6
  1557. #emit ADD.C 36
  1558. #emit PUSH.pri
  1559. #emit CONST.pri formatex
  1560. #emit SCTRL 6
  1561.  
  1562. #if !STRLIB_USE_FORMATEX
  1563. do_sysreq:
  1564. #endif
  1565.  
  1566. // Call format (unless formatex was called, in which case this is skipped)
  1567. #emit SYSREQ.C format
  1568.  
  1569. // Restore the stack pointer to FRM
  1570. #emit LCTRL 5
  1571. #emit SCTRL 4
  1572.  
  1573. // Copy back the frame header
  1574. #emit MOVE.alt
  1575. #emit CONST.pri frm_header
  1576. #emit MOVS 12
  1577.  
  1578. // Restore heap if needed
  1579. if (heap) {
  1580. RestoreHeapToAddress(heap);
  1581. }{}
  1582.  
  1583. // IMPORTANT: Fix compiler bug (returning strings in variadic functions)
  1584. #emit LOAD.S.pri 8
  1585. #emit ADD.C 12
  1586. #emit MOVE.alt
  1587. #emit LCTRL 5
  1588. #emit ADD
  1589. #emit LOAD.I
  1590. #emit STOR.S.pri 20 // 16 + (static_args * 4)
  1591.  
  1592. return output;
  1593.  
  1594. // It is actually used, just not by its symbol name
  1595. #pragma unused fmat
  1596. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement