util.c
DEFINITIONS
This source file includes following functions.
- scan_oct
- scan_hex
- S_ISDIR
- ruby_add_suffix
- valid_filename
- make_dbcs_table
- mblen
- push_element
- __crt0_glob_function
- mmswap_
- mmrot3_
- ruby_qsort
- ruby_strdup
- ruby_getcwd
- ruby_strtod
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <errno.h>
18
19 #ifdef NT
20 #include "missing/file.h"
21 #endif
22
23 #include "util.h"
24 #ifndef HAVE_STRING_H
25 char *strchr _((char*,char));
26 #endif
27
28 unsigned long
29 scan_oct(start, len, retlen)
30 const char *start;
31 int len;
32 int *retlen;
33 {
34 register const char *s = start;
35 register unsigned long retval = 0;
36
37 while (len-- && *s >= '0' && *s <= '7') {
38 retval <<= 3;
39 retval |= *s++ - '0';
40 }
41 *retlen = s - start;
42 return retval;
43 }
44
45 unsigned long
46 scan_hex(start, len, retlen)
47 const char *start;
48 int len;
49 int *retlen;
50 {
51 static char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
52 register const char *s = start;
53 register unsigned long retval = 0;
54 char *tmp;
55
56 while (len-- && *s && (tmp = strchr(hexdigit, *s))) {
57 retval <<= 4;
58 retval |= (tmp - hexdigit) & 15;
59 s++;
60 }
61 *retlen = s - start;
62 return retval;
63 }
64
65 #include <sys/types.h>
66 #include <sys/stat.h>
67 #ifdef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
70 #if defined(HAVE_FCNTL_H)
71 #include <fcntl.h>
72 #endif
73
74 #ifndef S_ISDIR
75 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
76 #endif
77
78 #ifdef NT
79 #include "missing/file.h"
80 #endif
81
82 #if defined(MSDOS) || defined(__CYGWIN32__) || defined(NT)
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 static int valid_filename(char *s);
153
154 static char suffix1[] = ".$$$";
155 static char suffix2[] = ".~~~";
156
157 #define ext (&buf[1000])
158
159 #define strEQ(s1,s2) (strcmp(s1,s2) == 0)
160
161 void
162 ruby_add_suffix(str, suffix)
163 VALUE str;
164 char *suffix;
165 {
166 int baselen;
167 int extlen = strlen(suffix);
168 char *s, *t, *p;
169 long slen;
170 char buf[1024];
171
172 if (RSTRING(str)->len > 1000)
173 rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
174 RSTRING(str)->len);
175
176 #if defined(DJGPP) || defined(__CYGWIN32__) || defined(NT)
177
178 slen = RSTRING(str)->len;
179 rb_str_cat(str, suffix, extlen);
180 #if defined(DJGPP)
181 if (_USE_LFN) return;
182 #else
183 if (valid_filename(RSTRING(str)->ptr)) return;
184 #endif
185
186
187 RSTRING(str)->ptr[RSTRING(str)->len = slen] = '\0';
188 #endif
189
190 slen = extlen;
191 t = buf; baselen = 0; s = RSTRING(str)->ptr;
192 while ((*t = *s) && *s != '.') {
193 baselen++;
194 if (*s == '\\' || *s == '/') baselen = 0;
195 s++; t++;
196 }
197 p = t;
198
199 t = ext; extlen = 0;
200 while (*t++ = *s++) extlen++;
201 if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
202
203 if (*suffix == '.') {
204 if (strEQ(ext, suffix)) goto fallback;
205 strcpy(p, suffix);
206 }
207 else if (suffix[1] == '\0') {
208 if (extlen < 4) {
209 ext[extlen] = *suffix;
210 ext[++extlen] = '\0';
211 }
212 else if (baselen < 8) {
213 *p++ = *suffix;
214 }
215 else if (ext[3] != *suffix) {
216 ext[3] = *suffix;
217 }
218 else if (buf[7] != *suffix) {
219 buf[7] = *suffix;
220 }
221 else goto fallback;
222 strcpy(p, ext);
223 }
224 else {
225 fallback:
226 (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
227 }
228 rb_str_resize(str, strlen(buf));
229 memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len);
230 }
231
232 #if defined(__CYGWIN32__) || defined(NT)
233 static int
234 valid_filename(char *s)
235 {
236 int fd;
237
238
239
240
241
242 if (_access(s, 0) == 0) {
243 return 1;
244 }
245
246
247
248
249
250 if ((fd = _open(s, O_CREAT, 0666)) >= 0) {
251 _close(fd);
252 _unlink (s);
253 return 1;
254 }
255 return 0;
256 }
257 #endif
258 #endif
259
260 #if defined __DJGPP__
261
262 #include <dpmi.h>
263
264 static char dbcs_table[256];
265
266 int
267 make_dbcs_table()
268 {
269 __dpmi_regs r;
270 struct {
271 unsigned char start;
272 unsigned char end;
273 } vec;
274 int offset;
275
276 memset(&r, 0, sizeof(r));
277 r.x.ax = 0x6300;
278 __dpmi_int(0x21, &r);
279 offset = r.x.ds * 16 + r.x.si;
280
281 for (;;) {
282 int i;
283 dosmemget(offset, sizeof vec, &vec);
284 if (!vec.start && !vec.end)
285 break;
286 for (i = vec.start; i <= vec.end; i++)
287 dbcs_table[i] = 1;
288 offset += 2;
289 }
290 }
291
292 int
293 mblen(const char *s, size_t n)
294 {
295 static int need_init = 1;
296 if (need_init) {
297 make_dbcs_table();
298 need_init = 0;
299 }
300 if (s) {
301 if (n == 0 || *s == 0)
302 return 0;
303 return dbcs_table[(unsigned char)*s] + 1;
304 }
305 else
306 return 1;
307 }
308
309 struct PathList {
310 struct PathList *next;
311 char *path;
312 };
313
314 struct PathInfo {
315 struct PathList *head;
316 int count;
317 };
318
319 static void
320 push_element(const char *path, VALUE vinfo)
321 {
322 struct PathList *p;
323 struct PathInfo *info = (struct PathInfo *)vinfo;
324
325 p = ALLOC(struct PathList);
326 MEMZERO(p, struct PathList, 1);
327 p->path = ruby_strdup(path);
328 p->next = info->head;
329 info->head = p;
330 info->count++;
331 }
332
333 #include <dirent.h>
334 int __opendir_flags = __OPENDIR_PRESERVE_CASE;
335
336 char **
337 __crt0_glob_function(char *path)
338 {
339 int len = strlen(path);
340 int i;
341 char **rv;
342 char path_buffer[PATH_MAX];
343 char *buf = path_buffer;
344 char *p;
345 struct PathInfo info;
346 struct PathList *plist;
347
348 if (PATH_MAX <= len)
349 buf = ruby_xmalloc(len + 1);
350
351 strncpy(buf, path, len);
352 buf[len] = '\0';
353
354 for (p = buf; *p; p += mblen(p, MB_CUR_MAX))
355 if (*p == '\\')
356 *p = '/';
357
358 info.count = 0;
359 info.head = 0;
360
361 rb_globi(buf, push_element, (VALUE)&info);
362
363 if (buf != path_buffer)
364 ruby_xfree(buf);
365
366 if (info.count == 0)
367 return 0;
368
369 rv = ruby_xmalloc((info.count + 1) * sizeof (char *));
370
371 plist = info.head;
372 i = 0;
373 while (plist) {
374 struct PathList *cur;
375 rv[i] = plist->path;
376 cur = plist;
377 plist = plist->next;
378 ruby_xfree(cur);
379 i++;
380 }
381 rv[i] = 0;
382 return rv;
383 }
384
385 #endif
386
387
388
389 #define A ((int*)a)
390 #define B ((int*)b)
391 #define C ((int*)c)
392 #define D ((int*)d)
393
394 #define mmprepare(base, size) do {\
395 if (((long)base & (0x3)) == 0)\
396 if (size >= 16) mmkind = 1;\
397 else mmkind = 0;\
398 else mmkind = -1;\
399 high = (size & (~0xf));\
400 low = (size & 0x0c);\
401 } while (0)\
402
403 #define mmarg mmkind, size, high, low
404
405 static void mmswap_(a, b, mmarg)
406 register char *a, *b;
407 int mmarg;
408 {
409 register int s;
410 if (a == b) return;
411 if (mmkind >= 0) {
412 if (mmkind > 0) {
413 register char *t = a + high;
414 do {
415 s = A[0]; A[0] = B[0]; B[0] = s;
416 s = A[1]; A[1] = B[1]; B[1] = s;
417 s = A[2]; A[2] = B[2]; B[2] = s;
418 s = A[3]; A[3] = B[3]; B[3] = s; a += 16; b += 16;
419 } while (a < t);
420 }
421 if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = s;
422 if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = s;
423 if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}}
424 }
425 else {
426 register char *t = a + size;
427 do {s = *a; *a++ = *b; *b++ = s;} while (a < t);
428 }
429 }
430 #define mmswap(a,b) mmswap_((a),(b),mmarg)
431
432 static void mmrot3_(a, b, c, mmarg)
433 register char *a, *b, *c;
434 int mmarg;
435 {
436 register int s;
437 if (mmkind >= 0) {
438 if (mmkind > 0) {
439 register char *t = a + high;
440 do {
441 s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s;
442 s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s;
443 s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;
444 s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s; a += 16; b += 16; c += 16;
445 } while (a < t);
446 }
447 if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s;
448 if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s;
449 if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}}
450 }
451 else {
452 register char *t = a + size;
453 do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t);
454 }
455 }
456 #define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg)
457
458
459
460
461
462
463
464
465
466
467 typedef struct { char *LL, *RR; } stack_node;
468 #define PUSH(ll,rr) do { top->LL = (ll); top->RR = (rr); ++top; } while (0)
469 #define POP(ll,rr) do { --top; ll = top->LL; rr = top->RR; } while (0)
470
471 #define med3(a,b,c) ((*cmp)(a,b)<0 ? \
472 ((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \
473 ((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<0 ? a : c)))
474
475 void ruby_qsort (base, nel, size, cmp)
476 void* base;
477 const int nel;
478 const int size;
479 int (*cmp)();
480 {
481 register char *l, *r, *m;
482 register int t, eq_l, eq_r;
483 char *L = base;
484 char *R = (char*)base + size*(nel-1);
485 int chklim = 63;
486 stack_node stack[32], *top = stack;
487 int mmkind, high, low;
488
489 if (nel <= 1) return;
490 mmprepare(base, size);
491 goto start;
492
493 nxt:
494 if (stack == top) return;
495 POP(L,R);
496
497 for (;;) {
498 start:
499 if (L + size == R) {
500 if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt;
501 }
502
503 l = L; r = R;
504 t = (r - l + size) / size;
505 m = l + size * (t >> 1);
506
507 if (t >= 60) {
508 register char *m1;
509 register char *m3;
510 if (t >= 200) {
511 t = size*(t>>3);
512 {
513 register char *p1 = l + t;
514 register char *p2 = p1 + t;
515 register char *p3 = p2 + t;
516 m1 = med3(p1, p2, p3);
517 p1 = m + t;
518 p2 = p1 + t;
519 p3 = p2 + t;
520 m3 = med3(p1, p2, p3);
521 }
522 }
523 else {
524 t = size*(t>>2);
525 m1 = l + t;
526 m3 = m + t;
527 }
528 m = med3(m1, m, m3);
529 }
530
531 if ((t = (*cmp)(l,m)) < 0) {
532 if ((t = (*cmp)(m,r)) < 0) {
533 if (chklim && nel >= chklim) {
534 char *p;
535 chklim = 0;
536 for (p=l; p<r; p+=size) if ((*cmp)(p,p+size) > 0) goto fail;
537 goto nxt;
538 }
539 fail: goto loopA;
540 }
541 if (t > 0) {
542 if ((*cmp)(l,r) <= 0) {mmswap(m,r); goto loopA;}
543 mmrot3(r,m,l); goto loopA;
544 }
545 goto loopB;
546 }
547
548 if (t > 0) {
549 if ((t = (*cmp)(m,r)) > 0) {
550 if (chklim && nel >= chklim) {
551 char *p;
552 chklim = 0;
553 for (p=l; p<r; p+=size) if ((*cmp)(p,p+size) < 0) goto fail2;
554 while (l<r) {mmswap(l,r); l+=size; r-=size;}
555 goto nxt;
556 }
557 fail2: mmswap(l,r); goto loopA;
558 }
559 if (t < 0) {
560 if ((*cmp)(l,r) <= 0) {mmswap(l,m); goto loopB;}
561 mmrot3(l,m,r); goto loopA;
562 }
563 mmswap(l,r); goto loopA;
564 }
565
566 if ((t = (*cmp)(m,r)) < 0) {goto loopA;}
567 if (t > 0) {mmswap(l,r); goto loopB;}
568
569
570 for (;;) {
571 if ((l += size) == r) goto nxt;
572 if (l == m) continue;
573 if ((t = (*cmp)(l,m)) > 0) {mmswap(l,r); l = L; goto loopA;}
574 if (t < 0) {mmswap(L,l); l = L; goto loopB;}
575 }
576
577 loopA: eq_l = 1; eq_r = 1;
578 for (;;) {
579 for (;;) {
580 if ((l += size) == r)
581 {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
582 if (l == m) continue;
583 if ((t = (*cmp)(l,m)) > 0) {eq_r = 0; break;}
584 if (t < 0) eq_l = 0;
585 }
586 for (;;) {
587 if (l == (r -= size))
588 {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
589 if (r == m) {m = l; break;}
590 if ((t = (*cmp)(r,m)) < 0) {eq_l = 0; break;}
591 if (t == 0) break;
592 }
593 mmswap(l,r);
594 }
595
596 loopB: eq_l = 1; eq_r = 1;
597 for (;;) {
598 for (;;) {
599 if (l == (r -= size))
600 {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
601 if (r == m) continue;
602 if ((t = (*cmp)(r,m)) < 0) {eq_l = 0; break;}
603 if (t > 0) eq_r = 0;
604 }
605 for (;;) {
606 if ((l += size) == r)
607 {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
608 if (l == m) {m = r; break;}
609 if ((t = (*cmp)(l,m)) > 0) {eq_r = 0; break;}
610 if (t == 0) break;
611 }
612 mmswap(l,r);
613 }
614
615 fin:
616 if (eq_l == 0)
617 if (eq_r == 0)
618 if (l-L < R-r) {PUSH(r,R); R = l;}
619 else {PUSH(L,l); L = r;}
620 else R = l;
621 else if (eq_r == 0) L = r;
622 else goto nxt;
623 }
624 }
625
626 char *
627 ruby_strdup(str)
628 const char *str;
629 {
630 char *tmp;
631 int len = strlen(str) + 1;
632
633 tmp = xmalloc(len);
634 if (tmp == NULL) return NULL;
635 memcpy(tmp, str, len);
636
637 return tmp;
638 }
639
640 char *
641 ruby_getcwd()
642 {
643 int size = 200;
644 char *buf = xmalloc(size);
645
646 while (!getcwd(buf, size)) {
647 if (errno != ERANGE) rb_sys_fail(0);
648 size *= 2;
649 buf = xrealloc(buf, size);
650 }
651 return buf;
652 }
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669 #define TRUE 1
670 #define FALSE 0
671
672 static int maxExponent = 511;
673
674
675
676
677 static double powersOf10[] = {
678 10.0,
679 100.0,
680 1.0e4,
681 1.0e8,
682 1.0e16,
683 1.0e32,
684 1.0e64,
685 1.0e128,
686 1.0e256
687 };
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710 double
711 ruby_strtod(string, endPtr)
712 const char *string;
713
714
715
716
717
718
719
720
721
722
723
724 char **endPtr;
725
726 {
727 int sign, expSign = FALSE;
728 double fraction, dblExp, *d;
729 register const char *p;
730 register int c;
731 int exp = 0;
732 int fracExp = 0;
733
734
735
736
737
738
739
740
741 int mantSize;
742 int decPt;
743
744 const char *pExp;
745
746
747
748
749
750
751 errno = 0;
752 p = string;
753 while (ISSPACE(*p)) {
754 p += 1;
755 }
756 if (*p == '-') {
757 sign = TRUE;
758 p += 1;
759 }
760 else {
761 if (*p == '+') {
762 p += 1;
763 }
764 sign = FALSE;
765 }
766
767
768
769
770
771
772 decPt = -1;
773 for (mantSize = 0; ; mantSize += 1) {
774 c = *p;
775 if (!ISDIGIT(c)) {
776 if ((c != '.') || (decPt >= 0)) {
777 break;
778 }
779 decPt = mantSize;
780 }
781 p += 1;
782 }
783
784
785
786
787
788
789
790
791 pExp = p;
792 p -= mantSize;
793 if (decPt < 0) {
794 decPt = mantSize;
795 }
796 else {
797 mantSize -= 1;
798 }
799 if (mantSize > 18) {
800 fracExp = decPt - 18;
801 mantSize = 18;
802 }
803 else {
804 fracExp = decPt - mantSize;
805 }
806 if (mantSize == 0) {
807 fraction = 0.0;
808 p = string;
809 goto done;
810 }
811 else {
812 int frac1, frac2;
813 frac1 = 0;
814 for ( ; mantSize > 9; mantSize -= 1) {
815 c = *p;
816 p += 1;
817 if (c == '.') {
818 c = *p;
819 p += 1;
820 }
821 frac1 = 10*frac1 + (c - '0');
822 }
823 frac2 = 0;
824 for (; mantSize > 0; mantSize -= 1) {
825 c = *p;
826 p += 1;
827 if (c == '.') {
828 c = *p;
829 p += 1;
830 }
831 frac2 = 10*frac2 + (c - '0');
832 }
833 fraction = (1.0e9 * frac1) + frac2;
834 }
835
836
837
838
839
840 p = pExp;
841 if ((*p == 'E') || (*p == 'e')) {
842 p += 1;
843 if (*p == '-') {
844 expSign = TRUE;
845 p += 1;
846 }
847 else {
848 if (*p == '+') {
849 p += 1;
850 }
851 expSign = FALSE;
852 }
853 while (ISDIGIT(*p)) {
854 exp = exp * 10 + (*p - '0');
855 p += 1;
856 }
857 }
858 if (expSign) {
859 exp = fracExp - exp;
860 }
861 else {
862 exp = fracExp + exp;
863 }
864
865
866
867
868
869
870
871
872 if (exp < 0) {
873 expSign = TRUE;
874 exp = -exp;
875 }
876 else {
877 expSign = FALSE;
878 }
879 if (exp > maxExponent) {
880 exp = maxExponent;
881 errno = ERANGE;
882 }
883 dblExp = 1.0;
884 for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
885 if (exp & 01) {
886 dblExp *= *d;
887 }
888 }
889 if (expSign) {
890 fraction /= dblExp;
891 }
892 else {
893 fraction *= dblExp;
894 }
895
896 done:
897 if (endPtr != NULL) {
898 *endPtr = (char *) p;
899 }
900
901 if (sign) {
902 return -fraction;
903 }
904 return fraction;
905 }