home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3342 < prev    next >
Internet Message Format  |  1991-05-16  |  62KB

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