xref: /illumos-gate/usr/src/cmd/awk_xpg4/awk4.c (revision 55fea89d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * awk -- functions
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * Copyright (c) 1995, 1996 by Sun Microsystems, Inc.
267c478bd9Sstevel@tonic-gate  * All rights reserved.
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * Copyright 1986, 1994 by Mortice Kern Systems Inc.  All rights reserved.
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes
317c478bd9Sstevel@tonic-gate  */
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include "awk.h"
347c478bd9Sstevel@tonic-gate #include "y.tab.h"
357c478bd9Sstevel@tonic-gate #include <time.h>
367c478bd9Sstevel@tonic-gate #include <sys/wait.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static uint	nargs(NODE *np);
397c478bd9Sstevel@tonic-gate static NODE	*dosub(NODE *np, int glob);
407c478bd9Sstevel@tonic-gate static NODE	*docasetr(NODE *np, int upper);
417c478bd9Sstevel@tonic-gate static int	asortcmp(const void *npp1, const void *npp2);
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate static char	nargerr[] = "wrong number of arguments to function \"%s\"";
447c478bd9Sstevel@tonic-gate static NODE	*asortfunc;		/* Function call for asort() */
457c478bd9Sstevel@tonic-gate static NODE	*asnp1, *asnp2;		/* index1, index2 nodes */
467c478bd9Sstevel@tonic-gate static int	asarraylen;		/* strlen(array)+1 for asort */
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate /*
497c478bd9Sstevel@tonic-gate  * Return the value of exp(x).
507c478bd9Sstevel@tonic-gate  * Usage:	y = exp(x)
517c478bd9Sstevel@tonic-gate  *		y = exp()
527c478bd9Sstevel@tonic-gate  */
537c478bd9Sstevel@tonic-gate NODE *
f_exp(NODE * np)547c478bd9Sstevel@tonic-gate f_exp(NODE *np)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	register uint na;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
597c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_exp);
607c478bd9Sstevel@tonic-gate 	return (realnode(exp(exprreal(na==0 ? field0 : getlist(&np)))));
617c478bd9Sstevel@tonic-gate }
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * Return the integer part of the argument.
657c478bd9Sstevel@tonic-gate  * Usage:	i = int(r)
667c478bd9Sstevel@tonic-gate  *		i = int()
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate NODE *
f_int(NODE * np)697c478bd9Sstevel@tonic-gate f_int(NODE *np)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	register uint na;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
747c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_int);
757c478bd9Sstevel@tonic-gate 	return (intnode(exprint(na==0 ? field0 : getlist(&np))));
767c478bd9Sstevel@tonic-gate }
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * Logarithm function.
807c478bd9Sstevel@tonic-gate  * Usage:	y = log(x)
817c478bd9Sstevel@tonic-gate  *		y = log()
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate NODE *
f_log(NODE * np)847c478bd9Sstevel@tonic-gate f_log(NODE *np)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	register uint na;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
897c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_log);
907c478bd9Sstevel@tonic-gate 	return (realnode(log(exprreal(na==0 ? field0 : getlist(&np)))));
917c478bd9Sstevel@tonic-gate }
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Square root function.
957c478bd9Sstevel@tonic-gate  * Usage:	y = sqrt(x)
967c478bd9Sstevel@tonic-gate  *		y = sqrt()
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate NODE *
f_sqrt(NODE * np)997c478bd9Sstevel@tonic-gate f_sqrt(NODE *np)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	register uint na;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
1047c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_sqrt);
1057c478bd9Sstevel@tonic-gate 	return (realnode(sqrt(exprreal(na==0 ? field0 : getlist(&np)))));
1067c478bd9Sstevel@tonic-gate }
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * Trigonometric sine function.
1107c478bd9Sstevel@tonic-gate  * Usage:	y = sin(x)
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate NODE *
f_sin(NODE * np)1137c478bd9Sstevel@tonic-gate f_sin(NODE *np)
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
1167c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_sin);
1177c478bd9Sstevel@tonic-gate 	return (realnode(sin(exprreal(getlist(&np)))));
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /*
1217c478bd9Sstevel@tonic-gate  * Trigonometric cosine function.
1227c478bd9Sstevel@tonic-gate  * Usage:	y = cos(x)
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate NODE *
f_cos(NODE * np)1257c478bd9Sstevel@tonic-gate f_cos(NODE *np)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
1287c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_cos);
1297c478bd9Sstevel@tonic-gate 	return (realnode(cos(exprreal(getlist(&np)))));
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * Arctangent of y/x.
1347c478bd9Sstevel@tonic-gate  * Usage:	z = atan2(y, x)
1357c478bd9Sstevel@tonic-gate  */
1367c478bd9Sstevel@tonic-gate NODE *
f_atan2(NODE * np)1377c478bd9Sstevel@tonic-gate f_atan2(NODE *np)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate 	double y, x;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
1427c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_atan2);
1437c478bd9Sstevel@tonic-gate 	y = (double)exprreal(getlist(&np));
1447c478bd9Sstevel@tonic-gate 	x = (double)exprreal(getlist(&np));
1457c478bd9Sstevel@tonic-gate 	return (realnode(atan2(y, x)));
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * Set the seed for the random number generator function -- rand.
1507c478bd9Sstevel@tonic-gate  * Usage:	srand(x)
1517c478bd9Sstevel@tonic-gate  *		srand()
1527c478bd9Sstevel@tonic-gate  */
1537c478bd9Sstevel@tonic-gate NODE *
f_srand(NODE * np)1547c478bd9Sstevel@tonic-gate f_srand(NODE *np)
1557c478bd9Sstevel@tonic-gate {
1567c478bd9Sstevel@tonic-gate 	register uint na;
1577c478bd9Sstevel@tonic-gate 	register uint seed;
1587c478bd9Sstevel@tonic-gate 	static uint oldseed = 0;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
1617c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_srand);
1627c478bd9Sstevel@tonic-gate 	if (na == 0)
1637c478bd9Sstevel@tonic-gate 		seed = (uint)time((time_t *)0); else
1647c478bd9Sstevel@tonic-gate 		seed = (uint)exprint(getlist(&np));
1657c478bd9Sstevel@tonic-gate 	srand(seed);
1667c478bd9Sstevel@tonic-gate 	na = oldseed;
1677c478bd9Sstevel@tonic-gate 	oldseed = seed;
1687c478bd9Sstevel@tonic-gate 	return (intnode((INT)na));
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate /*
1727c478bd9Sstevel@tonic-gate  * Generate a random number.
1737c478bd9Sstevel@tonic-gate  * Usage:	x = rand()
1747c478bd9Sstevel@tonic-gate  */
1757c478bd9Sstevel@tonic-gate NODE *
f_rand(NODE * np)1767c478bd9Sstevel@tonic-gate f_rand(NODE *np)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	double result;
1797c478bd9Sstevel@tonic-gate 	int expon;
1807c478bd9Sstevel@tonic-gate 	ushort rint;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	if (nargs(np) != 0)
1837c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_rand);
1847c478bd9Sstevel@tonic-gate 	rint = rand() & SHRT_MAX;
1857c478bd9Sstevel@tonic-gate 	result = frexp((double)rint, &expon);
1867c478bd9Sstevel@tonic-gate 	return (realnode((REAL)ldexp(result, expon-15)));
1877c478bd9Sstevel@tonic-gate }
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * Substitute function.
1917c478bd9Sstevel@tonic-gate  * Usage:	n = sub(regex, replace, target)
1927c478bd9Sstevel@tonic-gate  *		n = sub(regex, replace)
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate NODE *
f_sub(NODE * np)1957c478bd9Sstevel@tonic-gate f_sub(NODE *np)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	return (dosub(np, 1));
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Global substitution function.
2027c478bd9Sstevel@tonic-gate  * Usage:	n = gsub(regex, replace, target)
2037c478bd9Sstevel@tonic-gate  *		n = gsub(regex, replace)
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate NODE *
f_gsub(NODE * np)2067c478bd9Sstevel@tonic-gate f_gsub(NODE *np)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	return (dosub(np, 0));
2097c478bd9Sstevel@tonic-gate }
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate /*
2127c478bd9Sstevel@tonic-gate  * Do actual substitutions.
2137c478bd9Sstevel@tonic-gate  * `glob' is the number to substitute, 0 for all.
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate static NODE *
dosub(NODE * np,int glob)2167c478bd9Sstevel@tonic-gate dosub(NODE *np, int glob)
2177c478bd9Sstevel@tonic-gate {
2187c478bd9Sstevel@tonic-gate 	wchar_t *text;
2197c478bd9Sstevel@tonic-gate 	register wchar_t *sub;
2207c478bd9Sstevel@tonic-gate 	register uint n;
2217c478bd9Sstevel@tonic-gate 	register uint na;
2227c478bd9Sstevel@tonic-gate 	register REGEXP rp;
2237c478bd9Sstevel@tonic-gate 	NODE *left;
2247c478bd9Sstevel@tonic-gate 	static wchar_t *buf;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) != 2 && na != 3)
2277c478bd9Sstevel@tonic-gate 		awkerr(nargerr, glob==0 ? s_gsub : s_sub);
2287c478bd9Sstevel@tonic-gate 	rp = getregexp(getlist(&np));
2297c478bd9Sstevel@tonic-gate 	sub = exprstring(getlist(&np));
2307c478bd9Sstevel@tonic-gate 	if (na == 3) {
2317c478bd9Sstevel@tonic-gate 		left = getlist(&np);
2327c478bd9Sstevel@tonic-gate 		text = exprstring(left);
2337c478bd9Sstevel@tonic-gate 	} else {
2347c478bd9Sstevel@tonic-gate 		left = field0;
2357c478bd9Sstevel@tonic-gate 		text = linebuf;
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 	switch (REGWDOSUBA(rp, sub, text, &buf, 256, &glob)) {
2387c478bd9Sstevel@tonic-gate 	case REG_OK:
2397c478bd9Sstevel@tonic-gate 	case REG_NOMATCH:
2407c478bd9Sstevel@tonic-gate 		n = glob;
2417c478bd9Sstevel@tonic-gate 		break;
2427c478bd9Sstevel@tonic-gate 	case REG_ESPACE:
2437c478bd9Sstevel@tonic-gate 		if (buf != NULL)
2447c478bd9Sstevel@tonic-gate 			free(buf);
2457c478bd9Sstevel@tonic-gate 		awkerr(nomem);
2467c478bd9Sstevel@tonic-gate 	default:
2477c478bd9Sstevel@tonic-gate 		awkerr(gettext("regular expression error"));
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 	(void)assign(left, stringnode(buf, FNOALLOC, wcslen(buf)));
2507c478bd9Sstevel@tonic-gate 	return (intnode((INT)n));
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * Match function.  Return position (origin 1) or 0 for regular
2557c478bd9Sstevel@tonic-gate  * expression match in string.  Set new variables RSTART and RLENGTH
2567c478bd9Sstevel@tonic-gate  * as well.
2577c478bd9Sstevel@tonic-gate  * Usage:	pos = match(string, re)
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate NODE *
f_match(NODE * np)2607c478bd9Sstevel@tonic-gate f_match(NODE *np)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	register wchar_t *text;
2637c478bd9Sstevel@tonic-gate 	register REGEXP rp;
2647c478bd9Sstevel@tonic-gate 	register int pos, length;
2657c478bd9Sstevel@tonic-gate 	REGWMATCH_T match[10];
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
2687c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_match);
2697c478bd9Sstevel@tonic-gate 	text = exprstring(getlist(&np));
2707c478bd9Sstevel@tonic-gate 	rp = getregexp(getlist(&np));
2717c478bd9Sstevel@tonic-gate 	if (REGWEXEC(rp, text, 10, match, 0) == REG_OK) {
2727c478bd9Sstevel@tonic-gate 		pos = match[0].rm_sp-text+1;
2737c478bd9Sstevel@tonic-gate 		length = match[0].rm_ep - match[0].rm_sp;
2747c478bd9Sstevel@tonic-gate 	} else {
2757c478bd9Sstevel@tonic-gate 		pos = 0;
2767c478bd9Sstevel@tonic-gate 		length = -1;
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 	constant->n_int = length;
2797c478bd9Sstevel@tonic-gate 	(void)assign(vlook(M_MB_L("RLENGTH")), constant);
2807c478bd9Sstevel@tonic-gate 	return (assign(vlook(M_MB_L("RSTART")), intnode((INT)pos)));
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate /*
2847c478bd9Sstevel@tonic-gate  * Call shell or command interpreter.
2857c478bd9Sstevel@tonic-gate  * Usage:	status = system(command)
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate NODE *
f_system(NODE * np)2887c478bd9Sstevel@tonic-gate f_system(NODE *np)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	int retcode;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
2937c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_system);
2947c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
2957c478bd9Sstevel@tonic-gate 	retcode = system(mbunconvert(exprstring(getlist(&np))));
2967c478bd9Sstevel@tonic-gate 	return (intnode((INT)WEXITSTATUS(retcode)));
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * Search for string within string.
3017c478bd9Sstevel@tonic-gate  * Usage:	pos = index(string1, string2)
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate NODE *
f_index(NODE * np)3047c478bd9Sstevel@tonic-gate f_index(NODE *np)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	register wchar_t *s1, *s2;
3077c478bd9Sstevel@tonic-gate 	register int l1, l2;
3087c478bd9Sstevel@tonic-gate 	register int result;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
3117c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_index);
3127c478bd9Sstevel@tonic-gate 	s1 = (wchar_t *)exprstring(getlist(&np));
3137c478bd9Sstevel@tonic-gate 	s2 = (wchar_t *)exprstring(getlist(&np));
3147c478bd9Sstevel@tonic-gate 	l1 = wcslen(s1);
3157c478bd9Sstevel@tonic-gate 	l2 = wcslen(s2);
3167c478bd9Sstevel@tonic-gate 	result = 1;
3177c478bd9Sstevel@tonic-gate 	while (l2 <= l1) {
3187c478bd9Sstevel@tonic-gate 		if (memcmp(s1, s2, l2 * sizeof(wchar_t)) == 0)
3197c478bd9Sstevel@tonic-gate 			break;
3207c478bd9Sstevel@tonic-gate 		result++;
3217c478bd9Sstevel@tonic-gate 		s1++;
3227c478bd9Sstevel@tonic-gate 		l1--;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	if (l2 > l1)
3257c478bd9Sstevel@tonic-gate 		result = 0;
3267c478bd9Sstevel@tonic-gate 	return (intnode((INT)result));
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * Return length of argument or $0
3317c478bd9Sstevel@tonic-gate  * Usage:	n = length(string)
3327c478bd9Sstevel@tonic-gate  *		n = length()
3337c478bd9Sstevel@tonic-gate  *		n = length
3347c478bd9Sstevel@tonic-gate  */
3357c478bd9Sstevel@tonic-gate NODE *
f_length(NODE * np)3367c478bd9Sstevel@tonic-gate f_length(NODE *np)
3377c478bd9Sstevel@tonic-gate {
3387c478bd9Sstevel@tonic-gate 	register uint na;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
3417c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_length);
3427c478bd9Sstevel@tonic-gate 	if (na == 0)
3437c478bd9Sstevel@tonic-gate 		na = lbuflen; else
3447c478bd9Sstevel@tonic-gate 		na = wcslen((wchar_t *)exprstring(getlist(&np)));
3457c478bd9Sstevel@tonic-gate 	return (intnode((INT)na));
3467c478bd9Sstevel@tonic-gate }
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate /*
3497c478bd9Sstevel@tonic-gate  * Split string into fields.
3507c478bd9Sstevel@tonic-gate  * Usage: nfields = split(string, array [, separator]);
3517c478bd9Sstevel@tonic-gate  */
3527c478bd9Sstevel@tonic-gate NODE *
f_split(NODE * np)3537c478bd9Sstevel@tonic-gate f_split(NODE *np)
3547c478bd9Sstevel@tonic-gate {
3557c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
3567c478bd9Sstevel@tonic-gate 	wchar_t *ep, *saved = 0;
3577c478bd9Sstevel@tonic-gate 	register NODE *tnp, *snp, *otnp;
3587c478bd9Sstevel@tonic-gate 	register NODE *sep;
3597c478bd9Sstevel@tonic-gate 	REGEXP old_resep = 0;
3607c478bd9Sstevel@tonic-gate 	size_t seplen;
3617c478bd9Sstevel@tonic-gate 	uint n;
3627c478bd9Sstevel@tonic-gate 	wint_t c;
3637c478bd9Sstevel@tonic-gate 	wchar_t savesep[20];
3647c478bd9Sstevel@tonic-gate 	wchar_t  *(*old_awkfield)(wchar_t **) = 0;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	if ((n = nargs(np))<2 || n>3)
3677c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_split);
3687c478bd9Sstevel@tonic-gate 	ep = exprstring(snp = getlist(&np));
3697c478bd9Sstevel@tonic-gate 	tnp = getlist(&np);
3707c478bd9Sstevel@tonic-gate 	if (snp->n_type == INDEX && snp->n_left == tnp)
3717c478bd9Sstevel@tonic-gate 		ep = saved = wsdup(ep);
3727c478bd9Sstevel@tonic-gate 	if (n == 3) {
3737c478bd9Sstevel@tonic-gate 		sep = getlist(&np);
3747c478bd9Sstevel@tonic-gate 	} else
3757c478bd9Sstevel@tonic-gate 		sep = NNULL;
3767c478bd9Sstevel@tonic-gate 	switch (tnp->n_type) {
3777c478bd9Sstevel@tonic-gate 	case ARRAY:
3787c478bd9Sstevel@tonic-gate 		delarray(tnp);
3797c478bd9Sstevel@tonic-gate 		break;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	case PARM:
3827c478bd9Sstevel@tonic-gate 		break;
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	case VAR:
3857c478bd9Sstevel@tonic-gate 		if (isstring(tnp->n_flags) && tnp->n_string==_null)
3867c478bd9Sstevel@tonic-gate 			break;
387b2be350eSToomas Soome 		/* FALLTHROUGH */
388b2be350eSToomas Soome 
3897c478bd9Sstevel@tonic-gate 	default:
3907c478bd9Sstevel@tonic-gate 		awkerr(gettext(
3917c478bd9Sstevel@tonic-gate 			"second parameter to \"split\" must be an array"));
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate 	/*
3947c478bd9Sstevel@tonic-gate 	 * If an argument has been passed in to be used as the
3957c478bd9Sstevel@tonic-gate 	 * field separator check to see if it is a constant regular
3967c478bd9Sstevel@tonic-gate 	 * expression. If so, use it directly otherwise reduce the
3977c478bd9Sstevel@tonic-gate 	 * expression, convert the result into a string and assign it
3987c478bd9Sstevel@tonic-gate 	 * to "FS" (after saving the old value for FS.)
3997c478bd9Sstevel@tonic-gate 	 */
4007c478bd9Sstevel@tonic-gate 	if (sep != NNULL) {
4017c478bd9Sstevel@tonic-gate 		if (sep->n_type == PARM)
4027c478bd9Sstevel@tonic-gate 			sep = sep->n_next;
4037c478bd9Sstevel@tonic-gate 		if (sep->n_type == RE) {
4047c478bd9Sstevel@tonic-gate 			old_resep = resep;
4057c478bd9Sstevel@tonic-gate 			resep = sep->n_regexp;
4067c478bd9Sstevel@tonic-gate 			old_awkfield = awkfield;
4077c478bd9Sstevel@tonic-gate 			awkfield = refield;
4087c478bd9Sstevel@tonic-gate 		} else {
4097c478bd9Sstevel@tonic-gate 			sep = exprreduce(sep);
4107c478bd9Sstevel@tonic-gate 			seplen = wcslen(cp = (wchar_t *)exprstring(varFS));
411*55fea89dSDan Cross 			(void) memcpy(savesep, cp,
4127c478bd9Sstevel@tonic-gate 				(seplen+1) * sizeof(wchar_t));
4137c478bd9Sstevel@tonic-gate 			(void) assign(varFS, sep);
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * Iterate over the record, extracting each field and assigning it to
4187c478bd9Sstevel@tonic-gate 	 * the corresponding element in the array.
4197c478bd9Sstevel@tonic-gate 	 */
4207c478bd9Sstevel@tonic-gate 	otnp = tnp;	/* save tnp for possible promotion */
4217c478bd9Sstevel@tonic-gate 	tnp = node(INDEX, tnp, constant);
4227c478bd9Sstevel@tonic-gate 	fcount = 0;
4237c478bd9Sstevel@tonic-gate 	for (;;) {
4247c478bd9Sstevel@tonic-gate 		if ((cp = (*awkfield)(&ep)) == NULL) {
4257c478bd9Sstevel@tonic-gate 			if (fcount == 0) {
4267c478bd9Sstevel@tonic-gate 				if (otnp->n_type == PARM)
4277c478bd9Sstevel@tonic-gate 					otnp = otnp->n_next;
4287c478bd9Sstevel@tonic-gate 				promote(otnp);
4297c478bd9Sstevel@tonic-gate 			}
4307c478bd9Sstevel@tonic-gate 			break;
4317c478bd9Sstevel@tonic-gate 		}
4327c478bd9Sstevel@tonic-gate 		c = *ep;
4337c478bd9Sstevel@tonic-gate 		*ep = '\0';
4347c478bd9Sstevel@tonic-gate 		constant->n_int = ++fcount;
4357c478bd9Sstevel@tonic-gate 		(void)assign(tnp, stringnode(cp,FALLOC|FSENSE,(size_t)(ep-cp)));
4367c478bd9Sstevel@tonic-gate 		*ep = c;
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 	/*
4397c478bd9Sstevel@tonic-gate 	 * Restore the old record separator/and or regular expression.
4407c478bd9Sstevel@tonic-gate 	 */
4417c478bd9Sstevel@tonic-gate 	if (sep != NNULL) {
4427c478bd9Sstevel@tonic-gate 		if (old_awkfield != 0) {
4437c478bd9Sstevel@tonic-gate 			resep = old_resep;
4447c478bd9Sstevel@tonic-gate 			awkfield = old_awkfield;
4457c478bd9Sstevel@tonic-gate 		} else {
4467c478bd9Sstevel@tonic-gate 			(void)assign(varFS,
4477c478bd9Sstevel@tonic-gate 				stringnode(savesep, FSTATIC, seplen));
4487c478bd9Sstevel@tonic-gate 		}
4497c478bd9Sstevel@tonic-gate 	}
4507c478bd9Sstevel@tonic-gate 	if (saved)
4517c478bd9Sstevel@tonic-gate 		free(saved);
4527c478bd9Sstevel@tonic-gate 	return (intnode((INT)fcount));
4537c478bd9Sstevel@tonic-gate }
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate  * Sprintf function.
4577c478bd9Sstevel@tonic-gate  * Usage:	string = sprintf(format, arg, ...)
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate NODE *
f_sprintf(NODE * np)4607c478bd9Sstevel@tonic-gate f_sprintf(NODE *np)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate         wchar_t *cp;
4637c478bd9Sstevel@tonic-gate         size_t length;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate         if (nargs(np) == 0)
4667c478bd9Sstevel@tonic-gate                 awkerr(nargerr, s_sprintf);
4677c478bd9Sstevel@tonic-gate         length = xprintf(np, (FILE *)NULL, &cp);
4687c478bd9Sstevel@tonic-gate         np = stringnode(cp, FNOALLOC, length);
4697c478bd9Sstevel@tonic-gate         return (np);
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate /*
4737c478bd9Sstevel@tonic-gate  * Substring.
4747c478bd9Sstevel@tonic-gate  * newstring = substr(string, start, [length])
4757c478bd9Sstevel@tonic-gate  */
4767c478bd9Sstevel@tonic-gate NODE *
f_substr(NODE * np)4777c478bd9Sstevel@tonic-gate f_substr(NODE *np)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate 	register STRING str;
4807c478bd9Sstevel@tonic-gate 	register size_t n;
4817c478bd9Sstevel@tonic-gate 	register int start;
4827c478bd9Sstevel@tonic-gate 	register size_t len;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if ((n = nargs(np))<2 || n>3)
4857c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_substr);
4867c478bd9Sstevel@tonic-gate 	str = exprstring(getlist(&np));
4877c478bd9Sstevel@tonic-gate 	if ((start = (int)exprint(getlist(&np))-1) < 0)
4887c478bd9Sstevel@tonic-gate 		start = 0;
4897c478bd9Sstevel@tonic-gate 	if (n == 3) {
4907c478bd9Sstevel@tonic-gate 		int x;
4917c478bd9Sstevel@tonic-gate 		x = (int)exprint(getlist(&np));
4927c478bd9Sstevel@tonic-gate 		if (x < 0)
4937c478bd9Sstevel@tonic-gate 			len = 0;
4947c478bd9Sstevel@tonic-gate 		else
4957c478bd9Sstevel@tonic-gate 			len = (size_t)x;
4967c478bd9Sstevel@tonic-gate 	} else
4977c478bd9Sstevel@tonic-gate 		len = LARGE;
4987c478bd9Sstevel@tonic-gate 	n = wcslen((wchar_t *)str);
4997c478bd9Sstevel@tonic-gate 	if (start > n)
5007c478bd9Sstevel@tonic-gate 		start = n;
5017c478bd9Sstevel@tonic-gate 	n -= start;
5027c478bd9Sstevel@tonic-gate 	if (len > n)
5037c478bd9Sstevel@tonic-gate 		len = n;
5047c478bd9Sstevel@tonic-gate 	str += start;
5057c478bd9Sstevel@tonic-gate 	n = str[len];
5067c478bd9Sstevel@tonic-gate 	str[len] = '\0';
5077c478bd9Sstevel@tonic-gate 	np = stringnode(str, FALLOC, len);
5087c478bd9Sstevel@tonic-gate 	str[len] = n;
5097c478bd9Sstevel@tonic-gate 	return (np);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate  * Close an output or input file stream.
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate NODE *
f_close(NODE * np)5167c478bd9Sstevel@tonic-gate f_close(NODE *np)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	register OFILE *op;
5197c478bd9Sstevel@tonic-gate 	register char *name;
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
5227c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_close);
5237c478bd9Sstevel@tonic-gate 	name = mbunconvert(exprstring(getlist(&np)));
5247c478bd9Sstevel@tonic-gate 	for (op = &ofiles[0]; op < &ofiles[NIOSTREAM]; op++)
5257c478bd9Sstevel@tonic-gate 		if (op->f_fp!=FNULL && strcmp(name, op->f_name)==0) {
5267c478bd9Sstevel@tonic-gate 			awkclose(op);
5277c478bd9Sstevel@tonic-gate 			break;
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 	if (op >= &ofiles[NIOSTREAM])
5307c478bd9Sstevel@tonic-gate 		return (const1);
5317c478bd9Sstevel@tonic-gate 	return (const0);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate /*
5357c478bd9Sstevel@tonic-gate  * Return the integer value of the first character of a string.
5367c478bd9Sstevel@tonic-gate  * Usage:	char = ord(string)
5377c478bd9Sstevel@tonic-gate  */
5387c478bd9Sstevel@tonic-gate NODE *
f_ord(NODE * np)5397c478bd9Sstevel@tonic-gate f_ord(NODE *np)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
5427c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_ord);
5437c478bd9Sstevel@tonic-gate 	return (intnode((INT)*exprstring(getlist(&np))));
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate /*
5477c478bd9Sstevel@tonic-gate  * Return the argument string in lower case:
5487c478bd9Sstevel@tonic-gate  * Usage:
5497c478bd9Sstevel@tonic-gate  *	lower = tolower(upper)
5507c478bd9Sstevel@tonic-gate  */
5517c478bd9Sstevel@tonic-gate NODE *
f_tolower(NODE * np)5527c478bd9Sstevel@tonic-gate f_tolower(NODE *np)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	return (docasetr(np, 0));
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate  * Return the argument string in upper case:
5597c478bd9Sstevel@tonic-gate  * Usage:
5607c478bd9Sstevel@tonic-gate  *	upper = toupper(lower)
5617c478bd9Sstevel@tonic-gate  */
5627c478bd9Sstevel@tonic-gate NODE *
f_toupper(NODE * np)5637c478bd9Sstevel@tonic-gate f_toupper(NODE *np)
5647c478bd9Sstevel@tonic-gate {
5657c478bd9Sstevel@tonic-gate 	return (docasetr(np, 1));
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate /*
5697c478bd9Sstevel@tonic-gate  * Sort the array into traversal order by the next "for (i in array)" loop.
5707c478bd9Sstevel@tonic-gate  * Usage:
5717c478bd9Sstevel@tonic-gate  *	asort(array, "cmpfunc")
5727c478bd9Sstevel@tonic-gate  * 	cmpfunc(array, index1, index2)
5737c478bd9Sstevel@tonic-gate  *		returns:
5747c478bd9Sstevel@tonic-gate  *		<0		if 	array[index1] <  array[index2]
5757c478bd9Sstevel@tonic-gate  *		 0		if	array[index1] == array[index2]
5767c478bd9Sstevel@tonic-gate  *		>0		if	array[index1] >  array[index2]
5777c478bd9Sstevel@tonic-gate  */
5787c478bd9Sstevel@tonic-gate NODE *
f_asort(NODE * np)5797c478bd9Sstevel@tonic-gate f_asort(NODE *np)
5807c478bd9Sstevel@tonic-gate {
5817c478bd9Sstevel@tonic-gate 	NODE *array;
5827c478bd9Sstevel@tonic-gate 	STRING funcname;
5837c478bd9Sstevel@tonic-gate 	register size_t nel;
5847c478bd9Sstevel@tonic-gate 	register NODE *tnp;
5857c478bd9Sstevel@tonic-gate 	register NODE *funcnp;
5867c478bd9Sstevel@tonic-gate 	register NODE **alist, **npp;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
5897c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_asort);
5907c478bd9Sstevel@tonic-gate 	array = getlist(&np);
5917c478bd9Sstevel@tonic-gate 	if (array->n_type == PARM)
5927c478bd9Sstevel@tonic-gate 		array = array->n_next;
5937c478bd9Sstevel@tonic-gate 	if (array->n_type != ARRAY)
5947c478bd9Sstevel@tonic-gate 		awkerr(gettext("%s function requires an array"),
5957c478bd9Sstevel@tonic-gate 			s_asort);
5967c478bd9Sstevel@tonic-gate 	funcname = exprstring(getlist(&np));
5977c478bd9Sstevel@tonic-gate 	if ((funcnp = vlookup(funcname, 1)) == NNULL
5987c478bd9Sstevel@tonic-gate 	 || funcnp->n_type != UFUNC)
5997c478bd9Sstevel@tonic-gate 		awkerr(gettext("%s: %s is not a function\n"),
6007c478bd9Sstevel@tonic-gate 		    s_asort, funcname);
6017c478bd9Sstevel@tonic-gate 	/*
6027c478bd9Sstevel@tonic-gate 	 * Count size of array, allowing one extra for NULL at end
6037c478bd9Sstevel@tonic-gate 	 */
6047c478bd9Sstevel@tonic-gate 	nel = 1;
6057c478bd9Sstevel@tonic-gate 	for (tnp = array->n_alink; tnp != NNULL; tnp = tnp->n_alink)
6067c478bd9Sstevel@tonic-gate 		++nel;
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * Create UFUNC node that points at the funcnp on left and the
6097c478bd9Sstevel@tonic-gate 	 * list of three variables on right (array, index1, index2)
6107c478bd9Sstevel@tonic-gate 	 *				UFUNC
6117c478bd9Sstevel@tonic-gate 	 *				/    \
6127c478bd9Sstevel@tonic-gate 	 *			   funcnp    COMMA
6137c478bd9Sstevel@tonic-gate 	 *				      /   \
6147c478bd9Sstevel@tonic-gate 	 *				array	  COMMA
6157c478bd9Sstevel@tonic-gate 	 *					  /    \
6167c478bd9Sstevel@tonic-gate 	 *					index1 index2
6177c478bd9Sstevel@tonic-gate 	 */
6187c478bd9Sstevel@tonic-gate 	if (asortfunc == NNULL) {
6197c478bd9Sstevel@tonic-gate 		running = 0;
6207c478bd9Sstevel@tonic-gate 		asortfunc = node(CALLUFUNC, NNULL,
6217c478bd9Sstevel@tonic-gate 				    node(COMMA, NNULL,
6227c478bd9Sstevel@tonic-gate 				    node(COMMA,
6237c478bd9Sstevel@tonic-gate 					asnp1=stringnode(_null, FSTATIC, 0),
6247c478bd9Sstevel@tonic-gate 					asnp2=stringnode(_null, FSTATIC, 0))));
6257c478bd9Sstevel@tonic-gate 		running = 1;
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 	asortfunc->n_left = funcnp;
6287c478bd9Sstevel@tonic-gate 	asortfunc->n_right->n_left = array;
6297c478bd9Sstevel@tonic-gate 	asarraylen = wcslen(array->n_name)+1;
6307c478bd9Sstevel@tonic-gate 	alist = (NODE **) emalloc(nel*sizeof(NODE *));
6317c478bd9Sstevel@tonic-gate 	/*
6327c478bd9Sstevel@tonic-gate 	 * Copy array into alist.
6337c478bd9Sstevel@tonic-gate 	 */
6347c478bd9Sstevel@tonic-gate 	npp = alist;
6357c478bd9Sstevel@tonic-gate 	for (tnp = array->n_alink; tnp != NNULL; tnp = tnp->n_alink)
6367c478bd9Sstevel@tonic-gate 		*npp++ = tnp;
6377c478bd9Sstevel@tonic-gate 	*npp = NNULL;
6387c478bd9Sstevel@tonic-gate 	/*
6397c478bd9Sstevel@tonic-gate 	 * Re-order array to this list
6407c478bd9Sstevel@tonic-gate 	 */
6417c478bd9Sstevel@tonic-gate 	qsort((wchar_t *)alist, nel-1, sizeof (NODE *), asortcmp);
6427c478bd9Sstevel@tonic-gate 	tnp = array;
6437c478bd9Sstevel@tonic-gate 	npp = alist;
6447c478bd9Sstevel@tonic-gate 	do {
6457c478bd9Sstevel@tonic-gate 		tnp = tnp->n_alink = *npp;
6467c478bd9Sstevel@tonic-gate 	} while (*npp++ != NNULL);
6477c478bd9Sstevel@tonic-gate 	free((wchar_t *)alist);
6487c478bd9Sstevel@tonic-gate 	return (constundef);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate  * Return the number of arguments of a function.
6537c478bd9Sstevel@tonic-gate  */
6547c478bd9Sstevel@tonic-gate static uint
nargs(NODE * np)6557c478bd9Sstevel@tonic-gate nargs(NODE *np)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate 	register int n;
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if (np == NNULL)
6607c478bd9Sstevel@tonic-gate 		return (0);
6617c478bd9Sstevel@tonic-gate 	n = 1;
6627c478bd9Sstevel@tonic-gate 	while (np!=NNULL && np->n_type==COMMA) {
6637c478bd9Sstevel@tonic-gate 		np = np->n_right;
6647c478bd9Sstevel@tonic-gate 		n++;
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 	return (n);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate /*
6707c478bd9Sstevel@tonic-gate  * Do case translation.
6717c478bd9Sstevel@tonic-gate  */
6727c478bd9Sstevel@tonic-gate static NODE *
docasetr(NODE * np,int upper)6737c478bd9Sstevel@tonic-gate docasetr(NODE *np, int upper)
6747c478bd9Sstevel@tonic-gate {
6757c478bd9Sstevel@tonic-gate 	register int c;
6767c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
6777c478bd9Sstevel@tonic-gate 	register wchar_t *str;
6787c478bd9Sstevel@tonic-gate 	register uint na;
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
6817c478bd9Sstevel@tonic-gate 		awkerr(nargerr, upper ? s_toupper : s_tolower);
6827c478bd9Sstevel@tonic-gate 	str = strsave(na==0 ? linebuf : exprstring(getlist(&np)));
6837c478bd9Sstevel@tonic-gate 	cp = str;
6847c478bd9Sstevel@tonic-gate 	if (upper) {
6857c478bd9Sstevel@tonic-gate 		while ((c = *cp++) != '\0')
6867c478bd9Sstevel@tonic-gate 			cp[-1] = towupper(c);
6877c478bd9Sstevel@tonic-gate 	} else {
6887c478bd9Sstevel@tonic-gate 		while ((c = *cp++) != '\0')
6897c478bd9Sstevel@tonic-gate 			cp[-1] = towlower(c);
6907c478bd9Sstevel@tonic-gate 	}
6917c478bd9Sstevel@tonic-gate 	return (stringnode((STRING)str, FNOALLOC, (size_t)(cp-str-1)));
6927c478bd9Sstevel@tonic-gate }
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate /*
6957c478bd9Sstevel@tonic-gate  * The comparison routine used by qsort inside f_asort()
6967c478bd9Sstevel@tonic-gate  */
6977c478bd9Sstevel@tonic-gate static int
asortcmp(const void * npp1,const void * npp2)6987c478bd9Sstevel@tonic-gate asortcmp(const void *npp1, const void *npp2)
6997c478bd9Sstevel@tonic-gate {
7007c478bd9Sstevel@tonic-gate 	asnp1->n_strlen =
7017c478bd9Sstevel@tonic-gate 	    wcslen(asnp1->n_string = (*(NODE **)npp1)->n_name+asarraylen);
7027c478bd9Sstevel@tonic-gate 	asnp2->n_strlen =
7037c478bd9Sstevel@tonic-gate 	    wcslen(asnp2->n_string = (*(NODE **)npp2)->n_name+asarraylen);
7047c478bd9Sstevel@tonic-gate 	return ((int)exprint(asortfunc));
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate #if M_MATHERR
7087c478bd9Sstevel@tonic-gate #if !defined(__BORLANDC__)&&defined(__TURBOC__)&&__COMPACT__&&__EMULATE__
7097c478bd9Sstevel@tonic-gate /* So it won't optimize registers our FP is using */
7107c478bd9Sstevel@tonic-gate #define	flushesbx()	(_BX = 0, _ES = _BX)
7117c478bd9Sstevel@tonic-gate #else
7127c478bd9Sstevel@tonic-gate #define	flushesbx()	(0)
7137c478bd9Sstevel@tonic-gate #endif
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate /*
7167c478bd9Sstevel@tonic-gate  * Math error for awk.
7177c478bd9Sstevel@tonic-gate  */
7187c478bd9Sstevel@tonic-gate int
matherr(struct exception * ep)7197c478bd9Sstevel@tonic-gate matherr(struct exception *ep)
7207c478bd9Sstevel@tonic-gate {
7217c478bd9Sstevel@tonic-gate 	register uint type;
7227c478bd9Sstevel@tonic-gate 	static char msgs[7][256];
7237c478bd9Sstevel@tonic-gate 	static int first_time = 1;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (first_time) {
7267c478bd9Sstevel@tonic-gate 		msgs[0] = gettext("Unknown FP error"),
7277c478bd9Sstevel@tonic-gate 		msgs[1] = gettext("Domain"),
7287c478bd9Sstevel@tonic-gate 		msgs[2] = gettext("Singularity"),
7297c478bd9Sstevel@tonic-gate 		msgs[3] = gettext("Overflow"),
7307c478bd9Sstevel@tonic-gate 		msgs[4] = gettext("Underflow"),
7317c478bd9Sstevel@tonic-gate 		msgs[5] = gettext("Total loss of precision"),
7327c478bd9Sstevel@tonic-gate 		msgs[6] = gettext("Partial loss of precision")
7337c478bd9Sstevel@tonic-gate 		first_time = 0;
7347c478bd9Sstevel@tonic-gate 	}
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	if ((type = ep->type) > (uint)PLOSS)
7377c478bd9Sstevel@tonic-gate 		type = 0;
7387c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr, "awk: %s", strmsg(msgs[type]));
7397c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr, gettext(
7407c478bd9Sstevel@tonic-gate 		" error in function %s(%g) at NR=%lld\n"),
7417c478bd9Sstevel@tonic-gate 		((void) flushesbx(), ep->name), ep->arg1, (INT)exprint(varNR));
7427c478bd9Sstevel@tonic-gate 	return (1);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate #endif	/*M_MATHERR*/
745