make var.c:getint() more like misc.c:getn(), except for the API differences:

getn() parses a decimal 32-bit integer, getint() a POSIX- or ksh-style based
integer with unsigned wraparound to 32 bit, then possible negation (so that,
for example, -0xFFFFFFFF continues to work)
This commit is contained in:
tg 2015-04-19 18:13:31 +00:00
parent 94acf49453
commit a2a4e41975
1 changed files with 47 additions and 28 deletions

75
var.c
View File

@ -28,7 +28,7 @@
#include <sys/sysctl.h>
#endif
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.188 2015/04/19 14:22:09 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.189 2015/04/19 18:13:31 tg Exp $");
/*-
* Variables
@ -481,41 +481,57 @@ setint(struct tbl *vq, mksh_ari_t n)
static int
getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
{
mksh_uari_t c, num, base;
mksh_uari_t c, num = 0, base = 10;
const char *s;
bool have_base = false, neg = false;
if (vp->flag&SPECIAL)
if (vp->flag & SPECIAL)
getspec(vp);
/* XXX is it possible for ISSET to be set and val.s to be NULL? */
if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
if (!(vp->flag & ISSET) || (!(vp->flag & INTEGER) && vp->val.s == NULL))
return (-1);
if (vp->flag&INTEGER) {
if (vp->flag & INTEGER) {
nump->i = vp->val.i;
return (vp->type);
}
s = vp->val.s + vp->type;
base = 10;
num = 0;
if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
s += 2;
base = 16;
have_base = true;
do {
c = (unsigned char)*s++;
} while (ksh_isspace(c));
switch (c) {
case '-':
neg = true;
/* FALLTHROUGH */
case '+':
c = (unsigned char)*s++;
break;
}
if (Flag(FPOSIX) && arith && s[0] == '0' && ksh_isdigit(s[1]) &&
!(vp->flag & ZEROFIL)) {
/* interpret as octal (deprecated) */
base = 8;
have_base = true;
if (c == '0' && arith) {
if ((s[0] | 0x20) == 'x') {
/* interpret as hexadecimal */
base = 16;
++s;
goto getint_c_style_base;
} else if (Flag(FPOSIX) && ksh_isdigit(s[0]) &&
!(vp->flag & ZEROFIL)) {
/* interpret as octal (deprecated) */
base = 8;
getint_c_style_base:
have_base = true;
c = (unsigned char)*s++;
}
}
while ((c = (unsigned char)*s++)) {
if (c == '-') {
neg = true;
continue;
} else if (c == '#') {
do {
if (c == '#') {
/* ksh-style base determination */
if (have_base || num < 1)
return (-1);
if ((base = num) == 1) {
/* mksh-specific extension */
unsigned int wc;
if (!UTFMODE)
@ -535,18 +551,21 @@ getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
num = 0;
have_base = true;
continue;
} else if (ksh_isdigit(c))
}
if (ksh_isdigit(c))
c -= '0';
else if (ksh_islower(c))
else {
c |= 0x20;
if (!ksh_islower(c))
return (-1);
c -= 'a' - 10;
else if (ksh_isupper(c))
c -= 'A' - 10;
else
return (-1);
}
if (c >= base)
return (-1);
/* handle overflow as truncation */
num = num * base + c;
}
} while ((c = (unsigned char)*s++));
if (neg)
num = -num;
nump->u = num;