Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals  

util.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   util.c -
00004 
00005   $Author: matz $
00006   $Date: 2004/09/21 09:35:28 $
00007   created at: Fri Mar 10 17:22:34 JST 1995
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
00010 
00011 **********************************************************************/
00012 
00013 #include "ruby.h"
00014 
00015 #include <ctype.h>
00016 #include <stdio.h>
00017 #include <errno.h>
00018 
00019 #ifdef _WIN32
00020 #include "missing/file.h"
00021 #endif
00022 
00023 #include "util.h"
00024 #ifndef HAVE_STRING_H
00025 char *strchr (char*,char);
00026 #endif
00027 
00028 unsigned long
00029 scan_oct(start, len, retlen)
00030     const char *start;
00031     int len;
00032     int *retlen;
00033 {
00034     register const char *s = start;
00035     register unsigned long retval = 0;
00036 
00037     while (len-- && *s >= '0' && *s <= '7') {
00038         retval <<= 3;
00039         retval |= *s++ - '0';
00040     }
00041     *retlen = s - start;
00042     return retval;
00043 }
00044 
00045 unsigned long
00046 scan_hex(start, len, retlen)
00047     const char *start;
00048     int len;
00049     int *retlen;
00050 {
00051     static char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
00052     register const char *s = start;
00053     register unsigned long retval = 0;
00054     char *tmp;
00055 
00056     while (len-- && *s && (tmp = strchr(hexdigit, *s))) {
00057         retval <<= 4;
00058         retval |= (tmp - hexdigit) & 15;
00059         s++;
00060     }
00061     *retlen = s - start;
00062     return retval;
00063 }
00064 
00065 #include <sys/types.h>
00066 #include <sys/stat.h>
00067 #ifdef HAVE_UNISTD_H
00068 #include <unistd.h>
00069 #endif
00070 #if defined(HAVE_FCNTL_H)
00071 #include <fcntl.h>
00072 #endif
00073 
00074 #ifndef S_ISDIR
00075 #   define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
00076 #endif
00077 
00078 #if defined(MSDOS) || defined(__CYGWIN32__) || defined(_WIN32)
00079 /*
00080  *  Copyright (c) 1993, Intergraph Corporation
00081  *
00082  *  You may distribute under the terms of either the GNU General Public
00083  *  License or the Artistic License, as specified in the perl README file.
00084  *
00085  *  Various Unix compatibility functions and NT specific functions.
00086  *
00087  *  Some of this code was derived from the MSDOS port(s) and the OS/2 port.
00088  *
00089  */
00090 
00091 
00092 /*
00093  * Suffix appending for in-place editing under MS-DOS and OS/2 (and now NT!).
00094  *
00095  * Here are the rules:
00096  *
00097  * Style 0:  Append the suffix exactly as standard perl would do it.
00098  *           If the filesystem groks it, use it.  (HPFS will always
00099  *           grok it.  So will NTFS. FAT will rarely accept it.)
00100  *
00101  * Style 1:  The suffix begins with a '.'.  The extension is replaced.
00102  *           If the name matches the original name, use the fallback method.
00103  *
00104  * Style 2:  The suffix is a single character, not a '.'.  Try to add the 
00105  *           suffix to the following places, using the first one that works.
00106  *               [1] Append to extension.  
00107  *               [2] Append to filename, 
00108  *               [3] Replace end of extension, 
00109  *               [4] Replace end of filename.
00110  *           If the name matches the original name, use the fallback method.
00111  *
00112  * Style 3:  Any other case:  Ignore the suffix completely and use the
00113  *           fallback method.
00114  *
00115  * Fallback method:  Change the extension to ".$$$".  If that matches the
00116  *           original name, then change the extension to ".~~~".
00117  *
00118  * If filename is more than 1000 characters long, we die a horrible
00119  * death.  Sorry.
00120  *
00121  * The filename restriction is a cheat so that we can use buf[] to store
00122  * assorted temporary goo.
00123  *
00124  * Examples, assuming style 0 failed.
00125  *
00126  * suffix = ".bak" (style 1)
00127  *                foo.bar => foo.bak
00128  *                foo.bak => foo.$$$    (fallback)
00129  *                foo.$$$ => foo.~~~    (fallback)
00130  *                makefile => makefile.bak
00131  *
00132  * suffix = "~" (style 2)
00133  *                foo.c => foo.c~
00134  *                foo.c~ => foo.c~~
00135  *                foo.c~~ => foo~.c~~
00136  *                foo~.c~~ => foo~~.c~~
00137  *                foo~~~~~.c~~ => foo~~~~~.$$$ (fallback)
00138  *
00139  *                foo.pas => foo~.pas
00140  *                makefile => makefile.~
00141  *                longname.fil => longname.fi~
00142  *                longname.fi~ => longnam~.fi~
00143  *                longnam~.fi~ => longnam~.$$$
00144  *                
00145  */
00146 
00147 
00148 static int valid_filename(char *s);
00149 
00150 static char suffix1[] = ".$$$";
00151 static char suffix2[] = ".~~~";
00152 
00153 #define ext (&buf[1000])
00154 
00155 #define strEQ(s1,s2) (strcmp(s1,s2) == 0)
00156 
00157 void
00158 ruby_add_suffix(str, suffix)
00159     VALUE str;
00160     char *suffix;
00161 {
00162     int baselen;
00163     int extlen = strlen(suffix);
00164     char *s, *t, *p;
00165     long slen;
00166     char buf[1024];
00167 
00168     if (RSTRING(str)->len > 1000)
00169         rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
00170                  RSTRING(str)->len);
00171 
00172 #if defined(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32)
00173     /* Style 0 */
00174     slen = RSTRING(str)->len;
00175     rb_str_cat(str, suffix, extlen);
00176 #if defined(DJGPP)
00177     if (_USE_LFN) return;
00178 #else
00179     if (valid_filename(RSTRING(str)->ptr)) return;
00180 #endif
00181 
00182     /* Fooey, style 0 failed.  Fix str before continuing. */
00183     RSTRING(str)->ptr[RSTRING(str)->len = slen] = '\0';
00184 #endif
00185 
00186     slen = extlen;
00187     t = buf; baselen = 0; s = RSTRING(str)->ptr;
00188     while ((*t = *s) && *s != '.') {
00189         baselen++;
00190         if (*s == '\\' || *s == '/') baselen = 0;
00191         s++; t++;
00192     }
00193     p = t;
00194 
00195     t = ext; extlen = 0;
00196     while (*t++ = *s++) extlen++;
00197     if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
00198 
00199     if (*suffix == '.') {        /* Style 1 */
00200         if (strEQ(ext, suffix)) goto fallback;
00201         strcpy(p, suffix);
00202     }
00203     else if (suffix[1] == '\0') {  /* Style 2 */
00204         if (extlen < 4) { 
00205             ext[extlen] = *suffix;
00206             ext[++extlen] = '\0';
00207         }
00208         else if (baselen < 8) {
00209             *p++ = *suffix;
00210         }
00211         else if (ext[3] != *suffix) {
00212             ext[3] = *suffix;
00213         }
00214         else if (buf[7] != *suffix) {
00215             buf[7] = *suffix;
00216         }
00217         else goto fallback;
00218         strcpy(p, ext);
00219     }
00220     else { /* Style 3:  Panic */
00221 fallback:
00222         (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
00223     }
00224     rb_str_resize(str, strlen(buf));
00225     memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len);
00226 }
00227 
00228 #if defined(__CYGWIN32__) || defined(_WIN32)
00229 static int 
00230 valid_filename(char *s)
00231 {
00232     int fd;
00233 
00234     /*
00235     // if the file exists, then it's a valid filename!
00236     */
00237 
00238     if (_access(s, 0) == 0) {
00239         return 1;
00240     }
00241 
00242     /*
00243     // It doesn't exist, so see if we can open it.
00244     */
00245 
00246     if ((fd = _open(s, O_CREAT, 0666)) >= 0) {
00247         _close(fd);
00248         _unlink(s);     /* don't leave it laying around */
00249         return 1;
00250     }
00251     return 0;
00252 }
00253 #endif
00254 #endif
00255 
00256 #if defined __DJGPP__
00257 
00258 #include <dpmi.h>
00259 
00260 static char dbcs_table[256];
00261 
00262 int
00263 make_dbcs_table()
00264 {
00265     __dpmi_regs r;
00266     struct {
00267         unsigned char start;
00268         unsigned char end;
00269     } vec;
00270     int offset;
00271 
00272     memset(&r, 0, sizeof(r));
00273     r.x.ax = 0x6300;
00274     __dpmi_int(0x21, &r);
00275     offset = r.x.ds * 16 + r.x.si;
00276 
00277     for (;;) {
00278         int i;
00279         dosmemget(offset, sizeof vec, &vec);
00280         if (!vec.start && !vec.end)
00281             break;
00282         for (i = vec.start; i <= vec.end; i++)
00283             dbcs_table[i] = 1;
00284         offset += 2;
00285     }
00286 }
00287 
00288 int
00289 mblen(const char *s, size_t n)
00290 {
00291     static int need_init = 1;
00292     if (need_init) {
00293         make_dbcs_table();
00294         need_init = 0;
00295     }
00296     if (s) {
00297         if (n == 0 || *s == 0)
00298             return 0;
00299         else if (!s[1])
00300             return 1;
00301         return dbcs_table[(unsigned char)*s] + 1;
00302     }
00303     else
00304         return 1;
00305 }
00306 
00307 struct PathList {
00308     struct PathList *next;
00309     char *path;
00310 };
00311 
00312 struct PathInfo {
00313     struct PathList *head;
00314     int count;
00315 };
00316 
00317 static void
00318 push_element(const char *path, VALUE vinfo)
00319 {
00320     struct PathList *p;
00321     struct PathInfo *info = (struct PathInfo *)vinfo;
00322 
00323     p = ALLOC(struct PathList);
00324     MEMZERO(p, struct PathList, 1);
00325     p->path = ruby_strdup(path);
00326     p->next = info->head;
00327     info->head = p;
00328     info->count++;
00329 }
00330 
00331 #include <dirent.h>
00332 int __opendir_flags = __OPENDIR_PRESERVE_CASE;
00333 
00334 char **
00335 __crt0_glob_function(char *path)
00336 {
00337     int len = strlen(path);
00338     int i;
00339     char **rv;
00340     char path_buffer[PATH_MAX];
00341     char *buf = path_buffer;
00342     char *p;
00343     struct PathInfo info;
00344     struct PathList *plist;
00345 
00346     if (PATH_MAX <= len)
00347         buf = ruby_xmalloc(len + 1);
00348 
00349     strncpy(buf, path, len);
00350     buf[len] = '\0';
00351 
00352     for (p = buf; *p; p += mblen(p, MB_CUR_MAX))
00353         if (*p == '\\')
00354             *p = '/';
00355 
00356     info.count = 0;
00357     info.head = 0;
00358 
00359     rb_globi(buf, push_element, (VALUE)&info);
00360 
00361     if (buf != path_buffer)
00362         ruby_xfree(buf);
00363 
00364     if (info.count == 0)
00365         return 0;
00366 
00367     rv = ruby_xmalloc((info.count + 1) * sizeof (char *));
00368 
00369     plist = info.head;
00370     i = 0;
00371     while (plist) {
00372         struct PathList *cur;
00373         rv[i] = plist->path;
00374         cur = plist;
00375         plist = plist->next;
00376         ruby_xfree(cur);
00377         i++;
00378     }
00379     rv[i] = 0;
00380     return rv;
00381 }
00382 
00383 #endif
00384 
00385 /* mm.c */
00386 
00387 #define A ((int*)a)
00388 #define B ((int*)b)
00389 #define C ((int*)c)
00390 #define D ((int*)d)
00391 
00392 #define mmprepare(base, size) do {\
00393  if (((long)base & (0x3)) == 0)\
00394    if (size >= 16) mmkind = 1;\
00395    else            mmkind = 0;\
00396  else              mmkind = -1;\
00397  high = (size & (~0xf));\
00398  low  = (size &  0x0c);\
00399 } while (0)\
00400 
00401 #define mmarg mmkind, size, high, low
00402 
00403 static void mmswap_(a, b, mmarg)
00404     register char *a, *b;
00405     int mmarg;
00406 {
00407  register int s;
00408  if (a == b) return;
00409  if (mmkind >= 0) {
00410    if (mmkind > 0) {
00411      register char *t = a + high;
00412      do {
00413        s = A[0]; A[0] = B[0]; B[0] = s;
00414        s = A[1]; A[1] = B[1]; B[1] = s;
00415        s = A[2]; A[2] = B[2]; B[2] = s;
00416        s = A[3]; A[3] = B[3]; B[3] = s;  a += 16; b += 16;
00417      } while (a < t);
00418    }
00419    if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = s;
00420      if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = s;
00421        if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}}
00422  }
00423  else {
00424    register char *t = a + size;
00425    do {s = *a; *a++ = *b; *b++ = s;} while (a < t);
00426  }
00427 }
00428 #define mmswap(a,b) mmswap_((a),(b),mmarg)
00429 
00430 static void mmrot3_(a, b, c, mmarg)
00431     register char *a, *b, *c;
00432     int mmarg;
00433 {
00434  register int s;
00435  if (mmkind >= 0) {
00436    if (mmkind > 0) {
00437      register char *t = a + high;
00438      do {
00439        s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s;
00440        s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s;
00441        s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;
00442        s = A[3]; A[3] = B[3]; B[3] = C[3]; C[3] = s; a += 16; b += 16; c += 16;
00443      } while (a < t);
00444    }
00445    if (low != 0) { s = A[0]; A[0] = B[0]; B[0] = C[0]; C[0] = s;
00446      if (low >= 8) { s = A[1]; A[1] = B[1]; B[1] = C[1]; C[1] = s;
00447        if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}}
00448  }
00449  else {
00450    register char *t = a + size;
00451    do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t);
00452  }
00453 }
00454 #define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg)
00455 
00456 /* qs6.c */
00457 /*****************************************************/
00458 /*                                                   */
00459 /*          qs6   (Quick sort function)              */
00460 /*                                                   */
00461 /* by  Tomoyuki Kawamura              1995.4.21      */
00462 /* kawamura@tokuyama.ac.jp                           */
00463 /*****************************************************/
00464 
00465 typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */
00466 #define PUSH(ll,rr) do { top->LL = (ll); top->RR = (rr); ++top; } while (0)  /* Push L,l,R,r */
00467 #define POP(ll,rr)  do { --top; ll = top->LL; rr = top->RR; } while (0)      /* Pop L,l,R,r */
00468 
00469 #define med3(a,b,c) ((*cmp)(a,b,d)<0 ?                                   \
00470                        ((*cmp)(b,c,d)<0 ? b : ((*cmp)(a,c,d)<0 ? c : a)) : \
00471                        ((*cmp)(b,c,d)>0 ? b : ((*cmp)(a,c,d)<0 ? a : c)))
00472 
00473 void ruby_qsort (base, nel, size, cmp, d)
00474      void* base;
00475      const int nel;
00476      const int size;
00477      int (*cmp)();
00478      void *d;
00479 {
00480   register char *l, *r, *m;             /* l,r:left,right group   m:median point */
00481   register int  t, eq_l, eq_r;          /* eq_l: all items in left group are equal to S */
00482   char *L = base;                       /* left end of curren region */
00483   char *R = (char*)base + size*(nel-1); /* right end of current region */
00484   int  chklim = 63;                     /* threshold of ordering element check */
00485   stack_node stack[32], *top = stack;   /* 32 is enough for 32bit CPU */
00486   int mmkind, high, low;
00487 
00488   if (nel <= 1) return;        /* need not to sort */
00489   mmprepare(base, size);
00490   goto start;
00491 
00492   nxt:
00493   if (stack == top) return;    /* return if stack is empty */
00494   POP(L,R);
00495 
00496   for (;;) {
00497     start:
00498     if (L + size == R) {       /* 2 elements */
00499       if ((*cmp)(L,R,d) > 0) mmswap(L,R); goto nxt;
00500     }
00501 
00502     l = L; r = R;
00503     t = (r - l + size) / size;  /* number of elements */
00504     m = l + size * (t >> 1);    /* calculate median value */
00505 
00506     if (t >= 60) {
00507       register char *m1;
00508       register char *m3;
00509       if (t >= 200) {
00510         t = size*(t>>3); /* number of bytes in splitting 8 */
00511         {
00512           register char *p1 = l  + t;
00513           register char *p2 = p1 + t;
00514           register char *p3 = p2 + t;
00515           m1 = med3(p1, p2, p3);
00516           p1 = m  + t;
00517           p2 = p1 + t;
00518           p3 = p2 + t;
00519           m3 = med3(p1, p2, p3);
00520         }
00521       }
00522       else {
00523         t = size*(t>>2); /* number of bytes in splitting 4 */
00524         m1 = l + t;
00525         m3 = m + t;
00526       }
00527       m = med3(m1, m, m3);
00528     }
00529 
00530     if ((t = (*cmp)(l,m,d)) < 0) {                           /*3-5-?*/
00531       if ((t = (*cmp)(m,r,d)) < 0) {                         /*3-5-7*/
00532         if (chklim && nel >= chklim) {   /* check if already ascending order */
00533           char *p;
00534           chklim = 0;
00535           for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) > 0) goto fail;
00536           goto nxt;
00537         }
00538         fail: goto loopA;                                    /*3-5-7*/
00539       }
00540       if (t > 0) {
00541         if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;}     /*3-5-4*/
00542         mmrot3(r,m,l); goto loopA;                           /*3-5-2*/
00543       }
00544       goto loopB;                                            /*3-5-5*/
00545     }
00546 
00547     if (t > 0) {                                             /*7-5-?*/
00548       if ((t = (*cmp)(m,r,d)) > 0) {                         /*7-5-3*/
00549         if (chklim && nel >= chklim) {   /* check if already ascending order */
00550           char *p;
00551           chklim = 0;
00552           for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) < 0) goto fail2;
00553           while (l<r) {mmswap(l,r); l+=size; r-=size;}  /* reverse region */
00554           goto nxt;
00555         }
00556         fail2: mmswap(l,r); goto loopA;                      /*7-5-3*/
00557       }
00558       if (t < 0) {
00559         if ((*cmp)(l,r,d) <= 0) {mmswap(l,m); goto loopB;}   /*7-5-8*/
00560         mmrot3(l,m,r); goto loopA;                           /*7-5-6*/
00561       }
00562       mmswap(l,r); goto loopA;                               /*7-5-5*/
00563     }
00564 
00565     if ((t = (*cmp)(m,r,d)) < 0)  {goto loopA;}              /*5-5-7*/
00566     if (t > 0) {mmswap(l,r); goto loopB;}                    /*5-5-3*/
00567 
00568     /* determining splitting type in case 5-5-5 */           /*5-5-5*/
00569     for (;;) {
00570       if ((l += size) == r)      goto nxt;                   /*5-5-5*/
00571       if (l == m) continue;
00572       if ((t = (*cmp)(l,m,d)) > 0) {mmswap(l,r); l = L; goto loopA;}/*575-5*/
00573       if (t < 0)                 {mmswap(L,l); l = L; goto loopB;}  /*535-5*/
00574     }
00575 
00576     loopA: eq_l = 1; eq_r = 1;  /* splitting type A */ /* left <= median < right */
00577     for (;;) {
00578       for (;;) {
00579         if ((l += size) == r)
00580           {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
00581         if (l == m) continue;
00582         if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
00583         if (t < 0) eq_l = 0;
00584       }
00585       for (;;) {
00586         if (l == (r -= size))
00587           {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;}
00588         if (r == m) {m = l; break;}
00589         if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
00590         if (t == 0) break;
00591       }
00592       mmswap(l,r);    /* swap left and right */
00593     }
00594 
00595     loopB: eq_l = 1; eq_r = 1;  /* splitting type B */ /* left < median <= right */
00596     for (;;) {
00597       for (;;) {
00598         if (l == (r -= size))
00599           {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
00600         if (r == m) continue;
00601         if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;}
00602         if (t > 0) eq_r = 0;
00603       }
00604       for (;;) {
00605         if ((l += size) == r)
00606           {r += size; if (r != m) mmswap(r,m); r += size; goto fin;}
00607         if (l == m) {m = r; break;}
00608         if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;}
00609         if (t == 0) break;
00610       }
00611       mmswap(l,r);    /* swap left and right */
00612     }
00613 
00614     fin:
00615     if (eq_l == 0)                         /* need to sort left side */
00616       if (eq_r == 0)                       /* need to sort right side */
00617         if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */
00618         else           {PUSH(L,l); L = r;} /* sort right side first */
00619       else R = l;                          /* need to sort left side only */
00620     else if (eq_r == 0) L = r;             /* need to sort right side only */
00621     else goto nxt;                         /* need not to sort both sides */
00622   }
00623 }
00624 
00625 char *
00626 ruby_strdup(str)
00627     const char *str;
00628 {
00629     char *tmp;
00630     int len = strlen(str) + 1;
00631 
00632     tmp = xmalloc(len);
00633     memcpy(tmp, str, len);
00634 
00635     return tmp;
00636 }
00637 
00638 char *
00639 ruby_getcwd()
00640 {
00641 #ifdef HAVE_GETCWD
00642     int size = 200;
00643     char *buf = xmalloc(size);
00644 
00645     while (!getcwd(buf, size)) {
00646         if (errno != ERANGE) {
00647             free(buf);
00648             rb_sys_fail("getcwd");
00649         }
00650         size *= 2;
00651         buf = xrealloc(buf, size);
00652     }
00653 #else
00654 # ifndef PATH_MAX
00655 #  define PATH_MAX 8192
00656 # endif
00657     char *buf = xmalloc(PATH_MAX+1);
00658 
00659     if (!getwd(buf)) {
00660         free(buf);
00661         rb_sys_fail("getwd");
00662     }
00663 #endif
00664     return buf;
00665 }
00666 
00667 /* copyright notice for strtod implementation --
00668  *
00669  * Copyright (c) 1988-1993 The Regents of the University of California.
00670  * Copyright (c) 1994 Sun Microsystems, Inc.
00671  *
00672  * Permission to use, copy, modify, and distribute this
00673  * software and its documentation for any purpose and without
00674  * fee is hereby granted, provided that the above copyright
00675  * notice appear in all copies.  The University of California
00676  * makes no representations about the suitability of this
00677  * software for any purpose.  It is provided "as is" without
00678  * express or implied warranty.
00679  *
00680  */
00681 
00682 #define TRUE 1
00683 #define FALSE 0
00684 
00685 static  int     MDMINEXPT       = -323;
00686 static  int     MDMAXEXPT       =  309;
00687 static double powersOf10[] = {  /* Table giving binary powers of 10.  Entry */
00688     10.0,                       /* is 10^2^i.  Used to convert decimal */
00689     100.0,                      /* exponents into floating-point numbers. */
00690     1.0e4,
00691     1.0e8,
00692     1.0e16,
00693     1.0e32,
00694     1.0e64,
00695     1.0e128,
00696     1.0e256
00697 };
00698 
00699 /*
00700  *----------------------------------------------------------------------
00701  *
00702  * strtod --
00703  *
00704  *      This procedure converts a floating-point number from an ASCII
00705  *      decimal representation to internal double-precision format.
00706  *
00707  * Results:
00708  *      The return value is the double-precision floating-point
00709  *      representation of the characters in string.  If endPtr isn't
00710  *      NULL, then *endPtr is filled in with the address of the
00711  *      next character after the last one that was part of the
00712  *      floating-point number.
00713  *
00714  * Side effects:
00715  *      None.
00716  *
00717  *----------------------------------------------------------------------
00718  */
00719 
00720 double
00721 ruby_strtod(string, endPtr)
00722     const char *string;         /* A decimal ASCII floating-point number,
00723                                  * optionally preceded by white space.
00724                                  * Must have form "-I.FE-X", where I is the
00725                                  * integer part of the mantissa, F is the
00726                                  * fractional part of the mantissa, and X
00727                                  * is the exponent.  Either of the signs
00728                                  * may be "+", "-", or omitted.  Either I
00729                                  * or F may be omitted, but both cannot be
00730                                  * ommitted at once. The decimal
00731                                  * point isn't necessary unless F is present.
00732                                  * The "E" may actually be an "e".  E and X
00733                                  * may both be omitted (but not just one).
00734                                  */
00735     char **endPtr;              /* If non-NULL, store terminating character's
00736                                  * address here. */
00737 {
00738     int sign, expSign = FALSE;
00739     double fraction, dblExp, *d;
00740     register const char *p;
00741     register int c;
00742     int exp = 0;                /* Exponent read from "EX" field. */
00743     int fracExp = 0;            /* Exponent that derives from the fractional
00744                                  * part.  Under normal circumstatnces, it is
00745                                  * the negative of the number of digits in F.
00746                                  * However, if I is very long, the last digits
00747                                  * of I get dropped (otherwise a long I with a
00748                                  * large negative exponent could cause an
00749                                  * unnecessary overflow on I alone).  In this
00750                                  * case, fracExp is incremented one for each
00751                                  * dropped digit. */
00752     int mantSize = 0;           /* Number of digits in mantissa. */
00753     int hasPoint = FALSE;       /* Decimal point exists. */
00754     int hasDigit = FALSE;       /* I or F exists. */
00755     const char *pMant;          /* Temporarily holds location of mantissa
00756                                  * in string. */
00757     const char *pExp;           /* Temporarily holds location of exponent
00758                                  * in string. */
00759 
00760     /*
00761      * Strip off leading blanks and check for a sign.
00762      */
00763 
00764     errno = 0;
00765     p = string;
00766     while (ISSPACE(*p)) {
00767         p += 1;
00768     }
00769     if (*p == '-') {
00770         sign = TRUE;
00771         p += 1;
00772     }
00773     else {
00774         if (*p == '+') {
00775             p += 1;
00776         }
00777         sign = FALSE;
00778     }
00779 
00780     /*
00781      * Count the number of digits in the mantissa
00782      * and also locate the decimal point.
00783      */
00784 
00785     for ( ; c = *p; p += 1) {
00786         if (!ISDIGIT(c)) {
00787             if (c != '.' || hasPoint) {
00788                 break;
00789             }
00790             hasPoint = TRUE;
00791         }
00792         else {
00793             if (hasPoint) { /* already in fractional part */
00794                 fracExp -= 1;
00795             }
00796             if (mantSize) { /* already in mantissa */
00797                 mantSize += 1;
00798             }
00799             else if (c != '0') { /* have entered mantissa */
00800                 mantSize += 1;
00801                 pMant = p;
00802             }
00803             hasDigit = TRUE;
00804         }
00805     }
00806 
00807     /*
00808      * Now suck up the digits in the mantissa.  Use two integers to
00809      * collect 9 digits each (this is faster than using floating-point).
00810      * If the mantissa has more than 18 digits, ignore the extras, since
00811      * they can't affect the value anyway.
00812      */
00813     
00814     pExp  = p;
00815     if (mantSize) {
00816         p = pMant;
00817     }
00818     if (mantSize > 18) {
00819         fracExp += (mantSize - 18);
00820         mantSize = 18;
00821     }
00822     if (!hasDigit) {
00823         fraction = 0.0;
00824         p = string;
00825     }
00826     else {
00827         int frac1, frac2;
00828         frac1 = 0;
00829         for ( ; mantSize > 9; mantSize -= 1) {
00830             c = *p;
00831             p += 1;
00832             if (c == '.') {
00833                 c = *p;
00834                 p += 1;
00835             }
00836             frac1 = 10*frac1 + (c - '0');
00837         }
00838         frac2 = 0;
00839         for (; mantSize > 0; mantSize -= 1) {
00840             c = *p;
00841             p += 1;
00842             if (c == '.') {
00843                 c = *p;
00844                 p += 1;
00845             }
00846             frac2 = 10*frac2 + (c - '0');
00847         }
00848 
00849         /*
00850          * Skim off the exponent.
00851          */
00852 
00853         p = pExp;
00854         if ((*p == 'E') || (*p == 'e')) {
00855             p += 1;
00856             if (*p == '-') {
00857                 expSign = TRUE;
00858                 p += 1;
00859             }
00860             else {
00861                 if (*p == '+') {
00862                     p += 1;
00863                 }
00864                 expSign = FALSE;
00865             }
00866             while (ISDIGIT(*p)) {
00867                 exp = exp * 10 + (*p - '0');
00868                 p += 1;
00869             }
00870         }
00871         if (expSign) {
00872             exp = fracExp - exp;
00873         }
00874         else {
00875             exp = fracExp + exp;
00876         }
00877 
00878         /*
00879          * Generate a floating-point number that represents the exponent.
00880          * Do this by processing the exponent one bit at a time to combine
00881          * many powers of 2 of 10. Then combine the exponent with the
00882          * fraction.
00883          */
00884     
00885         if (exp >= MDMAXEXPT - 18) {
00886             exp = MDMAXEXPT;
00887             errno = ERANGE;
00888         }
00889         else if (exp < MDMINEXPT + 18) {
00890             exp = MDMINEXPT;
00891             errno = ERANGE;
00892         }
00893         fracExp = exp;
00894         exp += 9;
00895         if (exp < 0) {
00896             expSign = TRUE;
00897             exp = -exp;
00898         }
00899         else {
00900             expSign = FALSE;
00901         }
00902         dblExp = 1.0;
00903         for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
00904             if (exp & 01) {
00905                 dblExp *= *d;
00906             }
00907         }
00908         if (expSign) {
00909             fraction = frac1 / dblExp;
00910         }
00911         else {
00912             fraction = frac1 * dblExp;
00913         }
00914         exp = fracExp;
00915         if (exp < 0) {
00916             expSign = TRUE;
00917             exp = -exp;
00918         }
00919         else {
00920             expSign = FALSE;
00921         }
00922         dblExp = 1.0;
00923         for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
00924             if (exp & 01) {
00925                 dblExp *= *d;
00926             }
00927         }
00928         if (expSign) {
00929             fraction += frac2 / dblExp;
00930         }
00931         else {
00932             fraction += frac2 * dblExp;
00933         }
00934     }
00935 
00936     if (endPtr != NULL) {
00937         *endPtr = (char *) p;
00938     }
00939 
00940     if (sign) {
00941         return -fraction;
00942     }
00943     return fraction;
00944 }
00945 

Generated on Sat Jan 22 14:29:52 2005 for Ruby by doxygen1.2.18