Example #1
0
static int
getint(struct tbl *vp, mksh_ari_u *nump, bool arith)
{
	mksh_uari_t c, num = 0, base = 10;
	const char *s;
	bool have_base = false, neg = false;

	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))
		return (-1);
	if (vp->flag & INTEGER) {
		nump->i = vp->val.i;
		return (vp->type);
	}
	s = vp->val.s + vp->type;

	do {
		c = (unsigned char)*s++;
	} while (ksh_isspace(c));

	switch (c) {
	case '-':
		neg = true;
		/* FALLTHROUGH */
	case '+':
		c = (unsigned char)*s++;
		break;
	}

	if (c == '0' && arith) {
		if (ksh_eq(s[0], 'X', '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++;
		}
	}

	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)
					wc = *(const unsigned char *)s;
				else if (utf_mbtowc(&wc, s) == (size_t)-1)
					/* OPTU-8 -> OPTU-16 */
					/*
					 * (with a twist: 1#\uEF80 converts
					 * the same as 1#\x80 does, thus is
					 * not round-tripping correctly XXX)
					 */
					wc = 0xEF00 + *(const unsigned char *)s;
				nump->u = (mksh_uari_t)wc;
				return (1);
			} else if (base > 36)
				base = 10;
			num = 0;
			have_base = true;
			continue;
		}
		if (ksh_isdigit(c))
			c = ksh_numdig(c);
		else if (ksh_isupper(c))
			c = ksh_numuc(c) + 10;
		else if (ksh_islower(c))
			c = ksh_numlc(c) + 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;
	return (base);
}
Example #2
0
/*
 * print variable/alias value using necessary quotes
 * (POSIX says they should be suitable for re-entry...)
 * No trailing newline is printed.
 */
void
print_value_quoted(struct shf *shf, const char *s)
{
	unsigned char c;
	const unsigned char *p = (const unsigned char *)s;
	bool inquote = true;

	/* first, check whether any quotes are needed */
	while ((c = *p++) >= 32)
		if (ctype(c, C_QUOTE))
			inquote = false;

	p = (const unsigned char *)s;
	if (c == 0) {
		if (inquote) {
			/* nope, use the shortcut */
			shf_puts(s, shf);
			return;
		}

		/* otherwise, quote nicely via state machine */
		while ((c = *p++) != 0) {
			if (c == '\'') {
				/*
				 * multiple single quotes or any of them
				 * at the beginning of a string look nicer
				 * this way than when simply substituting
				 */
				if (inquote) {
					shf_putc('\'', shf);
					inquote = false;
				}
				shf_putc('\\', shf);
			} else if (!inquote) {
				shf_putc('\'', shf);
				inquote = true;
			}
			shf_putc(c, shf);
		}
	} else {
		unsigned int wc;
		size_t n;

		/* use $'...' quote format */
		shf_putc('$', shf);
		shf_putc('\'', shf);
		while ((c = *p) != 0) {
			if (c >= 0xC2) {
				n = utf_mbtowc(&wc, (const char *)p);
				if (n != (size_t)-1) {
					p += n;
					shf_fprintf(shf, "\\u%04X", wc);
					continue;
				}
			}
			++p;
			switch (c) {
			/* see unbksl() in this file for comments */
			case 7:
				c = 'a';
				if (0)
					/* FALLTHROUGH */
			case '\b':
				  c = 'b';
				if (0)
					/* FALLTHROUGH */
			case '\f':
				  c = 'f';
				if (0)
					/* FALLTHROUGH */
			case '\n':
				  c = 'n';
				if (0)
					/* FALLTHROUGH */
			case '\r':
				  c = 'r';
				if (0)
					/* FALLTHROUGH */
			case '\t':
				  c = 't';
				if (0)
					/* FALLTHROUGH */
			case 11:
				  c = 'v';
				if (0)
					/* FALLTHROUGH */
			case '\033':
				/* take E not e because \e is \ in *roff */
				  c = 'E';
				/* FALLTHROUGH */
			case '\\':
				shf_putc('\\', shf);

				if (0)
					/* FALLTHROUGH */
			default:
				  if (c < 32 || c > 0x7E) {
					/* FALLTHROUGH */
			case '\'':
					shf_fprintf(shf, "\\%03o", c);
					break;
				}

				shf_putc(c, shf);
				break;
			}
		}
		inquote = true;
	}
	if (inquote)
		shf_putc('\'', shf);
}
static int
getint(struct tbl *vp, mksh_ari_t *nump, bool arith)
{
	int c, base, neg;
	mksh_uari_t num;
	const char *s;
	bool have_base = false;

	if (vp->flag&SPECIAL)
		getspec(vp);
	/* XXX is it possible for ISSET to be set and val.s to be 0? */
	if (!(vp->flag&ISSET) || (!(vp->flag&INTEGER) && vp->val.s == NULL))
		return (-1);
	if (vp->flag&INTEGER) {
		*nump = vp->val.i;
		return (vp->type);
	}
	s = vp->val.s + vp->type;
	base = 10;
	num = 0;
	neg = 0;
	if (arith && s[0] == '0' && (s[1] | 0x20) == 'x') {
		s += 2;
		base = 16;
		have_base = true;
	}
#ifdef MKSH_LEGACY_MODE
	if (arith && s[0] == '0' && ksh_isdigit(s[1]) &&
	    !(vp->flag & ZEROFIL)) {
		/* interpret as octal (deprecated) */
		base = 8;
		have_base = true;
	}
#endif
	while ((c = *s++)) {
		if (c == '-') {
			neg++;
			continue;
		} else if (c == '#') {
			if (have_base || num < 1 || num > 36)
				return (-1);
			base = (int)num;
			if (base == 1) {
				unsigned int wc;

				if (!UTFMODE)
					wc = *(const unsigned char *)s;
				else if (utf_mbtowc(&wc, s) == (size_t)-1)
					/* OPTU-8 -> OPTU-16 */
					/*
					 * (with a twist: 1#\uEF80 converts
					 * the same as 1#\x80 does, thus is
					 * not round-tripping correctly XXX)
					 */
					wc = 0xEF00 + *(const unsigned char *)s;
				*nump = (mksh_ari_t)wc;
				return (1);
			}
			num = 0;
			have_base = true;
			continue;
		} else if (ksh_isdigit(c))
			c -= '0';
		else if (ksh_islower(c))
			c -= 'a' - 10;
		else if (ksh_isupper(c))
			c -= 'A' - 10;
		else
			return (-1);
		if (c < 0 || c >= base)
			return (-1);
		num = num * base + c;
	}
	*nump = neg ? -((mksh_ari_t)num) : (mksh_ari_t)num;
	return (base);
}