From 5ea9e707be09a1df0407e195a11908f6fac19e14 Mon Sep 17 00:00:00 2001 From: Thomas Veerman Date: Wed, 6 Jun 2012 13:03:39 +0000 Subject: [PATCH] Import NetBSD nawk --- commands/Makefile | 2 +- commands/awk/Makefile | 25 - external/Makefile | 2 +- external/historical/Makefile | 7 + external/historical/nawk/Makefile | 5 + external/historical/nawk/bin/Makefile | 41 + external/historical/nawk/bin/TODO | 22 + external/historical/nawk/bin/awk.1 | 732 ++++++++++++++++++ .../historical/nawk/dist}/FIXES | 7 + .../historical/nawk/dist}/README | 0 .../historical/nawk/dist}/awk.1 | 0 .../historical/nawk/dist}/awk.h | 18 +- .../historical/nawk/dist}/awkgram.y | 30 +- .../awk => external/historical/nawk/dist}/b.c | 383 +++++---- .../historical/nawk/dist}/lex.c | 40 +- .../historical/nawk/dist}/lib.c | 190 +++-- .../historical/nawk/dist}/main.c | 100 ++- .../historical/nawk/dist/makefile | 24 +- .../historical/nawk/dist}/maketab.c | 24 +- .../historical/nawk/dist}/parse.c | 29 +- external/historical/nawk/dist/proctab.c | 213 +++++ .../historical/nawk/dist}/proto.h | 41 +- .../historical/nawk/dist}/run.c | 589 ++++++++++---- .../historical/nawk/dist}/tran.c | 84 +- 24 files changed, 2122 insertions(+), 486 deletions(-) delete mode 100644 commands/awk/Makefile create mode 100644 external/historical/Makefile create mode 100644 external/historical/nawk/Makefile create mode 100644 external/historical/nawk/bin/Makefile create mode 100644 external/historical/nawk/bin/TODO create mode 100644 external/historical/nawk/bin/awk.1 rename {commands/awk => external/historical/nawk/dist}/FIXES (99%) rename {commands/awk => external/historical/nawk/dist}/README (100%) rename {commands/awk => external/historical/nawk/dist}/awk.1 (100%) rename {commands/awk => external/historical/nawk/dist}/awk.h (95%) rename {commands/awk => external/historical/nawk/dist}/awkgram.y (93%) rename {commands/awk => external/historical/nawk/dist}/b.c (74%) rename {commands/awk => external/historical/nawk/dist}/lex.c (94%) rename {commands/awk => external/historical/nawk/dist}/lib.c (79%) rename {commands/awk => external/historical/nawk/dist}/main.c (71%) rename commands/awk/Makefile.orig => external/historical/nawk/dist/makefile (85%) rename {commands/awk => external/historical/nawk/dist}/maketab.c (88%) rename {commands/awk => external/historical/nawk/dist}/parse.c (91%) create mode 100644 external/historical/nawk/dist/proctab.c rename {commands/awk => external/historical/nawk/dist}/proto.h (84%) rename {commands/awk => external/historical/nawk/dist}/run.c (76%) rename {commands/awk => external/historical/nawk/dist}/tran.c (87%) diff --git a/commands/Makefile b/commands/Makefile index 9ac6b4003..814f2aea4 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -2,7 +2,7 @@ .include -SUBDIR= add_route arp ash at awk \ +SUBDIR= add_route arp ash at \ backup badblocks banner basename \ btrace cal \ cawf cd cdprobe checkhier cpp \ diff --git a/commands/awk/Makefile b/commands/awk/Makefile deleted file mode 100644 index ea7d01eca..000000000 --- a/commands/awk/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -.include - -PROG= awk -SRCS= awkgram.y b.c lex.c lib.c main.c parse.c proctab.c run.c tran.c -LDADD= -lm -DEPEND+= ${LIBM} -YHEADER= yes -QUIET_YACC= yes - -CPPFLAGS+= -I. -I${.CURDIR} - -build-tools: maketab - -proctab.c: maketab - ./maketab > proctab.c - -maketab.lo: awkgram.h - - -maketab: maketab.lo - ${HOST_LINK.c} maketab.lo -o $@ - -CLEANFILES= maketab proctab.c maketab.lo - -.include diff --git a/external/Makefile b/external/Makefile index 4072adc24..a9ec2eb91 100644 --- a/external/Makefile +++ b/external/Makefile @@ -1,3 +1,3 @@ -SUBDIR=bsd +SUBDIR=bsd historical .include diff --git a/external/historical/Makefile b/external/historical/Makefile new file mode 100644 index 000000000..f2ce08513 --- /dev/null +++ b/external/historical/Makefile @@ -0,0 +1,7 @@ +# $NetBSD: Makefile,v 1.1 2010/08/26 14:57:15 christos Exp $ + +.include + +SUBDIR+= nawk + +.include diff --git a/external/historical/nawk/Makefile b/external/historical/nawk/Makefile new file mode 100644 index 000000000..f9ee78b82 --- /dev/null +++ b/external/historical/nawk/Makefile @@ -0,0 +1,5 @@ +# $NetBSD: Makefile,v 1.1 2010/08/26 14:57:16 christos Exp $ + +SUBDIR+= bin + +.include diff --git a/external/historical/nawk/bin/Makefile b/external/historical/nawk/bin/Makefile new file mode 100644 index 000000000..b421c3132 --- /dev/null +++ b/external/historical/nawk/bin/Makefile @@ -0,0 +1,41 @@ +# $NetBSD: Makefile,v 1.8 2011/08/16 10:45:37 christos Exp $ + +WARNS?= 4 +CWARNFLAGS.clang+= -Wno-self-assign + +.include + +BINDIR?= /usr/bin +DIST= ${.CURDIR}/../dist +.PATH: ${DIST} + +PROG= awk +SRCS= awkgram.y b.c lex.c lib.c main.c parse.c proctab.c run.c tran.c +CPPFLAGS+= -I${DIST} -I. +LDADD+= -lm +.if !defined(HOSTPROG) +DPADD+= ${LIBM} +.endif +YHEADER= yes +.if defined(HAVE_GCC) || defined(HAVE_PCC) +COPTS+= -Wno-pointer-sign +.endif +COPTS.run.c += -Wno-format-nonliteral +COPTS.tran.c += -Wno-format-nonliteral + +# info file originally from GNU awk 3.1.3, adjusted for nawk slightly +# Don't install on Minix, we don't have it. +#.PATH: ${NETBSDSRCDIR}/external/gpl2/gawk/dist +#TEXINFO= awk.info + +# During the tools build (from src/tools/awk/Makefile), +# src/tools/Makefile.host changes .CURDIR back and forth between +# src/tools/awk and src/usr.bin/awk. For some unknown reason, including +# bsd.info.mk here leads to the obj dir being created at the wrong time, +# while .CURDIR is src/usr.bin/awk. Work around the problem by not +# including bsd.info.mk when MKINFO=no. +.if ${MKINFO} != "no" +.include +.endif + +.include diff --git a/external/historical/nawk/bin/TODO b/external/historical/nawk/bin/TODO new file mode 100644 index 000000000..00e376739 --- /dev/null +++ b/external/historical/nawk/bin/TODO @@ -0,0 +1,22 @@ +$NetBSD: TODO,v 1.1 2010/08/26 14:57:16 christos Exp $ + +Besides general regression testing to ensure everything still works +with nawk instead of gawk, following GNU awk extensions should be implemented +or handled somehow (the list is probably incomplete, please add entries +if anything is missing): + +* String functions: gensub() (partly done, finish backref. support) +* (done) Time functions: strftime(), systime() +* --posix flag, which would switch off nawk extensions over POSIX awk (?) +* special file names: /dev/pid, /dev/ppid, /dev/pgrpid, /dev/user, + /dev/stdin, /dev/stdout, /dev/stderr, /dev/fd/X +* special variables: ARGIND, ERRNO, FIELDWIDTHS, IGNORECASE, RT + +Also, the manpage should be improved to be generally more helpful +and document extensions over what POSIX says about awk. + +Other misc: +* run.c: don't limit files[] to FOPEN_MAX (which is ridiculously low), + make the limit the current process open file limit +* nawk doesn't permit empty RE, like +// { do_something; } diff --git a/external/historical/nawk/bin/awk.1 b/external/historical/nawk/bin/awk.1 new file mode 100644 index 000000000..505971056 --- /dev/null +++ b/external/historical/nawk/bin/awk.1 @@ -0,0 +1,732 @@ +.\" $NetBSD: awk.1,v 1.2 2011/04/20 10:10:32 drochner Exp $ +.\" +.\" Copyright (C) Lucent Technologies 1997 +.\" All Rights Reserved +.\" +.\" Permission to use, copy, modify, and distribute this software and +.\" its documentation for any purpose and without fee is hereby +.\" granted, provided that the above copyright notice appear in all +.\" copies and that both that the copyright notice and this +.\" permission notice and warranty disclaimer appear in supporting +.\" documentation, and that the name Lucent Technologies or any of +.\" its entities not be used in advertising or publicity pertaining +.\" to distribution of the software without specific, written prior +.\" permission. +.\" +.\" LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +.\" IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +.\" SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +.\" ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +.\" THIS SOFTWARE. +.\" +.Dd May 25, 2008 +.Dt AWK 1 +.Os +.Sh NAME +.Nm awk +.Nd pattern-directed scanning and processing language +.Sh SYNOPSIS +.Nm +.Op Fl F Ar fs +.Op Fl v Ar var=value +.Op Fl safe +.Op Fl d Ns Op Ar N +.Op Ar prog | Fl f Ar filename +.Ar +.Nm +.Fl version +.Sh DESCRIPTION +.Nm +is the Bell Labs' implementation of the AWK programming language as +described in the +.Em The AWK Programming Language +by +A. V. Aho, B. W. Kernighan, and P. J. Weinberger. +.Pp +.Nm +scans each input +.Ar file +for lines that match any of a set of patterns specified literally in +.Ar prog +or in one or more files +specified as +.Fl f Ar filename . +With each pattern +there can be an associated action that will be performed +when a line of a +.Ar file +matches the pattern. +Each line is matched against the +pattern portion of every pattern-action statement; +the associated action is performed for each matched pattern. +The file name +.Ar - +means the standard input. +Any +.Ar file +of the form +.Ar var=value +is treated as an assignment, not a filename, +and is executed at the time it would have been opened if it were a filename. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl d Ns Op Ar N +Set debug level to specified number +.Ar N . +If the number is omitted, debug level is set to 1. +.It Fl f Ar filename +Read the AWK program source from specified file +.Ar filename , +instead of the first command line argument. +Multiple +.Fl f +options may be specified. +.It Fl F Ar fs +Set the input field separator +.Va FS +to the regular expression +.Ar fs . +.It Fl mr Ar NNN , Fl mf Ar NNN +Obsolete, no longer needed options. +Set limit on maximum record or +fields number. +.It Fl safe +Potentially unsafe functions such as +.Fn system +make the program abort (with a warning message). +.It Fl v Ar var Ns = Ns Ar value +Assign the value +.Ar value +to the variable +.Va var +before +.Ar prog +is executed. +Any number of +.Fl v +options may be present. +.It Fl version +Print +.Nm +version on standard output and exit. +.El +.Pp +An input line is normally made up of fields separated by white space, +or by regular expression +.Va FS . +The fields are denoted +.Va $1 , +.Va $2 , +\&..., while +.Va $0 +refers to the entire line. +If +.Va FS +is null, the input line is split into one field per character. +.Pp +A pattern-action statement has the form +.Lp +.Dl pattern \&{ action \&} +.Lp +A missing \&{ action \&} +means print the line; +a missing pattern always matches. +Pattern-action statements are separated by newlines or semicolons. +.Pp +An action is a sequence of statements. +Statements are terminated by +semicolons, newlines or right braces. +An empty +.Ar expression-list +stands for +.Va $0 . +String constants are quoted +.Em \&"\ \&" , +with the usual C escapes recognized within. +Expressions take on string or numeric values as appropriate, +and are built using the +.Sx Operators +(see next subsection). +Variables may be scalars, array elements +(denoted +.Va x[i] ) +or fields. +Variables are initialized to the null string. +Array subscripts may be any string, +not necessarily numeric; +this allows for a form of associative memory. +Multiple subscripts such as +.Va [i,j,k] +are permitted; the constituents are concatenated, +separated by the value of +.Va SUBSEP . +.Ss Operators +.Nm +operators, in order of decreasing precedence, are: +.Pp +.Bl -tag -width ident -compact +.It Ic (...) +Grouping +.It Ic $ +Field reference +.It Ic ++ -- +Increment and decrement, can be used either as postfix or prefix. +.It Ic ^ +Exponentiation (the +.Ic ** +form is also supported, and +.Ic **= +for the assignment operator). +.It + - \&! +Unary plus, unary minus and logical negation. +.It * / % +Multiplication, division and modulus. +.It + - +Addition and subtraction. +.It Ar space +String concatenation. +.It Ic \*[Lt] \*[Gt] +.It Ic \*[Le] \*[Ge] +.It Ic != == +Regular relational operators +.It Ic ~ !~ +Regular expression match and not match +.It Ic in +Array membership +.It Ic "\*[Am]\*[Am]" +Logical AND +.It Ic "||" +Logical OR +.It Ic ?: +C conditional expression. +This is used as +.Ar expr1 Ic \&? Ar expr2 Ic \&: Ar expr3 No . +If +.Ar expr1 +is true, the result value is +.Ar expr2 , +otherwise it is +.Ar expr3 . +Only one of +.Ar expr2 +and +.Ar expr3 +is evaluated. +.It Ic = += -= +.It Ic *= /= %= ^= +Assignment and Operator-Assignment +.El +.Ss Control Statements +The control statements are as follows: +.Pp +.Bl -hang -offset indent -width indent -compact +.It Ic if \&( Ar expression Ic \&) Ar statement Bq Ic else Ar statement +.It Ic while \&( Ar expression Ic \&) Ar statement +.It Ic for \&( Ar expression Ic \&; Ar expression Ic \&; \ +Ar expression Ic \&) Ar statement +.It Ic for \&( Va var Ic in Ar array Ic \&) Ar statement +.It Ic do Ar statement Ic while \&( Ar expression Ic \&) +.It Ic break +.It Ic continue +.It Ic delete Va array Bq Ar expression +.It Ic delete Va array +.It Ic exit Bq Ar expression +.Ar expression +.It Ic return Bq Ar expression +.It Ic \&{ Ar [ statement ... ] Ic \&} +.El +.Ss I/O Statements +The input/output statements are as follows: +.Pp +.Bl -tag -width indent +.It Fn close expr +Closes the file or pipe +.Ar expr . +Returns zero on success; otherwise nonzero. +.It Fn fflush expr +Flushes any buffered output for the file or pipe +.Ar expr . +Returns zero on success; otherwise nonzero. +.It Ic getline Bq Va var +Set +.Va var +(or +.Va $0 if +.Va var +is not specified) +to the next input record from the current input file. +.Ic getline +returns 1 for a successful input, +0 for end of file, and \-1 for an error. +.It Ic getline Bo Va var Bc Ic \*[Lt] Ar file +Set +.Va var +(or +.Va $0 if +.Va var +is not specified) +to the next input record from the specified file +.Ar file . +.It Ar expr Ic \&| getline +Pipes the output of +.Ar expr +into +.Ic getline ; +each call of +.Ic getline +returns the next line of output from +.Ar expr . +.It Ic next +Skip remaining patterns on this input line. +.It Ic nextfile +Skip rest of this file, open next, start at top. +.It Ic print Bo Ar expr-list Bc Bq Ic \*[Gt] Ar file +The +.Ic print +statement prints its arguments on the standard output (or to a file +if +.Ic \*[Gt] file +or to a pipe if +.Ic | Ar expr +is present), +separated by the current output field separator +.Va OFS , +and terminated by the +output record separator +.Va ORS . +Both +.Ar file +and +.Ar expr +may be literal names or parenthesized expressions; identical string values in +different statements denote the same open file. +.It Ic printf Ar format Bo Ic \&, Ar expr-list Bc Bq Ic \*[Gt] Ar file +Format and print its expression list according to +.Ar format . +See +.Xr printf 3 +for list of supported formats and their meaning. +.El +.Ss Mathematical and Numeric Functions +AWK has the following mathematical and numerical functions built-in: +.Pp +.Bl -tag -width indent +.It Fn atan2 x y +Returns the arctangent of +.Ar x Ic / Ar y +in radians. +See also +.Xr atan2 3 . +.It Fn cos expr +Computes the cosine of +.Ar expr , +measured in radians. +See also +.Xr cos 3 . +.It Fn exp expr +Computes the exponential value of the given argument +.Ar expr . +See also +.Xr exp 3 . +.It Fn int expr +Truncates +.Ar expr +to integer. +.It Fn log expr +Computes the value of the natural logarithm of argument +.Ar expr . +See also +.Xr log 3 . +.It Fn rand +Returns random number between 0 and 1. +.It Fn sin expr +Computes the sine of +.Ar expr , +measured in radians. +See also +.Xr sin 3 . +.It Fn sqrt expr +Computes the non-negative square root of +.Ar expr . +See also +.Xr sqrt 3 . +.It Fn srand [expr] +Sets seed for random number generator ( +.Fn rand ) +and returns the previous seed. +.El +.Ss String Functions +AWK has the following string functions built-in: +.Pp +.Bl -tag -width indent +.It Fn gensub r s h [t] +Search the target string +.Ar t +for matches of the regular expression +.Ar r . +If +.Ar h +is a string beginning with +.Ic g +or +.Ic G , +then replace all matches of +.Ar r +with +.Ar s . +Otherwise, +.Ar h +is a number indicating which match of +.Ar r +to replace. +If no +.Ar t +is supplied, +.Va $0 +is used instead. +.\"Within the replacement text +.\".Ar s , +.\"the sequence +.\".Ar \en , +.\"where +.\".Ar n +.\"is a digit from 1 to 9, may be used to indicate just the text that +.\"matched the +.\".Ar n Ap th +.\"parenthesized subexpression. +.\"The sequence +.\".Ic \e0 +.\"represents the entire text, as does the character +.\".Ic & . +Unlike +.Fn sub +and +.Fn gsub , +the modified string is returned as the result of the function, +and the original target is +.Em not +changed. +Note that the +.Ar \en +sequences within replacement string +.Ar s +supported by GNU +.Nm +are +.Em not +supported at this moment. +.It Fn gsub r t "[s]" +same as +.Fn sub +except that all occurrences of the regular expression +are replaced; +.Fn sub +and +.Fn gsub +return the number of replacements. +.It Fn index s t +the position in +.Ar s +where the string +.Ar t +occurs, or 0 if it does not. +.It Fn length "[string]" +the length of its argument +taken as a string, +or of +.Va $0 +if no argument. +.It Fn match s r +the position in +.Ar s +where the regular expression +.Ar r +occurs, or 0 if it does not. +The variables +.Va RSTART +and +.Va RLENGTH +are set to the position and length of the matched string. +.It Fn split s a "[fs]" +splits the string +.Ar s +into array elements +.Va a[1] , +.Va a[2] , +\&..., +.Va a[n] , +and returns +.Va n . +The separation is done with the regular expression +.Ar fs +or with the field separator +.Va FS +if +.Ar fs +is not given. +An empty string as field separator splits the string +into one array element per character. +.It Fn sprintf fmt expr "..." +Returns the string resulting from formatting +.Ar expr +according to the +.Xr printf 3 +format +.Ar fmt . +.It Fn sub r t "[s]" +substitutes +.Ar t +for the first occurrence of the regular expression +.Ar r +in the string +.Ar s . +If +.Ar s +is not given, +.Va $0 +is used. +.It Fn substr s m [n] +Returns the at most +.Ar n Ns No -character +substring of +.Ar s +starting at position +.Ar m , +counted from 1. +If +.Ar n +is omitted, the rest of +.Ar s +is returned. +.It Fn tolower str +returns a copy of +.Ar str +with all upper-case characters translated to their +corresponding lower-case equivalents. +.It Fn toupper str +returns a copy of +.Ar str +with all lower-case characters translated to their +corresponding upper-case equivalents. +.El +.Ss Time Functions +This +.Nm +provides the following two functions for obtaining time +stamps and formatting them: +.Bl -tag -width indent +.It Fn systime +Returns the value of time in seconds since the start of +.Tn Unix +Epoch (Midnight, January 1, 1970, Coordinated Universal Time). +See also +.Xr time 3 . +.It Fn strftime "[format [, timestamp]]" +Formats the time +.Ar timestamp +according to the string +.Ar format . +.Ar timestamp +should be in same form as value returned by +.Fn systime . +If +.Ar timestamp +is missing, current time is used. +If +.Ar format +is missing, a default format equivalent to the output of +.Xr date 1 +would be used. +See the specification of ANSI C +.Xr strftime 3 +for the format conversions which are supported. +.El +.Ss Other built-in functions +.Bl -tag -width indent +.It Fn system cmd +executes +.Ar cmd +and returns its exit status +.El +.Ss Patterns +Patterns are arbitrary Boolean combinations +(with +.Ic "! || \*[Am]\*[Am]" ) +of regular expressions and +relational expressions. +Regular expressions are as in +.Xr egrep 1 . +Isolated regular expressions +in a pattern apply to the entire line. +Regular expressions may also occur in +relational expressions, using the operators +.Ic ~ +and +.Ic !~ . +.Ic / re / +is a constant regular expression; +any string (constant or variable) may be used +as a regular expression, except in the position of an isolated regular expression +in a pattern. +.Pp +A pattern may consist of two patterns separated by a comma; +in this case, the action is performed for all lines +from an occurrence of the first pattern +though an occurrence of the second. +.Pp +A relational expression is one of the following: +.Bl -tag -offset indent -width indent -compact +.It Ar expression matchop regular-expression +.It Ar expression relop expression +.It Ar expression Ic in Ar array-name +.It ( Ar expr , expr,\&... Ic ") in" Ar array-name +.El +.Pp +where a +.Ar relop +is any of the six relational operators in C, +and a +.Ar matchop +is either +.Ic ~ +(matches) +or +.Ic !~ +(does not match). +A conditional is an arithmetic expression, +a relational expression, +or a Boolean combination +of these. +.Pp +The special patterns +.Ic BEGIN +and +.Ic END +may be used to capture control before the first input line is read +and after the last. +.Ic BEGIN +and +.Ic END +do not combine with other patterns. +.Ss Built-in Variables +Variable names with special meanings: +.Bl -hang -width FILENAMES +.It Va ARGC +argument count, assignable +.It Va ARGV +argument array, assignable; +non-null members are taken as filenames +.It Va CONVFMT +conversion format used when converting numbers +(default +.Qq %.6g ) +.It Va ENVIRON +array of environment variables; subscripts are names. +.It Va FILENAME +the name of the current input file +.It Va FNR +ordinal number of the current record in the current file +.It Va FS +regular expression used to separate fields; also settable +by option +.Fl F Ar fs . +.It Va NF +number of fields in the current record +.It Va NR +ordinal number of the current record +.It Va OFMT +output format for numbers (default +.Qq "%.6g" +) +.It Va OFS +output field separator (default blank) +.It Va ORS +output record separator (default newline) +.It Va RS +input record separator (default newline) +.It Va RSTART +Position of the first character matched by +.Fn match ; +0 if not match. +.It Va RLENGTH +Length of the string matched by +.Fn match ; +-1 if no match. +.It Va SUBSEP +separates multiple subscripts (default 034) +.El +.Ss Functions +Functions may be defined (at the position of a pattern-action statement) thus: +.Bd -filled -offset indent +.Ic function foo(a, b, c) { ...; return x } +.Ed +.Pp +Parameters are passed by value if scalar and by reference if array name; +functions may be called recursively. +Parameters are local to the function; all other variables are global. +Thus local variables may be created by providing excess parameters in +the function definition. +.Sh EXAMPLES +.Bl -tag -width indent -compact +.It Ic length($0) \*[Gt] 72 +Print lines longer than 72 characters. +.Pp +.It Ic \&{ print $2, $1 \&} +Print first two fields in opposite order. +.Pp +.It Ic BEGIN { FS = \&",[ \et]*|[ \et]+\&" } +.It Ic "\ \ \ \ \ \ {" print \&$2, \&$1 } +Same, with input fields separated by comma and/or blanks and tabs. +.Pp +.It Ic "\ \ \ \ {" s += $1 } +.It Ic END { print \&"sum is\&", s, \&" average is\ \&",\ s/NR\ } +Add up first column, print sum and average. +.Pp +.It Ic /start/, /stop/ +Print all lines between start/stop pairs. +.Pp +.It Ic BEGIN { # Simulate echo(1) +.It Ic "\ \ \ \ " for (i = 1; i \*[Lt] ARGC;\ i++)\ printf\ \&"%s\ \&",\ ARGV[i] +.It Ic "\ \ \ \ " printf \&"\en\&" +.It Ic "\ \ \ \ " exit } +.El +.Sh SEE ALSO +.Xr egrep 1 , +.Xr lex 1 , +.Xr sed 1 , +.Xr atan2 3 , +.Xr cos 3 , +.Xr exp 3 , +.Xr log 3 , +.Xr sin 3 , +.Xr sqrt 3 , +.Xr strftime 3 , +.Xr time 3 +.Pp +A. V. Aho, B. W. Kernighan, P. J. Weinberger, +.Em The AWK Programming Language , +Addison-Wesley, 1988. +ISBN 0-201-07981-X +.Pp +.Em AWK Language Programming , +Edition 1.0, published by the Free Software Foundation, 1995 +.Sh HISTORY +.Nm nawk +has been the default system +.Nm +since +.Nx 2.0 , +replacing the previously used GNU +.Nm . +.Sh BUGS +There are no explicit conversions between numbers and strings. +To force an expression to be treated as a number add 0 to it; +to force it to be treated as a string concatenate +\&"\&" to it. +.Pp +The scope rules for variables in functions are a botch; +the syntax is worse. diff --git a/commands/awk/FIXES b/external/historical/nawk/dist/FIXES similarity index 99% rename from commands/awk/FIXES rename to external/historical/nawk/dist/FIXES index e611e2a7c..310da0790 100644 --- a/commands/awk/FIXES +++ b/external/historical/nawk/dist/FIXES @@ -25,6 +25,13 @@ THIS SOFTWARE. This file lists all bug fixes, changes, etc., made since the AWK book was sent to the printers in August, 1987. +May 23, 2010: + fixed long-standing overflow bug in run.c; many thanks to + nelson beebe for spotting it and providing the fix. + + fixed bug that didn't parse -vd=1 properly; thanks to santiago + vila for spotting it. + Feb 8, 2010: i give up. replaced isblank with isspace in b.c; there are no consistent header files. diff --git a/commands/awk/README b/external/historical/nawk/dist/README similarity index 100% rename from commands/awk/README rename to external/historical/nawk/dist/README diff --git a/commands/awk/awk.1 b/external/historical/nawk/dist/awk.1 similarity index 100% rename from commands/awk/awk.1 rename to external/historical/nawk/dist/awk.1 diff --git a/commands/awk/awk.h b/external/historical/nawk/dist/awk.h similarity index 95% rename from commands/awk/awk.h rename to external/historical/nawk/dist/awk.h index a36cdb151..71418a73b 100644 --- a/commands/awk/awk.h +++ b/external/historical/nawk/dist/awk.h @@ -48,6 +48,7 @@ extern int safe; /* 0 => unsafe, 1 => safe */ #define RECSIZE (8 * 1024) /* sets limit on records, fields, etc., etc. */ extern int recsize; /* size of current record, orig RECSIZE */ +extern char EMPTY[]; extern char **FS; extern char **RS; extern char **ORS; @@ -61,16 +62,15 @@ extern char **SUBSEP; extern Awkfloat *RSTART; extern Awkfloat *RLENGTH; -extern char *record; /* points to $0 */ +extern uschar *record; /* points to $0 */ extern int lineno; /* line number in awk program */ extern int errorflag; /* 1 if error has occurred */ extern int donefld; /* 1 if record broken into fields */ extern int donerec; /* 1 if record is valid (no fld has changed */ -extern char inputFS[]; /* FS at time of input, for field splitting */ extern int dbg; -extern char *patbeg; /* beginning of pattern matched */ +extern uschar *patbeg; /* beginning of pattern matched */ extern int patlen; /* length of pattern matched. set in b.c */ /* Cell: all information about a variable or constant */ @@ -126,6 +126,8 @@ extern Cell *rlengthloc; /* RLENGTH */ #define FTOUPPER 12 #define FTOLOWER 13 #define FFLUSH 14 +#define FSYSTIME 15 +#define FSTRFTIME 16 /* Node: parse tree is made of nodes, with Cell's at bottom */ @@ -203,8 +205,6 @@ extern int pairstack[], paircnt; #define NCHARS (256+3) /* 256 handles 8-bit chars; 128 does 7-bit */ /* watch out in match(), etc. */ -#define NSTATES 32 - typedef struct rrow { long ltype; /* long avoids pointer warnings on 64-bit */ union { @@ -216,16 +216,16 @@ typedef struct rrow { } rrow; typedef struct fa { - uschar gototab[NSTATES][NCHARS]; - uschar out[NSTATES]; + unsigned int **gototab; + uschar *out; uschar *restr; - int *posns[NSTATES]; + int **posns; + int state_count; int anchor; int use; int initstat; int curstat; int accept; - int reset; struct rrow re[1]; /* variable: actual size set by calling malloc */ } fa; diff --git a/commands/awk/awkgram.y b/external/historical/nawk/dist/awkgram.y similarity index 93% rename from commands/awk/awkgram.y rename to external/historical/nawk/dist/awkgram.y index 91b62571b..46731c22c 100644 --- a/commands/awk/awkgram.y +++ b/external/historical/nawk/dist/awkgram.y @@ -23,6 +23,10 @@ THIS SOFTWARE. ****************************************************************/ %{ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #include #include #include "awk.h" @@ -71,6 +75,7 @@ Node *arglist = 0; /* list of args for current function */ %type do st %type pst opt_pst lbrace rbrace rparen comma nl opt_nl and bor %type subop print +%type string %right ASGNOP %right '?' @@ -80,7 +85,7 @@ Node *arglist = 0; /* list of args for current function */ %left GETLINE %nonassoc APPEND EQ GE GT LE LT NE MATCHOP IN '|' %left ARG BLTIN BREAK CALL CLOSE CONTINUE DELETE DO EXIT FOR FUNC -%left GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER +%left GENSUB GSUB IF INDEX LSUBSTR MATCHFCN NEXT NUMBER %left PRINT PRINTF RETURN SPLIT SPRINTF STRING SUB SUBSTR %left REGEXPR VAR VARNF IVAR WHILE '(' %left CAT @@ -348,6 +353,11 @@ subop: SUB | GSUB ; +string: + STRING + | string STRING { $$ = catstr($1, $2); } + ; + term: term '/' ASGNOP term { $$ = op2(DIVEQ, $1, $4); } | term '+' term { $$ = op2(ADD, $1, $3); } @@ -369,6 +379,22 @@ term: | INCR var { $$ = op1(PREINCR, $2); } | var DECR { $$ = op1(POSTDECR, $1); } | var INCR { $$ = op1(POSTINCR, $1); } + | GENSUB '(' reg_expr comma pattern comma pattern ')' + { $$ = op5(GENSUB, NIL, (Node*)makedfa($3, 1), $5, $7, rectonode()); } + | GENSUB '(' pattern comma pattern comma pattern ')' + { if (constnode($3)) + $$ = op5(GENSUB, NIL, (Node *)makedfa(strnode($3), 1), $5, $7, rectonode()); + else + $$ = op5(GENSUB, (Node *)1, $3, $5, $7, rectonode()); + } + | GENSUB '(' reg_expr comma pattern comma pattern comma pattern ')' + { $$ = op5(GENSUB, NIL, (Node*)makedfa($3, 1), $5, $7, $9); } + | GENSUB '(' pattern comma pattern comma pattern comma pattern ')' + { if (constnode($3)) + $$ = op5(GENSUB, NIL, (Node *)makedfa(strnode($3),1), $5,$7,$9); + else + $$ = op5(GENSUB, (Node *)1, $3, $5, $7, $9); + } | GETLINE var LT term { $$ = op3(GETLINE, $2, itonp($3), $4); } | GETLINE LT term { $$ = op3(GETLINE, NIL, itonp($2), $3); } | GETLINE var { $$ = op3(GETLINE, $2, NIL, NIL); } @@ -394,7 +420,7 @@ term: | SPLIT '(' pattern comma varname ')' { $$ = op4(SPLIT, $3, makearr($5), NIL, (Node*)STRING); } /* default */ | SPRINTF '(' patlist ')' { $$ = op1($1, $3); } - | STRING { $$ = celltonode($1, CCON); } + | string { $$ = celltonode($1, CCON); } | subop '(' reg_expr comma pattern ')' { $$ = op4($1, NIL, (Node*)makedfa($3, 1), $5, rectonode()); } | subop '(' pattern comma pattern ')' diff --git a/commands/awk/b.c b/external/historical/nawk/dist/b.c similarity index 74% rename from commands/awk/b.c rename to external/historical/nawk/dist/b.c index 0fbfab1fb..a99bb87fc 100644 --- a/commands/awk/b.c +++ b/external/historical/nawk/dist/b.c @@ -24,12 +24,17 @@ THIS SOFTWARE. /* lasciate ogne speranza, voi ch'intrate. */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #define DEBUG #include #include #include #include +#include #include "awk.h" #include "awkgram.h" @@ -62,33 +67,80 @@ int maxsetvec = 0; int rtok; /* next token in current re */ int rlxval; -static uschar *rlxstr; -static uschar *prestr; /* current position in current re */ -static uschar *lastre; /* origin of last re */ +static const uschar *rlxstr; +static const uschar *prestr; /* current position in current re */ +static const uschar *lastre; /* origin of last re */ static int setcnt; static int poscnt; -char *patbeg; +uschar *patbeg; int patlen; -#define NFA 20 /* cache this many dynamic fa's */ +#define NFA 128 /* cache this many dynamic fa's */ fa *fatab[NFA]; int nfatab = 0; /* entries in fatab */ +static void +resizesetvec(const char *msg) +{ + if (maxsetvec == 0) + maxsetvec = MAXLIN; + else + maxsetvec *= 4; + setvec = realloc(setvec, maxsetvec * sizeof(*setvec)); + tmpset = realloc(tmpset, maxsetvec * sizeof(*tmpset)); + if (setvec == 0 || tmpset == 0) + overflo(msg); +} + +static void +resize_state(fa *f, int state) +{ + void *p; + int i, new_count; + + if (++state < f->state_count) + return; + + new_count = state + 10; /* needs to be tuned */ + + p = realloc(f->gototab, new_count * sizeof(f->gototab[0])); + if (p == NULL) + goto out; + f->gototab = p; + + p = realloc(f->out, new_count * sizeof(f->out[0])); + if (p == NULL) + goto out; + f->out = p; + + p = realloc(f->posns, new_count * sizeof(f->posns[0])); + if (p == NULL) + goto out; + f->posns = p; + + for (i = f->state_count; i < new_count; ++i) { + f->gototab[i] = calloc(1, NCHARS * sizeof (**f->gototab)); + if (f->gototab[i] == NULL) + goto out; + f->out[i] = 0; + f->posns[i] = NULL; + } + f->state_count = new_count; + return; +out: + overflo("out of memory in resize_state"); +} + fa *makedfa(const char *s, int anchor) /* returns dfa for reg expr s */ { int i, use, nuse; fa *pfa; static int now = 1; - if (setvec == 0) { /* first time through any RE */ - maxsetvec = MAXLIN; - setvec = (int *) malloc(maxsetvec * sizeof(int)); - tmpset = (int *) malloc(maxsetvec * sizeof(int)); - if (setvec == 0 || tmpset == 0) - overflo("out of space initializing makedfa"); - } + if (setvec == 0) /* first time through any RE */ + resizesetvec("out of space initializing makedfa"); if (compile_time) /* a constant for sure */ return mkdfa(s, anchor); @@ -132,14 +184,15 @@ fa *mkdfa(const char *s, int anchor) /* does the real work of making a dfa */ poscnt = 0; penter(p1); /* enter parent pointers and leaf indices */ - if ((f = (fa *) calloc(1, sizeof(fa) + poscnt*sizeof(rrow))) == NULL) + if ((f = calloc(1, sizeof(*f) + poscnt*sizeof(rrow))) == NULL) overflo("out of space for fa"); f->accept = poscnt-1; /* penter has computed number of positions in re */ cfoll(f, p1); /* set up follow sets */ freetr(p1); - if ((f->posns[0] = (int *) calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL) + resize_state(f, 1); + if ((f->posns[0] = calloc(1, *(f->re[0].lfollow)*sizeof(int))) == NULL) overflo("out of space in makedfa"); - if ((f->posns[1] = (int *) calloc(1, sizeof(int))) == NULL) + if ((f->posns[1] = calloc(1, sizeof(int))) == NULL) overflo("out of space in makedfa"); *f->posns[1] = 0; f->initstat = makeinit(f, anchor); @@ -152,12 +205,12 @@ int makeinit(fa *f, int anchor) { int i, k; + resize_state(f, 2); f->curstat = 2; f->out[2] = 0; - f->reset = 0; k = *(f->re[0].lfollow); xfree(f->posns[2]); - if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) + if ((f->posns[2] = calloc(1, (k+1)*sizeof(int))) == NULL) overflo("out of space in makeinit"); for (i=0; i <= k; i++) { (f->posns[2])[i] = (f->re[0].lfollow)[i]; @@ -174,8 +227,10 @@ int makeinit(fa *f, int anchor) } f->out[0] = f->out[2]; - if (f->curstat != 2) + if (f->curstat != 2) { + resize_state(f, f->curstat); --(*f->posns[f->curstat]); + } } return f->curstat; } @@ -231,13 +286,13 @@ void freetr(Node *p) /* free parse tree */ /* in the parsing of regular expressions, metacharacters like . have */ /* to be seen literally; \056 is not a metacharacter. */ -int hexstr(char **pp) /* find and eval hex string at pp, return new p */ +int hexstr(const uschar **pp) /* find and eval hex string at pp, return new p */ { /* only pick up one 8-bit byte (2 chars) */ - uschar *p; + const uschar *p; int n = 0; int i; - for (i = 0, p = (uschar *) *pp; i < 2 && isxdigit(*p); i++, p++) { + for (i = 0, p = *pp; i < 2 && isxdigit(*p); i++, p++) { if (isdigit(*p)) n = 16 * n + *p - '0'; else if (*p >= 'a' && *p <= 'f') @@ -245,16 +300,16 @@ int hexstr(char **pp) /* find and eval hex string at pp, return new p */ else if (*p >= 'A' && *p <= 'F') n = 16 * n + *p - 'A' + 10; } - *pp = (char *) p; + *pp = p; return n; } #define isoctdigit(c) ((c) >= '0' && (c) <= '7') /* multiple use of arg */ -int quoted(char **pp) /* pick up next thing after a \\ */ +int quoted(const uschar **pp) /* pick up next thing after a \\ */ /* and increment *pp */ { - char *p = *pp; + const uschar *p = *pp; int c; if ((c = *p++) == 't') @@ -288,31 +343,32 @@ int quoted(char **pp) /* pick up next thing after a \\ */ char *cclenter(const char *argp) /* add a character class */ { int i, c, c2; - uschar *p = (uschar *) argp; - uschar *op, *bp; + const uschar *p = (const uschar *) argp; + const uschar *op; + uschar *bp; static uschar *buf = 0; static int bufsz = 100; op = p; - if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL) + if (buf == 0 && (buf = malloc(bufsz)) == NULL) FATAL("out of space for character class [%.10s...] 1", p); bp = buf; for (i = 0; (c = *p++) != 0; ) { if (c == '\\') { - c = quoted((char **) &p); + c = quoted(&p); } else if (c == '-' && i > 0 && bp[-1] != 0) { if (*p != 0) { c = bp[-1]; c2 = *p++; if (c2 == '\\') - c2 = quoted((char **) &p); + c2 = quoted(&p); if (c > c2) { /* empty; ignore */ bp--; i--; continue; } while (c < c2) { - if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "cclenter1")) + if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter1")) FATAL("out of space for character class [%.10s...] 2", p); *bp++ = ++c; i++; @@ -320,14 +376,14 @@ char *cclenter(const char *argp) /* add a character class */ continue; } } - if (!adjbuf((char **) &buf, &bufsz, bp-buf+2, 100, (char **) &bp, "cclenter2")) + if (!adjbuf(&buf, &bufsz, bp-buf+2, 100, &bp, "cclenter2")) FATAL("out of space for character class [%.10s...] 3", p); *bp++ = c; i++; } *bp = 0; dprintf( ("cclenter: in = |%s|, out = |%s|\n", op, buf) ); - xfree(op); + free(__UNCONST(op)); return (char *) tostring((char *) buf); } @@ -346,18 +402,13 @@ void cfoll(fa *f, Node *v) /* enter follow set of each leaf of vertex v into lfo LEAF f->re[info(v)].ltype = type(v); f->re[info(v)].lval.np = right(v); - while (f->accept >= maxsetvec) { /* guessing here! */ - maxsetvec *= 4; - setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); - tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); - if (setvec == 0 || tmpset == 0) - overflo("out of space in cfoll()"); - } + while (f->accept >= maxsetvec) /* guessing here! */ + resizesetvec("out of space in cfoll()"); for (i = 0; i <= f->accept; i++) setvec[i] = 0; setcnt = 0; follow(v); /* computes setvec and setcnt */ - if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL) + if ((p = calloc(1, (setcnt+1)*sizeof(int))) == NULL) overflo("out of space building follow set"); f->re[info(v)].lfollow = p; *p = setcnt; @@ -378,7 +429,7 @@ void cfoll(fa *f, Node *v) /* enter follow set of each leaf of vertex v into lfo } } -int first(const Node *p) /* collects initially active leaves of p into setvec */ +int first(Node *p) /* collects initially active leaves of p into setvec */ /* returns 0 if p matches empty string */ { int b, lp; @@ -387,13 +438,8 @@ int first(const Node *p) /* collects initially active leaves of p into setvec */ ELEAF LEAF lp = info(p); /* look for high-water mark of subscripts */ - while (setcnt >= maxsetvec || lp >= maxsetvec) { /* guessing here! */ - maxsetvec *= 4; - setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); - tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); - if (setvec == 0 || tmpset == 0) - overflo("out of space in first()"); - } + while (setcnt >= maxsetvec || lp >= maxsetvec) /* guessing here! */ + resizesetvec("out of space in first()"); if (type(p) == EMPTYRE) { setvec[lp] = 0; return(0); @@ -457,7 +503,7 @@ void follow(Node *v) /* collects leaves that can follow v into setvec */ int member(int c, const char *sarg) /* is c in s? */ { - uschar *s = (uschar *) sarg; + const uschar *s = (const uschar *) sarg; while (*s) if (c == *s++) @@ -468,9 +514,11 @@ int member(int c, const char *sarg) /* is c in s? */ int match(fa *f, const char *p0) /* shortest match ? */ { int s, ns; - uschar *p = (uschar *) p0; + const uschar *p = (const uschar *) p0; + + s = f->initstat; + assert (s < f->state_count); - s = f->reset ? makeinit(f,0) : f->initstat; if (f->out[s]) return(1); do { @@ -479,6 +527,9 @@ int match(fa *f, const char *p0) /* shortest match ? */ s = ns; else s = cgoto(f, s, *p); + + assert (s < f->state_count); + if (f->out[s]) return(1); } while (*p++ != 0); @@ -488,17 +539,12 @@ int match(fa *f, const char *p0) /* shortest match ? */ int pmatch(fa *f, const char *p0) /* longest match, for sub */ { int s, ns; - uschar *p = (uschar *) p0; + uschar *p = __UNCONST(p0); uschar *q; - int i, k; - /* s = f->reset ? makeinit(f,1) : f->initstat; */ - if (f->reset) { - f->initstat = s = makeinit(f,1); - } else { - s = f->initstat; - } - patbeg = (char *) p; + s = f->initstat; + assert(s < f->state_count); + patbeg = p; patlen = -1; do { q = p; @@ -510,9 +556,12 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */ s = ns; else s = cgoto(f, s, *q); + + assert(s < f->state_count); + if (s == 1) { /* no transition */ if (patlen >= 0) { - patbeg = (char *) p; + patbeg = p; return(1); } else @@ -522,24 +571,11 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */ if (f->out[s]) patlen = q-p-1; /* don't count $ */ if (patlen >= 0) { - patbeg = (char *) p; + patbeg = p; return(1); } nextin: s = 2; - if (f->reset) { - for (i = 2; i <= f->curstat; i++) - xfree(f->posns[i]); - k = *f->posns[0]; - if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) - overflo("out of space in pmatch"); - for (i = 0; i <= k; i++) - (f->posns[2])[i] = (f->posns[0])[i]; - f->initstat = f->curstat = 2; - f->out[2] = f->out[0]; - for (i = 0; i < NCHARS; i++) - f->gototab[2][i] = 0; - } } while (*p++ != 0); return (0); } @@ -547,16 +583,12 @@ int pmatch(fa *f, const char *p0) /* longest match, for sub */ int nematch(fa *f, const char *p0) /* non-empty match, for sub */ { int s, ns; - uschar *p = (uschar *) p0; + uschar *p = __UNCONST(p0); uschar *q; - int i, k; - /* s = f->reset ? makeinit(f,1) : f->initstat; */ - if (f->reset) { - f->initstat = s = makeinit(f,1); - } else { - s = f->initstat; - } + s = f->initstat; + assert(s < f->state_count); + patlen = -1; while (*p) { q = p; @@ -568,9 +600,12 @@ int nematch(fa *f, const char *p0) /* non-empty match, for sub */ s = ns; else s = cgoto(f, s, *q); + + assert(s < f->state_count); + if (s == 1) { /* no transition */ if (patlen > 0) { - patbeg = (char *) p; + patbeg = p; return(1); } else goto nnextin; /* no nonempty match */ @@ -579,35 +614,112 @@ int nematch(fa *f, const char *p0) /* non-empty match, for sub */ if (f->out[s]) patlen = q-p-1; /* don't count $ */ if (patlen > 0 ) { - patbeg = (char *) p; + patbeg = p; return(1); } nnextin: s = 2; - if (f->reset) { - for (i = 2; i <= f->curstat; i++) - xfree(f->posns[i]); - k = *f->posns[0]; - if ((f->posns[2] = (int *) calloc(1, (k+1)*sizeof(int))) == NULL) - overflo("out of state space"); - for (i = 0; i <= k; i++) - (f->posns[2])[i] = (f->posns[0])[i]; - f->initstat = f->curstat = 2; - f->out[2] = f->out[0]; - for (i = 0; i < NCHARS; i++) - f->gototab[2][i] = 0; - } p++; } return (0); } + +/* + * NAME + * fnematch + * + * DESCRIPTION + * A stream-fed version of nematch which transfers characters to a + * null-terminated buffer. All characters up to and including the last + * character of the matching text or EOF are placed in the buffer. If + * a match is found, patbeg and patlen are set appropriately. + * + * RETURN VALUES + * 0 No match found. + * 1 Match found. + */ + +int fnematch(fa *pfa, FILE *f, uschar **pbuf, int *pbufsize, int quantum) +{ + uschar *buf = *pbuf; + int bufsize = *pbufsize; + int c, i, j, k, ns, s; + + s = pfa->initstat; + assert(s < pfa->state_count); + patlen = 0; + + /* + * All indices relative to buf. + * i <= j <= k <= bufsize + * + * i: origin of active substring + * j: current character + * k: destination of next getc() + */ + i = -1, k = 0; + do { + j = i++; + do { + if (++j == k) { + if (k == bufsize) + if (!adjbuf(&buf, &bufsize, bufsize+1, quantum, 0, "fnematch")) + FATAL("stream '%.30s...' too long", buf); + buf[k++] = (c = getc(f)) != EOF ? c : 0; + } + c = buf[j]; + /* assert(c < NCHARS); */ + + if ((ns = pfa->gototab[s][c]) != 0) + s = ns; + else + s = cgoto(pfa, s, c); + assert(s < pfa->state_count); + + if (pfa->out[s]) { /* final state */ + patlen = j - i + 1; + if (c == 0) /* don't count $ */ + patlen--; + } + } while (buf[j] && s != 1); + s = 2; + } while (buf[i] && !patlen); + + /* adjbuf() may have relocated a resized buffer. Inform the world. */ + *pbuf = buf; + *pbufsize = bufsize; + + if (patlen) { + patbeg = buf + i; + /* + * Under no circumstances is the last character fed to + * the automaton part of the match. It is EOF's nullbyte, + * or it sent the automaton into a state with no further + * transitions available (s==1), or both. Room for a + * terminating nullbyte is guaranteed. + * + * ungetc any chars after the end of matching text + * (except for EOF's nullbyte, if present) and null + * terminate the buffer. + */ + do + if (buf[--k] && ungetc(buf[k], f) == EOF) + FATAL("unable to ungetc '%c'", buf[k]); + while (k > i + patlen); + buf[k] = 0; + return 1; + } + else + return 0; +} + Node *reparse(const char *p) /* parses regular expression pointed to by p */ { /* uses relex() to scan regular expression */ Node *np; dprintf( ("reparse <%s>\n", p) ); - lastre = prestr = (uschar *) p; /* prestr points to string to be parsed */ + lastre = prestr = (const uschar *) p; /* prestr points to string to be parsed */ rtok = relex(); /* GNU compatibility: an empty regexp matches anything */ if (rtok == '\0') { @@ -644,11 +756,11 @@ Node *primary(void) rtok = relex(); return (unary(op2(DOT, NIL, NIL))); case CCL: - np = op2(CCL, NIL, (Node*) cclenter((char *) rlxstr)); + np = op2(CCL, NIL, (Node*) cclenter((const char *) rlxstr)); rtok = relex(); return (unary(np)); case NCCL: - np = op2(NCCL, NIL, (Node *) cclenter((char *) rlxstr)); + np = op2(NCCL, NIL, (Node *) cclenter((const char *) rlxstr)); rtok = relex(); return (unary(np)); case '^': @@ -732,23 +844,15 @@ Node *unary(Node *np) */ /* #define HAS_ISBLANK */ -#ifndef HAS_ISBLANK - -int (xisblank)(int c) -{ - return c==' ' || c=='\t'; -} - -#endif -struct charclass { +static const struct charclass { const char *cc_name; int cc_namelen; int (*cc_func)(int); } charclasses[] = { { "alnum", 5, isalnum }, { "alpha", 5, isalpha }, - { "blank", 5, isspace }, /* was isblank */ + { "blank", 5, isblank }, { "cntrl", 5, iscntrl }, { "digit", 5, isdigit }, { "graph", 5, isgraph }, @@ -769,7 +873,7 @@ int relex(void) /* lexical analyzer for reparse */ static uschar *buf = 0; static int bufsz = 100; uschar *bp; - struct charclass *cc; + const struct charclass *cc; int i; switch (c = *prestr++) { @@ -785,13 +889,13 @@ int relex(void) /* lexical analyzer for reparse */ case ')': return c; case '\\': - rlxval = quoted((char **) &prestr); + rlxval = quoted(&prestr); return CHAR; default: rlxval = c; return CHAR; case '[': - if (buf == 0 && (buf = (uschar *) malloc(bufsz)) == NULL) + if (buf == 0 && (buf = malloc(bufsz)) == NULL) FATAL("out of space in reg expr %.10s..", lastre); bp = buf; if (*prestr == '^') { @@ -801,7 +905,7 @@ int relex(void) /* lexical analyzer for reparse */ else cflag = 0; n = 2 * strlen((const char *) prestr)+1; - if (!adjbuf((char **) &buf, &bufsz, n, n, (char **) &bp, "relex1")) + if (!adjbuf(&buf, &bufsz, n, n, &bp, "relex1")) FATAL("out of space for reg expr %.10s...", lastre); for (; ; ) { if ((c = *prestr++) == '\\') { @@ -819,8 +923,8 @@ int relex(void) /* lexical analyzer for reparse */ if (cc->cc_name != NULL && prestr[1 + cc->cc_namelen] == ':' && prestr[2 + cc->cc_namelen] == ']') { prestr += cc->cc_namelen + 3; - for (i = 0; i < NCHARS; i++) { - if (!adjbuf((char **) &buf, &bufsz, bp-buf+1, 100, (char **) &bp, "relex2")) + for (i = 1; i < NCHARS; i++) { + if (!adjbuf(&buf, &bufsz, bp-buf+1, 100, &bp, "relex2")) FATAL("out of space for reg expr %.10s...", lastre); if (cc->cc_func(i)) { *bp++ = i; @@ -852,16 +956,12 @@ int cgoto(fa *f, int s, int c) int *p, *q; assert(c == HAT || c < NCHARS); - while (f->accept >= maxsetvec) { /* guessing here! */ - maxsetvec *= 4; - setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); - tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); - if (setvec == 0 || tmpset == 0) - overflo("out of space in cgoto()"); - } + while (f->accept >= maxsetvec) /* guessing here! */ + resizesetvec("out of space in cgoto()"); for (i = 0; i <= f->accept; i++) setvec[i] = 0; setcnt = 0; + resize_state(f, s); /* compute positions of gototab[s,c] into setvec */ p = f->posns[s]; for (i = 1; i <= *p; i++) { @@ -874,13 +974,8 @@ int cgoto(fa *f, int s, int c) || (k == NCCL && !member(c, (char *) f->re[p[i]].lval.up) && c != 0 && c != HAT)) { q = f->re[p[i]].lfollow; for (j = 1; j <= *q; j++) { - if (q[j] >= maxsetvec) { - maxsetvec *= 4; - setvec = (int *) realloc(setvec, maxsetvec * sizeof(int)); - tmpset = (int *) realloc(tmpset, maxsetvec * sizeof(int)); - if (setvec == 0 || tmpset == 0) - overflo("cgoto overflow"); - } + if (q[j] >= maxsetvec) + resizesetvec("cgoto overflow"); if (setvec[q[j]] == 0) { setcnt++; setvec[q[j]] = 1; @@ -896,6 +991,8 @@ int cgoto(fa *f, int s, int c) if (setvec[i]) { tmpset[j++] = i; } + + resize_state(f, f->curstat > s ? f->curstat : s); /* tmpset == previous state? */ for (i = 1; i <= f->curstat; i++) { p = f->posns[i]; @@ -905,27 +1002,24 @@ int cgoto(fa *f, int s, int c) if (tmpset[j] != p[j]) goto different; /* setvec is state i */ - f->gototab[s][c] = i; + if (c != HAT) + f->gototab[s][c] = i; return i; different:; } /* add tmpset to current set of states */ - if (f->curstat >= NSTATES-1) { - f->curstat = 2; - f->reset = 1; - for (i = 2; i < NSTATES; i++) - xfree(f->posns[i]); - } else - ++(f->curstat); + ++(f->curstat); + resize_state(f, f->curstat); for (i = 0; i < NCHARS; i++) f->gototab[f->curstat][i] = 0; xfree(f->posns[f->curstat]); - if ((p = (int *) calloc(1, (setcnt+1)*sizeof(int))) == NULL) + if ((p = calloc(1, (setcnt+1)*sizeof(int))) == NULL) overflo("out of space in cgoto"); f->posns[f->curstat] = p; - f->gototab[s][c] = f->curstat; + if (c != HAT) + f->gototab[s][c] = f->curstat; for (i = 0; i <= setcnt; i++) p[i] = tmpset[i]; if (setvec[f->accept]) @@ -942,13 +1036,18 @@ void freefa(fa *f) /* free a finite automaton */ if (f == NULL) return; - for (i = 0; i <= f->curstat; i++) + for (i = 0; i < f->state_count; i++) { + xfree(f->gototab[i]) xfree(f->posns[i]); + } for (i = 0; i <= f->accept; i++) { xfree(f->re[i].lfollow); if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL) xfree((f->re[i].lval.np)); } xfree(f->restr); + xfree(f->out); + xfree(f->posns); + xfree(f->gototab); xfree(f); } diff --git a/commands/awk/lex.c b/external/historical/nawk/dist/lex.c similarity index 94% rename from commands/awk/lex.c rename to external/historical/nawk/dist/lex.c index 8c59c4a0b..82f06daad 100644 --- a/commands/awk/lex.c +++ b/external/historical/nawk/dist/lex.c @@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #include #include #include @@ -43,7 +47,11 @@ typedef struct Keyword { int type; } Keyword; -Keyword keywords[] ={ /* keep sorted: binary searched */ +int peek(void); +int gettok(char **, int *); +int binsearch(const char *, const Keyword *, int); + +const Keyword keywords[] ={ /* keep sorted: binary searched */ { "BEGIN", XBEGIN, XBEGIN }, { "END", XEND, XEND }, { "NF", VARNF, VARNF }, @@ -61,6 +69,7 @@ Keyword keywords[] ={ /* keep sorted: binary searched */ { "for", FOR, FOR }, { "func", FUNC, FUNC }, { "function", FUNC, FUNC }, + { "gensub", GENSUB, GENSUB }, { "getline", GETLINE, GETLINE }, { "gsub", GSUB, GSUB }, { "if", IF, IF }, @@ -81,9 +90,11 @@ Keyword keywords[] ={ /* keep sorted: binary searched */ { "sprintf", SPRINTF, SPRINTF }, { "sqrt", FSQRT, BLTIN }, { "srand", FSRAND, BLTIN }, + { "strftime", FSTRFTIME, BLTIN }, { "sub", SUB, SUB }, { "substr", SUBSTR, SUBSTR }, { "system", FSYSTEM, BLTIN }, + { "systime", FSYSTIME, BLTIN }, { "tolower", FTOLOWER, BLTIN }, { "toupper", FTOUPPER, BLTIN }, { "while", WHILE, WHILE }, @@ -101,9 +112,9 @@ int peek(void) int gettok(char **pbuf, int *psz) /* get next input token */ { int c, retc; - char *buf = *pbuf; + uschar *buf = (uschar *) *pbuf; int sz = *psz; - char *bp = buf; + uschar *bp = buf; c = input(); if (c == 0) @@ -146,7 +157,7 @@ int gettok(char **pbuf, int *psz) /* get next input token */ } *bp = 0; strtod(buf, &rem); /* parse the number */ - if (rem == buf) { /* it wasn't a valid number at all */ + if (rem == (char *)buf) { /* it wasn't a valid number at all */ buf[1] = 0; /* return one character as token */ retc = buf[0]; /* character is its own type */ unputstr(rem+1); /* put rest back for later */ @@ -173,7 +184,7 @@ int yylex(void) static char *buf = 0; static int bufsize = 5; /* BUG: setting this small causes core dump! */ - if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL) + if (buf == 0 && (buf = malloc(bufsize)) == NULL) FATAL( "out of space in yylex" ); if (sc) { sc = 0; @@ -357,11 +368,11 @@ int yylex(void) int string(void) { int c, n; - char *s, *bp; - static char *buf = 0; + uschar *s, *bp; + static uschar *buf = 0; static int bufsz = 500; - if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + if (buf == 0 && (buf = malloc(bufsz)) == NULL) FATAL("out of space for strings"); for (bp = buf; (c = input()) != '"'; ) { if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string")) @@ -378,6 +389,7 @@ int string(void) case '\\': c = input(); switch (c) { + case '\n': break; case '"': *bp++ = '"'; break; case 'n': *bp++ = '\n'; break; case 't': *bp++ = '\t'; break; @@ -416,7 +428,9 @@ int string(void) break; } - default: + default: + WARNING("warning: escape sequence `\\%c' " + "treated as plain `%c'", c, c); *bp++ = c; break; } @@ -454,7 +468,7 @@ int binsearch(const char *w, const Keyword *kp, int n) int word(char *w) { - Keyword *kp; + const Keyword *kp; int c, n; n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0])); @@ -504,11 +518,11 @@ void startreg(void) /* next call to yylex will return a regular expression */ int regexpr(void) { int c; - static char *buf = 0; + static uschar *buf = 0; static int bufsz = 500; - char *bp; + uschar *bp; - if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) + if (buf == 0 && (buf = malloc(bufsz)) == NULL) FATAL("out of space for rex expr"); bp = buf; for ( ; (c = input()) != '/' && c != 0; ) { diff --git a/commands/awk/lib.c b/external/historical/nawk/dist/lib.c similarity index 79% rename from commands/awk/lib.c rename to external/historical/nawk/dist/lib.c index 8ba14e6df..28a4b97e8 100644 --- a/commands/awk/lib.c +++ b/external/historical/nawk/dist/lib.c @@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #define DEBUG #include #include @@ -32,15 +36,19 @@ THIS SOFTWARE. #include "awk.h" #include "awkgram.h" +char EMPTY[] = { '\0' }; FILE *infile = NULL; -char *file = ""; -char *record; +int innew; /* 1 = infile has not been read by readrec */ +char *file = EMPTY; +uschar *record; int recsize = RECSIZE; char *fields; int fieldssize = RECSIZE; Cell **fldtab; /* pointers to Cells */ -char inputFS[100] = " "; + +static size_t len_inputFS = 0; +static char *inputFS = NULL; #define MAXFLD 2 int nfields = MAXFLD; /* last allocated slot for $i */ @@ -52,15 +60,15 @@ int lastfld = 0; /* last used field */ int argno = 1; /* current input argument number */ extern Awkfloat *ARGC; -static Cell dollar0 = { OCELL, CFLD, NULL, "", 0.0, REC|STR|DONTFREE }; -static Cell dollar1 = { OCELL, CFLD, NULL, "", 0.0, FLD|STR|DONTFREE }; +static Cell dollar0 = { OCELL, CFLD, NULL, EMPTY, 0.0, REC|STR|DONTFREE, NULL }; +static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL }; void recinit(unsigned int n) { - if ( (record = (char *) malloc(n)) == NULL - || (fields = (char *) malloc(n+1)) == NULL - || (fldtab = (Cell **) malloc((nfields+1) * sizeof(Cell *))) == NULL - || (fldtab[0] = (Cell *) malloc(sizeof(Cell))) == NULL ) + if ( (record = malloc(n)) == NULL + || (fields = malloc(n+1)) == NULL + || (fldtab = malloc((nfields+1) * sizeof(*fldtab))) == NULL + || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL ) FATAL("out of space for $0 and fields"); *fldtab[0] = dollar0; fldtab[0]->sval = record; @@ -74,11 +82,11 @@ void makefields(int n1, int n2) /* create $n1..$n2 inclusive */ int i; for (i = n1; i <= n2; i++) { - fldtab[i] = (Cell *) malloc(sizeof (struct Cell)); + fldtab[i] = malloc(sizeof(**fldtab)); if (fldtab[i] == NULL) FATAL("out of space in makefields %d", i); *fldtab[i] = dollar1; - sprintf(temp, "%d", i); + snprintf(temp, sizeof(temp), "%d", i); fldtab[i]->nval = tostring(temp); } } @@ -97,14 +105,15 @@ void initgetrec(void) argno++; } infile = stdin; /* no filenames, so use stdin */ + innew = 1; } static int firsttime = 1; -int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */ +int getrec(uschar **pbuf, int *pbufsize, int isrecord) /* get next input record */ { /* note: cares whether buf == record */ int c; - char *buf = *pbuf; + uschar *buf = *pbuf; uschar saveb0; int bufsize = *pbufsize, savebufsize = bufsize; @@ -139,9 +148,12 @@ int getrec(char **pbuf, int *pbufsize, int isrecord) /* get next input record */ infile = stdin; else if ((infile = fopen(file, "r")) == NULL) FATAL("can't open file %s", file); + innew = 1; setfval(fnrloc, 0.0); } - c = readrec(&buf, &bufsize, infile); + c = readrec(&buf, &bufsize, infile, innew); + if (innew) + innew = 0; if (c != 0 || buf[0] != '\0') { /* normal record */ if (isrecord) { if (freeable(fldtab[0])) @@ -179,45 +191,71 @@ void nextfile(void) argno++; } -int readrec(char **pbuf, int *pbufsize, FILE *inf) /* read one record into buf */ +int readrec(uschar **pbuf, int *pbufsize, FILE *inf, int newflag) /* read one record into buf */ { - int sep, c; - char *rr, *buf = *pbuf; + int sep, c, isrec, found, tempstat; + uschar *rr, *buf = *pbuf; int bufsize = *pbufsize; - - if (strlen(*FS) >= sizeof(inputFS)) - FATAL("field separator %.10s... is too long", *FS); - strcpy(inputFS, *FS); /* for subsequent field splitting */ - if ((sep = **RS) == 0) { - sep = '\n'; - while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ - ; - if (c != EOF) - ungetc(c, inf); + size_t len; + + if ((len = strlen(*FS)) < len_inputFS) { + strcpy(inputFS, *FS); /* for subsequent field splitting */ + } else { + len_inputFS = len + 1; + inputFS = realloc(inputFS, len_inputFS); + if (inputFS == NULL) + FATAL("field separator %.10s... is too long", *FS); + memcpy(inputFS, *FS, len_inputFS); } - for (rr = buf; ; ) { - for (; (c=getc(inf)) != sep && c != EOF; ) { - if (rr-buf+1 > bufsize) - if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 1")) - FATAL("input record `%.30s...' too long", buf); + if (**RS && (*RS)[1]) { + fa *pfa = makedfa(*RS, 1); + if (newflag) + found = fnematch(pfa, inf, &buf, &bufsize, recsize); + else { + tempstat = pfa->initstat; + pfa->initstat = 2; + found = fnematch(pfa, inf, &buf, &bufsize, recsize); + pfa->initstat = tempstat; + } + if (found) + *patbeg = 0; + } else { + if ((sep = **RS) == 0) { + sep = '\n'; + while ((c=getc(inf)) == '\n' && c != EOF) /* skip leading \n's */ + ; + if (c != EOF) + ungetc(c, inf); + } + for (rr = buf; ; ) { + for (; (c=getc(inf)) != sep && c != EOF; ) { + if (rr-buf+1 > bufsize) + if (!adjbuf(&buf, &bufsize, 1+rr-buf, + recsize, &rr, "readrec 1")) + FATAL("input record `%.30s...'" + " too long", buf); + *rr++ = c; + } + if (**RS == sep || c == EOF) + break; + if ((c = getc(inf)) == '\n' || c == EOF) + /* 2 in a row */ + break; + if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, + "readrec 2")) + FATAL("input record `%.30s...' too long", buf); + *rr++ = '\n'; *rr++ = c; } - if (**RS == sep || c == EOF) - break; - if ((c = getc(inf)) == '\n' || c == EOF) /* 2 in a row */ - break; - if (!adjbuf(&buf, &bufsize, 2+rr-buf, recsize, &rr, "readrec 2")) + if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) FATAL("input record `%.30s...' too long", buf); - *rr++ = '\n'; - *rr++ = c; + *rr = 0; } - if (!adjbuf(&buf, &bufsize, 1+rr-buf, recsize, &rr, "readrec 3")) - FATAL("input record `%.30s...' too long", buf); - *rr = 0; - dprintf( ("readrec saw <%s>, returns %d\n", buf, c == EOF && rr == buf ? 0 : 1) ); *pbuf = buf; *pbufsize = bufsize; - return c == EOF && rr == buf ? 0 : 1; + isrec = *buf || !feof(inf); + dprintf( ("readrec saw <%s>, returns %d\n", buf, isrec) ); + return isrec; } char *getargv(int n) /* get ARGV[n] */ @@ -226,7 +264,7 @@ char *getargv(int n) /* get ARGV[n] */ char *s, temp[50]; extern Array *ARGVtab; - sprintf(temp, "%d", n); + snprintf(temp, sizeof(temp), "%d", n); x = setsymtab(temp, "", 0.0, STR, ARGVtab); s = getsval(x); dprintf( ("getargv(%d) returns |%s|\n", n, s) ); @@ -268,14 +306,15 @@ void fldbld(void) /* create fields from current record */ n = strlen(r); if (n > fieldssize) { xfree(fields); - if ((fields = (char *) malloc(n+1)) == NULL) + if ((fields = malloc(n+1)) == NULL) FATAL("out of space for fields in fldbld %d", n); fieldssize = n; } fr = fields; i = 0; /* number of fields accumulated here */ - strcpy(inputFS, *FS); - if (strlen(inputFS) > 1) { /* it's a regular expression */ + if (!inputFS) { + /* do nothing */ + } else if (inputFS[0] && inputFS[1]) { /* it's a regular expression */ i = refldbld(r, inputFS); } else if ((sep = *inputFS) == ' ') { /* default whitespace */ for (i = 0; ; ) { @@ -347,6 +386,7 @@ void fldbld(void) /* create fields from current record */ } } setfval(nfloc, (Awkfloat) lastfld); + donerec = 1; /* restore */ if (dbg) { for (j = 0; j <= lastfld; j++) { p = fldtab[j]; @@ -364,7 +404,7 @@ void cleanfld(int n1, int n2) /* clean out fields n1 .. n2 inclusive */ p = fldtab[i]; if (freeable(p)) xfree(p->sval); - p->sval = ""; + p->sval = EMPTY; p->tval = FLD | STR | DONTFREE; } } @@ -378,6 +418,19 @@ void newfld(int n) /* add field n after end of existing lastfld */ setfval(nfloc, (Awkfloat) n); } +void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */ +{ + if (n > nfields) + growfldtab(n); + + if (lastfld < n) + cleanfld(lastfld+1, n); + else + cleanfld(n+1, lastfld); + + lastfld = n; +} + Cell *fieldadr(int n) /* get nth field */ { if (n < 0) @@ -395,8 +448,8 @@ void growfldtab(int n) /* make new fields up to at least $n */ if (n > nf) nf = n; s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */ - if (s / sizeof(struct Cell *) - 1 == nf) /* didn't overflow */ - fldtab = (Cell **) realloc(fldtab, s); + if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */ + fldtab = realloc(fldtab, s); else /* overflow sizeof int */ xfree(fldtab); /* make it null */ if (fldtab == NULL) @@ -416,7 +469,7 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F n = strlen(rec); if (n > fieldssize) { xfree(fields); - if ((fields = (char *) malloc(n+1)) == NULL) + if ((fields = malloc(n+1)) == NULL) FATAL("out of space for fields in refldbld %d", n); fieldssize = n; } @@ -438,8 +491,8 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F if (nematch(pfa, rec)) { pfa->initstat = 2; /* horrible coupling to b.c */ dprintf( ("match %s (%d chars)\n", patbeg, patlen) ); - strncpy(fr, rec, patbeg-rec); - fr += patbeg - rec + 1; + strncpy(fr, rec, ((const char*)patbeg)-rec); + fr += ((const char*)patbeg) - rec + 1; *(fr-1) = '\0'; rec = patbeg + patlen; } else { @@ -455,7 +508,8 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F void recbld(void) /* create $0 from $1..$NF if necessary */ { int i; - char *r, *p; + uschar *r; + char *p; if (donerec == 1) return; @@ -517,11 +571,6 @@ void SYNTAX(const char *fmt, ...) eprint(); } -void fpecatch(int n) -{ - FATAL("floating point exception %d", n); -} - extern int bracecnt, brackcnt, parencnt; void bracecheck(void) @@ -603,7 +652,6 @@ void error() void eprint(void) /* try to print context around error */ { char *p, *q; - int c; static int been_here = 0; extern char ebuf[], *ep; @@ -627,11 +675,25 @@ void eprint(void) /* try to print context around error */ if (*p) putc(*p, stderr); fprintf(stderr, " <<< "); - if (*ep) +#if 0 + /* + * The following code was used to print the rest of the line of + * error context. It naively counts brackets, parens and braces in + * order to minimize the parsing effect of dropping the rest of the + * line but it does not work in all the cases. It is too much work + * to save the current program input point and restore it in all the + * cases just for the benefit of error printing so for now this + * code is disabled. In particular this code is confused if the + * [ { ( ) } ] is inside a quoted string or a pattern. + */ + if (*ep) { + int c; while ((c = input()) != '\n' && c != '\0' && c != EOF) { putc(c, stderr); bclass(c); } + } +#endif putc('\n', stderr); ep = ebuf; } @@ -686,7 +748,9 @@ int is_number(const char *s) char *ep; errno = 0; r = strtod(s, &ep); - if (ep == s || r == HUGE_VAL || errno == ERANGE) + if (ep == s || errno == ERANGE) + return 0; + if (ep - s >= 3 && strncasecmp(ep - 3, "nan", 3) == 0) return 0; while (*ep == ' ' || *ep == '\t' || *ep == '\n') ep++; diff --git a/commands/awk/main.c b/external/historical/nawk/dist/main.c similarity index 71% rename from commands/awk/main.c rename to external/historical/nawk/dist/main.c index 704599ce4..9d64d1773 100644 --- a/commands/awk/main.c +++ b/external/historical/nawk/dist/main.c @@ -22,7 +22,11 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ -const char *version = "version 20100208"; +const char *version = "version 20100523"; + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif #define DEBUG #include @@ -38,6 +42,7 @@ extern char **environ; extern int nfields; int dbg = 0; +unsigned int srand_seed; char *cmdname; /* gets argv[0] for error messages */ extern FILE *yyin; /* lex input file */ char *lexprog; /* points to program argument if it exists */ @@ -45,19 +50,59 @@ extern int errorflag; /* non-zero if any syntax errors; set by yyerror */ int compile_time = 2; /* for error printing: */ /* 2 = cmdline, 1 = compile, 0 = running */ -#define MAX_PFILE 20 /* max number of -f's */ - -char *pfile[MAX_PFILE]; /* program filenames from -f's */ -int npfile = 0; /* number of filenames */ -int curpfile = 0; /* current filename */ +static char **pfile = NULL; /* program filenames from -f's */ +static size_t maxpfile = 0; /* max program filenames */ +static size_t npfile = 0; /* number of filenames */ +static size_t curpfile = 0; /* current filename */ int safe = 0; /* 1 => "safe" mode */ +static char * +setfs(char *p) +{ +#ifdef notdef + /* wart: t=>\t */ + if (p[0] == 't' && p[1] == 0) + return "\t"; + else +#endif + if (p[0] != 0) + return p; + return NULL; +} + +__dead static void fpecatch(int n +#ifdef SA_SIGINFO + , siginfo_t *si, void *uc +#endif +) +{ +#ifdef SA_SIGINFO + static const char *emsg[] = { + "Unknown error", + "Integer divide by zero", + "Integer overflow", + "Floating point divide by zero", + "Floating point overflow", + "Floating point underflow", + "Floating point inexact result", + "Invalid Floating point operation", + "Subscript out of range", + }; +#endif + FATAL("floating point exception" +#ifdef SA_SIGINFO + ": %s\n", emsg[si->si_code >= 1 && si->si_code <= 8 ? + si->si_code : 0] +#endif + ); +} + int main(int argc, char *argv[]) { const char *fs = NULL; - setlocale(LC_CTYPE, ""); + setlocale(LC_ALL, ""); setlocale(LC_NUMERIC, "C"); /* for parsing cmdline & prog */ cmdname = argv[0]; if (argc == 1) { @@ -66,7 +111,22 @@ int main(int argc, char *argv[]) cmdname); exit(1); } - signal(SIGFPE, fpecatch); + +#ifdef SA_SIGINFO + { + struct sigaction sa; + sa.sa_sigaction = fpecatch; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + (void)sigaction(SIGFPE, &sa, NULL); + } +#else + (void)signal(SIGFPE, fpecatch); +#endif + /* Set and keep track of the random seed */ + srand_seed = 1; + srand(srand_seed); + yyin = NULL; symtab = makesymtab(NSYMTAB/NSYMTAB); while (argc > 1 && argv[1][0] == '-' && argv[1][1] != '\0') { @@ -90,22 +150,23 @@ int main(int argc, char *argv[]) argv++; if (argc <= 1) FATAL("no program filename"); - if (npfile >= MAX_PFILE - 1) - FATAL("too many -f options"); + if (npfile >= maxpfile) { + maxpfile += 20; + pfile = realloc(pfile, + maxpfile * sizeof(*pfile)); + if (pfile == NULL) + FATAL("error allocating space for " + "-f options"); + } pfile[npfile++] = argv[1]; break; case 'F': /* set field separator */ if (argv[1][2] != 0) { /* arg is -Fsomething */ - if (argv[1][2] == 't' && argv[1][3] == 0) /* wart: t=>\t */ - fs = "\t"; - else if (argv[1][2] != 0) - fs = &argv[1][2]; + fs = setfs(argv[1] + 2); } else { /* arg is -F something */ argc--; argv++; - if (argc > 1 && argv[1][0] == 't' && argv[1][1] == 0) /* wart: t=>\t */ - fs = "\t"; - else if (argc > 1 && argv[1][0] != 0) - fs = &argv[1][0]; + if (argc > 1) + fs = setfs(argv[1]); } if (fs == NULL || *fs == '\0') WARNING("field separator FS is empty"); @@ -113,6 +174,8 @@ int main(int argc, char *argv[]) case 'v': /* -v a=1 to be done NOW. one -v for each */ if (argv[1][2] == '\0' && --argc > 1 && isclvar((++argv)[1])) setclvar(argv[1]); + else if (argv[1][2] != '\0') + setclvar(&argv[1][2]); break; case 'd': dbg = atoi(&argv[1][2]); @@ -148,7 +211,6 @@ int main(int argc, char *argv[]) if (!safe) envinit(environ); yyparse(); - setlocale(LC_NUMERIC, ""); /* back to whatever it is locally */ if (fs) *FS = qstring(fs, '\0'); dprintf( ("errorflag=%d\n", errorflag) ); diff --git a/commands/awk/Makefile.orig b/external/historical/nawk/dist/makefile similarity index 85% rename from commands/awk/Makefile.orig rename to external/historical/nawk/dist/makefile index 7f8a389e2..a454d7ad9 100644 --- a/commands/awk/Makefile.orig +++ b/external/historical/nawk/dist/makefile @@ -26,13 +26,13 @@ CFLAGS = -g CFLAGS = -O2 CFLAGS = -CC = gcc -Wall -g -Wwrite-strings -CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov CC = gcc -Wall -g +CC = /opt/SUNWspro/bin/cc +CC = /opt/pure/purify/purify cc CC = cc +CC = gcc -Wall -g -Wwrite-strings +CC = gcc -fprofile-arcs -ftest-coverage # then gcov f1.c; cat f1.c.gcov CC = gcc -O4 -CC = cc -O - YACC = bison -y YACC = yacc @@ -49,19 +49,13 @@ LISTING = awk.h proto.h awkgram.y lex.c b.c main.c maketab.c parse.c \ SHIP = README FIXES $(SOURCE) ytab[ch].bak makefile makefile.win \ vcvars32.bat buildwin.bat awk.1 -all: awk - -install: awk awk.1 - install -m 755 -o bin -g operator awk /usr/bin/awk - install -m 644 -o bin -g operator awk.1 /usr/man/man1 - -awk: ytab.o $(OFILES) - $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC) -lm -o $@ +a.out: ytab.o $(OFILES) + $(CC) $(CFLAGS) ytab.o $(OFILES) $(ALLOC) -lm $(OFILES): awk.h ytab.h proto.h -ytab.o ytab.c ytab.h: awk.h proto.h awkgram.y - $(YACC) $(YFLAGS) awkgram.y 2>/dev/null +ytab.o: awk.h proto.h awkgram.y + $(YACC) $(YFLAGS) awkgram.y mv y.tab.c ytab.c mv y.tab.h ytab.h $(CC) $(CFLAGS) -c ytab.c @@ -91,4 +85,4 @@ names: @echo $(LISTING) clean: - rm -f awk *.o *.obj maketab maketab.exe *.bb *.bbg *.da *.gcov *.gcno *.gcda # proctab.c + rm -f a.out *.o *.obj maketab maketab.exe ytab.[ch] *.bb *.bbg *.da *.gcov *.gcno *.gcda # proctab.c diff --git a/commands/awk/maketab.c b/external/historical/nawk/dist/maketab.c similarity index 88% rename from commands/awk/maketab.c rename to external/historical/nawk/dist/maketab.c index 608bd5849..1a5c1e596 100644 --- a/commands/awk/maketab.c +++ b/external/historical/nawk/dist/maketab.c @@ -25,9 +25,13 @@ THIS SOFTWARE. /* * this program makes the table to link function names * and type indices that is used by execute() in run.c. - * it finds the indices in awkgram.h, produced by yacc. + * it finds the indices in ytab.h, produced by yacc. */ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #include #include #include @@ -103,6 +107,7 @@ struct xx { ARG, "arg", "arg" }, { VARNF, "getnf", "NF" }, { GETLINE, "awkgetline", "getline" }, + { GENSUB, "gensub", "gensub" }, { 0, "", "" }, }; @@ -128,19 +133,22 @@ int main(int argc, char *argv[]) fprintf(stderr, "maketab can't open awkgram.h!\n"); exit(1); } - printf("static char *printname[%d] = {\n", SIZE); + printf("static const char * const printname[%d] = {\n", SIZE); i = 0; while (fgets(buf, sizeof buf, fp) != NULL) { - n = sscanf(buf, "%1c %s %s %d", &c, def, name, &tok); + n = sscanf(buf, "%1c %199s %199s %d", &c, def, name, &tok); if (c != '#' || (n != 4 && strcmp(def,"define") != 0)) /* not a valid #define */ continue; if (tok < FIRSTTOKEN || tok > LASTTOKEN) { /* fprintf(stderr, "maketab funny token %d %s ignored\n", tok, buf); */ continue; } - names[tok-FIRSTTOKEN] = (char *) malloc(strlen(name)+1); - strcpy(names[tok-FIRSTTOKEN], name); - printf("\t(char *) \"%s\",\t/* %d */\n", name, tok); + names[tok-FIRSTTOKEN] = strdup(name); + if (names[tok-FIRSTTOKEN] == NULL) { + fprintf(stderr, "maketab out of space copying %s", name); + continue; + } + printf("\t\"%s\",\t/* %d */\n", name, tok); i++; } printf("};\n\n"); @@ -155,11 +163,11 @@ int main(int argc, char *argv[]) printf("\t%s,\t/* %s */\n", table[i], names[i]); printf("};\n\n"); - printf("char *tokname(int n)\n"); /* print a tokname() function */ + printf("const char *tokname(int n)\n"); /* print a tokname() function */ printf("{\n"); printf(" static char buf[100];\n\n"); printf(" if (n < FIRSTTOKEN || n > LASTTOKEN) {\n"); - printf(" sprintf(buf, \"token %%d\", n);\n"); + printf(" snprintf(buf, sizeof(buf), \"token %%d\", n);\n"); printf(" return buf;\n"); printf(" }\n"); printf(" return printname[n-FIRSTTOKEN];\n"); diff --git a/commands/awk/parse.c b/external/historical/nawk/dist/parse.c similarity index 91% rename from commands/awk/parse.c rename to external/historical/nawk/dist/parse.c index 05b4d1a8d..503e71623 100644 --- a/commands/awk/parse.c +++ b/external/historical/nawk/dist/parse.c @@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #define DEBUG #include #include @@ -33,7 +37,7 @@ Node *nodealloc(int n) { Node *x; - x = (Node *) malloc(sizeof(Node) + (n-1)*sizeof(Node *)); + x = malloc(sizeof(Node) + (n-1)*sizeof(Node *)); if (x == NULL) FATAL("out of space in nodealloc"); x->nnext = NULL; @@ -93,6 +97,20 @@ Node *node4(int a, Node *b, Node *c, Node *d, Node *e) return(x); } +Node *node5(int a, Node *b, Node *c, Node *d, Node *e, Node *f) +{ + Node *x; + + x = nodealloc(5); + x->nobj = a; + x->narg[0] = b; + x->narg[1] = c; + x->narg[2] = d; + x->narg[3] = e; + x->narg[4] = f; + return(x); +} + Node *stat1(int a, Node *b) { Node *x; @@ -165,6 +183,15 @@ Node *op4(int a, Node *b, Node *c, Node *d, Node *e) return(x); } +Node *op5(int a, Node *b, Node *c, Node *d, Node *e, Node *f) +{ + Node *x; + + x = node5(a,b,c,d,e, f); + x->ntype = NEXPR; + return(x); +} + Node *celltonode(Cell *a, int b) { Node *x; diff --git a/external/historical/nawk/dist/proctab.c b/external/historical/nawk/dist/proctab.c new file mode 100644 index 000000000..9401744a2 --- /dev/null +++ b/external/historical/nawk/dist/proctab.c @@ -0,0 +1,213 @@ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#include +#include "awk.h" +#include "awkgram.h" + +static const char * const printname[94] = { + "FIRSTTOKEN", /* 257 */ + "PROGRAM", /* 258 */ + "PASTAT", /* 259 */ + "PASTAT2", /* 260 */ + "XBEGIN", /* 261 */ + "XEND", /* 262 */ + "NL", /* 263 */ + "ARRAY", /* 264 */ + "MATCH", /* 265 */ + "NOTMATCH", /* 266 */ + "MATCHOP", /* 267 */ + "FINAL", /* 268 */ + "DOT", /* 269 */ + "ALL", /* 270 */ + "CCL", /* 271 */ + "NCCL", /* 272 */ + "CHAR", /* 273 */ + "OR", /* 274 */ + "STAR", /* 275 */ + "QUEST", /* 276 */ + "PLUS", /* 277 */ + "EMPTYRE", /* 278 */ + "AND", /* 279 */ + "BOR", /* 280 */ + "APPEND", /* 281 */ + "EQ", /* 282 */ + "GE", /* 283 */ + "GT", /* 284 */ + "LE", /* 285 */ + "LT", /* 286 */ + "NE", /* 287 */ + "IN", /* 288 */ + "ARG", /* 289 */ + "BLTIN", /* 290 */ + "BREAK", /* 291 */ + "CLOSE", /* 292 */ + "CONTINUE", /* 293 */ + "DELETE", /* 294 */ + "DO", /* 295 */ + "EXIT", /* 296 */ + "FOR", /* 297 */ + "FUNC", /* 298 */ + "SUB", /* 299 */ + "GSUB", /* 300 */ + "IF", /* 301 */ + "INDEX", /* 302 */ + "LSUBSTR", /* 303 */ + "MATCHFCN", /* 304 */ + "NEXT", /* 305 */ + "NEXTFILE", /* 306 */ + "ADD", /* 307 */ + "MINUS", /* 308 */ + "MULT", /* 309 */ + "DIVIDE", /* 310 */ + "MOD", /* 311 */ + "ASSIGN", /* 312 */ + "ASGNOP", /* 313 */ + "ADDEQ", /* 314 */ + "SUBEQ", /* 315 */ + "MULTEQ", /* 316 */ + "DIVEQ", /* 317 */ + "MODEQ", /* 318 */ + "POWEQ", /* 319 */ + "PRINT", /* 320 */ + "PRINTF", /* 321 */ + "SPRINTF", /* 322 */ + "ELSE", /* 323 */ + "INTEST", /* 324 */ + "CONDEXPR", /* 325 */ + "POSTINCR", /* 326 */ + "PREINCR", /* 327 */ + "POSTDECR", /* 328 */ + "PREDECR", /* 329 */ + "VAR", /* 330 */ + "IVAR", /* 331 */ + "VARNF", /* 332 */ + "CALL", /* 333 */ + "NUMBER", /* 334 */ + "STRING", /* 335 */ + "REGEXPR", /* 336 */ + "GETLINE", /* 337 */ + "GENSUB", /* 338 */ + "RETURN", /* 339 */ + "SPLIT", /* 340 */ + "SUBSTR", /* 341 */ + "WHILE", /* 342 */ + "CAT", /* 343 */ + "NOT", /* 344 */ + "UMINUS", /* 345 */ + "POWER", /* 346 */ + "DECR", /* 347 */ + "INCR", /* 348 */ + "INDIRECT", /* 349 */ + "LASTTOKEN", /* 350 */ +}; + + +Cell *(*proctab[94])(Node **, int) = { + nullproc, /* FIRSTTOKEN */ + program, /* PROGRAM */ + pastat, /* PASTAT */ + dopa2, /* PASTAT2 */ + nullproc, /* XBEGIN */ + nullproc, /* XEND */ + nullproc, /* NL */ + array, /* ARRAY */ + matchop, /* MATCH */ + matchop, /* NOTMATCH */ + nullproc, /* MATCHOP */ + nullproc, /* FINAL */ + nullproc, /* DOT */ + nullproc, /* ALL */ + nullproc, /* CCL */ + nullproc, /* NCCL */ + nullproc, /* CHAR */ + nullproc, /* OR */ + nullproc, /* STAR */ + nullproc, /* QUEST */ + nullproc, /* PLUS */ + nullproc, /* EMPTYRE */ + boolop, /* AND */ + boolop, /* BOR */ + nullproc, /* APPEND */ + relop, /* EQ */ + relop, /* GE */ + relop, /* GT */ + relop, /* LE */ + relop, /* LT */ + relop, /* NE */ + instat, /* IN */ + arg, /* ARG */ + bltin, /* BLTIN */ + jump, /* BREAK */ + closefile, /* CLOSE */ + jump, /* CONTINUE */ + awkdelete, /* DELETE */ + dostat, /* DO */ + jump, /* EXIT */ + forstat, /* FOR */ + nullproc, /* FUNC */ + sub, /* SUB */ + gsub, /* GSUB */ + ifstat, /* IF */ + sindex, /* INDEX */ + nullproc, /* LSUBSTR */ + matchop, /* MATCHFCN */ + jump, /* NEXT */ + jump, /* NEXTFILE */ + arith, /* ADD */ + arith, /* MINUS */ + arith, /* MULT */ + arith, /* DIVIDE */ + arith, /* MOD */ + assign, /* ASSIGN */ + nullproc, /* ASGNOP */ + assign, /* ADDEQ */ + assign, /* SUBEQ */ + assign, /* MULTEQ */ + assign, /* DIVEQ */ + assign, /* MODEQ */ + assign, /* POWEQ */ + printstat, /* PRINT */ + awkprintf, /* PRINTF */ + awksprintf, /* SPRINTF */ + nullproc, /* ELSE */ + intest, /* INTEST */ + condexpr, /* CONDEXPR */ + incrdecr, /* POSTINCR */ + incrdecr, /* PREINCR */ + incrdecr, /* POSTDECR */ + incrdecr, /* PREDECR */ + nullproc, /* VAR */ + nullproc, /* IVAR */ + getnf, /* VARNF */ + call, /* CALL */ + nullproc, /* NUMBER */ + nullproc, /* STRING */ + nullproc, /* REGEXPR */ + awkgetline, /* GETLINE */ + gensub, /* GENSUB */ + jump, /* RETURN */ + split, /* SPLIT */ + substr, /* SUBSTR */ + whilestat, /* WHILE */ + cat, /* CAT */ + boolop, /* NOT */ + arith, /* UMINUS */ + arith, /* POWER */ + nullproc, /* DECR */ + nullproc, /* INCR */ + indirect, /* INDIRECT */ + nullproc, /* LASTTOKEN */ +}; + +const char *tokname(int n) +{ + static char buf[100]; + + if (n < FIRSTTOKEN || n > LASTTOKEN) { + snprintf(buf, sizeof(buf), "token %d", n); + return buf; + } + return printname[n-FIRSTTOKEN]; +} diff --git a/commands/awk/proto.h b/external/historical/nawk/dist/proto.h similarity index 84% rename from commands/awk/proto.h rename to external/historical/nawk/dist/proto.h index 359ae64c9..f1bb62daa 100644 --- a/commands/awk/proto.h +++ b/external/historical/nawk/dist/proto.h @@ -43,17 +43,18 @@ extern fa *mkdfa(const char *, int); extern int makeinit(fa *, int); extern void penter(Node *); extern void freetr(Node *); -extern int hexstr(char **); -extern int quoted(char **); +extern int hexstr(const uschar **); +extern int quoted(const uschar **); extern char *cclenter(const char *); -extern void overflo(const char *); +extern void overflo(const char *) __dead; extern void cfoll(fa *, Node *); -extern int first(const Node *); +extern int first(Node *); extern void follow(Node *); extern int member(int, const char *); extern int match(fa *, const char *); extern int pmatch(fa *, const char *); extern int nematch(fa *, const char *); +extern int fnematch(fa *, FILE *, uschar **, int *, int); extern Node *reparse(const char *); extern Node *regexp(void); extern Node *primary(void); @@ -73,12 +74,14 @@ extern Node *node1(int, Node *); extern Node *node2(int, Node *, Node *); extern Node *node3(int, Node *, Node *, Node *); extern Node *node4(int, Node *, Node *, Node *, Node *); +extern Node *node5(int, Node *, Node *, Node *, Node *, Node *); extern Node *stat3(int, Node *, Node *, Node *); extern Node *op2(int, Node *, Node *); extern Node *op1(int, Node *); extern Node *stat1(int, Node *); extern Node *op3(int, Node *, Node *, Node *); extern Node *op4(int, Node *, Node *, Node *, Node *); +extern Node *op5(int, Node *, Node *, Node *, Node *, Node *); extern Node *stat2(int, Node *, Node *); extern Node *stat4(int, Node *, Node *, Node *, Node *); extern Node *celltonode(Cell *, int); @@ -88,7 +91,7 @@ extern Node *pa2stat(Node *, Node *, Node *); extern Node *linkum(Node *, Node *); extern void defn(Cell *, Node *, Node *); extern int isarg(const char *); -extern char *tokname(int); +extern const char *tokname(int); extern Cell *(*proctab[])(Node **, int); extern int ptoi(void *); extern Node *itonp(int); @@ -97,12 +100,12 @@ extern void syminit(void); extern void arginit(int, char **); extern void envinit(char **); extern Array *makesymtab(int); -extern void freesymtab(const Cell *); -extern void freeelem(const Cell *, const char *); +extern void freesymtab(Cell *); +extern void freeelem(Cell *, const char *); extern Cell *setsymtab(const char *, const char *, double, unsigned int, Array *); extern int hash(const char *, int); extern void rehash(Array *); -extern Cell *lookup(const char *, const Array *); +extern Cell *lookup(const char *, Array *); extern double setfval(Cell *, double); extern void funnyvar(Cell *, const char *); extern char *setsval(Cell *, const char *); @@ -110,30 +113,35 @@ extern double getfval(Cell *); extern char *getsval(Cell *); extern char *getpssval(Cell *); /* for print */ extern char *tostring(const char *); +extern char *tostringN(const char *, size_t n); extern char *qstring(const char *, int); +extern Cell *catstr(Cell *, Cell *); extern void recinit(unsigned int); extern void initgetrec(void); extern void makefields(int, int); extern void growfldtab(int n); -extern int getrec(char **, int *, int); +extern int getrec(uschar **, int *, int); extern void nextfile(void); -extern int readrec(char **buf, int *bufsize, FILE *inf); +extern int readrec(uschar **buf, int *bufsize, FILE *inf, int newflag); extern char *getargv(int); extern void setclvar(char *); extern void fldbld(void); extern void cleanfld(int, int); extern void newfld(int); +extern void setlastfld(int); extern int refldbld(const char *, const char *); extern void recbld(void); extern Cell *fieldadr(int); extern void yyerror(const char *); -extern void fpecatch(int); extern void bracecheck(void); extern void bcheck2(int, int, int); -extern void SYNTAX(const char *, ...); -extern void FATAL(const char *, ...); -extern void WARNING(const char *, ...); +extern void SYNTAX(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); +extern void FATAL(const char *, ...) __dead + __attribute__((__format__(__printf__, 1, 2))); +extern void WARNING(const char *, ...) + __attribute__((__format__(__printf__, 1, 2))); extern void error(void); extern void eprint(void); extern void bclass(int); @@ -141,7 +149,7 @@ extern double errcheck(double, const char *); extern int isclvar(const char *); extern int is_number(const char *); -extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, const char *what); +extern int adjbuf(uschar **pb, int *sz, int min, int q, uschar **pbp, const char *what); extern void run(Node *); extern Cell *execute(Node *); extern Cell *program(Node **, int); @@ -184,12 +192,13 @@ extern Cell *bltin(Node **, int); extern Cell *printstat(Node **, int); extern Cell *nullproc(Node **, int); extern FILE *redirect(int, Node *); -extern FILE *openfile(int, const char *); +extern FILE *openfile(int, const char *, int *); extern const char *filename(FILE *); extern Cell *closefile(Node **, int); extern void closeall(void); extern Cell *sub(Node **, int); extern Cell *gsub(Node **, int); +extern Cell *gensub(Node **, int); extern FILE *popen(const char *, const char *); extern int pclose(FILE *); diff --git a/commands/awk/run.c b/external/historical/nawk/dist/run.c similarity index 76% rename from commands/awk/run.c rename to external/historical/nawk/dist/run.c index 128761042..44cadc24c 100644 --- a/commands/awk/run.c +++ b/external/historical/nawk/dist/run.c @@ -22,19 +22,28 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #define DEBUG #include #include +#include +#include #include #include #include #include #include #include +#include #include "awk.h" #include "awkgram.h" -#define tempfree(x) if (istemp(x)) tfree(x); else +#define tempfree(x) do { if (istemp(x)) tfree(x); } while (/*CONSTCOND*/0) + +void stdinit(void); /* #undef tempfree @@ -66,32 +75,33 @@ void tempfree(Cell *p) { jmp_buf env; extern int pairstack[]; +extern unsigned int srand_seed; Node *winner = NULL; /* root of parse tree */ Cell *tmps; /* free temporary cells for execution */ -static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM }; +static Cell truecell ={ OBOOL, BTRUE, 0, 0, 1.0, NUM, NULL }; Cell *True = &truecell; -static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM }; +static Cell falsecell ={ OBOOL, BFALSE, 0, 0, 0.0, NUM, NULL }; Cell *False = &falsecell; -static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM }; +static Cell breakcell ={ OJUMP, JBREAK, 0, 0, 0.0, NUM, NULL }; Cell *jbreak = &breakcell; -static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM }; +static Cell contcell ={ OJUMP, JCONT, 0, 0, 0.0, NUM, NULL }; Cell *jcont = &contcell; -static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM }; +static Cell nextcell ={ OJUMP, JNEXT, 0, 0, 0.0, NUM, NULL }; Cell *jnext = &nextcell; -static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM }; +static Cell nextfilecell ={ OJUMP, JNEXTFILE, 0, 0, 0.0, NUM, NULL}; Cell *jnextfile = &nextfilecell; -static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM }; +static Cell exitcell ={ OJUMP, JEXIT, 0, 0, 0.0, NUM, NULL }; Cell *jexit = &exitcell; -static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM }; +static Cell retcell ={ OJUMP, JRET, 0, 0, 0.0, NUM, NULL }; Cell *jret = &retcell; -static Cell tempcell ={ OCELL, CTEMP, 0, "", 0.0, NUM|STR|DONTFREE }; +static Cell tempcell ={ OCELL, CTEMP, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL }; Node *curnode = NULL; /* the node being executed, for debugging */ /* buffer memory management */ -int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, +int adjbuf(uschar **pbuf, int *psiz, int minlen, int quantum, uschar **pbptr, const char *whatrtn) /* pbuf: address of pointer to buffer being managed * psiz: address of buffer size variable @@ -110,7 +120,7 @@ int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, /* round up to next multiple of quantum */ if (rminlen) minlen += quantum - rminlen; - tbuf = (char *) realloc(*pbuf, minlen); + tbuf = realloc(*pbuf, minlen); dprintf( ("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, *pbuf, tbuf) ); if (tbuf == NULL) { if (whatrtn) @@ -127,8 +137,6 @@ int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr, void run(Node *a) /* execution of parse tree starts here */ { - extern void stdinit(void); - stdinit(); execute(a); closeall(); @@ -216,11 +224,11 @@ struct Frame { /* stack frame for awk function calls */ struct Frame *frame = NULL; /* base of stack frames; dynamically allocated */ int nframe = 0; /* number of frames allocated */ -struct Frame *fp = NULL; /* frame pointer. bottom level unused */ +struct Frame *frp = NULL; /* frame pointer. bottom level unused */ Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ { - static Cell newcopycell = { OCELL, CCOPY, 0, "", 0.0, NUM|STR|DONTFREE }; + static const Cell newcopycell = { OCELL, CCOPY, 0, EMPTY, 0.0, NUM|STR|DONTFREE, NULL }; int i, ncall, ndef; int freed = 0; /* handles potential double freeing when fcn & param share a tempcell */ Node *x; @@ -233,21 +241,21 @@ Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ if (!isfcn(fcn)) FATAL("calling undefined function %s", s); if (frame == NULL) { - fp = frame = (struct Frame *) calloc(nframe += 100, sizeof(struct Frame)); + frp = frame = calloc(nframe += 100, sizeof(*frp)); if (frame == NULL) FATAL("out of space for stack frames calling %s", s); } for (ncall = 0, x = a[1]; x != NULL; x = x->nnext) /* args in call */ ncall++; ndef = (int) fcn->fval; /* args in defn */ - dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (fp-frame)) ); + dprintf( ("calling %s, %d args (%d in defn), fp=%d\n", s, ncall, ndef, (int) (frp-frame)) ); if (ncall > ndef) WARNING("function %s called with %d args, uses only %d", s, ncall, ndef); if (ncall + ndef > NARGS) FATAL("function %s has %d arguments, limit %d", s, ncall+ndef, NARGS); for (i = 0, x = a[1]; x != NULL; i++, x = x->nnext) { /* get call args */ - dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (fp-frame)) ); + dprintf( ("evaluate args[%d], fp=%d:\n", i, (int) (frp-frame)) ); y = execute(x); oargs[i] = y; dprintf( ("args[%d]: %s %f <%s>, t=%o\n", @@ -264,26 +272,25 @@ Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ args[i] = gettemp(); *args[i] = newcopycell; } - fp++; /* now ok to up frame */ - if (fp >= frame + nframe) { - int dfp = fp - frame; /* old index */ - frame = (struct Frame *) - realloc((char *) frame, (nframe += 100) * sizeof(struct Frame)); + frp++; /* now ok to up frame */ + if (frp >= frame + nframe) { + int dfp = frp - frame; /* old index */ + frame = realloc(frame, (nframe += 100) * sizeof(*frame)); if (frame == NULL) FATAL("out of space for stack frames in %s", s); - fp = frame + dfp; + frp = frame + dfp; } - fp->fcncell = fcn; - fp->args = args; - fp->nargs = ndef; /* number defined with (excess are locals) */ - fp->retval = gettemp(); + frp->fcncell = fcn; + frp->args = args; + frp->nargs = ndef; /* number defined with (excess are locals) */ + frp->retval = gettemp(); - dprintf( ("start exec of %s, fp=%d\n", s, (int) (fp-frame)) ); + dprintf( ("start exec of %s, fp=%d\n", s, (int) (frp-frame)) ); y = execute((Node *)(fcn->sval)); /* execute body */ - dprintf( ("finished exec of %s, fp=%d\n", s, (int) (fp-frame)) ); + dprintf( ("finished exec of %s, fp=%d\n", s, (int) (frp-frame)) ); for (i = 0; i < ndef; i++) { - Cell *t = fp->args[i]; + Cell *t = frp->args[i]; if (isarr(t)) { if (t->csub == CCOPY) { if (i >= ncall) { @@ -312,9 +319,9 @@ Cell *call(Node **a, int n) /* function call. very kludgy and fragile */ if (freed == 0) { tempfree(y); /* don't free twice! */ } - z = fp->retval; /* return value */ + z = frp->retval; /* return value */ dprintf( ("%s returns %g |%s| %o\n", s, getfval(z), getsval(z), z->tval) ); - fp--; + frp--; return(z); } @@ -322,14 +329,18 @@ Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ { Cell *y; + /* copy is not constant or field */ + y = gettemp(); + y->tval = x->tval & ~(CON|FLD|REC); y->csub = CCOPY; /* prevents freeing until call is over */ y->nval = x->nval; /* BUG? */ - if (isstr(x)) + if (isstr(x) /* || x->ctype == OCELL */) { y->sval = tostring(x->sval); + y->tval &= ~DONTFREE; + } else + y->tval |= DONTFREE; y->fval = x->fval; - y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ - /* is DONTFREE right? */ return y; } @@ -337,11 +348,11 @@ Cell *arg(Node **a, int n) /* nth argument of a function */ { n = ptoi(a[0]); /* argument number, counting from 0 */ - dprintf( ("arg(%d), fp->nargs=%d\n", n, fp->nargs) ); - if (n+1 > fp->nargs) + dprintf( ("arg(%d), fp->nargs=%d\n", n, frp->nargs) ); + if (n+1 > frp->nargs) FATAL("argument #%d of function %s was not supplied", - n+1, fp->fcncell->nval); - return fp->args[n]; + n+1, frp->fcncell->nval); + return frp->args[n]; } Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ @@ -360,14 +371,14 @@ Cell *jump(Node **a, int n) /* break, continue, next, nextfile, return */ if (a[0] != NULL) { y = execute(a[0]); if ((y->tval & (STR|NUM)) == (STR|NUM)) { - setsval(fp->retval, getsval(y)); - fp->retval->fval = getfval(y); - fp->retval->tval |= NUM; + setsval(frp->retval, getsval(y)); + frp->retval->fval = getfval(y); + frp->retval->tval |= NUM; } else if (y->tval & STR) - setsval(fp->retval, getsval(y)); + setsval(frp->retval, getsval(y)); else if (y->tval & NUM) - setfval(fp->retval, getfval(y)); + setfval(frp->retval, getfval(y)); else /* can't happen */ FATAL("bad type variable %d", y->tval); tempfree(y); @@ -393,11 +404,11 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */ Cell *r, *x; extern Cell **fldtab; FILE *fp; - char *buf; + uschar *buf; int bufsize = recsize; - int mode; + int mode, newflag; - if ((buf = (char *) malloc(bufsize)) == NULL) + if ((buf = malloc(bufsize)) == NULL) FATAL("out of memory in getline"); fflush(stdout); /* in case someone is waiting for a prompt */ @@ -407,12 +418,12 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */ mode = ptoi(a[1]); if (mode == '|') /* input pipe */ mode = LE; /* arbitrary flag */ - fp = openfile(mode, getsval(x)); + fp = openfile(mode, getsval(x), &newflag); tempfree(x); if (fp == NULL) n = -1; else - n = readrec(&buf, &bufsize, fp); + n = readrec(&buf, &bufsize, fp, newflag); if (n <= 0) { ; } else if (a[0] != NULL) { /* getline var nval, buf); - strcat(buf, s); + strlcat(buf, s, bufsz); if (np->nnext) - strcat(buf, *SUBSEP); + strlcat(buf, *SUBSEP, bufsz); tempfree(y); } if (!isarr(x)) { @@ -492,7 +503,7 @@ Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts * { Cell *x, *y; Node *np; - char *s; + uschar *s; int nsub = strlen(*SUBSEP); x = execute(a[0]); /* Cell* for symbol table */ @@ -505,8 +516,8 @@ Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts * x->sval = (char *) makesymtab(NSYMTAB); } else { int bufsz = recsize; - char *buf; - if ((buf = (char *) malloc(bufsz)) == NULL) + uschar *buf; + if ((buf = malloc(bufsz)) == NULL) FATAL("out of memory in adelete"); buf[0] = 0; for (np = a[1]; np; np = np->nnext) { @@ -514,9 +525,9 @@ Cell *awkdelete(Node **a, int n) /* a[0] is symtab, a[1] is list of subscripts * s = getsval(y); if (!adjbuf(&buf, &bufsz, strlen(buf)+strlen(s)+nsub+1, recsize, 0, "awkdelete")) FATAL("out of memory deleting %s[%s...]", x->nval, buf); - strcat(buf, s); + strlcat(buf, s, bufsz); if (np->nnext) - strcat(buf, *SUBSEP); + strlcat(buf, *SUBSEP, bufsz); tempfree(y); } freeelem(x, buf); @@ -530,7 +541,7 @@ Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ { Cell *x, *ap, *k; Node *p; - char *buf; + uschar *buf; char *s; int bufsz = recsize; int nsub = strlen(*SUBSEP); @@ -544,7 +555,7 @@ Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ ap->tval |= ARR; ap->sval = (char *) makesymtab(NSYMTAB); } - if ((buf = (char *) malloc(bufsz)) == NULL) { + if ((buf = malloc(bufsz)) == NULL) { FATAL("out of memory in intest"); } buf[0] = 0; @@ -571,7 +582,8 @@ Cell *intest(Node **a, int n) /* a[0] is index (list), a[1] is symtab */ Cell *matchop(Node **a, int n) /* ~ and match() */ { Cell *x, *y; - char *s, *t; + uschar *s; + char *t; int i; fa *pfa; int (*mf)(fa *, const char *) = match, mode = 0; @@ -693,7 +705,7 @@ Cell *gettemp(void) /* get a tempcell */ Cell *x; if (!tmps) { - tmps = (Cell *) calloc(100, sizeof(Cell)); + tmps = calloc(100, sizeof(*tmps)); if (!tmps) FATAL("out of space for temporaries"); for(i = 1; i < 100; i++) @@ -806,19 +818,20 @@ Cell *sindex(Node **a, int nnn) /* index(a[0], a[1]) */ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like conversions */ { - char *fmt; - char *p, *t; + uschar *fmt, *p, *t; const char *os; Cell *x; int flag = 0, n; int fmtwd; /* format width */ int fmtsz = recsize; - char *buf = *pbuf; + uschar *buf = *pbuf; int bufsize = *pbufsize; +#define FMTSZ(a) (fmtsz - ((a) - fmt)) +#define BUFSZ(a) (bufsize - ((a) - buf)) os = s; p = buf; - if ((fmt = (char *) malloc(fmtsz)) == NULL) + if ((fmt = malloc(fmtsz)) == NULL) FATAL("out of memory in format()"); while (*s) { adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1"); @@ -839,12 +852,18 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co for (t = fmt; (*t++ = *s) != '\0'; s++) { if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3")) FATAL("format item %.30s... ran format() out of memory", os); - if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L') + if (*s == 'l' || *s == 'h' || *s == 'L') + goto weird; + if (isalpha((uschar)*s)) break; /* the ansi panoply */ if (*s == '*') { + if (a == NULL) + FATAL("not enough args in printf(" + "\"%.30s\")", os); x = execute(a); a = a->nnext; - sprintf(t-1, "%d", fmtwd=(int) getfval(x)); + snprintf(t - 1, FMTSZ(t - 1), + "%d", fmtwd=(int) getfval(x)); if (fmtwd < 0) fmtwd = -fmtwd; adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format"); @@ -864,12 +883,15 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co case 'd': case 'i': flag = 'd'; if(*(s-1) == 'l') break; - *(t-1) = 'l'; + *(t-1) = 'j'; *t = 'd'; *++t = '\0'; break; case 'o': case 'x': case 'X': case 'u': flag = *(s-1) == 'l' ? 'd' : 'u'; + *(t-1) = 'j'; + *t = *s; + *++t = '\0'; break; case 's': flag = 's'; @@ -878,6 +900,7 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co flag = 'c'; break; default: + weird: WARNING("weird printf conversion %s", fmt); flag = '?'; break; @@ -891,18 +914,18 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co n = fmtwd; adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format5"); switch (flag) { - case '?': sprintf(p, "%s", fmt); /* unknown, so dump it too */ + case '?': snprintf(p, BUFSZ(p), "%s", fmt); /* unknown, so dump it too */ t = getsval(x); n = strlen(t); if (fmtwd > n) n = fmtwd; adjbuf(&buf, &bufsize, 1+strlen(p)+n+p-buf, recsize, &p, "format6"); p += strlen(p); - sprintf(p, "%s", t); + snprintf(p, BUFSZ(p), "%s", t); break; - case 'f': sprintf(p, fmt, getfval(x)); break; - case 'd': sprintf(p, fmt, (long) getfval(x)); break; - case 'u': sprintf(p, fmt, (int) getfval(x)); break; + case 'f': snprintf(p, BUFSZ(p), fmt, getfval(x)); break; + case 'd': snprintf(p, BUFSZ(p), fmt, (intmax_t) getfval(x)); break; + case 'u': snprintf(p, BUFSZ(p), fmt, (uintmax_t) getfval(x)); break; case 's': t = getsval(x); n = strlen(t); @@ -910,18 +933,18 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co n = fmtwd; if (!adjbuf(&buf, &bufsize, 1+n+p-buf, recsize, &p, "format7")) FATAL("huge string/format (%d chars) in printf %.30s... ran format() out of memory", n, t); - sprintf(p, fmt, t); + snprintf(p, BUFSZ(p), fmt, t); break; case 'c': if (isnum(x)) { if (getfval(x)) - sprintf(p, fmt, (int) getfval(x)); + snprintf(p, BUFSZ(p), fmt, (int) getfval(x)); else { *p++ = '\0'; /* explicit null byte */ *p = '\0'; /* next output will start here */ } } else - sprintf(p, fmt, getsval(x)[0]); + snprintf(p, BUFSZ(p), fmt, getsval(x)[0]); break; default: FATAL("can't happen: bad conversion %c in format()", flag); @@ -946,7 +969,7 @@ Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */ char *buf; int bufsz=3*recsize; - if ((buf = (char *) malloc(bufsz)) == NULL) + if ((buf = malloc(bufsz)) == NULL) FATAL("out of memory in awksprintf"); y = a[0]->nnext; x = execute(a[0]); @@ -969,7 +992,7 @@ Cell *awkprintf(Node **a, int n) /* printf */ int len; int bufsz=3*recsize; - if ((buf = (char *) malloc(bufsz)) == NULL) + if ((buf = malloc(bufsz)) == NULL) FATAL("out of memory in awkprintf"); y = a[0]->nnext; x = execute(a[0]); @@ -1153,7 +1176,7 @@ Cell *cat(Node **a, int q) /* a[0] cat a[1] */ getsval(y); n1 = strlen(x->sval); n2 = strlen(y->sval); - s = (char *) malloc(n1 + n2 + 1); + s = malloc(n1 + n2 + 1); if (s == NULL) FATAL("out of space concatenating %.15s... and %.15s...", x->sval, y->sval); @@ -1206,6 +1229,7 @@ Cell *dopa2(Node **a, int n) /* a[0], a[1] { a[2] } */ return(False); } +static char regexpr[] = "(regexpr)"; Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ { Cell *x = 0, *y, *ap; @@ -1223,7 +1247,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ x = execute(a[2]); fs = getsval(x); } else if (arg3type == REGEXPR) - fs = "(regexpr)"; /* split(str,arr,/regexpr/) */ + fs = regexpr; /* split(str,arr,/regexpr/) */ else FATAL("illegal type of split"); sep = *fs; @@ -1247,7 +1271,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ pfa->initstat = 2; do { n++; - sprintf(num, "%d", n); + snprintf(num, sizeof(num), "%d", n); temp = *patbeg; *patbeg = '\0'; if (is_number(s)) @@ -1258,7 +1282,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ s = patbeg + patlen; if (*(patbeg+patlen-1) == 0 || *s == 0) { n++; - sprintf(num, "%d", n); + snprintf(num, sizeof(num), "%d", n); setsymtab(num, "", 0.0, STR, (Array *) ap->sval); pfa->initstat = tempstat; goto spdone; @@ -1268,7 +1292,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ /* cf gsub and refldbld */ } n++; - sprintf(num, "%d", n); + snprintf(num, sizeof(num), "%d", n); if (is_number(s)) setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval); else @@ -1288,7 +1312,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ while (*s!=' ' && *s!='\t' && *s!='\n' && *s!='\0'); temp = *s; *s = '\0'; - sprintf(num, "%d", n); + snprintf(num, sizeof(num), "%d", n); if (is_number(t)) setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); else @@ -1301,7 +1325,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ for (n = 0; *s != 0; s++) { char buf[2]; n++; - sprintf(num, "%d", n); + snprintf(num, sizeof(num), "%d", n); buf[0] = *s; buf[1] = 0; if (isdigit((uschar)buf[0])) @@ -1317,7 +1341,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */ s++; temp = *s; *s = '\0'; - sprintf(num, "%d", n); + snprintf(num, sizeof(num), "%d", n); if (is_number(t)) setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval); else @@ -1461,15 +1485,78 @@ Cell *instat(Node **a, int n) /* for (a[0] in a[1]) a[2] */ return True; } +void flush_all(void); + +static char *nawk_toXXX(const char *s, + int (*fun_c)(int), + wint_t (*fun_wc)(wint_t)) +{ + char *buf = NULL; + char *pbuf = NULL; + const char *ps = NULL; + size_t n = 0; + mbstate_t mbs, mbs2; + wchar_t wc; + size_t sz = MB_CUR_MAX; + + if (sz == 1) { + buf = tostring(s); + + for (pbuf = buf; *pbuf; pbuf++) + *pbuf = fun_c((uschar)*pbuf); + + return buf; + } else { + /* upper/lower character may be shorter/longer */ + buf = tostringN(s, strlen(s) * sz + 1); + + memset(&mbs, 0, sizeof(mbs)); + memset(&mbs2, 0, sizeof(mbs2)); + + ps = s; + pbuf = buf; + while (n = mbrtowc(&wc, ps, sz, &mbs), + n > 0 && n != (size_t)-1 && n != (size_t)-2) + { + ps += n; + + n = wcrtomb(pbuf, fun_wc(wc), &mbs2); + if (n == (size_t)-1) + FATAL("illegal wide character %s", s); + + pbuf += n; + } + + *pbuf = 0; + + if (n) + FATAL("illegal byte sequence %s", s); + + return buf; + } +} + +static char *nawk_toupper(const char *s) +{ + return nawk_toXXX(s, toupper, towupper); +} + +static char *nawk_tolower(const char *s) +{ + return nawk_toXXX(s, tolower, towlower); +} + Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg list */ { Cell *x, *y; Awkfloat u; - int t; - char *p, *buf; + int t, sz; + unsigned int tmp; + char *buf, *fmt; Node *nextarg; FILE *fp; - void flush_all(void); + time_t tv; + struct tm *tm; t = ptoi(a[0]); x = execute(a[1]); @@ -1517,20 +1604,16 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis u = time((time_t *)0); else u = getfval(x); - srand((unsigned int) u); + srand(tmp = (unsigned int) u); + u = srand_seed; + srand_seed = tmp; break; case FTOUPPER: case FTOLOWER: - buf = tostring(getsval(x)); - if (t == FTOUPPER) { - for (p = buf; *p; p++) - if (islower((uschar) *p)) - *p = toupper((uschar)*p); - } else { - for (p = buf; *p; p++) - if (isupper((uschar) *p)) - *p = tolower((uschar)*p); - } + if (t == FTOUPPER) + buf = nawk_toupper(getsval(x)); + else + buf = nawk_tolower(getsval(x)); tempfree(x); x = gettemp(); setsval(x, buf); @@ -1540,11 +1623,41 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis if (isrec(x) || strlen(getsval(x)) == 0) { flush_all(); /* fflush() or fflush("") -> all */ u = 0; - } else if ((fp = openfile(FFLUSH, getsval(x))) == NULL) - u = EOF; + } else if ((fp = openfile(FFLUSH, getsval(x), NULL)) == NULL) + u = -1; else u = fflush(fp); break; + case FSYSTIME: + u = time((time_t *) 0); break; + case FSTRFTIME: + /* strftime([format [,timestamp]]) */ + if (nextarg) { + y = execute(nextarg), nextarg = nextarg->nnext; + tv = (time_t) getfval(y); + tempfree(y); + } else + tv = time((time_t *) 0); + tm = localtime(&tv); + + if (isrec(x)) { + /* format argument not provided, use default */ + fmt = tostring("%a %b %d %H:%M:%S %Z %Y"); + } else + fmt = tostring(getsval(x)); + + sz = 32, buf = NULL; + do { + if ((buf = realloc(buf, (sz *= 2))) == NULL) + FATAL("out of memory in strftime"); + } while(strftime(buf, sz, fmt, tm) == 0); + + y = gettemp(); + setsval(y, buf); + free(fmt); + free(buf); + + return y; default: /* can't happen */ FATAL("illegal function type %d", t); break; @@ -1602,7 +1715,7 @@ FILE *redirect(int a, Node *b) /* set up all i/o redirections */ x = execute(b); fname = getsval(x); - fp = openfile(a, fname); + fp = openfile(a, fname, NULL); if (fp == NULL) FATAL("can't open file %s", fname); tempfree(x); @@ -1613,42 +1726,59 @@ struct files { FILE *fp; const char *fname; int mode; /* '|', 'a', 'w' => LE/LT, GT */ -} files[FOPEN_MAX] ={ - { NULL, "/dev/stdin", LT }, /* watch out: don't free this! */ - { NULL, "/dev/stdout", GT }, - { NULL, "/dev/stderr", GT } -}; +} *files; +size_t nfiles; void stdinit(void) /* in case stdin, etc., are not constants */ { + nfiles = FOPEN_MAX; + files = calloc(nfiles, sizeof(*files)); + if (files == NULL) + FATAL("can't allocate file memory for %zu files", nfiles); files[0].fp = stdin; + files[0].fname = "/dev/stdin"; + files[0].mode = LT; files[1].fp = stdout; + files[1].fname = "/dev/stdout"; + files[1].mode = GT; files[2].fp = stderr; + files[2].fname = "/dev/stderr"; + files[2].mode = GT; } -FILE *openfile(int a, const char *us) +FILE *openfile(int a, const char *us, int *pnewflag) { const char *s = us; - int i, m; + size_t i; + int m; FILE *fp = 0; if (*s == '\0') FATAL("null file name in print or getline"); - for (i=0; i < FOPEN_MAX; i++) - if (files[i].fname && strcmp(s, files[i].fname) == 0) { - if (a == files[i].mode || (a==APPEND && files[i].mode==GT)) - return files[i].fp; - if (a == FFLUSH) - return files[i].fp; + for (i = 0; i < nfiles; i++) + if (files[i].fname && strcmp(s, files[i].fname) == 0 && + (a == files[i].mode || (a==APPEND && files[i].mode==GT) || + a == FFLUSH)) { + if (pnewflag) + *pnewflag = 0; + return files[i].fp; } if (a == FFLUSH) /* didn't find it, so don't create it! */ return NULL; - for (i=0; i < FOPEN_MAX; i++) - if (files[i].fp == 0) + for (i = 0; i < nfiles; i++) + if (files[i].fp == NULL) break; - if (i >= FOPEN_MAX) - FATAL("%s makes too many open files", s); + if (i >= nfiles) { + struct files *nf; + size_t nnf = nfiles + FOPEN_MAX; + nf = realloc(files, nnf * sizeof(*nf)); + if (nf == NULL) + FATAL("cannot grow files for %s and %zu files", s, nnf); + (void)memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf)); + nfiles = nnf; + files = nf; + } fflush(stdout); /* force a semblance of order */ m = a; if (a == GT) { @@ -1668,15 +1798,17 @@ FILE *openfile(int a, const char *us) files[i].fname = tostring(s); files[i].fp = fp; files[i].mode = m; + if (pnewflag) + *pnewflag = 1; } return fp; } const char *filename(FILE *fp) { - int i; + size_t i; - for (i = 0; i < FOPEN_MAX; i++) + for (i = 0; i < nfiles; i++) if (fp == files[i].fp) return files[i].fname; return "???"; @@ -1685,24 +1817,28 @@ const char *filename(FILE *fp) Cell *closefile(Node **a, int n) { Cell *x; - int i, stat; + size_t i; + int stat; n = n; x = execute(a[0]); getsval(x); stat = -1; - for (i = 0; i < FOPEN_MAX; i++) { + for (i = 0; i < nfiles; i++) { if (files[i].fname && strcmp(x->sval, files[i].fname) == 0) { if (ferror(files[i].fp)) WARNING( "i/o error occurred on %s", files[i].fname ); if (files[i].mode == '|' || files[i].mode == LE) - stat = pclose(files[i].fp); + stat = pclose(files[i].fp) == -1; else - stat = fclose(files[i].fp); - if (stat == EOF) - WARNING( "i/o error occurred closing %s", files[i].fname ); + stat = fclose(files[i].fp) == EOF; + if (stat) { + stat = -1; + WARNING( "i/o error occurred closing %s", + files[i].fname ); + } if (i > 2) /* don't do /dev/std... */ - xfree(files[i].fname); + free(__UNCONST(files[i].fname)); files[i].fname = NULL; /* watch out for ref thru this */ files[i].fp = NULL; } @@ -1715,17 +1851,22 @@ Cell *closefile(Node **a, int n) void closeall(void) { - int i, stat; + size_t i; + int stat; - for (i = 0; i < FOPEN_MAX; i++) { + for (i = 0; i < nfiles; i++) { if (files[i].fp) { if (ferror(files[i].fp)) WARNING( "i/o error occurred on %s", files[i].fname ); - if (files[i].mode == '|' || files[i].mode == LE) - stat = pclose(files[i].fp); + if (i == 0) + stat = fpurge(files[i].fp) == EOF; + else if (i <= 2) + stat = fflush(files[i].fp) == EOF; + else if (files[i].mode == '|' || files[i].mode == LE) + stat = pclose(files[i].fp) == -1; else - stat = fclose(files[i].fp); - if (stat == EOF) + stat = fclose(files[i].fp) == EOF; + if (stat) WARNING( "i/o error occurred while closing %s", files[i].fname ); } } @@ -1733,24 +1874,25 @@ void closeall(void) void flush_all(void) { - int i; + size_t i; - for (i = 0; i < FOPEN_MAX; i++) + for (i = 0; i < nfiles; i++) if (files[i].fp) fflush(files[i].fp); } -void backsub(char **pb_ptr, char **sptr_ptr); +void backsub(uschar **pb_ptr, const uschar **sptr_ptr); Cell *sub(Node **a, int nnn) /* substitute command */ { - char *sptr, *pb, *q; + const uschar *sptr; + uschar *q; Cell *x, *y, *result; - char *t, *buf; + uschar *t, *buf, *pb; fa *pfa; int bufsz = recsize; - if ((buf = (char *) malloc(bufsz)) == NULL) + if ((buf = malloc(bufsz)) == NULL) FATAL("out of memory in sub"); x = execute(a[3]); /* target string */ t = getsval(x); @@ -1805,13 +1947,15 @@ Cell *sub(Node **a, int nnn) /* substitute command */ Cell *gsub(Node **a, int nnn) /* global substitute */ { Cell *x, *y; - char *rptr, *sptr, *t, *pb, *q; - char *buf; + const char *rptr; + const uschar *sptr; + uschar *t, *q; + uschar *pb, *buf; fa *pfa; int mflag, tempstat, num; int bufsz = recsize; - if ((buf = (char *) malloc(bufsz)) == NULL) + if ((buf = malloc(bufsz)) == NULL) FATAL("out of memory in gsub"); mflag = 0; /* if mflag == 0, can replace empty string */ num = 0; @@ -1887,9 +2031,10 @@ Cell *gsub(Node **a, int nnn) /* global substitute */ adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gsub"); while ((*pb++ = *sptr++) != 0) ; - done: if (pb > buf + bufsz) - FATAL("gsub result2 %.30s too big; can't happen", buf); - *pb = '\0'; + done: if (pb < buf + bufsz) + *pb = '\0'; + else if (*(pb-1) != '\0') + FATAL("gsub result2 %.30s truncated; can't happen", buf); setsval(x, buf); /* BUG: should be able to avoid copy + free */ pfa->initstat = tempstat; } @@ -1902,9 +2047,149 @@ Cell *gsub(Node **a, int nnn) /* global substitute */ return(x); } -void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ +Cell *gensub(Node **a, int nnn) /* global selective substitute */ + /* XXX incomplete - doesn't support backreferences \0 ... \9 */ +{ + Cell *x, *y, *res, *h; + char *rptr; + const uschar *sptr; + uschar *q, *pb, *t, *buf; + fa *pfa; + int mflag, tempstat, num, whichm; + int bufsz = recsize; + + if ((buf = malloc(bufsz)) == NULL) + FATAL("out of memory in gensub"); + mflag = 0; /* if mflag == 0, can replace empty string */ + num = 0; + x = execute(a[4]); /* source string */ + t = getsval(x); + res = copycell(x); /* target string - initially copy of source */ + if (a[0] == 0) /* 0 => a[1] is already-compiled regexpr */ + pfa = (fa *) a[1]; /* regular expression */ + else { + y = execute(a[1]); + pfa = makedfa(getsval(y), 1); + tempfree(y); + } + y = execute(a[2]); /* replacement string */ + h = execute(a[3]); /* which matches should be replaced */ + sptr = getsval(h); + if (sptr[0] == 'g' || sptr[0] == 'G') + whichm = -1; + else { + /* + * The specified number is index of replacement, starting + * from 1. GNU awk treats index lower than 0 same as + * 1, we do same for compatibility. + */ + whichm = (int) getfval(h) - 1; + if (whichm < 0) + whichm = 0; + } + tempfree(h); + + if (pmatch(pfa, t)) { + char *sl; + + tempstat = pfa->initstat; + pfa->initstat = 2; + pb = buf; + rptr = getsval(y); + /* + * XXX if there are any backreferences in subst string, + * complain now. + */ + for(sl=rptr; (sl = strchr(sl, '\\')) && sl[1]; sl++) { + if (strchr("0123456789", sl[1])) { + FATAL("gensub doesn't support backreferences (subst \"%s\")", rptr); + } + } + + do { + if (whichm >= 0 && whichm != num) { + num++; + adjbuf(&buf, &bufsz, (pb - buf) + (patbeg - t) + patlen, recsize, &pb, "gensub"); + + /* copy the part of string up to and including + * match to output buffer */ + while (t < patbeg + patlen) + *pb++ = *t++; + continue; + } + + if (patlen == 0 && *patbeg != 0) { /* matched empty string */ + if (mflag == 0) { /* can replace empty */ + num++; + sptr = rptr; + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + } + if (*t == 0) /* at end */ + goto done; + adjbuf(&buf, &bufsz, 2+pb-buf, recsize, &pb, "gensub"); + *pb++ = *t++; + if (pb > buf + bufsz) /* BUG: not sure of this test */ + FATAL("gensub result0 %.30s too big; can't happen", buf); + mflag = 0; + } + else { /* matched nonempty string */ + num++; + sptr = t; + adjbuf(&buf, &bufsz, 1+(patbeg-sptr)+pb-buf, recsize, &pb, "gensub"); + while (sptr < patbeg) + *pb++ = *sptr++; + sptr = rptr; + while (*sptr != 0) { + adjbuf(&buf, &bufsz, 5+pb-buf, recsize, &pb, "gensub"); + if (*sptr == '\\') { + backsub(&pb, &sptr); + } else if (*sptr == '&') { + sptr++; + adjbuf(&buf, &bufsz, 1+patlen+pb-buf, recsize, &pb, "gensub"); + for (q = patbeg; q < patbeg+patlen; ) + *pb++ = *q++; + } else + *pb++ = *sptr++; + } + t = patbeg + patlen; + if (patlen == 0 || *t == 0 || *(t-1) == 0) + goto done; + if (pb > buf + bufsz) + FATAL("gensub result1 %.30s too big; can't happen", buf); + mflag = 1; + } + } while (pmatch(pfa,t)); + sptr = t; + adjbuf(&buf, &bufsz, 1+strlen(sptr)+pb-buf, 0, &pb, "gensub"); + while ((*pb++ = *sptr++) != 0) + ; + done: if (pb > buf + bufsz) + FATAL("gensub result2 %.30s too big; can't happen", buf); + *pb = '\0'; + setsval(res, buf); + pfa->initstat = tempstat; + } + tempfree(x); + tempfree(y); + free(buf); + return(res); +} + +void backsub(uschar **pb_ptr, const uschar **sptr_ptr)/* handle \\& variations */ { /* sptr[0] == '\\' */ - char *pb = *pb_ptr, *sptr = *sptr_ptr; + uschar *pb = *pb_ptr; + const uschar *sptr = *sptr_ptr; if (sptr[1] == '\\') { if (sptr[2] == '\\' && sptr[3] == '&') { /* \\\& -> \& */ diff --git a/commands/awk/tran.c b/external/historical/nawk/dist/tran.c similarity index 87% rename from commands/awk/tran.c rename to external/historical/nawk/dist/tran.c index 24affc104..0651cc946 100644 --- a/commands/awk/tran.c +++ b/external/historical/nawk/dist/tran.c @@ -22,6 +22,10 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + #define DEBUG #include #include @@ -108,7 +112,7 @@ void arginit(int ac, char **av) /* set up ARGV and ARGC */ ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ cp->sval = (char *) ARGVtab; for (i = 0; i < ac; i++) { - sprintf(temp, "%d", i); + snprintf(temp, sizeof(temp), "%d", i); if (is_number(*av)) setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); else @@ -144,8 +148,8 @@ Array *makesymtab(int n) /* make a new symbol table */ Array *ap; Cell **tp; - ap = (Array *) malloc(sizeof(Array)); - tp = (Cell **) calloc(n, sizeof(Cell *)); + ap = malloc(sizeof(*ap)); + tp = calloc(n, sizeof(*tp)); if (ap == NULL || tp == NULL) FATAL("out of space in makesymtab"); ap->nelem = 0; @@ -154,7 +158,7 @@ Array *makesymtab(int n) /* make a new symbol table */ return(ap); } -void freesymtab(const Cell *ap) /* free a symbol table */ +void freesymtab(Cell *ap) /* free a symbol table */ { Cell *cp, *temp; Array *tp; @@ -182,8 +186,7 @@ void freesymtab(const Cell *ap) /* free a symbol table */ free(tp); } -void freeelem(const Cell *ap, const char *s) -/* free elem s from ap (i.e., ap["s"] */ +void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ { Array *tp; Cell *p, *prev = NULL; @@ -211,12 +214,15 @@ Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) int h; Cell *p; - if (n != NULL && (p = lookup(n, tp)) != NULL) { + if (n == NULL) + n = ""; + + if ((p = lookup(n, tp)) != NULL) { dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); return(p); } - p = (Cell *) malloc(sizeof(Cell)); + p = malloc(sizeof(*p)); if (p == NULL) FATAL("out of space for symbol table at %s", n); p->nval = tostring(n); @@ -251,7 +257,7 @@ void rehash(Array *tp) /* rehash items in small table into big one */ Cell *cp, *op, **np; nsz = GROWTAB * tp->size; - np = (Cell **) calloc(nsz, sizeof(Cell *)); + np = calloc(nsz, sizeof(*np)); if (np == NULL) /* can't do it, but can keep running. */ return; /* someone else will run out later. */ for (i = 0; i < tp->size; i++) { @@ -267,7 +273,7 @@ void rehash(Array *tp) /* rehash items in small table into big one */ tp->size = nsz; } -Cell *lookup(const char *s, const Array *tp) /* look for s in tp */ +Cell *lookup(const char *s, Array *tp) /* look for s in tp */ { Cell *p; int h; @@ -283,6 +289,7 @@ Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ { int fldno; + f += 0.0; /* normalise negative zero to positive zero */ if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); if (isfld(vp)) { @@ -291,6 +298,10 @@ Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ if (fldno > *NF) newfld(fldno); dprintf( ("setting field %d to %g\n", fldno, f) ); + } else if (&vp->fval == NF) { + donerec = 0; /* mark $0 invalid */ + setlastfld(f); + dprintf( ("setting NF to %g\n", f) ); } else if (isrec(vp)) { donefld = 0; /* mark $1... invalid */ donerec = 1; @@ -317,6 +328,7 @@ char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ { char *t; int fldno; + Awkfloat f; dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); @@ -340,7 +352,16 @@ char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ vp->tval &= ~DONTFREE; dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); - return(vp->sval = t); + + vp->sval = t; + if (&vp->fval == NF) { + donerec = 0; /* mark $0 invalid */ + f = getfval(vp); + setlastfld(f); + dprintf( ("setting NF to %g\n", f) ); + } + + return(vp->sval); } Awkfloat getfval(Cell *vp) /* get float val of a Cell */ @@ -360,10 +381,9 @@ Awkfloat getfval(Cell *vp) /* get float val of a Cell */ return(vp->fval); } -static char *get_str_val(Cell *vp, char **fmt) -/* get string val of a Cell */ +static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ { - char s[100]; /* BUG: unchecked */ + char s[100]; double dtemp; if ((vp->tval & (NUM | STR)) == 0) @@ -376,9 +396,9 @@ static char *get_str_val(Cell *vp, char **fmt) if (freeable(vp)) xfree(vp->sval); if (modf(vp->fval, &dtemp) == 0) /* it's integral */ - sprintf(s, "%.30g", vp->fval); + snprintf(s, sizeof(s), "%.30g", vp->fval); else - sprintf(s, *fmt, vp->fval); + snprintf(s, sizeof(s), *fmt, vp->fval); vp->sval = tostring(s); vp->tval &= ~DONTFREE; vp->tval |= STR; @@ -402,7 +422,33 @@ char *tostring(const char *s) /* make a copy of string s */ { char *p; - p = (char *) malloc(strlen(s)+1); + p = strdup(s); + if (p == NULL) + FATAL("out of space in tostring on %s", s); + return(p); +} + +Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ +{ + Cell *c; + char *p; + char *sa = getsval(a); + char *sb = getsval(b); + size_t l = strlen(sa) + strlen(sb) + 1; + p = malloc(l); + if (p == NULL) + FATAL("out of space concatenating %s and %s", sa, sb); + snprintf(p, l, "%s%s", sa, sb); + c = setsymtab(p, p, 0.0, CON|STR|DONTFREE, symtab); + free(p); + return c; +} + +char *tostringN(const char *s, size_t n) /* make a copy of string s */ +{ + char *p; + + p = malloc(n); if (p == NULL) FATAL("out of space in tostring on %s", s); strcpy(p, s); @@ -413,10 +459,10 @@ char *qstring(const char *is, int delim) /* collect string up to next delim */ { const char *os = is; int c, n; - uschar *s = (uschar *) is; + const uschar *s = (const uschar *) is; uschar *buf, *bp; - if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) + if ((buf = malloc(strlen(is)+3)) == NULL) FATAL( "out of space in qstring(%s)", s); for (bp = buf; (c = *s) != delim; s++) { if (c == '\n') -- 2.44.0