mirror of
https://github.com/lcn2/calc.git
synced 2025-08-16 01:03:29 +03:00
Converted all ASCII tabs to ASCII spaces using a 8 character tab stop, for all files, except for all Makefiles (plus rpm.mk). The `git diff -w` reports no changes.
373 lines
12 KiB
C
373 lines
12 KiB
C
/*
|
|
* lib_util - calc library utility routines
|
|
*
|
|
* Copyright (C) 1999-2006,2021-2023 Landon Curt Noll
|
|
*
|
|
* Calc is open software; you can redistribute it and/or modify it under
|
|
* the terms of the version 2.1 of the GNU Lesser General Public License
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* Calc is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
|
|
* Public License for more details.
|
|
*
|
|
* A copy of version 2.1 of the GNU Lesser General Public License is
|
|
* distributed with calc under the filename COPYING-LGPL. You should have
|
|
* received a copy with calc; if not, write to Free Software Foundation, Inc.
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
* Under source code control: 1997/04/19 21:38:30
|
|
* File existed as early as: 1997
|
|
*
|
|
* chongo <was here> /\oo/\ http://www.isthe.com/chongo/
|
|
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
|
|
*/
|
|
|
|
/*
|
|
* These routines are here to support users of libcalc.a. These routines
|
|
* are not directly used by calc itself, however.
|
|
*/
|
|
|
|
|
|
#include "zmath.h"
|
|
#include "alloc.h"
|
|
#include "lib_util.h"
|
|
|
|
|
|
#include "errtbl.h"
|
|
#include "banned.h" /* include after system header <> includes */
|
|
|
|
|
|
/*
|
|
* lowhex2bin - quick low order ASCII hex to binary conversion
|
|
*
|
|
* We just use mod 16 for non-hex ASCII chars. We use just mod 128
|
|
* for non-ASCII to ASCII conversion.
|
|
*
|
|
* | 00 nul | 01 soh | 02 stx | 03 etx | 04 eot | 05 enq | 06 ack | 07 bel |
|
|
* | 08 bs | 09 ht | 0a nl | 0b vt | 0c np | 0d cr | 0e so | 0f si |
|
|
* | 10 dle | 11 dc1 | 12 dc2 | 13 dc3 | 14 dc4 | 15 nak | 16 syn | 17 etb |
|
|
* | 18 can | 19 em | 1a sub | 1b esc | 1c fs | 1d gs | 1e rs | 1f us |
|
|
* | 20 sp | 21 ! | 22 " | 23 # | 24 $ | 25 % | 26 & | 27 ' |
|
|
* | 28 ( | 29 ) | 2a * | 2b + | 2c , | 2d - | 2e . | 2f / |
|
|
* | 30 0 | 31 1 | 32 2 | 33 3 | 34 4 | 35 5 | 36 6 | 37 7 |
|
|
* | 38 8 | 39 9 | 3a : | 3b ; | 3c < | 3d = | 3e > | 3f ? |
|
|
* | 40 @ | 41 A | 42 B | 43 C | 44 D | 45 E | 46 F | 47 G |
|
|
* | 48 H | 49 I | 4a J | 4b K | 4c L | 4d M | 4e N | 4f O |
|
|
* | 50 P | 51 Q | 52 R | 53 S | 54 T | 55 U | 56 V | 57 W |
|
|
* | 58 X | 59 Y | 5a Z | 5b [ | 5c \ | 5d ] | 5e ^ | 5f _ |
|
|
* | 60 ` | 61 a | 62 b | 63 c | 64 d | 65 e | 66 f | 67 g |
|
|
* | 68 h | 69 i | 6a j | 6b k | 6c l | 6d m | 6e n | 6f o |
|
|
* | 70 p | 71 q | 72 r | 73 s | 74 t | 75 u | 76 v | 77 w |
|
|
* | 78 x | 79 y | 7a z | 7b { | 7c | | 7d } | 7e ~ | 7f del |
|
|
*/
|
|
int lowhex2bin[256] = {
|
|
/* 0 1 2 3 4 5 6 7 8 9 a b c d e f */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 0 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 1 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 2 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 3 */
|
|
0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 4 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 5 */
|
|
0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 6 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 7 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 8 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* 9 */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* a */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* b */
|
|
0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* c */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* d */
|
|
0x0,0xa,0xb,0xc,0xd,0xe,0xf,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf, /* e */
|
|
0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xa,0xb,0xc,0xd,0xe,0xf /* f */
|
|
};
|
|
|
|
|
|
/*
|
|
* hex2bin - macro to convert two ASCII hex chars into binary value
|
|
*
|
|
* given:
|
|
* high - high order hex ASCII char
|
|
* low - low order hex ASCII char
|
|
*
|
|
* returns:
|
|
* numeric equivalent to 0x{high}{low} as an int
|
|
*/
|
|
#define hex2bin(high,low) \
|
|
(lowhex2bin[(int)((char)(high))]<<4 | lowhex2bin[((int)(char)(low))])
|
|
|
|
/*
|
|
* lowbin2hex - quick low order binary conversion to ASCII hex
|
|
*/
|
|
char lowbin2hex[256] = {
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',
|
|
'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'
|
|
};
|
|
|
|
|
|
/*
|
|
* convstr2z - convert a string into a ZVALUE
|
|
*
|
|
* NOTE: No attempt is make to deal with byte order.
|
|
*
|
|
* given:
|
|
* str string to convert
|
|
*
|
|
* returns:
|
|
* ZVALUE
|
|
*/
|
|
ZVALUE
|
|
convstr2z(char *str)
|
|
{
|
|
HALF *v; /* storage for string as HALFs */
|
|
ZVALUE ret; /* return value */
|
|
size_t len; /* length in HALFs of our string rounded up */
|
|
|
|
/*
|
|
* firewall
|
|
*/
|
|
if (str == NULL || *str == '\0') {
|
|
/* NULL or empty strings return 0 */
|
|
return _zero_;
|
|
}
|
|
|
|
/*
|
|
* allocate HALF storage
|
|
*/
|
|
len = (strlen(str)+sizeof(HALF)-1)/sizeof(HALF);
|
|
v = (HALF *)malloc(len * sizeof(HALF));
|
|
if (v == NULL) {
|
|
math_error("convstr2z bad malloc");
|
|
not_reached();
|
|
}
|
|
v[len-1] = 0; /* deal with possible partial end of string HALF */
|
|
|
|
/*
|
|
* initialize HALF array with string value
|
|
*/
|
|
memcpy((void *)v, (void *)str, strlen(str));
|
|
|
|
/*
|
|
* setup the rest of the ZVALUE
|
|
*/
|
|
ret.v = v;
|
|
ret.len = len;
|
|
ret.sign = 0;
|
|
ztrim(&ret);
|
|
|
|
/*
|
|
* return our result
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* convhex2z - convert hex string to ZVALUE
|
|
*
|
|
* usage:
|
|
* str hex ASCII string with optional leading 0x
|
|
*
|
|
* returns:
|
|
* ZVALUE
|
|
*/
|
|
ZVALUE
|
|
convhex2z(char *hex)
|
|
{
|
|
HALF *v; /* storage for string as HALFs */
|
|
HALF *hp; /* HALF pointer */
|
|
char *sp; /* string pointer */
|
|
ZVALUE ret; /* return value */
|
|
int len; /* length in HALFs of our string rounded up */
|
|
size_t slen; /* hex string length */
|
|
int i;
|
|
|
|
/*
|
|
* firewall
|
|
*/
|
|
if (hex == NULL || hex[0] == '\0') {
|
|
/* NULL or empty strings return 0 */
|
|
return _zero_;
|
|
}
|
|
|
|
/*
|
|
* skip leading 0X or 0x if needed
|
|
*/
|
|
if (hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) {
|
|
hex += 2;
|
|
}
|
|
if (hex[0] == '\0') {
|
|
/* just 0X or 0x returns 0 */
|
|
return _zero_;
|
|
}
|
|
|
|
/*
|
|
* allocate HALF storage
|
|
*/
|
|
slen = strlen(hex);
|
|
len = ((slen*4)+BASEB-1)/BASEB;
|
|
v = (HALF *)malloc(len * sizeof(HALF));
|
|
if (v == NULL) {
|
|
math_error("convhex2z bad malloc");
|
|
not_reached();
|
|
}
|
|
v[len-1] = 0; /* deal with possible partial end of string HALF */
|
|
|
|
/*
|
|
* deal with the upper partial HALF value
|
|
*/
|
|
hp = v+len-1;
|
|
sp = hex;
|
|
if ((slen % (BASEB/4)) != 0) {
|
|
|
|
/* deal with a odd length hex string first */
|
|
if (slen % 2 == 1) {
|
|
*hp = hex2bin('0', *sp++);
|
|
--slen;
|
|
|
|
/* even length - top top hex char to process */
|
|
} else {
|
|
*hp = 0;
|
|
}
|
|
/* slen is even now */
|
|
|
|
/* eat two hex chars at a time until the HALF is full */
|
|
for (; (slen % (BASEB/4)) != 0; slen -= 2, sp += 2) {
|
|
*hp = ((*hp<<8) | hex2bin(sp[0], sp[1]));
|
|
}
|
|
|
|
/* move on to the next HALF */
|
|
--hp;
|
|
}
|
|
/* slen is now a multiple of BASEB/4 */
|
|
|
|
/*
|
|
* deal with full HALFs
|
|
*/
|
|
for (; slen > 0; slen -= (BASEB/4), --hp) {
|
|
|
|
/* clear HALF */
|
|
*hp = 0;
|
|
|
|
/* eat two hex chars at a time until the HALF is full */
|
|
for (i=0; i < (BASEB/4); i += 2) {
|
|
*hp = ((*hp<<8) | hex2bin(sp[i], sp[i+1]));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* setup the rest of the ZVALUE
|
|
*/
|
|
ret.v = v;
|
|
ret.len = len;
|
|
ret.sign = 0;
|
|
ztrim(&ret);
|
|
|
|
/*
|
|
* return our result
|
|
*/
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* convz2hex - convert ZVALUE to hex string
|
|
*
|
|
* We will ignore the sign of the value.
|
|
*
|
|
* usage:
|
|
* z ZVALUE
|
|
*
|
|
* returns:
|
|
* str hex ASCII malloced string (without a leading 0x)
|
|
*/
|
|
char *
|
|
convz2hex(ZVALUE z)
|
|
{
|
|
char *ret; /* string to return */
|
|
int slen; /* string length (not counting \0) */
|
|
HALF half; /* HALF value to convert */
|
|
int seen_nz; /* 0 => we have not seen a non-zero hex char (yet) */
|
|
char *p;
|
|
int i;
|
|
int j;
|
|
|
|
/*
|
|
* firewall
|
|
*/
|
|
if (z.v == NULL || ziszero(z)) {
|
|
/* malloc and return "0" */
|
|
ret = (char *)malloc(sizeof("0"));
|
|
if (ret == NULL) {
|
|
math_error("convz2hex bad malloc of 0 value");
|
|
not_reached();
|
|
}
|
|
ret[0] = '0';
|
|
ret[1] = '\0';
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* malloc string storage
|
|
*/
|
|
slen = (z.len * BASEB/4);
|
|
ret = (char *)calloc(slen+1+1, sizeof(char));
|
|
if (ret == NULL) {
|
|
math_error("convz2hex bad malloc of string");
|
|
not_reached();
|
|
}
|
|
|
|
/*
|
|
* load in hex ASCII chars for each HALF
|
|
*
|
|
* We will not write leading '0' hex chars into the string.
|
|
*/
|
|
seen_nz = 0;
|
|
for (p=ret, i=z.len-1; i >= 0; --i) {
|
|
|
|
/*
|
|
* load in ASCII hex by ASCII hex
|
|
*/
|
|
for (half=z.v[i], j=BASEB-4; j >= 0; j-=4) {
|
|
if (seen_nz) {
|
|
/* we saw a non-zero, just load the rest */
|
|
*p++ = lowbin2hex[(half >> j) & 0xff];
|
|
} else {
|
|
/* all zeros so far */
|
|
*p = lowbin2hex[(half >> j) & 0xff];
|
|
if (*p != '0') {
|
|
/* we found our first non-zero char */
|
|
++p;
|
|
seen_nz = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (seen_nz) {
|
|
*p = '\0';
|
|
} else {
|
|
/* saw nothing but 0's, so just return 0 */
|
|
*ret = '0';
|
|
*(ret+1) = '\0';
|
|
}
|
|
|
|
/*
|
|
* return the new string
|
|
*/
|
|
return ret;
|
|
}
|