expr.y revision 92979
14Srgrimes%{
24Srgrimes/* Written by Pace Willisson (pace@blitz.com)
3295Sjtc * and placed in the public domain.
44Srgrimes *
5295Sjtc * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
6295Sjtc *
750471Speter * $FreeBSD: head/bin/expr/expr.y 92979 2002-03-22 20:18:26Z wollman $
84Srgrimes */
9468Sjtc
1062926Sse#include <sys/types.h>
1192979Swollman
1292979Swollman#include <ctype.h>
1392979Swollman#include <err.h>
1492979Swollman#include <errno.h>
1592979Swollman#include <inttypes.h>
1692979Swollman#include <limits.h>
1792979Swollman#include <locale.h>
184Srgrimes#include <stdio.h>
194Srgrimes#include <stdlib.h>
204Srgrimes#include <string.h>
2162926Sse#include <regex.h>
2292979Swollman#include <unistd.h>
2331Salm
2492979Swollman/*
2592979Swollman * POSIX specifies a specific error code for syntax errors.  We exit
2692979Swollman * with this code for all errors.
2792979Swollman */
2892979Swollman#define	ERR_EXIT	2
2992979Swollman
304Srgrimesenum valtype {
3112378Sjoerg	integer, numeric_string, string
324Srgrimes} ;
3331Salm
344Srgrimesstruct val {
354Srgrimes	enum valtype type;
364Srgrimes	union {
374Srgrimes		char *s;
3892979Swollman		intmax_t i;
394Srgrimes	} u;
4031Salm} ;
414Srgrimes
424Srgrimesstruct val *result;
434Srgrimes
4492979Swollmanint		chk_div(intmax_t, intmax_t);
4592979Swollmanint		chk_minus(intmax_t, intmax_t, intmax_t);
4692979Swollmanint		chk_plus(intmax_t, intmax_t, intmax_t);
4792979Swollmanint		chk_times(intmax_t, intmax_t, intmax_t);
4890109Simpvoid		free_value(struct val *);
4990109Simpint		is_zero_or_null(struct val *);
5090109Simpint		isstring(struct val *);
5192979Swollmanstruct val	*make_integer(intmax_t);
5290109Simpstruct val	*make_str(const char *);
5390109Simpstruct val	*op_and(struct val *, struct val *);
5490109Simpstruct val	*op_colon(struct val *, struct val *);
5590109Simpstruct val	*op_div(struct val *, struct val *);
5690109Simpstruct val	*op_eq(struct val *, struct val *);
5790109Simpstruct val	*op_ge(struct val *, struct val *);
5890109Simpstruct val	*op_gt(struct val *, struct val *);
5990109Simpstruct val	*op_le(struct val *, struct val *);
6090109Simpstruct val	*op_lt(struct val *, struct val *);
6190109Simpstruct val	*op_minus(struct val *, struct val *);
6290109Simpstruct val	*op_ne(struct val *, struct val *);
6390109Simpstruct val	*op_or(struct val *, struct val *);
6490109Simpstruct val	*op_plus(struct val *, struct val *);
6590109Simpstruct val	*op_rem(struct val *, struct val *);
6690109Simpstruct val	*op_times(struct val *, struct val *);
6792979Swollmanintmax_t	to_integer(struct val *);
6890109Simpvoid		to_string(struct val *);
6990109Simpint		yyerror(const char *);
7090109Simpint		yylex(void);
7190109Simpint		yyparse(void);
7277244Skris
734Srgrimeschar **av;
744Srgrimes%}
754Srgrimes
764Srgrimes%union
774Srgrimes{
784Srgrimes	struct val *val;
794Srgrimes}
804Srgrimes
814Srgrimes%left <val> '|'
824Srgrimes%left <val> '&'
834Srgrimes%left <val> '=' '>' '<' GE LE NE
844Srgrimes%left <val> '+' '-'
854Srgrimes%left <val> '*' '/' '%'
864Srgrimes%left <val> ':'
874Srgrimes
884Srgrimes%token <val> TOKEN
894Srgrimes%type <val> start expr
904Srgrimes
914Srgrimes%%
924Srgrimes
934Srgrimesstart: expr { result = $$; }
944Srgrimes
954Srgrimesexpr:	TOKEN
964Srgrimes	| '(' expr ')' { $$ = $2; }
974Srgrimes	| expr '|' expr { $$ = op_or ($1, $3); }
984Srgrimes	| expr '&' expr { $$ = op_and ($1, $3); }
994Srgrimes	| expr '=' expr { $$ = op_eq ($1, $3); }
1004Srgrimes	| expr '>' expr { $$ = op_gt ($1, $3); }
1014Srgrimes	| expr '<' expr { $$ = op_lt ($1, $3); }
1024Srgrimes	| expr GE expr  { $$ = op_ge ($1, $3); }
1034Srgrimes	| expr LE expr  { $$ = op_le ($1, $3); }
1044Srgrimes	| expr NE expr  { $$ = op_ne ($1, $3); }
1054Srgrimes	| expr '+' expr { $$ = op_plus ($1, $3); }
1064Srgrimes	| expr '-' expr { $$ = op_minus ($1, $3); }
1074Srgrimes	| expr '*' expr { $$ = op_times ($1, $3); }
1084Srgrimes	| expr '/' expr { $$ = op_div ($1, $3); }
1094Srgrimes	| expr '%' expr { $$ = op_rem ($1, $3); }
1104Srgrimes	| expr ':' expr { $$ = op_colon ($1, $3); }
1114Srgrimes	;
1124Srgrimes
1134Srgrimes
1144Srgrimes%%
1154Srgrimes
1164Srgrimesstruct val *
11792979Swollmanmake_integer(intmax_t i)
1184Srgrimes{
1194Srgrimes	struct val *vp;
1204Srgrimes
1214Srgrimes	vp = (struct val *) malloc (sizeof (*vp));
1224Srgrimes	if (vp == NULL) {
12392979Swollman		errx(ERR_EXIT, "malloc() failed");
1244Srgrimes	}
1254Srgrimes
1264Srgrimes	vp->type = integer;
1274Srgrimes	vp->u.i  = i;
1284Srgrimes	return vp;
1294Srgrimes}
1304Srgrimes
1314Srgrimesstruct val *
13290109Simpmake_str(const char *s)
1334Srgrimes{
1344Srgrimes	struct val *vp;
13592979Swollman	char *ep;
1364Srgrimes
1374Srgrimes	vp = (struct val *) malloc (sizeof (*vp));
1384Srgrimes	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
13992979Swollman		errx(ERR_EXIT, "malloc() failed");
1404Srgrimes	}
1414Srgrimes
14292979Swollman	/*
14392979Swollman	 * Previously we tried to scan the string to see if it ``looked like''
14492979Swollman	 * an integer (erroneously, as it happened).  Let strtoimax() do the
14592979Swollman	 * dirty work.  We could cache the value, except that we are using
14692979Swollman	 * a union and need to preserve the original string form until we
14792979Swollman	 * are certain that it is not needed.
14892979Swollman	 *
14992979Swollman	 * IEEE Std.1003.1-2001 says:
15092979Swollman	 * /integer/ An argument consisting only of an (optional) unary minus
15192979Swollman	 *	     followed by digits.
15292979Swollman	 *
15392979Swollman	 * This means that arguments which consist of digits followed by
15492979Swollman	 * non-digits MUST NOT be considered integers.  strtoimax() will
15592979Swollman	 * figure this out for us.
15692979Swollman	 */
15792979Swollman	(void)strtoimax(s, &ep, 10);
1589909Sjoerg
15992979Swollman	if (*ep != '\0')
16092979Swollman		vp->type = string;
16192979Swollman	else
16212378Sjoerg		vp->type = numeric_string;
1639909Sjoerg
1644Srgrimes	return vp;
1654Srgrimes}
1664Srgrimes
1674Srgrimes
1684Srgrimesvoid
16990109Simpfree_value(struct val *vp)
1704Srgrimes{
17112378Sjoerg	if (vp->type == string || vp->type == numeric_string)
1724Srgrimes		free (vp->u.s);
1734Srgrimes}
1744Srgrimes
1754Srgrimes
17692979Swollmanintmax_t
17790109Simpto_integer(struct val *vp)
1784Srgrimes{
17992979Swollman	intmax_t i;
1804Srgrimes
1814Srgrimes	if (vp->type == integer)
1824Srgrimes		return 1;
1834Srgrimes
18412378Sjoerg	if (vp->type == string)
18512378Sjoerg		return 0;
1864Srgrimes
18712378Sjoerg	/* vp->type == numeric_string, make it numeric */
18863755Sse	errno = 0;
18992979Swollman	i  = strtoimax(vp->u.s, (char **)NULL, 10);
19092979Swollman	if (errno == ERANGE)
19192979Swollman		err(ERR_EXIT, NULL);
19292979Swollman
1934Srgrimes	free (vp->u.s);
19412378Sjoerg	vp->u.i = i;
1954Srgrimes	vp->type = integer;
1964Srgrimes	return 1;
1974Srgrimes}
1984Srgrimes
1994Srgrimesvoid
20090109Simpto_string(struct val *vp)
2014Srgrimes{
2024Srgrimes	char *tmp;
2034Srgrimes
20412378Sjoerg	if (vp->type == string || vp->type == numeric_string)
2054Srgrimes		return;
2064Srgrimes
20792979Swollman	/*
20892979Swollman	 * log_10(x) ~= 0.3 * log_2(x).  Rounding up gives the number
20992979Swollman	 * of digits; add one each for the sign and terminating null
21092979Swollman	 * character, respectively.
21192979Swollman	 */
21292979Swollman#define	NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
21392979Swollman	tmp = malloc(NDIGITS(vp->u.i));
21492979Swollman	if (tmp == NULL)
21592979Swollman		errx(ERR_EXIT, "malloc() failed");
2164Srgrimes
21792979Swollman	sprintf(tmp, "%jd", vp->u.i);
2184Srgrimes	vp->type = string;
2194Srgrimes	vp->u.s  = tmp;
2204Srgrimes}
2214Srgrimes
2224Srgrimes
2234Srgrimesint
22490109Simpisstring(struct val *vp)
2254Srgrimes{
22612378Sjoerg	/* only TRUE if this string is not a valid integer */
2274Srgrimes	return (vp->type == string);
2284Srgrimes}
2294Srgrimes
2304Srgrimes
2314Srgrimesint
23290109Simpyylex(void)
2334Srgrimes{
2344Srgrimes	char *p;
2354Srgrimes
2364Srgrimes	if (*av == NULL)
2374Srgrimes		return (0);
2384Srgrimes
2394Srgrimes	p = *av++;
2404Srgrimes
2414Srgrimes	if (strlen (p) == 1) {
2424Srgrimes		if (strchr ("|&=<>+-*/%:()", *p))
2434Srgrimes			return (*p);
2444Srgrimes	} else if (strlen (p) == 2 && p[1] == '=') {
2454Srgrimes		switch (*p) {
2464Srgrimes		case '>': return (GE);
2474Srgrimes		case '<': return (LE);
2484Srgrimes		case '!': return (NE);
2494Srgrimes		}
2504Srgrimes	}
2514Srgrimes
2524Srgrimes	yylval.val = make_str (p);
2534Srgrimes	return (TOKEN);
2544Srgrimes}
2554Srgrimes
2564Srgrimesint
25790109Simpis_zero_or_null(struct val *vp)
2584Srgrimes{
2594Srgrimes	if (vp->type == integer) {
2604Srgrimes		return (vp->u.i == 0);
2614Srgrimes	} else {
262181Sconklin		return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
2634Srgrimes	}
2644Srgrimes	/* NOTREACHED */
2654Srgrimes}
2664Srgrimes
26712378Sjoergint
26892979Swollmanmain(int argc, char *argv[])
2694Srgrimes{
27092979Swollman	int c;
27192979Swollman
272468Sjtc	setlocale (LC_ALL, "");
27392979Swollman	while ((c = getopt(argc, argv, "")) != -1)
27492979Swollman		switch (c) {
27592979Swollman		default:
27692979Swollman			fprintf(stderr, "usage: expr [--] expression\n");
27792979Swollman			exit(ERR_EXIT);
27892979Swollman		}
279468Sjtc
28092979Swollman	av = argv + optind;
2814Srgrimes
28292979Swollman	yyparse();
2834Srgrimes
2844Srgrimes	if (result->type == integer)
28592979Swollman		printf("%jd\n", result->u.i);
2864Srgrimes	else
28792979Swollman		printf("%s\n", result->u.s);
2884Srgrimes
28992979Swollman	return (is_zero_or_null(result));
2904Srgrimes}
2914Srgrimes
2924Srgrimesint
29390109Simpyyerror(const char *s __unused)
2944Srgrimes{
29592979Swollman	errx(ERR_EXIT, "syntax error");
2964Srgrimes}
2974Srgrimes
2984Srgrimes
2994Srgrimesstruct val *
30090109Simpop_or(struct val *a, struct val *b)
3014Srgrimes{
3024Srgrimes	if (is_zero_or_null (a)) {
3034Srgrimes		free_value (a);
3044Srgrimes		return (b);
3054Srgrimes	} else {
3064Srgrimes		free_value (b);
3074Srgrimes		return (a);
3084Srgrimes	}
3094Srgrimes}
3104Srgrimes
3114Srgrimesstruct val *
31290109Simpop_and(struct val *a, struct val *b)
3134Srgrimes{
3144Srgrimes	if (is_zero_or_null (a) || is_zero_or_null (b)) {
3154Srgrimes		free_value (a);
3164Srgrimes		free_value (b);
31792979Swollman		return (make_integer ((intmax_t)0));
3184Srgrimes	} else {
3194Srgrimes		free_value (b);
3204Srgrimes		return (a);
3214Srgrimes	}
3224Srgrimes}
3234Srgrimes
3244Srgrimesstruct val *
32590109Simpop_eq(struct val *a, struct val *b)
3264Srgrimes{
3274Srgrimes	struct val *r;
3284Srgrimes
3294Srgrimes	if (isstring (a) || isstring (b)) {
3304Srgrimes		to_string (a);
3314Srgrimes		to_string (b);
33292979Swollman		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) == 0));
3334Srgrimes	} else {
33412378Sjoerg		(void)to_integer(a);
33512378Sjoerg		(void)to_integer(b);
33692979Swollman		r = make_integer ((intmax_t)(a->u.i == b->u.i));
3374Srgrimes	}
3384Srgrimes
3394Srgrimes	free_value (a);
3404Srgrimes	free_value (b);
3414Srgrimes	return r;
3424Srgrimes}
3434Srgrimes
3444Srgrimesstruct val *
34590109Simpop_gt(struct val *a, struct val *b)
3464Srgrimes{
3474Srgrimes	struct val *r;
3484Srgrimes
3494Srgrimes	if (isstring (a) || isstring (b)) {
3504Srgrimes		to_string (a);
3514Srgrimes		to_string (b);
35292979Swollman		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) > 0));
3534Srgrimes	} else {
35412378Sjoerg		(void)to_integer(a);
35512378Sjoerg		(void)to_integer(b);
35692979Swollman		r = make_integer ((intmax_t)(a->u.i > b->u.i));
3574Srgrimes	}
3584Srgrimes
3594Srgrimes	free_value (a);
3604Srgrimes	free_value (b);
3614Srgrimes	return r;
3624Srgrimes}
3634Srgrimes
3644Srgrimesstruct val *
36590109Simpop_lt(struct val *a, struct val *b)
3664Srgrimes{
3674Srgrimes	struct val *r;
3684Srgrimes
3694Srgrimes	if (isstring (a) || isstring (b)) {
3704Srgrimes		to_string (a);
3714Srgrimes		to_string (b);
37292979Swollman		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) < 0));
3734Srgrimes	} else {
37412378Sjoerg		(void)to_integer(a);
37512378Sjoerg		(void)to_integer(b);
37692979Swollman		r = make_integer ((intmax_t)(a->u.i < b->u.i));
3774Srgrimes	}
3784Srgrimes
3794Srgrimes	free_value (a);
3804Srgrimes	free_value (b);
3814Srgrimes	return r;
3824Srgrimes}
3834Srgrimes
3844Srgrimesstruct val *
38590109Simpop_ge(struct val *a, struct val *b)
3864Srgrimes{
3874Srgrimes	struct val *r;
3884Srgrimes
3894Srgrimes	if (isstring (a) || isstring (b)) {
3904Srgrimes		to_string (a);
3914Srgrimes		to_string (b);
39292979Swollman		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) >= 0));
3934Srgrimes	} else {
39412378Sjoerg		(void)to_integer(a);
39512378Sjoerg		(void)to_integer(b);
39692979Swollman		r = make_integer ((intmax_t)(a->u.i >= b->u.i));
3974Srgrimes	}
3984Srgrimes
3994Srgrimes	free_value (a);
4004Srgrimes	free_value (b);
4014Srgrimes	return r;
4024Srgrimes}
4034Srgrimes
4044Srgrimesstruct val *
40590109Simpop_le(struct val *a, struct val *b)
4064Srgrimes{
4074Srgrimes	struct val *r;
4084Srgrimes
4094Srgrimes	if (isstring (a) || isstring (b)) {
4104Srgrimes		to_string (a);
4114Srgrimes		to_string (b);
41292979Swollman		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) <= 0));
4134Srgrimes	} else {
41412378Sjoerg		(void)to_integer(a);
41512378Sjoerg		(void)to_integer(b);
41692979Swollman		r = make_integer ((intmax_t)(a->u.i <= b->u.i));
4174Srgrimes	}
4184Srgrimes
4194Srgrimes	free_value (a);
4204Srgrimes	free_value (b);
4214Srgrimes	return r;
4224Srgrimes}
4234Srgrimes
4244Srgrimesstruct val *
42590109Simpop_ne(struct val *a, struct val *b)
4264Srgrimes{
4274Srgrimes	struct val *r;
4284Srgrimes
4294Srgrimes	if (isstring (a) || isstring (b)) {
4304Srgrimes		to_string (a);
4314Srgrimes		to_string (b);
43292979Swollman		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) != 0));
4334Srgrimes	} else {
43412378Sjoerg		(void)to_integer(a);
43512378Sjoerg		(void)to_integer(b);
43692979Swollman		r = make_integer ((intmax_t)(a->u.i != b->u.i));
4374Srgrimes	}
4384Srgrimes
4394Srgrimes	free_value (a);
4404Srgrimes	free_value (b);
4414Srgrimes	return r;
4424Srgrimes}
4434Srgrimes
44463755Sseint
44592979Swollmanchk_plus(intmax_t a, intmax_t b, intmax_t r)
44663755Sse{
44763755Sse	/* sum of two positive numbers must be positive */
44863755Sse	if (a > 0 && b > 0 && r <= 0)
44963755Sse		return 1;
45063755Sse	/* sum of two negative numbers must be negative */
45163755Sse	if (a < 0 && b < 0 && r >= 0)
45263755Sse		return 1;
45363755Sse	/* all other cases are OK */
45463755Sse	return 0;
45563755Sse}
45663755Sse
4574Srgrimesstruct val *
45890109Simpop_plus(struct val *a, struct val *b)
4594Srgrimes{
4604Srgrimes	struct val *r;
4614Srgrimes
4624Srgrimes	if (!to_integer (a) || !to_integer (b)) {
46392979Swollman		errx(ERR_EXIT, "non-numeric argument");
4644Srgrimes	}
4654Srgrimes
46692979Swollman	r = make_integer (/*(intmax_t)*/(a->u.i + b->u.i));
46763755Sse	if (chk_plus (a->u.i, b->u.i, r->u.i)) {
46892979Swollman		errx(ERR_EXIT, "overflow");
46963755Sse	}
4704Srgrimes	free_value (a);
4714Srgrimes	free_value (b);
4724Srgrimes	return r;
4734Srgrimes}
47463755Sse
47563755Sseint
47692979Swollmanchk_minus(intmax_t a, intmax_t b, intmax_t r)
47763755Sse{
47892979Swollman	/* special case subtraction of INTMAX_MIN */
47992979Swollman	if (b == INTMAX_MIN) {
48063755Sse		if (a >= 0)
48163755Sse			return 1;
48263755Sse		else
48363755Sse			return 0;
48463755Sse	}
48592979Swollman	/* this is allowed for b != INTMAX_MIN */
48663755Sse	return chk_plus (a, -b, r);
48763755Sse}
48863755Sse
4894Srgrimesstruct val *
49090109Simpop_minus(struct val *a, struct val *b)
4914Srgrimes{
4924Srgrimes	struct val *r;
4934Srgrimes
4944Srgrimes	if (!to_integer (a) || !to_integer (b)) {
49592979Swollman		errx(ERR_EXIT, "non-numeric argument");
4964Srgrimes	}
4974Srgrimes
49892979Swollman	r = make_integer (/*(intmax_t)*/(a->u.i - b->u.i));
49963755Sse	if (chk_minus (a->u.i, b->u.i, r->u.i)) {
50092979Swollman		errx(ERR_EXIT, "overflow");
50163755Sse	}
5024Srgrimes	free_value (a);
5034Srgrimes	free_value (b);
5044Srgrimes	return r;
5054Srgrimes}
50663755Sse
50763755Sseint
50892979Swollmanchk_times(intmax_t a, intmax_t b, intmax_t r)
50963755Sse{
51063755Sse	/* special case: first operand is 0, no overflow possible */
51163755Sse	if (a == 0)
51263755Sse		return 0;
51363755Sse	/* cerify that result of division matches second operand */
51463755Sse	if (r / a != b)
51563755Sse		return 1;
51663755Sse	return 0;
51763755Sse}
51863755Sse
5194Srgrimesstruct val *
52090109Simpop_times(struct val *a, struct val *b)
5214Srgrimes{
5224Srgrimes	struct val *r;
5234Srgrimes
5244Srgrimes	if (!to_integer (a) || !to_integer (b)) {
52592979Swollman		errx(ERR_EXIT, "non-numeric argument");
5264Srgrimes	}
5274Srgrimes
52892979Swollman	r = make_integer (/*(intmax_t)*/(a->u.i * b->u.i));
52963755Sse	if (chk_times (a->u.i, b->u.i, r->u.i)) {
53092979Swollman		errx(ERR_EXIT, "overflow");
53163755Sse	}
5324Srgrimes	free_value (a);
5334Srgrimes	free_value (b);
5344Srgrimes	return (r);
5354Srgrimes}
53663755Sse
53763755Sseint
53892979Swollmanchk_div(intmax_t a, intmax_t b)
53963755Sse{
54063755Sse	/* div by zero has been taken care of before */
54192979Swollman	/* only INTMAX_MIN / -1 causes overflow */
54292979Swollman	if (a == INTMAX_MIN && b == -1)
54363755Sse		return 1;
54463755Sse	/* everything else is OK */
54563755Sse	return 0;
54663755Sse}
54763755Sse
5484Srgrimesstruct val *
54990109Simpop_div(struct val *a, struct val *b)
5504Srgrimes{
5514Srgrimes	struct val *r;
5524Srgrimes
5534Srgrimes	if (!to_integer (a) || !to_integer (b)) {
55492979Swollman		errx(ERR_EXIT, "non-numeric argument");
5554Srgrimes	}
5564Srgrimes
5574Srgrimes	if (b->u.i == 0) {
55892979Swollman		errx(ERR_EXIT, "division by zero");
5594Srgrimes	}
5604Srgrimes
56192979Swollman	r = make_integer (/*(intmax_t)*/(a->u.i / b->u.i));
56277244Skris	if (chk_div (a->u.i, b->u.i)) {
56392979Swollman		errx(ERR_EXIT, "overflow");
56463755Sse	}
5654Srgrimes	free_value (a);
5664Srgrimes	free_value (b);
5674Srgrimes	return r;
5684Srgrimes}
5694Srgrimes
5704Srgrimesstruct val *
57190109Simpop_rem(struct val *a, struct val *b)
5724Srgrimes{
5734Srgrimes	struct val *r;
5744Srgrimes
5754Srgrimes	if (!to_integer (a) || !to_integer (b)) {
57692979Swollman		errx(ERR_EXIT, "non-numeric argument");
5774Srgrimes	}
5784Srgrimes
5794Srgrimes	if (b->u.i == 0) {
58092979Swollman		errx(ERR_EXIT, "division by zero");
5814Srgrimes	}
5824Srgrimes
58392979Swollman	r = make_integer (/*(intmax_t)*/(a->u.i % b->u.i));
58463755Sse	/* chk_rem necessary ??? */
5854Srgrimes	free_value (a);
5864Srgrimes	free_value (b);
5874Srgrimes	return r;
5884Srgrimes}
5894Srgrimes
5904Srgrimesstruct val *
59190109Simpop_colon(struct val *a, struct val *b)
5924Srgrimes{
59331Salm	regex_t rp;
594468Sjtc	regmatch_t rm[2];
59531Salm	char errbuf[256];
59631Salm	int eval;
597181Sconklin	struct val *v;
5984Srgrimes
599181Sconklin	/* coerce to both arguments to strings */
600181Sconklin	to_string(a);
601181Sconklin	to_string(b);
602181Sconklin
60331Salm	/* compile regular expression */
604539Sjtc	if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
60531Salm		regerror (eval, &rp, errbuf, sizeof(errbuf));
60692979Swollman		errx(ERR_EXIT, "%s", errbuf);
6074Srgrimes	}
6084Srgrimes
60931Salm	/* compare string against pattern */
610539Sjtc	/* remember that patterns are anchored to the beginning of the line */
61177244Skris	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
61231Salm		if (rm[1].rm_so >= 0) {
613295Sjtc			*(a->u.s + rm[1].rm_eo) = '\0';
61431Salm			v = make_str (a->u.s + rm[1].rm_so);
61531Salm
6164Srgrimes		} else {
61792979Swollman			v = make_integer ((intmax_t)(rm[0].rm_eo - rm[0].rm_so));
6184Srgrimes		}
6194Srgrimes	} else {
620295Sjtc		if (rp.re_nsub == 0) {
62192979Swollman			v = make_integer ((intmax_t)0);
622295Sjtc		} else {
623295Sjtc			v = make_str ("");
624295Sjtc		}
6254Srgrimes	}
6264Srgrimes
62731Salm	/* free arguments and pattern buffer */
62831Salm	free_value (a);
62931Salm	free_value (b);
63031Salm	regfree (&rp);
63131Salm
63231Salm	return v;
6334Srgrimes}
634