1 /*
2  * lib_util - calc library utility routines
3  *
4  * Copyright (C) 1999-2006,2021  Landon Curt Noll
5  *
6  * Calc is open software; you can redistribute it and/or modify it under
7  * the terms of the version 2.1 of the GNU Lesser General Public License
8  * as published by the Free Software Foundation.
9  *
10  * Calc is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU Lesser General
13  * Public License for more details.
14  *
15  * A copy of version 2.1 of the GNU Lesser General Public License is
16  * distributed with calc under the filename COPYING-LGPL.  You should have
17  * received a copy with calc; if not, write to Free Software Foundation, Inc.
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  * Under source code control:	1997/04/19 21:38:30
21  * File existed as early as:	1997
22  *
23  * chongo <was here> /\oo/\	http://www.isthe.com/chongo/
24  * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/
25  */
26 
27 /*
28  * These routines are here to support users of libcalc.a.  These routines
29  * are not directly used by calc itself, however.
30  */
31 
32 
33 #include "zmath.h"
34 #include "alloc.h"
35 #include "lib_util.h"
36 
37 
38 #include "banned.h"	/* include after system header <> includes */
39 
40 
41 /*
42  * lowhex2bin - quick low order ASCII hex to binary conversion
43  *
44  * We just use mod 16 for non-hex ASCII chars.	We use just mod 128
45  * for non-ASCII to ASCII conversion.
46  *
47  *   | 00 nul | 01 soh | 02 stx | 03 etx | 04 eot | 05 enq | 06 ack | 07 bel |
48  *   | 08 bs  | 09 ht  | 0a nl	| 0b vt	 | 0c np  | 0d cr  | 0e so  | 0f si  |
49  *   | 10 dle | 11 dc1 | 12 dc2 | 13 dc3 | 14 dc4 | 15 nak | 16 syn | 17 etb |
50  *   | 18 can | 19 em  | 1a sub | 1b esc | 1c fs  | 1d gs  | 1e rs  | 1f us  |
51  *   | 20 sp  | 21 !   | 22 "	| 23 #	 | 24 $	  | 25 %   | 26 &   | 27 '   |
52  *   | 28 (   | 29 )   | 2a *	| 2b +	 | 2c ,	  | 2d -   | 2e .   | 2f /   |
53  *   | 30 0   | 31 1   | 32 2	| 33 3	 | 34 4	  | 35 5   | 36 6   | 37 7   |
54  *   | 38 8   | 39 9   | 3a :	| 3b ;	 | 3c <	  | 3d =   | 3e >   | 3f ?   |
55  *   | 40 @   | 41 A   | 42 B	| 43 C	 | 44 D	  | 45 E   | 46 F   | 47 G   |
56  *   | 48 H   | 49 I   | 4a J	| 4b K	 | 4c L	  | 4d M   | 4e N   | 4f O   |
57  *   | 50 P   | 51 Q   | 52 R	| 53 S	 | 54 T	  | 55 U   | 56 V   | 57 W   |
58  *   | 58 X   | 59 Y   | 5a Z	| 5b [	 | 5c \	  | 5d ]   | 5e ^   | 5f _   |
59  *   | 60 `   | 61 a   | 62 b	| 63 c	 | 64 d	  | 65 e   | 66 f   | 67 g   |
60  *   | 68 h   | 69 i   | 6a j	| 6b k	 | 6c l	  | 6d m   | 6e n   | 6f o   |
61  *   | 70 p   | 71 q   | 72 r	| 73 s	 | 74 t	  | 75 u   | 76 v   | 77 w   |
62  *   | 78 x   | 79 y   | 7a z	| 7b {	 | 7c |	  | 7d }   | 7e ~   | 7f del |
63  */
64 int lowhex2bin[256] = {
65   /* 0	 1   2	 3   4	 5   6	 7   8	 9   a	 b   c	 d   e	 f  */
66     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 0 */
67     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 1 */
68     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 2 */
69     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 3 */
70     0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 4 */
71     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 5 */
72     0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 6 */
73     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 7 */
74     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 8 */
75     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* 9 */
76     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* a */
77     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* b */
78     0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* c */
79     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* d */
80     0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf,	/* e */
81     0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf	/* f */
82 };
83 
84 
85 /*
86  * hex2bin - macro to convert two ASCII hex chars into binary value
87  *
88  * given:
89  *	high - high order hex ASCII char
90  *	low - low order hex ASCII char
91  *
92  * returns:
93  *	numeric equivalent to 0x{high}{low} as an int
94  */
95 #define hex2bin(high,low) \
96 	(lowhex2bin[(int)((char)(high))]<<4 | lowhex2bin[((int)(char)(low))])
97 
98 /*
99  * lowbin2hex - quick low order binary conversion to ASCII hex
100  */
101 char lowbin2hex[256] = {
102 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
103 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
104 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
105 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
106 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
107 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
108 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
109 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
110 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
111 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
112 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
113 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
114 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
115 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
116 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
117 	'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
118 };
119 
120 
121 /*
122  * convstr2z - convert a string into a ZVALUE
123  *
124  * NOTE: No attempt is make to deal with byte order.
125  *
126  * given:
127  *	str	string to convert
128  *
129  * returns:
130  *	ZVALUE
131  */
132 ZVALUE
convstr2z(char * str)133 convstr2z(char *str)
134 {
135 	HALF *v;	/* storage for string as HALFs */
136 	ZVALUE ret;	/* return value */
137 	size_t len;	/* length in HALFs of our string rounded up */
138 
139 	/*
140 	 * firewall
141 	 */
142 	if (str == NULL || *str == '\0') {
143 		/* NULL or empty strings return 0 */
144 		return _zero_;
145 	}
146 
147 	/*
148 	 * allocate HALF storage
149 	 */
150 	len = (strlen(str)+sizeof(HALF)-1)/sizeof(HALF);
151 	v = (HALF *)malloc(len * sizeof(HALF));
152 	if (v == NULL) {
153 		math_error("convstr2z bad malloc");
154 		/*NOTREACHED*/
155 	}
156 	v[len-1] = 0;	/* deal with possible partial end of string HALF */
157 
158 	/*
159 	 * initialize HALF array with string value
160 	 */
161 	memcpy((void *)v, (void *)str, strlen(str));
162 
163 	/*
164 	 * setup the rest of the ZVALUE
165 	 */
166 	ret.v = v;
167 	ret.len = len;
168 	ret.sign = 0;
169 	ztrim(&ret);
170 
171 	/*
172 	 * return our result
173 	 */
174 	return ret;
175 }
176 
177 
178 /*
179  * convhex2z - convert hex string to ZVALUE
180  *
181  * usage:
182  *	str	hex ASCII string with optional leading 0x
183  *
184  * returns:
185  *	ZVALUE
186  */
187 ZVALUE
convhex2z(char * hex)188 convhex2z(char *hex)
189 {
190 	HALF *v;	/* storage for string as HALFs */
191 	HALF *hp;	/* HALF pointer */
192 	char *sp;	/* string pointer */
193 	ZVALUE ret;	/* return value */
194 	int len;	/* length in HALFs of our string rounded up */
195 	size_t slen;	/* hex string length */
196 	int i;
197 
198 	/*
199 	 * firewall
200 	 */
201 	if (hex == NULL || hex[0] == '\0') {
202 		/* NULL or empty strings return 0 */
203 		return _zero_;
204 	}
205 
206 	/*
207 	 * skip leading 0X or 0x if needed
208 	 */
209 	if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) {
210 		hex += 2;
211 	}
212 	if (hex[0] == '\0') {
213 		/* just 0X or 0x returns 0 */
214 		return _zero_;
215 	}
216 
217 	/*
218 	 * allocate HALF storage
219 	 */
220 	slen = strlen(hex);
221 	len = ((slen*4)+BASEB-1)/BASEB;
222 	v = (HALF *)malloc(len * sizeof(HALF));
223 	if (v == NULL) {
224 		math_error("convhex2z bad malloc");
225 		/*NOTREACHED*/
226 	}
227 	v[len-1] = 0;	/* deal with possible partial end of string HALF */
228 
229 	/*
230 	 * deal with the upper partial HALF value
231 	 */
232 	hp = v+len-1;
233 	sp = hex;
234 	if ((slen % (BASEB/4)) != 0) {
235 
236 		/* deal with a odd length hex string first */
237 		if (slen % 2 == 1) {
238 			*hp = hex2bin('0', *sp++);
239 			--slen;
240 
241 		/* even length - top top hex char to process */
242 		} else {
243 			*hp = 0;
244 		}
245 		/* slen is even now */
246 
247 		/* eat two hex chars at a time until the HALF is full */
248 		for (; (slen % (BASEB/4)) != 0; slen -= 2, sp += 2) {
249 			*hp = ((*hp<<8) | hex2bin(sp[0], sp[1]));
250 		}
251 
252 		/* move on to the next HALF */
253 		--hp;
254 	}
255 	/* slen is now a multiple of BASEB/4 */
256 
257 	/*
258 	 * deal with full HALFs
259 	 */
260 	for (; slen > 0; slen -= (BASEB/4), --hp) {
261 
262 		/* clear HALF */
263 		*hp = 0;
264 
265 		/* eat two hex chars at a time until the HALF is full */
266 		for (i=0; i < (BASEB/4); i += 2) {
267 			*hp = ((*hp<<8) | hex2bin(sp[i], sp[i+1]));
268 		}
269 	}
270 
271 	/*
272 	 * setup the rest of the ZVALUE
273 	 */
274 	ret.v = v;
275 	ret.len = len;
276 	ret.sign = 0;
277 	ztrim(&ret);
278 
279 	/*
280 	 * return our result
281 	 */
282 	return ret;
283 }
284 
285 
286 /*
287  * convz2hex - convert ZVALUE to hex string
288  *
289  * We will ignore the sign of the value.
290  *
291  * usage:
292  *	z	ZVALUE
293  *
294  * returns:
295  *	str	hex ASCII malloced string (without a leading 0x)
296  */
297 char *
convz2hex(ZVALUE z)298 convz2hex(ZVALUE z)
299 {
300 	char *ret;	/* string to return */
301 	int slen;	/* string length (not counting \0) */
302 	HALF half;	/* HALF value to convert */
303 	int seen_nz;	/* 0 => we have not seen a non-zero hex char (yet) */
304 	char *p;
305 	int i;
306 	int j;
307 
308 	/*
309 	 * firewall
310 	 */
311 	if (z.v == NULL || ziszero(z)) {
312 		/* malloc and return "0" */
313 		ret = (char *)malloc(sizeof("0"));
314 		if (ret == NULL) {
315 			math_error("convz2hex bad malloc of 0 value");
316 			/*NOTREACHED*/
317 		}
318 		ret[0] = '0';
319 		ret[1] = '\0';
320 		return ret;
321 	}
322 
323 	/*
324 	 * malloc string storage
325 	 */
326 	slen = (z.len * BASEB/4);
327 	ret = (char *)calloc(slen+1+1, sizeof(char));
328 	if (ret == NULL) {
329 		math_error("convz2hex bad malloc of string");
330 		/*NOTREACHED*/
331 	}
332 
333 	/*
334 	 * load in hex ASCII chars for each HALF
335 	 *
336 	 * We will not write leading '0' hex chars into the string.
337 	 */
338 	seen_nz = 0;
339 	for (p=ret, i=z.len-1; i >= 0; --i) {
340 
341 		/*
342 		 * load in ASCII hex by ASCII hex
343 		 */
344 		for (half=z.v[i], j=BASEB-4; j >= 0; j-=4) {
345 			if (seen_nz) {
346 				/* we saw a non-zero, just load the rest */
347 				*p++ = lowbin2hex[(half >> j) & 0xff];
348 			} else {
349 				/* all zeros so far */
350 				*p = lowbin2hex[(half >> j) & 0xff];
351 				if (*p != '0') {
352 					/* we found our first non-zero char */
353 					++p;
354 					seen_nz = 1;
355 				}
356 			}
357 		}
358 	}
359 	if (seen_nz) {
360 		*p = '\0';
361 	} else {
362 		/* saw nothing but 0's, so just return 0 */
363 		*ret = '0';
364 		*(ret+1) = '\0';
365 	}
366 
367 	/*
368 	 * return the new string
369 	 */
370 	return ret;
371 }
372