home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / AWF.ZIP / PASS3 < prev    next >
Text File  |  1990-12-12  |  10KB  |  333 lines

  1. # third pass:  setting lines and pages
  2. # The input language of this pass is basically <width, word> pairs, where
  3. # "word" may have imbedded strangeness (backspaces, etc.) for font changes
  4. # and special characters.  Zero width is not special.  A third field may
  5. # appear to indicate that this is a fragment of a word that can be
  6. # hyphenated; the third field is the width of the hyphen that would have
  7. # to be added if the line broke after this fragment.
  8. # Negative widths denote special operations.  -3 is an error message, the
  9. # second field being the message.  -1 and -2 are control messages to this
  10. # pass, the difference being whether a break is implied or not.  The second
  11. # field is a message type string; more fields may appear as arguments.  The
  12. # semantics of control messages are often -- but not always! -- similar to
  13. # those of troff commands.  For example, "linelen" is .ll, but "center" is
  14. # not semantically equivalent to .ce -- it is related but more primitive.
  15. BEGIN {
  16.     # input and output details
  17.     FS = "\t"
  18.     nobreak = -1
  19.     dobreak = -2
  20.     message = -3
  21.     errs = "awf.err"    # default only, normally changed by "errsto"
  22.  
  23.     # page setup -- some are defaults only, normally altered by pass 2
  24.     nextlineno = 1
  25.     thispageno = 1
  26.     topmargin = 5
  27.     botmargin = 5
  28.     ind = 0            # current indent
  29.     tmpind = 0
  30.     pageoffset = ""        # string to emit at start of each line
  31.     nospacemode = 1
  32.     hdrs["CH"] = "- % -"
  33.     nop = split("LH,CH,RH,LF,CF,RF", hdrnames, ",")
  34.     fph = 0            # print header on first page?
  35.     fill = 1
  36.     adj = "both"
  37.     pagelen = 66
  38.     linelen = 78
  39.  
  40.     # line-builder setup
  41.     line = ""        # line so far, without padding
  42.     paddable = ""        # x means corresp. char in "line" is paddable
  43.     thislinelen = -1    # -1 means nothing there
  44.     cont = " "        # thing to append to continue line
  45.     contlen = 1
  46.     eol = ""        # thing to append to break line
  47.     eollen = 0
  48.     padfrom = "R"        # "L" or "R", alternating for river avoidance
  49.  
  50.     # many spaces, so we can use substr to get any number we need
  51.     sps = "                                                     "
  52.     sps = sps sps sps sps sps sps sps sps sps sps
  53. }
  54. {
  55.     # process word, if any, causing a break if appropriate
  56.     if ($1 >= 0 && thislinelen < 0) {    # word, and first on line
  57.         line = $2
  58.         paddable = substr(sps, 1, length($2))
  59.         thislinelen = $1
  60.     } else if ($1 >= 0 && thislinelen+contlen+$1+$3 <= linelen-ind-tmpind) {
  61.         # word, and it fits on line
  62.         line = line cont $2
  63.         if (cont == " ")
  64.             paddable = paddable "x"
  65.         else
  66.             paddable = paddable substr(sps, 1, length(cont))
  67.         paddable = paddable substr(sps, 1, length($2))
  68.         thislinelen += contlen + $1
  69.     } else if ($1 == nobreak || $1 == message)
  70.         nop = 0        # no attention (i.e. break) needed here
  71.     else if ($1 == dobreak && $2 == "need" && \
  72.                 nextlineno + $3 < pagelen + 1 - botmargin)
  73.         nop = 0        # enough space is available, no action needed
  74.     else if ($1 == dobreak && $2 == "toindent" && \
  75.                     ind + tmpind + thislinelen < ind) {
  76.         # move to indent position within line; there is room
  77.         n = ind - (ind + tmpind + thislinelen)
  78.         line = line substr(sps, 1, n)
  79.         # nothing before this is paddable
  80.         paddable = substr(sps, 1, length(line))
  81.         thislinelen += n
  82.         # prevent padding immediately after this point
  83.         cont = ""
  84.         contlen = 0
  85.     } else if (thislinelen >= 0 || ($1 == dobreak && $2 == "need")) {
  86.         # must emit output, either due to break or "need"
  87.  
  88.         # if at top of page, header
  89.         if (nextlineno == 1) {
  90.             for (i = int((topmargin-1)/2); i > 0; i--) {
  91.                 print ""
  92.                 nextlineno++
  93.             }
  94.             for (hno in hdrnames) {
  95.                 h = hdrnames[hno]
  96.                 if (hdrs[h] ~ /%/) {
  97.                     n = split(hdrs[h], t, "%")
  98.                     thispagehdrs[h] = t[1] thispageno t[2]
  99.                 } else
  100.                     thispagehdrs[h] = hdrs[h]
  101.             }
  102.             if (fph || thispageno > 1) {
  103.                 lh = thispagehdrs["LH"]
  104.                 ch = thispagehdrs["CH"]
  105.                 rh = thispagehdrs["RH"]
  106.                 lsp = int((linelen - length(lh ch rh)) / 2)
  107.                 rsp = linelen - length(lh ch rh) - lsp
  108.                 print pageoffset lh substr(sps, 1, lsp) ch substr(sps, 1, rsp) rh
  109.             } else
  110.                 print ""
  111.             nextlineno++
  112.             while (nextlineno <= topmargin) {
  113.                 print ""
  114.                 nextlineno++
  115.             }
  116.         }
  117.  
  118.         # the current line
  119.         # first, add a trailing hyphen if any
  120.         line = line eol
  121.         paddable = paddable substr(sps, 1, length(eol))
  122.         thislinelen += eollen
  123.  
  124.         # trim trailing spaces if any
  125.         while (line ~ / $/) {
  126.             line = substr(line, 1, length(line)-1)
  127.             paddable = substr(paddable, 1, length(line))
  128.             thislinelen--
  129.         }
  130.  
  131.         # print it in a suitable way
  132.         if (line == "")        # empty always prints as nothing
  133.             print ""
  134.         else if ($1 < 0 && $2 == "center") {
  135.             # center it
  136.             hsp = int((linelen - thislinelen) / 2)
  137.             if (hsp < 0)
  138.                 hsp = 0
  139.             print pageoffset substr(sps, 1, ind+tmpind+hsp) line
  140.         } else if (adj == "left" || (adj == "both" && \
  141.                     ($1 < 0 || index(paddable, "x") == 0)))
  142.             # no right-margin adjustment (disabled, inappropriate
  143.             # (line ended by break), or impossible)
  144.             print pageoffset substr(sps, 1, ind+tmpind) line
  145.         else if (adj == "both") {
  146.             # hard case -- adjust right margin
  147.             # sanity check
  148.             if (length(paddable) != length(line))    # aieeeee
  149.                 printf "awf: %f != %f!\n", length(paddable), \
  150.                             length(line) >errs
  151.  
  152.             # compute parameters
  153.             textlen = linelen - (ind+tmpind)
  154.             mustadd = textlen - thislinelen
  155.             npad = 0    # number of paddable spaces
  156.             for (tmp = paddable; (i = index(tmp, "x")) > 0; \
  157.                             tmp = substr(tmp, i+1))
  158.                 npad++
  159.             addatall = int(mustadd/npad)    # all grow this much
  160.             spall = substr(sps, 1, addatall)
  161.             nmore = mustadd - addatall*npad    # this many grow more
  162.  
  163.             # build padded output text
  164.             out = substr(sps, 1, ind+tmpind)
  165.             padno = 0
  166.             while ((i = index(paddable, "x")) > 0) {
  167.                 out = out substr(line, 1, i)
  168.                 padno++
  169.                 out = out spall
  170.                 if (padfrom == "L") {
  171.                     if (padno <= nmore)
  172.                         out = out " "
  173.                 } else {
  174.                     if (padno > npad-nmore)
  175.                         out = out " "
  176.                 }
  177.                 line = substr(line, i+1)
  178.                 paddable = substr(paddable, i+1)
  179.             }
  180.  
  181.             # print it, plus remnant not processed by loop
  182.             print pageoffset out line
  183.  
  184.             # tidy up
  185.             if (padfrom == "L")
  186.                 padfrom = "R"
  187.             else
  188.                 padfrom = "L"
  189.         }
  190.  
  191.         # tidy up after output line
  192.         nextlineno++
  193.         line = ""
  194.         paddable = ""
  195.         thislinelen = -1
  196.         tmpind = 0
  197.         nospacemode = 0
  198.  
  199.         # if we broke from a "need", go to bottom of page
  200.         if ($1 == dobreak && $2 == "need")
  201.             while (nextlineno < pagelen + 1 - botmargin) {
  202.                 print ""
  203.                 nextlineno++
  204.             }
  205.  
  206.         # footer, if at bottom of page
  207.         if (nextlineno >= pagelen + 1 - botmargin) {
  208.             for (i = int((botmargin-1)/2); i > 0; i--) {
  209.                 print ""
  210.                 nextlineno++
  211.             }
  212.             # header code prepared thispagehdrs
  213.             lf = thispagehdrs["LF"]
  214.             cf = thispagehdrs["CF"]
  215.             rf = thispagehdrs["RF"]
  216.             lsp = int((linelen - length(lf cf rf)) / 2)
  217.             rsp = linelen - length(lf cf rf) - lsp
  218.             print pageoffset lf substr(sps, 1, lsp) cf substr(sps, 1, rsp) rf
  219.             nextlineno++
  220.             while (nextlineno <= pagelen) {
  221.                 print ""
  222.                 nextlineno++
  223.             }
  224.             nextlineno = 1
  225.             thispageno++
  226.  
  227.             # after page break, should not space unnecessarily,
  228.             # and should pad first line from right
  229.             nospacemode = 1
  230.             padfrom = "R"
  231.         }
  232.  
  233.         # we are finally done with emitting output
  234.         # pick up input word, if any
  235.         if ($1 >= 0) {
  236.             line = $2
  237.             paddable = substr(sps, 1, length($2))
  238.             thislinelen = $1
  239.         }
  240.     }
  241.  
  242.     # if we broke, next line should pad from right
  243.     if ($1 == dobreak)
  244.         padfrom = "R"
  245.  
  246.     # cleanup and post-break command processing
  247.     if ($1 >= 0 || $2 == "nohyphen") {
  248.         # reset hyphenation trickery after each word (fragment)
  249.         cont = " "
  250.         contlen = 1
  251.         eol = ""
  252.         eollen = 0
  253.     } else if ($2 == "need" || $2 == "toindent")
  254.         nop = 0        # dealt with above
  255.     else if ($2 == "flush" || $2 == "center")
  256.         nop = 0        # exist only to cause break
  257.     else if ($1 == message)
  258.         print "awf: " $2 >errs
  259.     else if ($2 == "gap") {
  260.         # gap between last word and next one should be >= $3
  261.         if (thislinelen >= 0) {
  262.             line = line substr(sps, 1, $3-1)
  263.             paddable = paddable substr(sps, 1, $3-1)
  264.             thislinelen += $3-1
  265.         }
  266.     } else if ($2 == "tabto") {
  267.         # move to tab stop at $3
  268.         if (thislinelen < 0)
  269.             thislinelen = 0        # make line exist
  270.         n = $3 - thislinelen
  271.         if (n > 0) {            # must emit some space
  272.             line = line substr(sps, 1, n)
  273.             # nothing before a tab is paddable
  274.             paddable = substr(sps, 1, length(line))
  275.             thislinelen += n
  276.             # suppress space following
  277.             cont = ""
  278.             contlen = 0
  279.         }
  280.     } else if ($2 == "errsto")
  281.         errs = $3
  282.     else if ($2 ~ /^[LCR][HF]$/)
  283.         hdrs[$2] = $3
  284.     else if ($2 == "fph")
  285.         fph = $3
  286.     else if ($2 == "space") {
  287.         if (!nospacemode) {
  288.             # generate an empty line, which will be flushed by
  289.             # the next word; NB we know "space" caused a flush
  290.             line = ""
  291.             paddable = ""
  292.             thislinelen = linelen + 1
  293.             nospacemode = 0
  294.         }
  295.     } else if ($2 == "left")
  296.         adj = "left"
  297.     else if ($2 == "both")
  298.         adj = "both"
  299.     else if ($2 == "indent")
  300.         ind = $3
  301.     else if ($2 == "tempindent")
  302.         tmpind = $3
  303.     else if ($2 == "linelen")
  304.         linelen = $3
  305.     else if ($2 == "pagelen")
  306.         pagelen = $3
  307.     else if ($2 == "nospace")
  308.         nospacemode = 1
  309.     else if ($2 == "yesspace")
  310.         nospacemode = 0
  311.     else if ($2 == "hyphen") {
  312.         # discretionary hyphen at this point
  313.         cont = ""
  314.         contlen = 0
  315.         eol = $3
  316.         eollen = $4
  317.     } else if ($2 == "userhyphen") {
  318.         # user-supplied hyphen at this point
  319.         cont = $3
  320.         contlen = $4
  321.         eol = $3
  322.         eollen = $4
  323.     } else if ($2 == "pageoffset")
  324.         pageoffset = substr(sps, 1, $3)
  325.     else
  326.         print "awf: URK -- INTERNAL OPCODE `" $2 "' UNKNOWN" >errs
  327. }
  328. END {
  329.     # second pass is supposed to fake a .ne to flush the last page
  330.     if (nextlineno != 1)
  331.         print "awf: last page not flushed!" >errs
  332. }
  333.