expr.y revision 106065
1280905Sganbold%{
2280905Sganbold/* Written by Pace Willisson (pace@blitz.com)
3280905Sganbold * and placed in the public domain.
4280905Sganbold *
5280905Sganbold * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
6280905Sganbold *
7280905Sganbold * $FreeBSD: head/bin/expr/expr.y 106065 2002-10-28 00:15:43Z wollman $
8280905Sganbold */
9280905Sganbold
10280905Sganbold#include <sys/types.h>
11280905Sganbold
12280905Sganbold#include <ctype.h>
13280905Sganbold#include <err.h>
14280905Sganbold#include <errno.h>
15280905Sganbold#include <inttypes.h>
16280905Sganbold#include <limits.h>
17280905Sganbold#include <locale.h>
18280905Sganbold#include <stdio.h>
19280905Sganbold#include <stdlib.h>
20280905Sganbold#include <string.h>
21280905Sganbold#include <regex.h>
22280905Sganbold#include <unistd.h>
23280905Sganbold
24280905Sganbold/*
25280905Sganbold * POSIX specifies a specific error code for syntax errors.  We exit
26280905Sganbold * with this code for all errors.
27280905Sganbold */
28280905Sganbold#define	ERR_EXIT	2
29280905Sganbold
30280905Sganboldenum valtype {
31280905Sganbold	integer, numeric_string, string
32280905Sganbold} ;
33280905Sganbold
34280905Sganboldstruct val {
35280905Sganbold	enum valtype type;
36280905Sganbold	union {
37280905Sganbold		char *s;
38280905Sganbold		intmax_t i;
39280905Sganbold	} u;
40280905Sganbold} ;
41280905Sganbold
42280905Sganboldstruct val *result;
43280905Sganbold
44280905Sganboldint		chk_div(intmax_t, intmax_t);
45280905Sganboldint		chk_minus(intmax_t, intmax_t, intmax_t);
46280905Sganboldint		chk_plus(intmax_t, intmax_t, intmax_t);
47280905Sganboldint		chk_times(intmax_t, intmax_t, intmax_t);
48280905Sganboldvoid		free_value(struct val *);
49280905Sganboldint		is_zero_or_null(struct val *);
50280905Sganboldint		isstring(struct val *);
51280905Sganboldstruct val	*make_integer(intmax_t);
52280905Sganboldstruct val	*make_str(const char *);
53281092Sandrewstruct val	*op_and(struct val *, struct val *);
54281092Sandrewstruct val	*op_colon(struct val *, struct val *);
55281092Sandrewstruct val	*op_div(struct val *, struct val *);
56280905Sganboldstruct val	*op_eq(struct val *, struct val *);
57280905Sganboldstruct val	*op_ge(struct val *, struct val *);
58280905Sganboldstruct val	*op_gt(struct val *, struct val *);
59280905Sganboldstruct val	*op_le(struct val *, struct val *);
60280905Sganboldstruct val	*op_lt(struct val *, struct val *);
61280905Sganboldstruct val	*op_minus(struct val *, struct val *);
62280905Sganboldstruct val	*op_ne(struct val *, struct val *);
63280905Sganboldstruct val	*op_or(struct val *, struct val *);
64280905Sganboldstruct val	*op_plus(struct val *, struct val *);
65280905Sganboldstruct val	*op_rem(struct val *, struct val *);
66280905Sganboldstruct val	*op_times(struct val *, struct val *);
67280905Sganboldintmax_t	to_integer(struct val *);
68280905Sganboldvoid		to_string(struct val *);
69280905Sganboldint		yyerror(const char *);
70280905Sganboldint		yylex(void);
71280905Sganboldint		yyparse(void);
72280905Sganbold
73280905Sganboldstatic int	eflag;
74280905Sganboldchar **av;
75280905Sganbold%}
76280905Sganbold
77280905Sganbold%union
78280905Sganbold{
79280905Sganbold	struct val *val;
80280905Sganbold}
81280905Sganbold
82280905Sganbold%left <val> '|'
83280905Sganbold%left <val> '&'
84280905Sganbold%left <val> '=' '>' '<' GE LE NE
85280905Sganbold%left <val> '+' '-'
86280905Sganbold%left <val> '*' '/' '%'
87280905Sganbold%left <val> ':'
88280905Sganbold
89280905Sganbold%token <val> TOKEN
90280905Sganbold%type <val> start expr
91280905Sganbold
92280905Sganbold%%
93280905Sganbold
94280905Sganboldstart: expr { result = $$; }
95280905Sganbold
96280905Sganboldexpr:	TOKEN
97280905Sganbold	| '(' expr ')' { $$ = $2; }
98280905Sganbold	| expr '|' expr { $$ = op_or ($1, $3); }
99280905Sganbold	| expr '&' expr { $$ = op_and ($1, $3); }
100280905Sganbold	| expr '=' expr { $$ = op_eq ($1, $3); }
101280905Sganbold	| expr '>' expr { $$ = op_gt ($1, $3); }
102280905Sganbold	| expr '<' expr { $$ = op_lt ($1, $3); }
103280905Sganbold	| expr GE expr  { $$ = op_ge ($1, $3); }
104280905Sganbold	| expr LE expr  { $$ = op_le ($1, $3); }
105280905Sganbold	| expr NE expr  { $$ = op_ne ($1, $3); }
106280905Sganbold	| expr '+' expr { $$ = op_plus ($1, $3); }
107280905Sganbold	| expr '-' expr { $$ = op_minus ($1, $3); }
108280905Sganbold	| expr '*' expr { $$ = op_times ($1, $3); }
109280905Sganbold	| expr '/' expr { $$ = op_div ($1, $3); }
110280905Sganbold	| expr '%' expr { $$ = op_rem ($1, $3); }
111280905Sganbold	| expr ':' expr { $$ = op_colon ($1, $3); }
112280905Sganbold	;
113280905Sganbold
114280905Sganbold
115280905Sganbold%%
116280905Sganbold
117280905Sganboldstruct val *
118280905Sganboldmake_integer(intmax_t i)
119280905Sganbold{
120280905Sganbold	struct val *vp;
121280905Sganbold
122280905Sganbold	vp = (struct val *) malloc (sizeof (*vp));
123280905Sganbold	if (vp == NULL) {
124280905Sganbold		errx(ERR_EXIT, "malloc() failed");
125280905Sganbold	}
126280905Sganbold
127280905Sganbold	vp->type = integer;
128280905Sganbold	vp->u.i  = i;
129280905Sganbold	return vp;
130280905Sganbold}
131280905Sganbold
132280905Sganboldstruct val *
133280905Sganboldmake_str(const char *s)
134280905Sganbold{
135280905Sganbold	struct val *vp;
136280905Sganbold	char *ep;
137280905Sganbold
138280905Sganbold	vp = (struct val *) malloc (sizeof (*vp));
139280905Sganbold	if (vp == NULL || ((vp->u.s = strdup (s)) == NULL)) {
140280905Sganbold		errx(ERR_EXIT, "malloc() failed");
141280905Sganbold	}
142280905Sganbold
143280905Sganbold	/*
144280905Sganbold	 * Previously we tried to scan the string to see if it ``looked like''
145280905Sganbold	 * an integer (erroneously, as it happened).  Let strtoimax() do the
146280905Sganbold	 * dirty work.  We could cache the value, except that we are using
147280905Sganbold	 * a union and need to preserve the original string form until we
148280905Sganbold	 * are certain that it is not needed.
149280905Sganbold	 *
150280905Sganbold	 * IEEE Std.1003.1-2001 says:
151280905Sganbold	 * /integer/ An argument consisting only of an (optional) unary minus
152280905Sganbold	 *	     followed by digits.
153280905Sganbold	 *
154280905Sganbold	 * This means that arguments which consist of digits followed by
155280905Sganbold	 * non-digits MUST NOT be considered integers.  strtoimax() will
156280905Sganbold	 * figure this out for us.
157280905Sganbold	 */
158280905Sganbold	if (eflag)
159280905Sganbold		(void)strtoimax(s, &ep, 10);
160280905Sganbold	else
161280905Sganbold		(void)strtol(s, &ep, 10);
162280905Sganbold
163280905Sganbold	if (*ep != '\0')
164280905Sganbold		vp->type = string;
165280905Sganbold	else
166280905Sganbold		vp->type = numeric_string;
167280905Sganbold
168280905Sganbold	return vp;
169280905Sganbold}
170280905Sganbold
171280905Sganbold
172280905Sganboldvoid
173280905Sganboldfree_value(struct val *vp)
174280905Sganbold{
175280905Sganbold	if (vp->type == string || vp->type == numeric_string)
176280905Sganbold		free (vp->u.s);
177280905Sganbold}
178280905Sganbold
179280905Sganbold
180280905Sganboldintmax_t
181280905Sganboldto_integer(struct val *vp)
182280905Sganbold{
183280905Sganbold	intmax_t i;
184280905Sganbold
185280905Sganbold	if (vp->type == integer)
186280905Sganbold		return 1;
187280905Sganbold
188280905Sganbold	if (vp->type == string)
189280905Sganbold		return 0;
190280905Sganbold
191280905Sganbold	/* vp->type == numeric_string, make it numeric */
192280905Sganbold	errno = 0;
193280905Sganbold	if (eflag) {
194280905Sganbold		i  = strtoimax(vp->u.s, (char **)NULL, 10);
195280905Sganbold		if (errno == ERANGE)
196280905Sganbold			err(ERR_EXIT, NULL);
197280905Sganbold	} else {
198280905Sganbold		i = strtol(vp->u.s, (char **)NULL, 10);
199280905Sganbold	}
200280905Sganbold
201280905Sganbold	free (vp->u.s);
202280905Sganbold	vp->u.i = i;
203280905Sganbold	vp->type = integer;
204280905Sganbold	return 1;
205280905Sganbold}
206280905Sganbold
207280905Sganboldvoid
208280905Sganboldto_string(struct val *vp)
209280905Sganbold{
210280905Sganbold	char *tmp;
211280905Sganbold
212280905Sganbold	if (vp->type == string || vp->type == numeric_string)
213280905Sganbold		return;
214280905Sganbold
215280905Sganbold	/*
216280905Sganbold	 * log_10(x) ~= 0.3 * log_2(x).  Rounding up gives the number
217280905Sganbold	 * of digits; add one each for the sign and terminating null
218280905Sganbold	 * character, respectively.
219280905Sganbold	 */
220280905Sganbold#define	NDIGITS(x) (3 * (sizeof(x) * CHAR_BIT) / 10 + 1 + 1 + 1)
221280905Sganbold	tmp = malloc(NDIGITS(vp->u.i));
222280905Sganbold	if (tmp == NULL)
223280905Sganbold		errx(ERR_EXIT, "malloc() failed");
224280905Sganbold
225280905Sganbold	sprintf(tmp, "%jd", vp->u.i);
226280905Sganbold	vp->type = string;
227280905Sganbold	vp->u.s  = tmp;
228280905Sganbold}
229280905Sganbold
230280905Sganbold
231280905Sganboldint
232280905Sganboldisstring(struct val *vp)
233280905Sganbold{
234280905Sganbold	/* only TRUE if this string is not a valid integer */
235280905Sganbold	return (vp->type == string);
236280905Sganbold}
237280905Sganbold
238280905Sganbold
239280905Sganboldint
240280905Sganboldyylex(void)
241280905Sganbold{
242280905Sganbold	char *p;
243280905Sganbold
244280905Sganbold	if (*av == NULL)
245280905Sganbold		return (0);
246280905Sganbold
247280905Sganbold	p = *av++;
248280905Sganbold
249280905Sganbold	if (strlen (p) == 1) {
250280905Sganbold		if (strchr ("|&=<>+-*/%:()", *p))
251280905Sganbold			return (*p);
252280905Sganbold	} else if (strlen (p) == 2 && p[1] == '=') {
253280905Sganbold		switch (*p) {
254280905Sganbold		case '>': return (GE);
255280905Sganbold		case '<': return (LE);
256280905Sganbold		case '!': return (NE);
257280905Sganbold		}
258280905Sganbold	}
259280905Sganbold
260280905Sganbold	yylval.val = make_str (p);
261280905Sganbold	return (TOKEN);
262280905Sganbold}
263280905Sganbold
264280905Sganboldint
265280905Sganboldis_zero_or_null(struct val *vp)
266280905Sganbold{
267280905Sganbold	if (vp->type == integer) {
268280905Sganbold		return (vp->u.i == 0);
269280905Sganbold	} else {
270280905Sganbold		return (*vp->u.s == 0 || (to_integer (vp) && vp->u.i == 0));
271280905Sganbold	}
272280905Sganbold	/* NOTREACHED */
273280905Sganbold}
274280905Sganbold
275280905Sganboldint
276280905Sganboldmain(int argc, char *argv[])
277280905Sganbold{
278280905Sganbold	int c;
279280905Sganbold
280280905Sganbold	setlocale (LC_ALL, "");
281280905Sganbold	if (getenv("EXPR_COMPAT") != NULL
282280905Sganbold	    || check_utility_compat("expr")) {
283280905Sganbold		av = argv + 1;
284280905Sganbold		eflag = 1;
285280905Sganbold	} else {
286280905Sganbold		while ((c = getopt(argc, argv, "e")) != -1)
287280905Sganbold			switch (c) {
288280905Sganbold			case 'e':
289280905Sganbold				eflag = 1;
290280905Sganbold				break;
291280905Sganbold
292280905Sganbold			default:
293280905Sganbold				fprintf(stderr,
294280905Sganbold				    "usage: expr [-e] expression\n");
295280905Sganbold				exit(ERR_EXIT);
296280905Sganbold			}
297280905Sganbold		av = argv + optind;
298280905Sganbold	}
299280905Sganbold
300280905Sganbold	yyparse();
301280905Sganbold
302280905Sganbold	if (result->type == integer)
303280905Sganbold		printf("%jd\n", result->u.i);
304280905Sganbold	else
305280905Sganbold		printf("%s\n", result->u.s);
306280905Sganbold
307280905Sganbold	return (is_zero_or_null(result));
308280905Sganbold}
309280905Sganbold
310280905Sganboldint
311280905Sganboldyyerror(const char *s __unused)
312280905Sganbold{
313280905Sganbold	errx(ERR_EXIT, "syntax error");
314280905Sganbold}
315280905Sganbold
316280905Sganbold
317280905Sganboldstruct val *
318280905Sganboldop_or(struct val *a, struct val *b)
319280905Sganbold{
320280905Sganbold	if (is_zero_or_null (a)) {
321280905Sganbold		free_value (a);
322280905Sganbold		return (b);
323280905Sganbold	} else {
324280905Sganbold		free_value (b);
325280905Sganbold		return (a);
326280905Sganbold	}
327280905Sganbold}
328280905Sganbold
329280905Sganboldstruct val *
330280905Sganboldop_and(struct val *a, struct val *b)
331280905Sganbold{
332280905Sganbold	if (is_zero_or_null (a) || is_zero_or_null (b)) {
333280905Sganbold		free_value (a);
334280905Sganbold		free_value (b);
335280905Sganbold		return (make_integer ((intmax_t)0));
336280905Sganbold	} else {
337280905Sganbold		free_value (b);
338280905Sganbold		return (a);
339280905Sganbold	}
340280905Sganbold}
341280905Sganbold
342280905Sganboldstruct val *
343280905Sganboldop_eq(struct val *a, struct val *b)
344280905Sganbold{
345280905Sganbold	struct val *r;
346280905Sganbold
347280905Sganbold	if (isstring (a) || isstring (b)) {
348280905Sganbold		to_string (a);
349280905Sganbold		to_string (b);
350280905Sganbold		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) == 0));
351280905Sganbold	} else {
352280905Sganbold		(void)to_integer(a);
353280905Sganbold		(void)to_integer(b);
354280905Sganbold		r = make_integer ((intmax_t)(a->u.i == b->u.i));
355280905Sganbold	}
356280905Sganbold
357280905Sganbold	free_value (a);
358280905Sganbold	free_value (b);
359280905Sganbold	return r;
360280905Sganbold}
361280905Sganbold
362280905Sganboldstruct val *
363280905Sganboldop_gt(struct val *a, struct val *b)
364280905Sganbold{
365280905Sganbold	struct val *r;
366280905Sganbold
367280905Sganbold	if (isstring (a) || isstring (b)) {
368280905Sganbold		to_string (a);
369280905Sganbold		to_string (b);
370280905Sganbold		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) > 0));
371280905Sganbold	} else {
372280905Sganbold		(void)to_integer(a);
373280905Sganbold		(void)to_integer(b);
374280905Sganbold		r = make_integer ((intmax_t)(a->u.i > b->u.i));
375280905Sganbold	}
376280905Sganbold
377280905Sganbold	free_value (a);
378280905Sganbold	free_value (b);
379280905Sganbold	return r;
380280905Sganbold}
381280905Sganbold
382280905Sganboldstruct val *
383280905Sganboldop_lt(struct val *a, struct val *b)
384280905Sganbold{
385280905Sganbold	struct val *r;
386280905Sganbold
387280905Sganbold	if (isstring (a) || isstring (b)) {
388280905Sganbold		to_string (a);
389280905Sganbold		to_string (b);
390280905Sganbold		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) < 0));
391280905Sganbold	} else {
392280905Sganbold		(void)to_integer(a);
393280905Sganbold		(void)to_integer(b);
394280905Sganbold		r = make_integer ((intmax_t)(a->u.i < b->u.i));
395280905Sganbold	}
396280905Sganbold
397280905Sganbold	free_value (a);
398280905Sganbold	free_value (b);
399280905Sganbold	return r;
400280905Sganbold}
401280905Sganbold
402280905Sganboldstruct val *
403280905Sganboldop_ge(struct val *a, struct val *b)
404280905Sganbold{
405280905Sganbold	struct val *r;
406280905Sganbold
407280905Sganbold	if (isstring (a) || isstring (b)) {
408280905Sganbold		to_string (a);
409280905Sganbold		to_string (b);
410280905Sganbold		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) >= 0));
411280905Sganbold	} else {
412280905Sganbold		(void)to_integer(a);
413280905Sganbold		(void)to_integer(b);
414280905Sganbold		r = make_integer ((intmax_t)(a->u.i >= b->u.i));
415280905Sganbold	}
416280905Sganbold
417280905Sganbold	free_value (a);
418280905Sganbold	free_value (b);
419280905Sganbold	return r;
420280905Sganbold}
421280905Sganbold
422280905Sganboldstruct val *
423280905Sganboldop_le(struct val *a, struct val *b)
424280905Sganbold{
425280905Sganbold	struct val *r;
426280905Sganbold
427280905Sganbold	if (isstring (a) || isstring (b)) {
428280905Sganbold		to_string (a);
429280905Sganbold		to_string (b);
430280905Sganbold		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) <= 0));
431280905Sganbold	} else {
432280905Sganbold		(void)to_integer(a);
433280905Sganbold		(void)to_integer(b);
434280905Sganbold		r = make_integer ((intmax_t)(a->u.i <= b->u.i));
435280905Sganbold	}
436280905Sganbold
437280905Sganbold	free_value (a);
438280905Sganbold	free_value (b);
439280905Sganbold	return r;
440280905Sganbold}
441280905Sganbold
442280905Sganboldstruct val *
443280905Sganboldop_ne(struct val *a, struct val *b)
444280905Sganbold{
445280905Sganbold	struct val *r;
446280905Sganbold
447280905Sganbold	if (isstring (a) || isstring (b)) {
448280905Sganbold		to_string (a);
449280905Sganbold		to_string (b);
450280905Sganbold		r = make_integer ((intmax_t)(strcoll (a->u.s, b->u.s) != 0));
451280905Sganbold	} else {
452280905Sganbold		(void)to_integer(a);
453280905Sganbold		(void)to_integer(b);
454280905Sganbold		r = make_integer ((intmax_t)(a->u.i != b->u.i));
455280905Sganbold	}
456280905Sganbold
457280905Sganbold	free_value (a);
458280905Sganbold	free_value (b);
459280905Sganbold	return r;
460280905Sganbold}
461280905Sganbold
462280905Sganboldint
463280905Sganboldchk_plus(intmax_t a, intmax_t b, intmax_t r)
464280905Sganbold{
465280905Sganbold
466280905Sganbold	/* sum of two positive numbers must be positive */
467280905Sganbold	if (a > 0 && b > 0 && r <= 0)
468280905Sganbold		return 1;
469280905Sganbold	/* sum of two negative numbers must be negative */
470280905Sganbold	if (a < 0 && b < 0 && r >= 0)
471280905Sganbold		return 1;
472280905Sganbold	/* all other cases are OK */
473280905Sganbold	return 0;
474280905Sganbold}
475280905Sganbold
476280905Sganboldstruct val *
477280905Sganboldop_plus(struct val *a, struct val *b)
478280905Sganbold{
479280905Sganbold	struct val *r;
480280905Sganbold
481280905Sganbold	if (!to_integer(a) || !to_integer(b)) {
482280905Sganbold		errx(ERR_EXIT, "non-numeric argument");
483280905Sganbold	}
484280905Sganbold
485280905Sganbold	if (eflag) {
486280905Sganbold		r = make_integer(a->u.i + b->u.i);
487280905Sganbold		if (chk_plus(a->u.i, b->u.i, r->u.i)) {
488280905Sganbold			errx(ERR_EXIT, "overflow");
489280905Sganbold		}
490280905Sganbold	} else
491280905Sganbold		r = make_integer((long)a->u.i + (long)b->u.i);
492280905Sganbold
493280905Sganbold	free_value (a);
494280905Sganbold	free_value (b);
495280905Sganbold	return r;
496280905Sganbold}
497280905Sganbold
498280905Sganboldint
499280905Sganboldchk_minus(intmax_t a, intmax_t b, intmax_t r)
500280905Sganbold{
501280905Sganbold
502280905Sganbold	/* special case subtraction of INTMAX_MIN */
503280905Sganbold	if (b == INTMAX_MIN) {
504280905Sganbold		if (a >= 0)
505280905Sganbold			return 1;
506280905Sganbold		else
507280905Sganbold			return 0;
508280905Sganbold	}
509280905Sganbold	/* this is allowed for b != INTMAX_MIN */
510280905Sganbold	return chk_plus (a, -b, r);
511280905Sganbold}
512280905Sganbold
513280905Sganboldstruct val *
514280905Sganboldop_minus(struct val *a, struct val *b)
515280905Sganbold{
516280905Sganbold	struct val *r;
517280905Sganbold
518280905Sganbold	if (!to_integer(a) || !to_integer(b)) {
519280905Sganbold		errx(ERR_EXIT, "non-numeric argument");
520280905Sganbold	}
521280905Sganbold
522280905Sganbold	if (eflag) {
523280905Sganbold		r = make_integer(a->u.i - b->u.i);
524280905Sganbold		if (chk_minus(a->u.i, b->u.i, r->u.i)) {
525280905Sganbold			errx(ERR_EXIT, "overflow");
526280905Sganbold		}
527280905Sganbold	} else
528280905Sganbold		r = make_integer((long)a->u.i - (long)b->u.i);
529280905Sganbold
530280905Sganbold	free_value (a);
531280905Sganbold	free_value (b);
532280905Sganbold	return r;
533280905Sganbold}
534280905Sganbold
535280905Sganboldint
536280905Sganboldchk_times(intmax_t a, intmax_t b, intmax_t r)
537280905Sganbold{
538280905Sganbold	/* special case: first operand is 0, no overflow possible */
539280905Sganbold	if (a == 0)
540280905Sganbold		return 0;
541280905Sganbold	/* cerify that result of division matches second operand */
542280905Sganbold	if (r / a != b)
543280905Sganbold		return 1;
544280905Sganbold	return 0;
545280905Sganbold}
546280905Sganbold
547280905Sganboldstruct val *
548280905Sganboldop_times(struct val *a, struct val *b)
549280905Sganbold{
550280905Sganbold	struct val *r;
551280905Sganbold
552280905Sganbold	if (!to_integer(a) || !to_integer(b)) {
553280905Sganbold		errx(ERR_EXIT, "non-numeric argument");
554280905Sganbold	}
555280905Sganbold
556280905Sganbold	if (eflag) {
557280905Sganbold		r = make_integer(a->u.i * b->u.i);
558280905Sganbold		if (chk_times(a->u.i, b->u.i, r->u.i)) {
559280905Sganbold			errx(ERR_EXIT, "overflow");
560280905Sganbold		}
561280905Sganbold	} else
562280905Sganbold		r = make_integer((long)a->u.i * (long)b->u.i);
563280905Sganbold
564280905Sganbold	free_value (a);
565280905Sganbold	free_value (b);
566280905Sganbold	return (r);
567280905Sganbold}
568280905Sganbold
569280905Sganboldint
570280905Sganboldchk_div(intmax_t a, intmax_t b)
571280905Sganbold{
572280905Sganbold	/* div by zero has been taken care of before */
573280905Sganbold	/* only INTMAX_MIN / -1 causes overflow */
574280905Sganbold	if (a == INTMAX_MIN && b == -1)
575280905Sganbold		return 1;
576280905Sganbold	/* everything else is OK */
577280905Sganbold	return 0;
578280905Sganbold}
579280905Sganbold
580280905Sganboldstruct val *
581280905Sganboldop_div(struct val *a, struct val *b)
582280905Sganbold{
583280905Sganbold	struct val *r;
584280905Sganbold
585280905Sganbold	if (!to_integer(a) || !to_integer(b)) {
586280905Sganbold		errx(ERR_EXIT, "non-numeric argument");
587280905Sganbold	}
588280905Sganbold
589280905Sganbold	if (b->u.i == 0) {
590280905Sganbold		errx(ERR_EXIT, "division by zero");
591280905Sganbold	}
592280905Sganbold
593280905Sganbold	if (eflag) {
594280905Sganbold		r = make_integer(a->u.i / b->u.i);
595280905Sganbold		if (chk_div(a->u.i, b->u.i)) {
596280905Sganbold			errx(ERR_EXIT, "overflow");
597280905Sganbold		}
598280905Sganbold	} else
599280905Sganbold		r = make_integer((long)a->u.i / (long)b->u.i);
600280905Sganbold
601280905Sganbold	free_value (a);
602280905Sganbold	free_value (b);
603280905Sganbold	return r;
604280905Sganbold}
605280905Sganbold
606280905Sganboldstruct val *
607280905Sganboldop_rem(struct val *a, struct val *b)
608280905Sganbold{
609280905Sganbold	struct val *r;
610280905Sganbold
611280905Sganbold	if (!to_integer(a) || !to_integer(b)) {
612280905Sganbold		errx(ERR_EXIT, "non-numeric argument");
613280905Sganbold	}
614280905Sganbold
615280905Sganbold	if (b->u.i == 0) {
616280905Sganbold		errx(ERR_EXIT, "division by zero");
617280905Sganbold	}
618280905Sganbold
619280905Sganbold	if (eflag)
620280905Sganbold		r = make_integer(a->u.i % b->u.i);
621280905Sganbold	        /* chk_rem necessary ??? */
622280905Sganbold	else
623280905Sganbold		r = make_integer((long)a->u.i % (long)b->u.i);
624280905Sganbold
625280905Sganbold	free_value (a);
626280905Sganbold	free_value (b);
627280905Sganbold	return r;
628280905Sganbold}
629280905Sganbold
630280905Sganboldstruct val *
631280905Sganboldop_colon(struct val *a, struct val *b)
632280905Sganbold{
633280905Sganbold	regex_t rp;
634280905Sganbold	regmatch_t rm[2];
635280905Sganbold	char errbuf[256];
636280905Sganbold	int eval;
637280905Sganbold	struct val *v;
638280905Sganbold
639280905Sganbold	/* coerce to both arguments to strings */
640280905Sganbold	to_string(a);
641280905Sganbold	to_string(b);
642280905Sganbold
643280905Sganbold	/* compile regular expression */
644280905Sganbold	if ((eval = regcomp (&rp, b->u.s, 0)) != 0) {
645280905Sganbold		regerror (eval, &rp, errbuf, sizeof(errbuf));
646280905Sganbold		errx(ERR_EXIT, "%s", errbuf);
647280905Sganbold	}
648280905Sganbold
649280905Sganbold	/* compare string against pattern */
650280905Sganbold	/* remember that patterns are anchored to the beginning of the line */
651280905Sganbold	if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0) {
652280905Sganbold		if (rm[1].rm_so >= 0) {
653280905Sganbold			*(a->u.s + rm[1].rm_eo) = '\0';
654280905Sganbold			v = make_str (a->u.s + rm[1].rm_so);
655280905Sganbold
656280905Sganbold		} else {
657280905Sganbold			v = make_integer ((intmax_t)(rm[0].rm_eo - rm[0].rm_so));
658280905Sganbold		}
659280905Sganbold	} else {
660280905Sganbold		if (rp.re_nsub == 0) {
661			v = make_integer ((intmax_t)0);
662		} else {
663			v = make_str ("");
664		}
665	}
666
667	/* free arguments and pattern buffer */
668	free_value (a);
669	free_value (b);
670	regfree (&rp);
671
672	return v;
673}
674