y_utils.inc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. /**--------------------------------------------------------------------------**\
  2. =================================
  3. Y Sever Includes - Misc Functions
  4. =================================
  5. Description:
  6. Misc functions used throughout.
  7. Legal:
  8. Version: MPL 1.1
  9. The contents of this file are subject to the Mozilla Public License Version
  10. 1.1 (the "License"); you may not use this file except in compliance with
  11. the License. You may obtain a copy of the License at
  12. http://www.mozilla.org/MPL/
  13. Software distributed under the License is distributed on an "AS IS" basis,
  14. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. for the specific language governing rights and limitations under the
  16. License.
  17. The Original Code is the YSI utils include.
  18. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  19. Portions created by the Initial Developer are Copyright (C) 2011
  20. the Initial Developer. All Rights Reserved.
  21. Contributors:
  22. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  23. Thanks:
  24. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  25. ZeeX - Very productive conversations.
  26. koolk - IsPlayerinAreaEx code.
  27. TheAlpha - Danish translation.
  28. breadfish - German translation.
  29. Fireburn - Dutch translation.
  30. yom - French translation.
  31. 50p - Polish translation.
  32. Zamaroht - Spanish translation.
  33. Los - Portuguese translation.
  34. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  35. for me to strive to better.
  36. Pixels^ - Running XScripters where the idea was born.
  37. Matite - Pestering me to release it and using it.
  38. Very special thanks to:
  39. Thiadmer - PAWN, whose limits continue to amaze me!
  40. Kye/Kalcor - SA:MP.
  41. SA:MP Team past, present and future - SA:MP.
  42. Optional plugins:
  43. Gamer_Z - GPS.
  44. Incognito - Streamer.
  45. Me - sscanf2, fixes2, Whirlpool.
  46. Version:
  47. 0.1.3
  48. Changelog:
  49. 06/10/12:
  50. Upgraded "memset" to use "FILL".
  51. 22/12/11:
  52. Changed "ceildiv" to only evaluate arguments once.
  53. 05/12/11:
  54. Added NO_VALUE to test if macros have no value.
  55. 08/09/10:
  56. Added strcpy and StripNL.
  57. 08/08/10:
  58. Scrapped almost everything. Only VERY usefult things go in now.
  59. Functions:
  60. Stock:
  61. StripNL - Strips the newline characters from the end of a string.
  62. Inline:
  63. iseven - Checks if a number is even.
  64. isodd - Checks if a number is odd.
  65. isnull - Checks if a string is NULL ("\1\0").
  66. strcpy - Copy one string to another.
  67. Variables:
  68. Global:
  69. TRUE - True hack for infinate loops.
  70. FALSE - False hack for one-time loops.
  71. NULL - 1 long string for passing via Call(Remote|Local)Function.
  72. </remarks>
  73. \**--------------------------------------------------------------------------**/
  74. #include "internal\y_version"
  75. #include "y_debug"
  76. #include "y_amx"
  77. //#tryinclude <sscanf>
  78. /*// "File,Float," must remain last always.
  79. #if defined CUSTOM_TAG_TYPES
  80. #define File,Float, Float,File,CUSTOM_TAG_TYPES
  81. #else
  82. #define File,Float, Float,File
  83. #endif*/
  84. // Add new tags to the START of this list.
  85. #include "internal\y_globaltags"
  86. // VERY VERY VERY IMPORTANT!!! y_inline uses "130" instead of "YSI_MAX_STRING"
  87. // for two lines (one is "520" for "130 * 4").
  88. #define YSI_MAX_STRING (130)
  89. #define FUNCTION_LENGTH (32)
  90. #define NO_VALUE(%0) ((2*%0-1+1)==-1)
  91. #if !defined TRUE
  92. new stock
  93. bool:TRUE = true;
  94. #endif
  95. #if !defined FALSE
  96. new stock
  97. bool:FALSE = false;
  98. #endif
  99. #if !defined NULL
  100. new stock
  101. NULL[2] = {1, 0};
  102. #endif
  103. // Define "volatile" as nothing.
  104. #if !defined volatile
  105. #define volatile
  106. #endif
  107. #define YSIM_MASTER #M
  108. #define YSIM_RETURN #R
  109. #define YSIM_CALLER #C
  110. #define YSIM_TEXT_D #T
  111. #define YSIM_TEXT_L #L
  112. #define YSIM_TEXT_S #Y
  113. #define YSIM_TEXT_P #Z
  114. #define YSIM_ORDERS #O
  115. #define YSIM_HFIRST #H
  116. #define YSIM_OPDRET #D
  117. #define YSIM_TXTFND #X
  118. #define YSIM_TXTIND #I
  119. #define YSIM_TXTLEN #E
  120. #define YSIM_LOG_IN #U
  121. #if !defined YSIM_STRING
  122. #define YSIM_STRING (42)
  123. #endif
  124. #define FLOAT_INFINITY (Float:0x7F800000)
  125. #define FLOAT_NEG_INFINITY (Float:0xFF800000)
  126. #define FLOAT_NEGATIVE_INFINITY (Float:0xFF800000)
  127. #define FLOAT_NAN (Float:0x7FFFFFFF)
  128. #define FLOAT_NOT_A_NUMBER (Float:0x7FFFFFFF)
  129. #define FLOAT_QNAN (Float:0x7FFFFFFF)
  130. #define FLOAT_QUIET_NAN (Float:0x7FFFFFFF)
  131. #define FLOAT_QUIET_NOT_A_NUMBER (Float:0x7FFFFFFF)
  132. #define FLOAT_SNAN (Float:0x7FBFFFFF)
  133. #define FLOAT_SIGNALING_NAN (Float:0x7FBFFFFF)
  134. #define FLOAT_SIGNALING_NOT_A_NUMBER (Float:0x7FBFFFFF)
  135. //#pragma unused TRUE, FALSE, NULL
  136. #define ceildiv(%0,%1) \
  137. (((%0)-1)/(%1)+1)
  138. #define floordiv(%0,%1) \
  139. ((%0)/(%1))
  140. /**--------------------------------------------------------------------------**\
  141. <summary>isnull</summary>
  142. <param name="str">String to check if is null.</param>
  143. <returns>
  144. -
  145. </returns>
  146. <remarks>
  147. -
  148. </remarks>
  149. \**--------------------------------------------------------------------------**/
  150. #if !defined isnull
  151. #define isnull(%1) \
  152. ((%1[0] == 0) || (%1[0] == 1 && %1[1] == 0))
  153. #endif
  154. /**--------------------------------------------------------------------------**\
  155. <summary>isodd</summary>
  156. <param name="value">Value to check if is odd.</param>
  157. <returns>
  158. -
  159. </returns>
  160. <remarks>
  161. -
  162. </remarks>
  163. \**--------------------------------------------------------------------------**/
  164. #define isodd(%1) \
  165. ((%1) & 1)
  166. /**--------------------------------------------------------------------------**\
  167. <summary>iseven</summary>
  168. <param name="value">Value to check if is even.</param>
  169. <returns>
  170. -
  171. </returns>
  172. <remarks>
  173. -
  174. </remarks>
  175. \**--------------------------------------------------------------------------**/
  176. #define iseven(%1) \
  177. (!isodd(%1))
  178. /**--------------------------------------------------------------------------**\
  179. <summary>strcpy</summary>
  180. <param name="dest">Destination string.</param>
  181. <param name="src">Source string.</param>
  182. <param name="len">(Implicit) maximum length of the destination.</param>
  183. <returns>
  184. -
  185. </returns>
  186. <remarks>
  187. -
  188. </remarks>
  189. \**--------------------------------------------------------------------------**/
  190. #define strcpy(%0,%1) \
  191. strcat((%0[0] = '\0', %0), %1)
  192. // memcpy(%0,%1,0,strlen(%1)*4+4,%2)
  193. /**--------------------------------------------------------------------------**\
  194. <summary>StripNL</summary>
  195. <param name="str[]">The string to remove the newline characters from</param>
  196. <returns>
  197. -
  198. </returns>
  199. <remarks>
  200. Updated from old versions, should be more efficient
  201. </remarks>
  202. \**--------------------------------------------------------------------------**/
  203. stock StripNL(str[])
  204. {
  205. P:3("StripNL called: \"%s\"", str);
  206. new
  207. i = strlen(str);
  208. while (i-- && str[i] <= ' ') str[i] = '\0';
  209. }
  210. /**--------------------------------------------------------------------------**\
  211. <summary>endofline</summary>
  212. <param name="line[]">String to check.</param>
  213. <param name="pos">Postion to start from.</param>
  214. <returns>
  215. -
  216. </returns>
  217. <remarks>
  218. Checks if the current point in a line is the end of non-whitespace data.
  219. </remarks>
  220. \**--------------------------------------------------------------------------**/
  221. stock endofline(line[], pos)
  222. {
  223. P:3("endofline called: \"%s\", %i", line, pos);
  224. if (pos < 0 || pos > strlen(line)) return 0;
  225. while (line[pos]) if (line[pos++] > ' ') return 0;
  226. return 1;
  227. }
  228. /**--------------------------------------------------------------------------**\
  229. <summary>chrfind</summary>
  230. <param name="needle">The character to find.</param>
  231. <param name="haystack[]">The string to find it in.</param>
  232. <param name="start">The offset to start from.</param>
  233. <returns>
  234. Fail - -1, Success - pos
  235. </returns>
  236. <remarks>
  237. -
  238. </remarks>
  239. \**--------------------------------------------------------------------------**/
  240. stock chrfind(needle, haystack[], start = 0)
  241. {
  242. P:3("chrfind called: %c, \"%s\", %i", needle, haystack, start);
  243. if (start < 0)
  244. {
  245. start = 0;
  246. }
  247. else if (start > strlen(haystack)) return -1;
  248. while (haystack[start]) if (haystack[start++] == needle) return start - 1;
  249. return -1;
  250. }
  251. //#define chrfind(%0'%1'%2,%3) str
  252. stock chrfindp(needle, haystack[], start = 0)
  253. {
  254. P:3("chrfind called: %c, \"%s\", %i", needle, haystack, start);
  255. if (start < 0)
  256. {
  257. start = 0;
  258. }
  259. while (haystack{start}) if (haystack{start++} == needle) return start - 1;
  260. return -1;
  261. }
  262. /**--------------------------------------------------------------------------**\
  263. <summary>bernstein</summary>
  264. <param name="string[]">the string to hash.</param>
  265. <returns>
  266. the bernstein hash of the input string
  267. </returns>
  268. <remarks>
  269. This is a 32bit hash system so is not very secure, however we're only
  270. using this as a string enumerator to uniquely identify strings easilly
  271. and allow for a binary search of strings based on the hash of their name.
  272. crc32, then jenkins were originally used however this is far faster, if a
  273. little collision prone, but we're checking the strings manually anyway.
  274. This doesn't matter as it would be done regardless of hash method, so this
  275. doesn't need to be accounted for. Speed is all that matters with at
  276. least a bit of non collision (the number of strings we're dealing with,
  277. this should have none-few collisions).
  278. I modified it slightly from the original code pasted by aru, to code
  279. closer to the code http://www.burtleburtle.net/bob/hash/doobs.html and
  280. to work with PAWN (and shaved 0.2�s off the time for one call :D).
  281. Uber reduced version (just for fun):
  282. b(s[]){new h=-1,i,j;while((j=s[i++]))h=h*33+j;return h;}
  283. Update: Contrary to what I said above this is also used to identify colour
  284. strings for the updated text system involving file based styling and this
  285. is not checked for collisions as it's unimportant. But this doesn't affect
  286. the function at all, I just mentioned it here for "interest".
  287. </remarks>
  288. \**--------------------------------------------------------------------------**/
  289. stock bernstein(string[])
  290. {
  291. P:3("bernstein called: \"%s\"", string);
  292. new
  293. hash = -1,
  294. i,
  295. j;
  296. while ((j = string[i++]))
  297. {
  298. hash = hash * 33 + j;
  299. //printf("Hash stage %d: %d", i - 1, hash);
  300. }
  301. return hash;
  302. }
  303. /**--------------------------------------------------------------------------**\
  304. <summary>ishex</summary>
  305. <param name="str[]">String to check.</param>
  306. <returns>
  307. -
  308. </returns>
  309. <remarks>
  310. -
  311. </remarks>
  312. \**--------------------------------------------------------------------------**/
  313. stock ishex(str[])
  314. {
  315. P:3("ishex called: \"%s\"", str);
  316. new
  317. i,
  318. cur;
  319. if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) i = 2;
  320. while (str[i])
  321. {
  322. cur = str[i++];
  323. if (!(('0' <= cur <= '9') || ('A' <= cur <= 'F') || ('a' <= cur <= 'f'))) return 0;
  324. //if ((cur < '0') || ('9' < cur < 'A') || ('F' < cur < 'a') || (cur > 'f')) return 0;
  325. }
  326. return 1;
  327. }
  328. /**--------------------------------------------------------------------------**\
  329. <summary>unpack</summary>
  330. <param name="str[]">String to unpack</param>
  331. <returns>
  332. unpacked string
  333. </returns>
  334. <remarks>
  335. Mainly used for debugging.
  336. </remarks>
  337. \**--------------------------------------------------------------------------**/
  338. stock unpack(const str[])
  339. {
  340. P:3("unpack called: \"%s\"", str);
  341. new
  342. ret[YSI_MAX_STRING] = {0};
  343. if (strlen(str) <= YSI_MAX_STRING)
  344. {
  345. strunpack(ret, str);
  346. }
  347. return ret;
  348. }
  349. /**--------------------------------------------------------------------------**\
  350. <summary>GetIP</summary>
  351. <param name="playerid">Player to get IP of.</param>
  352. <returns>
  353. IP as a 32bit int.
  354. </returns>
  355. <remarks>
  356. -
  357. </remarks>
  358. \**--------------------------------------------------------------------------**/
  359. stock GetIP(playerid)
  360. {
  361. new
  362. ip[16];
  363. GetPlayerIp(playerid, ip, sizeof (ip));
  364. new
  365. ipv = strval(ip) << 24,
  366. pos = 0;
  367. while (pos < 15 && ip[pos++] != '.') {}
  368. ipv += strval(ip[pos]) << 16;
  369. while (pos < 15 && ip[pos++] != '.') {}
  370. ipv += strval(ip[pos]) << 8;
  371. while (pos < 15 && ip[pos++] != '.') {}
  372. ipv += strval(ip[pos]);
  373. return ipv;
  374. }
  375. /**--------------------------------------------------------------------------**\
  376. <summary>getstring</summary>
  377. <param name="addr">Address of the string on the heap.</param>
  378. <returns>
  379. string
  380. </returns>
  381. <remarks>
  382. Is passed the result of getarg, which will be the address of a string (in
  383. theory) and uses that for DMA to get the string.
  384. </remarks>
  385. \**--------------------------------------------------------------------------**/
  386. stock getstring(addr)
  387. {
  388. new
  389. ret[YSI_MAX_STRING];
  390. va_getstring(ret, addr);
  391. return ret;
  392. }
  393. stock getstringarg(addr)
  394. {
  395. new
  396. ret[YSI_MAX_STRING];
  397. va_getstring(ret, addr);
  398. return ret;
  399. }
  400. /**--------------------------------------------------------------------------**\
  401. <summary>isnumeric</summary>
  402. <param name="str[]">String to check</param>
  403. <returns>
  404. -
  405. </returns>
  406. <remarks>
  407. Checks if a given string is numeric.
  408. </remarks>
  409. \**--------------------------------------------------------------------------**/
  410. stock isnumeric(str[])
  411. {
  412. P:3("isnumeric called: \"%s\"", str);
  413. new
  414. ch,
  415. i;
  416. while ((ch = str[i++])) if (!('0' <= ch <= '9')) return 0;
  417. return 1;
  418. }
  419. #if !defined _inc_sscanf || 1
  420. /**----------------------------------------------------------------------**\
  421. <summary>hexstr</summary>
  422. <param name=" string[]">String to convert to a number.</param>
  423. <returns>
  424. value of the passed hex string.
  425. </returns>
  426. <remarks>
  427. Now stops on invalid characters.
  428. </remarks>
  429. \**----------------------------------------------------------------------**/
  430. stock hexstr(string[])
  431. {
  432. new
  433. ret,
  434. val,
  435. i;
  436. if (string[0] == '0' && string[1] | 0x20 == 'x') i = 2;
  437. for ( ; ; )
  438. {
  439. switch ((val = string[i++]))
  440. {
  441. case '0' .. '9':
  442. {
  443. val -= '0';
  444. }
  445. case 'a' .. 'f':
  446. {
  447. val -= 'a' - 10;
  448. }
  449. case 'A' .. 'F':
  450. {
  451. val -= 'A' - 10;
  452. }
  453. default: break;
  454. }
  455. ret = ret << 4 | val;
  456. }
  457. return ret;
  458. }
  459. /**----------------------------------------------------------------------**\
  460. <summary>boolstr</summary>
  461. <param name=" string[]">String to try convert to a boolean.</param>
  462. <returns>
  463. bool: passed boolean.
  464. </returns>
  465. <remarks>
  466. This can take a number of ways of representing booleans - 0, false and
  467. nothing there. Anything not one of those things (false is not case
  468. sensitive) is assumed true.
  469. </remarks>
  470. \**----------------------------------------------------------------------**/
  471. stock bool:boolstr(string[])
  472. {
  473. if (!string[0] || string[0] == '0' || !strcmp(string, "false", true)) return false;
  474. return true;
  475. }
  476. /**----------------------------------------------------------------------**\
  477. <summary>binstr</summary>
  478. <param name=" string[]">String to try convert to a boolean.</param>
  479. <returns>
  480. bool: passed boolean.
  481. </returns>
  482. <remarks>
  483. This takes a value in 0110101 (boolean) format and returns it as a
  484. regular value.
  485. </remarks>
  486. \**----------------------------------------------------------------------**/
  487. stock binstr(string[])
  488. {
  489. new
  490. pos = 0;
  491. switch (string[0])
  492. {
  493. case '0':
  494. {
  495. if (string[1] | 0x20 == 'b')
  496. {
  497. pos = 2;
  498. }
  499. }
  500. case '1':
  501. {
  502. }
  503. default:
  504. {
  505. return 0;
  506. }
  507. }
  508. new
  509. value = 0;
  510. for ( ; ; )
  511. {
  512. switch (string[pos++])
  513. {
  514. case '0':
  515. {
  516. value <<= 1;
  517. }
  518. case '1':
  519. {
  520. value = (value << 1) | 1;
  521. }
  522. default:
  523. {
  524. break;
  525. }
  526. }
  527. }
  528. return value;
  529. }
  530. #endif
  531. /**--------------------------------------------------------------------------**\
  532. <summary>
  533. memset
  534. rawMemset
  535. </summary>
  536. <param name="arr[], iAddress">Array or address to set to a value.</param>
  537. <param name="iSize">Number of cells to fill.</param>
  538. <param name="iValue">What to set the cells to.</param>
  539. <returns>
  540. -
  541. </returns>
  542. <remarks>
  543. Based on code by Slice:
  544. http://forum.sa-mp.com/showthread.php?p=1606781#post1606781
  545. Modified to use binary flags instead of a loop.
  546. "memset" takes an array, the size of the array, and a value to fill it with
  547. and sets the whole array to that value.
  548. "rawmemset" is similar, but takes an AMX data segment address instead and
  549. the size is in bytes, not cells.
  550. </remarks>
  551. \**--------------------------------------------------------------------------**/
  552. stock memset(arr[], size = sizeof (arr), val = 0)
  553. {
  554. new
  555. addr;
  556. #emit LOAD.S.pri arr
  557. #emit STOR.S.pri addr
  558. // Convert the size from cells to bytes.
  559. rawMemset(addr, size * 4, val);
  560. return 0;
  561. }
  562. stock rawMemset(iAddress, iSize, iValue)
  563. {
  564. // Loop until there are only little bits left to fill.
  565. while (iSize >= 4096)
  566. {
  567. // I have to do this because the FILL instruction doesn't accept a
  568. // dynamic number.
  569. #emit LOAD.S.alt iAddress
  570. #emit LOAD.S.pri iValue
  571. #emit FILL 4096
  572. iSize -= 4096;
  573. iAddress += 4096;
  574. }
  575. if (iSize & 2048)
  576. {
  577. #emit LOAD.S.alt iAddress
  578. #emit LOAD.S.pri iValue
  579. #emit FILL 2048
  580. iAddress += 2048;
  581. }
  582. if (iSize & 1024)
  583. {
  584. #emit LOAD.S.alt iAddress
  585. #emit LOAD.S.pri iValue
  586. #emit FILL 1024
  587. iAddress += 1024;
  588. }
  589. if (iSize & 512)
  590. {
  591. #emit LOAD.S.alt iAddress
  592. #emit LOAD.S.pri iValue
  593. #emit FILL 512
  594. iAddress += 512;
  595. }
  596. if (iSize & 256)
  597. {
  598. #emit LOAD.S.alt iAddress
  599. #emit LOAD.S.pri iValue
  600. #emit FILL 256
  601. iAddress += 256;
  602. }
  603. if (iSize & 128)
  604. {
  605. #emit LOAD.S.alt iAddress
  606. #emit LOAD.S.pri iValue
  607. #emit FILL 128
  608. iAddress += 128;
  609. }
  610. if (iSize & 64)
  611. {
  612. #emit LOAD.S.alt iAddress
  613. #emit LOAD.S.pri iValue
  614. #emit FILL 64
  615. iAddress += 64;
  616. }
  617. if (iSize & 32)
  618. {
  619. #emit LOAD.S.alt iAddress
  620. #emit LOAD.S.pri iValue
  621. #emit FILL 32
  622. iAddress += 32;
  623. }
  624. if (iSize & 16)
  625. {
  626. #emit LOAD.S.alt iAddress
  627. #emit LOAD.S.pri iValue
  628. #emit FILL 16
  629. iAddress += 16;
  630. }
  631. if (iSize & 8)
  632. {
  633. #emit LOAD.S.alt iAddress
  634. #emit LOAD.S.pri iValue
  635. #emit FILL 8
  636. iAddress += 8;
  637. }
  638. if (iSize & 4)
  639. {
  640. #emit LOAD.S.alt iAddress
  641. #emit LOAD.S.pri iValue
  642. #emit FILL 4
  643. iAddress += 4;
  644. }
  645. }
  646. //#if !defined ReturnPlayerName
  647. stock ReturnPlayerName(playerid)
  648. {
  649. new
  650. str[MAX_PLAYER_NAME];
  651. GetPlayerName(playerid, str, sizeof (str));
  652. return str;
  653. }
  654. //#endif
  655. stock ftouch(const filename[])
  656. {
  657. if (fexist(filename))
  658. {
  659. return 0;
  660. }
  661. else
  662. {
  663. new
  664. File:f = fopen(filename, io_write);
  665. if (f)
  666. {
  667. fclose(f);
  668. return 1;
  669. }
  670. else
  671. {
  672. return -1;
  673. }
  674. }
  675. }
  676. #include "y_va"