4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
25 * Copyright (c) 1995, 1996 by Sun Microsystems, Inc.
26 * All rights reserved.
28 * Copyright 1986, 1994 by Mortice Kern Systems Inc. All rights reserved.
30 * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes
33 #pragma ident "%Z%%M% %I% %E% SMI"
40 static uint
nargs(NODE
*np
);
41 static NODE
*dosub(NODE
*np
, int glob
);
42 static NODE
*docasetr(NODE
*np
, int upper
);
43 static int asortcmp(const void *npp1
, const void *npp2
);
45 static char nargerr
[] = "wrong number of arguments to function \"%s\"";
46 static NODE
*asortfunc
; /* Function call for asort() */
47 static NODE
*asnp1
, *asnp2
; /* index1, index2 nodes */
48 static int asarraylen
; /* strlen(array)+1 for asort */
51 * Return the value of exp(x).
60 if ((na
= nargs(np
)) > 1)
61 awkerr(nargerr
, s_exp
);
62 return (realnode(exp(exprreal(na
==0 ? field0
: getlist(&np
)))));
66 * Return the integer part of the argument.
75 if ((na
= nargs(np
)) > 1)
76 awkerr(nargerr
, s_int
);
77 return (intnode(exprint(na
==0 ? field0
: getlist(&np
))));
90 if ((na
= nargs(np
)) > 1)
91 awkerr(nargerr
, s_log
);
92 return (realnode(log(exprreal(na
==0 ? field0
: getlist(&np
)))));
96 * Square root function.
105 if ((na
= nargs(np
)) > 1)
106 awkerr(nargerr
, s_sqrt
);
107 return (realnode(sqrt(exprreal(na
==0 ? field0
: getlist(&np
)))));
111 * Trigonometric sine function.
118 awkerr(nargerr
, s_sin
);
119 return (realnode(sin(exprreal(getlist(&np
)))));
123 * Trigonometric cosine function.
130 awkerr(nargerr
, s_cos
);
131 return (realnode(cos(exprreal(getlist(&np
)))));
136 * Usage: z = atan2(y, x)
144 awkerr(nargerr
, s_atan2
);
145 y
= (double)exprreal(getlist(&np
));
146 x
= (double)exprreal(getlist(&np
));
147 return (realnode(atan2(y
, x
)));
151 * Set the seed for the random number generator function -- rand.
160 static uint oldseed
= 0;
162 if ((na
= nargs(np
)) > 1)
163 awkerr(nargerr
, s_srand
);
165 seed
= (uint
)time((time_t *)0); else
166 seed
= (uint
)exprint(getlist(&np
));
170 return (intnode((INT
)na
));
174 * Generate a random number.
185 awkerr(nargerr
, s_rand
);
186 rint
= rand() & SHRT_MAX
;
187 result
= frexp((double)rint
, &expon
);
188 return (realnode((REAL
)ldexp(result
, expon
-15)));
192 * Substitute function.
193 * Usage: n = sub(regex, replace, target)
194 * n = sub(regex, replace)
199 return (dosub(np
, 1));
203 * Global substitution function.
204 * Usage: n = gsub(regex, replace, target)
205 * n = gsub(regex, replace)
210 return (dosub(np
, 0));
214 * Do actual substitutions.
215 * `glob' is the number to substitute, 0 for all.
218 dosub(NODE
*np
, int glob
)
221 register wchar_t *sub
;
228 if ((na
= nargs(np
)) != 2 && na
!= 3)
229 awkerr(nargerr
, glob
==0 ? s_gsub
: s_sub
);
230 rp
= getregexp(getlist(&np
));
231 sub
= exprstring(getlist(&np
));
234 text
= exprstring(left
);
239 switch (REGWDOSUBA(rp
, sub
, text
, &buf
, 256, &glob
)) {
249 awkerr(gettext("regular expression error"));
251 (void)assign(left
, stringnode(buf
, FNOALLOC
, wcslen(buf
)));
252 return (intnode((INT
)n
));
256 * Match function. Return position (origin 1) or 0 for regular
257 * expression match in string. Set new variables RSTART and RLENGTH
259 * Usage: pos = match(string, re)
264 register wchar_t *text
;
266 register int pos
, length
;
267 REGWMATCH_T match
[10];
270 awkerr(nargerr
, s_match
);
271 text
= exprstring(getlist(&np
));
272 rp
= getregexp(getlist(&np
));
273 if (REGWEXEC(rp
, text
, 10, match
, 0) == REG_OK
) {
274 pos
= match
[0].rm_sp
-text
+1;
275 length
= match
[0].rm_ep
- match
[0].rm_sp
;
280 constant
->n_int
= length
;
281 (void)assign(vlook(M_MB_L("RLENGTH")), constant
);
282 return (assign(vlook(M_MB_L("RSTART")), intnode((INT
)pos
)));
286 * Call shell or command interpreter.
287 * Usage: status = system(command)
295 awkerr(nargerr
, s_system
);
296 (void) fflush(stdout
);
297 retcode
= system(mbunconvert(exprstring(getlist(&np
))));
298 return (intnode((INT
)WEXITSTATUS(retcode
)));
302 * Search for string within string.
303 * Usage: pos = index(string1, string2)
308 register wchar_t *s1
, *s2
;
313 awkerr(nargerr
, s_index
);
314 s1
= (wchar_t *)exprstring(getlist(&np
));
315 s2
= (wchar_t *)exprstring(getlist(&np
));
320 if (memcmp(s1
, s2
, l2
* sizeof(wchar_t)) == 0)
328 return (intnode((INT
)result
));
332 * Return length of argument or $0
333 * Usage: n = length(string)
342 if ((na
= nargs(np
)) > 1)
343 awkerr(nargerr
, s_length
);
346 na
= wcslen((wchar_t *)exprstring(getlist(&np
)));
347 return (intnode((INT
)na
));
351 * Split string into fields.
352 * Usage: nfields = split(string, array [, separator]);
357 register wchar_t *cp
;
358 wchar_t *ep
, *saved
= 0;
359 register NODE
*tnp
, *snp
, *otnp
;
361 REGEXP old_resep
= 0;
366 wchar_t *(*old_awkfield
)(wchar_t **) = 0;
368 if ((n
= nargs(np
))<2 || n
>3)
369 awkerr(nargerr
, s_split
);
370 ep
= exprstring(snp
= getlist(&np
));
372 if (snp
->n_type
== INDEX
&& snp
->n_left
== tnp
)
373 ep
= saved
= wsdup(ep
);
378 switch (tnp
->n_type
) {
387 if (isstring(tnp
->n_flags
) && tnp
->n_string
==_null
)
391 "second parameter to \"split\" must be an array"));
395 * If an argument has been passed in to be used as the
396 * field separator check to see if it is a constant regular
397 * expression. If so, use it directly otherwise reduce the
398 * expression, convert the result into a string and assign it
399 * to "FS" (after saving the old value for FS.)
402 if (sep
->n_type
== PARM
)
404 if (sep
->n_type
== RE
) {
406 resep
= sep
->n_regexp
;
407 old_awkfield
= awkfield
;
410 sep
= exprreduce(sep
);
411 seplen
= wcslen(cp
= (wchar_t *)exprstring(varFS
));
412 (void) memcpy(savesep
, cp
,
413 (seplen
+1) * sizeof(wchar_t));
414 (void) assign(varFS
, sep
);
418 * Iterate over the record, extracting each field and assigning it to
419 * the corresponding element in the array.
421 otnp
= tnp
; /* save tnp for possible promotion */
422 tnp
= node(INDEX
, tnp
, constant
);
425 if ((cp
= (*awkfield
)(&ep
)) == NULL
) {
427 if (otnp
->n_type
== PARM
)
435 constant
->n_int
= ++fcount
;
436 (void)assign(tnp
, stringnode(cp
,FALLOC
|FSENSE
,(size_t)(ep
-cp
)));
440 * Restore the old record separator/and or regular expression.
443 if (old_awkfield
!= 0) {
445 awkfield
= old_awkfield
;
448 stringnode(savesep
, FSTATIC
, seplen
));
453 return (intnode((INT
)fcount
));
458 * Usage: string = sprintf(format, arg, ...)
467 awkerr(nargerr
, s_sprintf
);
468 length
= xprintf(np
, (FILE *)NULL
, &cp
);
469 np
= stringnode(cp
, FNOALLOC
, length
);
475 * newstring = substr(string, start, [length])
485 if ((n
= nargs(np
))<2 || n
>3)
486 awkerr(nargerr
, s_substr
);
487 str
= exprstring(getlist(&np
));
488 if ((start
= (int)exprint(getlist(&np
))-1) < 0)
492 x
= (int)exprint(getlist(&np
));
499 n
= wcslen((wchar_t *)str
);
508 np
= stringnode(str
, FALLOC
, len
);
514 * Close an output or input file stream.
523 awkerr(nargerr
, s_close
);
524 name
= mbunconvert(exprstring(getlist(&np
)));
525 for (op
= &ofiles
[0]; op
< &ofiles
[NIOSTREAM
]; op
++)
526 if (op
->f_fp
!=FNULL
&& strcmp(name
, op
->f_name
)==0) {
530 if (op
>= &ofiles
[NIOSTREAM
])
536 * Return the integer value of the first character of a string.
537 * Usage: char = ord(string)
543 awkerr(nargerr
, s_ord
);
544 return (intnode((INT
)*exprstring(getlist(&np
))));
548 * Return the argument string in lower case:
550 * lower = tolower(upper)
555 return (docasetr(np
, 0));
559 * Return the argument string in upper case:
561 * upper = toupper(lower)
566 return (docasetr(np
, 1));
570 * Sort the array into traversal order by the next "for (i in array)" loop.
572 * asort(array, "cmpfunc")
573 * cmpfunc(array, index1, index2)
575 * <0 if array[index1] < array[index2]
576 * 0 if array[index1] == array[index2]
577 * >0 if array[index1] > array[index2]
586 register NODE
*funcnp
;
587 register NODE
**alist
, **npp
;
590 awkerr(nargerr
, s_asort
);
591 array
= getlist(&np
);
592 if (array
->n_type
== PARM
)
593 array
= array
->n_next
;
594 if (array
->n_type
!= ARRAY
)
595 awkerr(gettext("%s function requires an array"),
597 funcname
= exprstring(getlist(&np
));
598 if ((funcnp
= vlookup(funcname
, 1)) == NNULL
599 || funcnp
->n_type
!= UFUNC
)
600 awkerr(gettext("%s: %s is not a function\n"),
603 * Count size of array, allowing one extra for NULL at end
606 for (tnp
= array
->n_alink
; tnp
!= NNULL
; tnp
= tnp
->n_alink
)
609 * Create UFUNC node that points at the funcnp on left and the
610 * list of three variables on right (array, index1, index2)
619 if (asortfunc
== NNULL
) {
621 asortfunc
= node(CALLUFUNC
, NNULL
,
624 asnp1
=stringnode(_null
, FSTATIC
, 0),
625 asnp2
=stringnode(_null
, FSTATIC
, 0))));
628 asortfunc
->n_left
= funcnp
;
629 asortfunc
->n_right
->n_left
= array
;
630 asarraylen
= wcslen(array
->n_name
)+1;
631 alist
= (NODE
**) emalloc(nel
*sizeof(NODE
*));
633 * Copy array into alist.
636 for (tnp
= array
->n_alink
; tnp
!= NNULL
; tnp
= tnp
->n_alink
)
640 * Re-order array to this list
642 qsort((wchar_t *)alist
, nel
-1, sizeof (NODE
*), asortcmp
);
646 tnp
= tnp
->n_alink
= *npp
;
647 } while (*npp
++ != NNULL
);
648 free((wchar_t *)alist
);
653 * Return the number of arguments of a function.
663 while (np
!=NNULL
&& np
->n_type
==COMMA
) {
671 * Do case translation.
674 docasetr(NODE
*np
, int upper
)
677 register wchar_t *cp
;
678 register wchar_t *str
;
681 if ((na
= nargs(np
)) > 1)
682 awkerr(nargerr
, upper
? s_toupper
: s_tolower
);
683 str
= strsave(na
==0 ? linebuf
: exprstring(getlist(&np
)));
686 while ((c
= *cp
++) != '\0')
687 cp
[-1] = towupper(c
);
689 while ((c
= *cp
++) != '\0')
690 cp
[-1] = towlower(c
);
692 return (stringnode((STRING
)str
, FNOALLOC
, (size_t)(cp
-str
-1)));
696 * The comparison routine used by qsort inside f_asort()
699 asortcmp(const void *npp1
, const void *npp2
)
702 wcslen(asnp1
->n_string
= (*(NODE
**)npp1
)->n_name
+asarraylen
);
704 wcslen(asnp2
->n_string
= (*(NODE
**)npp2
)->n_name
+asarraylen
);
705 return ((int)exprint(asortfunc
));
709 #if !defined(__BORLANDC__)&&defined(__TURBOC__)&&__COMPACT__&&__EMULATE__
710 /* So it won't optimize registers our FP is using */
711 #define flushesbx() (_BX = 0, _ES = _BX)
713 #define flushesbx() (0)
717 * Math error for awk.
720 matherr(struct exception
*ep
)
723 static char msgs
[7][256];
724 static int first_time
= 1;
727 msgs
[0] = gettext("Unknown FP error"),
728 msgs
[1] = gettext("Domain"),
729 msgs
[2] = gettext("Singularity"),
730 msgs
[3] = gettext("Overflow"),
731 msgs
[4] = gettext("Underflow"),
732 msgs
[5] = gettext("Total loss of precision"),
733 msgs
[6] = gettext("Partial loss of precision")
737 if ((type
= ep
->type
) > (uint
)PLOSS
)
739 (void)fprintf(stderr
, "awk: %s", strmsg(msgs
[type
]));
740 (void)fprintf(stderr
, gettext(
741 " error in function %s(%g) at NR=%lld\n"),
742 ((void) flushesbx(), ep
->name
), ep
->arg1
, (INT
)exprint(varNR
));