xref: /titanic_53/usr/src/cmd/awk_xpg4/awk4.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * awk -- functions
24*7c478bd9Sstevel@tonic-gate  *
25*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1995, 1996 by Sun Microsystems, Inc.
26*7c478bd9Sstevel@tonic-gate  * All rights reserved.
27*7c478bd9Sstevel@tonic-gate  *
28*7c478bd9Sstevel@tonic-gate  * Copyright 1986, 1994 by Mortice Kern Systems Inc.  All rights reserved.
29*7c478bd9Sstevel@tonic-gate  *
30*7c478bd9Sstevel@tonic-gate  * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes
31*7c478bd9Sstevel@tonic-gate  */
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "awk.h"
36*7c478bd9Sstevel@tonic-gate #include "y.tab.h"
37*7c478bd9Sstevel@tonic-gate #include <time.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/wait.h>
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate static uint	nargs(NODE *np);
41*7c478bd9Sstevel@tonic-gate static NODE	*dosub(NODE *np, int glob);
42*7c478bd9Sstevel@tonic-gate static NODE	*docasetr(NODE *np, int upper);
43*7c478bd9Sstevel@tonic-gate static int	asortcmp(const void *npp1, const void *npp2);
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate static char	nargerr[] = "wrong number of arguments to function \"%s\"";
46*7c478bd9Sstevel@tonic-gate static NODE	*asortfunc;		/* Function call for asort() */
47*7c478bd9Sstevel@tonic-gate static NODE	*asnp1, *asnp2;		/* index1, index2 nodes */
48*7c478bd9Sstevel@tonic-gate static int	asarraylen;		/* strlen(array)+1 for asort */
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate /*
51*7c478bd9Sstevel@tonic-gate  * Return the value of exp(x).
52*7c478bd9Sstevel@tonic-gate  * Usage:	y = exp(x)
53*7c478bd9Sstevel@tonic-gate  *		y = exp()
54*7c478bd9Sstevel@tonic-gate  */
55*7c478bd9Sstevel@tonic-gate NODE *
f_exp(NODE * np)56*7c478bd9Sstevel@tonic-gate f_exp(NODE *np)
57*7c478bd9Sstevel@tonic-gate {
58*7c478bd9Sstevel@tonic-gate 	register uint na;
59*7c478bd9Sstevel@tonic-gate 
60*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
61*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_exp);
62*7c478bd9Sstevel@tonic-gate 	return (realnode(exp(exprreal(na==0 ? field0 : getlist(&np)))));
63*7c478bd9Sstevel@tonic-gate }
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate /*
66*7c478bd9Sstevel@tonic-gate  * Return the integer part of the argument.
67*7c478bd9Sstevel@tonic-gate  * Usage:	i = int(r)
68*7c478bd9Sstevel@tonic-gate  *		i = int()
69*7c478bd9Sstevel@tonic-gate  */
70*7c478bd9Sstevel@tonic-gate NODE *
f_int(NODE * np)71*7c478bd9Sstevel@tonic-gate f_int(NODE *np)
72*7c478bd9Sstevel@tonic-gate {
73*7c478bd9Sstevel@tonic-gate 	register uint na;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
76*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_int);
77*7c478bd9Sstevel@tonic-gate 	return (intnode(exprint(na==0 ? field0 : getlist(&np))));
78*7c478bd9Sstevel@tonic-gate }
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /*
81*7c478bd9Sstevel@tonic-gate  * Logarithm function.
82*7c478bd9Sstevel@tonic-gate  * Usage:	y = log(x)
83*7c478bd9Sstevel@tonic-gate  *		y = log()
84*7c478bd9Sstevel@tonic-gate  */
85*7c478bd9Sstevel@tonic-gate NODE *
f_log(NODE * np)86*7c478bd9Sstevel@tonic-gate f_log(NODE *np)
87*7c478bd9Sstevel@tonic-gate {
88*7c478bd9Sstevel@tonic-gate 	register uint na;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
91*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_log);
92*7c478bd9Sstevel@tonic-gate 	return (realnode(log(exprreal(na==0 ? field0 : getlist(&np)))));
93*7c478bd9Sstevel@tonic-gate }
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate /*
96*7c478bd9Sstevel@tonic-gate  * Square root function.
97*7c478bd9Sstevel@tonic-gate  * Usage:	y = sqrt(x)
98*7c478bd9Sstevel@tonic-gate  *		y = sqrt()
99*7c478bd9Sstevel@tonic-gate  */
100*7c478bd9Sstevel@tonic-gate NODE *
f_sqrt(NODE * np)101*7c478bd9Sstevel@tonic-gate f_sqrt(NODE *np)
102*7c478bd9Sstevel@tonic-gate {
103*7c478bd9Sstevel@tonic-gate 	register uint na;
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
106*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_sqrt);
107*7c478bd9Sstevel@tonic-gate 	return (realnode(sqrt(exprreal(na==0 ? field0 : getlist(&np)))));
108*7c478bd9Sstevel@tonic-gate }
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate /*
111*7c478bd9Sstevel@tonic-gate  * Trigonometric sine function.
112*7c478bd9Sstevel@tonic-gate  * Usage:	y = sin(x)
113*7c478bd9Sstevel@tonic-gate  */
114*7c478bd9Sstevel@tonic-gate NODE *
f_sin(NODE * np)115*7c478bd9Sstevel@tonic-gate f_sin(NODE *np)
116*7c478bd9Sstevel@tonic-gate {
117*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
118*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_sin);
119*7c478bd9Sstevel@tonic-gate 	return (realnode(sin(exprreal(getlist(&np)))));
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * Trigonometric cosine function.
124*7c478bd9Sstevel@tonic-gate  * Usage:	y = cos(x)
125*7c478bd9Sstevel@tonic-gate  */
126*7c478bd9Sstevel@tonic-gate NODE *
f_cos(NODE * np)127*7c478bd9Sstevel@tonic-gate f_cos(NODE *np)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
130*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_cos);
131*7c478bd9Sstevel@tonic-gate 	return (realnode(cos(exprreal(getlist(&np)))));
132*7c478bd9Sstevel@tonic-gate }
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate /*
135*7c478bd9Sstevel@tonic-gate  * Arctangent of y/x.
136*7c478bd9Sstevel@tonic-gate  * Usage:	z = atan2(y, x)
137*7c478bd9Sstevel@tonic-gate  */
138*7c478bd9Sstevel@tonic-gate NODE *
f_atan2(NODE * np)139*7c478bd9Sstevel@tonic-gate f_atan2(NODE *np)
140*7c478bd9Sstevel@tonic-gate {
141*7c478bd9Sstevel@tonic-gate 	double y, x;
142*7c478bd9Sstevel@tonic-gate 
143*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
144*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_atan2);
145*7c478bd9Sstevel@tonic-gate 	y = (double)exprreal(getlist(&np));
146*7c478bd9Sstevel@tonic-gate 	x = (double)exprreal(getlist(&np));
147*7c478bd9Sstevel@tonic-gate 	return (realnode(atan2(y, x)));
148*7c478bd9Sstevel@tonic-gate }
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate /*
151*7c478bd9Sstevel@tonic-gate  * Set the seed for the random number generator function -- rand.
152*7c478bd9Sstevel@tonic-gate  * Usage:	srand(x)
153*7c478bd9Sstevel@tonic-gate  *		srand()
154*7c478bd9Sstevel@tonic-gate  */
155*7c478bd9Sstevel@tonic-gate NODE *
f_srand(NODE * np)156*7c478bd9Sstevel@tonic-gate f_srand(NODE *np)
157*7c478bd9Sstevel@tonic-gate {
158*7c478bd9Sstevel@tonic-gate 	register uint na;
159*7c478bd9Sstevel@tonic-gate 	register uint seed;
160*7c478bd9Sstevel@tonic-gate 	static uint oldseed = 0;
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
163*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_srand);
164*7c478bd9Sstevel@tonic-gate 	if (na == 0)
165*7c478bd9Sstevel@tonic-gate 		seed = (uint)time((time_t *)0); else
166*7c478bd9Sstevel@tonic-gate 		seed = (uint)exprint(getlist(&np));
167*7c478bd9Sstevel@tonic-gate 	srand(seed);
168*7c478bd9Sstevel@tonic-gate 	na = oldseed;
169*7c478bd9Sstevel@tonic-gate 	oldseed = seed;
170*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)na));
171*7c478bd9Sstevel@tonic-gate }
172*7c478bd9Sstevel@tonic-gate 
173*7c478bd9Sstevel@tonic-gate /*
174*7c478bd9Sstevel@tonic-gate  * Generate a random number.
175*7c478bd9Sstevel@tonic-gate  * Usage:	x = rand()
176*7c478bd9Sstevel@tonic-gate  */
177*7c478bd9Sstevel@tonic-gate NODE *
f_rand(NODE * np)178*7c478bd9Sstevel@tonic-gate f_rand(NODE *np)
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	double result;
181*7c478bd9Sstevel@tonic-gate 	int expon;
182*7c478bd9Sstevel@tonic-gate 	ushort rint;
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 0)
185*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_rand);
186*7c478bd9Sstevel@tonic-gate 	rint = rand() & SHRT_MAX;
187*7c478bd9Sstevel@tonic-gate 	result = frexp((double)rint, &expon);
188*7c478bd9Sstevel@tonic-gate 	return (realnode((REAL)ldexp(result, expon-15)));
189*7c478bd9Sstevel@tonic-gate }
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate /*
192*7c478bd9Sstevel@tonic-gate  * Substitute function.
193*7c478bd9Sstevel@tonic-gate  * Usage:	n = sub(regex, replace, target)
194*7c478bd9Sstevel@tonic-gate  *		n = sub(regex, replace)
195*7c478bd9Sstevel@tonic-gate  */
196*7c478bd9Sstevel@tonic-gate NODE *
f_sub(NODE * np)197*7c478bd9Sstevel@tonic-gate f_sub(NODE *np)
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate 	return (dosub(np, 1));
200*7c478bd9Sstevel@tonic-gate }
201*7c478bd9Sstevel@tonic-gate 
202*7c478bd9Sstevel@tonic-gate /*
203*7c478bd9Sstevel@tonic-gate  * Global substitution function.
204*7c478bd9Sstevel@tonic-gate  * Usage:	n = gsub(regex, replace, target)
205*7c478bd9Sstevel@tonic-gate  *		n = gsub(regex, replace)
206*7c478bd9Sstevel@tonic-gate  */
207*7c478bd9Sstevel@tonic-gate NODE *
f_gsub(NODE * np)208*7c478bd9Sstevel@tonic-gate f_gsub(NODE *np)
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate 	return (dosub(np, 0));
211*7c478bd9Sstevel@tonic-gate }
212*7c478bd9Sstevel@tonic-gate 
213*7c478bd9Sstevel@tonic-gate /*
214*7c478bd9Sstevel@tonic-gate  * Do actual substitutions.
215*7c478bd9Sstevel@tonic-gate  * `glob' is the number to substitute, 0 for all.
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate static NODE *
dosub(NODE * np,int glob)218*7c478bd9Sstevel@tonic-gate dosub(NODE *np, int glob)
219*7c478bd9Sstevel@tonic-gate {
220*7c478bd9Sstevel@tonic-gate 	wchar_t *text;
221*7c478bd9Sstevel@tonic-gate 	register wchar_t *sub;
222*7c478bd9Sstevel@tonic-gate 	register uint n;
223*7c478bd9Sstevel@tonic-gate 	register uint na;
224*7c478bd9Sstevel@tonic-gate 	register REGEXP rp;
225*7c478bd9Sstevel@tonic-gate 	NODE *left;
226*7c478bd9Sstevel@tonic-gate 	static wchar_t *buf;
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) != 2 && na != 3)
229*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, glob==0 ? s_gsub : s_sub);
230*7c478bd9Sstevel@tonic-gate 	rp = getregexp(getlist(&np));
231*7c478bd9Sstevel@tonic-gate 	sub = exprstring(getlist(&np));
232*7c478bd9Sstevel@tonic-gate 	if (na == 3) {
233*7c478bd9Sstevel@tonic-gate 		left = getlist(&np);
234*7c478bd9Sstevel@tonic-gate 		text = exprstring(left);
235*7c478bd9Sstevel@tonic-gate 	} else {
236*7c478bd9Sstevel@tonic-gate 		left = field0;
237*7c478bd9Sstevel@tonic-gate 		text = linebuf;
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 	switch (REGWDOSUBA(rp, sub, text, &buf, 256, &glob)) {
240*7c478bd9Sstevel@tonic-gate 	case REG_OK:
241*7c478bd9Sstevel@tonic-gate 	case REG_NOMATCH:
242*7c478bd9Sstevel@tonic-gate 		n = glob;
243*7c478bd9Sstevel@tonic-gate 		break;
244*7c478bd9Sstevel@tonic-gate 	case REG_ESPACE:
245*7c478bd9Sstevel@tonic-gate 		if (buf != NULL)
246*7c478bd9Sstevel@tonic-gate 			free(buf);
247*7c478bd9Sstevel@tonic-gate 		awkerr(nomem);
248*7c478bd9Sstevel@tonic-gate 	default:
249*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("regular expression error"));
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	(void)assign(left, stringnode(buf, FNOALLOC, wcslen(buf)));
252*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)n));
253*7c478bd9Sstevel@tonic-gate }
254*7c478bd9Sstevel@tonic-gate 
255*7c478bd9Sstevel@tonic-gate /*
256*7c478bd9Sstevel@tonic-gate  * Match function.  Return position (origin 1) or 0 for regular
257*7c478bd9Sstevel@tonic-gate  * expression match in string.  Set new variables RSTART and RLENGTH
258*7c478bd9Sstevel@tonic-gate  * as well.
259*7c478bd9Sstevel@tonic-gate  * Usage:	pos = match(string, re)
260*7c478bd9Sstevel@tonic-gate  */
261*7c478bd9Sstevel@tonic-gate NODE *
f_match(NODE * np)262*7c478bd9Sstevel@tonic-gate f_match(NODE *np)
263*7c478bd9Sstevel@tonic-gate {
264*7c478bd9Sstevel@tonic-gate 	register wchar_t *text;
265*7c478bd9Sstevel@tonic-gate 	register REGEXP rp;
266*7c478bd9Sstevel@tonic-gate 	register int pos, length;
267*7c478bd9Sstevel@tonic-gate 	REGWMATCH_T match[10];
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
270*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_match);
271*7c478bd9Sstevel@tonic-gate 	text = exprstring(getlist(&np));
272*7c478bd9Sstevel@tonic-gate 	rp = getregexp(getlist(&np));
273*7c478bd9Sstevel@tonic-gate 	if (REGWEXEC(rp, text, 10, match, 0) == REG_OK) {
274*7c478bd9Sstevel@tonic-gate 		pos = match[0].rm_sp-text+1;
275*7c478bd9Sstevel@tonic-gate 		length = match[0].rm_ep - match[0].rm_sp;
276*7c478bd9Sstevel@tonic-gate 	} else {
277*7c478bd9Sstevel@tonic-gate 		pos = 0;
278*7c478bd9Sstevel@tonic-gate 		length = -1;
279*7c478bd9Sstevel@tonic-gate 	}
280*7c478bd9Sstevel@tonic-gate 	constant->n_int = length;
281*7c478bd9Sstevel@tonic-gate 	(void)assign(vlook(M_MB_L("RLENGTH")), constant);
282*7c478bd9Sstevel@tonic-gate 	return (assign(vlook(M_MB_L("RSTART")), intnode((INT)pos)));
283*7c478bd9Sstevel@tonic-gate }
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate /*
286*7c478bd9Sstevel@tonic-gate  * Call shell or command interpreter.
287*7c478bd9Sstevel@tonic-gate  * Usage:	status = system(command)
288*7c478bd9Sstevel@tonic-gate  */
289*7c478bd9Sstevel@tonic-gate NODE *
f_system(NODE * np)290*7c478bd9Sstevel@tonic-gate f_system(NODE *np)
291*7c478bd9Sstevel@tonic-gate {
292*7c478bd9Sstevel@tonic-gate 	int retcode;
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
295*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_system);
296*7c478bd9Sstevel@tonic-gate 	(void) fflush(stdout);
297*7c478bd9Sstevel@tonic-gate 	retcode = system(mbunconvert(exprstring(getlist(&np))));
298*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)WEXITSTATUS(retcode)));
299*7c478bd9Sstevel@tonic-gate }
300*7c478bd9Sstevel@tonic-gate 
301*7c478bd9Sstevel@tonic-gate /*
302*7c478bd9Sstevel@tonic-gate  * Search for string within string.
303*7c478bd9Sstevel@tonic-gate  * Usage:	pos = index(string1, string2)
304*7c478bd9Sstevel@tonic-gate  */
305*7c478bd9Sstevel@tonic-gate NODE *
f_index(NODE * np)306*7c478bd9Sstevel@tonic-gate f_index(NODE *np)
307*7c478bd9Sstevel@tonic-gate {
308*7c478bd9Sstevel@tonic-gate 	register wchar_t *s1, *s2;
309*7c478bd9Sstevel@tonic-gate 	register int l1, l2;
310*7c478bd9Sstevel@tonic-gate 	register int result;
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
313*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_index);
314*7c478bd9Sstevel@tonic-gate 	s1 = (wchar_t *)exprstring(getlist(&np));
315*7c478bd9Sstevel@tonic-gate 	s2 = (wchar_t *)exprstring(getlist(&np));
316*7c478bd9Sstevel@tonic-gate 	l1 = wcslen(s1);
317*7c478bd9Sstevel@tonic-gate 	l2 = wcslen(s2);
318*7c478bd9Sstevel@tonic-gate 	result = 1;
319*7c478bd9Sstevel@tonic-gate 	while (l2 <= l1) {
320*7c478bd9Sstevel@tonic-gate 		if (memcmp(s1, s2, l2 * sizeof(wchar_t)) == 0)
321*7c478bd9Sstevel@tonic-gate 			break;
322*7c478bd9Sstevel@tonic-gate 		result++;
323*7c478bd9Sstevel@tonic-gate 		s1++;
324*7c478bd9Sstevel@tonic-gate 		l1--;
325*7c478bd9Sstevel@tonic-gate 	}
326*7c478bd9Sstevel@tonic-gate 	if (l2 > l1)
327*7c478bd9Sstevel@tonic-gate 		result = 0;
328*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)result));
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate 
331*7c478bd9Sstevel@tonic-gate /*
332*7c478bd9Sstevel@tonic-gate  * Return length of argument or $0
333*7c478bd9Sstevel@tonic-gate  * Usage:	n = length(string)
334*7c478bd9Sstevel@tonic-gate  *		n = length()
335*7c478bd9Sstevel@tonic-gate  *		n = length
336*7c478bd9Sstevel@tonic-gate  */
337*7c478bd9Sstevel@tonic-gate NODE *
f_length(NODE * np)338*7c478bd9Sstevel@tonic-gate f_length(NODE *np)
339*7c478bd9Sstevel@tonic-gate {
340*7c478bd9Sstevel@tonic-gate 	register uint na;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
343*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_length);
344*7c478bd9Sstevel@tonic-gate 	if (na == 0)
345*7c478bd9Sstevel@tonic-gate 		na = lbuflen; else
346*7c478bd9Sstevel@tonic-gate 		na = wcslen((wchar_t *)exprstring(getlist(&np)));
347*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)na));
348*7c478bd9Sstevel@tonic-gate }
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate /*
351*7c478bd9Sstevel@tonic-gate  * Split string into fields.
352*7c478bd9Sstevel@tonic-gate  * Usage: nfields = split(string, array [, separator]);
353*7c478bd9Sstevel@tonic-gate  */
354*7c478bd9Sstevel@tonic-gate NODE *
f_split(NODE * np)355*7c478bd9Sstevel@tonic-gate f_split(NODE *np)
356*7c478bd9Sstevel@tonic-gate {
357*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
358*7c478bd9Sstevel@tonic-gate 	wchar_t *ep, *saved = 0;
359*7c478bd9Sstevel@tonic-gate 	register NODE *tnp, *snp, *otnp;
360*7c478bd9Sstevel@tonic-gate 	register NODE *sep;
361*7c478bd9Sstevel@tonic-gate 	REGEXP old_resep = 0;
362*7c478bd9Sstevel@tonic-gate 	size_t seplen;
363*7c478bd9Sstevel@tonic-gate 	uint n;
364*7c478bd9Sstevel@tonic-gate 	wint_t c;
365*7c478bd9Sstevel@tonic-gate 	wchar_t savesep[20];
366*7c478bd9Sstevel@tonic-gate 	wchar_t  *(*old_awkfield)(wchar_t **) = 0;
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	if ((n = nargs(np))<2 || n>3)
369*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_split);
370*7c478bd9Sstevel@tonic-gate 	ep = exprstring(snp = getlist(&np));
371*7c478bd9Sstevel@tonic-gate 	tnp = getlist(&np);
372*7c478bd9Sstevel@tonic-gate 	if (snp->n_type == INDEX && snp->n_left == tnp)
373*7c478bd9Sstevel@tonic-gate 		ep = saved = wsdup(ep);
374*7c478bd9Sstevel@tonic-gate 	if (n == 3) {
375*7c478bd9Sstevel@tonic-gate 		sep = getlist(&np);
376*7c478bd9Sstevel@tonic-gate 	} else
377*7c478bd9Sstevel@tonic-gate 		sep = NNULL;
378*7c478bd9Sstevel@tonic-gate 	switch (tnp->n_type) {
379*7c478bd9Sstevel@tonic-gate 	case ARRAY:
380*7c478bd9Sstevel@tonic-gate 		delarray(tnp);
381*7c478bd9Sstevel@tonic-gate 		break;
382*7c478bd9Sstevel@tonic-gate 
383*7c478bd9Sstevel@tonic-gate 	case PARM:
384*7c478bd9Sstevel@tonic-gate 		break;
385*7c478bd9Sstevel@tonic-gate 
386*7c478bd9Sstevel@tonic-gate 	case VAR:
387*7c478bd9Sstevel@tonic-gate 		if (isstring(tnp->n_flags) && tnp->n_string==_null)
388*7c478bd9Sstevel@tonic-gate 			break;
389*7c478bd9Sstevel@tonic-gate 	default:
390*7c478bd9Sstevel@tonic-gate 		awkerr(gettext(
391*7c478bd9Sstevel@tonic-gate 			"second parameter to \"split\" must be an array"));
392*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
393*7c478bd9Sstevel@tonic-gate 	}
394*7c478bd9Sstevel@tonic-gate 	/*
395*7c478bd9Sstevel@tonic-gate 	 * If an argument has been passed in to be used as the
396*7c478bd9Sstevel@tonic-gate 	 * field separator check to see if it is a constant regular
397*7c478bd9Sstevel@tonic-gate 	 * expression. If so, use it directly otherwise reduce the
398*7c478bd9Sstevel@tonic-gate 	 * expression, convert the result into a string and assign it
399*7c478bd9Sstevel@tonic-gate 	 * to "FS" (after saving the old value for FS.)
400*7c478bd9Sstevel@tonic-gate 	 */
401*7c478bd9Sstevel@tonic-gate 	if (sep != NNULL) {
402*7c478bd9Sstevel@tonic-gate 		if (sep->n_type == PARM)
403*7c478bd9Sstevel@tonic-gate 			sep = sep->n_next;
404*7c478bd9Sstevel@tonic-gate 		if (sep->n_type == RE) {
405*7c478bd9Sstevel@tonic-gate 			old_resep = resep;
406*7c478bd9Sstevel@tonic-gate 			resep = sep->n_regexp;
407*7c478bd9Sstevel@tonic-gate 			old_awkfield = awkfield;
408*7c478bd9Sstevel@tonic-gate 			awkfield = refield;
409*7c478bd9Sstevel@tonic-gate 		} else {
410*7c478bd9Sstevel@tonic-gate 			sep = exprreduce(sep);
411*7c478bd9Sstevel@tonic-gate 			seplen = wcslen(cp = (wchar_t *)exprstring(varFS));
412*7c478bd9Sstevel@tonic-gate 			(void) memcpy(savesep, cp,
413*7c478bd9Sstevel@tonic-gate 				(seplen+1) * sizeof(wchar_t));
414*7c478bd9Sstevel@tonic-gate 			(void) assign(varFS, sep);
415*7c478bd9Sstevel@tonic-gate 		}
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 	/*
418*7c478bd9Sstevel@tonic-gate 	 * Iterate over the record, extracting each field and assigning it to
419*7c478bd9Sstevel@tonic-gate 	 * the corresponding element in the array.
420*7c478bd9Sstevel@tonic-gate 	 */
421*7c478bd9Sstevel@tonic-gate 	otnp = tnp;	/* save tnp for possible promotion */
422*7c478bd9Sstevel@tonic-gate 	tnp = node(INDEX, tnp, constant);
423*7c478bd9Sstevel@tonic-gate 	fcount = 0;
424*7c478bd9Sstevel@tonic-gate 	for (;;) {
425*7c478bd9Sstevel@tonic-gate 		if ((cp = (*awkfield)(&ep)) == NULL) {
426*7c478bd9Sstevel@tonic-gate 			if (fcount == 0) {
427*7c478bd9Sstevel@tonic-gate 				if (otnp->n_type == PARM)
428*7c478bd9Sstevel@tonic-gate 					otnp = otnp->n_next;
429*7c478bd9Sstevel@tonic-gate 				promote(otnp);
430*7c478bd9Sstevel@tonic-gate 			}
431*7c478bd9Sstevel@tonic-gate 			break;
432*7c478bd9Sstevel@tonic-gate 		}
433*7c478bd9Sstevel@tonic-gate 		c = *ep;
434*7c478bd9Sstevel@tonic-gate 		*ep = '\0';
435*7c478bd9Sstevel@tonic-gate 		constant->n_int = ++fcount;
436*7c478bd9Sstevel@tonic-gate 		(void)assign(tnp, stringnode(cp,FALLOC|FSENSE,(size_t)(ep-cp)));
437*7c478bd9Sstevel@tonic-gate 		*ep = c;
438*7c478bd9Sstevel@tonic-gate 	}
439*7c478bd9Sstevel@tonic-gate 	/*
440*7c478bd9Sstevel@tonic-gate 	 * Restore the old record separator/and or regular expression.
441*7c478bd9Sstevel@tonic-gate 	 */
442*7c478bd9Sstevel@tonic-gate 	if (sep != NNULL) {
443*7c478bd9Sstevel@tonic-gate 		if (old_awkfield != 0) {
444*7c478bd9Sstevel@tonic-gate 			resep = old_resep;
445*7c478bd9Sstevel@tonic-gate 			awkfield = old_awkfield;
446*7c478bd9Sstevel@tonic-gate 		} else {
447*7c478bd9Sstevel@tonic-gate 			(void)assign(varFS,
448*7c478bd9Sstevel@tonic-gate 				stringnode(savesep, FSTATIC, seplen));
449*7c478bd9Sstevel@tonic-gate 		}
450*7c478bd9Sstevel@tonic-gate 	}
451*7c478bd9Sstevel@tonic-gate 	if (saved)
452*7c478bd9Sstevel@tonic-gate 		free(saved);
453*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)fcount));
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate /*
457*7c478bd9Sstevel@tonic-gate  * Sprintf function.
458*7c478bd9Sstevel@tonic-gate  * Usage:	string = sprintf(format, arg, ...)
459*7c478bd9Sstevel@tonic-gate  */
460*7c478bd9Sstevel@tonic-gate NODE *
f_sprintf(NODE * np)461*7c478bd9Sstevel@tonic-gate f_sprintf(NODE *np)
462*7c478bd9Sstevel@tonic-gate {
463*7c478bd9Sstevel@tonic-gate         wchar_t *cp;
464*7c478bd9Sstevel@tonic-gate         size_t length;
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate         if (nargs(np) == 0)
467*7c478bd9Sstevel@tonic-gate                 awkerr(nargerr, s_sprintf);
468*7c478bd9Sstevel@tonic-gate         length = xprintf(np, (FILE *)NULL, &cp);
469*7c478bd9Sstevel@tonic-gate         np = stringnode(cp, FNOALLOC, length);
470*7c478bd9Sstevel@tonic-gate         return (np);
471*7c478bd9Sstevel@tonic-gate }
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate /*
474*7c478bd9Sstevel@tonic-gate  * Substring.
475*7c478bd9Sstevel@tonic-gate  * newstring = substr(string, start, [length])
476*7c478bd9Sstevel@tonic-gate  */
477*7c478bd9Sstevel@tonic-gate NODE *
f_substr(NODE * np)478*7c478bd9Sstevel@tonic-gate f_substr(NODE *np)
479*7c478bd9Sstevel@tonic-gate {
480*7c478bd9Sstevel@tonic-gate 	register STRING str;
481*7c478bd9Sstevel@tonic-gate 	register size_t n;
482*7c478bd9Sstevel@tonic-gate 	register int start;
483*7c478bd9Sstevel@tonic-gate 	register size_t len;
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate 	if ((n = nargs(np))<2 || n>3)
486*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_substr);
487*7c478bd9Sstevel@tonic-gate 	str = exprstring(getlist(&np));
488*7c478bd9Sstevel@tonic-gate 	if ((start = (int)exprint(getlist(&np))-1) < 0)
489*7c478bd9Sstevel@tonic-gate 		start = 0;
490*7c478bd9Sstevel@tonic-gate 	if (n == 3) {
491*7c478bd9Sstevel@tonic-gate 		int x;
492*7c478bd9Sstevel@tonic-gate 		x = (int)exprint(getlist(&np));
493*7c478bd9Sstevel@tonic-gate 		if (x < 0)
494*7c478bd9Sstevel@tonic-gate 			len = 0;
495*7c478bd9Sstevel@tonic-gate 		else
496*7c478bd9Sstevel@tonic-gate 			len = (size_t)x;
497*7c478bd9Sstevel@tonic-gate 	} else
498*7c478bd9Sstevel@tonic-gate 		len = LARGE;
499*7c478bd9Sstevel@tonic-gate 	n = wcslen((wchar_t *)str);
500*7c478bd9Sstevel@tonic-gate 	if (start > n)
501*7c478bd9Sstevel@tonic-gate 		start = n;
502*7c478bd9Sstevel@tonic-gate 	n -= start;
503*7c478bd9Sstevel@tonic-gate 	if (len > n)
504*7c478bd9Sstevel@tonic-gate 		len = n;
505*7c478bd9Sstevel@tonic-gate 	str += start;
506*7c478bd9Sstevel@tonic-gate 	n = str[len];
507*7c478bd9Sstevel@tonic-gate 	str[len] = '\0';
508*7c478bd9Sstevel@tonic-gate 	np = stringnode(str, FALLOC, len);
509*7c478bd9Sstevel@tonic-gate 	str[len] = n;
510*7c478bd9Sstevel@tonic-gate 	return (np);
511*7c478bd9Sstevel@tonic-gate }
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate /*
514*7c478bd9Sstevel@tonic-gate  * Close an output or input file stream.
515*7c478bd9Sstevel@tonic-gate  */
516*7c478bd9Sstevel@tonic-gate NODE *
f_close(NODE * np)517*7c478bd9Sstevel@tonic-gate f_close(NODE *np)
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	register OFILE *op;
520*7c478bd9Sstevel@tonic-gate 	register char *name;
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
523*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_close);
524*7c478bd9Sstevel@tonic-gate 	name = mbunconvert(exprstring(getlist(&np)));
525*7c478bd9Sstevel@tonic-gate 	for (op = &ofiles[0]; op < &ofiles[NIOSTREAM]; op++)
526*7c478bd9Sstevel@tonic-gate 		if (op->f_fp!=FNULL && strcmp(name, op->f_name)==0) {
527*7c478bd9Sstevel@tonic-gate 			awkclose(op);
528*7c478bd9Sstevel@tonic-gate 			break;
529*7c478bd9Sstevel@tonic-gate 		}
530*7c478bd9Sstevel@tonic-gate 	if (op >= &ofiles[NIOSTREAM])
531*7c478bd9Sstevel@tonic-gate 		return (const1);
532*7c478bd9Sstevel@tonic-gate 	return (const0);
533*7c478bd9Sstevel@tonic-gate }
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate /*
536*7c478bd9Sstevel@tonic-gate  * Return the integer value of the first character of a string.
537*7c478bd9Sstevel@tonic-gate  * Usage:	char = ord(string)
538*7c478bd9Sstevel@tonic-gate  */
539*7c478bd9Sstevel@tonic-gate NODE *
f_ord(NODE * np)540*7c478bd9Sstevel@tonic-gate f_ord(NODE *np)
541*7c478bd9Sstevel@tonic-gate {
542*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 1)
543*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_ord);
544*7c478bd9Sstevel@tonic-gate 	return (intnode((INT)*exprstring(getlist(&np))));
545*7c478bd9Sstevel@tonic-gate }
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate /*
548*7c478bd9Sstevel@tonic-gate  * Return the argument string in lower case:
549*7c478bd9Sstevel@tonic-gate  * Usage:
550*7c478bd9Sstevel@tonic-gate  *	lower = tolower(upper)
551*7c478bd9Sstevel@tonic-gate  */
552*7c478bd9Sstevel@tonic-gate NODE *
f_tolower(NODE * np)553*7c478bd9Sstevel@tonic-gate f_tolower(NODE *np)
554*7c478bd9Sstevel@tonic-gate {
555*7c478bd9Sstevel@tonic-gate 	return (docasetr(np, 0));
556*7c478bd9Sstevel@tonic-gate }
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate /*
559*7c478bd9Sstevel@tonic-gate  * Return the argument string in upper case:
560*7c478bd9Sstevel@tonic-gate  * Usage:
561*7c478bd9Sstevel@tonic-gate  *	upper = toupper(lower)
562*7c478bd9Sstevel@tonic-gate  */
563*7c478bd9Sstevel@tonic-gate NODE *
f_toupper(NODE * np)564*7c478bd9Sstevel@tonic-gate f_toupper(NODE *np)
565*7c478bd9Sstevel@tonic-gate {
566*7c478bd9Sstevel@tonic-gate 	return (docasetr(np, 1));
567*7c478bd9Sstevel@tonic-gate }
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate /*
570*7c478bd9Sstevel@tonic-gate  * Sort the array into traversal order by the next "for (i in array)" loop.
571*7c478bd9Sstevel@tonic-gate  * Usage:
572*7c478bd9Sstevel@tonic-gate  *	asort(array, "cmpfunc")
573*7c478bd9Sstevel@tonic-gate  * 	cmpfunc(array, index1, index2)
574*7c478bd9Sstevel@tonic-gate  *		returns:
575*7c478bd9Sstevel@tonic-gate  *		<0		if 	array[index1] <  array[index2]
576*7c478bd9Sstevel@tonic-gate  *		 0		if	array[index1] == array[index2]
577*7c478bd9Sstevel@tonic-gate  *		>0		if	array[index1] >  array[index2]
578*7c478bd9Sstevel@tonic-gate  */
579*7c478bd9Sstevel@tonic-gate NODE *
f_asort(NODE * np)580*7c478bd9Sstevel@tonic-gate f_asort(NODE *np)
581*7c478bd9Sstevel@tonic-gate {
582*7c478bd9Sstevel@tonic-gate 	NODE *array;
583*7c478bd9Sstevel@tonic-gate 	STRING funcname;
584*7c478bd9Sstevel@tonic-gate 	register size_t nel;
585*7c478bd9Sstevel@tonic-gate 	register NODE *tnp;
586*7c478bd9Sstevel@tonic-gate 	register NODE *funcnp;
587*7c478bd9Sstevel@tonic-gate 	register NODE **alist, **npp;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 	if (nargs(np) != 2)
590*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, s_asort);
591*7c478bd9Sstevel@tonic-gate 	array = getlist(&np);
592*7c478bd9Sstevel@tonic-gate 	if (array->n_type == PARM)
593*7c478bd9Sstevel@tonic-gate 		array = array->n_next;
594*7c478bd9Sstevel@tonic-gate 	if (array->n_type != ARRAY)
595*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("%s function requires an array"),
596*7c478bd9Sstevel@tonic-gate 			s_asort);
597*7c478bd9Sstevel@tonic-gate 	funcname = exprstring(getlist(&np));
598*7c478bd9Sstevel@tonic-gate 	if ((funcnp = vlookup(funcname, 1)) == NNULL
599*7c478bd9Sstevel@tonic-gate 	 || funcnp->n_type != UFUNC)
600*7c478bd9Sstevel@tonic-gate 		awkerr(gettext("%s: %s is not a function\n"),
601*7c478bd9Sstevel@tonic-gate 		    s_asort, funcname);
602*7c478bd9Sstevel@tonic-gate 	/*
603*7c478bd9Sstevel@tonic-gate 	 * Count size of array, allowing one extra for NULL at end
604*7c478bd9Sstevel@tonic-gate 	 */
605*7c478bd9Sstevel@tonic-gate 	nel = 1;
606*7c478bd9Sstevel@tonic-gate 	for (tnp = array->n_alink; tnp != NNULL; tnp = tnp->n_alink)
607*7c478bd9Sstevel@tonic-gate 		++nel;
608*7c478bd9Sstevel@tonic-gate 	/*
609*7c478bd9Sstevel@tonic-gate 	 * Create UFUNC node that points at the funcnp on left and the
610*7c478bd9Sstevel@tonic-gate 	 * list of three variables on right (array, index1, index2)
611*7c478bd9Sstevel@tonic-gate 	 *				UFUNC
612*7c478bd9Sstevel@tonic-gate 	 *				/    \
613*7c478bd9Sstevel@tonic-gate 	 *			   funcnp    COMMA
614*7c478bd9Sstevel@tonic-gate 	 *				      /   \
615*7c478bd9Sstevel@tonic-gate 	 *				array	  COMMA
616*7c478bd9Sstevel@tonic-gate 	 *					  /    \
617*7c478bd9Sstevel@tonic-gate 	 *					index1 index2
618*7c478bd9Sstevel@tonic-gate 	 */
619*7c478bd9Sstevel@tonic-gate 	if (asortfunc == NNULL) {
620*7c478bd9Sstevel@tonic-gate 		running = 0;
621*7c478bd9Sstevel@tonic-gate 		asortfunc = node(CALLUFUNC, NNULL,
622*7c478bd9Sstevel@tonic-gate 				    node(COMMA, NNULL,
623*7c478bd9Sstevel@tonic-gate 				    node(COMMA,
624*7c478bd9Sstevel@tonic-gate 					asnp1=stringnode(_null, FSTATIC, 0),
625*7c478bd9Sstevel@tonic-gate 					asnp2=stringnode(_null, FSTATIC, 0))));
626*7c478bd9Sstevel@tonic-gate 		running = 1;
627*7c478bd9Sstevel@tonic-gate 	}
628*7c478bd9Sstevel@tonic-gate 	asortfunc->n_left = funcnp;
629*7c478bd9Sstevel@tonic-gate 	asortfunc->n_right->n_left = array;
630*7c478bd9Sstevel@tonic-gate 	asarraylen = wcslen(array->n_name)+1;
631*7c478bd9Sstevel@tonic-gate 	alist = (NODE **) emalloc(nel*sizeof(NODE *));
632*7c478bd9Sstevel@tonic-gate 	/*
633*7c478bd9Sstevel@tonic-gate 	 * Copy array into alist.
634*7c478bd9Sstevel@tonic-gate 	 */
635*7c478bd9Sstevel@tonic-gate 	npp = alist;
636*7c478bd9Sstevel@tonic-gate 	for (tnp = array->n_alink; tnp != NNULL; tnp = tnp->n_alink)
637*7c478bd9Sstevel@tonic-gate 		*npp++ = tnp;
638*7c478bd9Sstevel@tonic-gate 	*npp = NNULL;
639*7c478bd9Sstevel@tonic-gate 	/*
640*7c478bd9Sstevel@tonic-gate 	 * Re-order array to this list
641*7c478bd9Sstevel@tonic-gate 	 */
642*7c478bd9Sstevel@tonic-gate 	qsort((wchar_t *)alist, nel-1, sizeof (NODE *), asortcmp);
643*7c478bd9Sstevel@tonic-gate 	tnp = array;
644*7c478bd9Sstevel@tonic-gate 	npp = alist;
645*7c478bd9Sstevel@tonic-gate 	do {
646*7c478bd9Sstevel@tonic-gate 		tnp = tnp->n_alink = *npp;
647*7c478bd9Sstevel@tonic-gate 	} while (*npp++ != NNULL);
648*7c478bd9Sstevel@tonic-gate 	free((wchar_t *)alist);
649*7c478bd9Sstevel@tonic-gate 	return (constundef);
650*7c478bd9Sstevel@tonic-gate }
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate /*
653*7c478bd9Sstevel@tonic-gate  * Return the number of arguments of a function.
654*7c478bd9Sstevel@tonic-gate  */
655*7c478bd9Sstevel@tonic-gate static uint
nargs(NODE * np)656*7c478bd9Sstevel@tonic-gate nargs(NODE *np)
657*7c478bd9Sstevel@tonic-gate {
658*7c478bd9Sstevel@tonic-gate 	register int n;
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	if (np == NNULL)
661*7c478bd9Sstevel@tonic-gate 		return (0);
662*7c478bd9Sstevel@tonic-gate 	n = 1;
663*7c478bd9Sstevel@tonic-gate 	while (np!=NNULL && np->n_type==COMMA) {
664*7c478bd9Sstevel@tonic-gate 		np = np->n_right;
665*7c478bd9Sstevel@tonic-gate 		n++;
666*7c478bd9Sstevel@tonic-gate 	}
667*7c478bd9Sstevel@tonic-gate 	return (n);
668*7c478bd9Sstevel@tonic-gate }
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate /*
671*7c478bd9Sstevel@tonic-gate  * Do case translation.
672*7c478bd9Sstevel@tonic-gate  */
673*7c478bd9Sstevel@tonic-gate static NODE *
docasetr(NODE * np,int upper)674*7c478bd9Sstevel@tonic-gate docasetr(NODE *np, int upper)
675*7c478bd9Sstevel@tonic-gate {
676*7c478bd9Sstevel@tonic-gate 	register int c;
677*7c478bd9Sstevel@tonic-gate 	register wchar_t *cp;
678*7c478bd9Sstevel@tonic-gate 	register wchar_t *str;
679*7c478bd9Sstevel@tonic-gate 	register uint na;
680*7c478bd9Sstevel@tonic-gate 
681*7c478bd9Sstevel@tonic-gate 	if ((na = nargs(np)) > 1)
682*7c478bd9Sstevel@tonic-gate 		awkerr(nargerr, upper ? s_toupper : s_tolower);
683*7c478bd9Sstevel@tonic-gate 	str = strsave(na==0 ? linebuf : exprstring(getlist(&np)));
684*7c478bd9Sstevel@tonic-gate 	cp = str;
685*7c478bd9Sstevel@tonic-gate 	if (upper) {
686*7c478bd9Sstevel@tonic-gate 		while ((c = *cp++) != '\0')
687*7c478bd9Sstevel@tonic-gate 			cp[-1] = towupper(c);
688*7c478bd9Sstevel@tonic-gate 	} else {
689*7c478bd9Sstevel@tonic-gate 		while ((c = *cp++) != '\0')
690*7c478bd9Sstevel@tonic-gate 			cp[-1] = towlower(c);
691*7c478bd9Sstevel@tonic-gate 	}
692*7c478bd9Sstevel@tonic-gate 	return (stringnode((STRING)str, FNOALLOC, (size_t)(cp-str-1)));
693*7c478bd9Sstevel@tonic-gate }
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate /*
696*7c478bd9Sstevel@tonic-gate  * The comparison routine used by qsort inside f_asort()
697*7c478bd9Sstevel@tonic-gate  */
698*7c478bd9Sstevel@tonic-gate static int
asortcmp(const void * npp1,const void * npp2)699*7c478bd9Sstevel@tonic-gate asortcmp(const void *npp1, const void *npp2)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate 	asnp1->n_strlen =
702*7c478bd9Sstevel@tonic-gate 	    wcslen(asnp1->n_string = (*(NODE **)npp1)->n_name+asarraylen);
703*7c478bd9Sstevel@tonic-gate 	asnp2->n_strlen =
704*7c478bd9Sstevel@tonic-gate 	    wcslen(asnp2->n_string = (*(NODE **)npp2)->n_name+asarraylen);
705*7c478bd9Sstevel@tonic-gate 	return ((int)exprint(asortfunc));
706*7c478bd9Sstevel@tonic-gate }
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate #if M_MATHERR
709*7c478bd9Sstevel@tonic-gate #if !defined(__BORLANDC__)&&defined(__TURBOC__)&&__COMPACT__&&__EMULATE__
710*7c478bd9Sstevel@tonic-gate /* So it won't optimize registers our FP is using */
711*7c478bd9Sstevel@tonic-gate #define	flushesbx()	(_BX = 0, _ES = _BX)
712*7c478bd9Sstevel@tonic-gate #else
713*7c478bd9Sstevel@tonic-gate #define	flushesbx()	(0)
714*7c478bd9Sstevel@tonic-gate #endif
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate /*
717*7c478bd9Sstevel@tonic-gate  * Math error for awk.
718*7c478bd9Sstevel@tonic-gate  */
719*7c478bd9Sstevel@tonic-gate int
matherr(struct exception * ep)720*7c478bd9Sstevel@tonic-gate matherr(struct exception *ep)
721*7c478bd9Sstevel@tonic-gate {
722*7c478bd9Sstevel@tonic-gate 	register uint type;
723*7c478bd9Sstevel@tonic-gate 	static char msgs[7][256];
724*7c478bd9Sstevel@tonic-gate 	static int first_time = 1;
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 	if (first_time) {
727*7c478bd9Sstevel@tonic-gate 		msgs[0] = gettext("Unknown FP error"),
728*7c478bd9Sstevel@tonic-gate 		msgs[1] = gettext("Domain"),
729*7c478bd9Sstevel@tonic-gate 		msgs[2] = gettext("Singularity"),
730*7c478bd9Sstevel@tonic-gate 		msgs[3] = gettext("Overflow"),
731*7c478bd9Sstevel@tonic-gate 		msgs[4] = gettext("Underflow"),
732*7c478bd9Sstevel@tonic-gate 		msgs[5] = gettext("Total loss of precision"),
733*7c478bd9Sstevel@tonic-gate 		msgs[6] = gettext("Partial loss of precision")
734*7c478bd9Sstevel@tonic-gate 		first_time = 0;
735*7c478bd9Sstevel@tonic-gate 	}
736*7c478bd9Sstevel@tonic-gate 
737*7c478bd9Sstevel@tonic-gate 	if ((type = ep->type) > (uint)PLOSS)
738*7c478bd9Sstevel@tonic-gate 		type = 0;
739*7c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr, "awk: %s", strmsg(msgs[type]));
740*7c478bd9Sstevel@tonic-gate 	(void)fprintf(stderr, gettext(
741*7c478bd9Sstevel@tonic-gate 		" error in function %s(%g) at NR=%lld\n"),
742*7c478bd9Sstevel@tonic-gate 		((void) flushesbx(), ep->name), ep->arg1, (INT)exprint(varNR));
743*7c478bd9Sstevel@tonic-gate 	return (1);
744*7c478bd9Sstevel@tonic-gate }
745*7c478bd9Sstevel@tonic-gate #endif	/*M_MATHERR*/
746