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
38 static uint
nargs(NODE
*np
);
39 static NODE
*dosub(NODE
*np
, int glob
);
40 static NODE
*docasetr(NODE
*np
, int upper
);
41 static int asortcmp(const void *npp1
, const void *npp2
);
43 static char nargerr
[] = "wrong number of arguments to function \"%s\"";
44 static NODE
*asortfunc
; /* Function call for asort() */
45 static NODE
*asnp1
, *asnp2
; /* index1, index2 nodes */
46 static int asarraylen
; /* strlen(array)+1 for asort */
49 * Return the value of exp(x).
58 if ((na
= nargs(np
)) > 1)
59 awkerr(nargerr
, s_exp
);
60 return (realnode(exp(exprreal(na
==0 ? field0
: getlist(&np
)))));
64 * Return the integer part of the argument.
73 if ((na
= nargs(np
)) > 1)
74 awkerr(nargerr
, s_int
);
75 return (intnode(exprint(na
==0 ? field0
: getlist(&np
))));
88 if ((na
= nargs(np
)) > 1)
89 awkerr(nargerr
, s_log
);
90 return (realnode(log(exprreal(na
==0 ? field0
: getlist(&np
)))));
94 * Square root function.
103 if ((na
= nargs(np
)) > 1)
104 awkerr(nargerr
, s_sqrt
);
105 return (realnode(sqrt(exprreal(na
==0 ? field0
: getlist(&np
)))));
109 * Trigonometric sine function.
116 awkerr(nargerr
, s_sin
);
117 return (realnode(sin(exprreal(getlist(&np
)))));
121 * Trigonometric cosine function.
128 awkerr(nargerr
, s_cos
);
129 return (realnode(cos(exprreal(getlist(&np
)))));
134 * Usage: z = atan2(y, x)
142 awkerr(nargerr
, s_atan2
);
143 y
= (double)exprreal(getlist(&np
));
144 x
= (double)exprreal(getlist(&np
));
145 return (realnode(atan2(y
, x
)));
149 * Set the seed for the random number generator function -- rand.
158 static uint oldseed
= 0;
160 if ((na
= nargs(np
)) > 1)
161 awkerr(nargerr
, s_srand
);
163 seed
= (uint
)time((time_t *)0); else
164 seed
= (uint
)exprint(getlist(&np
));
168 return (intnode((INT
)na
));
172 * Generate a random number.
183 awkerr(nargerr
, s_rand
);
184 rint
= rand() & SHRT_MAX
;
185 result
= frexp((double)rint
, &expon
);
186 return (realnode((REAL
)ldexp(result
, expon
-15)));
190 * Substitute function.
191 * Usage: n = sub(regex, replace, target)
192 * n = sub(regex, replace)
197 return (dosub(np
, 1));
201 * Global substitution function.
202 * Usage: n = gsub(regex, replace, target)
203 * n = gsub(regex, replace)
208 return (dosub(np
, 0));
212 * Do actual substitutions.
213 * `glob' is the number to substitute, 0 for all.
216 dosub(NODE
*np
, int glob
)
219 register wchar_t *sub
;
226 if ((na
= nargs(np
)) != 2 && na
!= 3)
227 awkerr(nargerr
, glob
==0 ? s_gsub
: s_sub
);
228 rp
= getregexp(getlist(&np
));
229 sub
= exprstring(getlist(&np
));
232 text
= exprstring(left
);
237 switch (REGWDOSUBA(rp
, sub
, text
, &buf
, 256, &glob
)) {
247 awkerr(gettext("regular expression error"));
249 (void)assign(left
, stringnode(buf
, FNOALLOC
, wcslen(buf
)));
250 return (intnode((INT
)n
));
254 * Match function. Return position (origin 1) or 0 for regular
255 * expression match in string. Set new variables RSTART and RLENGTH
257 * Usage: pos = match(string, re)
262 register wchar_t *text
;
264 register int pos
, length
;
265 REGWMATCH_T match
[10];
268 awkerr(nargerr
, s_match
);
269 text
= exprstring(getlist(&np
));
270 rp
= getregexp(getlist(&np
));
271 if (REGWEXEC(rp
, text
, 10, match
, 0) == REG_OK
) {
272 pos
= match
[0].rm_sp
-text
+1;
273 length
= match
[0].rm_ep
- match
[0].rm_sp
;
278 constant
->n_int
= length
;
279 (void)assign(vlook(M_MB_L("RLENGTH")), constant
);
280 return (assign(vlook(M_MB_L("RSTART")), intnode((INT
)pos
)));
284 * Call shell or command interpreter.
285 * Usage: status = system(command)
293 awkerr(nargerr
, s_system
);
294 (void) fflush(stdout
);
295 retcode
= system(mbunconvert(exprstring(getlist(&np
))));
296 return (intnode((INT
)WEXITSTATUS(retcode
)));
300 * Search for string within string.
301 * Usage: pos = index(string1, string2)
306 register wchar_t *s1
, *s2
;
311 awkerr(nargerr
, s_index
);
312 s1
= (wchar_t *)exprstring(getlist(&np
));
313 s2
= (wchar_t *)exprstring(getlist(&np
));
318 if (memcmp(s1
, s2
, l2
* sizeof(wchar_t)) == 0)
326 return (intnode((INT
)result
));
330 * Return length of argument or $0
331 * Usage: n = length(string)
340 if ((na
= nargs(np
)) > 1)
341 awkerr(nargerr
, s_length
);
344 na
= wcslen((wchar_t *)exprstring(getlist(&np
)));
345 return (intnode((INT
)na
));
349 * Split string into fields.
350 * Usage: nfields = split(string, array [, separator]);
355 register wchar_t *cp
;
356 wchar_t *ep
, *saved
= 0;
357 register NODE
*tnp
, *snp
, *otnp
;
359 REGEXP old_resep
= 0;
364 wchar_t *(*old_awkfield
)(wchar_t **) = 0;
366 if ((n
= nargs(np
))<2 || n
>3)
367 awkerr(nargerr
, s_split
);
368 ep
= exprstring(snp
= getlist(&np
));
370 if (snp
->n_type
== INDEX
&& snp
->n_left
== tnp
)
371 ep
= saved
= wsdup(ep
);
376 switch (tnp
->n_type
) {
385 if (isstring(tnp
->n_flags
) && tnp
->n_string
==_null
)
391 "second parameter to \"split\" must be an array"));
394 * If an argument has been passed in to be used as the
395 * field separator check to see if it is a constant regular
396 * expression. If so, use it directly otherwise reduce the
397 * expression, convert the result into a string and assign it
398 * to "FS" (after saving the old value for FS.)
401 if (sep
->n_type
== PARM
)
403 if (sep
->n_type
== RE
) {
405 resep
= sep
->n_regexp
;
406 old_awkfield
= awkfield
;
409 sep
= exprreduce(sep
);
410 seplen
= wcslen(cp
= (wchar_t *)exprstring(varFS
));
411 (void) memcpy(savesep
, cp
,
412 (seplen
+1) * sizeof(wchar_t));
413 (void) assign(varFS
, sep
);
417 * Iterate over the record, extracting each field and assigning it to
418 * the corresponding element in the array.
420 otnp
= tnp
; /* save tnp for possible promotion */
421 tnp
= node(INDEX
, tnp
, constant
);
424 if ((cp
= (*awkfield
)(&ep
)) == NULL
) {
426 if (otnp
->n_type
== PARM
)
434 constant
->n_int
= ++fcount
;
435 (void)assign(tnp
, stringnode(cp
,FALLOC
|FSENSE
,(size_t)(ep
-cp
)));
439 * Restore the old record separator/and or regular expression.
442 if (old_awkfield
!= 0) {
444 awkfield
= old_awkfield
;
447 stringnode(savesep
, FSTATIC
, seplen
));
452 return (intnode((INT
)fcount
));
457 * Usage: string = sprintf(format, arg, ...)
466 awkerr(nargerr
, s_sprintf
);
467 length
= xprintf(np
, (FILE *)NULL
, &cp
);
468 np
= stringnode(cp
, FNOALLOC
, length
);
474 * newstring = substr(string, start, [length])
484 if ((n
= nargs(np
))<2 || n
>3)
485 awkerr(nargerr
, s_substr
);
486 str
= exprstring(getlist(&np
));
487 if ((start
= (int)exprint(getlist(&np
))-1) < 0)
491 x
= (int)exprint(getlist(&np
));
498 n
= wcslen((wchar_t *)str
);
507 np
= stringnode(str
, FALLOC
, len
);
513 * Close an output or input file stream.
522 awkerr(nargerr
, s_close
);
523 name
= mbunconvert(exprstring(getlist(&np
)));
524 for (op
= &ofiles
[0]; op
< &ofiles
[NIOSTREAM
]; op
++)
525 if (op
->f_fp
!=FNULL
&& strcmp(name
, op
->f_name
)==0) {
529 if (op
>= &ofiles
[NIOSTREAM
])
535 * Return the integer value of the first character of a string.
536 * Usage: char = ord(string)
542 awkerr(nargerr
, s_ord
);
543 return (intnode((INT
)*exprstring(getlist(&np
))));
547 * Return the argument string in lower case:
549 * lower = tolower(upper)
554 return (docasetr(np
, 0));
558 * Return the argument string in upper case:
560 * upper = toupper(lower)
565 return (docasetr(np
, 1));
569 * Sort the array into traversal order by the next "for (i in array)" loop.
571 * asort(array, "cmpfunc")
572 * cmpfunc(array, index1, index2)
574 * <0 if array[index1] < array[index2]
575 * 0 if array[index1] == array[index2]
576 * >0 if array[index1] > array[index2]
585 register NODE
*funcnp
;
586 register NODE
**alist
, **npp
;
589 awkerr(nargerr
, s_asort
);
590 array
= getlist(&np
);
591 if (array
->n_type
== PARM
)
592 array
= array
->n_next
;
593 if (array
->n_type
!= ARRAY
)
594 awkerr(gettext("%s function requires an array"),
596 funcname
= exprstring(getlist(&np
));
597 if ((funcnp
= vlookup(funcname
, 1)) == NNULL
598 || funcnp
->n_type
!= UFUNC
)
599 awkerr(gettext("%s: %s is not a function\n"),
602 * Count size of array, allowing one extra for NULL at end
605 for (tnp
= array
->n_alink
; tnp
!= NNULL
; tnp
= tnp
->n_alink
)
608 * Create UFUNC node that points at the funcnp on left and the
609 * list of three variables on right (array, index1, index2)
618 if (asortfunc
== NNULL
) {
620 asortfunc
= node(CALLUFUNC
, NNULL
,
623 asnp1
=stringnode(_null
, FSTATIC
, 0),
624 asnp2
=stringnode(_null
, FSTATIC
, 0))));
627 asortfunc
->n_left
= funcnp
;
628 asortfunc
->n_right
->n_left
= array
;
629 asarraylen
= wcslen(array
->n_name
)+1;
630 alist
= (NODE
**) emalloc(nel
*sizeof(NODE
*));
632 * Copy array into alist.
635 for (tnp
= array
->n_alink
; tnp
!= NNULL
; tnp
= tnp
->n_alink
)
639 * Re-order array to this list
641 qsort((wchar_t *)alist
, nel
-1, sizeof (NODE
*), asortcmp
);
645 tnp
= tnp
->n_alink
= *npp
;
646 } while (*npp
++ != NNULL
);
647 free((wchar_t *)alist
);
652 * Return the number of arguments of a function.
662 while (np
!=NNULL
&& np
->n_type
==COMMA
) {
670 * Do case translation.
673 docasetr(NODE
*np
, int upper
)
676 register wchar_t *cp
;
677 register wchar_t *str
;
680 if ((na
= nargs(np
)) > 1)
681 awkerr(nargerr
, upper
? s_toupper
: s_tolower
);
682 str
= strsave(na
==0 ? linebuf
: exprstring(getlist(&np
)));
685 while ((c
= *cp
++) != '\0')
686 cp
[-1] = towupper(c
);
688 while ((c
= *cp
++) != '\0')
689 cp
[-1] = towlower(c
);
691 return (stringnode((STRING
)str
, FNOALLOC
, (size_t)(cp
-str
-1)));
695 * The comparison routine used by qsort inside f_asort()
698 asortcmp(const void *npp1
, const void *npp2
)
701 wcslen(asnp1
->n_string
= (*(NODE
**)npp1
)->n_name
+asarraylen
);
703 wcslen(asnp2
->n_string
= (*(NODE
**)npp2
)->n_name
+asarraylen
);
704 return ((int)exprint(asortfunc
));
708 #if !defined(__BORLANDC__)&&defined(__TURBOC__)&&__COMPACT__&&__EMULATE__
709 /* So it won't optimize registers our FP is using */
710 #define flushesbx() (_BX = 0, _ES = _BX)
712 #define flushesbx() (0)
716 * Math error for awk.
719 matherr(struct exception
*ep
)
722 static char msgs
[7][256];
723 static int first_time
= 1;
726 msgs
[0] = gettext("Unknown FP error"),
727 msgs
[1] = gettext("Domain"),
728 msgs
[2] = gettext("Singularity"),
729 msgs
[3] = gettext("Overflow"),
730 msgs
[4] = gettext("Underflow"),
731 msgs
[5] = gettext("Total loss of precision"),
732 msgs
[6] = gettext("Partial loss of precision")
736 if ((type
= ep
->type
) > (uint
)PLOSS
)
738 (void)fprintf(stderr
, "awk: %s", strmsg(msgs
[type
]));
739 (void)fprintf(stderr
, gettext(
740 " error in function %s(%g) at NR=%lld\n"),
741 ((void) flushesbx(), ep
->name
), ep
->arg1
, (INT
)exprint(varNR
));