/src/runtime/mosml.c

https://github.com/bluegnu/mosml · C · 1647 lines · 1369 code · 194 blank · 84 comment · 261 complexity · 0019e344a3fc3f9df11b935ef90b4ba4 MD5 · raw file

  1. /* Moscow ML primitives */
  2. #include <math.h>
  3. #include <errno.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <sys/stat.h>
  8. #include <time.h>
  9. #include <ctype.h>
  10. #ifdef WIN32
  11. #include <sys/timeb.h>
  12. #include <sys/utime.h>
  13. #include <io.h>
  14. #include <direct.h>
  15. #include <windows.h>
  16. #else
  17. #include <sys/time.h>
  18. #include <sys/times.h>
  19. #include <sys/resource.h>
  20. #include <dirent.h>
  21. #include <sys/param.h>
  22. #include <unistd.h>
  23. #include <utime.h>
  24. #endif
  25. #include "mlvalues.h"
  26. #include "fail.h"
  27. #include "memory.h"
  28. #include "str.h"
  29. #include "runtime.h"
  30. #include "alloc.h"
  31. #include "major_gc.h"
  32. #include "intext.h"
  33. #include "debugger.h"
  34. #include "interp.h"
  35. #include "globals.h"
  36. #include "mosml.h"
  37. /* SunOS 4 appears not to have mktime: */
  38. #if defined(sun) && !defined(__svr4__)
  39. #define tm2cal(tptr) timelocal(tptr)
  40. #else
  41. #define tm2cal(tptr) mktime(tptr)
  42. #endif
  43. #define Raise_float_if(cond) \
  44. if( cond ) \
  45. { raiseprimitive0(float_exn); }
  46. #define Check_float(dval) \
  47. Raise_float_if( (dval > maxdouble) || (dval < -maxdouble) )
  48. /* Structural equality on trees. */
  49. /* Note how reference cells are treated! */
  50. static int sml_equal_aux(value v1, value v2)
  51. {
  52. mlsize_t i;
  53. value * p1, * p2;
  54. again:
  55. if (v1 == v2) return 1;
  56. if (Is_long(v1) || Is_long(v2)) return 0;
  57. if (!Is_in_heap(v1) && !Is_young(v1)) return 0;
  58. if (!Is_in_heap(v2) && !Is_young(v2)) return 0;
  59. if (Tag_val(v1) != Tag_val(v2)) return 0;
  60. switch(Tag_val(v1)) {
  61. case String_tag:
  62. { // Faster string comparison 2002-12-03
  63. register int len = string_length(v1);
  64. register unsigned char * p1, * p2;
  65. if (len != string_length(v2))
  66. return 0;
  67. for (p1 = (unsigned char *) String_val(v1),
  68. p2 = (unsigned char *) String_val(v2);
  69. len > 0;
  70. len--, p1++, p2++)
  71. if (*p1 != *p2)
  72. return 0;
  73. return 1;
  74. }
  75. case Double_tag:
  76. return (Double_val(v1) == Double_val(v2));
  77. case Reference_tag: /* Different reference cells are not equal! */
  78. case Abstract_tag:
  79. case Final_tag:
  80. return 0;
  81. case Closure_tag:
  82. invalid_argument("sml_equal: functional value");
  83. default:
  84. i = Wosize_val(v1);
  85. if (i != Wosize_val(v2)) return 0;
  86. for(p1 = Op_val(v1), p2 = Op_val(v2);
  87. i > 1;
  88. i--, p1++, p2++)
  89. if (!sml_equal_aux(*p1, *p2)) return 0;
  90. v1 = *p1;
  91. v2 = *p2; /* Tail-call */
  92. goto again;
  93. }
  94. }
  95. value sml_equal(value v1, value v2) /* ML */
  96. {
  97. return Atom(sml_equal_aux(v1,v2));
  98. }
  99. value sml_not_equal(value v1, value v2) /* ML */
  100. {
  101. return Atom(!sml_equal_aux(v1,v2));
  102. }
  103. value sml_system(value cmd) /* ML */
  104. {
  105. value res;
  106. errno = 0;
  107. res = system(String_val(cmd));
  108. if (errno == ENOENT)
  109. return -1;
  110. else
  111. return Val_int(res);
  112. }
  113. value sml_abs_int(value x) /* ML */
  114. { value tmp, v;
  115. tmp = Long_val(x);
  116. if( tmp < 0 ) tmp = -tmp;
  117. v = Val_long(tmp);
  118. if( Long_val(v) != tmp )
  119. raise_overflow();
  120. return v;
  121. }
  122. value sml_floor(value f) /* ML */
  123. { double r;
  124. long i;
  125. value v;
  126. r = Double_val(f);
  127. if( r >= 0.0 )
  128. { if( r >= ((double) Max_long + 1) ) goto raise_floor;
  129. i = (long) r;
  130. }
  131. else
  132. {
  133. if( r < ((double) Min_long) ) goto raise_floor;
  134. i = (long) r;
  135. if( r < ((double) i) ) i -= 1;
  136. }
  137. v = Val_long(i);
  138. if( Long_val(v) != i ) goto raise_floor;
  139. return v;
  140. raise_floor:
  141. raise_overflow();
  142. return Val_unit; /* Can't reach return */
  143. }
  144. value sml_ceil(value f) /* ML */
  145. { double r;
  146. long i;
  147. value v;
  148. r = Double_val(f);
  149. if( r >= 0.0 )
  150. { if( r > ((double) (Max_long)) ) goto raise_ceil;
  151. i = (long) r;
  152. if( r > ((double) i) ) i += 1;
  153. }
  154. else
  155. { if( r <= ((double) (Min_long-1)) ) goto raise_ceil;
  156. i = (long) r;
  157. }
  158. v = Val_long(i);
  159. if( Long_val(v) != i ) goto raise_ceil;
  160. return v;
  161. raise_ceil:
  162. raise_overflow();
  163. return Val_unit; /* Can't reach return */
  164. }
  165. #ifdef __MWERKS__
  166. #if __MWERKS__ < 0x0400
  167. #include <Types.h>
  168. double_t nearbyint ( double_t x );
  169. #define rint nearbyint
  170. #endif
  171. #endif
  172. value sml_round(value f) /* ML */
  173. { double r;
  174. long i;
  175. value v;
  176. /* Apparently no rint() in djgpp's libm: */
  177. #if defined(MSDOS) || defined(hpux) || defined(WIN32)
  178. double delta;
  179. r = floor(Double_val(f));
  180. if (r < (double)(Min_long-1) || r > (double)(Max_long)) goto raise_round;
  181. i = (long)r;
  182. delta = Double_val(f) - r; // belongs to [0, 1[
  183. // Round to nearest even integer.
  184. // If delta > 0.5, round up; if delta == 0.5, round to nearest even:
  185. if (delta > 0.5 || delta == 0.5 && i % 2 != 0)
  186. i++;
  187. v = Val_long(i);
  188. if( Long_val(v) != i ) goto raise_round;
  189. #else
  190. r = rint(Double_val(f));
  191. if ((r > (double) (Max_long)) || (r < (double)(Min_long))) goto raise_round;
  192. i = (long) r;
  193. v = Val_long(i);
  194. #endif
  195. return v;
  196. raise_round:
  197. raise_overflow();
  198. return Val_unit; /* Can't reach return */
  199. }
  200. value sml_trunc(value f) /* ML */
  201. { double r;
  202. long i;
  203. value v;
  204. r = Double_val(f);
  205. if ((r >= (double) (Max_long+1)) || (r <= (double)(Min_long-1)))
  206. goto raise_trunc;
  207. i = (long) r;
  208. v = Val_long(i);
  209. return v;
  210. raise_trunc:
  211. raise_overflow();
  212. return Val_unit; /* Can't reach return */
  213. }
  214. value sml_abs_real(value f) /* ML */
  215. { double r;
  216. float_exn = SYS__EXN_OVERFLOW;
  217. r = Double_val(f);
  218. if( r >= 0.0 )
  219. return f;
  220. else
  221. r = -r;
  222. Check_float(r);
  223. return copy_double(r);
  224. }
  225. value sml_sqrt(value f) /* ML */
  226. { double r;
  227. float_exn = SYS__EXN_DOMAIN;
  228. r = Double_val(f);
  229. Raise_float_if( r < 0.0 );
  230. r = sqrt(r);
  231. Check_float(r);
  232. return copy_double(r);
  233. }
  234. value sml_sin(value f) /* ML */
  235. { double r;
  236. r = Double_val(f);
  237. r = sin(r);
  238. if( r != r || r > 1.0 || r < -1.0 )
  239. failwith("sin: argument too large");
  240. return copy_double(r);
  241. }
  242. value sml_cos(value f) /* ML */
  243. { double r;
  244. r = Double_val(f);
  245. r = cos(r);
  246. if( r != r || r > 1.0 || r < -1.0 )
  247. failwith("cos: argument too large");
  248. return copy_double(r);
  249. }
  250. value sml_exp(value f) /* ML */
  251. { double r;
  252. float_exn = SYS__EXN_OVERFLOW;
  253. r = exp(Double_val(f));
  254. Check_float(r);
  255. return copy_double(r);
  256. }
  257. value sml_ln(value f) /* ML */
  258. { double r;
  259. float_exn = SYS__EXN_DOMAIN;
  260. r = Double_val(f);
  261. Raise_float_if( r <= 0.0 );
  262. r = log(r);
  263. Check_float(r);
  264. return copy_double(r);
  265. }
  266. unsigned long scandec(char * p, unsigned long max)
  267. { unsigned long res;
  268. int c, d;
  269. res = 0;
  270. while (1) {
  271. c = *p;
  272. if (c >= '0' && c <= '9')
  273. d = c - '0';
  274. else
  275. break;
  276. if( (res > (max/10)) ||
  277. ((res == (max/10) && ((max % 10) <= d))) )
  278. goto raise_failure;
  279. res = 10 * res + d;
  280. p++;
  281. }
  282. if (*p != 0)
  283. goto raise_failure;
  284. return res;
  285. raise_failure:
  286. failwith("scandec");
  287. return 0; /* Can't reach return */
  288. }
  289. unsigned long scanhex(char * p, unsigned long max)
  290. { unsigned long res;
  291. int c, d;
  292. res = 0;
  293. while (1) {
  294. c = toupper(*p);
  295. if (c >= '0' && c <= '9')
  296. d = c - '0';
  297. else if (c >= 'A' && c <= 'F')
  298. d = c + (10 - 'A');
  299. else
  300. break;
  301. if( (res > (max/16)) ||
  302. ((res == (max/16) && ((max % 16) <= d))) )
  303. goto raise_failure;
  304. res = 16 * res + d;
  305. p++;
  306. }
  307. if (*p != 0)
  308. goto raise_failure;
  309. return res;
  310. raise_failure:
  311. failwith("scanhex");
  312. return 0; /* Can't reach return */
  313. }
  314. value sml_int_of_string(value s) /* ML */
  315. { value v;
  316. long res;
  317. int sign;
  318. char * p;
  319. p = String_val(s);
  320. sign = 1;
  321. if (*p == '~') {
  322. sign = -1;
  323. p++;
  324. }
  325. res = sign * scandec(p, (unsigned long)Min_long);
  326. v = Val_long(res);
  327. if( Long_val(v) != res )
  328. goto raise_failure;
  329. return v;
  330. raise_failure:
  331. failwith("sml_int_of_string");
  332. return Val_unit; /* Can't reach return */
  333. }
  334. value sml_concat(value s1, value s2) /* ML */
  335. {
  336. mlsize_t len1, len2, len;
  337. value s;
  338. len1 = string_length(s1);
  339. if (len1 == 0)
  340. return s2;
  341. len2 = string_length(s2);
  342. if (len2 == 0)
  343. return s1;
  344. {
  345. Push_roots(r, 2);
  346. r[0] = s1;
  347. r[1] = s2;
  348. len = len1 + len2;
  349. if( (len + sizeof (value)) / sizeof (value) > Max_wosize )
  350. raiseprimitive0(SYS__EXN_SIZE);
  351. s = alloc_string(len);
  352. bcopy(&Byte(r[0],0), &Byte(s,0), len1);
  353. bcopy(&Byte(r[1],0), &Byte(s,len1), len2);
  354. Pop_roots();
  355. return s;
  356. }
  357. }
  358. value sml_chr(value v) /* ML */
  359. {
  360. long i;
  361. value s;
  362. i = Long_val(v);
  363. if( i < 0 || i > 255 )
  364. raiseprimitive0(SYS__EXN_CHR);
  365. s = alloc_string(1);
  366. *(&Byte(s,0)) = (unsigned char) i;
  367. return s;
  368. }
  369. value sml_ord(value s) /* ML */
  370. {
  371. long i;
  372. if( string_length(s) == 0 )
  373. raiseprimitive0(SYS__EXN_ORD);
  374. i = (unsigned char) *(&Byte(s,0));
  375. return Val_long(i);
  376. }
  377. value sml_float_of_string(value s) /* ML */
  378. {
  379. char buff[64];
  380. mlsize_t len;
  381. int i, e_len;
  382. char c;
  383. char *p;
  384. double r;
  385. len = string_length(s);
  386. if(len > sizeof(buff) - 1)
  387. failwith("sml_float_of_string: argument too large");
  388. p = String_val(s);
  389. e_len = -1;
  390. for (i = 0; i<len; i++) {
  391. c = *p++;
  392. switch( c ) {
  393. case '~':
  394. buff[i] = '-'; break;
  395. case 'E':
  396. buff[i] = 'e'; e_len = 0; break;
  397. default:
  398. buff[i] = c;
  399. if( e_len >= 0 ) e_len++;
  400. Raise_float_if( e_len > 5 )
  401. break;
  402. }
  403. }
  404. buff[len] = 0;
  405. r = atof(buff);
  406. if( (r > maxdouble) || (r < -maxdouble) )
  407. failwith("sml_float_of_string: result too large");
  408. return copy_double(r);
  409. }
  410. static int countChar(int c, char * s)
  411. {
  412. char *p; int count;
  413. count = 0;
  414. for( p=s; *p != '\0'; p++ ) {
  415. if( *p == c ) count++;
  416. }
  417. return count;
  418. }
  419. /* Here we remove all '+', and replace '-' and 'e' with '~' and 'E'.
  420. Also, drop a single leading zero from the exponent. */
  421. static void mkSMLMinus(char * s)
  422. {
  423. char *p = s, *q = s;
  424. int justafterexp = 0; /* After exponent but before digits */
  425. for ( ; *p != '\0'; p++) {
  426. switch( *p ) {
  427. case '+': break;
  428. case '-': *q++ = '~'; break;
  429. case 'e': *q++ = 'E'; justafterexp = 1; break;
  430. case '0':
  431. if (!justafterexp) /* Don't copy zero just after exponent */
  432. *q++ = '0';
  433. justafterexp = 0;
  434. break;
  435. default: *q++ = *p; justafterexp = 0; break;
  436. }
  437. }
  438. *q = '\0';
  439. return;
  440. }
  441. value sml_string_of_int(value arg) /* ML */
  442. {
  443. char format_buffer[32];
  444. sprintf(format_buffer, "%ld", Long_val(arg));
  445. mkSMLMinus(format_buffer);
  446. return copy_string(format_buffer);
  447. }
  448. /* Convert real x to SMLish format in format_buffer */
  449. void string_of_float_aux(char* format_buffer, double x)
  450. {
  451. sprintf(format_buffer, "%.12g", x);
  452. mkSMLMinus(format_buffer);
  453. if( countChar('.', format_buffer) == 0 &&
  454. countChar('E', format_buffer) == 0 )
  455. strcat(format_buffer, ".0");
  456. }
  457. value sml_string_of_float(value arg) /* ML */
  458. {
  459. char format_buffer[64];
  460. string_of_float_aux(format_buffer, Double_val(arg));
  461. return copy_string(format_buffer);
  462. }
  463. #ifdef __MWERKS__
  464. #pragma mpwc_newline on
  465. #endif
  466. value sml_makestring_of_char(value arg) /* ML */
  467. {
  468. unsigned char c;
  469. char buff[8];
  470. c = Int_val(arg);
  471. switch (c)
  472. {
  473. case '"': return copy_string("#\"\\\"\"");
  474. case '\\': return copy_string("#\"\\\\\"");
  475. case '\a': return copy_string("#\"\\a\"");
  476. case '\b': return copy_string("#\"\\b\"");
  477. case '\t': return copy_string("#\"\\t\"");
  478. case '\n': return copy_string("#\"\\n\"");
  479. case '\v': return copy_string("#\"\\v\"");
  480. case '\f': return copy_string("#\"\\f\"");
  481. case '\r': return copy_string("#\"\\r\"");
  482. default:
  483. buff[0] = '#'; buff[1] = '"';
  484. if( c <= 31 ) {
  485. buff[2] = '\\'; buff[3] = '^'; buff[4] = c + 64;
  486. buff[5] = '"'; buff[6] = 0;
  487. return copy_string(buff);
  488. }
  489. else if( (32 <= c && c <= 126) || (128 <= c && c <= 254) ) {
  490. buff[2] = c; buff[3] = '"'; buff[4] = 0;
  491. return copy_string(buff);
  492. }
  493. else {
  494. buff[2] = '\\';
  495. buff[3] = 48 + c / 100;
  496. buff[4] = 48 + (c / 10) % 10;
  497. buff[5] = 48 + c % 10;
  498. buff[6] = '"';
  499. buff[7] = 0;
  500. return copy_string(buff);
  501. }
  502. }
  503. }
  504. value sml_makestring_of_string(value arg) /* ML */
  505. {
  506. mlsize_t arg_len, len, i;
  507. value res;
  508. char *a; char *b;
  509. unsigned char c;
  510. Push_roots(r, 1);
  511. r[0] = arg;
  512. arg_len = string_length(arg);
  513. a = String_val(r[0]);
  514. len = 0;
  515. for( i = 0; i < arg_len; i++ ) {
  516. c = a[i];
  517. switch (c)
  518. {
  519. case '"': case '\\':
  520. case '\a': case '\b': case '\t': case '\n': case '\v':
  521. case '\f': case '\r':
  522. len += 2; break;
  523. default:
  524. if( c <= 31)
  525. len += 3;
  526. else if( (32 <= c && c <= 126) || (128 <= c && c <= 254) )
  527. len += 1;
  528. else
  529. len += 4;
  530. break;
  531. }
  532. }
  533. if( (len + 2 + sizeof (value)) / sizeof (value) > Max_wosize )
  534. failwith("sml_string_for_read: result too large");
  535. res = alloc_string(len + 2);
  536. a = String_val(r[0]);
  537. b = String_val(res);
  538. *b++ = '"';
  539. for( i = 0; i < arg_len; i++) {
  540. c = a[i];
  541. switch (c)
  542. {
  543. case '"': *b++ = '\\'; *b++ = '"'; break;
  544. case '\\': *b++ = '\\'; *b++ = '\\'; break;
  545. case '\a': *b++ = '\\'; *b++ = 'a'; break;
  546. case '\b': *b++ = '\\'; *b++ = 'b'; break;
  547. case '\t': *b++ = '\\'; *b++ = 't'; break;
  548. case '\n': *b++ = '\\'; *b++ = 'n'; break;
  549. case '\v': *b++ = '\\'; *b++ = 'v'; break;
  550. case '\f': *b++ = '\\'; *b++ = 'f'; break;
  551. case '\r': *b++ = '\\'; *b++ = 'r'; break;
  552. default:
  553. if( c <= 31 )
  554. { *b++ = '\\'; *b++ = '^'; *b++ = c + 64; break; }
  555. else if( (32 <= c && c <= 126) || (128 <= c && c <= 254) )
  556. { *b++ = c; break; }
  557. else
  558. { *b++ = '\\';
  559. *b++ = 48 + c / 100;
  560. *b++ = 48 + (c / 10) % 10;
  561. *b++ = 48 + c % 10;
  562. break; }
  563. }
  564. }
  565. *b++ = '"';
  566. Pop_roots();
  567. return res;
  568. }
  569. #ifdef __MWERKS__
  570. #pragma mpwc_newline off
  571. #endif
  572. /* There is another problem on the Mac: with a time base of 1904,
  573. most times are simply out of range of mosml integers. So, I added
  574. the macros below to compensate. 07Sep95 e
  575. */
  576. #ifndef macintosh
  577. #define SYStoSMLtime
  578. #define SMLtoSYStime
  579. #endif
  580. /* Return time as (double) number of usec since the epoch */
  581. value sml_getrealtime (value v) /* ML */
  582. {
  583. #ifdef WIN32
  584. value res;
  585. struct timeb t;
  586. /*
  587. // It seems that the time returned by 'ftime' under MS Windows
  588. // disagree with that returned by 'gettimeofday' under MS DOS!
  589. // The following lines are written according the specification
  590. // of 'ftime' though...
  591. // Experiments show, that in Moscow the result returned by
  592. // 'ftime' is recalculated into the correct local time, while
  593. // the time calculated from the result of 'gettimeofday' is
  594. // 1 hour late.
  595. // Sergei Romanenko
  596. */
  597. ftime(&t);
  598. return copy_double(t.time*1000000.0 + t.millitm*1000.0);
  599. #else
  600. struct timeval tp;
  601. gettimeofday(&tp, NULL);
  602. return copy_double((SYStoSMLtime(tp.tv_sec))*1000000.0 + (double)tp.tv_usec);
  603. #endif
  604. }
  605. value sml_getrutime (value v) /* ML */
  606. {
  607. value res;
  608. #if defined(__MWERKS__)
  609. res = e_getrusage();
  610. #else
  611. #ifdef WIN32
  612. /*
  613. // Here I return sysTime = usrTime.
  614. // Perhaps, win32 enables sysTime and usrTime to be mesured
  615. // in an accurate way...
  616. // Sergei Romanenko
  617. */
  618. struct timeb t;
  619. ftime(&t);
  620. res = alloc (6, 0);
  621. Field (res, 2) = Val_long (t.time);
  622. Field (res, 3) = Val_long (((long) t.millitm) * 1000);
  623. Field (res, 4) = Val_long (t.time);
  624. Field (res, 5) = Val_long (((long) t.millitm) * 1000);
  625. #elif defined(hpux) || defined(__svr4__)
  626. struct tms buffer;
  627. long persec = sysconf(_SC_CLK_TCK);
  628. times(&buffer);
  629. res = alloc (6, 0);
  630. Field (res, 2) = Val_long (buffer.tms_stime / persec);
  631. Field (res, 3) = Val_long ((buffer.tms_stime % persec) * (1000000 / persec));
  632. Field (res, 4) = Val_long (buffer.tms_utime / persec);
  633. Field (res, 5) = Val_long ((buffer.tms_utime % persec) * (1000000 / persec));
  634. #else
  635. struct rusage rusages;
  636. getrusage(RUSAGE_SELF, &rusages);
  637. res = alloc (6, 0);
  638. Field (res, 2) = Val_long (rusages.ru_stime.tv_sec);
  639. Field (res, 3) = Val_long (rusages.ru_stime.tv_usec);
  640. Field (res, 4) = Val_long (rusages.ru_utime.tv_sec);
  641. Field (res, 5) = Val_long (rusages.ru_utime.tv_usec);
  642. #endif
  643. Field (res, 0) = Val_long (gc_time.tv_sec);
  644. Field (res, 1) = Val_long (gc_time.tv_usec);
  645. #endif
  646. return res;
  647. }
  648. value sml_errno(value arg) /* ML */
  649. {
  650. return Val_long(errno);
  651. }
  652. value sml_getdir(value arg) /* ML */
  653. {
  654. #ifdef WIN32
  655. char directory[_MAX_PATH];
  656. char *res;
  657. errno = 0;
  658. /* Unlike Unix and DJ GPP, the path is returned with the drive letter, */
  659. /* and with '\', rather then '/'! */
  660. res = getcwd(directory, _MAX_PATH);
  661. if (res == NULL)
  662. failwith("getcwd");
  663. for( ; *res; res++ )
  664. if( *res == '\\' )
  665. *res = '/';
  666. return copy_string(directory);
  667. #else
  668. char directory[MAXPATHLEN];
  669. char *res;
  670. errno = 0;
  671. res = getcwd(directory, MAXPATHLEN);
  672. if (res == NULL)
  673. failwith("getcwd");
  674. return copy_string(directory);
  675. #endif
  676. }
  677. value sml_mkdir(value path) /* ML */
  678. {
  679. #ifdef WIN32
  680. /* Unlike Unix and DJ GPP, the path may contain a drive letter, */
  681. /* and must contain '\' rather than '/'. */
  682. if (mkdir(String_val(path)) == -1)
  683. failwith("mkdir");
  684. return Val_unit;
  685. #else
  686. if (mkdir(String_val(path), 0777) == -1)
  687. failwith("mkdir");
  688. return Val_unit;
  689. #endif
  690. }
  691. value sml_rmdir(value path) /* ML */
  692. {
  693. if (rmdir(String_val(path)) == -1)
  694. failwith("rmdir");
  695. return Val_unit;
  696. }
  697. #ifdef WIN32
  698. typedef struct
  699. {
  700. WIN32_FIND_DATA FileData;
  701. char szSearchPath[MAX_PATH];
  702. HANDLE hSearch;
  703. BOOL fFinished;
  704. char d_name[MAX_PATH];
  705. } MY_DIR;
  706. MY_DIR *my_opendir(const char* dirname)
  707. {
  708. MY_DIR *dstr;
  709. dstr = malloc(sizeof(MY_DIR));
  710. if( dstr == NULL ) return NULL;
  711. memset(dstr, 0, sizeof(MY_DIR));
  712. strncpy(dstr->szSearchPath, dirname, MAX_PATH);
  713. strncat(dstr->szSearchPath, "\\*.*", MAX_PATH);
  714. dstr->szSearchPath[MAX_PATH-1] = '\0';
  715. dstr->hSearch = FindFirstFile(dstr->szSearchPath, &dstr->FileData);
  716. if (dstr->hSearch == INVALID_HANDLE_VALUE)
  717. {
  718. free(dstr);
  719. return NULL;
  720. }
  721. dstr->fFinished = FALSE;
  722. return dstr;
  723. }
  724. void my_readdir(MY_DIR *dstr)
  725. {
  726. if( dstr->fFinished )
  727. dstr->d_name[0] = '\0';
  728. else
  729. {
  730. strncpy(dstr->d_name, dstr->FileData.cFileName, MAX_PATH);
  731. if (!FindNextFile(dstr->hSearch, &dstr->FileData))
  732. {
  733. dstr->fFinished = TRUE;
  734. FindClose(dstr->hSearch);
  735. }
  736. }
  737. }
  738. void my_closedir(MY_DIR *dstr)
  739. {
  740. if( !dstr->fFinished )
  741. FindClose(dstr->hSearch);
  742. free(dstr);
  743. }
  744. BOOL my_rewinddir(MY_DIR *dstr)
  745. {
  746. if( !dstr->fFinished )
  747. FindClose(dstr->hSearch);
  748. dstr->hSearch = FindFirstFile(dstr->szSearchPath, &dstr->FileData);
  749. if (dstr->hSearch == INVALID_HANDLE_VALUE)
  750. {
  751. free(dstr);
  752. return FALSE;
  753. }
  754. dstr->fFinished = FALSE;
  755. return TRUE;
  756. }
  757. #endif
  758. value sml_opendir(value path) /* ML */
  759. {
  760. #ifdef WIN32
  761. MY_DIR *dstr;
  762. dstr = my_opendir(String_val(path));
  763. if (dstr == NULL)
  764. failwith("opendir");
  765. return (value) dstr;
  766. #else
  767. DIR * dstr;
  768. dstr = opendir(String_val(path));
  769. if (dstr == NULL)
  770. failwith("opendir");
  771. #ifdef MSDOS
  772. if (readdir(dstr) == NULL)
  773. failwith("opendir");
  774. else
  775. rewinddir(dstr);
  776. #endif
  777. return (value) dstr;
  778. #endif
  779. }
  780. value sml_rewinddir(value v) /* ML */
  781. {
  782. #ifdef WIN32
  783. if( !my_rewinddir((MY_DIR *) v) )
  784. failwith("opendir");
  785. return Val_unit;
  786. #else
  787. rewinddir((DIR *) v);
  788. return Val_unit;
  789. #endif
  790. }
  791. value sml_readdir(value v) /* ML */
  792. {
  793. #ifdef WIN32
  794. MY_DIR *dstr;
  795. dstr = (MY_DIR *) v;
  796. my_readdir(dstr);
  797. if( dstr->d_name[0] == '\0' )
  798. return copy_string("");
  799. return copy_string(dstr->d_name);
  800. #else
  801. struct dirent *direntry;
  802. direntry = readdir((DIR *) v);
  803. if (direntry == NULL)
  804. return copy_string("");
  805. return copy_string((*direntry).d_name);
  806. #endif
  807. }
  808. value sml_closedir(value v) /* ML */
  809. {
  810. #ifdef WIN32
  811. my_closedir((MY_DIR *) v);
  812. return Val_unit;
  813. #else
  814. if (closedir((DIR *) v) == -1)
  815. failwith("closedir");
  816. return Val_unit;
  817. #endif
  818. }
  819. value sml_isdir(value path) /* ML */
  820. {
  821. #ifdef WIN32
  822. DWORD dwFileAttributes = GetFileAttributes( String_val(path) );
  823. if( dwFileAttributes == 0xFFFFFFFF )
  824. failwith("isdir");
  825. return (Val_bool(dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
  826. #else
  827. struct stat buf;
  828. if (stat(String_val(path), &buf) == -1)
  829. failwith("stat");
  830. return (Val_bool(S_ISDIR(buf.st_mode)));
  831. #endif
  832. }
  833. value sml_modtime(value path) /* ML */
  834. { struct stat buf;
  835. if (stat(String_val(path), &buf) == -1)
  836. failwith("stat");
  837. return (copy_double ((double) (SYStoSMLtime(buf.st_mtime))));
  838. }
  839. value sml_settime(value path, value time) /* ML */
  840. {
  841. struct utimbuf tbuf;
  842. tbuf.actime = tbuf.modtime = SMLtoSYStime((long) (Double_val(time)));
  843. if (utime(String_val(path), &tbuf) == -1)
  844. failwith("utime");
  845. return Val_unit;
  846. }
  847. #ifdef WIN32
  848. #define F_OK 0 /* does file exist */
  849. #define X_OK 1 /* is it executable by caller */
  850. #define W_OK 2 /* is it writable by caller */
  851. #define R_OK 4 /* is it readable by caller */
  852. #endif
  853. value sml_access(value path, value permarg) /* ML */
  854. {
  855. long perms;
  856. long perm = Long_val(permarg);
  857. perms = ((0x1 & perm) ? R_OK : 0);
  858. perms |= ((0x2 & perm) ? W_OK : 0);
  859. perms |= ((0x4 & perm) ? X_OK : 0);
  860. if (perms == 0) perms = F_OK;
  861. if (access(String_val(path), perms) == 0)
  862. return Val_bool(1);
  863. return Val_bool(0);
  864. }
  865. #ifndef HAS_STRERROR
  866. #if (!defined(__FreeBSD__) && !defined(linux))
  867. extern int sys_nerr;
  868. extern char * sys_errlist [];
  869. #endif
  870. extern char *realpath();
  871. #endif
  872. value sml_tmpnam(value v) /* ML */
  873. { char *res;
  874. #ifdef WIN32
  875. value value_res;
  876. res = _tempnam(NULL, "mosml");
  877. if (res == NULL)
  878. failwith("tmpnam");
  879. value_res = copy_string(res);
  880. free(res);
  881. return value_res;
  882. #else
  883. res = tmpnam(NULL);
  884. if (res == NULL)
  885. failwith("tmpnam");
  886. return copy_string(res);
  887. #endif
  888. }
  889. value sml_errormsg(value err) /* ML */
  890. {
  891. int errnum;
  892. errnum = Long_val(err);
  893. #ifdef HAS_STRERROR
  894. return copy_string(strerror(errnum));
  895. #else
  896. if (errnum < 0 || errnum >= sys_nerr)
  897. return copy_string("(Unknown error)");
  898. else
  899. return copy_string(sys_errlist[errnum]);
  900. #endif
  901. }
  902. value sml_asin(value f) /* ML */
  903. { double r = Double_val(f);
  904. float_exn = SYS__EXN_DOMAIN;
  905. Raise_float_if( r < -1.0 || r > 1.0 );
  906. r = asin(r);
  907. Raise_float_if( r != r );
  908. return copy_double(r);
  909. }
  910. value sml_acos(value f) /* ML */
  911. { double r = Double_val(f);
  912. float_exn = SYS__EXN_DOMAIN;
  913. Raise_float_if( r < -1.0 || r > 1.0 );
  914. r = acos(r);
  915. Raise_float_if( r != r );
  916. return copy_double(r);
  917. }
  918. value sml_atan2(value f1, value f2) /* ML */
  919. { double r, r1, r2;
  920. float_exn = SYS__EXN_DOMAIN;
  921. r1 = Double_val(f1);
  922. r2 = Double_val(f2);
  923. if (r1 == 0.0 && r2 == 0.0)
  924. return copy_double(0.0);
  925. r = atan2(r1, r2);
  926. Check_float(r);
  927. Raise_float_if( r != r );
  928. return copy_double(r);
  929. }
  930. value sml_pow(value f1, value f2) /* ML */
  931. { double r, r1, r2;
  932. float_exn = SYS__EXN_DOMAIN;
  933. r1 = Double_val(f1);
  934. r2 = Double_val(f2);
  935. if (r1 == 0.0 && r2 == 0.0)
  936. return copy_double(1.0);
  937. if ( (r1 == 0.0 && r2 < 0.0)
  938. || (r1 < 0.0 && ( fabs(r2) > (double) (Max_long)
  939. || r2 != (double)(long)r2)))
  940. raiseprimitive0(float_exn);
  941. r = pow(r1, r2);
  942. float_exn = SYS__EXN_OVERFLOW;
  943. Check_float(r);
  944. float_exn = SYS__EXN_DOMAIN;
  945. Raise_float_if( r != r );
  946. return copy_double(r);
  947. }
  948. value sml_localtime (value v) /* ML */
  949. {
  950. value res;
  951. struct tm *tmr;
  952. time_t clock = SMLtoSYStime((long) (Double_val(v)));
  953. tmr = localtime(&clock);
  954. res = alloc (9, 0);
  955. Field (res, 0) = Val_long ((*tmr).tm_hour);
  956. Field (res, 1) = Val_long ((*tmr).tm_isdst);
  957. Field (res, 2) = Val_long ((*tmr).tm_mday);
  958. Field (res, 3) = Val_long ((*tmr).tm_min);
  959. Field (res, 4) = Val_long ((*tmr).tm_mon);
  960. Field (res, 5) = Val_long ((*tmr).tm_sec);
  961. Field (res, 6) = Val_long ((*tmr).tm_wday);
  962. Field (res, 7) = Val_long ((*tmr).tm_yday);
  963. Field (res, 8) = Val_long ((*tmr).tm_year);
  964. return res;
  965. }
  966. value sml_gmtime (value v) /* ML */
  967. {
  968. value res;
  969. struct tm *tmr;
  970. time_t clock = SMLtoSYStime((long) (Double_val(v)));
  971. tmr = gmtime(&clock);
  972. res = alloc (9, 0);
  973. Field (res, 0) = Val_long ((*tmr).tm_hour);
  974. Field (res, 1) = Val_long ((*tmr).tm_isdst);
  975. Field (res, 2) = Val_long ((*tmr).tm_mday);
  976. Field (res, 3) = Val_long ((*tmr).tm_min);
  977. Field (res, 4) = Val_long ((*tmr).tm_mon);
  978. Field (res, 5) = Val_long ((*tmr).tm_sec);
  979. Field (res, 6) = Val_long ((*tmr).tm_wday);
  980. Field (res, 7) = Val_long ((*tmr).tm_yday);
  981. Field (res, 8) = Val_long ((*tmr).tm_year);
  982. return res;
  983. }
  984. value sml_mktime (value v) /* ML */
  985. {
  986. struct tm tmr = {0};
  987. tmr.tm_hour = Long_val(Field (v, 0));
  988. tmr.tm_isdst = Long_val(Field (v, 1));
  989. tmr.tm_mday = Long_val(Field (v, 2));
  990. tmr.tm_min = Long_val(Field (v, 3));
  991. tmr.tm_mon = Long_val(Field (v, 4));
  992. tmr.tm_sec = Long_val(Field (v, 5));
  993. tmr.tm_wday = Long_val(Field (v, 6));
  994. tmr.tm_yday = Long_val(Field (v, 7));
  995. tmr.tm_year = Long_val(Field (v, 8));
  996. return copy_double((double)SYStoSMLtime(tm2cal(&tmr)));
  997. }
  998. value sml_asctime (value v) /* ML */
  999. {
  1000. struct tm tmr = {0};
  1001. char *res;
  1002. tmr.tm_hour = Long_val(Field (v, 0));
  1003. tmr.tm_isdst = Long_val(Field (v, 1));
  1004. tmr.tm_mday = Long_val(Field (v, 2));
  1005. tmr.tm_min = Long_val(Field (v, 3));
  1006. tmr.tm_mon = Long_val(Field (v, 4));
  1007. tmr.tm_sec = Long_val(Field (v, 5));
  1008. tmr.tm_wday = Long_val(Field (v, 6));
  1009. tmr.tm_yday = Long_val(Field (v, 7));
  1010. tmr.tm_year = Long_val(Field (v, 8));
  1011. res = asctime(&tmr);
  1012. if (res == NULL)
  1013. failwith("asctime");
  1014. return copy_string(res);
  1015. }
  1016. value sml_strftime (value fmt, value v) /* ML */
  1017. {
  1018. struct tm tmr = {0};
  1019. #define BUFSIZE 256
  1020. char buf[BUFSIZE];
  1021. long ressize;
  1022. tmr.tm_hour = Long_val(Field (v, 0));
  1023. tmr.tm_isdst = Long_val(Field (v, 1));
  1024. tmr.tm_mday = Long_val(Field (v, 2));
  1025. tmr.tm_min = Long_val(Field (v, 3));
  1026. tmr.tm_mon = Long_val(Field (v, 4));
  1027. tmr.tm_sec = Long_val(Field (v, 5));
  1028. tmr.tm_wday = Long_val(Field (v, 6));
  1029. tmr.tm_yday = Long_val(Field (v, 7));
  1030. tmr.tm_year = Long_val(Field (v, 8));
  1031. ressize = strftime(buf, BUFSIZE, String_val(fmt), &tmr);
  1032. if (ressize == 0 || ressize == BUFSIZE)
  1033. failwith("strftime");
  1034. return copy_string(buf);
  1035. #undef BUFSIZE
  1036. }
  1037. value sml_general_string_of_float(value fmt, value arg) /* ML */
  1038. {
  1039. #define BUFSIZE 512
  1040. char format_buffer[BUFSIZE];
  1041. /* Unfortunately there seems to be no way to ensure that this does not
  1042. * crash by overflowing the format_buffer (e.g. when specifying a huge
  1043. * number of decimal digits in the fixed-point format). Well, we might
  1044. * use snprintf if universally supported?
  1045. */
  1046. double x = Double_val(arg);
  1047. if (x == -0.0) x = 0.0;
  1048. sprintf(format_buffer, String_val(fmt), x);
  1049. mkSMLMinus(format_buffer);
  1050. return copy_string(format_buffer);
  1051. #undef BUFSIZE
  1052. }
  1053. value sml_filesize(value path) /* ML */
  1054. { struct stat buf;
  1055. if (stat(String_val(path), &buf) == -1)
  1056. failwith("stat");
  1057. return (Val_long (buf.st_size));
  1058. }
  1059. value sml_int_of_hex(value s) /* ML */
  1060. { value v;
  1061. long res;
  1062. int sign;
  1063. char * p;
  1064. /* The argument s has form [~]?0x[0-9a-fA-F]+ */
  1065. p = String_val(s);
  1066. sign = 1;
  1067. if (*p == '~') {
  1068. sign = -1;
  1069. p++;
  1070. }
  1071. /* skip 0x in s */
  1072. p += 2;
  1073. res = sign * scanhex(p, (unsigned long)Min_long);
  1074. v = Val_long(res);
  1075. if( Long_val(v) != res )
  1076. goto raise_failure;
  1077. return v;
  1078. raise_failure:
  1079. failwith("sml_int_of_hex");
  1080. return Val_unit; /* Can't reach return */
  1081. }
  1082. value sml_word_of_hex(value s) /* ML */
  1083. { value v;
  1084. long res;
  1085. char * p;
  1086. /* The argument s has form 0wx[0-9a-fA-F]+ */
  1087. p = String_val(s);
  1088. /* skip 0wx in s */
  1089. p += 3;
  1090. res = scanhex(p, 2 * (unsigned long)Min_long);
  1091. v = Val_long((long)res);
  1092. return v;
  1093. }
  1094. value sml_word_of_dec(value s) /* ML */
  1095. { value v;
  1096. long res;
  1097. char * p;
  1098. /* The argument s has form 0w[0-9]+ */
  1099. p = String_val(s);
  1100. /* skip 0w in s */
  1101. p += 2;
  1102. res = (long)scandec(p, 2 * (unsigned long)Min_long);
  1103. v = Val_long((long)res);
  1104. return v;
  1105. }
  1106. value sml_hexstring_of_word(value arg) /* ML */
  1107. {
  1108. char format_buffer[32];
  1109. sprintf(format_buffer, "0wx%lX", Long_val((unsigned long)arg));
  1110. return copy_string(format_buffer);
  1111. }
  1112. value sml_sinh(value f) /* ML */
  1113. { double r;
  1114. float_exn = SYS__EXN_OVERFLOW;
  1115. r = Double_val(f);
  1116. r = sinh(r);
  1117. Check_float(r);
  1118. return copy_double(r);
  1119. }
  1120. value sml_cosh(value f) /* ML */
  1121. { double r;
  1122. float_exn = SYS__EXN_OVERFLOW;
  1123. r = Double_val(f);
  1124. r = cosh(r);
  1125. Check_float(r);
  1126. return copy_double(r);
  1127. }
  1128. value sml_tanh(value f) /* ML */
  1129. { double r;
  1130. float_exn = SYS__EXN_DOMAIN;
  1131. r = Double_val(f);
  1132. r = tanh(r);
  1133. Check_float(r);
  1134. return copy_double(r);
  1135. }
  1136. /* A weak pointer v is dead (dangling) if NULL, or if we are in the
  1137. weak phase and v is a white block in the heap.
  1138. Conversely, v is live if
  1139. * v is non-NULL
  1140. AND
  1141. * v isn't a block (e.g. an int or char), OR
  1142. * v isn't in the heap (e.g. is an atom, or in the young generation), OR
  1143. * we're in the mark phase (in which v may be resurrected by darkening), OR
  1144. * we're in the weak phase but v has been darkened (so it will survive
  1145. the sweep phase), OR
  1146. * we're in the sweep phase (since the pointer hasn't been reset by the
  1147. weak phase, v must have been dark at that time; hence v will
  1148. not be deallocated, but sweeping may have changed its color already).
  1149. */
  1150. int isdead(value v)
  1151. {
  1152. return v == (value)NULL
  1153. || (gc_phase == Phase_weak
  1154. && Is_block(v) && Is_in_heap(v) && Is_white_val(v));
  1155. }
  1156. value weak_sub(value arr, value index) /* ML */
  1157. {
  1158. value v = Field(arr, Long_val(index));
  1159. if (isdead(v))
  1160. failwith("Dangling weak pointer");
  1161. else
  1162. if (gc_phase == Phase_mark)
  1163. darken(v);
  1164. return v;
  1165. }
  1166. value weak_isdead(value arr, value index) /* ML */
  1167. {
  1168. return Val_bool(isdead(Field(arr, Long_val(index))));
  1169. }
  1170. value weak_arr(value size) /* ML */
  1171. {
  1172. value res;
  1173. mlsize_t sz, i;
  1174. sz = Long_val(size);
  1175. if (sz == 0) return Atom(Weak_tag);
  1176. res = alloc_shr(sz, Weak_tag); /* Must go in the major heap */
  1177. for (i = 0; i < sz; i++)
  1178. Field(res, i) = (value)NULL;
  1179. return res;
  1180. }
  1181. /* Turn an ML value into an externalized ML value (a string), a la extern.c */
  1182. value string_mlval(value val) /* ML */
  1183. {
  1184. value s;
  1185. byteoffset_t res;
  1186. extern_size = INITIAL_EXTERN_SIZE;
  1187. extern_block =
  1188. (byteoffset_t *) stat_alloc(extern_size * sizeof(unsigned long));
  1189. extern_pos = 0;
  1190. extern_table_size = INITIAL_EXTERN_TABLE_SIZE;
  1191. alloc_extern_table();
  1192. extern_table_used = 0;
  1193. res = emit_all(val);
  1194. stat_free((char *) extern_table);
  1195. /* We can allocate a string in the heap since the argument value is
  1196. not used from now on. */
  1197. if (extern_pos == 0)
  1198. {
  1199. s = alloc_string(8);
  1200. ((asize_t *)s)[0] = (asize_t)extern_pos;
  1201. ((asize_t *)s)[1] = (asize_t)res;
  1202. }
  1203. else
  1204. {
  1205. s = alloc_string(4 + extern_pos * sizeof(unsigned long));
  1206. ((asize_t *)s)[0] = (asize_t)extern_pos;
  1207. bcopy((char *) extern_block, &Byte(s, 4),
  1208. extern_pos * sizeof(unsigned long));
  1209. }
  1210. stat_free((char *) extern_block);
  1211. return s;
  1212. }
  1213. /* Turn an externalized ML value (a string) into an ML value, a la intern.c */
  1214. value mlval_string(value s) /* ML */
  1215. {
  1216. value res;
  1217. mlsize_t whsize, wosize;
  1218. unsigned long bhsize;
  1219. color_t color;
  1220. header_t hd;
  1221. whsize = ((mlsize_t *)s)[0];
  1222. if (whsize == 0) {
  1223. res = (value) ((mlsize_t *)s)[1];
  1224. if (Is_long(res))
  1225. return res;
  1226. else
  1227. return Atom(res >> 2);
  1228. }
  1229. bhsize = Bsize_wsize (whsize);
  1230. wosize = Wosize_whsize (whsize);
  1231. if (wosize > Max_wosize)
  1232. failwith("mlval_string: structure too big");
  1233. res = alloc_shr(wosize, String_tag);
  1234. hd = Hd_val (res);
  1235. color = Color_hd (hd);
  1236. Assert (color == White || color == Black);
  1237. if (bhsize + 4 > string_length(s)) {
  1238. Hd_val (res) = hd; /* Avoid confusing the GC. */
  1239. failwith ("mlval_string: truncated object");
  1240. }
  1241. bcopy(&Byte(s, 4), Hp_val(res), bhsize);
  1242. adjust_pointers((value*)(Hp_val (res)), whsize, color);
  1243. return res;
  1244. }
  1245. /* Make a double from a float object, represented as a big-endian
  1246. four-byte Word8Vector value */
  1247. value w8vectofloat(value v) /* ML */
  1248. {
  1249. /* The v vector must have length = 4 bytes */
  1250. union { float flt; char w8[4]; } buf;
  1251. int i;
  1252. char* p = String_val(v);
  1253. for (i=0; i<4; i++)
  1254. #ifdef MOSML_BIG_ENDIAN
  1255. buf.w8[i] = p[i];
  1256. #else
  1257. buf.w8[i] = p[3-i];
  1258. #endif
  1259. return copy_double(buf.flt);
  1260. }
  1261. /* Make a big-endian four-byte Word8Vector value from a float,
  1262. represented as a double. */
  1263. value floattow8vec(value v) /* ML */
  1264. {
  1265. union { float flt; char w8[4]; } buf;
  1266. value res;
  1267. char* p;
  1268. int i;
  1269. buf.flt = (float)(Double_val(v));
  1270. res = alloc_string(4);
  1271. p = String_val(res);
  1272. for (i=0; i<4; i++)
  1273. #ifdef MOSML_BIG_ENDIAN
  1274. p[i] = buf.w8[i];
  1275. #else
  1276. p[i] = buf.w8[3-i];
  1277. #endif
  1278. return res;
  1279. }
  1280. /* Make a double from a double object, represented as a big-endian
  1281. eight-byte Word8Vector value */
  1282. value w8vectodouble(value v) /* ML */
  1283. {
  1284. /* The v vector must have length = 8 bytes */
  1285. value res;
  1286. #ifdef MOSML_BIG_ENDIAN
  1287. res = copy_double(Double_val(v));
  1288. #else
  1289. Push_roots(r, 1);
  1290. r[0] = v;
  1291. res = copy_double(0.0);
  1292. {
  1293. int i;
  1294. for (i=0; i<8; i++)
  1295. Byte(res, i) = Byte(r[0], 7-i);
  1296. }
  1297. Pop_roots();
  1298. #endif
  1299. return res;
  1300. }
  1301. /* Make a big-endian eight-byte Word8Vector value from a double. */
  1302. value doubletow8vec(value v) /* ML */
  1303. {
  1304. value res;
  1305. Push_roots(r, 1);
  1306. r[0] = v;
  1307. res = alloc_string(8);
  1308. Store_double_val(res, Double_val(r[0]));
  1309. Pop_roots();
  1310. #ifndef MOSML_BIG_ENDIAN
  1311. {
  1312. int i;
  1313. for (i=0; i<4; i++)
  1314. {
  1315. char tmp = Byte(res, i);
  1316. Byte(res, i) = Byte(res, 7-i);
  1317. Byte(res, 7-i) = tmp;
  1318. }
  1319. }
  1320. #endif
  1321. return res;
  1322. }
  1323. /* Modified from John Reppy's code (see SML Basis mail of 1997-08-01) */
  1324. value sml_localoffset(value v) /* ML */
  1325. {
  1326. struct tm *gmt;
  1327. time_t t1, t2;
  1328. double td;
  1329. t1 = time((time_t*)0);
  1330. gmt = gmtime (&t1);
  1331. t2 = tm2cal(gmt);
  1332. /* SunOS appears to lack difftime: */
  1333. #if defined(sun) && !defined(__svr4__)
  1334. td = (long)t2 - (long)t1;
  1335. #else
  1336. td = difftime(t2, t1);
  1337. #endif
  1338. return copy_double(td); /* not SYStoSMLtime(td) */
  1339. }
  1340. /* Return a name (as a string) of SML exception exn */
  1341. value sml_exnname(value exn) /* ML */
  1342. {
  1343. value strval = Field(Field(exn, 0), 0);
  1344. return strval;
  1345. }
  1346. /* Create a string representation of SML exception exn, if possible. */
  1347. char* exnmessage_aux(value exn)
  1348. {
  1349. #define BUFSIZE 256
  1350. char* buf = (char*)malloc(BUFSIZE+1);
  1351. /* An exn val is a pair (strref, argval) : string ref * 'a */
  1352. value strref = Field(exn, 0);
  1353. value strval = Field(strref, 0);
  1354. value argval = Field(exn, 1);
  1355. if (strref == Field(global_data, SYS__EXN_SYSERR)) {
  1356. value msgval = Field(argval, 0);
  1357. #if defined(__CYGWIN__) || defined(hpux)
  1358. sprintf(buf, "%s: %s",
  1359. String_val(strval), String_val(msgval));
  1360. #elif defined(WIN32)
  1361. _snprintf(buf, BUFSIZE, "%s: %s",
  1362. String_val(strval), String_val(msgval));
  1363. #else
  1364. snprintf(buf, BUFSIZE, "%s: %s",
  1365. String_val(strval), String_val(msgval));
  1366. #endif
  1367. return buf;
  1368. } else if (strref == Field(global_data, SYS__EXN_IO)) {
  1369. value causeval = Field(argval, 0);
  1370. value fcnval = Field(argval, 1);
  1371. value nameval = Field(argval, 2);
  1372. char* causetxt = exnmessage_aux(causeval);
  1373. #if defined(__CYGWIN__) || defined(hpux)
  1374. sprintf(buf, "%s: %s failed on `%s'; %s",
  1375. String_val(strval), String_val(fcnval),
  1376. String_val(nameval), causetxt);
  1377. #elif defined(WIN32)
  1378. _snprintf(buf, BUFSIZE, "%s: %s failed on `%s'; %s",
  1379. String_val(strval), String_val(fcnval),
  1380. String_val(nameval), causetxt);
  1381. #else
  1382. snprintf(buf, BUFSIZE, "%s: %s failed on `%s'; %s",
  1383. String_val(strval), String_val(fcnval),
  1384. String_val(nameval), causetxt);
  1385. #endif
  1386. free(causetxt);
  1387. return buf;
  1388. } else if (Is_block(argval)) {
  1389. if (Tag_val(argval) == String_tag) {
  1390. #if defined(__CYGWIN__) || defined(hpux)
  1391. sprintf(buf, "%s: %s", String_val(strval), String_val(argval));
  1392. #elif defined(WIN32)
  1393. _snprintf(buf, BUFSIZE, "%s: %s", String_val(strval), String_val(argval));
  1394. #else
  1395. snprintf(buf, BUFSIZE, "%s: %s", String_val(strval), String_val(argval));
  1396. #endif
  1397. return buf;
  1398. } else if (Tag_val(argval) == Double_tag){
  1399. char doubletxt[64];
  1400. string_of_float_aux(doubletxt, Double_val(argval));
  1401. #if defined(__CYGWIN__) || defined(hpux)
  1402. sprintf(buf, "%s: %s", String_val(strval), doubletxt);
  1403. #elif defined(WIN32)
  1404. _snprintf(buf, BUFSIZE, "%s: %s", String_val(strval), doubletxt);
  1405. #else
  1406. snprintf(buf, BUFSIZE, "%s: %s", String_val(strval), doubletxt);
  1407. #endif
  1408. return buf;
  1409. }
  1410. }
  1411. /* If unknown exception, copy the name and return it */
  1412. #if defined(__CYGWIN__)
  1413. sprintf(buf, "%s", String_val(strval));
  1414. #elif defined(WIN32)
  1415. _snprintf(buf, BUFSIZE, "%s", String_val(strval));
  1416. #else
  1417. snprintf(buf, BUFSIZE, "%s", String_val(strval));
  1418. #endif
  1419. return buf;
  1420. #undef BUFSIZE
  1421. }
  1422. /* Return a string representation of SML exception exn, if possible */
  1423. value sml_exnmessage(value exn) /* ML */
  1424. {
  1425. char* buf = exnmessage_aux(exn);
  1426. value res = copy_string(buf);
  1427. free(buf);
  1428. return res;
  1429. }
  1430. /* Sleep for the number of usec indicated the Double val vtime */
  1431. value sml_sleep(value vtime) /* ML */
  1432. {
  1433. double time = Double_val(vtime);
  1434. #ifdef WIN32
  1435. /* cvr: is this correct for win32? */
  1436. unsigned long msec = (long)(time/1000.0);
  1437. if (time > 0) {
  1438. Sleep(msec);
  1439. }
  1440. #else
  1441. unsigned long sec = (long)(time/1000000.0);
  1442. unsigned long usec = (long)(time - 1000000.0 * sec);
  1443. if (time > 0) {
  1444. sleep(sec);
  1445. usleep(usec);
  1446. }
  1447. #endif
  1448. return Val_unit;
  1449. }