xref: /plan9-contrib/sys/src/cmd/unix/drawterm/libc/charstod.c (revision 0d601874851962e88c6c60fdd2e637bba04e13c2)
1 /*
2  * The authors of this software are Rob Pike and Ken Thompson.
3  *              Copyright (c) 2002 by Lucent Technologies.
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose without fee is hereby granted, provided that this entire notice
6  * is included in all copies of any software which is or includes a copy
7  * or modification of this software and in all copies of the supporting
8  * documentation for such software.
9  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
10  * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
11  * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
12  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
13  */
14 #include <u.h>
15 #include <libc.h>
16 #include "fmtdef.h"
17 
18 /*
19  * Reads a floating-point number by interpreting successive characters
20  * returned by (*f)(vp).  The last call it makes to f terminates the
21  * scan, so is not a character in the number.  It may therefore be
22  * necessary to back up the input stream up one byte after calling charstod.
23  */
24 
25 double
26 fmtcharstod(int(*f)(void*), void *vp)
27 {
28 	double num, dem;
29 	int neg, eneg, dig, exp, c;
30 
31 	num = 0;
32 	neg = 0;
33 	dig = 0;
34 	exp = 0;
35 	eneg = 0;
36 
37 	c = (*f)(vp);
38 	while(c == ' ' || c == '\t')
39 		c = (*f)(vp);
40 	if(c == '-' || c == '+'){
41 		if(c == '-')
42 			neg = 1;
43 		c = (*f)(vp);
44 	}
45 	while(c >= '0' && c <= '9'){
46 		num = num*10 + c-'0';
47 		c = (*f)(vp);
48 	}
49 	if(c == '.')
50 		c = (*f)(vp);
51 	while(c >= '0' && c <= '9'){
52 		num = num*10 + c-'0';
53 		dig++;
54 		c = (*f)(vp);
55 	}
56 	if(c == 'e' || c == 'E'){
57 		c = (*f)(vp);
58 		if(c == '-' || c == '+'){
59 			if(c == '-'){
60 				dig = -dig;
61 				eneg = 1;
62 			}
63 			c = (*f)(vp);
64 		}
65 		while(c >= '0' && c <= '9'){
66 			exp = exp*10 + c-'0';
67 			c = (*f)(vp);
68 		}
69 	}
70 	exp -= dig;
71 	if(exp < 0){
72 		exp = -exp;
73 		eneg = !eneg;
74 	}
75 	dem = __fmtpow10(exp);
76 	if(eneg)
77 		num /= dem;
78 	else
79 		num *= dem;
80 	if(neg)
81 		return -num;
82 	return num;
83 }
84