Subject: v22i090: GNU AWK, version 2.11, Part04/16 Newsgroups: comp.sources.unix Approved: rsalz@uunet.UU.NET X-Checksum-Snefru: 35836423 9d91dc22 c899fe92 c7b41f10 Submitted-by: "Arnold D. Robbins" Posting-number: Volume 22, Issue 90 Archive-name: gawk2.11/part04 #! /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.texinfo.05 ./patchlevel.h ./pc.d/popen.c # Wrapped by rsalz@litchi.bbn.com on Wed Jun 6 12:24:48 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 4 (of 16)."' if test -f './gawk.texinfo.05' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./gawk.texinfo.05'\" else echo shar: Extracting \"'./gawk.texinfo.05'\" \(49666 characters\) sed "s/^X//" >'./gawk.texinfo.05' <<'END_OF_FILE' XIf a line number is repeated, the last line with a given number overrides Xthe others. X XGaps in the line numbers can be handled with an easy improvement to the Xprogram's @code{END} rule: X X@example XEND @{ X for (x = 1; x <= max; x++) X if (x in arr) X print arr[x] X@} X@end example X X@node Scanning an Array, Delete, Array Example, Arrays X@section Scanning All Elements of an Array X@cindex @code{for (x in @dots{})} X@cindex arrays, special @code{for} statement X@cindex scanning an array X XIn programs that use arrays, often you need a loop that executes Xonce for each element of an array. In other languages, where arrays are Xcontiguous and indices are limited to positive integers, this is Xeasy: the largest index is one less than the length of the array, and you can Xfind all the valid indices by counting from zero up to that value. This Xtechnique won't do the job in @code{awk}, since any number or string Xmay be an array index. So @code{awk} has a special kind of @code{for} Xstatement for scanning an array: X X@example Xfor (@var{var} in @var{array}) X @var{body} X@end example X X@noindent XThis loop executes @var{body} once for each different value that your Xprogram has previously used as an index in @var{array}, with the Xvariable @var{var} set to that index.@refill X XHere is a program that uses this form of the @code{for} statement. The Xfirst rule scans the input records and notes which words appear (at Xleast once) in the input, by storing a 1 into the array @code{used} with Xthe word as index. The second rule scans the elements of @code{used} to Xfind all the distinct words that appear in the input. It prints each Xword that is more than 10 characters long, and also prints the number of Xsuch words. @xref{Built-in}, for more information on the built-in Xfunction @code{length}. X X@example X# Record a 1 for each word that is used at least once. X@{ X for (i = 0; i < NF; i++) X used[$i] = 1 X@} X X# Find number of distinct words more than 10 characters long. XEND @{ X num_long_words = 0 X for (x in used) X if (length(x) > 10) @{ X ++num_long_words X print x X @} X print num_long_words, "words longer than 10 characters" X@} X@end example X X@noindent X@xref{Sample Program}, for a more detailed example of this type. X XThe order in which elements of the array are accessed by this statement Xis determined by the internal arrangement of the array elements within X@code{awk} and cannot be controlled or changed. This can lead to Xproblems if new elements are added to @var{array} by statements in X@var{body}; you cannot predict whether or not the @code{for} loop will Xreach them. Similarly, changing @var{var} inside the loop can produce Xstrange results. It is best to avoid such things.@refill X X@node Delete, Multi-dimensional, Scanning an Array, Arrays X@section The @code{delete} Statement X@cindex @code{delete} statement X@cindex deleting elements of arrays X@cindex removing elements of arrays X@cindex arrays, deleting an element X XYou can remove an individual element of an array using the @code{delete} Xstatement: X X@example Xdelete @var{array}[@var{index}] X@end example X XWhen an array element is deleted, it is as if you had never referred to it Xand had never given it any value. Any value the element formerly had Xcan no longer be obtained. X XHere is an example of deleting elements in an array: X X@example Xfor (i in frequencies) X delete frequencies[i] X@end example X X@noindent XThis example removes all the elements from the array @code{frequencies}. X XIf you delete an element, a subsequent @code{for} statement to scan the array Xwill not report that element, and the @code{in} operator to check for Xthe presence of that element will return 0: X X@example Xdelete foo[4] Xif (4 in foo) X print "This will never be printed" X@end example X X@node Multi-dimensional, Multi-scanning, Delete, Arrays X@section Multi-dimensional Arrays X X@cindex subscripts, multi-dimensional in arrays X@cindex arrays, multi-dimensional subscripts X@cindex multi-dimensional subscripts XA multi-dimensional array is an array in which an element is identified Xby a sequence of indices, not a single index. For example, a Xtwo-dimensional array requires two indices. The usual way (in most Xlanguages, including @code{awk}) to refer to an element of a Xtwo-dimensional array named @code{grid} is with X@code{grid[@var{x},@var{y}]}. X X@vindex SUBSEP XMulti-dimensional arrays are supported in @code{awk} through Xconcatenation of indices into one string. What happens is that X@code{awk} converts the indices into strings (@pxref{Conversion}) and Xconcatenates them together, with a separator between them. This creates Xa single string that describes the values of the separate indices. The Xcombined string is used as a single index into an ordinary, Xone-dimensional array. The separator used is the value of the built-in Xvariable @code{SUBSEP}. X XFor example, suppose we evaluate the expression @code{foo[5,12]="value"} Xwhen the value of @code{SUBSEP} is @code{"@@"}. The numbers 5 and 12 are Xconcatenated with a comma between them, yielding @code{"5@@12"}; thus, Xthe array element @code{foo["5@@12"]} is set to @code{"value"}. X XOnce the element's value is stored, @code{awk} has no record of whether Xit was stored with a single index or a sequence of indices. The two Xexpressions @code{foo[5,12]} and @w{@code{foo[5 SUBSEP 12]}} always have Xthe same value. X XThe default value of @code{SUBSEP} is actually the string @code{"\034"}, Xwhich contains a nonprinting character that is unlikely to appear in an X@code{awk} program or in the input data. X XThe usefulness of choosing an unlikely character comes from the fact Xthat index values that contain a string matching @code{SUBSEP} lead to Xcombined strings that are ambiguous. Suppose that @code{SUBSEP} were X@code{"@@"}; then @w{@code{foo["a@@b", "c"]}} and @w{@code{foo["a", X"b@@c"]}} would be indistinguishable because both would actually be Xstored as @code{foo["a@@b@@c"]}. Because @code{SUBSEP} is X@code{"\034"}, such confusion can actually happen only when an index Xcontains the character with ASCII code 034, which is a rare Xevent.@refill X XYou can test whether a particular index-sequence exists in a X``multi-dimensional'' array with the same operator @code{in} used for single Xdimensional arrays. Instead of a single index as the left-hand operand, Xwrite the whole sequence of indices, separated by commas, in Xparentheses:@refill X X@example X(@var{subscript1}, @var{subscript2}, @dots{}) in @var{array} X@end example X XThe following example treats its input as a two-dimensional array of Xfields; it rotates this array 90 degrees clockwise and prints the Xresult. It assumes that all lines have the same number of Xelements. X X@example Xawk '@{ X if (max_nf < NF) X max_nf = NF X max_nr = NR X for (x = 1; x <= NF; x++) X vector[x, NR] = $x X@} X XEND @{ X for (x = 1; x <= max_nf; x++) @{ X for (y = max_nr; y >= 1; --y) X printf("%s ", vector[x, y]) X printf("\n") X @} X@}' X@end example X X@noindent XWhen given the input: X X@example X1 2 3 4 5 6 X2 3 4 5 6 1 X3 4 5 6 1 2 X4 5 6 1 2 3 X@end example X X@noindent Xit produces: X X@example X4 3 2 1 X5 4 3 2 X6 5 4 3 X1 6 5 4 X2 1 6 5 X3 2 1 6 X@end example X X@node Multi-scanning, , Multi-dimensional, Arrays X@section Scanning Multi-dimensional Arrays X XThere is no special @code{for} statement for scanning a X``multi-dimensional'' array; there cannot be one, because in truth there Xare no multi-dimensional arrays or elements; there is only a Xmulti-dimensional @emph{way of accessing} an array. X XHowever, if your program has an array that is always accessed as Xmulti-dimensional, you can get the effect of scanning it by combining Xthe scanning @code{for} statement (@pxref{Scanning an Array}) with the X@code{split} built-in function (@pxref{String Functions}). It works Xlike this: X X@example Xfor (combined in @var{array}) @{ X split(combined, separate, SUBSEP) X @dots{} X@} X@end example X X@noindent XThis finds each concatenated, combined index in the array, and splits it Xinto the individual indices by breaking it apart where the value of X@code{SUBSEP} appears. The split-out indices become the elements of Xthe array @code{separate}. X XThus, suppose you have previously stored in @code{@var{array}[1, X"foo"]}; then an element with index @code{"1\034foo"} exists in X@var{array}. (Recall that the default value of @code{SUBSEP} contains Xthe character with code 034.) Sooner or later the @code{for} statement Xwill find that index and do an iteration with @code{combined} set to X@code{"1\034foo"}. Then the @code{split} function is called as Xfollows: X X@example Xsplit("1\034foo", separate, "\034") X@end example X X@noindent XThe result of this is to set @code{separate[1]} to 1 and @code{separate[2]} Xto @code{"foo"}. Presto, the original sequence of separate indices has Xbeen recovered. X X@node Built-in, User-defined, Arrays, Top X@chapter Built-in Functions X X@cindex built-in functions X@dfn{Built-in} functions are functions that are always available for Xyour @code{awk} program to call. This chapter defines all the built-in Xfunctions in @code{awk}; some of them are mentioned in other sections, Xbut they are summarized here for your convenience. (You can also define Xnew functions yourself. @xref{User-defined}.) X X@menu X* Calling Built-in:: How to call built-in functions. X X* Numeric Functions:: Functions that work with numbers, X including @code{int}, @code{sin} and @code{rand}. X X* String Functions:: Functions for string manipulation, X such as @code{split}, @code{match}, and @code{sprintf}. X X* I/O Functions:: Functions for files and shell commands X@end menu X X@node Calling Built-in, Numeric Functions, Built-in, Built-in X@section Calling Built-in Functions X XTo call a built-in function, write the name of the function followed Xby arguments in parentheses. For example, @code{atan2(y + z, 1)} Xis a call to the function @code{atan2}, with two arguments. X XWhitespace is ignored between the built-in function name and the Xopen-parenthesis, but we recommend that you avoid using whitespace Xthere. User-defined functions do not permit whitespace in this way, and Xyou will find it easier to avoid mistakes by following a simple Xconvention which always works: no whitespace after a function name. X XEach built-in function accepts a certain number of arguments. In most Xcases, any extra arguments given to built-in functions are ignored. The Xdefaults for omitted arguments vary from function to function and are Xdescribed under the individual functions. X XWhen a function is called, expressions that create the function's actual Xparameters are evaluated completely before the function call is performed. XFor example, in the code fragment: X X@example Xi = 4 Xj = sqrt(i++) X@end example X X@noindent Xthe variable @code{i} is set to 5 before @code{sqrt} is called Xwith a value of 4 for its actual parameter. X X@node Numeric Functions, String Functions, Calling Built-in, Built-in X@section Numeric Built-in Functions X XHere is a full list of built-in functions that work with numbers: X X@table @code X@item int(@var{x}) XThis gives you the integer part of @var{x}, truncated toward 0. This Xproduces the nearest integer to @var{x}, located between @var{x} and 0. X XFor example, @code{int(3)} is 3, @code{int(3.9)} is 3, @code{int(-3.9)} Xis @minus{}3, and @code{int(-3)} is @minus{}3 as well.@refill X X@item sqrt(@var{x}) XThis gives you the positive square root of @var{x}. It reports an error Xif @var{x} is negative. Thus, @code{sqrt(4)} is 2.@refill X X@item exp(@var{x}) XThis gives you the exponential of @var{x}, or reports an error if X@var{x} is out of range. The range of values @var{x} can have depends Xon your machine's floating point representation.@refill X X@item log(@var{x}) XThis gives you the natural logarithm of @var{x}, if @var{x} is positive; Xotherwise, it reports an error.@refill X X@item sin(@var{x}) XThis gives you the sine of @var{x}, with @var{x} in radians. X X@item cos(@var{x}) XThis gives you the cosine of @var{x}, with @var{x} in radians. X X@item atan2(@var{y}, @var{x}) XThis gives you the arctangent of @code{@var{y} / @var{x}}, with the Xquotient understood in radians. X X@item rand() XThis gives you a random number. The values of @code{rand} are Xuniformly-distributed between 0 and 1. The value is never 0 and never X1. X XOften you want random integers instead. Here is a user-defined function Xyou can use to obtain a random nonnegative integer less than @var{n}: X X@example Xfunction randint(n) @{ X return int(n * rand()) X@} X@end example X X@noindent XThe multiplication produces a random real number greater than 0 and less Xthan @var{n}. We then make it an integer (using @code{int}) between 0 Xand @code{@var{n} @minus{} 1}. X XHere is an example where a similar function is used to produce Xrandom integers between 1 and @var{n}: X X@example Xawk ' X# Function to roll a simulated die. Xfunction roll(n) @{ return 1 + int(rand() * n) @} X X# Roll 3 six-sided dice and print total number of points. X@{ X printf("%d points\n", roll(6)+roll(6)+roll(6)) X@}' X@end example X X@strong{Note:} @code{rand} starts generating numbers from the same Xpoint, or @dfn{seed}, each time you run @code{awk}. This means that Xa program will produce the same results each time you run it. XThe numbers are random within one @code{awk} run, but predictable Xfrom run to run. This is convenient for debugging, but if you want Xa program to do different things each time it is used, you must change Xthe seed to a value that will be different in each run. To do this, Xuse @code{srand}. X X@item srand(@var{x}) XThe function @code{srand} sets the starting point, or @dfn{seed}, Xfor generating random numbers to the value @var{x}. X XEach seed value leads to a particular sequence of ``random'' numbers. XThus, if you set the seed to the same value a second time, you will get Xthe same sequence of ``random'' numbers again. X XIf you omit the argument @var{x}, as in @code{srand()}, then the current Xdate and time of day are used for a seed. This is the way to get random Xnumbers that are truly unpredictable. X XThe return value of @code{srand} is the previous seed. This makes it Xeasy to keep track of the seeds for use in consistently reproducing Xsequences of random numbers. X@end table X X@node String Functions, I/O Functions, Numeric Functions, Built-in X@section Built-in Functions for String Manipulation X X The functions in this section look at the text of one or more Xstrings. X X@table @code X@item index(@var{in}, @var{find}) X@findex match XThis searches the string @var{in} for the first occurrence of the string X@var{find}, and returns the position where that occurrence begins in the Xstring @var{in}. For example:@refill X X@example Xawk 'BEGIN @{ print index("peanut", "an") @}' X@end example X X@noindent Xprints @samp{3}. If @var{find} is not found, @code{index} returns 0. X X@item length(@var{string}) X@findex length XThis gives you the number of characters in @var{string}. If X@var{string} is a number, the length of the digit string representing Xthat number is returned. For example, @code{length("abcde")} is 5. By Xcontrast, @code{length(15 * 35)} works out to 3. How? Well, 15 * 35 = X525, and 525 is then converted to the string @samp{"525"}, which has Xthree characters. X XIf no argument is supplied, @code{length} returns the length of @code{$0}. X X@item match(@var{string}, @var{regexp}) X@findex match XThe @code{match} function searches the string, @var{string}, for the Xlongest, leftmost substring matched by the regular expression, X@var{regexp}. It returns the character position, or @dfn{index}, of Xwhere that substring begins (1, if it starts at the beginning of X@var{string}). If no match if found, it returns 0. X X@vindex RSTART X@vindex RLENGTH XThe @code{match} function sets the built-in variable @code{RSTART} to Xthe index. It also sets the built-in variable @code{RLENGTH} to the Xlength of the matched substring. If no match is found, @code{RSTART} Xis set to 0, and @code{RLENGTH} to @minus{}1. X XFor example: X X@example Xawk '@{ X if ($1 == "FIND") X regex = $2 X else @{ X where = match($0, regex) X if (where) X print "Match of", regex, "found at", where, "in", $0 X @} X@}' X@end example X X@noindent XThis program looks for lines that match the regular expression stored in Xthe variable @code{regex}. This regular expression can be changed. If the Xfirst word on a line is @samp{FIND}, @code{regex} is changed to be the Xsecond word on that line. Therefore, given: X X@example XFIND fo*bar XMy program was a foobar XBut none of it would doobar XFIND Melvin XJF+KM XThis line is property of The Reality Engineering Co. XThis file created by Melvin. X@end example X X@noindent X@code{awk} prints: X X@example XMatch of fo*bar found at 18 in My program was a foobar XMatch of Melvin found at 26 in This file created by Melvin. X@end example X X@item split(@var{string}, @var{array}, @var{fieldsep}) X@findex split XThis divides @var{string} up into pieces separated by @var{fieldsep}, Xand stores the pieces in @var{array}. The first piece is stored in X@code{@var{array}[1]}, the second piece in @code{@var{array}[2]}, and so Xforth. The string value of the third argument, @var{fieldsep}, is used Xas a regexp to search for to find the places to split @var{string}. If Xthe @var{fieldsep} is omitted, the value of @code{FS} is used. X@code{split} returns the number of elements created.@refill X XThe @code{split} function, then, splits strings into pieces in a Xmanner similar to the way input lines are split into fields. For example: X X@example Xsplit("auto-da-fe", a, "-") X@end example X X@noindent Xsplits the string @samp{auto-da-fe} into three fields using @samp{-} as the Xseparator. It sets the contents of the array @code{a} as follows: X X@example Xa[1] = "auto" Xa[2] = "da" Xa[3] = "fe" X@end example X X@noindent XThe value returned by this call to @code{split} is 3. X X@item sprintf(@var{format}, @var{expression1},@dots{}) X@findex sprintf XThis returns (without printing) the string that @code{printf} would Xhave printed out with the same arguments (@pxref{Printf}). For Xexample: X X@example Xsprintf("pi = %.2f (approx.)", 22/7) X@end example X X@noindent Xreturns the string @w{@code{"pi = 3.14 (approx.)"}}. X X@item sub(@var{regexp}, @var{replacement}, @var{target}) X@findex sub XThe @code{sub} function alters the value of @var{target}. XIt searches this value, which should be a string, for the Xleftmost substring matched by the regular expression, @var{regexp}, Xextending this match as far as possible. Then the entire string is Xchanged by replacing the matched text with @var{replacement}. XThe modified string becomes the new value of @var{target}. X XThis function is peculiar because @var{target} is not simply Xused to compute a value, and not just any expression will do: it Xmust be a variable, field or array reference, so that @code{sub} can Xstore a modified value there. If this argument is omitted, then the Xdefault is to use and alter @code{$0}. X XFor example:@refill X X@example Xstr = "water, water, everywhere" Xsub(/at/, "ith", str) X@end example X X@noindent Xsets @code{str} to @w{@code{"wither, water, everywhere"}}, by replacing the Xleftmost, longest occurrence of @samp{at} with @samp{ith}. X XThe @code{sub} function returns the number of substitutions made (either Xone or zero). X XIf the special character @samp{&} appears in @var{replacement}, it Xstands for the precise substring that was matched by @var{regexp}. (If Xthe regexp can match more than one string, then this precise substring Xmay vary.) For example:@refill X X@example Xawk '@{ sub(/candidate/, "& and his wife"); print @}' X@end example X X@noindent Xchanges the first occurrence of @samp{candidate} to @samp{candidate Xand his wife} on each input line. X XThe effect of this special character can be turned off by putting a Xbackslash before it in the string. As usual, to insert one backslash in Xthe string, you must write two backslashes. Therefore, write @samp{\\&} Xin a string constant to include a literal @samp{&} in the replacement. XFor example, here is how to replace the first @samp{|} on each line with Xan @samp{&}:@refill X X@example Xawk '@{ sub(/\|/, "\\&"); print @}' X@end example X X@strong{Note:} as mentioned above, the third argument to @code{sub} must Xbe an lvalue. Some versions of @code{awk} allow the third argument to Xbe an expression which is not an lvalue. In such a case, @code{sub} Xwould still search for the pattern and return 0 or 1, but the result of Xthe substitution (if any) would be thrown away because there is no place Xto put it. Such versions of @code{awk} accept expressions like Xthis:@refill X X@example Xsub(/USA/, "United States", "the USA and Canada") X@end example X X@noindent XBut that is considered erroneous in @code{gawk}. X X@item gsub(@var{regexp}, @var{replacement}, @var{target}) X@findex gsub XThis is similar to the @code{sub} function, except @code{gsub} replaces X@emph{all} of the longest, leftmost, @emph{nonoverlapping} matching Xsubstrings it can find. The @samp{g} in @code{gsub} stands for X``global'', which means replace everywhere. For example:@refill X X@example Xawk '@{ gsub(/Britain/, "United Kingdom"); print @}' X@end example X X@noindent Xreplaces all occurrences of the string @samp{Britain} with @samp{United XKingdom} for all input records.@refill X XThe @code{gsub} function returns the number of substitutions made. If Xthe variable to be searched and altered, @var{target}, is Xomitted, then the entire input record, @code{$0}, is used.@refill X XAs in @code{sub}, the characters @samp{&} and @samp{\} are special, and Xthe third argument must be an lvalue. X X@item substr(@var{string}, @var{start}, @var{length}) X@findex substr XThis returns a @var{length}-character-long substring of @var{string}, Xstarting at character number @var{start}. The first character of a Xstring is character number one. For example, X@code{substr("washington", 5, 3)} returns @code{"ing"}.@refill X XIf @var{length} is not present, this function returns the whole suffix of X@var{string} that begins at character number @var{start}. For example, X@code{substr("washington", 5)} returns @code{"ington"}. X X@item tolower(@var{string}) X@findex tolower XThis returns a copy of @var{string}, with each upper-case character Xin the string replaced with its corresponding lower-case character. XNonalphabetic characters are left unchanged. For example, X@code{tolower("MiXeD cAsE 123")} returns @code{"mixed case 123"}. X X@item toupper(@var{string}) X@findex toupper XThis returns a copy of @var{string}, with each lower-case character Xin the string replaced with its corresponding upper-case character. XNonalphabetic characters are left unchanged. For example, X@code{toupper("MiXeD cAsE 123")} returns @code{"MIXED CASE 123"}. X@end table X X@node I/O Functions, , String Functions, Built-in X@section Built-in Functions For Input/Output X X@table @code X@item close(@var{filename}) XClose the file @var{filename}, for input or output. The argument may Xalternatively be a shell command that was used for redirecting to or Xfrom a pipe; then the pipe is closed. X X@xref{Close Input}, regarding closing input files and pipes. X@xref{Close Output}, regarding closing output files and pipes. X X@item system(@var{command}) X@findex system X@cindex interaction of @code{awk} with other programs XThe system function allows the user to execute operating system commands Xand then return to the @code{awk} program. The @code{system} function Xexecutes the command given by the string @var{command}. It returns, as Xits value, the status returned by the command that was executed. X XFor example, if the following fragment of code is put in your @code{awk} Xprogram: X X@example XEND @{ X system("mail -s 'awk run done' operator < /dev/null") X@} X@end example X X@noindent Xthe system operator will be sent mail when the @code{awk} program Xfinishes processing input and begins its end-of-input processing. X XNote that much the same result can be obtained by redirecting X@code{print} or @code{printf} into a pipe. However, if your @code{awk} Xprogram is interactive, @code{system} is useful for cranking up large Xself-contained programs, such as a shell or an editor.@refill X XSome operating systems cannot implement the @code{system} function. X@code{system} causes a fatal error if it is not supported. X@end table X X@node User-defined, Built-in Variables, Built-in, Top X@chapter User-defined Functions X X@cindex user-defined functions X@cindex functions, user-defined XComplicated @code{awk} programs can often be simplified by defining Xyour own functions. User-defined functions can be called just like Xbuilt-in ones (@pxref{Function Calls}), but it is up to you to define Xthem---to tell @code{awk} what they should do. X X@menu X* Definition Syntax:: How to write definitions and what they mean. X* Function Example:: An example function definition and what it does. X* Function Caveats:: Things to watch out for. X* Return Statement:: Specifying the value a function returns. X@end menu X X@node Definition Syntax, Function Example, User-defined, User-defined X@section Syntax of Function Definitions X@cindex defining functions X@cindex function definition X XDefinitions of functions can appear anywhere between the rules of the X@code{awk} program. Thus, the general form of an @code{awk} program is Xextended to include sequences of rules @emph{and} user-defined function Xdefinitions. X XThe definition of a function named @var{name} looks like this: X X@example Xfunction @var{name} (@var{parameter-list}) @{ X @var{body-of-function} X@} X@end example X X@noindent XThe keyword @code{function} may be abbreviated @code{func}. X X@var{name} is the name of the function to be defined. A valid function Xname is like a valid variable name: a sequence of letters, digits and Xunderscores, not starting with a digit. X X@var{parameter-list} is a list of the function's arguments and local Xvariable names, separated by commas. When the function is called, Xthe argument names are used to hold the argument values given in Xthe call. The local variables are initialized to the null string. X XThe @var{body-of-function} consists of @code{awk} statements. It is the Xmost important part of the definition, because it says what the function Xshould actually @emph{do}. The argument names exist to give the body a Xway to talk about the arguments; local variables, to give the body Xplaces to keep temporary values. X XArgument names are not distinguished syntactically from local variable Xnames; instead, the number of arguments supplied when the function is Xcalled determines how many argument variables there are. Thus, if three Xargument values are given, the first three names in @var{parameter-list} Xare arguments, and the rest are local variables. X XIt follows that if the number of arguments is not the same in all calls Xto the function, some of the names in @var{parameter-list} may be Xarguments on some occasions and local variables on others. Another Xway to think of this is that omitted arguments default to the Xnull string. X XUsually when you write a function you know how many names you intend to Xuse for arguments and how many you intend to use as locals. By Xconvention, you should write an extra space between the arguments and Xthe locals, so that other people can follow how your function is Xsupposed to be used. X XDuring execution of the function body, the arguments and local variable Xvalues hide or @dfn{shadow} any variables of the same names used in the Xrest of the program. The shadowed variables are not accessible in the Xfunction definition, because there is no way to name them while their Xnames have been taken away for the local variables. All other variables Xused in the @code{awk} program can be referenced or set normally in the Xfunction definition. X XThe arguments and local variables last only as long as the function body Xis executing. Once the body finishes, the shadowed variables come back. X XThe function body can contain expressions which call functions. They Xcan even call this function, either directly or by way of another Xfunction. When this happens, we say the function is @dfn{recursive}. X XThere is no need in @code{awk} to put the definition of a function Xbefore all uses of the function. This is because @code{awk} reads the Xentire program before starting to execute any of it. X X@node Function Example, Function Caveats, Definition Syntax, User-defined X@section Function Definition Example X XHere is an example of a user-defined function, called @code{myprint}, that Xtakes a number and prints it in a specific format. X X@example Xfunction myprint(num) X@{ X printf "%6.3g\n", num X@} X@end example X X@noindent XTo illustrate, here is an @code{awk} rule which uses our @code{myprint} Xfunction: X X@example X$3 > 0 @{ myprint($3) @} X@end example X X@noindent XThis program prints, in our special format, all the third fields that Xcontain a positive number in our input. Therefore, when given: X X@example X 1.2 3.4 5.6 7.8 X 9.10 11.12 13.14 15.16 X17.18 19.20 21.22 23.24 X@end example X X@noindent Xthis program, using our function to format the results, prints: X X@example X 5.6 X 13.1 X 21.2 X@end example X XHere is a rather contrived example of a recursive function. It prints a Xstring backwards: X X@example Xfunction rev (str, len) @{ X if (len == 0) @{ X printf "\n" X return X @} X printf "%c", substr(str, len, 1) X rev(str, len - 1) X@} X@end example X X@node Function Caveats, Return Statement, Function Example, User-defined X@section Calling User-defined Functions X X@dfn{Calling a function} means causing the function to run and do its job. XA function call is an expression, and its value is the value returned by Xthe function. X XA function call consists of the function name followed by the arguments Xin parentheses. What you write in the call for the arguments are X@code{awk} expressions; each time the call is executed, these Xexpressions are evaluated, and the values are the actual arguments. For Xexample, here is a call to @code{foo} with three arguments: X X@example Xfoo(x y, "lose", 4 * z) X@end example X X@strong{Note:} whitespace characters (spaces and tabs) are not allowed Xbetween the function name and the open-parenthesis of the argument list. XIf you write whitespace by mistake, @code{awk} might think that you mean Xto concatenate a variable with an expression in parentheses. However, it Xnotices that you used a function name and not a variable name, and reports Xan error. X X@cindex call by value XWhen a function is called, it is given a @emph{copy} of the values of Xits arguments. This is called @dfn{call by value}. The caller may use Xa variable as the expression for the argument, but the called function Xdoes not know this: all it knows is what value the argument had. For Xexample, if you write this code: X X@example Xfoo = "bar" Xz = myfunc(foo) X@end example X X@noindent Xthen you should not think of the argument to @code{myfunc} as being X``the variable @code{foo}''. Instead, think of the argument as the Xstring value, @code{"bar"}. X XIf the function @code{myfunc} alters the values of its local variables, Xthis has no effect on any other variables. In particular, if @code{myfunc} Xdoes this: X X@example Xfunction myfunc (win) @{ X print win X win = "zzz" X print win X@} X@end example X X@noindent Xto change its first argument variable @code{win}, this @emph{does not} Xchange the value of @code{foo} in the caller. The role of @code{foo} in Xcalling @code{myfunc} ended when its value, @code{"bar"}, was computed. XIf @code{win} also exists outside of @code{myfunc}, the function body Xcannot alter this outer value, because it is shadowed during the Xexecution of @code{myfunc} and cannot be seen or changed from there. X X@cindex call by reference XHowever, when arrays are the parameters to functions, they are @emph{not} Xcopied. Instead, the array itself is made available for direct manipulation Xby the function. This is usually called @dfn{call by reference}. XChanges made to an array parameter inside the body of a function @emph{are} Xvisible outside that function. @emph{This can be very dangerous if you don't Xwatch what you are doing.} For example:@refill X X@example Xfunction changeit (array, ind, nvalue) @{ X array[ind] = nvalue X@} X XBEGIN @{ X a[1] = 1 ; a[2] = 2 ; a[3] = 3 X changeit(a, 2, "two") X printf "a[1] = %s, a[2] = %s, a[3] = %s\n", a[1], a[2], a[3] X @} X@end example X X@noindent Xprints @samp{a[1] = 1, a[2] = two, a[3] = 3}, because calling X@code{changeit} stores @code{"two"} in the second element of @code{a}. X X@node Return Statement, , Function Caveats, User-defined X@section The @code{return} Statement X@cindex @code{return} statement X XThe body of a user-defined function can contain a @code{return} statement. XThis statement returns control to the rest of the @code{awk} program. It Xcan also be used to return a value for use in the rest of the @code{awk} Xprogram. It looks like this:@refill X X@example Xreturn @var{expression} X@end example X XThe @var{expression} part is optional. If it is omitted, then the returned Xvalue is undefined and, therefore, unpredictable. X XA @code{return} statement with no value expression is assumed at the end of Xevery function definition. So if control reaches the end of the function Xdefinition, then the function returns an unpredictable value. X XHere is an example of a user-defined function that returns a value Xfor the largest number among the elements of an array:@refill X X@example Xfunction maxelt (vec, i, ret) @{ X for (i in vec) @{ X if (ret == "" || vec[i] > ret) X ret = vec[i] X @} X return ret X@} X@end example X X@noindent XYou call @code{maxelt} with one argument, an array name. The local Xvariables @code{i} and @code{ret} are not intended to be arguments; Xwhile there is nothing to stop you from passing two or three arguments Xto @code{maxelt}, the results would be strange. The extra space before X@code{i} in the function parameter list is to indicate that @code{i} and X@code{ret} are not supposed to be arguments. This is a convention which Xyou should follow when you define functions. X XHere is a program that uses our @code{maxelt} function. It loads an Xarray, calls @code{maxelt}, and then reports the maximum number in that Xarray:@refill X X@example Xawk ' Xfunction maxelt (vec, i, ret) @{ X for (i in vec) @{ X if (ret == "" || vec[i] > ret) X ret = vec[i] X @} X return ret X@} X X# Load all fields of each record into nums. X@{ X for(i = 1; i <= NF; i++) X nums[NR, i] = $i X@} X XEND @{ X print maxelt(nums) X@}' X@end example X XGiven the following input: X X@example X 1 5 23 8 16 X44 3 5 2 8 26 X256 291 1396 2962 100 X-6 467 998 1101 X99385 11 0 225 X@end example X X@noindent Xour program tells us (predictably) that: X X@example X99385 X@end example X X@noindent Xis the largest number in our array. X X@node Built-in Variables, Command Line, User-defined, Top X@chapter Built-in Variables X@cindex built-in variables X XMost @code{awk} variables are available for you to use for your own Xpurposes; they never change except when your program assigns them, and Xnever affect anything except when your program examines them. X XA few variables have special built-in meanings. Some of them @code{awk} Xexamines automatically, so that they enable you to tell @code{awk} how Xto do certain things. Others are set automatically by @code{awk}, so Xthat they carry information from the internal workings of @code{awk} to Xyour program. X XThis chapter documents all the built-in variables of @code{gawk}. Most Xof them are also documented in the chapters where their areas of Xactivity are described. X X@menu X* User-modified:: Built-in variables that you change to control @code{awk}. X X* Auto-set:: Built-in variables where @code{awk} gives you information. X@end menu X X@node User-modified, Auto-set, Built-in Variables, Built-in Variables X@section Built-in Variables That Control @code{awk} X@cindex built-in variables, user modifiable X XThis is a list of the variables which you can change to control how X@code{awk} does certain things. X X@table @code X@c it's unadvisable to have multiple index entries for the same name X@c since in Info there is no way to distinguish the two. X@c @vindex FS X@item FS X@code{FS} is the input field separator (@pxref{Field Separators}). XThe value is a single-character string or a multi-character regular Xexpression that matches the separations between fields in an input Xrecord. X XThe default value is @w{@code{" "}}, a string consisting of a single Xspace. As a special exception, this value actually means that any Xsequence of spaces and tabs is a single separator. It also causes Xspaces and tabs at the beginning or end of a line to be ignored. X XYou can set the value of @code{FS} on the command line using the X@samp{-F} option: X X@example Xawk -F, '@var{program}' @var{input-files} X@end example X X@item IGNORECASE X@c @vindex IGNORECASE XIf @code{IGNORECASE} is nonzero, then @emph{all} regular expression Xmatching is done in a case-independent fashion. In particular, regexp Xmatching with @samp{~} and @samp{!~}, and the @code{gsub} @code{index}, X@code{match}, @code{split} and @code{sub} functions all ignore case when Xdoing their particular regexp operations. @strong{Note:} since field Xsplitting with the value of the @code{FS} variable is also a regular Xexpression operation, that too is done with case ignored. X@xref{Case-sensitivity}. X XIf @code{gawk} is in compatibility mode (@pxref{Command Line}), then X@code{IGNORECASE} has no special meaning, and regexp operations are Xalways case-sensitive.@refill X X@item OFMT X@c @vindex OFMT XThis string is used by @code{awk} to control conversion of numbers to Xstrings (@pxref{Conversion}). It works by being passed, in effect, as Xthe first argument to the @code{sprintf} function. Its default value Xis @code{"%.6g"}.@refill X X@item OFS X@c @vindex OFS XThis is the output field separator (@pxref{Output Separators}). It is Xoutput between the fields output by a @code{print} statement. Its Xdefault value is @w{@code{" "}}, a string consisting of a single space. X X@item ORS X@c @vindex ORS XThis is the output record separator. It is output at the end of every X@code{print} statement. Its default value is a string containing a Xsingle newline character, which could be written as @code{"\n"}. X(@xref{Output Separators}).@refill X X@item RS X@c @vindex RS XThis is @code{awk}'s record separator. Its default value is a string Xcontaining a single newline character, which means that an input record Xconsists of a single line of text. (@xref{Records}.)@refill X X@item SUBSEP X@c @vindex SUBSEP X@code{SUBSEP} is a subscript separator. It has the default value of X@code{"\034"}, and is used to separate the parts of the name of a Xmulti-dimensional array. Thus, if you access @code{foo[12,3]}, it Xreally accesses @code{foo["12\0343"]}. (@xref{Multi-dimensional}).@refill X@end table X X@node Auto-set, , User-modified, Built-in Variables X@section Built-in Variables That Convey Information to You X XThis is a list of the variables that are set automatically by @code{awk} Xon certain occasions so as to provide information for your program. X X@table @code X@item ARGC X@itemx ARGV X@c @vindex ARGC X@c @vindex ARGV XThe command-line arguments available to @code{awk} are stored in an Xarray called @code{ARGV}. @code{ARGC} is the number of command-line Xarguments present. @code{ARGV} is indexed from zero to @w{@code{ARGC - 1}}. X@xref{Command Line}. For example: X X@example Xawk '@{ print ARGV[$1] @}' inventory-shipped BBS-list X@end example X X@noindent XIn this example, @code{ARGV[0]} contains @code{"awk"}, @code{ARGV[1]} Xcontains @code{"inventory-shipped"}, and @code{ARGV[2]} contains X@code{"BBS-list"}. The value of @code{ARGC} is 3, one more than the Xindex of the last element in @code{ARGV} since the elements are numbered Xfrom zero.@refill X XNotice that the @code{awk} program is not entered in @code{ARGV}. The Xother special command line options, with their arguments, are also not Xentered. But variable assignments on the command line @emph{are} Xtreated as arguments, and do show up in the @code{ARGV} array. X XYour program can alter @code{ARGC} and the elements of @code{ARGV}. XEach time @code{awk} reaches the end of an input file, it uses the next Xelement of @code{ARGV} as the name of the next input file. By storing a Xdifferent string there, your program can change which files are read. XYou can use @code{"-"} to represent the standard input. By storing Xadditional elements and incrementing @code{ARGC} you can cause Xadditional files to be read. X XIf you decrease the value of @code{ARGC}, that eliminates input files Xfrom the end of the list. By recording the old value of @code{ARGC} Xelsewhere, your program can treat the eliminated arguments as Xsomething other than file names. X XTo eliminate a file from the middle of the list, store the null string X(@code{""}) into @code{ARGV} in place of the file's name. As a Xspecial feature, @code{awk} ignores file names that have been Xreplaced with the null string. X X@item ENVIRON X@vindex ENVIRON XThis is an array that contains the values of the environment. The array Xindices are the environment variable names; the values are the values of Xthe particular environment variables. For example, X@code{ENVIRON["HOME"]} might be @file{/u/close}. Changing this array Xdoes not affect the environment passed on to any programs that X@code{awk} may spawn via redirection or the @code{system} function. X(In a future version of @code{gawk}, it may do so.) X XSome operating systems may not have environment variables. XOn such systems, the array @code{ENVIRON} is empty. X X@item FILENAME X@c @vindex FILENAME XThis is the name of the file that @code{awk} is currently reading. XIf @code{awk} is reading from the standard input (in other words, Xthere are no files listed on the command line), X@code{FILENAME} is set to @code{"-"}. X@code{FILENAME} is changed each time a new file is read (@pxref{Reading XFiles}).@refill X X@item FNR X@c @vindex FNR X@code{FNR} is the current record number in the current file. @code{FNR} is Xincremented each time a new record is read (@pxref{Getline}). XIt is reinitialized to 0 each time a new input file is started. X X@item NF X@c @vindex NF X@code{NF} is the number of fields in the current input record. X@code{NF} is set each time a new record is read, when a new field is Xcreated, or when @code{$0} changes (@pxref{Fields}).@refill X X@item NR X@c @vindex NR XThis is the number of input records @code{awk} has processed since Xthe beginning of the program's execution. (@pxref{Records}). X@code{NR} is set each time a new record is read.@refill X X@item RLENGTH X@c @vindex RLENGTH X@code{RLENGTH} is the length of the substring matched by the X@code{match} function (@pxref{String Functions}). @code{RLENGTH} is set Xby invoking the @code{match} function. Its value is the length of the Xmatched string, or @minus{}1 if no match was found.@refill X X@item RSTART X@c @vindex RSTART X@code{RSTART} is the start-index of the substring matched by the X@code{match} function (@pxref{String Functions}). @code{RSTART} is set Xby invoking the @code{match} function. Its value is the position of the Xstring where the matched substring starts, or 0 if no match was Xfound.@refill X@end table X X@node Command Line, Language History, Built-in Variables, Top X@c node-name, next, previous, up X@chapter Invocation of @code{awk} X@cindex command line X@cindex invocation of @code{gawk} X@cindex arguments, command line X@cindex options, command line X XThere are two ways to run @code{awk}: with an explicit program, or with Xone or more program files. Here are templates for both of them; items Xenclosed in @samp{@r{[}@dots{}@r{]}} in these templates are optional. X X@example Xawk @r{[@code{-F@var{fs}}] [@code{-v @var{var}=@var{val}}] [@code{-V}] [@code{-C}] [@code{-c}] [@code{-a}] [@code{-e}] [@code{--}]} '@var{program}' @var{file} @dots{} Xawk @r{[@code{-F@var{fs}}] @code{-f @var{source-file}} [@code{-f @var{source-file} @dots{}}] [@code{-v @var{var}=@var{val}}] [@code{-V}] [@code{-C}] [@code{-c}] [@code{-a}] [@code{-e}] [@code{--}]} @var{file} @dots{} X@end example X X@menu X* Options:: Command line options and their meanings. X* Other Arguments:: Input file names and variable assignments. X* AWKPATH Variable:: Searching directories for @code{awk} programs. X@end menu X X@node Options, Other Arguments, Command Line, Command Line X@section Command Line Options X XOptions begin with a minus sign, and consist of a single character. XThe options and their meanings are as follows: X X@table @code X@item -F@var{fs} XSets the @code{FS} variable to @var{fs} (@pxref{Field Separators}). X X@item -f @var{source-file} XIndicates that the @code{awk} program is to be found in @var{source-file} Xinstead of in the first non-option argument. X X@item -v @var{var}=@var{val} X@cindex @samp{-v} option XSets the variable @var{var} to the value @var{val} @emph{before} Xexecution of the program begins. Such variable values are available Xinside the @code{BEGIN} rule (see below for a fuller explanation). X XThe @samp{-v} option only has room to set one variable, but you can use Xit more than once, setting another variable each time, like this: X@samp{@w{-v foo=1} @w{-v bar=2}}. X X@item -a XSpecifies use of traditional @code{awk} syntax for regular expressions. XThis means that @samp{\} can be used to quote any regular expression Xoperators inside of square brackets, just as it can be outside of them. XThis mode is currently the default; the @samp{-a} option is useful in Xshell scripts so that they will not break if the default is changed. X@xref{Regexp Operators}. X X@item -e XSpecifies use of @code{egrep} syntax for regular expressions. This Xmeans that @samp{\} does not serve as a quoting character inside of Xsquare brackets; ideosyncratic techniques are needed to include various Xspecial characters within them. This mode may become the default at Xsome time in the future. @xref{Regexp Operators}. X X@item -c X@cindex @samp{-c} option XSpecifies @dfn{compatibility mode}, in which the GNU extensions in X@code{gawk} are disabled, so that @code{gawk} behaves just like Unix X@code{awk}. These extensions are noted below, where their usage is Xexplained. @xref{Compatibility Mode}. X X@item -V X@cindex @samp{-V} option XPrints version information for this particular copy of @code{gawk}. XThis is so you can determine if your copy of @code{gawk} is up to date Xwith respect to whatever the Free Software Foundation is currently Xdistributing. This option may disappear in a future version of @code{gawk}. X X@item -C X@cindex @samp{-C} option XPrints the short version of the General Public License. XThis option may disappear in a future version of @code{gawk}. X X@item -- XSignals the end of the command line options. The following arguments Xare not treated as options even if they begin with @samp{-}. This Xinterpretation of @samp{--} follows the POSIX argument parsing Xconventions. X XThis is useful if you have file names that start with @samp{-}, Xor in shell scripts, if you have file names that will be specified Xby the user and that might start with @samp{-}. X@end table X XAny other options are flagged as invalid with a warning message, but Xare otherwise ignored. X XIn compatibility mode, as a special case, if the value of @var{fs} supplied Xto the @samp{-F} option is @samp{t}, then @code{FS} is set to the tab Xcharacter (@code{"\t"}). Also, the @samp{-C} and @samp{-V} options Xare not recognized.@refill X XIf the @samp{-f} option is @emph{not} used, then the first non-option Xcommand line argument is expected to be the program text. X XThe @samp{-f} option may be used more than once on the command line. XThen @code{awk} reads its program source from all of the named files, as Xif they had been concatenated together into one big file. This is Xuseful for creating libraries of @code{awk} functions. Useful functions Xcan be written once, and then retrieved from a standard place, instead Xof having to be included into each individual program. You can still Xtype in a program at the terminal and use library functions, by specifying X@samp{-f /dev/tty}. @code{awk} will read a file from the terminal Xto use as part of the @code{awk} program. After typing your program, Xtype @kbd{Control-d} (the end-of-file character) to terminate it. X X@node Other Arguments, AWKPATH Variable, Options, Command Line X@section Other Command Line Arguments X XAny additional arguments on the command line are normally treated as Xinput files to be processed in the order specified. However, an Xargument that has the form @code{@var{var}=@var{value}}, means to assign Xthe value @var{value} to the variable @var{var}---it does not specify a Xfile at all. X X@vindex ARGV XAll these arguments are made available to your @code{awk} program in the X@code{ARGV} array (@pxref{Built-in Variables}). Command line options Xand the program text (if present) are omitted from the @code{ARGV} Xarray. All other arguments, including variable assignments, are Xincluded. X XThe distinction between file name arguments and variable-assignment Xarguments is made when @code{awk} is about to open the next input file. XAt that point in execution, it checks the ``file name'' to see whether Xit is really a variable assignment; if so, @code{awk} sets the variable Xinstead of reading a file. X XTherefore, the variables actually receive the specified values after all Xpreviously specified files have been read. In particular, the values of Xvariables assigned in this fashion are @emph{not} available inside a X@code{BEGIN} rule (@pxref{BEGIN/END}), since such rules are run before X@code{awk} begins scanning the argument list.@refill X XIn some earlier implementations of @code{awk}, when a variable assignment Xoccurred before any file names, the assignment would happen @emph{before} END_OF_FILE if test 49666 -ne `wc -c <'./gawk.texinfo.05'`; then echo shar: \"'./gawk.texinfo.05'\" unpacked with wrong size! fi # end of './gawk.texinfo.05' fi if test -f './patchlevel.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./patchlevel.h'\" else echo shar: Extracting \"'./patchlevel.h'\" \(21 characters\) sed "s/^X//" >'./patchlevel.h' <<'END_OF_FILE' X#define PATCHLEVEL 1 END_OF_FILE if test 21 -ne `wc -c <'./patchlevel.h'`; then echo shar: \"'./patchlevel.h'\" unpacked with wrong size! fi # end of './patchlevel.h' fi if test -f './pc.d/popen.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./pc.d/popen.c'\" else echo shar: Extracting \"'./pc.d/popen.c'\" \(2046 characters\) sed "s/^X//" >'./pc.d/popen.c' <<'END_OF_FILE' X#include X#include "popen.h" X#include X#include X#include X Xstatic char template[] = "piXXXXXX"; Xtypedef enum { unopened = 0, reading, writing } pipemode; Xstatic Xstruct { X char *command; X char *name; X pipemode pmode; X} pipes[_NFILE]; X XFILE * Xpopen( char *command, char *mode ) { X FILE *current; X char *name; X int cur; X pipemode curmode; X /* X ** decide on mode. X */ X if(strcmp(mode,"r") == 0) X curmode = reading; X else if(strcmp(mode,"w") == 0) X curmode = writing; X else X return NULL; X /* X ** get a name to use. X */ X if((name = tempnam(".","pip"))==NULL) X return NULL; X /* X ** If we're reading, just call system to get a file filled with X ** output. X */ X if(curmode == reading) { X char cmd[256]; X sprintf(cmd,"%s > %s",command,name); X system(cmd); X if((current = fopen(name,"r")) == NULL) X return NULL; X } else { X if((current = fopen(name,"w")) == NULL) X return NULL; X } X cur = fileno(current); X pipes[cur].name = name; X pipes[cur].pmode = curmode; X pipes[cur].command = strdup(command); X return current; X} X Xint Xpclose( FILE * current) { X int cur = fileno(current),rval; X /* X ** check for an open file. X */ X if(pipes[cur].pmode == unopened) X return -1; X if(pipes[cur].pmode == reading) { X /* X ** input pipes are just files we're done with. X */ X rval = fclose(current); X unlink(pipes[cur].name); X } else { X /* X ** output pipes are temporary files we have X ** to cram down the throats of programs. X */ X char command[256]; X fclose(current); X sprintf(command,"%s < %s",pipes[cur].command,pipes[cur].name); X rval = system(command); X unlink(pipes[cur].name); X } X /* X ** clean up current pipe. X */ X pipes[cur].pmode = unopened; X free(pipes[cur].name); X free(pipes[cur].command); X return rval; X} X END_OF_FILE if test 2046 -ne `wc -c <'./pc.d/popen.c'`; then echo shar: \"'./pc.d/popen.c'\" unpacked with wrong size! fi # end of './pc.d/popen.c' fi echo shar: End of archive 4 \(of 16\). cp /dev/null ark4isdone 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...