home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / oleo_src.lha / src / utils.c < prev   
Encoding:
C/C++ Source or Header  |  1992-08-14  |  17.5 KB  |  1,021 lines

  1. /*    Copyright (C) 1990 Free Software Foundation, Inc.
  2.  
  3. This file is part of Oleo, the GNU Spreadsheet.
  4.  
  5. Oleo is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. Oleo is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with Oleo; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18. #include <stdio.h>
  19.  
  20. #include "funcdef.h"
  21. #include "sysdef.h"
  22.  
  23. #ifdef SYSV
  24. #include <dirent.h>
  25. #define direct dirent
  26. #else
  27. #ifdef __TURBOC__
  28. typedef int ino_t;
  29. #include "msd_dir.h"
  30. #else
  31. #ifdef __STDC__
  32. #include <sys/types.h>
  33. #endif
  34. #include <sys/file.h>
  35. #include <sys/dir.h>
  36. #endif
  37. #endif
  38.  
  39. #ifdef __STDC__
  40. #ifndef VOIDSTAR
  41. #define VOIDSTAR void *
  42. #endif
  43. #define CONST const
  44. #undef NULL
  45. #else
  46. #ifndef VOIDSTAR
  47. #define VOIDSTAR char *
  48. #endif
  49. #define CONST
  50. #endif
  51.  
  52. #include <ctype.h>
  53.  
  54. #ifndef F_OK
  55. #define F_OK 0
  56. #endif
  57. #ifndef _IOSTRG
  58. #define _IOSTRG 0
  59. #endif
  60.  
  61. extern VOIDSTAR malloc();
  62.  
  63. VOIDSTAR ck_malloc EXT1(size_t);
  64. VOIDSTAR ck_realloc EXT2(VOIDSTAR,size_t);
  65. char *strdup EXT1(CONST char *);
  66.  
  67. struct id {
  68.     int flag;
  69.     FILE *fp;
  70.     char *name;
  71. };
  72.  
  73. struct id *__id_s;
  74. int __id_n;
  75. int __id_f;
  76.  
  77. int __make_backups;
  78. int __backup_by_copying;
  79.  
  80. /* Stash argv[0] here so panic will know what the program is called */
  81. char *myname = 0;
  82.  
  83. /* Blow chunks! */
  84. void
  85. panic FUN1N(char *, s)
  86. {
  87.     va_list iggy;
  88.     extern void abort EXT0();
  89.  
  90.     var_start(iggy,s);
  91.     if(myname)
  92.         fprintf(stderr,"%s:",myname);
  93.     vfprintf(stderr,s,iggy);
  94.     putc('\n',stderr);
  95.     va_end(iggy);
  96.     abort();    /* Should be changed to exit(EXIT_FATAL) for production */
  97. }
  98.  
  99. /* Given a file name, come up with a backup file name. . . */
  100. char *
  101. backup_file_name FUN1(char *,file_name)
  102. {
  103.     char    *dir_name,*dir_end;
  104.  
  105.     DIR     *dir;
  106.     register struct direct *dp;
  107.     int     len;
  108.     int     max_fnum;
  109.     int     cur_fnum;
  110.  
  111.     char *tmp_ptr;
  112.  
  113.     char *return_value;
  114.  
  115.     dir_end=rindex(file_name,'/');
  116.     if(dir_end) {
  117.         dir_name=file_name;
  118.         file_name=dir_end+1;
  119.         *dir_end='\0';
  120.     } else {
  121.         dir_name=".";
  122.     }
  123.     len=strlen(file_name);
  124.  
  125.     dir=opendir(dir_name);
  126.     if(dir==0) {
  127.         if(dir_end)
  128.             *dir_end='/';
  129.         return (char *)0;
  130.     }
  131.  
  132.     max_fnum=0;
  133.     while(dp=readdir(dir)) {
  134.         if(   !dp->d_ino
  135. #ifndef SYSV
  136.             || dp->d_namlen<=len
  137. #endif
  138.            || strncmp(dp->d_name,file_name,len)
  139.            || dp->d_name[len]!='.'
  140.            || dp->d_name[len+1]!='~'
  141. #ifndef SYSV
  142.            || dp->d_name[dp->d_namlen-1]!='~')
  143. #else
  144.            || dp->d_name[strlen(dp->d_name)-1]!='~')
  145. #endif
  146.             continue;
  147.  
  148.         tmp_ptr= &(dp->d_name[len+2]);
  149.         for(cur_fnum=0;isdigit(*tmp_ptr);tmp_ptr++)
  150.             cur_fnum=cur_fnum*10 + *tmp_ptr-'0';
  151. #ifndef SYSV
  152.         if(tmp_ptr!= &(dp->d_name[dp->d_namlen-1]) || cur_fnum<max_fnum)
  153. #else
  154.         if(tmp_ptr[2]!='\0' || cur_fnum<max_fnum)
  155. #endif
  156.             continue;
  157.         max_fnum=cur_fnum;
  158.     }
  159.     closedir(dir);
  160.     max_fnum++;
  161.     return_value=(char *)malloc(strlen(dir_name)+len+12);
  162.     if(!return_value)
  163.         return (char *)0;
  164.     sprintf(return_value,"%s/%s.~%d~",dir_name,file_name,max_fnum);
  165.     if(dir_end)
  166.         *dir_end='/';
  167.     return return_value;
  168. }
  169.  
  170.  
  171. char *
  172. __fp_name FUN1(FILE *, fp)
  173. {
  174.     int n;
  175.  
  176.     for(n=0;n<__id_n;n++) {
  177.         if(__id_s[n].fp==fp)
  178.             return __id_s[n].name;
  179.     }
  180.     return "{Unknown file pointer}";
  181. }
  182.  
  183. void
  184. __set_fp FUN3(FILE *,fp, CONST char *,name, int,flag)
  185. {
  186.     if(__id_s==0) {
  187.         __id_s=ck_malloc(20*sizeof(struct id));
  188.         __id_n=0;
  189.         __id_f=20;
  190.     } else {
  191.         int n;
  192.  
  193.         for(n=0;n<__id_n;n++)
  194.             if(__id_s[n].fp==fp) {
  195.                 free(__id_s[n].name);
  196.                 __id_s[n]=__id_s[--__id_n];
  197.                 __id_f++;
  198.                 break;
  199.             }
  200.     }
  201.     if(__id_f==0) {
  202.         __id_f=20;
  203.  
  204.         __id_s=ck_realloc(__id_s,(__id_f+__id_n)*sizeof(struct id));
  205.     }
  206.     __id_s[__id_n].flag=flag;
  207.     __id_s[__id_n].name=strdup(name);
  208.     __id_s[__id_n].fp=fp;
  209.     __id_n++;
  210.     __id_f--;
  211. }
  212.  
  213. /* Open a file or a pipe */
  214. FILE *
  215. xopen FUN2(CONST char *,name, CONST char *,mode)
  216. {
  217.     int flag = 0;
  218.     FILE *ret;
  219.     extern FILE *popen EXT2(CONST char *,CONST char *);
  220.  
  221.     while(*name==' ')
  222.         name++;
  223.     if(*name=='!') {
  224.         name++;
  225.         ret=popen(name,mode);
  226.         flag=1;
  227.     } else
  228.         ret=fopen(name,mode);
  229.     if(ret==0)
  230.         return ret;
  231.     __set_fp(ret,name,flag);
  232.     return ret;
  233. }
  234.  
  235. /* Open a file, creating a backup file if needed. . . */
  236. FILE *
  237. fopen_with_backup FUN2(char *,name, CONST char *,mode)
  238. {
  239.     char *newname;
  240.  
  241.     if(__make_backups && *mode=='w' && access(name,F_OK)==0) {
  242.         newname=backup_file_name(name);
  243.         if(!newname)
  244.             return (FILE *)0;
  245.         if(__backup_by_copying) {
  246.             FILE *c_in,*c_out;
  247.             int n_read;
  248. #ifdef __TURBOC__
  249.             char buf[512];
  250. #else
  251.             char buf[4096];
  252. #endif
  253.             extern FILE *ck_fopen();
  254.  
  255.             c_in=fopen(name,"r");
  256.             c_out=fopen(name,"w");
  257.             if(!c_in || !c_out)
  258.                 return (FILE *)0;
  259.             while((n_read=fread(buf,sizeof(buf),1,c_in))>0)
  260.                 if(fwrite(buf,n_read,1,c_out)!=n_read)
  261.                     return (FILE *)0;
  262.             if(fclose(c_in)==EOF ||fclose(c_out)==EOF)
  263.                 return (FILE *)0;
  264.         } else
  265. #ifdef NO_RENAME
  266.             if(link(name,newname) || unlink(name))
  267. #else
  268.             if(rename(name,newname)<0)
  269. #endif
  270.                 return (FILE *)0;
  271.         free(newname);
  272.     }
  273.     return fopen(name,mode);
  274. }
  275.  
  276. /* Open a file or a pipe, creating a backup file if it's a file */
  277. FILE *
  278. xopen_with_backup FUN2(char *,name, CONST char *,mode)
  279. {
  280.     int flag;
  281.     FILE *ret;
  282.  
  283.     while(*name==' ')
  284.         name++;
  285.     if(*name=='|') {
  286.         ret=popen(name+1,mode);
  287.         flag=1;
  288.     } else {
  289.         ret=fopen_with_backup(name,mode);
  290.         flag=0;
  291.     }
  292.     if(ret==0)
  293.         return ret;
  294.     __set_fp(ret,name,flag);
  295.     return ret;
  296. }
  297.  
  298. /* Close something opened with xopen. . . */
  299. int
  300. xclose FUN1(FILE *,fp)
  301. {
  302.     int ret;
  303.     int n;
  304.     extern int pclose();
  305.     extern int fclose();
  306.  
  307.     for(n=0;n<__id_n;n++) {
  308.         if(__id_s[n].fp==fp)
  309.             break;
  310.     }
  311.     if(n==__id_n)
  312.         panic("Unknown file pointer %p given to xclose",fp);
  313.     if(__id_s[n].flag)
  314.         ret=pclose(fp);
  315.     else
  316.         ret=fclose(fp);
  317.     return ret;
  318. }
  319.  
  320. /* Fclose or panic */
  321. void
  322. ck_fclose FUN1(FILE *, stream)
  323. {
  324. extern int fclose();
  325.  
  326.     if(fclose(stream)==EOF)
  327.         panic("Couldn't close %s",__fp_name(stream));
  328. }
  329.  
  330. /* fopen or panic */
  331. VOIDSTAR
  332. ck_malloc FUN1(size_t, size)
  333. {
  334.     VOIDSTAR ret;
  335.  
  336.     ret=malloc(size);
  337.     if(ret==(VOIDSTAR)0)
  338.         panic("Couldn't allocate %u bytes",size);
  339.     return ret;
  340. }
  341.  
  342. /* Realloc or panic */
  343. VOIDSTAR
  344. ck_realloc FUN2(VOIDSTAR, ptr,size_t, size)
  345. {
  346.     VOIDSTAR ret;
  347.     VOIDSTAR realloc EXT2(VOIDSTAR,size_t);
  348.  
  349.     ret=realloc(ptr,size);
  350.     if(ret==(VOIDSTAR)0)
  351.         panic("Couldn't re-allocate %u bytes from %p",size,ptr);
  352.     return ret;
  353. }
  354.  
  355. /* Do a sprintf into an allocated buffer. */
  356. char *
  357. #ifdef __STDC__
  358. mk_sprintf(char *str,...)
  359. {
  360.     va_list iggy;
  361. #ifdef __TURBOC__
  362.     static
  363. #endif
  364.     char tmpbuf[1024*8];
  365.     char *ret;
  366. #ifdef NEED_VPRINTF
  367.     auto FILE f;
  368. #endif
  369.  
  370.     va_start(iggy,str);
  371. #ifdef NEED_VPRINTF
  372.     f._cnt = 1024*8-1;
  373.     f._ptr = (unsigned char *)tmpbuf;
  374.     f._flag = _IOWRT+_IOSTRG;
  375.     _doprnt(str, iggy, &f);
  376.     *f._ptr = 0;
  377. #else
  378.     vsprintf(tmpbuf,str,iggy);
  379. #endif
  380.     va_end(iggy);
  381.     ret=(char *)ck_malloc(strlen(tmpbuf)+1);
  382.     strcpy(ret,tmpbuf);
  383.     return ret;
  384. }
  385. #else
  386. mk_sprintf(str,va_alist)
  387. char *str;
  388. va_dcl
  389. {
  390.     va_list iggy;
  391. #ifdef __TURBOC__
  392.     static
  393. #endif
  394.     char tmpbuf[1024*8];
  395.     char *ret;
  396. #ifdef NEED_VPRINTF
  397.     auto FILE f;
  398. #endif
  399.  
  400.     va_start(iggy);
  401. #ifdef NEED_VPRINTF
  402.     f._cnt = 1024*8-1;
  403.     f._ptr = (unsigned char *)tmpbuf;
  404.     f._flag = _IOWRT+_IOSTRG;
  405.     _doprnt(str, iggy, &f);
  406.     *f._ptr = 0;
  407. #else
  408.     vsprintf(tmpbuf,str,iggy);
  409. #endif
  410.     va_end(iggy);
  411.  
  412.     ret=(char *)ck_malloc(strlen(tmpbuf)+1);
  413.     strcpy(ret,tmpbuf);
  414.     return ret;
  415. }
  416. #endif
  417.  
  418. /* Implement a variable sized LIFO stack of pointers to void */
  419.  
  420. struct stack {
  421.     int allocated;
  422.     int used;
  423.     VOIDSTAR *buf;
  424. };
  425.  
  426. #define MIN_STACK 20
  427.  
  428. VOIDSTAR
  429. init_stack FUN0()
  430. {
  431.     struct stack *b;
  432.  
  433.     b=(struct stack *)ck_malloc(sizeof(struct stack));
  434.     b->allocated=MIN_STACK;
  435.     b->used=0;
  436.     b->buf=(VOIDSTAR *)ck_malloc(MIN_STACK*sizeof(VOIDSTAR));
  437.     return (VOIDSTAR)b;
  438. }
  439.  
  440. void
  441. flush_stack FUN1(VOIDSTAR, bb)
  442. {
  443.     struct stack *b;
  444.  
  445.     b=(struct stack *)bb;
  446.     free(b->buf);
  447.     b->buf=0;
  448.     b->allocated=0;
  449.     b->used=0;
  450.     free(b);
  451. }
  452.  
  453. void
  454. push_stack FUN2(VOIDSTAR,bb, VOIDSTAR,add)
  455. {
  456.     struct stack *b;
  457.  
  458.     b=(struct stack *)bb;
  459.     if(b->allocated==b->used) {
  460.         b->allocated*=2;
  461.  
  462.         b->buf=(VOIDSTAR *)ck_realloc(b->buf,b->allocated*sizeof(VOIDSTAR));
  463.     }
  464.     b->buf[(b->used)++]=add;
  465. }
  466.  
  467. VOIDSTAR
  468. pop_stack FUN1(VOIDSTAR, bb)
  469. {
  470.     struct stack *b;
  471.  
  472.     b=(struct stack *)bb;
  473.     if(b->used==0)
  474.         return (VOIDSTAR)0;
  475.     return b->buf[--(b->used)];
  476. }
  477.  
  478. int
  479. size_stack FUN1(VOIDSTAR, bb)
  480. {
  481.     struct stack *b;
  482.  
  483.     b=(struct stack *)bb;
  484.     return b->used;
  485. }
  486.  
  487.  
  488. /* For systems that don't have them */
  489. #ifdef NEED_VPRINTF
  490. int
  491. vfprintf FUN3(FILE *, fp, CONST char *, s, va_list, ap)
  492. {
  493.     int len;
  494.  
  495.     len = _doprnt(s,ap,fp);
  496.     return (ferror(fp) ? EOF : len);
  497. }
  498.  
  499. int
  500. vsprintf FUN3(char *, into, CONST char *, s, va_list, ap)
  501. {
  502.     int ret;
  503.     auto FILE f;
  504.  
  505.     f._cnt = 32767;
  506.     f._ptr = into;
  507.     f._flag = _IOWRT+_IOSTRG;
  508.     ret = _doprnt(s, ap, &f);
  509.     *f._ptr = 0;
  510.     return (ret);
  511. }
  512. #endif
  513.  
  514. #ifndef LMALLOC
  515. char *
  516. strdup FUN1(CONST char *, str)
  517. {
  518.     char *ret;
  519.  
  520.     ret=(char *)ck_malloc(strlen(str)+2);
  521.     strcpy(ret,str);
  522.     return ret;
  523. }
  524. #endif
  525.  
  526. /*
  527.  * stricmp - compare string s1 to s2, ignoring case
  528.  */
  529.  
  530. int
  531. stricmp FUN2(CONST char *,s1, CONST char *,s2)
  532. {
  533.     register CONST char *scan1;
  534.     register CONST char *scan2;
  535.     register char chr1,chr2;
  536.  
  537.     scan1 = s1;
  538.     scan2 = s2;
  539.     do {
  540.          chr1= isupper(*scan1) ? tolower(*scan1) : *scan1;
  541.          chr2= isupper(*scan2) ? tolower(*scan2) : *scan2;
  542.         scan1++;
  543.         scan2++;
  544.     } while(chr1 && chr1==chr2);
  545.  
  546.     /*
  547.      * The following case analysis is necessary so that characters
  548.      * which look negative collate low against normal characters but
  549.      * high against the end-of-string NUL.
  550.      */
  551.     if (chr1 == '\0' && chr2 == '\0')
  552.         return 0;
  553.     else if (chr1 == '\0')
  554.         return -1;
  555.     else if (chr2 == '\0')
  556.         return 1;
  557.     else
  558.         return chr1 - chr2;
  559. }
  560.  
  561. /* strincmp - compare first N chars of strings S1 and S2 */
  562. int
  563. strincmp FUN3(CONST char *,s1, CONST char *,s2, size_t,n)
  564. {
  565.     register CONST char *scan1;
  566.     register CONST char *scan2;
  567.     register size_t count;
  568.     register char chr1,chr2;
  569.  
  570.     scan1 = s1;
  571.     scan2 = s2;
  572.     count = n;
  573.     do {
  574.          chr1= isupper(*scan1) ? tolower(*scan1) : *scan1;
  575.          chr2= isupper(*scan2) ? tolower(*scan2) : *scan2;
  576.         scan1++;
  577.         scan2++;
  578.     } while(--count!=0 && chr1 && chr1==chr2);
  579.  
  580.     /* if (count == (size_t)-1)
  581.         return 0; */
  582.  
  583.     /*
  584.      * The following case analysis is necessary so that characters
  585.      * which look negative collate low against normal characters but
  586.      * high against the end-of-string NUL.
  587.      */
  588.     if (chr1 == '\0' && chr2 == '\0')
  589.         return 0;
  590.     else if (chr1 == '\0')
  591.         return -1;
  592.     else if (chr2 == '\0')
  593.         return 1;
  594.     else
  595.         return chr1 - chr2;
  596. }
  597.  
  598. CONST char *
  599. strstr FUN2(CONST char *,s, CONST char *,wanted)
  600. {
  601.     register CONST char *scan;
  602.     register size_t len;
  603.     register char firstc;
  604.  
  605.     /*
  606.      * The odd placement of the two tests is so "" is findable.
  607.      * Also, we inline the first char for speed.
  608.      * The ++ on scan has been moved down for optimization.
  609.      */
  610.     firstc = *wanted;
  611.     len = strlen(wanted);
  612.     for (scan = s; *scan != firstc || strncmp(scan, wanted, len) != 0; )
  613.         if (*scan++ == '\0')
  614.             return (char *)0;
  615.     return scan;
  616. }
  617.  
  618. extern int sys_nerr;
  619. extern char *sys_errlist[];
  620. extern int errno;
  621.  
  622. char *
  623. err_msg FUN0()
  624. {
  625.     int n;
  626.     static char buf[80];
  627.  
  628.     n=errno;
  629.  
  630.     if(n<sys_nerr)
  631.         return sys_errlist[n];
  632.     sprintf(buf,"Unknown error code %d (%#x)",n,n);
  633.     return buf;
  634. }
  635.  
  636. #if !defined(LMALLOC) && !defined(__GNU_LIBRARY__)
  637. CONST char *                /* found char, or NULL if none */
  638. index FUN2(CONST char *,s, char, charwanted)
  639. {
  640.     register CONST char *scan;
  641.  
  642.     /*
  643.      * The odd placement of the two tests is so NUL is findable.
  644.      */
  645.     for (scan = s; *scan != charwanted;)    /* ++ moved down for opt. */
  646.         if (*scan++ == '\0')
  647.             return (char *)0;
  648.     return scan;
  649. }
  650.  
  651. void
  652. bcopy FUN3(CONST VOIDSTAR,src, VOIDSTAR,dst, size_t,size)
  653. {
  654.     register char *d;
  655.     register CONST char *s;
  656.     register size_t n;
  657.  
  658.     if (size <= 0)
  659.         return;
  660.  
  661.     s = src;
  662.     d = dst;
  663.     if (s <= d && s + (size-1) >= d) {
  664.         /* Overlap, must copy right-to-left. */
  665.         s += size-1;
  666.         d += size-1;
  667.         for (n = size; n > 0; n--)
  668.             *d-- = *s--;
  669.     } else
  670.         for (n = size; n > 0; n--)
  671.             *d++ = *s++;
  672.  
  673. }
  674.  
  675. int                /* == 0 or != 0 for equality and inequality */
  676. bcmp FUN3(CONST VOIDSTAR,s1, CONST VOIDSTAR,s2, size_t,size)
  677. {
  678.     register CONST char *scan1;
  679.     register CONST char *scan2;
  680.     register size_t n;
  681.  
  682.     scan1 = s1;
  683.     scan2 = s2;
  684.     for (n = size; n > 0; n--)
  685.         if (*scan1 == *scan2) {
  686.             scan1++;
  687.             scan2++;
  688.         } else
  689.             return *scan1 - *scan2;
  690.  
  691.     return 0;
  692. }
  693.  
  694. void
  695. bzero FUN2(VOIDSTAR,dst, size_t,length)
  696. {
  697.     register char *scan;
  698.     register size_t n;
  699.  
  700.     scan = dst;
  701.     for (n = length; n > 0; n--)
  702.         *scan++ = 0;
  703. }
  704. #endif
  705.  
  706. /* Take a quoted string and return the character it represents */
  707. int
  708. string_to_char FUN1(char **,ptr)
  709. {
  710.     char *str;
  711.     int i;
  712.     char c1,c2;
  713.  
  714.     str= *ptr;
  715.     if(str[0]=='\\') {
  716.         switch(str[1]) {
  717.         case '\\':    i='\\';        break;
  718.         case 'a':    i='\a';        break;
  719.         case 'b':    i='\b';        break;
  720.         case 'f':    i='\f';        break;
  721.         case 'n':    i='\n';        break;
  722.         case 'r':    i='\r';        break;
  723.         case 't':    i='\t';        break;
  724.         case 'x':
  725.             c1=str[2];
  726.             c2=str[3];
  727.             if(isxdigit(c1)) {
  728.                 if(isdigit(c1))
  729.                     c1-='0';
  730.                 else if(isupper(c1))
  731.                     c1-='A';
  732.                 else
  733.                     c1-='a';
  734.                 if(isxdigit(c2)) {
  735.                     if(isdigit(c2))
  736.                         c2-='0';
  737.                     else if(isupper(c2))
  738.                         c2-='A';
  739.                     else
  740.                         c2-='a';
  741.                     i=c1*0x10+c2;
  742.                     str++;
  743.                 } else
  744.                     i=c1;
  745.             } else
  746.                 i='x';
  747.             break;
  748.  
  749.         case '0':  case '1':  case '2':  case '3':
  750.         case '4':  case '5':  case '6':  case '7':
  751.             if(str[2]>='0' && str[2]<='7') {
  752.                 if(str[3]>='0' && str[3]<='7') {
  753.                     i=(str[1]-'0')*0100+(str[2]-'0')*010+(str[3]-'0');
  754.                     str+=2;
  755.                 } else {
  756.                     i=(str[1]-'0')*010+(str[2]-'0');
  757.                     str++;
  758.                 }
  759.             } else
  760.                 i=str[1]-'0';
  761.             break;
  762.         default:    i=str[0];    --str;    break;
  763.         }
  764.         str+=2;
  765.         *ptr=str;
  766.         return i;
  767.     }
  768.  
  769.     if(str[0]=='M' && str[1]=='-') {
  770.         i=0x80;
  771.         str+=2;
  772.     } else
  773.         i=0;
  774.  
  775.     if(str[0]=='^') {
  776.          if(str[1]=='?')
  777.              i+=0x7f;
  778.         else if (str[1]>='@' && str[1]<='_')
  779.             i|= str[1]-'@';
  780.         else
  781.             return -1;
  782.         str+=2;
  783.     } else {
  784.         i|=str[0];
  785.         str++;
  786.     }
  787.     *ptr=str;
  788.     return i;
  789. }
  790.  
  791. /* Take a char and turn it into a readable string */
  792. char *
  793. char_to_string FUN1(char,ch)
  794. {
  795.     static char buf[5] = "M-";
  796.  
  797.     if(ch>=' ' && ch<='~') {
  798.         buf[3]=ch;
  799.         return &buf[3];
  800.     }
  801.     if(ch&0x80) {
  802.         ch&=0x7f;
  803.         if(ch==0x7f || ch<' ') {
  804.             buf[2]='^';
  805.             buf[3]=(ch==0x7f ? '?' : ch+'@');
  806.         } else {
  807.             buf[2]=ch;
  808.             buf[3]='\0';
  809.         }
  810.         return &buf[0];
  811.     }
  812.     if(ch==0x7f || ch<' ') {
  813.         buf[2]='^';
  814.         buf[3]=(ch==0x7f ? '?' : ch+'@');
  815.         return &buf[2];
  816.     }
  817.     return "huh";
  818. }
  819.  
  820. long
  821. astol FUN1(char **,ptr)
  822. {
  823.     register long i = 0;
  824.     register int c;
  825.     int sign = 1;
  826.     char *s;
  827.  
  828.     s= *ptr;
  829.     /* Skip whitespace */
  830.     while(isspace(*s))
  831.         if(*s++ == '\0') {
  832.             *ptr=s;
  833.             return(0);
  834.         }
  835.     /* Check for - or + */
  836.     if(*s == '-') {
  837.         s++;
  838.         sign = -1;
  839.     } else if(*s=='+')
  840.         s++;
  841.  
  842.     /* Read in the digits */
  843.     for(; c = *s; s++) {
  844.         if(!isdigit(c) || i>214748364 || (i==214748364 && c>(sign>0 ? '7' : '8')))
  845.             break;
  846.         i = i * 10 + c-'0';
  847.     }
  848.     *ptr=s;
  849.     return i*sign;
  850. }
  851.  
  852. /*
  853.  *    astof - accept a number of the form:
  854.  *        (and ignores leading white space)
  855.  *
  856.  *    null    ::=
  857.  *    digit    ::= 0|1|2|3|4|5|6|7|8|9
  858.  *    digits    ::= <digit>*
  859.  *    DIGITS    ::= <digit>+
  860.  *    sign    ::= <null> | + | -
  861.  *    -------------------------------
  862.  *        accepted:
  863.  *    -------------------------------
  864.  *    integer    ::= <sign><DIGITS>
  865.  *    real    ::= <integer> . <digits> | <null> . <DIGITS>
  866.  *    epart    ::= e <integer> | E <integer>
  867.  *    float    ::= <integer> <epart> | <real> <epart>
  868.  *
  869.  *    Always returned as a double
  870.  *
  871.  *    There is no particular attempt to reduce mpys/divs
  872.  *    those machines that are still out there (eg. PDP11/Small)
  873.  *    that shun floating point arithmetic might rethink this routine.
  874.  */
  875.  
  876. static double exps0[10] = { 1E0, 1E1, 1E2, 1E3, 1E4, 1E5, 1E6, 1E7, 1E8, 1E9};
  877. static double exps1[10] = { 1E00,1E10,1E20,1E30
  878. #ifndef vax
  879.     ,1E40,1E50,1E60,1E70,1E80,1E90
  880. #endif
  881. };
  882.  
  883. #define REGISTER register
  884.  
  885. double
  886. astof FUN1(char **,sp)
  887. {
  888.     REGISTER char *s;
  889.     REGISTER char *cp;
  890.     long ipart, epart;
  891.     int neg = 0;
  892.     double res;
  893.     int n;
  894.  
  895.     s= *sp;
  896.     while(isspace(*s)) {
  897.         s++;
  898.         if(*s == '\0') {
  899.             *sp = s;
  900.             return(0.0);
  901.         }
  902.     }
  903.     /*
  904.      *    Need to handle sign here due to '-.3' or '-0.3'
  905.      */
  906.     if(*s == '-') {
  907.         ++neg;
  908.         ++s;
  909.     } else if(*s=='+')
  910.         ++s;
  911.     cp = s;
  912.     /*
  913.      *    get ipart handling '.n' case
  914.      */
  915.     res= 0.0;
  916.     while(isdigit(*s)) {
  917.         for(n=0,ipart=0;n<6 && isdigit(*s);n++)
  918.             ipart=ipart*10 + *s++ -'0';
  919.         res=res*exps0[n]+(double)ipart;
  920.     }
  921.     if(s == cp) {
  922.         if(*s == '.')
  923.             ipart = 0;
  924.         else {
  925.             *sp = s;
  926.             return(0.0);
  927.         }
  928.     }
  929.     /*
  930.      *    either we find a '.' or e|E or done
  931.      */
  932.     if(*s == '.')
  933.     {
  934.         int m;
  935.         ++s;
  936.  
  937.         m=0;
  938.         while(isdigit(*s)) {
  939.             for(n=0,ipart=0;n<6 && isdigit(*s);n++)
  940.                 ipart=ipart*10 + *s++ -'0';
  941.             m+=n;
  942.             if(m>=100)
  943.                 continue;
  944.             if(m>=10)
  945.                 res+=((double)ipart)/(exps1[m/10]*exps0[m%10]);
  946.             else
  947.                 res+= ((double)ipart)/exps0[m];
  948.         }
  949.     }
  950.     /*
  951.      *    In either case (.) handle E part
  952.      */
  953.     if(*s=='e' || *s=='E') {
  954.         int eneg;
  955.  
  956.         ++s;
  957.         epart=0;
  958.         eneg=0;
  959.         if(*s=='-') {
  960.             eneg++;
  961.             s++;
  962.         } else if(*s=='+')
  963.             s++;
  964.         while(isdigit(*s))
  965.             epart=epart*10+*s++-'0';
  966.         if(eneg) {
  967. #ifndef vax
  968.             while(epart>=100) {
  969.                 res/=1E100;
  970.                 epart-=100;
  971.             }
  972. #endif
  973.             if(epart>9) {
  974.                 res/=exps1[epart/10];
  975.                 epart%=10;
  976.             }
  977.             if(epart)
  978.                 res/=exps0[epart];
  979.         } else {
  980. #ifndef vax
  981.             while(epart>=100) {
  982.                 res *=1E100;
  983.                 epart-=100;
  984.             }
  985. #endif
  986.             if(epart>9) {
  987.                 res*=exps1[epart/10];
  988.                 epart %= 10;
  989.             }
  990.             if(epart)
  991.                 res*=exps0[epart];
  992.         }
  993.     }
  994.     /*
  995.      *    fix sign
  996.      */
  997.     if(neg) res = -res;
  998.     *sp=s;
  999.     return(res);
  1000. }
  1001.  
  1002. #ifdef TEST_ASTOF
  1003. main()
  1004. {
  1005.     char buf[80];
  1006.     char *ptr;
  1007.     double at,ast;
  1008.     double atof();
  1009.  
  1010.     while(gets(buf)) {
  1011.         at=atof(buf);
  1012.         ptr=buf;
  1013.         ast=astof(&ptr);
  1014.         printf("%15.6f %15.6f %s ",at,ast,at==ast ? "eq" : "NEQ");
  1015.         if(*ptr) printf("%s->'%s'\n",buf,ptr);
  1016.         else printf("%s\n",buf);
  1017.     }
  1018. }
  1019.  
  1020. #endif
  1021.