rsalz@uunet.uu.net (Rich Salz) (06/08/90)
Submitted-by: "Arnold D. Robbins" <arnold@unix.cc.emory.edu> Posting-number: Volume 22, Issue 97 Archive-name: gawk2.11/part11 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: ./gawk.1 ./io.c ./missing.d/memcpy.c # Wrapped by rsalz@litchi.bbn.com on Wed Jun 6 12:24:56 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 11 (of 16)."' if test -f './gawk.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./gawk.1'\" else echo shar: Extracting \"'./gawk.1'\" \(33549 characters\) sed "s/^X//" >'./gawk.1' <<'END_OF_FILE' X.TH GAWK 1 "August 24 1989" "Free Software Foundation" X.SH NAME Xgawk \- pattern scanning and processing language X.SH SYNOPSIS X.B gawk X.ig X[ X.B \-d X] [ X.B \-D X] X.. X[ X.B \-a X] [ X.B \-e X] [ X.B \-c X] [ X.B \-C X] [ X.B \-V X] [ X.BI \-F\^ fs X] [ X.B \-v X.IR var = val X] X.B \-f X.I program-file X[ X.B \-\^\- X] file .\^.\^. X.br X.B gawk X.ig X[ X.B \-d X] [ X.B \-D X] X.. X[ X.B \-a X] [ X.B \-e X] [ X.B \-c X] [ X.B \-C X] [ X.B \-V X] [ X.BI \-F\^ fs X] [ X.B \-v X.IR var = val X] [ X.B \-\^\- X] X.I program-text Xfile .\^.\^. X.SH DESCRIPTION X.I Gawk Xis the GNU Project's implementation of the AWK programming language. XIt conforms to the definition and description of the language in X.IR "The AWK Programming Language" , Xby Aho, Kernighan, and Weinberger, Xwith the additional features defined in the System V Release 4 version Xof \s-1UNIX\s+1 X.IR awk , Xand some GNU-specific extensions. X.PP XThe command line consists of options to X.I gawk Xitself, the AWK program text (if not supplied via the X.B \-f Xoption), and values to be made Xavailable in the X.B ARGC Xand X.B ARGV Xpre-defined AWK variables. X.PP X.I Gawk Xaccepts the following options, which should be available on any implementation Xof the AWK language. X.TP X.BI \-F fs XUse X.I fs Xfor the input field separator (the value of the X.B FS Xpredefined Xvariable). X.TP X\fB\-v\fI var\fR\^=\^\fIval\fR XAssign the value X.IR val , Xto the variable X.IR var , Xbefore execution of the program begins. XSuch variable values are available to the X.B BEGIN Xblock of an AWK program. X.TP X.BI \-f " program-file" XRead the AWK program source from the file X.IR program-file , Xinstead of from the first command line argument. XMultiple X.B \-f Xoptions may be used. X.TP X.B \-\^\- XSignal the end of options. This is useful to allow further arguments to the XAWK program itself to start with a ``\-''. XThis is mainly for consistency with the argument parsing convention used Xby most other System V programs. X.PP XThe following options are specific to the GNU implementation. X.TP X.B \-a XUse AWK style regular expressions as described in the book. XThis is the current default, but may not be when the POSIX P1003.2 Xstandard is finalized. XIt is orthogonal to X.BR \-c . X.TP X.B \-e XUse X.IR egrep (1) Xstyle regular expressions as described in POSIX standard. XThis may become the default when the POSIX P1003.2 Xstandard is finalized. XIt is orthogonal to X.BR \-c . X.TP X.B \-c XRun in X.I compatibility Xmode. In compatibility mode, X.I gawk Xbehaves identically to \s-1UNIX\s+1 X.IR awk ; Xnone of the GNU-specific extensions are recognized. X.TP X.B \-C XPrint the short version of the GNU copyright information message on Xthe error output. XThis option may disappear in a future version of X.IR gawk . X.TP X.B \-V XPrint version information for this particular copy of X.I gawk Xon the error output. XThis is useful mainly for knowing if the current copy of X.I gawk Xon your system Xis up to date with respect to whatever the Free Software Foundation Xis distributing. XThis option may disappear in a future version of X.IR gawk . X.PP XAny other options are flagged as illegal, but are otherwise ignored. X.PP XAn AWK program consists of a sequence of pattern-action statements Xand optional function definitions. X.RS X.PP X\fIpattern\fB { \fIaction statements\fB }\fR X.br X\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements\fB }\fR X.RE X.PP X.I Gawk Xfirst reads the program source from the X.IR program-file (s) Xif specified, or from the first non-option argument on the command line. XThe X.B \-f Xoption may be used multiple times on the command line. X.I Gawk Xwill read the program text as if all the X.IR program-file s Xhad been concatenated together. This is useful for building libraries Xof AWK functions, without having to include them in each new AWK Xprogram that uses them. To use a library function in a file from a Xprogram typed in on the command line, specify X.B /dev/tty Xas one of the X.IR program-file s, Xtype your program, and end it with a X.B ^D X(control-d). X.PP XThe environment variable X.B AWKPATH Xspecifies a search path to use when finding source files named with Xthe X.B \-f Xoption. If this variable does not exist, the default path is X\fB".:/usr/lib/awk:/usr/local/lib/awk"\fR. XIf a file name given to the X.B \-f Xoption contains a ``/'' character, no path search is performed. X.PP X.I Gawk Xcompiles the program into an internal form, Xexecutes the code in the X.B BEGIN Xblock(s) (if any), Xand then proceeds to read Xeach file named in the X.B ARGV Xarray. XIf there are no files named on the command line, X.I gawk Xreads the standard input. X.PP XIf a ``file'' named on the command line has the form X.IB var = val Xit is treated as a variable assignment. The variable X.I var Xwill be assigned the value X.IR val . XThis is most useful for dynamically assigning values to the variables XAWK uses to control how input is broken into fields and records. It Xis also useful for controlling state if multiple passes are needed over Xa single data file. X.PP XFor each line in the input, X.I gawk Xtests to see if it matches any X.I pattern Xin the AWK program. XFor each pattern that the line matches, the associated X.I action Xis executed. X.SH VARIABLES AND FIELDS XAWK variables are dynamic; they come into existence when they are Xfirst used. Their values are either floating-point numbers or strings, Xdepending upon how they are used. AWK also has one dimension Xarrays; multiply dimensioned arrays may be simulated. XThere are several pre-defined variables that AWK sets as a program Xruns; these will be described as needed and summarized below. X.SS Fields X.PP XAs each input line is read, X.I gawk Xsplits the line into X.IR fields , Xusing the value of the X.B FS Xvariable as the field separator. XIf X.B FS Xis a single character, fields are separated by that character. XOtherwise, X.B FS Xis expected to be a full regular expression. XIn the special case that X.B FS Xis a single blank, fields are separated Xby runs of blanks and/or tabs. XNote that the value of X.B IGNORECASE X(see below) will also affect how fields are split when X.B FS Xis a regular expression. X.PP XEach field in the input line may be referenced by its position, X.BR $1 , X.BR $2 , Xand so on. X.B $0 Xis the whole line. The value of a field may be assigned to as well. XFields need not be referenced by constants: X.RS X.PP X.ft B Xn = 5 X.br Xprint $n X.ft R X.RE X.PP Xprints the fifth field in the input line. XThe variable X.B NF Xis set to the total number of fields in the input line. X.PP XReferences to non-existent fields (i.e. fields after X.BR $NF ), Xproduce the null-string. However, assigning to a non-existent field X(e.g., X.BR "$(NF+2) = 5" ) Xwill increase the value of X.BR NF , Xcreate any intervening fields with the null string as their value, and Xcause the value of X.B $0 Xto be recomputed, with the fields being separated by the value of X.BR OFS . X.SS Built-in Variables X.PP XAWK's built-in variables are: X.PP X.RS X.TP \l'\fBIGNORECASE\fR' X.B ARGC Xthe number of command line arguments (does not include options to X.IR gawk , Xor the program source). X.TP \l'\fBIGNORECASE\fR' X.B ARGV Xarray of command line arguments. The array is indexed from X0 to X.B ARGC X\- 1. XDynamically changing the contents of X.B ARGV Xcan control the files used for data. X.TP \l'\fBIGNORECASE\fR' X.B ENVIRON XAn array containing the values of the current environment. XThe array is indexed by the environment variables, each element being Xthe value of that variable (e.g., \fBENVIRON["HOME"]\fP might be X.BR /u/arnold ). XChanging this array does not affect the environment seen by programs which X.I gawk Xspawns via redirection or the X.B system Xfunction. X(This may change in a future version of X.IR gawk .) X.TP \l'\fBIGNORECASE\fR' X.B FILENAME Xthe name of the current input file. XIf no files are specified on the command line, the value of X.B FILENAME Xis ``\-''. X.TP \l'\fBIGNORECASE\fR' X.B FNR Xthe input record number in the current input file. X.TP \l'\fBIGNORECASE\fR' X.B FS Xthe input field separator, a blank by default. X.TP \l'\fBIGNORECASE\fR' X.B IGNORECASE XControls the case-sensitivity of all regular expression operations. If X.B IGNORECASE Xhas a non-zero value, then pattern matching in rules, Xfield splitting with X.BR FS , Xregular expression Xmatching with X.B ~ Xand X.BR !~ , Xand the X.BR gsub() , X.BR index() , X.BR match() , X.BR split() , Xand X.B sub() Xpre-defined functions will all ignore case when doing regular expression Xoperations. Thus, if X.B IGNORECASE Xis not equal to zero, X.B /aB/ Xmatches all of the strings \fB"ab"\fP, \fB"aB"\fP, \fB"Ab"\fP, Xand \fB"AB"\fP. XAs with all AWK variables, the initial value of X.B IGNORECASE Xis zero, so all regular expression operations are normally case-sensitive. X.TP \l'\fBIGNORECASE\fR' X.B NF Xthe number of fields in the current input record. X.TP \l'\fBIGNORECASE\fR' X.B NR Xthe total number of input records seen so far. X.TP \l'\fBIGNORECASE\fR' X.B OFMT Xthe output format for numbers, X.B %.6g Xby default. X.TP \l'\fBIGNORECASE\fR' X.B OFS Xthe output field separator, a blank by default. X.TP \l'\fBIGNORECASE\fR' X.B ORS Xthe output record separator, by default a newline. X.TP \l'\fBIGNORECASE\fR' X.B RS Xthe input record separator, by default a newline. X.B RS Xis exceptional in that only the first character of its string Xvalue is used for separating records. If X.B RS Xis set to the null string, then records are separated by Xblank lines. XWhen X.B RS Xis set to the null string, then the newline character always acts as Xa field separator, in addition to whatever value X.B FS Xmay have. X.TP \l'\fBIGNORECASE\fR' X.B RSTART Xthe index of the first character matched by X.BR match() ; X0 if no match. X.TP \l'\fBIGNORECASE\fR' X.B RLENGTH Xthe length of the string matched by X.BR match() ; X\-1 if no match. X.TP \l'\fBIGNORECASE\fR' X.B SUBSEP Xthe character used to separate multiple subscripts in array Xelements, by default \fB"\e034"\fR. X.RE X.SS Arrays X.PP XArrays are subscripted with an expression between square brackets X.RB ( [ " and " ] ). XIf the expression is an expression list X.RI ( expr ", " expr " ...)" Xthen the array subscript is a string consisting of the Xconcatenation of the (string) value of each expression, Xseparated by the value of the X.B SUBSEP Xvariable. XThis facility is used to simulate multiply dimensioned Xarrays. For example: X.PP X.RS X.ft B Xi = "A" ;\^ j = "B" ;\^ k = "C" X.br Xx[i, j, k] = "hello, world\en" X.ft R X.RE X.PP Xassigns the string \fB"hello, world\en"\fR to the element of the array X.B x Xwhich is indexed by the string \fB"A\e034B\e034C"\fR. All arrays in AWK Xare associative, i.e. indexed by string values. X.PP XThe special operator X.B in Xmay be used in an X.B if Xor X.B while Xstatement to see if an array has an index consisting of a particular Xvalue. X.PP X.RS X.ft B X.nf Xif (val in array) X print array[val] X.fi X.ft X.RE X.PP XIf the array has multiple subscripts, use X.BR "(i, j) in array" . X.PP XThe X.B in Xconstruct may also be used in a X.B for Xloop to iterate over all the elements of an array. X.PP XAn element may be deleted from an array using the X.B delete Xstatement. X.SS Variable Typing X.PP XVariables and fields Xmay be (floating point) numbers, or strings, or both. How the Xvalue of a variable is interpreted depends upon its context. If used in Xa numeric expression, it will be treated as a number, if used as a string Xit will be treated as a string. X.PP XTo force a variable to be treated as a number, add 0 to it; to force it Xto be treated as a string, concatenate it with the null string. X.PP XThe AWK language defines comparisons as being done numerically if Xpossible, otherwise one or both operands are converted to strings and Xa string comparison is performed. X.PP XUninitialized variables have the numeric value 0 and the string value "" X(the null, or empty, string). X.SH PATTERNS AND ACTIONS XAWK is a line oriented language. The pattern comes first, and then the Xaction. Action statements are enclosed in X.B { Xand X.BR } . XEither the pattern may be missing, or the action may be missing, but, Xof course, not both. If the pattern is missing, the action will be Xexecuted for every single line of input. XA missing action is equivalent to X.RS X.PP X.B "{ print }" X.RE X.PP Xwhich prints the entire line. X.PP XComments begin with the ``#'' character, and continue until the Xend of the line. XBlank lines may be used to separate statements. XNormally, a statement ends with a newline, however, this is not the Xcase for lines ending in Xa ``,'', ``{'', ``?'', ``:'', ``&&'', or ``||''. XLines ending in X.B do Xor X.B else Xalso have their statements automatically continued on the following line. XIn other cases, a line can be continued by ending it with a ``\e'', Xin which case the newline will be ignored. X.PP XMultiple statements may Xbe put on one line by separating them with a ``;''. XThis applies to both the statements within the action part of a Xpattern-action pair (the usual case), Xand to the pattern-action statements themselves. X.SS Patterns XAWK patterns may be one of the following: X.PP X.RS X.nf X.B BEGIN X.B END X.BI / "regular expression" / X.I "relational expression" X.IB pattern " && " pattern X.IB pattern " || " pattern X.IB pattern " ? " pattern " : " pattern X.BI ( pattern ) X.BI ! " pattern" X.IB pattern1 ", " pattern2" X.fi X.RE X.PP X.B BEGIN Xand X.B END Xare two special kinds of patterns which are not tested against Xthe input. XThe action parts of all X.B BEGIN Xpatterns are merged as if all the statements had Xbeen written in a single X.B BEGIN Xblock. They are executed before any Xof the input is read. Similarly, all the X.B END Xblocks are merged, Xand executed when all the input is exhausted (or when an X.B exit Xstatement is executed). X.B BEGIN Xand X.B END Xpatterns cannot be combined with other patterns in pattern expressions. X.B BEGIN Xand X.B END Xpatterns cannot have missing action parts. X.PP XFor X.BI / "regular expression" / Xpatterns, the associated statement is executed for each input line that matches Xthe regular expression. XRegular expressions are the same as those in X.IR egrep (1), Xand are summarized below. X.PP XA X.I "relational expression" Xmay use any of the operators defined below in the section on actions. XThese generally test whether certain fields match certain regular expressions. X.PP XThe X.BR && , X.BR || , Xand X.B ! Xoperators are logical AND, logical OR, and logical NOT, respectively, as in C. XThey do short-circuit evaluation, also as in C, and are used for combining Xmore primitive pattern expressions. As in most languages, parentheses Xmay be used to change the order of evaluation. X.PP XThe X.B ?\^: Xoperator is like the same operator in C. If the first pattern is true Xthen the pattern used for testing is the second pattern, otherwise it is Xthe third. Only one of the second and third patterns is evaluated. X.PP XThe X.IB pattern1 ", " pattern2" Xform of an expression is called a range pattern. XIt matches all input lines starting with a line that matches X.IR pattern1 , Xand continuing until a line that matches X.IR pattern2 , Xinclusive. It does not combine with any other sort of pattern expression. X.SS Regular Expressions XRegular expressions are the extended kind found in X.IR egrep . XThey are composed of characters as follows: X.RS X.TP \l'[^abc...]' X.I c Xmatches the non-metacharacter X.IR c . X.TP \l'[^abc...]' X.I \ec Xmatches the literal character X.IR c . X.TP \l'[^abc...]' X.B . Xmatches any character except newline. X.TP \l'[^abc...]' X.B ^ Xmatches the beginning of a line or a string. X.TP \l'[^abc...]' X.B $ Xmatches the end of a line or a string. X.TP \l'[^abc...]' X.BI [ abc... ] Xcharacter class, matches any of the characters X.IR abc... . X.TP \l'[^abc...]' X.BI [^ abc... ] Xnegated character class, matches any character except X.I abc... Xand newline. X.TP \l'[^abc...]' X.IB r1 | r2 Xalternation: matches either X.I r1 Xor X.IR r2 . X.TP \l'[^abc...]' X.I r1r2 Xconcatenation: matches X.IR r1 , Xand then X.IR r2 . X.TP \l'[^abc...]' X.IB r + Xmatches one or more X.IR r 's. X.TP \l'[^abc...]' X.IB r * Xmatches zero or more X.IR r 's. X.TP \l'[^abc...]' X.IB r ? Xmatches zero or one X.IR r 's. X.TP \l'[^abc...]' X.BI ( r ) Xgrouping: matches X.IR r . X.RE XThe escape sequences that are valid in string constants (see below) Xare also legal in regular expressions. X.SS Actions XAction statements are enclosed in braces, X.B { Xand X.BR } . XAction statements consist of the usual assignment, conditional, and looping Xstatements found in most languages. The operators, control statements, Xand input/output statements Xavailable are patterned after those in C. X.SS Operators X.PP XThe operators in AWK, in order of increasing precedence, are X.PP X.RS X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "= += \-= *= /= %= ^=" XAssignment. Both absolute assignment X.BI ( var " = " value ) Xand operator-assignment (the other forms) are supported. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B ?: XThe C conditional expression. This has the form X.IB expr1 " ? " expr2 " : " expr3\c X\&. If X.I expr1 Xis true, the value of the expression is X.IR expr2 , Xotherwise it is X.IR expr3 . XOnly one of X.I expr2 Xand X.I expr3 Xis evaluated. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B || Xlogical OR. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B && Xlogical AND. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "~ !~" Xregular expression match, negated match. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "< <= > >= != ==" Xthe regular relational operators. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.I blank Xstring concatenation. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "+ \-" Xaddition and subtraction. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "* / %" Xmultiplication, division, and modulus. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "+ \- !" Xunary plus, unary minus, and logical negation. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B ^ Xexponentiation (\fB**\fR may also be used, and \fB**=\fR for Xthe assignment operator). X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B "++ \-\^\-" Xincrement and decrement, both prefix and postfix. X.TP \l'\fB= += \-= *= /= %= ^=\fR' X.B $ Xfield reference. X.RE X.SS Control Statements X.PP XThe control statements are Xas follows: X.PP X.RS X.nf X\fBif (\fIcondition\fB) \fIstatement\fR [ \fBelse\fI statement \fR] X\fBwhile (\fIcondition\fB) \fIstatement \fR X\fBdo \fIstatement \fBwhile (\fIcondition\fB)\fR X\fBfor (\fIexpr1\fB; \fIexpr2\fB; \fIexpr3\fB) \fIstatement\fR X\fBfor (\fIvar \fBin\fI array\fB) \fIstatement\fR X\fBbreak\fR X\fBcontinue\fR X\fBdelete \fIarray\^\fB[\^\fIindex\^\fB]\fR X\fBexit\fR [ \fIexpression\fR ] X\fB{ \fIstatements \fB} X.fi X.RE X.SS "I/O Statements" X.PP XThe input/output statements are as follows: X.PP X.RS X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI close( filename ) Xclose file (or pipe, see below). X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.B getline Xset X.B $0 Xfrom next input record; set X.BR NF , X.BR NR , X.BR FNR . X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI "getline <" file Xset X.B $0 Xfrom next record of X.IR file ; Xset X.BR NF . X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI getline " var" Xset X.I var Xfrom next input record; set X.BR NF , X.BR FNR . X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI getline " var" " <" file Xset X.I var Xfrom next record of X.IR file . X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.B next XStop processing the current input record. The next input record Xis read and processing starts over with the first pattern in the XAWK program. If the end of the input data is reached, the X.B END Xblock(s), if any, are executed. X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.B print Xprints the current record. X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI print " expr-list" Xprints expressions. X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI print " expr-list" " >" file Xprints expressions on X.IR file . X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI printf " fmt, expr-list" Xformat and print. X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI printf " fmt, expr-list" " >" file Xformat and print on X.IR file . X.TP \l'\fBprintf \fIfmt, expr-list\fR' X.BI system( cmd-line ) Xexecute the command X.IR cmd-line , Xand return the exit status. X(This may not be available on Xsystems besides \s-1UNIX\s+1 and \s-1GNU\s+1.) X.RE X.PP XOther input/output redirections are also allowed. For X.B print Xand X.BR printf , X.BI >> file Xappends output to the X.IR file , Xwhile X.BI | " command" Xwrites on a pipe. XIn a similar fashion, X.IB command " | getline" Xpipes into X.BR getline . X.BR Getline Xwill return 0 on end of file, and \-1 on an error. X.SS The \fIprintf\fP Statement X.PP XThe AWK versions of the X.B printf Xand X.B sprintf X(see below) Xfunctions accept the following conversion specification formats: X.RS X.TP X.B %c XAn ASCII character. XIf the argument used for X.B %c Xis numeric, it is treated as a character and printed. XOtherwise, the argument is assumed to be a string, and the only first Xcharacter of that string is printed. X.TP X.B %d XA decimal number (the integer part). X.TP X.B %i XJust like X.BR %d . X.TP X.B %e XA floating point number of the form X.BR [\-]d.ddddddE[+\^\-]dd . X.TP X.B %f XA floating point number of the form X.BR [\-]ddd.dddddd . X.TP X.B %g XUse X.B e Xor X.B f Xconversion, whichever is shorter, with nonsignificant zeros suppressed. X.TP X.B %o XAn unsigned octal number (again, an integer). X.TP X.B %s XA character string. X.TP X.B %x XAn unsigned hexadecimal number (an integer). X.TP X.B %X XLike X.BR %x , Xbut using X.B ABCDEF Xinstead of X.BR abcdef . X.TP X.B %% XA single X.B % Xcharacter; no argument is converted. X.RE X.PP XThere are optional, additional parameters that may lie between the X.B % Xand the control letter: X.RS X.TP X.B \- XThe expression should be left-justified within its field. X.TP X.I width XThe field should be padded to this width. If the number has a leading Xzero, then the field will be padded with zeros. XOtherwise it is padded with blanks. X.TP X.BI . prec XA number indicating the maximum width of strings or digits to the right Xof the decimal point. X.RE X.PP XThe dynamic X.I width Xand X.I prec Xcapabilities of the C library X.B printf Xroutines are not supported. XHowever, they may be simulated by using Xthe AWK concatenation operation to build up Xa format specification dynamically. X.SS Special File Names X.PP XWhen doing I/O redirection from either X.B print Xor X.B printf Xinto a file, Xor via X.B getline Xfrom a file, X.I gawk Xrecognizes certain special filenames internally. These filenames Xallow access to open file descriptors inherited from X.IR gawk 's Xparent process (usually the shell). The filenames are: X.RS X.TP X.B /dev/stdin XThe standard input. X.TP X.B /dev/stdout XThe standard output. X.TP X.B /dev/stderr XThe standard error output. X.TP X.BI /dev/fd/\^ n XThe file denoted by the open file descriptor X.IR n . X.RE X.PP XThese are particularly useful for error messages. For example: X.PP X.RS X.ft B Xprint "You blew it!" > "/dev/stderr" X.ft R X.RE X.PP Xwhereas you would otherwise have to use X.PP X.RS X.ft B Xprint "You blew it!" | "cat 1>&2" X.ft R X.RE X.PP XThese file names may also be used on the command line to name data files. X.SS Numeric Functions X.PP XAWK has the following pre-defined arithmetic functions: X.PP X.RS X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI atan2( y , " x" ) Xreturns the arctangent of X.I y/x Xin radians. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI cos( expr ) Xreturns the cosine in radians. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI exp( expr ) Xthe exponential function. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI int( expr ) Xtruncates to integer. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI log( expr ) Xthe natural logarithm function. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.B rand() Xreturns a random number between 0 and 1. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI sin( expr ) Xreturns the sine in radians. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI sqrt( expr ) Xthe square root function. X.TP \l'\fBsrand(\fIexpr\fB)\fR' X.BI srand( expr ) Xuse X.I expr Xas a new seed for the random number generator. If no X.I expr Xis provided, the time of day will be used. XThe return value is the previous seed for the random Xnumber generator. X.RE X.SS String Functions X.PP XAWK has the following pre-defined string functions: X.PP X.RS X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X\fBgsub(\fIr\fB, \fIs\fB, \fIt\fB)\fR Xfor each substring matching the regular expression X.I r Xin the string X.IR t , Xsubstitute the string X.IR s , Xand return the number of substitutions. XIf X.I t Xis not supplied, use X.BR $0 . X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X.BI index( s , " t" ) Xreturns the index of the string X.I t Xin the string X.IR s , Xor 0 if X.I t Xis not present. X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X.BI length( s ) Xreturns the length of the string X.IR s . X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X.BI match( s , " r" ) Xreturns the position in X.I s Xwhere the regular expression X.I r Xoccurs, or 0 if X.I r Xis not present, and sets the values of X.B RSTART Xand X.BR RLENGTH . X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X\fBsplit(\fIs\fB, \fIa\fB, \fIr\fB)\fR Xsplits the string X.I s Xinto the array X.I a Xon the regular expression X.IR r , Xand returns the number of fields. If X.I r Xis omitted, X.B FS Xis used instead. X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X.BI sprintf( fmt , " expr-list" ) Xprints X.I expr-list Xaccording to X.IR fmt , Xand returns the resulting string. X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X\fBsub(\fIr\fB, \fIs\fB, \fIt\fB)\fR Xthis is just like X.BR gsub , Xbut only the first matching substring is replaced. X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X\fBsubstr(\fIs\fB, \fIi\fB, \fIn\fB)\fR Xreturns the X.IR n -character Xsubstring of X.I s Xstarting at X.IR i . XIf X.I n Xis omitted, the rest of X.I s Xis used. X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X.BI tolower( str ) Xreturns a copy of the string X.IR str , Xwith all the upper-case characters in X.I str Xtranslated to their corresponding lower-case counterparts. XNon-alphabetic characters are left unchanged. X.TP \l'\fBsprintf(\fIfmt\fB, \fIexpr-list\fB)\fR' X.BI toupper( str ) Xreturns a copy of the string X.IR str , Xwith all the lower-case characters in X.I str Xtranslated to their corresponding upper-case counterparts. XNon-alphabetic characters are left unchanged. X.RE X.SS String Constants X.PP XString constants in AWK are sequences of characters enclosed Xbetween double quotes (\fB"\fR). Within strings, certain X.I "escape sequences" Xare recognized, as in C. These are: X.PP X.RS X.TP \l'\fB\e\fIddd\fR' X.B \e\e XA literal backslash. X.TP \l'\fB\e\fIddd\fR' X.B \ea XThe ``alert'' character; usually the ASCII BEL character. X.TP \l'\fB\e\fIddd\fR' X.B \eb Xbackspace. X.TP \l'\fB\e\fIddd\fR' X.B \ef Xform-feed. X.TP \l'\fB\e\fIddd\fR' X.B \en Xnew line. X.TP \l'\fB\e\fIddd\fR' X.B \er Xcarriage return. X.TP \l'\fB\e\fIddd\fR' X.B \et Xhorizontal tab. X.TP \l'\fB\e\fIddd\fR' X.B \ev Xvertical tab. X.TP \l'\fB\e\fIddd\fR' X.BI \ex "\^hex digits" XThe character represented by the string of hexadecimal digits following Xthe X.BR \ex . XAs in ANSI C, all following hexadecimal digits are considered part of Xthe escape sequence. X(This feature should tell us something about language design by committee.) XE.g., "\ex1B" is the ASCII ESC (escape) character. X.TP \l'\fB\e\fIddd\fR' X.BI \e ddd XThe character represented by the 1-, 2-, or 3-digit sequence of octal Xdigits. E.g. "\e033" is the ASCII ESC (escape) character. X.TP \l'\fB\e\fIddd\fR' X.BI \e c XThe literal character X.IR c\^ . X.RE X.PP XThe escape sequences may also be used inside constant regular expressions X(e.g., X.B "/[\ \et\ef\en\er\ev]/" Xmatches whitespace characters). X.SH FUNCTIONS XFunctions in AWK are defined as follows: X.PP X.RS X\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements \fB}\fR X.RE X.PP XFunctions are executed when called from within the action parts of regular Xpattern-action statements. Actual parameters supplied in the function Xcall are used to instantiate the formal parameters declared in the function. XArrays are passed by reference, other variables are passed by value. X.PP XSince functions were not originally part of the AWK language, the provision Xfor local variables is rather clumsy: they are declared as extra parameters Xin the parameter list. The convention is to separate local variables from Xreal parameters by extra spaces in the parameter list. For example: X.PP X.RS X.ft B X.nf Xfunction f(p, q, a, b) { # a & b are local X ..... } X X/abc/ { ... ; f(1, 2) ; ... } X.fi X.ft R X.RE X.PP XThe left parenthesis in a function call is required Xto immediately follow the function name, Xwithout any intervening white space. XThis is to avoid a syntactic ambiguity with the concatenation operator. XThis restriction does not apply to the built-in functions listed above. X.PP XFunctions may call each other and may be recursive. XFunction parameters used as local variables are initialized Xto the null string and the number zero upon function invocation. X.PP XThe word X.B func Xmay be used in place of X.BR function . X.SH EXAMPLES X.nf XPrint and sort the login names of all users: X X.ft B X BEGIN { FS = ":" } X { print $1 | "sort" } X X.ft R XCount lines in a file: X X.ft B X { nlines++ } X END { print nlines } X X.ft R XPrecede each line by its number in the file: X X.ft B X { print FNR, $0 } X X.ft R XConcatenate and line number (a variation on a theme): X X.ft B X { print NR, $0 } X.ft R X.fi X.SH SEE ALSO X.IR egrep (1) X.PP X.IR "The AWK Programming Language" , XAlfred V. Aho, Brian W. Kernighan, Peter J. Weinberger, XAddison-Wesley, 1988. ISBN 0-201-07981-X. X.PP X.IR "The GAWK Manual" , Xpublished by the Free Software Foundation, 1989. X.SH SYSTEM V RELEASE 4 COMPATIBILITY XA primary goal for X.I gawk Xis compatibility with the latest version of \s-1UNIX\s+1 X.IR awk . XTo this end, X.I gawk Xincorporates the following user visible Xfeatures which are not described in the AWK book, Xbut are part of X.I awk Xin System V Release 4. X.PP XThe X.B \-v Xoption for assigning variables before program execution starts is new. XThe book indicates that command line variable assignment happens when X.I awk Xwould otherwise open the argument as a file, which is after the X.B BEGIN Xblock is executed. However, in earlier implementations, when such an Xassignment appeared before any file names, the assignment would happen X.I before Xthe X.B BEGIN Xblock was run. Applications came to depend on this ``feature.'' XWhen X.I awk Xwas changed to match its documentation, this option was added to Xaccomodate applications that depended upon the old behaviour. X.PP XWhen processing arguments, X.I gawk Xuses the special option ``\fB\-\^\-\fP'' to signal the end of Xarguments, and warns about, but otherwise ignores, undefined options. X.PP XThe AWK book does not define the return value of X.BR srand() . XThe System V Release 4 version of \s-1UNIX\s+1 X.I awk Xhas it return the seed it was using, to allow keeping track Xof random number sequences. Therefore X.B srand() Xin X.I gawk Xalso returns its current seed. X.PP XOther new features are: XThe use of multiple X.B \-f Xoptions; the X.B ENVIRON Xarray; the X.BR \ea , Xand X.BR \ev , X.B \ex Xescape sequences; the X.B tolower Xand X.B toupper Xbuilt-in functions; and the ANSI C conversion specifications in X.BR printf . X.SH GNU EXTENSIONS X.I Gawk Xhas some extensions to System V X.IR awk . XThey are described in this section. All the extensions described here Xcan be disabled by compiling X.I gawk Xwith X.BR \-DSTRICT , Xor by invoking X.I gawk Xwith the X.B \-c Xoption. XIf the underlying operating system supports the X.B /dev/fd Xdirectory and corresponding files, then X.I gawk Xcan be compiled with X.B \-DNO_DEV_FD Xto disable the special filename processing. X.PP XThe following features of X.I gawk Xare not available in XSystem V X.IR awk . X.RS X.TP \l'\(bu' X\(bu XThe special file names available for I/O redirection are not recognized. X.TP \l'\(bu' X\(bu XThe X.B IGNORECASE Xvariable and its side-effects are not available. X.TP \l'\(bu' X\(bu XNo path search is performed for files named via the X.B \-f Xoption. Therefore the X.B AWKPATH Xenvironment variable is not special. X.TP \l'\(bu' X\(bu XThe X.BR \-a , X.BR \-e , X.BR \-c , X.BR \-C , Xand X.B \-V Xcommand line options. X.RE X.PP XThe AWK book does not define the return value of the X.B close Xfunction. X.IR Gawk\^ 's X.B close Xreturns the value from X.IR fclose (3), Xor X.IR pclose (3), Xwhen closing a file or pipe, respectively. X.PP XWhen X.I gawk Xis invoked with the X.B \-c Xoption, Xif the X.I fs Xargument to the X.B \-F Xoption is ``t'', then X.B FS Xwill be set to the tab character. XSince this is a rather ugly special case, it is not the default behavior. X.ig X.PP XThe rest of the features described in this section may change at some time in Xthe future, or may go away entirely. XYou should not write programs that depend upon them. X.PP X.I Gawk Xaccepts the following additional options: X.TP X.B \-D XTurn on general debugging and turn on X.IR yacc (1) Xor X.IR bison (1) Xdebugging output during program parsing. XThis option should only be of interest to the X.I gawk Xmaintainers, and may not even be compiled into X.IR gawk . X.TP X.B \-d XTurn on general debugging and print the X.I gawk Xinternal tree as the program is executed. XThis option should only be of interest to the X.I gawk Xmaintainers, and may not even be compiled into X.IR gawk . X.. X.SH BUGS XThe X.B \-F Xoption is not necessary given the command line variable assignment feature; Xit remains only for backwards compatibility. X.PP XThere are now too many options. XFortunately, most of them are rarely needed. X.SH AUTHORS XThe original version of \s-1UNIX\s+1 X.I awk Xwas designed and implemented by Alfred Aho, XPeter Weinberger, and Brian Kernighan of AT&T Bell Labs. Brian Kernighan Xcontinues to maintain and enhance it. X.PP XPaul Rubin and Jay Fenlason, Xof the Free Software Foundation, wrote X.IR gawk , Xto be compatible with the original version of X.I awk Xdistributed in Seventh Edition \s-1UNIX\s+1. XJohn Woods contributed a number of bug fixes. XDavid Trueman of Dalhousie University, with contributions Xfrom Arnold Robbins at Emory University, made X.I gawk Xcompatible with the new version of \s-1UNIX\s+1 X.IR awk . X.SH ACKNOWLEDGEMENTS XBrian Kernighan of Bell Labs Xprovided valuable assistance during testing and debugging. XWe thank him. END_OF_FILE if test 33549 -ne `wc -c <'./gawk.1'`; then echo shar: \"'./gawk.1'\" unpacked with wrong size! fi # end of './gawk.1' fi if test -f './io.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./io.c'\" else echo shar: Extracting \"'./io.c'\" \(17467 characters\) sed "s/^X//" >'./io.c' <<'END_OF_FILE' X/* X * io.c - routines for dealing with input and output and records X */ X X/* X * Copyright (C) 1986, 1988, 1989 the Free Software Foundation, Inc. X * X * This file is part of GAWK, the GNU implementation of the X * AWK Progamming Language. X * X * GAWK is free software; you can redistribute it and/or modify X * it under the terms of the GNU General Public License as published by X * the Free Software Foundation; either version 1, or (at your option) X * any later version. X * X * GAWK is distributed in the hope that it will be useful, X * but WITHOUT ANY WARRANTY; without even the implied warranty of X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X * GNU General Public License for more details. X * X * You should have received a copy of the GNU General Public License X * along with GAWK; see the file COPYING. If not, write to X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. X */ X X#include "awk.h" X#ifndef O_RDONLY X#include <fcntl.h> X#endif X#include <signal.h> X Xextern FILE *popen(); X Xstatic void do_file(); Xstatic IOBUF *nextfile(); Xstatic int get_a_record(); Xstatic int iop_close(); Xstatic IOBUF *iop_alloc(); Xstatic void close_one(); Xstatic int close_redir(); Xstatic IOBUF *gawk_popen(); Xstatic int gawk_pclose(); X Xstatic struct redirect *red_head = NULL; Xstatic int getline_redirect = 0; /* "getline <file" being executed */ X Xextern char *line_buf; Xextern int output_is_tty; Xextern NODE *ARGC_node; Xextern NODE *ARGV_node; Xextern NODE **fields_arr; X Xint field_num; X Xstatic IOBUF * Xnextfile() X{ X static int i = 1; X static int files = 0; X static IOBUF *curfile = NULL; X char *arg; X char *cp; X int fd = -1; X X if (curfile != NULL && curfile->cnt != EOF) X return curfile; X for (; i < (int) (ARGC_node->lnode->numbr); i++) { X arg = (*assoc_lookup(ARGV_node, tmp_number((AWKNUM) i)))->stptr; X if (*arg == '\0') X continue; X cp = strchr(arg, '='); X if (cp != NULL) { X *cp++ = '\0'; X variable(arg)->var_value = make_string(cp, strlen(cp)); X *--cp = '='; /* restore original text of ARGV */ X } else { X files++; X if (STREQ(arg, "-")) X fd = 0; X else X fd = devopen(arg, "r"); X if (fd == -1) X fatal("cannot open file `%s' for reading (%s)", X arg, strerror(errno)); X /* NOTREACHED */ X /* This is a kludge. */ X deref = FILENAME_node->var_value; X do_deref(); X FILENAME_node->var_value = X make_string(arg, strlen(arg)); X FNR_node->var_value->numbr = 0.0; X i++; X break; X } X } X if (files == 0) { X files++; X /* no args. -- use stdin */ X /* FILENAME is init'ed to "-" */ X /* FNR is init'ed to 0 */ X fd = 0; X } X if (fd == -1) X return NULL; X return curfile = iop_alloc(fd); X} X Xstatic IOBUF * Xiop_alloc(fd) Xint fd; X{ X IOBUF *iop; X struct stat stb; X X /* X * System V doesn't have the file system block size in the X * stat structure. So we have to make some sort of reasonable X * guess. We use stdio's BUFSIZ, since that is what it was X * meant for in the first place. X */ X#ifdef BLKSIZE_MISSING X#define DEFBLKSIZE BUFSIZ X#else X#define DEFBLKSIZE (stb.st_blksize ? stb.st_blksize : BUFSIZ) X#endif X X if (fd == -1) X return NULL; X emalloc(iop, IOBUF *, sizeof(IOBUF), "nextfile"); X iop->flag = 0; X if (isatty(fd)) { X iop->flag |= IOP_IS_TTY; X iop->size = BUFSIZ; X } else if (fstat(fd, &stb) == -1) X fatal("can't stat fd %d (%s)", fd, strerror(errno)); X else if (lseek(fd, 0L, 0) == -1) X iop->size = DEFBLKSIZE; X else X iop->size = (stb.st_size < DEFBLKSIZE ? X stb.st_size+1 : DEFBLKSIZE); X errno = 0; X iop->fd = fd; X emalloc(iop->buf, char *, iop->size, "nextfile"); X iop->off = iop->buf; X iop->cnt = 0; X iop->secsiz = iop->size < BUFSIZ ? iop->size : BUFSIZ; X emalloc(iop->secbuf, char *, iop->secsiz, "nextfile"); X return iop; X} X Xvoid Xdo_input() X{ X IOBUF *iop; X extern int exiting; X X while ((iop = nextfile()) != NULL) { X do_file(iop); X if (exiting) X break; X } X} X Xstatic int Xiop_close(iop) XIOBUF *iop; X{ X int ret; X X ret = close(iop->fd); X if (ret == -1) X warning("close of fd %d failed (%s)", iop->fd, strerror(errno)); X free(iop->buf); X free(iop->secbuf); X free((char *)iop); X return ret == -1 ? 1 : 0; X} X X/* X * This reads in a record from the input file X */ Xstatic int Xinrec(iop) XIOBUF *iop; X{ X int cnt; X int retval = 0; X X cnt = get_a_record(&line_buf, iop); X if (cnt == EOF) { X cnt = 0; X retval = 1; X } else { X if (!getline_redirect) { X assign_number(&NR_node->var_value, X NR_node->var_value->numbr + 1.0); X assign_number(&FNR_node->var_value, X FNR_node->var_value->numbr + 1.0); X } X } X set_record(line_buf, cnt); X X return retval; X} X Xstatic void Xdo_file(iop) XIOBUF *iop; X{ X /* This is where it spends all its time. The infamous MAIN LOOP */ X if (inrec(iop) == 0) X while (interpret(expression_value) && inrec(iop) == 0) X ; X (void) iop_close(iop); X} X Xint Xget_rs() X{ X register NODE *tmp; X X tmp = force_string(RS_node->var_value); X if (tmp->stlen == 0) X return 0; X return *(tmp->stptr); X} X X/* Redirection for printf and print commands */ Xstruct redirect * Xredirect(tree, errflg) XNODE *tree; Xint *errflg; X{ X register NODE *tmp; X register struct redirect *rp; X register char *str; X int tflag = 0; X int outflag = 0; X char *direction = "to"; X char *mode; X int fd; X X switch (tree->type) { X case Node_redirect_append: X tflag = RED_APPEND; X case Node_redirect_output: X outflag = (RED_FILE|RED_WRITE); X tflag |= outflag; X break; X case Node_redirect_pipe: X tflag = (RED_PIPE|RED_WRITE); X break; X case Node_redirect_pipein: X tflag = (RED_PIPE|RED_READ); X break; X case Node_redirect_input: X tflag = (RED_FILE|RED_READ); X break; X default: X fatal ("invalid tree type %d in redirect()", tree->type); X break; X } X tmp = force_string(tree_eval(tree->subnode)); X str = tmp->stptr; X for (rp = red_head; rp != NULL; rp = rp->next) X if (STREQ(rp->value, str) X && ((rp->flag & ~RED_NOBUF) == tflag X || (outflag X && (rp->flag & (RED_FILE|RED_WRITE)) == outflag))) X break; X if (rp == NULL) { X emalloc(rp, struct redirect *, sizeof(struct redirect), X "redirect"); X emalloc(str, char *, tmp->stlen+1, "redirect"); X memcpy(str, tmp->stptr, tmp->stlen+1); X rp->value = str; X rp->flag = tflag; X rp->offset = 0; X rp->fp = NULL; X rp->iop = NULL; X /* maintain list in most-recently-used first order */ X if (red_head) X red_head->prev = rp; X rp->prev = NULL; X rp->next = red_head; X red_head = rp; X } X while (rp->fp == NULL && rp->iop == NULL) { X mode = NULL; X errno = 0; X switch (tree->type) { X case Node_redirect_output: X mode = "w"; X break; X case Node_redirect_append: X mode = "a"; X break; X case Node_redirect_pipe: X if ((rp->fp = popen(str, "w")) == NULL) X fatal("can't open pipe (\"%s\") for output (%s)", X str, strerror(errno)); X rp->flag |= RED_NOBUF; X break; X case Node_redirect_pipein: X direction = "from"; X if (gawk_popen(str, rp) == NULL) X fatal("can't open pipe (\"%s\") for input (%s)", X str, strerror(errno)); X break; X case Node_redirect_input: X direction = "from"; X rp->iop = iop_alloc(devopen(str, "r")); X break; X default: X cant_happen(); X } X if (mode != NULL) { X fd = devopen(str, mode); X if (fd != -1) { X rp->fp = fdopen(fd, mode); X if (isatty(fd)) X rp->flag |= RED_NOBUF; X } X } X if (rp->fp == NULL && rp->iop == NULL) { X /* too many files open -- close one and try again */ X if (errno == ENFILE || errno == EMFILE) X close_one(); X else { X /* X * Some other reason for failure. X * X * On redirection of input from a file, X * just return an error, so e.g. getline X * can return -1. For output to file, X * complain. The shell will complain on X * a bad command to a pipe. X */ X *errflg = 1; X if (tree->type == Node_redirect_output X || tree->type == Node_redirect_append) X fatal("can't redirect %s `%s' (%s)", X direction, str, strerror(errno)); X else X return NULL; X } X } X } X if (rp->offset != 0) /* this file was previously open */ X if (fseek(rp->fp, rp->offset, 0) == -1) X fatal("can't seek to %ld on `%s' (%s)", X rp->offset, str, strerror(errno)); X free_temp(tmp); X return rp; X} X Xstatic void Xclose_one() X{ X register struct redirect *rp; X register struct redirect *rplast = NULL; X X /* go to end of list first, to pick up least recently used entry */ X for (rp = red_head; rp != NULL; rp = rp->next) X rplast = rp; X /* now work back up through the list */ X for (rp = rplast; rp != NULL; rp = rp->prev) X if (rp->fp && (rp->flag & RED_FILE)) { X rp->offset = ftell(rp->fp); X if (fclose(rp->fp)) X warning("close of \"%s\" failed (%s).", X rp->value, strerror(errno)); X rp->fp = NULL; X break; X } X if (rp == NULL) X /* surely this is the only reason ??? */ X fatal("too many pipes or input files open"); X} X XNODE * Xdo_close(tree) XNODE *tree; X{ X NODE *tmp; X register struct redirect *rp; X X tmp = force_string(tree_eval(tree->subnode)); X for (rp = red_head; rp != NULL; rp = rp->next) { X if (STREQ(rp->value, tmp->stptr)) X break; X } X free_temp(tmp); X if (rp == NULL) /* no match */ X return tmp_number((AWKNUM) 0.0); X fflush(stdout); /* synchronize regular output */ X return tmp_number((AWKNUM)close_redir(rp)); X} X Xstatic int Xclose_redir(rp) Xregister struct redirect *rp; X{ X int status = 0; X X if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE)) X status = pclose(rp->fp); X else if (rp->fp) X status = fclose(rp->fp); X else if (rp->iop) { X if (rp->flag & RED_PIPE) X status = gawk_pclose(rp); X else X status = iop_close(rp->iop); X X } X /* SVR4 awk checks and warns about status of close */ X if (status) X warning("failure status (%d) on %s close of \"%s\" (%s).", X status, X (rp->flag & RED_PIPE) ? "pipe" : X "file", rp->value, strerror(errno)); X if (rp->next) X rp->next->prev = rp->prev; X if (rp->prev) X rp->prev->next = rp->next; X else X red_head = rp->next; X free(rp->value); X free((char *)rp); X return status; X} X Xint Xflush_io () X{ X register struct redirect *rp; X int status = 0; X X errno = 0; X if (fflush(stdout)) { X warning("error writing standard output (%s).", strerror(errno)); X status++; X } X errno = 0; X if (fflush(stderr)) { X warning("error writing standard error (%s).", strerror(errno)); X status++; X } X for (rp = red_head; rp != NULL; rp = rp->next) X /* flush both files and pipes, what the heck */ X if ((rp->flag & RED_WRITE) && rp->fp != NULL) X if (fflush(rp->fp)) { X warning("%s flush of \"%s\" failed (%s).", X (rp->flag & RED_PIPE) ? "pipe" : X "file", rp->value, strerror(errno)); X status++; X } X return status; X} X Xint Xclose_io () X{ X register struct redirect *rp; X int status = 0; X X for (rp = red_head; rp != NULL; rp = rp->next) X if (close_redir(rp)) X status++; X return status; X} X X/* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */ Xint Xdevopen (name, mode) Xchar *name, *mode; X{ X int openfd = -1; X FILE *fdopen (); X char *cp; X int flag = 0; X X switch(mode[0]) { X case 'r': X flag = O_RDONLY; X break; X X case 'w': X flag = O_WRONLY|O_CREAT|O_TRUNC; X break; X X case 'a': X flag = O_WRONLY|O_APPEND|O_CREAT; X break; X default: X cant_happen(); X } X X#if defined(STRICT) || defined(NO_DEV_FD) X return (open (name, flag, 0666)); X#else X if (strict) X return (open (name, flag, 0666)); X X if (!STREQN (name, "/dev/", 5)) X return (open (name, flag, 0666)); X else X cp = name + 5; X X /* XXX - first three tests ignore mode */ X if (STREQ(cp, "stdin")) X return (0); X else if (STREQ(cp, "stdout")) X return (1); X else if (STREQ(cp, "stderr")) X return (2); X else if (STREQN(cp, "fd/", 3)) { X cp += 3; X if (sscanf (cp, "%d", & openfd) == 1 && openfd >= 0) X /* got something */ X return openfd; X else X return -1; X } else X return (open (name, flag, 0666)); X#endif X} X X#ifndef MSDOS Xstatic IOBUF * Xgawk_popen(cmd, rp) Xchar *cmd; Xstruct redirect *rp; X{ X int p[2]; X register int pid; X X rp->pid = -1; X rp->iop = NULL; X if (pipe(p) < 0) X return NULL; X if ((pid = fork()) == 0) { X close(p[0]); X dup2(p[1], 1); X close(p[1]); X execl("/bin/sh", "sh", "-c", cmd, 0); X _exit(127); X } X if (pid == -1) X return NULL; X rp->pid = pid; X close(p[1]); X return (rp->iop = iop_alloc(p[0])); X} X Xstatic int Xgawk_pclose(rp) Xstruct redirect *rp; X{ X SIGTYPE (*hstat)(), (*istat)(), (*qstat)(); X int pid; X int status; X struct redirect *redp; X X iop_close(rp->iop); X if (rp->pid == -1) X return rp->status; X hstat = signal(SIGHUP, SIG_IGN); X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X for (;;) { X pid = wait(&status); X if (pid == -1 && errno == ECHILD) X break; X else if (pid == rp->pid) { X rp->pid = -1; X rp->status = status; X break; X } else { X for (redp = red_head; redp != NULL; redp = redp->next) X if (pid == redp->pid) { X redp->pid = -1; X redp->status = status; X break; X } X } X } X signal(SIGHUP, hstat); X signal(SIGINT, istat); X signal(SIGQUIT, qstat); X return(rp->status); X} X#else Xstatic Xstruct { X char *command; X char *name; X} pipes[_NFILE]; X Xstatic IOBUF * Xgawk_popen(cmd, rp) Xchar *cmd; Xstruct redirect *rp; X{ X extern char *strdup(const char *); X int current; X char *name; X static char cmdbuf[256]; X X /* get a name to use. */ X if ((name = tempnam(".", "pip")) == NULL) X return NULL; X sprintf(cmdbuf,"%s > %s", cmd, name); X system(cmdbuf); X if ((current = open(name,O_RDONLY)) == -1) X return NULL; X pipes[current].name = name; X pipes[current].command = strdup(cmd); X return (rp->iop = iop_alloc(current)); X} X Xstatic int Xgawk_pclose(rp) Xstruct redirect *rp; X{ X int cur = rp->iop->fd; X int rval; X X rval = iop_close(rp->iop); X X /* check for an open file */ X if (pipes[cur].name == NULL) X return -1; X unlink(pipes[cur].name); X free(pipes[cur].name); X pipes[cur].name = NULL; X free(pipes[cur].command); X return rval; X} X#endif X X#define DO_END_OF_BUF len = bp - iop->off;\ X used = last - start;\ X while (len + used > iop->secsiz) {\ X iop->secsiz *= 2;\ X erealloc(iop->secbuf,char *,iop->secsiz,"get");\ X }\ X last = iop->secbuf + used;\ X start = iop->secbuf;\ X memcpy(last, iop->off, len);\ X last += len;\ X iop->cnt = read(iop->fd, iop->buf, iop->size);\ X if (iop->cnt < 0)\ X return iop->cnt;\ X end_data = iop->buf + iop->cnt;\ X iop->off = bp = iop->buf; X X#define DO_END_OF_DATA iop->cnt = read(iop->fd, end_data, end_buf - end_data);\ X if (iop->cnt < 0)\ X return iop->cnt;\ X end_data += iop->cnt;\ X if (iop->cnt == 0)\ X break;\ X iop->cnt = end_data - iop->buf; X Xstatic int Xget_a_record(res, iop) Xchar **res; XIOBUF *iop; X{ X register char *end_data; X register char *end_buf; X char *start; X register char *bp; X register char *last; X int len, used; X register char rs = get_rs(); X X if (iop->cnt < 0) X return iop->cnt; X if ((iop->flag & IOP_IS_TTY) && output_is_tty) X fflush(stdout); X end_data = iop->buf + iop->cnt; X if (iop->off >= end_data) { X iop->cnt = read(iop->fd, iop->buf, iop->size); X if (iop->cnt <= 0) X return iop->cnt = EOF; X end_data = iop->buf + iop->cnt; X iop->off = iop->buf; X } X last = start = bp = iop->off; X end_buf = iop->buf + iop->size; X if (rs == 0) { X while (!(*bp == '\n' && bp != iop->buf && bp[-1] == '\n')) { X if (++bp == end_buf) { X DO_END_OF_BUF X } X if (bp == end_data) { X DO_END_OF_DATA X } X } X if (*bp == '\n' && bp != iop->off && bp[-1] == '\n') { X int tmp = 0; X X /* allow for more than two newlines */ X while (*bp == '\n') { X tmp++; X if (++bp == end_buf) { X DO_END_OF_BUF X } X if (bp == end_data) { X DO_END_OF_DATA X } X } X iop->off = bp; X bp -= 1 + tmp; X } else if (bp != iop->buf && bp[-1] != '\n') { X warning("record not terminated"); X iop->off = bp + 2; X } else { X bp--; X iop->off = bp + 2; X } X } else { X while (*bp++ != rs) { X if (bp == end_buf) { X DO_END_OF_BUF X } X if (bp == end_data) { X DO_END_OF_DATA X } X } X if (*--bp != rs) { X warning("record not terminated"); X bp++; X } X iop->off = bp + 1; X } X if (start == iop->secbuf) { X len = bp - iop->buf; X if (len > 0) { X used = last - start; X while (len + used > iop->secsiz) { X iop->secsiz *= 2; X erealloc(iop->secbuf,char *,iop->secsiz,"get2"); X } X last = iop->secbuf + used; X start = iop->secbuf; X memcpy(last, iop->buf, len); X last += len; X } X } else X last = bp; X *last = '\0'; X *res = start; X return last - start; X} X XNODE * Xdo_getline(tree) XNODE *tree; X{ X struct redirect *rp; X IOBUF *iop; X int cnt; X NODE **lhs; X int redir_error = 0; X X if (tree->rnode == NULL) { /* no redirection */ X iop = nextfile(); X if (iop == NULL) /* end of input */ X return tmp_number((AWKNUM) 0.0); X } else { X rp = redirect(tree->rnode, &redir_error); X if (rp == NULL && redir_error) /* failed redirect */ X return tmp_number((AWKNUM) -1.0); X iop = rp->iop; X getline_redirect++; X } X if (tree->lnode == NULL) { /* no optional var. -- read in $0 */ X if (inrec(iop) != 0) { X getline_redirect = 0; X return tmp_number((AWKNUM) 0.0); X } X } else { /* read in a named variable */ X char *s = NULL; X X lhs = get_lhs(tree->lnode, 1); X cnt = get_a_record(&s, iop); X if (!getline_redirect) { X assign_number(&NR_node->var_value, X NR_node->var_value->numbr + 1.0); X assign_number(&FNR_node->var_value, X FNR_node->var_value->numbr + 1.0); X } X if (cnt == EOF) { X getline_redirect = 0; X free(s); X return tmp_number((AWKNUM) 0.0); X } X *lhs = make_string(s, strlen(s)); X do_deref(); X /* we may have to regenerate $0 here! */ X if (field_num == 0) X set_record(fields_arr[0]->stptr, fields_arr[0]->stlen); X field_num = -1; X } X getline_redirect = 0; X return tmp_number((AWKNUM) 1.0); X} END_OF_FILE if test 17467 -ne `wc -c <'./io.c'`; then echo shar: \"'./io.c'\" unpacked with wrong size! fi # end of './io.c' fi if test -f './missing.d/memcpy.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./missing.d/memcpy.c'\" else echo shar: Extracting \"'./missing.d/memcpy.c'\" \(261 characters\) sed "s/^X//" >'./missing.d/memcpy.c' <<'END_OF_FILE' X/* X * memcpy --- copy strings. X * X * We supply this routine for those systems that aren't standard yet. X */ X Xchar * Xmemcpy (dest, src, l) Xregister char *dest, *src; Xregister int l; X{ X register char *ret = dest; X X while (l--) X *dest++ = *src++; X X return ret; X} END_OF_FILE if test 261 -ne `wc -c <'./missing.d/memcpy.c'`; then echo shar: \"'./missing.d/memcpy.c'\" unpacked with wrong size! fi # end of './missing.d/memcpy.c' fi echo shar: End of archive 11 \(of 16\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 16 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.