home *** CD-ROM | disk | FTP | other *** search
- # first pass: macro expansion and .if
- # We support macros, conditionals (of three quite limited forms), and macro
- # argument substitution.
- BEGIN {
- curmacro = ""
- macros[""] = 0 # just to make it an array
- macrolen[""] = 0 # just to make it an array
- macrotext[0] = "" # just to make it an array
- args[""] = "" # just to make it an array
- ntext = 1 # first slot in macrotext; cannot be 0
- nroffset = 0 # offset between NR and "real" line numbers
- inname = "?" # input filename
- sp = 0 # stack "pointer" (number of stacked macros)
- maxsp = 25 # limit on nesting depth
- macrostack[sp] = "" # to make it an array
- nleftstack[sp] = "" # to make it an array
- ptrstack[sp] = "" # to make it an array
- nargstack[sp] = "" # to make it an array
- argstack[sp] = "" # to make it an array
- condstack[sp] = "" # to make it an array
- }
- /^\.\^#/ { # filename and line no of next line: .^# no fn
- nroffset = (NR+1) - $2
- inname = $3
- print
- next
- }
- /^\.de/ { # macro start
- curmacro = "." $2
- macros[curmacro] = ntext
- macrostart = ntext
- next
- }
- curmacro != "" && $0 !~ /^\.\.$/ { # macro text - \\ becomes \
- if ($0 !~ /\\/) # quick case, no backslashes
- line = $0
- else {
- line = ""
- for (n = 1; n <= length; n++) {
- if (substr($0, n, 2) == "\\\\")
- n++
- line = line substr($0, n, 1)
- }
- }
- macrotext[ntext++] = line
- next
- }
- curmacro != "" && $0 ~ /^\.\.$/ { # macro end
- macrolen[curmacro] = ntext - macrostart
- curmacro = ""
- print ".^#", NR - nroffset + 1, inname
- next
- }
- $0 ~ /^\./ && ( macros[$1] != 0 || $0 ~ /^\.(i[ef]|el)/ ) {
- # something that needs attention
- print ".^=", NR - nroffset, inname
- line = $0
- nleft = 0
- macro = "<none>"
- nargs = 0
-
- while (line != "") {
- # conditionals; note that 1-n is !n (awk doesn't have !)
- invert = 0
- if (line ~ /^\.i[ef] !/)
- invert = 1
- prevcond = cond
- cond = 0
- if (line !~ /^\.(i[ef]|el)/) { # not conditional
- cond = 1
- iflen = 0
- } else if (line ~ /^\.i[ef] !?\\n\(\.\$[<=>][0-9] /) {
- # arithmetic comparison on arg count
- iflen = length(".if .n(.$=x ") + invert
- n = substr(line, iflen-1, 1) + 0
- op = substr(line, iflen-2, 1)
- if (op == "=" && nargs == n)
- cond = 1
- else if (op == "<" && nargs < n)
- cond = 1
- else if (op == ">" && nargs > n)
- cond = 1
- } else if (line ~ /^\.i[ef] !?'\\\$[0-9]'[^']*' /) {
- # string equality on argument
- iflen = length(".if '.$n'") + invert
- n = substr(line, iflen-1, 1)+0
- if (n <= nargs)
- s1 = args[n]
- else
- s1 = ""
- i = index(substr(line, iflen+1), "'")
- s2 = substr(line, iflen+1, i-1)
- iflen += i+1
- if (s1 == s2)
- cond = 1
- } else if (line ~ /^\.i[ef] !?[nt] /) {
- # nroff vs troff
- iflen = length(".if n ") + invert
- if (substr(line, iflen-1, 1) == "n")
- cond = 1
- } else if (line ~ /^\.el /) {
- cond = 1 - prevcond
- iflen = length(".el ")
- } else {
- line = ".tm unknown .if/.ie form: " line
- cond = 1
- iflen = 0
- }
- if (invert)
- cond = 1 - cond
- if (cond && iflen > 0) # trim true conditional off
- line = substr(line, iflen+1)
-
- # do argument substitution, if necessary
- if (cond && line ~ /\\\$/) {
- orig = line
- line = ""
- for (pos = index(orig, "\\$"); pos > 0; \
- pos = index(orig, "\\$")) {
- if (pos > 1)
- line = line substr(orig, 1, pos-1)
- c = substr(orig, pos+2, 1)
- if (c ~ /[0-9]/ && c+0 <= nargs)
- line = line args[c+0]
- orig = substr(orig, pos+3)
- }
- line = line orig # the remnant
- }
-
- # is it an nroff command?
- if (cond && line ~ /^\./) {
- cmd = substr(line, 1, 3)
- while (cmd ~ / $/)
- cmd = substr(cmd, 1, length(cmd)-1)
- } else
- cmd = ""
-
- # deal with it
- if (!cond)
- nop = 0 # nothing
- else if (cmd == "" || macros[cmd] == 0)
- print line # not a nested macro
- else if (sp >= maxsp)
- print ".tm macros nested too deeply (" sp " levels)"
- else { # nesting
- # stack old one
- sp++
- nleftstack[sp] = nleft
- ptrstack[sp] = ptr
- macrostack[sp] = macro
- nargstack[sp] = nargs
- condstack[sp] = cond
- for (i = 1; i <= nargs; i++)
- argstack[sp ":" i] = args[i]
-
- # start new one, mostly pulling arguments apart
- macro = cmd
- nleft = macrolen[macro]
- ptr = macros[macro]
- cond = 0
- argno = 1
- pos = length(macro) + 1
- for (;;) {
- while (substr(line, pos, 1) ~ /[ \t]/)
- pos++
- if (pos > length(line))
- break # NOTE BREAK OUT
- arg = ""
- if (substr(line, pos, 1) == "\"") {
- pos++
- while (substr(line, pos, 1) ~ /[^"]/) {
- arg = arg substr(line, pos, 1)
- pos++
- }
- pos++
- } else
- while (substr(line, pos, 1) ~ /[^ \t]/) {
- arg = arg substr(line, pos, 1)
- pos++
- }
- args[argno++] = arg
- }
- nargs = argno - 1
- }
-
- # clean up any completed macros
- while (nleft <= 0 && sp > 0) {
- nleft = nleftstack[sp]
- ptr = ptrstack[sp]
- macro = macrostack[sp]
- nargs = nargstack[sp]
- cond = condstack[sp]
- for (i = 1; i <= nargs; i++)
- args[i] = argstack[sp ":" i]
- sp--
- }
-
- # finally, get next line
- if (nleft > 0) {
- line = macrotext[ptr++]
- nleft--
- } else
- line = "" # signal loop to terminate
- }
-
- print ".^#", NR - nroffset + 1, inname
- next
- }
- {
- # it's ordinary
- print
- }
-