home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / pc / source / mawk.lzh / mawk.1 < prev    next >
Text File  |  1991-05-19  |  62KB  |  2,288 lines

  1.  
  2. # This is a shell archive.  Remove anything before this line,
  3. # then unpack it by saving it in a file and typing "sh file".
  4. #
  5. # Wrapped by ssc-bee!brennan on Fri May 10 18:11:41 PDT 1991
  6. # Contents:  mawk0.97/ mawk0.97/rexp/ mawk0.97/test/ mawk0.97/examples/
  7. #    mawk0.97/msdos/ mawk0.97/packing.list mawk0.97/README
  8. #    mawk0.97/LIMITATIONS mawk0.97/Makefile mawk0.97/mawk.manual
  9. #    mawk0.97/array.c mawk0.97/bi_funct.c mawk0.97/bi_funct.h
  10. #    mawk0.97/bi_vars.c mawk0.97/bi_vars.h mawk0.97/cast.c mawk0.97/code.c
  11. #    mawk0.97/code.h mawk0.97/da.c mawk0.97/error.c mawk0.97/execute.c
  12. #    mawk0.97/fcall.c mawk0.97/field.c mawk0.97/field.h mawk0.97/files.c
  13. #    mawk0.97/files.h mawk0.97/fin.c mawk0.97/fin.h mawk0.97/hash.c
  14. #    mawk0.97/init.c mawk0.97/init.h mawk0.97/jmp.c mawk0.97/jmp.h
  15. #    mawk0.97/kw.c mawk0.97/machine.h mawk0.97/main.c mawk0.97/makescan.c
  16. #    mawk0.97/matherr.c mawk0.97/mawk.h mawk0.97/memory.c mawk0.97/memory.h
  17. #    mawk0.97/parse.y mawk0.97/print.c mawk0.97/re_cmpl.c mawk0.97/regexp.h
  18. #    mawk0.97/repl.h mawk0.97/scan.c mawk0.97/scan.h mawk0.97/scancode.c
  19. #    mawk0.97/sizes.h mawk0.97/split.c mawk0.97/symtype.h mawk0.97/types.h
  20. #    mawk0.97/zmalloc.c mawk0.97/zmalloc.h mawk0.97/rexp/Makefile
  21. #    mawk0.97/rexp/rexp.c mawk0.97/rexp/rexp.h mawk0.97/rexp/rexp0.c
  22. #    mawk0.97/rexp/rexp1.c mawk0.97/rexp/rexp2.c mawk0.97/rexp/rexp3.c
  23. #    mawk0.97/rexp/rexpdb.c mawk0.97/test/README mawk0.97/test/benchmarks
  24. #    mawk0.97/test/cat.awk mawk0.97/test/concat.awk mawk0.97/test/fields.awk
  25. #    mawk0.97/test/loops.awk mawk0.97/test/newton.awk
  26. #    mawk0.97/test/primes.awk mawk0.97/test/qsort.awk mawk0.97/test/reg0.awk
  27. #    mawk0.97/test/reg1.awk mawk0.97/test/reg2.awk mawk0.97/test/sample
  28. #    mawk0.97/test/squeeze.awk mawk0.97/test/test.sh mawk0.97/test/wc.awk
  29. #    mawk0.97/test/wfrq.awk mawk0.97/test/wfrq0.awk mawk0.97/test/words.awk
  30. #    mawk0.97/test/words0.awk mawk0.97/examples/decl.awk
  31. #    mawk0.97/examples/deps.awk mawk0.97/examples/gdecl.awk
  32. #    mawk0.97/examples/nocomment.awk mawk0.97/msdos/INSTALL
  33. #    mawk0.97/msdos/makefile mawk0.97/msdos/mklib.bat
  34. #    mawk0.97/msdos/rand48.asm mawk0.97/msdos/rand48.h
  35. #    mawk0.97/msdos/rand48_0.c mawk0.97/msdos/reargv.c
  36.  
  37. echo mkdir - mawk0.97
  38. mkdir mawk0.97
  39. chmod u=rwx,g=rx,o=rx mawk0.97
  40.  
  41. echo x - mawk0.97/packing.list
  42. sed 's/^@//' > "mawk0.97/packing.list" <<'@//E*O*F mawk0.97/packing.list//'
  43.  
  44. ################################################
  45. # These files form the mawk distribution
  46. #
  47. # Mawk is an implementation of the AWK Programming Language as
  48. # defined and described in Aho, Kernighan and Weinberger, The
  49. # Awk Programming Language, Addison-Wesley, 1988.
  50. #
  51. ################################################
  52. # Source code written by Michael D. Brennan
  53. # Copyright (C) 1991 , Michael D. Brennan
  54. ################################################
  55. packing.list        this file
  56. README            how to get started
  57. LIMITATIONS        restrictions on use
  58. Makefile        mawk makefile
  59. mawk.manual        mock manual
  60. ######################
  61. array.c            source files
  62. bi_funct.c
  63. bi_funct.h
  64. bi_vars.c
  65. bi_vars.h
  66. cast.c
  67. code.c
  68. code.h
  69. da.c
  70. error.c
  71. execute.c
  72. fcall.c
  73. field.c
  74. field.h
  75. files.c
  76. files.h
  77. fin.c
  78. fin.h
  79. hash.c
  80. init.c
  81. init.h
  82. jmp.c
  83. jmp.h
  84. kw.c
  85. machine.h
  86. main.c
  87. makescan.c
  88. matherr.c
  89. mawk.h
  90. memory.c
  91. memory.h
  92. parse.y
  93. print.c
  94. re_cmpl.c
  95. regexp.h
  96. repl.h
  97. scan.c
  98. scan.h
  99. scancode.c
  100. sizes.h
  101. split.c
  102. symtype.h
  103. types.h
  104. zmalloc.c
  105. zmalloc.h
  106. ########################
  107. # directory:  rexp
  108. rexp/Makefile        makefile for regexp.a
  109. rexp/rexp.c        source for regular matching library
  110. rexp/rexp.h
  111. rexp/rexp0.c
  112. rexp/rexp1.c
  113. rexp/rexp2.c
  114. rexp/rexp3.c
  115. rexp/rexpdb.c
  116. #######################
  117. # directory:  test      benchmarking directory
  118. test/README
  119. test/benchmarks
  120. test/cat.awk
  121. test/concat.awk
  122. test/fields.awk
  123. test/loops.awk
  124. test/newton.awk
  125. test/primes.awk
  126. test/qsort.awk
  127. test/reg0.awk
  128. test/reg1.awk
  129. test/reg2.awk
  130. test/sample            sample input file for test.sh
  131. test/squeeze.awk
  132. test/test.sh
  133. test/wc.awk
  134. test/wfrq.awk
  135. test/wfrq0.awk
  136. test/words.awk
  137. test/words0.awk
  138. ######################
  139. # directory:  examples       useful awk programs
  140. examples/decl.awk
  141. examples/deps.awk
  142. examples/gdecl.awk
  143. examples/nocomment.awk
  144. ######################
  145. # directory  msdos
  146. msdos/INSTALL
  147. msdos/makefile
  148. msdos/mklib.bat
  149. msdos/rand48.asm
  150. msdos/rand48.h
  151. msdos/rand48_0.c
  152. msdos/reargv.c
  153. @//E*O*F mawk0.97/packing.list//
  154. chmod u=rw,g=r,o=r mawk0.97/packing.list
  155.  
  156. echo x - mawk0.97/README
  157. sed 's/^@//' > "mawk0.97/README" <<'@//E*O*F mawk0.97/README//'
  158.  
  159.  
  160. to build mawk:
  161.  
  162. make sure  there is an appropriate description of
  163. your system in machine.h
  164.  
  165. set CFLAGS in the Makefile to pick the appropriate blob
  166. in machine.h
  167.  
  168. run make
  169.  
  170.  
  171.  
  172. PS:
  173. I expected to have bcopy() <-> memcpy()
  174. hassles on 4.3BSD, but didn't
  175. Is this right? or did someone add memcpy(), strchr() etc
  176.    to that machine?
  177.    If 4.3BSD in machine.h is wrong, let me know at
  178.    brennan@bcsaic.boeing.com
  179. @//E*O*F mawk0.97/README//
  180. chmod u=r,g=r,o=r mawk0.97/README
  181.  
  182. echo x - mawk0.97/LIMITATIONS
  183. sed 's/^@//' > "mawk0.97/LIMITATIONS" <<'@//E*O*F mawk0.97/LIMITATIONS//'
  184.  
  185.  
  186. Mawk is an implementation of the AWK Programming Language
  187. as defined in Aho, Kernighan and Weinberger, The AWK 
  188. Programming Language, Addison-Wesley, 1988.
  189.  
  190. The source code is original work, in the sense that its
  191. development relied only on the specification of the AWK
  192. language in the book above.  Most of the algorithms and
  193. data structures used in this code are not original --
  194. but based on knowledge acquired from numerous sources.
  195. Originality is claimed only for the aggregate work.  Any
  196. ideas or techniques in this code can be freely copied and
  197. used in other work.  
  198.  
  199. The source code may be modified provided the copyright
  200. notices remain intact, and modifications are unambiguously
  201. distinct from the original.  I want to retain credit for my
  202. work and do not want credit for yours.
  203.  
  204. Redistribution in any form is permitted provided the built-in
  205. variable VERSION is retained, and its initial value only
  206. modified by appending extra lines.
  207.  
  208.     For example, if you modify a mawk with VERSION
  209.  
  210.     mawk x.xx Mon Year, Copyright (C) Michael D. Brennan
  211.  
  212.     then add an extra line to VERSION without modifying the
  213.     first line.
  214.  
  215.     mawk x.xx Mon Year, Copyright (C) Michael D. Brennan
  216.     mod y.yy  Mon Year, your name
  217.  
  218.  
  219. Michael D. Brennan
  220. 16 Apr 1991
  221.  
  222. @//E*O*F mawk0.97/LIMITATIONS//
  223. chmod u=r,g=r,o=r mawk0.97/LIMITATIONS
  224.  
  225. echo x - mawk0.97/Makefile
  226. sed 's/^@//' > "mawk0.97/Makefile" <<'@//E*O*F mawk0.97/Makefile//'
  227.  
  228. # ###################################################
  229. # This is a makefile for mawk,
  230. # an implementation of The AWK Programmin Language, 1988.
  231.  
  232. SHELL=/bin/sh
  233.  
  234. ####################################
  235. # CFLAGS needs to match a define in machine.h
  236. # unless machine.h uses a built-in compiler flag
  237. #
  238.  
  239. CFLAGS = -O -DULTRIX
  240. #CFLAGS =  -O -DBSD43
  241. YACC=yacc -dv
  242. #YACC=bison -dvy
  243.  
  244. #######################################
  245.  
  246. O=parse.o scan.o memory.o main.o hash.o execute.o code.o\
  247.   da.o error.o init.o bi_vars.o cast.o print.o bi_funct.o\
  248.   kw.o jmp.o array.o field.o  split.o re_cmpl.o zmalloc.o\
  249.   fin.o files.o  scancode.o matherr.o  fcall.o
  250.  
  251. REXP_C=rexp/rexp.c rexp/rexp0.c rexp/rexp1.c rexp/rexp2.c\
  252.     rexp/rexp3.c rexp/rexpdb.c
  253.  
  254.  
  255.  
  256. mawk : $(O)  rexp/regexp.a
  257.     cc $(CFLAGS) -o mawk $(O) -lm rexp/regexp.a
  258.  
  259. rexp/regexp.a :  $(REXP_C)
  260.     cd  rexp ; make
  261.  
  262.  
  263. parse.c  : parse.y
  264.     @echo  expect 3 shift/reduce conflicts
  265.     $(YACC)  parse.y
  266.     mv y.tab.c parse.c
  267.     -if cmp -s y.tab.h parse.h ;\
  268.        then rm y.tab.h ;\
  269.        else mv y.tab.h parse.h ; fi
  270.  
  271. scancode.c :  makescan.c  scan.h
  272.     cc -o makescan.exe  makescan.c
  273.     makescan.exe > scancode.c
  274.     rm makescan.exe
  275.  
  276.  
  277. array.o : bi_vars.h sizes.h zmalloc.h memory.h types.h machine.h mawk.h symtype.h
  278. bi_funct.o : fin.h bi_vars.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h repl.h files.h bi_funct.h mawk.h symtype.h init.h
  279. bi_vars.o : bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h mawk.h symtype.h init.h
  280. cast.o : parse.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h repl.h mawk.h symtype.h
  281. code.o : sizes.h memory.h zmalloc.h types.h machine.h code.h mawk.h init.h
  282. da.o : sizes.h memory.h zmalloc.h types.h machine.h field.h repl.h code.h bi_funct.h mawk.h symtype.h
  283. error.o : parse.h bi_vars.h sizes.h types.h machine.h scan.h mawk.h symtype.h
  284. execute.o : sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h code.h repl.h bi_funct.h mawk.h symtype.h
  285. fcall.o : sizes.h memory.h zmalloc.h types.h machine.h code.h mawk.h symtype.h
  286. field.o : parse.h bi_vars.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h scan.h repl.h mawk.h symtype.h init.h
  287. files.o : fin.h sizes.h memory.h zmalloc.h types.h machine.h files.h mawk.h
  288. fin.o : parse.h fin.h bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h mawk.h symtype.h
  289. hash.o : sizes.h memory.h zmalloc.h types.h machine.h mawk.h symtype.h
  290. init.o : bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h code.h mawk.h symtype.h init.h
  291. jmp.o : sizes.h memory.h zmalloc.h types.h machine.h code.h jmp.h mawk.h init.h
  292. kw.o : parse.h sizes.h types.h machine.h mawk.h symtype.h init.h
  293. main.o : fin.h bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h code.h files.h mawk.h init.h
  294. makescan.o : parse.h scan.h symtype.h
  295. matherr.o : sizes.h types.h machine.h mawk.h
  296. memory.o : sizes.h memory.h zmalloc.h types.h machine.h mawk.h
  297. parse.o : bi_vars.h sizes.h memory.h zmalloc.h types.h machine.h field.h code.h files.h bi_funct.h mawk.h jmp.h symtype.h
  298. print.o : bi_vars.h parse.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h files.h bi_funct.h mawk.h symtype.h
  299. re_cmpl.o : parse.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h scan.h repl.h mawk.h symtype.h
  300. scan.o : parse.h fin.h sizes.h memory.h zmalloc.h types.h machine.h field.h scan.h repl.h files.h mawk.h symtype.h init.h
  301. split.o : bi_vars.h parse.h sizes.h memory.h zmalloc.h regexp.h types.h machine.h field.h scan.h bi_funct.h mawk.h symtype.h
  302. zmalloc.o : sizes.h zmalloc.h types.h machine.h mawk.h
  303. @//E*O*F mawk0.97/Makefile//
  304. chmod u=r,g=r,o=r mawk0.97/Makefile
  305.  
  306. echo x - mawk0.97/mawk.manual
  307. sed 's/^@//' > "mawk0.97/mawk.manual" <<'@//E*O*F mawk0.97/mawk.manual//'
  308.  
  309.                               Mawk Manual 
  310.  
  311. Mawk implements the awk language as defined in Aho, Kernighan and 
  312. Weinberger, The AWK Programming Language, Addison-Wesley, 1988, ISBN 
  313. 0-201-07981-X, hereafter called the AWK book.  Chapter 2 serves as a 
  314. reference to the language and the rest (8 total chapters) provides a 
  315. wide range of examples and applications.  This book is must reading to 
  316. understand the versatility of the language.  
  317.  
  318. The 1988 version of the language is sometimes called new awk as opposed 
  319. to the 1977 version (awk or old awk.) Virtially every Unix system has 
  320. old awk, somewhere in the documentation will be an (old) awk tutorial 
  321. (probably in support tools).  If you use (old) awk, the transition to 
  322. new awk is easy.  The language has been extended and ambiguous points 
  323. clarified, but old awk programs still run under new awk.  
  324.  
  325. This manual assumes you know (old) awk, and hence concentrates on the 
  326. new features of awk.  Feature xxx is new means xxx was added to the 1988
  327. version.  
  328.  
  329. Experienced new awk users should read sections 9 and 12, and skim 
  330. sections 7 and 8.  
  331.  
  332. 1. Command line
  333.  
  334.     mawk [-Fs] 'program'  optional_list_of_files
  335.     mawk [-Fs] -f program_file  optional_list_of_files
  336.  
  337. 2. Program blocks
  338.  
  339.     Program blocks are of the form:
  340.  
  341.     pattern { action }
  342.  
  343.     pattern can be:
  344.  
  345.     regular_expression
  346.     expression
  347.     ( pattern )
  348.     ! pattern
  349.     pattern || pattern
  350.     pattern && pattern
  351.  
  352.     pattern , pattern  (range pattern)
  353.     BEGIN
  354.     END
  355.  
  356. Range, BEGIN and END patterns cannot be combined to form new patterns.  
  357. BEGIN and END patterns require an action; otherwise, if action is 
  358. omitted it is implicitly { print }.  
  359.  
  360.     NR==2    {  print }  # prints line number 2
  361.     NR==2             # also prints line number 2
  362.  
  363. If pattern is omitted then action is always applied.
  364.  
  365.     { print $NF }
  366.  
  367. prints the last field of every record.
  368.  
  369. 3. Statement format and loops
  370.  
  371. Statements are terminated by newlines, semi-colons or both.  Groups of 
  372. statements are blocked via { ...  } as in C.  The last statement in a 
  373. block doesn't need a terminator.  Blank lines have no meaning; an empty 
  374. statement is terminated with a semi-colon.  Long statements can be 
  375. continued with a backslash, \.  A statement can be broken without a 
  376. backslash after a comma, left brace, &&, ||, do, else, the right 
  377. parenthesis of an if, while or for statement, and the right parenthesis 
  378. of a function definition.  
  379.  
  380. Loops are for(){}, while(){} and do{}while() as in C.  
  381.  
  382. 4. Expression syntax
  383.  
  384. The expression syntax and grouping of the language is similar to C.  
  385. Primary expressions are numeric constants, string constants, variables, 
  386. arrays and functions.  Complex expressions are composed with the 
  387. following operators in order of increasing precedence.  
  388.  
  389.     assignment: = += -+ *= /= ^=
  390.     conditional:  ? :
  391.     logical or:   ||
  392.     logical and:  &&
  393.     array membership :   in
  394.     matching :   ~   !~
  395.     relational :  <  >   <=  >=  ==  !=
  396.     concatenation:   (no explicit operator)
  397.     add ops:  +  -
  398.     mul ops:  *  /  % 
  399.     unary  :  +  -
  400.     logical not :  !
  401.     exponentiation:  ^
  402.     inc and dec:  ++ -- (both post and pre)
  403.     field:  $
  404.  
  405. 5. Builtin variables.
  406.  
  407. The following variables are built-in and initialized before program 
  408. execution.  
  409.  
  410.     ARGC    number of command line arguments
  411.     ARGV    array of command line arguments, 0..ARGC-1
  412.     FILENAME    name of the current input file
  413.     FNR         current record number in the current input file
  414.     FS        splits records into fields as a regular expression
  415.     NF        number of fields in the current record, i.e., $0
  416.     NR        current record number in the total input stream
  417.     OFMT    format for printing numbers; initially = "%.6g"
  418.     OFS        inserted between fields on output, initially = " "
  419.     ORS        terminates each record on output, initially = "\n"
  420.     RLENGTH     length of the last call to the built-in function, match()
  421.     RS        input record separator, initially = " "
  422.     RSTART    index of the last call to match()
  423.     SUBSEP    used to build multiple array subscripts, initially = "\034"
  424.     VERSION     Mawk version, unique to mawk.
  425.  
  426. ARGC, ARGV, FNR, RLENGTH, RSTART and SUBSEP are new.  
  427.  
  428. The current input record is stored in the field, $0.  The fields of $0 
  429. determined by splitting with RS are stored in $1, $2, ..., $NF.  
  430.  
  431.  
  432. 6. Built-in Functions
  433.  
  434. String functions
  435.  
  436.     index(s,t)
  437.     length(s), length
  438.     split(s, A, r), split(s, A)
  439.     substr(s,i,n) , substr(s,i)
  440.     sprintf(format, expr_list)
  441.  
  442.     match(s,r)        returns the index where string s matches
  443.                 regular expression r or 0 if no match. As
  444.             a side effect, sets RSTART and RLENGTH.
  445.  
  446.     gsub(r, s, t)       Global substitution, every match of regular
  447.             expression r in variable t is replaced by s.
  448.             The number of matches/replacements is returned.
  449.  
  450.     sub(r, s, t)    Like gsub(), except at most one replacement.
  451.  
  452. Match(), gsub() and sub() are new.  If r is an expr it is coerced to 
  453. string and then treated as a regular expression.  In sub and gsub, t can
  454. be a variable, field or array element, i.e., it must have storage to 
  455. hold the modification.  Sub(r,s) and gsub(r,s) are the same as 
  456. sub(r,s,$0) and gsub(r,s,$0).  In the replacement string s, an & is 
  457. replaced by the matched piece and a literal & is obtained with \&.  
  458. E.g., 
  459.  
  460.         y = x = "abbc"
  461.         sub(/b+/, "B&B" , x)
  462.         sub(/b+/, "B\&B" , y)
  463.         print x, y
  464.  
  465. outputs:    aBbbBc aB&Bc
  466.  
  467.  
  468.  
  469.  
  470. Arithmetic functions
  471.  
  472.     atan2(y,x)        arctan of y/x between -pi and pi.
  473.     cos(x)
  474.     exp(x)
  475.     int(x)        x.dddd ->  x.0
  476.     log(x)
  477.     rand()        returns random number , 0 <= r < 1.
  478.     sin(x)
  479.     sqrt(x)
  480.     srand(x) , srand()  seeds random number generator, uses clock
  481.             if x is omitted.
  482.  
  483. Output functions
  484.  
  485.     print        writes  $0 ORS   to stdout.
  486.  
  487.     print expr1 , expr2 , ... , exprn
  488.             writes expr1 OFS expr2 OFS ... OFS exprn ORS to
  489.             stdout.
  490.  
  491.     printf format, expr_list
  492.             Acts like the C library function, writing to
  493.             stdout.  Supported conversions are
  494.             %c, %d, %e, %f, %g, %o, %s and %x.  
  495.             - , width and .prec are supported.
  496.             Dynamic widths can be built using string operations
  497.  
  498.  
  499. Output can be redirected 
  500.  
  501.    print[f]  > file
  502.          >> file
  503.          | command
  504.  
  505. File and command are awk expressions that are interpreted as a filename 
  506. or a shell command.  
  507.  
  508.  
  509. Input functions
  510.  
  511.     getline        read $0, update NF, NR and FNR.
  512.  
  513.     getline < file      read $0 from file, update NF.
  514.     getline var         read var from input stream, update NR, FNR.
  515.     getline var < file  read var from next record of file
  516.  
  517.     command | getline   read $0 from piped command, update NF.
  518.     command | getline var   read var from next record of piped command.
  519.  
  520. (Old) awk had getline, the redirection facilities are new.
  521.  
  522.     Files or commands are closed with
  523.  
  524.     close(expr)
  525.  
  526. where expr is command or file as a string.  Close returns 0 if expr was 
  527. in fact an open file or command else -1.  Close is needed if you want to
  528. reread a file, rerun a command, have a large number of output files 
  529. without mawk running out of resources or wait for an output command to 
  530. finish.  Here is an example of the last case: 
  531.  
  532.     { ....  do some processing on each input line
  533.       #  send the processed line to sort
  534.       print | "sort > temp_file"
  535.  
  536.     }
  537.  
  538.     END { # reread the sorted input
  539.       close( "sort > temp_file")  # makes sure sort is finished
  540.  
  541.       cnt=1
  542.       while ( getline line[cnt++] < "temp_file"  > 0 )  ;  
  543.       system( "rm temp_file" )  # cleanup
  544.  
  545.       ... process line[1], line[2] ... line[cnt-1]
  546.     }
  547.  
  548. The system() function executes a command and returns the command's exit 
  549. status.  Mawk uses the shell in the environment variable SHELL to 
  550. execute system or command pipelines; defaulting to "/bin/sh" if SHELL is
  551. not set.  
  552.  
  553.  
  554. 7. String constants
  555.  
  556. String constants are written as in C.
  557.  
  558.  
  559.     "This is a string with a newline at the end.\n"
  560.  
  561. Strings can be continued across a line by escaping (\) the newline.  The
  562. following escape sequences are recognized.  
  563.  
  564.     \\        \
  565.     \"        "
  566.     \'        '
  567.     \a        alert, ascii 7
  568.     \b        backspace, ascii 8
  569.     \t        tab, ascii 9
  570.     \n        newline, ascii 10
  571.     \v        vertical tab, ascii 11
  572.     \f        formfeed, ascii 12
  573.     \r        carriage return, ascii 13
  574.     \ddd        1, 2 or 3 octal digits for ascii ddd
  575.  
  576.     \xhh        1 or 2 hex digits for ascii  hh
  577.  
  578. If you escape any other character \c, you get \c, i.e.  the escape is 
  579. ignored.  Mawk is different than most awks here; the AWK book says \c is
  580. c.  The reason mawk chooses to be different is for easier conversion of 
  581. strings to regular expressions.  
  582.  
  583.  
  584. 8. Regular expressions
  585.  
  586. Awk notation for regular expressions is in the style of egrep(1).  In 
  587. awk, regular expressions are enclosed in / ...  /.  A regular expression
  588. /r/, is a set of strings.  
  589.  
  590.         s ~ /r/
  591.  
  592. is an awk expression that evaluates to 1 if an element of /r/ is a 
  593. substring of s and evaluates to 0 otherwise.  ~ is called the match 
  594. operator and the expression is read "s matches r".  
  595.  
  596.        s ~ /^r/   is 1 if some element of r is a prefix of s.
  597.        s ~ /r$/   is 1 if some element of r is a suffix of s.
  598.        s ~ /^r$/  is 1 if s is an element of r.
  599.  
  600. Replacing ~ by !~ , the not match operator, reverses the meanings.  In 
  601. patterns, /r/ and !/r/ are shorthand for $0 ~ /r/ and $0 !~ /r/.  
  602.  
  603. Regular expressions are combined by the following rules.
  604.  
  605.     //  stands for the one element set "" (not the empty set).
  606.     /c/ for a character c is the one element set "c".
  607.  
  608.     /rs/  is all elements of /r/ concatenated with all 
  609.           elements of /s/.
  610.  
  611.     /r|s/ is the set union of /r/ and /s/.
  612.  
  613.     /r*/  called the closure of r is // union /rr/ union /rrr/ ...
  614.           In words, r repeated zero or more times.
  615.  
  616. The above operations are sufficient to describe all regular expressions,
  617. but for ease of notation awk defines additional operations and notation.
  618.  
  619.     /r?/  // union /r/.  In words r 0 or 1 time.
  620.     /r+/  Positive closure of r.  R 1 or more times.
  621.     (r)   Same as r -- allows grouping.
  622.     .     Stands for any character (for mawk this means 
  623.           ascii 1 through ascii 255)
  624.     [c1c2..cn]    A character class same as (c1|c2|...|cn) where
  625.           ci's are single characters.
  626.  
  627.     [^c1c2..cn]   Complement of the class [c1c2..cn].  For mawk
  628.           complement in the ascii character set 1 to 255.
  629.  
  630. Ranges c1-cn are allowed in character classes.  For example,
  631.  
  632.     /[_a-zA-Z][_a-zA-Z0-9]*/
  633.  
  634. expresses the set of possible identifiers in awk.
  635.  
  636. The operators have increasing precedence:
  637.  
  638.        |
  639.        implicit concatenation
  640.        + * ?
  641.  
  642. So /a|b+/ means a or (1 or more b's), and /(a|b)+/ means (a or b) one or
  643. more times.  The so called regular expression metacharacters are \ ^ $ .
  644. [ ] | ( ) * + ? .  To stand for themselves as characters they have to be
  645. escaped.  (They don't have to be escaped in classes, inside classes the 
  646. meta-meaning is off).  The same escape sequences that are recognized in 
  647. strings (see above) are recognized in regular expressions.  For mawk, 
  648. the escape rule for \c changes to c.  
  649.  
  650. For example,
  651.  
  652.     /[ \t]*/   is optional space
  653.     /^[-+]?([0-9]+\.?|\.[0-9])[0-9]*([eE][-+]?[0-9]+)?$/
  654.            is numbers in the Awk language.
  655.            Note,  . must be escaped to have
  656.            its meaning as decimal point.
  657.  
  658. For building regular expressions, you can think of ^ and $ as phantom 
  659. characters at the front and back of every string.  So /(^a|b$|^A.*B$)/ 
  660. is the set of strings that start with a or end with b or (start with A 
  661. and end with B).  
  662.  
  663. Dynamic regular expressions are new.  You can write 
  664.  
  665.     x ~ expr
  666.  
  667. and expr is interpreted as a regular expression.  The result of x ~ y 
  668. can vary with the variable y; so 
  669.  
  670.     x ~ /a\+b/   and   x ~ "a\+b"
  671.  
  672. are the same, or are they? In mawk, they are; in some other awk's they 
  673. are not.  In the second expression, "a\+b" is scanned twice: once as a 
  674. string constant and then again as a regular expression.  In mawk the 
  675. first scan gives the four character string 'a' '\' '+' 'b' because mawk 
  676. treats \+ as \+; the second scan gives a regular expression matched by 
  677. the three character string 'a' '+' 'b' because on the second scan \+ 
  678. becomes +.  
  679.  
  680. If \c becomes c in strings, you need to double escape metacharacters, 
  681. i.e., write 
  682.  
  683.     x ~ "a\\+b".
  684.  
  685. Exercise: what happens if you double escape in mawk?
  686.  
  687. In strings if you only escape characters with defined escape sequences 
  688. such as \t or \n or meta-characters when you expect to use a string as a
  689. regular expression, then mawk's rules are intuitive and simple.  See 
  690. example/cdecl.awk and example/gdecl.awk for the same program with single
  691. and double escapes, the first is clearer.  
  692.  
  693.  
  694. 9. How Mawk splits lines, records and files.
  695.  
  696. Mawk uses the essentially the same algorithm to split lines into pieces 
  697. with split(), records into fields on FS, and files into records on RS.  
  698.  
  699. Split( s, A, sep ) splits string s into array A with separator sep as 
  700. follows: 
  701.  
  702.     Sep is interpreted as a regular expression.
  703.  
  704.     If s = "", there are no pieces and split returns 0.
  705.  
  706.     Otherwise s is split into pieces by the matches with sep
  707.     of positive length treated as a separator between pieces,
  708.     so the number of pieces is the number of matches + 1.
  709.     Matches of the null string do not split.
  710.     So sep = "b+" and sep = "b*" split the same although the
  711.     latter executes more slowly.
  712.  
  713.     Split(s, A) is the same as split(s, A, FS).
  714.     With mawk you can write sep as a regular expression, i.e.,
  715.     split(s, A, "b+") and split(s, A, /b+/) are the same.
  716.  
  717.     Sep = " " (a single space) is special.  Before the algorithm is
  718.     applied, white-space is trimmed from the front and back of s.
  719.     Mawk defines white-space as SPACE, TAB, FORMFEED, VERTICAL TAB
  720.     or NEWLINE, i.e [ \t\f\v\n].  Usually this means SPACE or TAB
  721.     because NEWLINE usually separates records, and the other
  722.     characters are rare.  The above algorithm
  723.     is then applied with sep = "[ \t\f\v\n]+".
  724.  
  725.     If length(sep) = 1, then regular expression metacharacters do
  726.     not have to be escaped, i.e. split(s, A, "+") is the same as
  727.     split(s, A, /\+/).
  728.  
  729.  
  730. Splitting records into fields works exactly the same except the pieces 
  731. are loaded into $1, $2 ...  $NF.  
  732.  
  733. Records are also the same, RS is treated as a regular expression.  But 
  734. there is a slight difference, RS is really a record terminator (ORS is 
  735. really a terminator also).  
  736.  
  737.     E.g., if FS = ":" and $0 = "a:b:" , then
  738.     NF = 3 and $1 = "a", $2 = "b" and $3 = "", but
  739.     if "a:b:" is the contents of an input file and RS = ":", then
  740.     there are two records "a" and "b".
  741.  
  742.     RS = " " does not have special meaning as with FS.
  743.  
  744.  
  745. Not all versions of (new) awk support RS as a regular expression.  This 
  746. feature of mawk is useful and improves performance.  
  747.  
  748.     BEGIN { RS = "[^a-zA-Z]+" 
  749.         getline
  750.         if ( $0 == "" ) NR = 0 
  751.         else word[1] = $0
  752.     }
  753.  
  754.     { word[NR] = $0 }
  755.  
  756.     END { ... do something with word[1]...word[NR] }
  757.  
  758. isolates words in a document over twice as fast as reading one line at a
  759. time and then examining each field with FS = "[^a-zA-Z]+".  
  760.  
  761. To remove comments from C code: 
  762.  
  763.     BEGIN { RS = "/\*([^*]|\*[^/])*\*/"  # comment is RS
  764.         ORS = " "
  765.     }
  766.  
  767.     { print }
  768.  
  769.     END { printf "\n" }
  770.  
  771.  
  772. 10. Multi-line records
  773.  
  774. Since mawk interprets RS as a regular expression, multi-line records are
  775. easy.  Setting RS = "\n\n+", makes one or more blank lines separate 
  776. records.  If FS = " " (the default), then single newlines, by the rules 
  777. for space above, become space.  
  778.  
  779.    For example, if a file is "a b\nc\n\n", RS = "\n\n+" and
  780.    FS = " ", then there is one record "a b\nc" with three
  781.    fields "a", "b" and "c".  Changing FS = "\n", gives two
  782.    fields "a b" and "c"; changing FS = "", gives one field
  783.    identical to the record.
  784.  
  785. For compatibility with (old) awk, setting RS = "" has the same
  786. effect on determining records as RS = "\n([ \t]*\n)+".
  787.  
  788. Most of the time when you change RS for mult-line records, you
  789. will also want to change ORS to "\n\n".
  790.  
  791. 11. User functions.
  792.  
  793. User defined functions are new.  They can be passed expressions by value
  794. or arrays by reference.  Function calls can be nested and support 
  795. recursion.  The syntax is 
  796.  
  797.     function  funcname( args ) {
  798.  
  799.     .... body
  800.  
  801.     }
  802.  
  803. Newlines are ignored after the ')' so the '{' can start on a different 
  804. line.  Inside the body, you can use a return statement 
  805.  
  806.     return expr
  807.     return
  808.  
  809. As in C, there is no distinction between functions and procedures.  A 
  810. function does not need an explicit return.  Extra arguments act as local
  811. variables.  For example, csplit(s, A) puts each character of s in array 
  812. A.  
  813.  
  814.     function  csplit(s, A,     i)
  815.     {
  816.       for(i=1; i <= length(s) ; i++)
  817.         A[i] = substr(s, i, 1)
  818.     }
  819.  
  820. Putting lots of space between the passed arguments and the local 
  821. variables is a convention that can be ignored if you don't like it.  
  822.  
  823. Dynamic regular expressions allow regular expressions to be passed to 
  824. user defined functions.  The following function gobble() is the lexical 
  825. scanner for a recursive descent parser, the whole program is in 
  826. examples/cdecl.awk.  
  827.  
  828.     function gobble( r,   x) # eat regular expression 
  829.         #  r off the front of global variable line
  830.  
  831.     {
  832.       if ( match( line, "^(" r ")") )
  833.       {
  834.         x = substr(line, 1, RLENGTH)
  835.         line = substr(line, RLENGTH)
  836.       }
  837.       else  x = ""
  838.  
  839.       return x
  840.     }
  841.  
  842. You can call a function before it is defined, but the function name and 
  843. the '(' must not be separated by white space to avoid confusion with 
  844. concatenation.  
  845.  
  846. 12. Other differences in mawk
  847.  
  848. The main differences between mawk and other awks have been discussed, RS
  849. as a regular expression and regular expression metacharacters don't have
  850. to be double escaped.  Here are some others: 
  851.  
  852.   VERSION  -- built-in variable holding version number of mawk.
  853.  
  854.     mawk 'BEGIN{print VERSION}'       shows it.
  855.  
  856.  
  857.   -D  --  command line flag causes mawk to dump to stderr 
  858.       a mawk assembler listing of the current program.
  859.       The program is executed by a stack machine internal
  860.       to mawk.  The op codes are in code.h, the machine in
  861.       execute.c.
  862.  
  863.   srand() --    
  864.       During initialization, mawk seeds the random number generator
  865.       by silently calling srand(), so calling srand() yourself is
  866.       unnecessary.  The main use of srand is to use srand(x) to get
  867.       a repeatable stream of random numbers.  Srand(x) returns x
  868.       and srand() returns the value of the system clock in some form
  869.       of ticks.
  870.  
  871.  
  872. 13. MsDOS
  873.  
  874. For a number of reasons, entering a mawk program on the command line 
  875. using command.com as your shell is an exercise in futility, so under 
  876. MsDOS the command syntax is 
  877.  
  878.     mawk [-Fs] optional_list_of_files
  879.  
  880. You'll get a prompt, and then type in the program.  The -f option works 
  881. as before.  
  882.  
  883. If you use a DOS shell that gives you a Unix style command line, to use 
  884. it you'll need to provide a C function reargv() that retrieves argc and 
  885. argv[] from your shell.  The details are in msdos/INSTALL.  
  886.  
  887. Some features are missing from the DOS version of mawk: No system(), and
  888. no input or output pipes.  To provide a hook to stderr, I've added 
  889.  
  890.     errmsg( "string" )
  891.  
  892. which prints "string\n" to stderr which will be the console and only the
  893. console under command.com.  A better solution would be to associate a 
  894. file with handle 2, so print and printf would be available.  Consider 
  895. the errmsg() feature as temporary.  
  896.  
  897. For compatibility with Unix, CR are silently stripped from input and LF 
  898. silently become CRLF on output.  
  899.  
  900. WARNING: If you write an infinite loop that does not print to the 
  901. screen, then you will have to reboot.  For example 
  902.  
  903.     x = 1 
  904.     while( x < 10 )  A[x] = x
  905.     x++
  906.  
  907. By mistake the x++ is outside the loop.  What you need to do is type 
  908. control break and the keyboard hardware will generate an interrupt and 
  909. the operating system will service that interrupt and terminate your 
  910. program, but unfortunately MsDOS does not have such a feature.  
  911.  
  912.  
  913. 14. Bugs
  914.  
  915. Currently mawk cannot handle \0 (NUL) characters in input files 
  916. otherwise mawk is 8 bit clean.  Also "a\0b", doesn't work right -- you 
  917. get "a".  You can't use \0 in regular expressions either.  
  918.  
  919.    printf "A string%c more string\n" , 0
  920.  
  921. does work, but more by luck than design since it doesn't work with 
  922. sprintf().  
  923.  
  924.  
  925. 15. Releases
  926.  
  927. This release is version 0.97.  After a reasonable period of time, any 
  928. bugs that appear will be fixed, and this release will become version 
  929. 1.0.  
  930.  
  931. Evidently features have been added to awk by Aho, Kernighan and 
  932. Weinberger since the 1988 release of the AWK book.  Version 1.1 will add
  933. whatever features are necessary to remain compatible with the language 
  934. as defined by its designers.  
  935.  
  936. After that ...  ? 
  937.  
  938. 16. Correspondence
  939.  
  940. Send bug reports or other correspondence to
  941.  
  942. Mike Brennan
  943. brennan@bcsaic.boeing.com
  944.  
  945. If you have some interesting awk programs, contributions to the examples
  946. directory would be appreciated.  
  947. @//E*O*F mawk0.97/mawk.manual//
  948. chmod u=rw,g=r,o=r mawk0.97/mawk.manual
  949.  
  950. echo x - mawk0.97/array.c
  951. sed 's/^@//' > "mawk0.97/array.c" <<'@//E*O*F mawk0.97/array.c//'
  952.  
  953. /********************************************
  954. array.c
  955. copyright 1991, Michael D. Brennan
  956.  
  957. This is a source file for mawk, an implementation of
  958. the Awk programming language as defined in
  959. Aho, Kernighan and Weinberger, The AWK Programming Language,
  960. Addison-Wesley, 1988.
  961.  
  962. See the accompaning file, LIMITATIONS, for restrictions
  963. regarding modification and redistribution of this
  964. program in source or binary form.
  965. ********************************************/
  966.  
  967. /* $Log:    array.c,v $
  968.  * Revision 2.1  91/04/08  08:22:15  brennan
  969.  * VERSION 0.97
  970.  * 
  971. */
  972.  
  973. #include "mawk.h"
  974. #include "symtype.h"
  975. #include "memory.h"
  976. #include "bi_vars.h"
  977.  
  978. extern int returning ; 
  979.    /* flag -- on if returning from function call */
  980.  
  981. extern unsigned hash() ;
  982.  
  983. /* An array A is a pointer to a hash table of size
  984.    A_HASH_PRIME holding linked lists of ANODEs.
  985.  
  986.    When an index is deleted via  delete A[i], the
  987.    ANODE is not removed from the hash chain.  A[i].cp
  988.    and A[i].sval are both freed and sval is set NULL.
  989.    This method of deletion simplifies for( i in A ) loops.
  990. */
  991.  
  992. /* is sval in A ? */
  993. int array_test( A, sval)
  994.   ARRAY A ; 
  995.   STRING *sval ;
  996. { char *s = sval->str ;
  997.   register ANODE *p = A[ hash(s) % A_HASH_PRIME ] ;
  998.   
  999.   while ( p )
  1000.   { if ( p->sval && strcmp(s, p->sval->str) == 0 )  return 1 ;
  1001.     p = p->link ; }
  1002.   /* not there */
  1003.   return 0 ;
  1004. }
  1005.   
  1006. /* find x in array a
  1007.    if flag is ON x is a char* else a STRING*,
  1008.    computes a[x] as a CELL*
  1009. */
  1010.  
  1011. CELL *array_find( a, x, flag)
  1012.   ARRAY a ; PTR  x ; int flag ;
  1013. { register ANODE *p ;  /* search with p */
  1014.   ANODE *q ;  /* pts at a deleted node */
  1015.   unsigned h ;
  1016.   char *s ;
  1017.  
  1018.   s = flag ? (char *) x : ( (STRING *) x) -> str ;
  1019.   p = a[ h = hash(s) % A_HASH_PRIME ] ;
  1020.   q = (ANODE *) 0 ; 
  1021.  
  1022.   while ( p )
  1023.   { 
  1024.     if ( p->sval )
  1025.     {
  1026.       if ( strcmp(s,p->sval->str) == 0 )  /* found */
  1027.         return  p->cp ;
  1028.     }
  1029.     else /* a deleted node */
  1030.     if ( !q )  q = p ;
  1031.  
  1032.     p = p->link ;
  1033.   }
  1034.   
  1035.   /* not there make one  */
  1036.   if ( q )  p = q ; /* reuse the node */
  1037.   else
  1038.   { p = (ANODE *) zmalloc( sizeof(ANODE) ) ;
  1039.     p->link = a[h] ; a[h] = p ; }
  1040.  
  1041.   if ( flag )  p->sval = new_STRING(s) ;
  1042.   else
  1043.   { p->sval = (STRING *) x ; p->sval->ref_cnt++ ; }
  1044.   p->cp = new_CELL() ; p->cp->type = C_NOINIT ;
  1045.   return p->cp ;
  1046. }
  1047.  
  1048. void  array_delete( a, sval)
  1049.   ARRAY a ; STRING *sval ;
  1050. { char *s = sval->str ;
  1051.   register ANODE *p = a[ hash(s) % A_HASH_PRIME ] ;
  1052.  
  1053.   while ( p )
  1054.   { if ( p->sval && strcmp(s, p->sval->str)== 0 ) /* found */
  1055.     { 
  1056.       cell_destroy(p->cp) ;  free_CELL(p->cp) ;
  1057.       free_STRING(p->sval) ; p->sval = (STRING *) 0 ;
  1058.  
  1059.       break ;
  1060.     }
  1061.  
  1062.     p = p->link ;
  1063.   }
  1064. }
  1065.       
  1066.  
  1067. /* for ( i in A ) ,
  1068.    loop over elements of an array 
  1069.  
  1070. sp[0].ptr :  a pointer to A ( the hash table of A)
  1071. sp[-1] :  a pointer to i ( a cell ptr)
  1072.  
  1073. cdp[0] :  a stop op to catch breaks
  1074. cdp[1] :  offset from cdp of the code after the loop (n+2)
  1075. cdp[2] :  start of body of the loop
  1076. cdp[3..n] : the rest of the body
  1077. cdp[n+1]  : a stop op to delimit the body and catch continues
  1078. */
  1079.  
  1080. INST  *array_loop( cdp, sp, fp) /* passed code, stack and frame ptrs */
  1081.   INST *cdp ; 
  1082.   CELL *sp, *fp ;
  1083. { int i ;
  1084.   register ANODE *p ;
  1085.   ARRAY   A = (ARRAY) sp-- -> ptr ;
  1086.   register CELL *cp = (CELL *) sp-- -> ptr ;
  1087.  
  1088.   for ( i = 0 ; i < A_HASH_PRIME ; i++ )
  1089.   for ( p = A[i] ; p ; p = p->link )
  1090.   { if ( ! p->sval /* its deleted */ )  continue ;
  1091.   
  1092.     cell_destroy(cp) ;
  1093.     cp->type = C_STRING ;
  1094.     cp->ptr = (PTR) p->sval ;
  1095.     p->sval->ref_cnt++ ;
  1096.  
  1097.     /* execute the body of the loop */
  1098.     if ( execute(cdp+2, sp, fp) == cdp /* exec'ed a break statement */
  1099.          || returning  /* function return in body of loop */
  1100.        )  
  1101.            goto break2 /* break both for loops */ ; 
  1102.   }
  1103.  
  1104. break2 :
  1105.   return   cdp + cdp[1].op ;
  1106. }
  1107.  
  1108.  
  1109. /* cat together cnt elements on the eval stack to form
  1110.    an array index using SUBSEP */
  1111.  
  1112. CELL *array_cat( sp, cnt)
  1113.   register CELL *sp ;
  1114.   int cnt ;
  1115. { register CELL *p ;  /* walks the stack */
  1116.   CELL subsep ;  /* a copy of bi_vars[SUBSEP] */
  1117.   unsigned subsep_len ;
  1118.   char *subsep_str ;
  1119.   unsigned total_len ; /* length of cat'ed expression */
  1120.   CELL *top ;  /* sp at entry */
  1121.   char *t ; /* target ptr when catting */
  1122.   STRING *sval ;  /* build new STRING here */
  1123.  
  1124.   /* get a copy of subsep, we may need to cast */
  1125.   (void) cellcpy(&subsep, bi_vars + SUBSEP) ;
  1126.   if ( subsep.type < C_STRING ) cast1_to_s(&subsep) ;
  1127.   subsep_len = string(&subsep)->len ;
  1128.   subsep_str = string(&subsep)->str ;
  1129.   total_len = --cnt * subsep_len ;
  1130.  
  1131.   top = sp ;
  1132.   sp -= cnt ;
  1133.   for( p = sp ; p <= top ; p++ )
  1134.   {
  1135.     if ( p->type < C_STRING ) cast1_to_s(p) ;
  1136.     total_len += string(p)->len ;
  1137.   }
  1138.  
  1139.   sval = new_STRING((char *)0, total_len) ;
  1140.   t = sval->str ;
  1141.  
  1142.   /* put the pieces together */
  1143.   for( p = sp ; p < top ; p++ )
  1144.   { (void) memcpy(t, string(p)->str, string(p)->len) ;
  1145.     (void) memcpy( t += string(p)->len, subsep_str, subsep_len) ;
  1146.     t += subsep_len ;
  1147.   }
  1148.   /* p == top */
  1149.   (void) memcpy(t, string(p)->str, string(p)->len) ;
  1150.  
  1151.   /* done, now cleanup */
  1152.   free_STRING(string(&subsep)) ;
  1153.   while ( p >= sp )  { free_STRING(string(p)) ; p-- ; }
  1154.   sp->type = C_STRING ;
  1155.   sp->ptr = (PTR) sval ;
  1156.   return sp ;
  1157. }
  1158.  
  1159.  
  1160. /* free all memory used by an array,
  1161.    only used for arrays local to a function call
  1162. */
  1163.  
  1164. void  array_free(A)
  1165.   ARRAY  A ;
  1166. { register ANODE *p ;
  1167.   register int i ;
  1168.   ANODE *q ;
  1169.  
  1170.   for( i = 0 ; i < A_HASH_PRIME ; i++ )
  1171.   { p = A[i] ;
  1172.     while ( p )
  1173.     { /* check its not a deleted node */
  1174.       if ( p->sval )
  1175.       { free_STRING(p->sval) ;
  1176.         cell_destroy(p->cp) ;
  1177.         free_CELL(p->cp) ;
  1178.       }
  1179.  
  1180.       q = p ; p = p->link ;
  1181.       zfree( q, sizeof(ANODE)) ;
  1182.     }
  1183.   }
  1184.  
  1185.   zfree(A, sizeof(ANODE *) * A_HASH_PRIME ) ;
  1186. }
  1187. @//E*O*F mawk0.97/array.c//
  1188. chmod u=rw,g=r,o=r mawk0.97/array.c
  1189.  
  1190. echo x - mawk0.97/bi_funct.c
  1191. sed 's/^@//' > "mawk0.97/bi_funct.c" <<'@//E*O*F mawk0.97/bi_funct.c//'
  1192.  
  1193. /********************************************
  1194. bi_funct.c
  1195. copyright 1991, Michael D. Brennan
  1196.  
  1197. This is a source file for mawk, an implementation of
  1198. the Awk programming language as defined in
  1199. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1200. Addison-Wesley, 1988.
  1201.  
  1202. See the accompaning file, LIMITATIONS, for restrictions
  1203. regarding modification and redistribution of this
  1204. program in source or binary form.
  1205. ********************************************/
  1206.  
  1207.  
  1208. /* $Log:    bi_funct.c,v $
  1209.  * Revision 2.3  91/04/17  06:34:00  brennan
  1210.  * index("","") should be 1 not 0 for consistency with match("",//)
  1211.  * 
  1212.  * Revision 2.2  91/04/09  12:38:42  brennan
  1213.  * added static to funct decls to satisfy STARDENT compiler
  1214.  * 
  1215.  * Revision 2.1  91/04/08  08:22:17  brennan
  1216.  * VERSION 0.97
  1217.  * 
  1218. */
  1219.  
  1220.  
  1221. #include "mawk.h"
  1222. #include "bi_funct.h"
  1223. #include "bi_vars.h"
  1224. #include "memory.h"
  1225. #include "init.h"
  1226. #include "files.h"
  1227. #include "fin.h"
  1228. #include "field.h"
  1229. #include "regexp.h"
  1230. #include "repl.h"
  1231. #include <math.h>
  1232.  
  1233. #ifndef  BSD43
  1234. void PROTO( srand48, (long) ) ;
  1235. double PROTO( drand48, (void) ) ;
  1236. #endif
  1237.  
  1238. /* statics */
  1239. static STRING *PROTO(gsub, (PTR, CELL *, char *, int) ) ;
  1240. static void  PROTO( fplib_err, (char *, double, char *) ) ;
  1241.  
  1242.  
  1243. /* global for the disassembler */
  1244. BI_REC  bi_funct[] = { /* info to load builtins */
  1245.  
  1246. "index" , bi_index , 2, 2 ,
  1247. "substr" , bi_substr, 2, 3,
  1248. "sprintf" , bi_sprintf, 1, 255,
  1249. "sin", bi_sin , 1, 1 ,
  1250. "cos", bi_cos , 1, 1 ,
  1251. "atan2", bi_atan2, 2,2,
  1252. "exp", bi_exp, 1, 1,
  1253. "log", bi_log , 1, 1 ,
  1254. "int", bi_int, 1, 1,
  1255. "sqrt", bi_sqrt, 1, 1,
  1256. "rand" , bi_rand, 0, 0,
  1257. "srand", bi_srand, 0, 1,
  1258. "close", bi_close, 1, 1,
  1259. "system", bi_system, 1, 1,
  1260.  
  1261. #if  DOS   /* this might go away, when pipes and system are added
  1262.           for DOS  */
  1263. "errmsg", bi_errmsg, 1, 1,
  1264. #endif
  1265.  
  1266. (char *) 0, (PF_CP) 0, 0, 0 } ;
  1267.  
  1268.  
  1269.  
  1270. void bi_funct_init()
  1271. { register BI_REC *p = bi_funct ;
  1272.   register SYMTAB *stp ;
  1273.  
  1274.   while ( p->name )
  1275.   { stp = insert( p->name ) ;
  1276.     stp->type = ST_BUILTIN ;
  1277.     stp->stval.bip = p++ ;
  1278.   }
  1279.   /* seed rand() off the clock */
  1280.   { CELL c ;
  1281.  
  1282.     c.type = 0 ; (void) bi_srand(&c) ;
  1283.   }
  1284.  
  1285.   stp = insert( "length") ;
  1286.   stp->type = ST_LENGTH ;
  1287. }
  1288.  
  1289. /**************************************************
  1290.  string builtins (except split (in split.c) and [g]sub (at end))
  1291.  **************************************************/
  1292.  
  1293. CELL *bi_length(sp)
  1294.   register  CELL *sp ;
  1295. { unsigned len ;
  1296.  
  1297.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  1298.   len = string(sp)->len ;
  1299.  
  1300.   free_STRING( string(sp) ) ;
  1301.   sp->type = C_DOUBLE ;
  1302.   sp->dval = (double) len ;
  1303.  
  1304.   return sp ;
  1305. }
  1306.  
  1307. char *str_str(target, key , key_len)
  1308.   register char *target, *key ;
  1309.   unsigned key_len ;
  1310.   switch( key_len )
  1311.   { case 0 :  return (char *) 0 ;
  1312.     case 1 :  return strchr( target, *key) ;
  1313.     case 2 :
  1314.         while ( target = strchr(target, *key) )
  1315.           if ( target[1] == key[1] )  return  target ;
  1316.           else target++ ;
  1317.         /*failed*/
  1318.         return (char *) 0 ;
  1319.   }
  1320.   key_len-- ;
  1321.   while ( target = strchr(target, *key) )
  1322.         if ( memcmp(target+1, key+1, key_len) == 0 ) return target ;
  1323.         else target++ ;
  1324.   /*failed*/
  1325.   return (char *) 0 ;
  1326. }
  1327.  
  1328.  
  1329.  
  1330. CELL *bi_index(sp)
  1331.   register CELL *sp ;
  1332. { register int idx ;
  1333.   unsigned len ;
  1334.   char *p ;
  1335.  
  1336.   sp-- ;
  1337.   if ( TEST2(sp) != TWO_STRINGS )
  1338.         cast2_to_s(sp) ;
  1339.  
  1340.   if ( len = string(sp+1)->len )
  1341.     idx = (p = str_str(string(sp)->str,string(sp+1)->str,len))
  1342.           ? p - string(sp)->str + 1 : 0 ;
  1343.  
  1344.   else  /* index of the empty string */
  1345.     idx = 1 ;
  1346.   
  1347.   free_STRING( string(sp) ) ;
  1348.   free_STRING( string(sp+1) ) ;
  1349.   sp->type = C_DOUBLE ;
  1350.   sp->dval = (double) idx ;
  1351.   return sp ;
  1352. }
  1353.  
  1354. /*  substr(s, i, n)
  1355.     if l = length(s)
  1356.     then get the characters
  1357.     from  max(1,i) to min(l,n-i-1) inclusive */
  1358.  
  1359. CELL *bi_substr(sp)
  1360.   CELL *sp ;
  1361. { int n_args, len ;
  1362.   register int i, n ;
  1363.   char *s ;    /* substr(s, i, n) */
  1364.   STRING *sval ;
  1365.  
  1366.   n_args = sp->type ;
  1367.   sp -= n_args ;
  1368.   if ( sp->type < C_STRING )  cast1_to_s(sp) ;
  1369.   s = (sval = string(sp)) -> str ;
  1370.  
  1371.   if ( n_args == 2 )  
  1372.   { n = 0x7fff  ;  /* essentially infinity */
  1373.     if ( sp[1].type != C_DOUBLE ) cast1_to_d(sp+1) ; 
  1374.   }
  1375.   else
  1376.   { if ( sp[1].type + sp[2].type != TWO_STRINGS ) cast2_to_d(sp+1) ;
  1377.     n = (int) sp[2].dval ;
  1378.   }
  1379.   i = (int) sp[1].dval - 1 ; /* i now indexes into string */
  1380.  
  1381.  
  1382.   if ( (len = strlen(s)) == 0 )  return sp ;
  1383.   /* get to here is s is not the null string */
  1384.   if ( i < 0 ) { n += i ; i = 0 ; }
  1385.   if ( n > len - i )  n = len - i ;
  1386.  
  1387.   if ( n <= 0 )  /* the null string */
  1388.   { free_STRING( sval ) ;
  1389.     sp->ptr = (PTR) &null_str ;
  1390.     null_str.ref_cnt++ ;
  1391.   }
  1392.   else  /* got something */
  1393.   { 
  1394.     sp->ptr = (PTR) new_STRING((char *)0, n) ;
  1395.     (void) memcpy(string(sp)->str, s+i, n) ;
  1396.     string(sp)->str[n] = 0 ;
  1397.   }
  1398.   return sp ;
  1399.  
  1400. /*
  1401.   match(s,r)
  1402.   sp[0] holds s, sp[-1] holds r
  1403. */
  1404.  
  1405. CELL *bi_match(sp)
  1406.   register CELL *sp ;
  1407. { double d ;
  1408.   char *p ;
  1409.   unsigned length ;
  1410.  
  1411.   if ( sp->type != C_RE )  cast_to_RE(sp) ;
  1412.   if ( (--sp)->type < C_STRING )  cast1_to_s(sp) ;
  1413.  
  1414.   if ( p = REmatch(string(sp)->str, (sp+1)->ptr, &length) )
  1415.       d = (double) ( p - string(sp)->str + 1 ) ;
  1416.   else  d = 0.0 ;
  1417.  
  1418.   cell_destroy( & bi_vars[RSTART] ) ;
  1419.   cell_destroy( & bi_vars[RLENGTH] ) ;
  1420.   bi_vars[RSTART].type = C_DOUBLE ;
  1421.   bi_vars[RSTART].dval = d ;
  1422.   bi_vars[RLENGTH].type = C_DOUBLE ;
  1423.   bi_vars[RLENGTH].dval = (double) length ;
  1424.  
  1425.   free_STRING(string(sp)) ;
  1426.     
  1427.   sp->type = C_DOUBLE ;  sp->dval = d ;
  1428.   return sp ;
  1429. }
  1430.  
  1431.  
  1432. /************************************************
  1433.   arithemetic builtins
  1434.  ************************************************/
  1435.  
  1436. static void fplib_err( fname, val, error)
  1437.   char *fname ;
  1438.   double val ;
  1439.   char *error ;
  1440. {
  1441.   rt_error("%s(%g) : %s" , fname, val, error) ;
  1442. }
  1443.  
  1444.  
  1445. CELL *bi_sin(sp)
  1446.   register CELL *sp ;
  1447. #if ! STDC_MATHERR
  1448.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1449.   sp->dval = sin( sp->dval ) ;
  1450.   return sp ;
  1451. #else
  1452.   double x ;
  1453.  
  1454.   errno = 0 ;
  1455.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1456.   x = sp->dval ;
  1457.   sp->dval = sin( sp->dval ) ;
  1458.   if ( errno )  fplib_err("sin", x, "loss of precision") ;
  1459.   return sp ;
  1460. #endif
  1461. }
  1462.  
  1463. CELL *bi_cos(sp)
  1464.   register CELL *sp ;
  1465. #if ! STDC_MATHERR
  1466.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1467.   sp->dval = cos( sp->dval ) ;
  1468.   return sp ;
  1469. #else
  1470.   double x ;
  1471.  
  1472.   errno = 0 ;
  1473.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1474.   x = sp->dval ;
  1475.   sp->dval = cos( sp->dval ) ;
  1476.   if ( errno )  fplib_err("cos", x, "loss of precision") ;
  1477.   return sp ;
  1478. #endif
  1479. }
  1480.  
  1481. CELL *bi_atan2(sp)
  1482.   register CELL *sp ;
  1483. #if  !  STDC_MATHERR
  1484.   sp-- ;
  1485.   if ( TEST2(sp) != TWO_DOUBLES ) cast2_to_d(sp) ;
  1486.   sp->dval = atan2(sp->dval, (sp+1)->dval) ;
  1487.   return sp ;
  1488. #else
  1489.  
  1490.   errno = 0 ;
  1491.   sp-- ;
  1492.   if ( TEST2(sp) != TWO_DOUBLES ) cast2_to_d(sp) ;
  1493.   sp->dval = atan2(sp->dval, (sp+1)->dval) ;
  1494.   if ( errno ) rt_error("atan2(0,0) : domain error") ;
  1495.   return sp ;
  1496. #endif
  1497. }
  1498.  
  1499. CELL *bi_log(sp)
  1500.   register CELL *sp ;
  1501. #if ! STDC_MATHERR
  1502.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1503.   sp->dval = log( sp->dval ) ;
  1504.   return sp ;
  1505. #else
  1506.   double  x ;
  1507.  
  1508.   errno = 0 ;
  1509.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1510.   x = sp->dval ;
  1511.   sp->dval = log( sp->dval ) ;
  1512.   if ( errno )  fplib_err("log", x, "domain error") ;
  1513.   return sp ;
  1514. #endif
  1515. }
  1516.  
  1517. CELL *bi_exp(sp)
  1518.   register CELL *sp ;
  1519. #if  ! STDC_MATHERR
  1520.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1521.   sp->dval = exp(sp->dval) ;
  1522.   return sp ;
  1523. #else
  1524.   double  x ;
  1525.  
  1526.   errno = 0 ;
  1527.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1528.   x = sp->dval ;
  1529.   sp->dval = exp(sp->dval) ;
  1530.   if ( errno && sp->dval)  fplib_err("exp", x, "overflow") ;
  1531.      /* on underflow sp->dval==0, ignore */
  1532.   return sp ;
  1533. #endif
  1534. }
  1535.  
  1536. CELL *bi_int(sp)
  1537.   register CELL *sp ;
  1538. { if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1539.   sp->dval = sp->dval >= 0.0 ? floor( sp->dval ) : ceil(sp->dval)  ;
  1540.   return sp ;
  1541. }
  1542.  
  1543. CELL *bi_sqrt(sp)
  1544.   register CELL *sp ;
  1545. #if  ! STDC_MATHERR
  1546.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1547.   sp->dval = sqrt( sp->dval ) ;
  1548.   return sp ;
  1549. #else
  1550.   double x ;
  1551.  
  1552.   errno = 0 ;
  1553.   if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1554.   x = sp->dval ;
  1555.   sp->dval = sqrt( sp->dval ) ;
  1556.   if ( errno )  fplib_err("sqrt", x, "domain error") ;
  1557.   return sp ;
  1558. #endif
  1559. }
  1560.  
  1561. #ifdef  __TURBOC__
  1562. long  biostime(int, long) ;
  1563. #define  time(x)  (biostime(0,0L)<<4)
  1564. #else
  1565. #include <sys/types.h>
  1566.  
  1567. #if 0
  1568. #ifndef  STARDENT
  1569. #include <sys/timeb.h>
  1570. #endif
  1571. #endif
  1572.  
  1573. #endif
  1574.  
  1575. CELL *bi_srand(sp)
  1576.   register CELL *sp ;
  1577. { register long l ; 
  1578.   void srand48() ;
  1579.  
  1580.   if ( sp-- -> type )  /* user seed */
  1581.   { if ( sp->type != C_DOUBLE )  cast1_to_d(sp) ;
  1582.     l = (long) sp->dval ; }
  1583.   else
  1584.   { l = (long) time( (time_t *) 0 ) ;
  1585.     (++sp)->type = C_DOUBLE ;
  1586.     sp->dval = (double) l ;
  1587.   }
  1588.   srand48(l) ;
  1589.   return sp ;
  1590. }
  1591.     
  1592. CELL *bi_rand(sp)
  1593.   register CELL *sp ;
  1594.  
  1595.   (++sp)->type = C_DOUBLE ;
  1596.   sp->dval = drand48() ;
  1597.   return sp ;
  1598. }
  1599.  
  1600. /*************************************************
  1601.  miscellaneous builtins
  1602.  close, system and getline
  1603.  *************************************************/
  1604.  
  1605. CELL *bi_close(sp)
  1606.   register CELL *sp ;
  1607. { int x ;
  1608.  
  1609.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  1610.   x = file_close( (STRING *) sp->ptr) ;
  1611.   free_STRING( string(sp) ) ;
  1612.   sp->type = C_DOUBLE ;
  1613.   sp->dval = (double) x ;
  1614.   return sp ;
  1615. }
  1616.  
  1617. #if   ! DOS
  1618. CELL *bi_system(sp)
  1619.   CELL *sp ;
  1620. { int pid ;
  1621.   unsigned ret_val ;
  1622.  
  1623.   if ( !shell ) shell = (shell = getenv("SHELL")) ? shell : "/bin/sh" ;
  1624.   if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  1625.  
  1626.   switch( pid = fork() )
  1627.   { case -1 :  /* fork failed */
  1628.  
  1629.        errmsg(errno, "could not create a new process") ;
  1630.        ret_val = 128 ;
  1631.        break ;
  1632.  
  1633.     case  0  :  /* the child */
  1634.        (void) execl(shell, shell, "-c", string(sp)->str, (char *) 0) ;
  1635.        /* if get here, execl() failed */
  1636.        errmsg(errno, "execute of %s failed", shell) ;
  1637.        fflush(stderr) ;
  1638.        _exit(128) ;
  1639.  
  1640.     default   :  /* wait for the child */
  1641.        ret_val = wait_for(pid) ;
  1642.        if ( ret_val & 0xff ) ret_val = 128 ;
  1643.        else  ret_val = (ret_val & 0xff00) >> 8 ;
  1644.        break ;
  1645.   }
  1646.  
  1647.   cell_destroy(sp) ;
  1648.   sp->type = C_DOUBLE ;
  1649.   sp->dval = (double) ret_val ;
  1650.   return sp ;
  1651. }
  1652.  
  1653. #else   /*  DOS   */
  1654.  
  1655. CELL *bi_system( sp )
  1656.   register CELL *sp ;
  1657. { rt_error("no system call in MsDos --yet") ;
  1658.   return sp ;
  1659. }
  1660.  
  1661. /* prints errmsgs for DOS  */
  1662. CELL *bi_errmsg(sp)
  1663.   register CELL *sp ;
  1664. {
  1665.   cast1_to_s(sp) ;
  1666.   fprintf(stderr, "%s\n", string(sp)->str) ;
  1667.   free_STRING(string(sp)) ;
  1668.   sp->type = C_DOUBLE ;
  1669.   sp->dval = 0.0 ;
  1670.   return sp ;
  1671. }
  1672. #endif
  1673.  
  1674.  
  1675. /*  getline()  */
  1676.  
  1677. /*  if type == 0 :  stack is 0 , target address
  1678.  
  1679.     if type == F_IN : stack is F_IN, expr(filename), target address
  1680.  
  1681.     if type == PIPE_IN : stack is PIPE_IN, target address, expr(pipename)
  1682. */
  1683.  
  1684. CELL *bi_getline(sp)
  1685.   register CELL *sp ;
  1686.   CELL tc , *cp ;
  1687.   char *p ;
  1688.   unsigned len ;
  1689.   FIN *fin_p ;
  1690.  
  1691.  
  1692.   switch( sp->type )
  1693.   { 
  1694.     case 0 :
  1695.         sp-- ;
  1696.         if ( main_fin == (FIN *) -1 && ! open_main() )
  1697.                 goto open_failure ;
  1698.     
  1699.         if ( ! main_fin || !(p = FINgets(main_fin, &len)) )
  1700.                 goto  eof ;
  1701.  
  1702.         cp = (CELL *) sp->ptr ;
  1703.         if ( TEST2(bi_vars+NR) != TWO_DOUBLES ) cast2_to_d(bi_vars+NR) ;
  1704.         bi_vars[NR].dval += 1.0 ;
  1705.         bi_vars[FNR].dval += 1.0 ;
  1706.         break ;
  1707.  
  1708.     case  F_IN :
  1709.         sp-- ;
  1710.         if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  1711.         fin_p = (FIN *) file_find(sp->ptr, F_IN) ;
  1712.         free_STRING(string(sp) ) ;
  1713.         sp-- ;
  1714.  
  1715.         if ( ! fin_p )   goto open_failure ;
  1716.         if ( ! (p = FINgets(fin_p, &len)) )  goto eof ; 
  1717.         cp = (CELL *) sp->ptr ;
  1718.         break ;
  1719.  
  1720.     case PIPE_IN :
  1721.         sp -= 2 ;
  1722.         if ( sp->type < C_STRING ) cast1_to_s(sp) ;
  1723.         fin_p = (FIN *) file_find(sp->ptr, PIPE_IN) ;
  1724.         free_STRING(string(sp)) ;
  1725.  
  1726.         if ( ! fin_p )   goto open_failure ;
  1727.         if ( ! (p = FINgets(fin_p, &len)) )  goto eof ; 
  1728.         cp = (CELL *) (sp+1)->ptr ;
  1729.         break ;
  1730.  
  1731.     default : bozo("type in bi_getline") ;
  1732.  
  1733.   }
  1734.  
  1735.   /* we've read a line , store it */
  1736.  
  1737.     if ( len == 0 )
  1738.     { tc.type = C_STRING ; 
  1739.       tc.ptr = (PTR) &null_str ; 
  1740.       null_str.ref_cnt++ ;
  1741.     }
  1742.     else
  1743.     { tc.type = C_MBSTRN ;
  1744.       tc.ptr = (PTR) new_STRING((char *) 0, len) ;
  1745.       (void) memcpy( string(&tc)->str, p, len) ;
  1746.     }
  1747.  
  1748.     if ( cp  >= field && cp < field+NUM_FIELDS )
  1749.            field_assign(cp-field, &tc) ;
  1750.     else
  1751.     { cell_destroy(cp) ;
  1752.       (void) cellcpy(cp, &tc) ;
  1753.     }
  1754.  
  1755.     cell_destroy(&tc) ;
  1756.  
  1757.   sp->dval = 1.0  ;  goto done ;
  1758.  
  1759. open_failure :
  1760.   sp->dval = -1.0  ; goto done ;
  1761.  
  1762. eof :
  1763.   sp->dval = 0.0  ;  /* fall thru to done  */
  1764.  
  1765. done :
  1766.   sp->type = C_DOUBLE  ;
  1767.   return sp ;
  1768. }
  1769.  
  1770. /**********************************************
  1771.  sub() and gsub()
  1772.  **********************************************/
  1773.  
  1774. /* entry:  sp[0] = address of CELL to sub on
  1775.            sp[-1] = substitution CELL
  1776.            sp[-2] = regular expression to match
  1777. */
  1778.  
  1779. CELL *bi_sub( sp )
  1780.   register CELL *sp ;
  1781. { CELL *cp ; /* pointer to the replacement target */
  1782.   CELL tc ;  /* build the new string here */
  1783.   CELL sc ;  /* copy of the target CELL */
  1784.   char *front, *middle, *back ; /* pieces */
  1785.   unsigned front_len, middle_len, back_len ;
  1786.  
  1787.   sp -= 2 ;
  1788.   if ( sp->type != C_RE )  cast_to_RE(sp) ;
  1789.   if ( sp[1].type != C_REPL && sp[1].type != C_REPLV )
  1790.               cast_to_REPL(sp+1) ;
  1791.   cp = (CELL *) (sp+2)->ptr ;
  1792.   /* make a copy of the target, because we won't change anything
  1793.      including type unless the match works */
  1794.   (void) cellcpy(&sc, cp) ;
  1795.   if ( sc.type < C_STRING ) cast1_to_s(&sc) ;
  1796.   front = string(&sc)->str ;
  1797.  
  1798.   if ( middle = REmatch(front, sp->ptr, &middle_len) )
  1799.   { 
  1800.     front_len = middle - front ;
  1801.     back = middle + middle_len ; 
  1802.     back_len = string(&sc)->len - front_len - middle_len ;
  1803.  
  1804.     if ( (sp+1)->type == C_REPLV ) 
  1805.     { STRING *sval = new_STRING((char *) 0, middle_len) ;
  1806.  
  1807.       (void) memcpy(sval->str, middle, middle_len) ;
  1808.       (void) replv_to_repl(sp+1, sval) ;
  1809.       free_STRING(sval) ;
  1810.     }
  1811.  
  1812.     tc.type = C_STRING ;
  1813.     tc.ptr = (PTR) new_STRING((char *) 0, 
  1814.              front_len + string(sp+1)->len + back_len ) ;
  1815.  
  1816.     { char *p = string(&tc)->str ;
  1817.  
  1818.       if ( front_len )
  1819.       { (void) memcpy(p, front, front_len) ;
  1820.         p += front_len ;
  1821.       }
  1822.       if ( string(sp+1)->len )
  1823.       { (void) memcpy(p, string(sp+1)->str, string(sp+1)->len) ;
  1824.         p += string(sp+1)->len ;
  1825.       }
  1826.       if ( back_len )  (void) memcpy(p, back, back_len) ;
  1827.     }
  1828.  
  1829.     if ( cp  >= field && cp < field+NUM_FIELDS )
  1830.            field_assign(cp-field, &tc) ;
  1831.     else
  1832.     { cell_destroy(cp) ;
  1833.       (void) cellcpy(cp, &tc) ;
  1834.     }
  1835.  
  1836.     free_STRING(string(&tc)) ;
  1837.   }
  1838.  
  1839.   free_STRING(string(&sc)) ;
  1840.   repl_destroy(sp+1) ;
  1841.   sp->type = C_DOUBLE ;
  1842.   sp->dval = middle != (char *) 0 ? 1.0 : 0.0 ;
  1843.   return sp ;
  1844. }
  1845.  
  1846. static  unsigned repl_cnt ;  /* number of global replacements */
  1847.  
  1848. /* recursive global subsitution 
  1849.    dealing with empty matches makes this mildly painful
  1850. */
  1851.  
  1852. static STRING *gsub( re, repl, target, flag)
  1853.   PTR  re ;
  1854.   CELL *repl ;  /* always of type REPL or REPLV */
  1855.   char *target ;
  1856.   int flag ; /* if on, match of empty string at front is OK */
  1857. { char *front, *middle ;
  1858.   STRING *back ;
  1859.   unsigned front_len, middle_len ;
  1860.   STRING  *ret_val ;
  1861.   CELL xrepl ; /* a copy of repl so we can change repl */
  1862.  
  1863.   if ( ! (middle = REmatch(target, re, &middle_len)) )
  1864.       return  new_STRING(target) ; /* no match */
  1865.  
  1866.   (void) cellcpy(&xrepl, repl) ;
  1867.  
  1868.   if ( !flag && middle_len == 0 && middle == target ) 
  1869.   { /* match at front that's not allowed */
  1870.  
  1871.     if ( *target == 0 )  /* target is empty string */
  1872.     { null_str.ref_cnt++ ;
  1873.       return & null_str ;
  1874.     }
  1875.     else
  1876.     { char xbuff[2] ;
  1877.  
  1878.       front_len = 0 ;
  1879.       /* make new repl with target[0] */
  1880.       repl_destroy(repl) ;
  1881.       xbuff[0] = *target++ ;  xbuff[1] = 0 ;
  1882.       repl->type = C_REPL ;
  1883.       repl->ptr = (PTR) new_STRING( xbuff ) ;
  1884.       back = gsub(re, &xrepl, target, 1) ;
  1885.     }
  1886.   }
  1887.   else  /* a match that counts */
  1888.   { repl_cnt++ ;
  1889.  
  1890.     front = target ;
  1891.     front_len = middle - target ;
  1892.  
  1893.     if ( *middle == 0 )  /* matched back of target */
  1894.     { back = &null_str ; null_str.ref_cnt++ ; }
  1895.     else back = gsub(re, &xrepl, middle + middle_len, 0) ;
  1896.       
  1897.     /* patch the &'s if needed */
  1898.     if ( repl->type == C_REPLV )
  1899.     { STRING *sval = new_STRING((char *) 0, middle_len) ;
  1900.  
  1901.       (void) memcpy(sval->str, middle, middle_len) ;
  1902.       (void) replv_to_repl(repl, sval) ;
  1903.       free_STRING(sval) ;
  1904.     }
  1905.   }
  1906.  
  1907.   /* put the three pieces together */
  1908.   ret_val = new_STRING((char *)0,
  1909.               front_len + string(repl)->len + back->len); 
  1910.   { char *p = ret_val->str ;
  1911.  
  1912.     if ( front_len )
  1913.     { (void) memcpy(p, front, front_len) ; p += front_len ; }
  1914.     if ( string(repl)->len )
  1915.     { (void) memcpy(p, string(repl)->str, string(repl)->len) ;
  1916.       p += string(repl)->len ;
  1917.     }
  1918.     if ( back->len ) (void) memcpy(p, back->str, back->len) ;
  1919.   }
  1920.  
  1921.   /* cleanup, repl is freed by the caller */
  1922.   repl_destroy(&xrepl) ;
  1923.   free_STRING(back) ;
  1924.  
  1925.   return ret_val ;
  1926. }
  1927.  
  1928. /* set up for call to gsub() */
  1929. CELL *bi_gsub( sp )
  1930.   register CELL *sp ;
  1931. { CELL *cp ;  /* pts at the replacement target */
  1932.   CELL sc  ;  /* copy of replacement target */
  1933.   CELL tc  ;  /* build the result here */
  1934.  
  1935.   sp -= 2 ;
  1936.   if ( sp->type != C_RE ) cast_to_RE(sp) ;
  1937.   if ( (sp+1)->type != C_REPL && (sp+1)->type != C_REPLV )
  1938.           cast_to_REPL(sp+1) ;
  1939.  
  1940.   (void) cellcpy(&sc, cp = (CELL *)(sp+2)->ptr) ;
  1941.   if ( sc.type < C_STRING ) cast1_to_s(&sc) ;
  1942.  
  1943.   repl_cnt = 0 ;
  1944.   tc.ptr = (PTR) gsub(sp->ptr, sp+1, string(&sc)->str, 1) ;
  1945.  
  1946.   if ( repl_cnt )
  1947.   { tc.type = C_STRING ;
  1948.  
  1949.     if ( cp >= field && cp < field + NUM_FIELDS )
  1950.         field_assign(cp-field, &tc) ;
  1951.     else
  1952.     { cell_destroy(cp) ; (void) cellcpy(cp, &tc) ; }
  1953.   }
  1954.  
  1955.   /* cleanup */
  1956.   free_STRING(string(&sc)) ; free_STRING(string(&tc)) ;
  1957.   repl_destroy(sp+1) ;
  1958.  
  1959.   sp->type = C_DOUBLE ;
  1960.   sp->dval = (double) repl_cnt ;
  1961.   return sp ;
  1962. }
  1963. @//E*O*F mawk0.97/bi_funct.c//
  1964. chmod u=rw,g=r,o=r mawk0.97/bi_funct.c
  1965.  
  1966. echo x - mawk0.97/bi_funct.h
  1967. sed 's/^@//' > "mawk0.97/bi_funct.h" <<'@//E*O*F mawk0.97/bi_funct.h//'
  1968.  
  1969. /********************************************
  1970. bi_funct.h
  1971. copyright 1991, Michael D. Brennan
  1972.  
  1973. This is a source file for mawk, an implementation of
  1974. the Awk programming language as defined in
  1975. Aho, Kernighan and Weinberger, The AWK Programming Language,
  1976. Addison-Wesley, 1988.
  1977.  
  1978. See the accompaning file, LIMITATIONS, for restrictions
  1979. regarding modification and redistribution of this
  1980. program in source or binary form.
  1981. ********************************************/
  1982.  
  1983.  
  1984. /* $Log:    bi_funct.h,v $
  1985.  * Revision 2.2  91/04/22  08:00:13  brennan
  1986.  * prototype for bi_errmsg() under DOS
  1987.  * 
  1988.  * Revision 2.1  91/04/08  08:22:20  brennan
  1989.  * VERSION 0.97
  1990.  * 
  1991. */
  1992.  
  1993. #ifndef  BI_FUNCT_H
  1994. #define  BI_FUNCT_H  1
  1995.  
  1996. #include "symtype.h"
  1997.  
  1998. extern BI_REC  bi_funct[] ;
  1999.  
  2000. void PROTO(bi_init, (void) ) ;
  2001.  
  2002. /* builtin string functions */
  2003. CELL *PROTO( bi_print, (CELL *) ) ;
  2004. CELL *PROTO( bi_printf, (CELL *) ) ;
  2005. CELL *PROTO( bi_length, (CELL *) ) ;
  2006. CELL *PROTO( bi_index, (CELL *) ) ;
  2007. CELL *PROTO( bi_substr, (CELL *) ) ;
  2008. CELL *PROTO( bi_sprintf, (CELL *) ) ;
  2009. CELL *PROTO( bi_split, (CELL *) ) ;
  2010. CELL *PROTO( bi_match, (CELL *) ) ;
  2011. CELL *PROTO( bi_getline, (CELL *) ) ;
  2012. CELL *PROTO( bi_sub, (CELL *) ) ;
  2013. CELL *PROTO( bi_gsub, (CELL *) ) ;
  2014.  
  2015. /* builtin arith functions */
  2016. CELL *PROTO( bi_sin, (CELL *) ) ;
  2017. CELL *PROTO( bi_cos, (CELL *) ) ;
  2018. CELL *PROTO( bi_atan2, (CELL *) ) ;
  2019. CELL *PROTO( bi_log, (CELL *) ) ;
  2020. CELL *PROTO( bi_exp, (CELL *) ) ;
  2021. CELL *PROTO( bi_int, (CELL *) ) ;
  2022. CELL *PROTO( bi_sqrt, (CELL *) ) ;
  2023. CELL *PROTO( bi_srand, (CELL *) ) ;
  2024. CELL *PROTO( bi_rand, (CELL *) ) ;
  2025.  
  2026. /* other builtins */
  2027. CELL *PROTO( bi_close, (CELL *) ) ;
  2028. CELL *PROTO( bi_system, (CELL *) ) ;
  2029.  
  2030. #if  DOS
  2031. CELL *PROTO(bi_errmsg, (CELL *) ) ;
  2032. #endif
  2033.  
  2034. #endif  /* BI_FUNCT_H  */
  2035.  
  2036. @//E*O*F mawk0.97/bi_funct.h//
  2037. chmod u=rw,g=r,o=r mawk0.97/bi_funct.h
  2038.  
  2039. echo x - mawk0.97/bi_vars.c
  2040. sed 's/^@//' > "mawk0.97/bi_vars.c" <<'@//E*O*F mawk0.97/bi_vars.c//'
  2041.  
  2042. /********************************************
  2043. bi_vars.c
  2044. copyright 1991, Michael D. Brennan
  2045.  
  2046. This is a source file for mawk, an implementation of
  2047. the Awk programming language as defined in
  2048. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2049. Addison-Wesley, 1988.
  2050.  
  2051. See the accompaning file, LIMITATIONS, for restrictions
  2052. regarding modification and redistribution of this
  2053. program in source or binary form.
  2054. ********************************************/
  2055.  
  2056. /* $Log:    bi_vars.c,v $
  2057.  * Revision 2.1  91/04/08  08:22:22  brennan
  2058.  * VERSION 0.97
  2059.  * 
  2060. */
  2061.  
  2062.  
  2063. /* bi_vars.c */
  2064.  
  2065. #include "mawk.h"
  2066. #include "symtype.h"
  2067. #include "bi_vars.h"
  2068. #include "field.h"
  2069. #include "init.h"
  2070. #include "memory.h"
  2071.  
  2072. /* the builtin variables */
  2073. CELL  bi_vars[NUM_BI_VAR] ;
  2074.  
  2075. /* the order here must match the order in bi_vars.h */
  2076.  
  2077. static char *bi_var_names[NUM_BI_VAR] = {
  2078. "ARGC" ,
  2079. "FILENAME" ,
  2080. "NR" ,
  2081. "FNR" ,
  2082. "OFS" ,
  2083. "ORS" ,
  2084. "RLENGTH" ,
  2085. "RSTART" ,
  2086. "SUBSEP",
  2087. "VERSION"
  2088. } ;
  2089.  
  2090. /* insert the builtin vars in the hash table */
  2091.  
  2092. void  bi_vars_init()
  2093. { register int i ;
  2094.   register SYMTAB *s ;
  2095.  
  2096.   for ( i = 0 ; i < NUM_BI_VAR ; i++ )
  2097.   { s = insert( bi_var_names[i] ) ;
  2098.     s->type = ST_VAR ; s->stval.cp = bi_vars + i ;
  2099.     /* bi_vars[i].type = 0 which is C_NOINIT */
  2100.   }
  2101.   /* set defaults */
  2102.  
  2103.   bi_vars[FILENAME].type = C_STRING ;
  2104.   bi_vars[FILENAME].ptr = (PTR) new_STRING( "" ) ; 
  2105.  
  2106.   bi_vars[ OFS ].type = C_STRING ;
  2107.   bi_vars[OFS].ptr = (PTR) new_STRING( " " ) ;
  2108.   
  2109.   bi_vars[ ORS ].type = C_STRING ;
  2110.   bi_vars[ORS].ptr = (PTR) new_STRING( "\n" ) ;
  2111.  
  2112.   bi_vars[ SUBSEP ].type = C_STRING ;
  2113.   bi_vars[SUBSEP].ptr =  (PTR) new_STRING( "\034" ) ;
  2114.  
  2115.   bi_vars[VERSION].type = C_STRING ;
  2116.   bi_vars[VERSION].ptr = (PTR) new_STRING( VERSION_STRING ) ;
  2117.  
  2118.   bi_vars[NR].type = bi_vars[FNR].type = C_DOUBLE ;
  2119.   /* dval is already 0.0 */
  2120.  
  2121.   cell_zero.type = C_DOUBLE ;
  2122.   cell_one.type = C_DOUBLE ;
  2123.   cell_one.dval = 1.0 ;
  2124. }
  2125.  
  2126. CELL cell_zero ;
  2127. CELL cell_one ;
  2128. @//E*O*F mawk0.97/bi_vars.c//
  2129. chmod u=rw,g=r,o=r mawk0.97/bi_vars.c
  2130.  
  2131. echo x - mawk0.97/bi_vars.h
  2132. sed 's/^@//' > "mawk0.97/bi_vars.h" <<'@//E*O*F mawk0.97/bi_vars.h//'
  2133.  
  2134. /********************************************
  2135. bi_vars.h
  2136. copyright 1991, Michael D. Brennan
  2137.  
  2138. This is a source file for mawk, an implementation of
  2139. the Awk programming language as defined in
  2140. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2141. Addison-Wesley, 1988.
  2142.  
  2143. See the accompaning file, LIMITATIONS, for restrictions
  2144. regarding modification and redistribution of this
  2145. program in source or binary form.
  2146. ********************************************/
  2147.  
  2148.  
  2149. /* $Log:    bi_vars.h,v $
  2150.  * Revision 2.1  91/04/08  08:26:30  brennan
  2151.  * VERSION 0.97
  2152.  * 
  2153. */
  2154.  
  2155.  
  2156. /* bi_vars.h */
  2157.  
  2158. #ifndef  BI_VARS_H
  2159. #define  BI_VARS_H  1
  2160.  
  2161. #define  VERSION_STRING  \
  2162.   "mawk 0.97 Mar 1991, Copyright (C) Michael D. Brennan"
  2163.  
  2164. /* If use different command line syntax for DOS
  2165.    mark that in VERSION  */
  2166.  
  2167. #if  DOS  &&  ! HAVE_REARGV
  2168. #undef   VERSION_STRING
  2169. #define  VERSION_STRING  \
  2170.   "mawk 0.97DOS Mar 1991, Copyright (C) Michael D. Brennan"
  2171. #endif
  2172.  
  2173. /* builtin variables NF, RS, FS, OFMT are stored
  2174.    internally in field[], so side effects of assignment can
  2175.    be handled 
  2176. */
  2177.  
  2178. #define  ARGC      0
  2179. #define  FILENAME  1
  2180. #define  NR        2  /* NR must be exactly one in front of FNR */
  2181. #define  FNR       3
  2182. #define  OFS       4
  2183. #define  ORS       5
  2184. #define  RLENGTH   6
  2185. #define  RSTART    7
  2186. #define  SUBSEP    8
  2187. #define  VERSION   9
  2188. #define  NUM_BI_VAR  10
  2189.  
  2190. extern CELL bi_vars[NUM_BI_VAR] ;
  2191.  
  2192.  
  2193. #endif
  2194. @//E*O*F mawk0.97/bi_vars.h//
  2195. chmod u=rw,g=r,o=r mawk0.97/bi_vars.h
  2196.  
  2197. echo x - mawk0.97/cast.c
  2198. sed 's/^@//' > "mawk0.97/cast.c" <<'@//E*O*F mawk0.97/cast.c//'
  2199.  
  2200. /********************************************
  2201. cast.c
  2202. copyright 1991, Michael D. Brennan
  2203.  
  2204. This is a source file for mawk, an implementation of
  2205. the Awk programming language as defined in
  2206. Aho, Kernighan and Weinberger, The AWK Programming Language,
  2207. Addison-Wesley, 1988.
  2208.  
  2209. See the accompaning file, LIMITATIONS, for restrictions
  2210. regarding modification and redistribution of this
  2211. program in source or binary form.
  2212. ********************************************/
  2213.  
  2214.  
  2215. /*   $Log:    cast.c,v $
  2216.  * Revision 2.1  91/04/08  08:22:44  brennan
  2217.  * VERSION 0.97
  2218.  * 
  2219. */
  2220.  
  2221.  
  2222. /*  cast.c  */
  2223.  
  2224. #include "mawk.h"
  2225. #include "field.h"
  2226. #include "memory.h"
  2227. #include "scan.h"
  2228. #include "repl.h"
  2229. #include <string.h>
  2230.  
  2231. int pow2[NUM_CELL_TYPES] = {1,2,4,8,16,32,64,128,256,512} ;
  2232.  
  2233. void cast1_to_d( cp )
  2234.   register CELL *cp ;
  2235. {
  2236.   switch( cp->type )
  2237.   { case C_NOINIT :  cp->dval = 0.0 ; break ;
  2238.  
  2239.     case C_DOUBLE :  return ;
  2240.  
  2241.     case C_MBSTRN :
  2242.     case C_STRING :  
  2243.           { register STRING *s = (STRING *) cp->ptr  ;
  2244.  
  2245. #if FPE_TRAPS  /* look for overflow error */
  2246.             errno = 0 ;
  2247.             cp->dval = strtod(s->str,(char **)0) ;
  2248.             if ( errno && cp->dval != 0.0 ) /* ignore underflow */
  2249.                 rt_error("overflow converting %s to double", s) ;
  2250. #else
  2251.             cp->dval = strtod(s->str,(char **)0) ;
  2252. #endif
  2253.             free_STRING(s) ;
  2254.           }
  2255.             break ;
  2256.  
  2257.     case C_STRNUM :  
  2258.       /* don't need to convert, but do need to free the STRING part */
  2259.             free_STRING( string(cp) ) ;
  2260.             break ;
  2261.  
  2262.  
  2263.     default :
  2264.             bozo("cast on bad type") ;
  2265.   }
  2266.   cp->type = C_DOUBLE ;
  2267. }
  2268.  
  2269. void cast2_to_d( cp )
  2270.   register CELL *cp ;
  2271. { register STRING *s ;
  2272.  
  2273.   switch( cp->type )
  2274.  
  2275.  
  2276.