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