home *** CD-ROM | disk | FTP | other *** search
- # second pass: interpretation of directives
- # A macro-set-specific portion gets interpolated into this at the "#include"
- # line. As a minimum, it must deal with .^b and .^e and with any input traps.
- BEGIN {
- # stuff for output to third pass
- nobreak = -1
- dobreak = -2
- message = -3
- OFS = "\t"
-
- # special-character table; this one character needs to be hardcoded
- chars[" "] = " " ; charwidths[" "] = 1
-
- debug["e"] = 0 # just to make it an array
- strings["a"] = "" # just to make it an array
- numbers["a"] = 0 # just to make it an array
- hyphens["a"] = "" # just to make it an array
- hyphenwidths["a"] = "" # just to make it an array
-
- # stuff for expression decoding
- signfactor["+"] = 1
- signfactor["-"] = -1
- scale["i"] = 240
- scale["c"] = 240*50/127
- scale["P"] = 240/6
- # we get m, n, and v when we see .^r
- scale["p"] = 240/72
- scale["u"] = 1
-
- # stuff for basic parameters that just get passed to third pass
- parms["in"] = 0 # just to make it an array
- prevparms["in"] = 0 # just to make it an array
- setcmd["ll"] = "linelen"
- setcmd["in"] = "indent"
- setcmd["ti"] = "tempindent"
- setcmd["po"] = "pageoffset"
- setcmd["pl"] = "pagelen"
-
- # did last word end with \c ? (in which case, it's still in "word")
- backc = 0
-
- # stuff for error reporting
- il = 0 # input line number
- lockil = 0 # il is locked, we're inside a macro
- inname = "?" # input filename
- msg = message "\t" # later picks up filename etc.
-
- # current input trap
- afternext = ""
- }
- {
- if (!lockil)
- il++
- msg = message "\t" inname "," il ": "
- # fallthrough
- }
- /^[ \t]*$/ { # empty line
- print dobreak, "space"
- next
- }
- /^[ \t]/ { # line starting with white space
- print dobreak, "flush"
- print 0, "" # empty word
- # fallthrough
- }
- /^[^.]/ { # text
- # dispose of the easy case
- if (font == "R" && $0 !~ /\\|\t|-| / && !backc && afternext == "") {
- for (i = 1; i <= NF; i++)
- print length($i), $i
- if ($0 ~ /[.!?:][\])'"*]*$/)
- print nobreak, "gap", 2
- if (centering > 0) {
- print dobreak, "center"
- centering--
- } else if (!fill)
- print dobreak, "flush"
- next
- }
-
- # the hard case, needs a character-by-character scan
- s = $0 " " # the space flushes the last word
- n = 1 # current position in s
- inword = 0 # have we been processing a word?
- period = "" # "." if this word ended a sentence
- nsp = 0 # count of spaces seen so far
- tabpos = 0 # which tab position was used last
- while (n <= length(s)) {
- c = substr(s, n, 1)
-
- # handle state transitions
- if (c == " " || c == "\t") {
- if (inword) { # ends word
- if (!backc) {
- print wordlen, word
- if (usedhyphen)
- print nobreak, "nohyphen"
- }
- inword = 0
- nsp = 0
- }
- } else {
- if (!inword) { # begins word
- if (!backc) {
- word = ""
- wordlen = 0
- usedhyphen = 0
- }
- backc = 0
- inword = 1
- if (nsp > 1)
- print nobreak, "gap", nsp
- }
- }
-
- # deal with the character
- if (c == " ") {
- nsp++
- if (n != length(s)) # not the trailing flusher
- period = ""
- } else if (c == "\t") {
- # not really right, should be based on input position
- # also, one space following tab gets ignored
- tabpos++
- if (tabpos <= ntabs)
- print nobreak, "tabto", tabs[tabpos]
- nsp = 0
- period = ""
- } else if (c == "-" && wordlen > 0) {
- # hyphen within word
- print wordlen, word, hyphenwidths[font]
- print nobreak, "userhyphen", hyphens[font], hyphenwidths[font]
- word = ""
- wordlen = 0
- period = ""
- usedhyphen = 1
- } else if (c != "\\") {
- # ordinary character
- if (font == "B")
- word = word c "\b" c "\b" c
- else if (font == "I" && c ~ /[a-zA-Z0-9]/)
- word = word "_\b" c
- else
- word = word c
- wordlen++
- if (c ~ /[.!?:]/)
- period = "."
- else if (c !~ /[\])'"*]/)
- period = ""
- } else { # backslash
- n++
- c = substr(s, n, 1)
- if (c == "f") {
- # font change
- n++
- code = substr(s, n, 1)
- if (code == "(") {
- n++
- code = substr(s, n, 2)
- n++
- }
- if (code == "P")
- font = prevfont
- else if (fontok[code] == "")
- print msg "unknown font `" code "'"
- else {
- prevfont = font
- font = code
- }
- } else if (c == "n") {
- # number-register value
- n++
- code = substr(s, n, 1)
- if (code == "(") {
- n++
- code = substr(s, n, 2)
- n++
- }
- s = substr(s, 1, n) numbers[code] substr(s, n+1)
- } else if (c == "s") {
- # size change
- n++
- if (substr(s, n, 1) ~ /[0-9]/)
- n++
- # just ignore it
- } else if (c == "c")
- # word continuation
- backc = 1
- else if (c == "*") {
- # string-variable value
- n++
- code = substr(s, n, 1)
- if (code == "(") {
- n++
- code = substr(s, n, 2)
- n++
- }
- s = substr(s, 1, n) strings[code] substr(s, n+1)
- } else if (c == "%") {
- # discretionary hyphen
- if (wordlen > 0) {
- print wordlen, word, hyphenwidths[font]
- print nobreak, "hyphen", hyphens[font], hyphenwidths[font]
- word = ""
- wordlen = 0
- usedhyphen = 1
- }
- } else if (c == "(" && substr(s, n+1, 2) == "em" && \
- chars["em"] != "") {
- # em-dash, special case due to hyphenation
- n += 2
- emw = charwidths["em"]
- print wordlen, word, emw
- print nobreak, "userhyphen", chars["em"], emw
- word = ""
- wordlen = 0
- period = ""
- usedhyphen = 1
- } else {
- # special-character name
- code = c
- if (code == "(") {
- n++
- code = substr(s, n, 2)
- n++
- }
- word = word chars[code]
- wordlen += charwidths[code]
- period = ""
- }
- }
-
- # on to the next character, at last
- n++
- }
-
- # end-of-line processing
- if (!backc) {
- if (period == ".")
- print nobreak, "gap", 2
- if (centering > 0) {
- print dobreak, "center"
- centering--
- } else if (!fill)
- print dobreak, "flush"
- }
-
- # if no input trap, we're done
- if (afternext == "")
- next
-
- # if there is an input trap, fall into the macro-dependent section
- }
- #
- #
- #
- # at this point we plug in the macro-specific stuff, keyed on the next line
- #include note that this is an awk comment
- #
- #
- #
- /^\.it/ { # plant an input trap, sort of
- if (NF > 1 && $2 != 1)
- print msg ".it first argument must be 1"
- if (NF > 2)
- afternext = afternext "," $3
- else
- afternext = ""
- next
- }
- /^\.\^r cpi / { # set resolutions, in cpi: .^r cpi hor vert
- scale["m"] = 240/$3
- scale["n"] = 240/$3
- scale["v"] = 240/$4
- next
- }
- /^\.(ta|ll|in|ti|po|ne|sp|pl|nr)/ { # expression processing
- # sort out default scale factor
- if ($1 ~ /^\.(ne|sp|pl)/)
- exprscale = "v"
- else if ($1 ~ /^\.(nr)/)
- exprscale = "u"
- else
- exprscale = "n"
-
- # which argument should we start with?
- offset = length($1) + 1
- if ($1 == ".nr")
- offset += length($2) + 1
-
- # beginning of debugging message
- if (debug["e"])
- printf "%s ", msg substr($0, 1, offset)
-
- # do the expressions
- s = substr($0, offset+1)
- n = 1
- while (s != "") {
- while (s ~ /^[ \t]/)
- s = substr(s, 2)
-
- # an initial sign is magic
- ssign = ""
- if (s ~ /^[+-]/) {
- ssign = substr(s, 1, 1)
- s = substr(s, 2)
- }
- s = "+" s # this is an un-magic addition operator
-
- # process terms
- sval = 0
- # there is no portable way to put a slash in a regexp
- while (s ~ /^[+*%)-]/ || substr(s, 1, 1) == "/") {
- # figure out what it is and what it contributes
- if (debug["e"] > 1)
- print "s=`" s "'"
- termop = substr(s, 1, 1)
- s = substr(s, 2)
- termscale = exprscale
- if (termop == ")") {
- if (debug["e"] > 1)
- print "pop " valstack[vsp] " " opstack[vsp] " with " sval
- termval = sval
- sval = valstack[vsp]
- termop = opstack[vsp]
- vsp--
- termscale = "u"
- } else if (s ~ /^\(/) {
- if (debug["e"] > 1)
- print "push " sval " " termop
- vsp++
- valstack[vsp] = sval
- opstack[vsp] = termop
- sval = 0
- termop = "+" # dummy op and value
- termval = 0
- s = "+" substr(s, 2)
- } else if (s ~ /^\\w/) {
- delim = substr(s, 3, 1)
- s = substr(s, 4)
- endp = index(s, delim)
- if (endp == 0)
- endp = length(s) + 1
- termval = (endp - 1) * scale["n"] # crude
- s = substr(s, endp+1)
- } else if (s ~ /^\\n/) {
- if (s ~ /^\\n\(/) {
- code = substr(s, 4, 2)
- s = substr(s, 6)
- } else {
- code = substr(s, 3, 1)
- s = substr(s, 4)
- }
- termval = numbers[code]
- } else if (s ~ /^[0-9.]/) {
- for (endp = 1; endp <= length(s); endp++)
- if (substr(s, endp, 1) !~ /[0-9.]/)
- break
- termval = substr(s, 1, endp-1) + 0
- s = substr(s, endp)
- }
-
- # add it in, with scaling factor
- c = substr(s, 1, 1)
- if (scale[c] != "") {
- termval *= scale[c]
- s = substr(s, 2)
- } else
- termval *= scale[termscale]
- if (termop == "+")
- sval += termval
- else if (termop == "-")
- sval -= termval
- else if (termop == "*")
- sval *= termval
- else if (termop == "/")
- sval = int(sval) / int(termval)
- else if (termop == "%")
- sval = int(sval) % int(termval)
- }
-
- # remember the value, print if debugging
- expr[n] = sval
- exprsign[n] = ssign
- iexpr[n] = signfactor[ssign] * sval # convenience
- if (debug["e"])
- printf "%s ", ssign "(" sval ")"
-
- # proceed to next, skipping trash if necessary
- while (s ~ /^[^ \t]/)
- s = substr(s, 2)
- n++
- }
-
- # final cleanup
- nexprs = n - 1
- if (debug["e"])
- printf "\n"
-
- # fallthrough
- }
- /^\.(ll|in|ti|po|pl)/ { # common code for set-parameter requests
- # relies on expression processing, including setting of exprscale
- name = substr($1, 2, 2)
- n = parms[name]
- if (nexprs == 0)
- n = prevparms[name]
- else if (exprsign[1] == "" || name == "ti")
- n = expr[1] / scale[exprscale]
- else
- n += iexpr[1] / scale[exprscale]
- prevparms[name] = parms[name]
- parms[name] = int(n)
- print dobreak, setcmd[name], parms[name]
- next
- }
- /^\.nr/ {
- # relies on expression processing
- n = numbers[$2]
- if (exprsign[1] == "")
- n = expr[1]
- else
- n += iexpr[1]
- numbers[$2] = int(n)
- next
- }
- /^\.ne/ {
- # relies on expression processing
- print dobreak, "need", int(expr[1]/scale["v"] + 0.99)
- next
- }
- /^\.sp/ {
- # relies on expression processing
- if (nexprs == 0)
- i = 1
- else
- i = int(expr[1]/scale["v"] + 0.99)
- for (; i > 0; i--)
- print dobreak, "space"
- next
- }
- /^\.ta/ {
- # relies on expression processing
- tabstop = 0
- for (n = 1; n <= nexprs; n++) {
- if (exprsign[n] == "")
- tabstop = expr[n]
- else
- tabstop += iexpr[n]
- tabs[n] = int(tabstop/scale["n"])
- }
- ntabs = nexprs
- next
- }
- /^\.ft/ {
- if (NF > 1)
- code = $2
- else
- code = "P"
-
- if (code == "P")
- font = prevfont
- else if (fontok[code] == "")
- print msg "unknown font `" code "'"
- else {
- prevfont = font
- font = code
- }
- next
- }
- /^\.br/ {
- print dobreak, "flush"
- next
- }
- /^\.ds/ {
- # note, macro-set-specific code often looks at .ds as well
- if ($3 !~ /^"/)
- strings[$2] = $3
- else
- strings[$2] = substr($0, index($0, "\"")+1)
- next
- }
- /^\.ns/ {
- print nobreak, "nospace"
- next
- }
- /^\.rs/ {
- print nobreak, "yesspace"
- next
- }
- /^\.ad/ {
- print nobreak, "both"
- next
- }
- /^\.na/ {
- print nobreak, "left"
- next
- }
- /^\.nf/ {
- fill = 0
- print dobreak, "flush"
- next
- }
- /^\.fi/ {
- fill = 1
- print dobreak, "flush"
- next
- }
- /^\.\^x/ { # direct errors to this file: .^x filename
- print nobreak, "errsto", $2
- next
- }
- /^\.\^c/ { # define character: .^c name width text
- if ($4 ~ /^"/)
- s = substr($0, index($0, "\"")+1)
- else
- s = $4
- ns = ""
- while ((n = index(s, "\\")) > 0) {
- if (n > 1)
- ns = ns substr(s, 1, n-1)
- n++
- c = substr(s, n, 1)
- if (c == "\\")
- ns = ns "\\"
- else if (c == "b")
- ns = ns "\b"
- s = substr(s, n+1)
- }
- ns = ns s
- if ($2 == "hy") {
- hyphens[font] = ns
- hyphenwidths[font] = $3
- } else {
- chars[$2] = ns
- charwidths[$2] = $3
- }
- next
- }
- /^\.\^f/ { # this font is okay: .^f fontname
- # someday, this might take font-change codes as further arguments
- fontok[$2] = "yes"
- next
- }
- /^\.tm/ {
- print msg $0
- next
- }
- /^\.ps/ {
- # ignore
- next
- }
- /^\.ce/ {
- if (NF > 1)
- centering = $2
- else
- centering = 1
- next
- }
- /^\.bp/ {
- print dobreak, "need", 999
- next
- }
- /^\.\^d/ { # debug control: .^d debugvar value
- debug[$2] = $3
- next
- }
- /^\.\^#/ { # set line number of next line: .^# no file
- il = $2 - 1
- lockil = 0
- inname = $3
- next
- }
- /^\.\^=/ { # lock line number to value: .^= no file
- il = $2
- lockil = 1
- inname = $3
- next
- }
- /^\.\\"/ { # comment
- next
- }
- /^\./ {
- print msg "command `" $1 "' unsupported or unknown"
- }
- END {
- print dobreak, "need", 999 # flush page
- }
-