xref: /plan9/sys/src/cmd/unix/drawterm/libmp/strtomp.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include "os.h"
2 #include <mp.h>
3 #include <libsec.h>
4 #include "dat.h"
5 
6 static struct {
7 	int	inited;
8 
9 	uchar	t64[256];
10 	uchar	t32[256];
11 	uchar	t16[256];
12 	uchar	t10[256];
13 } tab;
14 
15 enum {
16 	INVAL=	255
17 };
18 
19 static char set64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
20 static char set32[] = "23456789abcdefghijkmnpqrstuvwxyz";
21 static char set16[] = "0123456789ABCDEF0123456789abcdef";
22 static char set10[] = "0123456789";
23 
24 static void
init(void)25 init(void)
26 {
27 	char *p;
28 
29 	memset(tab.t64, INVAL, sizeof(tab.t64));
30 	memset(tab.t32, INVAL, sizeof(tab.t32));
31 	memset(tab.t16, INVAL, sizeof(tab.t16));
32 	memset(tab.t10, INVAL, sizeof(tab.t10));
33 
34 	for(p = set64; *p; p++)
35 		tab.t64[(uchar)*p] = p-set64;
36 	for(p = set32; *p; p++)
37 		tab.t32[(uchar)*p] = p-set32;
38 	for(p = set16; *p; p++)
39 		tab.t16[(uchar)*p] = (p-set16)%16;
40 	for(p = set10; *p; p++)
41 		tab.t10[(uchar)*p] = (p-set10);
42 
43 	tab.inited = 1;
44 }
45 
46 static char*
from16(char * a,mpint * b)47 from16(char *a, mpint *b)
48 {
49 	char *p, *next;
50 	int i;
51 	mpdigit x;
52 
53 	b->top = 0;
54 	for(p = a; *p; p++)
55 		if(tab.t16[(uchar)*p] == INVAL)
56 			break;
57 	mpbits(b, (p-a)*4);
58 	b->top = 0;
59 	next = p;
60 	while(p > a){
61 		x = 0;
62 		for(i = 0; i < Dbits; i += 4){
63 			if(p <= a)
64 				break;
65 			x |= tab.t16[(uchar)*--p]<<i;
66 		}
67 		b->p[b->top++] = x;
68 	}
69 	return next;
70 }
71 
72 static ulong mppow10[] = {
73 	1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
74 };
75 
76 static char*
from10(char * a,mpint * b)77 from10(char *a, mpint *b)
78 {
79 	ulong x, y;
80 	mpint *pow, *r;
81 	int i;
82 
83 	pow = mpnew(0);
84 	r = mpnew(0);
85 
86 	b->top = 0;
87 	for(;;){
88 		// do a billion at a time in native arithmetic
89 		x = 0;
90 		for(i = 0; i < 9; i++){
91 			y = tab.t10[(uchar)*a];
92 			if(y == INVAL)
93 				break;
94 			a++;
95 			x *= 10;
96 			x += y;
97 		}
98 		if(i == 0)
99 			break;
100 
101 		// accumulate into mpint
102 		uitomp(mppow10[i], pow);
103 		uitomp(x, r);
104 		mpmul(b, pow, b);
105 		mpadd(b, r, b);
106 		if(i != 9)
107 			break;
108 	}
109 	mpfree(pow);
110 	mpfree(r);
111 	return a;
112 }
113 
114 static char*
from64(char * a,mpint * b)115 from64(char *a, mpint *b)
116 {
117 	char *buf = a;
118 	uchar *p;
119 	int n, m;
120 
121 	for(; tab.t64[(uchar)*a] != INVAL; a++)
122 		;
123 	n = a-buf;
124 	mpbits(b, n*6);
125 	p = malloc(n);
126 	if(p == nil)
127 		return a;
128 	m = dec64(p, n, buf, n);
129 	betomp(p, m, b);
130 	free(p);
131 	return a;
132 }
133 
134 static char*
from32(char * a,mpint * b)135 from32(char *a, mpint *b)
136 {
137 	char *buf = a;
138 	uchar *p;
139 	int n, m;
140 
141 	for(; tab.t64[(uchar)*a] != INVAL; a++)
142 		;
143 	n = a-buf;
144 	mpbits(b, n*5);
145 	p = malloc(n);
146 	if(p == nil)
147 		return a;
148 	m = dec32(p, n, buf, n);
149 	betomp(p, m, b);
150 	free(p);
151 	return a;
152 }
153 
154 mpint*
strtomp(char * a,char ** pp,int base,mpint * b)155 strtomp(char *a, char **pp, int base, mpint *b)
156 {
157 	int sign;
158 	char *e;
159 
160 	if(b == nil)
161 		b = mpnew(0);
162 
163 	if(tab.inited == 0)
164 		init();
165 
166 	while(*a==' ' || *a=='\t')
167 		a++;
168 
169 	sign = 1;
170 	for(;; a++){
171 		switch(*a){
172 		case '-':
173 			sign *= -1;
174 			continue;
175 		}
176 		break;
177 	}
178 
179 	switch(base){
180 	case 10:
181 		e = from10(a, b);
182 		break;
183 	default:
184 	case 16:
185 		e = from16(a, b);
186 		break;
187 	case 32:
188 		e = from32(a, b);
189 		break;
190 	case 64:
191 		e = from64(a, b);
192 		break;
193 	}
194 
195 	// if no characters parsed, there wasn't a number to convert
196 	if(e == a)
197 		return nil;
198 
199 	mpnorm(b);
200 	b->sign = sign;
201 	if(pp != nil)
202 		*pp = e;
203 
204 	return b;
205 }
206