1 //                  ROFF for Multics
  2 //
  3 //  Last modified on 05/30/74 at 18:43:45 by R F Mabee.
  4 //
  5 //  This file contains the main routine for processing control
  6 //  lines for ROFF for Multics, and some short routines used by it.
  7 //  Routines are:
  8 //        Control             Routine to process control line.
  9 //        Set_param           Update parameter with possibly signed value.
 10 //        Number              Read numeric expression from line.
 11 
 12 //  Copyright (c) 1974 by Massachusetts Institute of Technology and Honeywell Information Systems, Inc.
 13 
 14 //  General permission is granted to copy and use this program, but not to sell it, provided that the above
 15 //  copyright statement is given.  Contact Information Processing Services, MIT, for further information.
 16 //  Please contact R F Mabee at MIT for information on this program and versions for other machines.
 17 
 18 get "runoff_head"   //  Declarations for ROFF.
 19 
 20 
 21 // Control is called with a control line in
 22 //        Rawchar[1] ... Rawchar[Nr]
 23 // when Rawchar[1] is '.' .  It processes
 24 // the control word in columns 2 and 3.
 25 
 26 let Control () be
 27 {                   // Control
 28 
 29 // Set Nrx to point to first non-blank
 30 // after column 3.  (We know column 3 is non-blank.)
 31 
 32    Nrx := 4                   // Start scan here.
 33    Nr := Nr + 1     // So characters in the last column of input can be read (kludge)
 34    while Rawchar[Nrx] ne '*s' & Nrx < Nr do Nrx := Nrx + 1
 35    while Rawchar[Nrx]  = '*s' & Nrx < Nr do Nrx := Nrx + 1
 36 
 37 // Branch, depending on the control word in columns 2 and 3.
 38 
 39    switchon (Rawchar[2]lshift ByteBits logor Rawchar[3]) into
 40    {
 41           default:  if Rawchar[2] = '**' return             //  Valid comment.
 42                     Report ("Unknown control request")
 43                     return
 44 
 45           case '** ':
 46                               return              //  Most comments.
 47 
 48           case '~ ':
 49                     if Charsw do                  //  .~ means copy line into chars file.
 50                          $(   for i = 1 to Nr - 1 do WrCh (Rawchar!i)
 51                               WrCh ('*n')
 52                          $)
 53                     return
 54 
 55           case 'ad':
 56                     Break (); Ad := true; return
 57 
 58           case 'ar':
 59                     Roman := false; return
 60 
 61           case 'bp':
 62                     Break (); Eject (); return
 63 
 64           case 'br':
 65                     Break (); return
 66 
 67           case 'cc':
 68                     test Nrx = Nr
 69                     then Spec_char := '%'
 70                     else Spec_char := Rawchar[Nrx]
 71                     return
 72 
 73           case 'ce':
 74                     Break (); Ce := Number (); Need (Ce); return
 75 
 76           case 'ch':
 77                     while Nrx < Nr do
 78                          $(   CharsTable!(Rawchar!Nrx) := Rawchar!(Nrx + 1)
 79                               Nrx := Nrx + 2
 80                          $)
 81                     return
 82 
 83           case 'ds':
 84                     Break (); Ms := 2; Need (2); return
 85 
 86           case 'ef':
 87                     Sethead (Ef); SetLinesLeft (); return
 88 
 89           case 'eh':
 90                     Sethead (Eh); return
 91 
 92           case 'eq':
 93                     //  Next n lines are equations.
 94                     Break (); Eq := Number (); Need (Eq); return
 95 
 96           case 'ex':
 97                     if Nrx < Nr do ExecuteCommand ()
 98                     return
 99 
100           case 'fh':
101                     unless Fth = 0 do Freevec (Fth)
102                     Fth := Gethead ()
103                     return
104 
105           case 'fi':
106                     Break (); unless NoFill do Fi := true; return
107 
108           case 'fo':
109                     Sethead (Ef); Sethead (Of); SetLinesLeft (); return
110 
111           case 'fr':
112                     if Rawchar[Nrx] = 'f' do { Fr := false; return }            //  Renumber on each page - _^Hfalse.
113                     if Rawchar[Nrx] = 't' do { Fr := true; return }             //  '' - _^Htrue.
114                     if Rawchar[Nrx] = 'u' do { NoFtNo := true; return }         //  Next footnote _^Hunnumbered.
115                     Fr := false
116                     return
117 
118           case 'ft':
119                     test Ft
120                     then Foot_end ()
121                     or Foot_begin ()
122                     return
123 
124           case 'gb':
125                     Skiptolabel (false)           //  Jump backwards.
126                     return
127 
128           case 'gf':
129                     Skiptolabel (true)            //  Jump forward.
130                     return
131 
132           case 'he':
133                     Sethead (Eh); Sethead (Oh); return
134 
135           case 'if':
136                     InsertFile (); return
137 
138           case 'in':
139                     // Establish indenting.
140                     Break ()
141                     Set_param (lv In, 0)
142                     Un := In
143                     return
144 
145           case 'la':
146                     return              //  Label for jumps, ignore.
147 
148           case 'li':
149                     // Treat next n lines as text.
150                     LIno := Number (); return
151 
152           case 'll':
153                     // Set line length.
154                     Set_param (lv Ll, LL_); return
155 
156           case 'ma':
157                     // Establish top and bottom margins.
158                     Set_param (lv Ma1, MA1_); Set_param (lv Ma4, MA4_)
159                     SetLinesLeft ()
160                     return
161 
162           case 'm1':
163                     // Set space above header
164                     Set_param (lv Ma1, MA1_)
165                     return
166 
167           case 'm2':
168                     // Set space below header and above text
169                     Set_param (lv Ma2,MA2_)
170                     return
171 
172           case 'm3':
173                     // Set space above footer and below text
174                     Set_param (lv Ma3,MA3_)
175                     SetLinesLeft ()
176                     return
177 
178           case 'm4':
179                     // Set space below footer
180                     Set_param (lv Ma4,MA4_)
181                     SetLinesLeft ()
182                     return
183 
184           case 'mp':
185                     //  Set multiple paging.
186                     Set_param (lv MultiplePagecount, 1)
187                     return
188 
189           case 'ms':
190                     // Set multiple spacing
191                     Break ()
192                     Set_param (lv Ms, 1)
193                     Need (2)
194                     return
195 
196           case 'na':
197                     Break (); Ad := false; return
198 
199           case 'ne':
200                     NeedSS (Number ()); return
201 
202           case 'nf':
203                     Break (); Fi := false; return
204 
205           case 'of':
206                     Sethead (Of); SetLinesLeft (); return
207 
208           case 'oh':
209                     Sethead (Oh); return
210 
211           case 'op':
212                     Break (); Eject (); Np := Np + 1 - Np rem 2; goto SetPrint
213 
214           case 'pa':
215                     // Start a new page, with designated page number.
216                     Break (); Eject ()            // Finish this page.
217                     Set_param (lv Np, Np)         // Set next page number.
218           SetPrint:
219                     NNp := Np + 1
220                     Print := Fp le Np le Lp & Passes le 1
221                     return
222 
223           case 'pi':
224                     // Leave space for a picture to be drawn.
225                     Pi := Pi + Number ()
226                     if Pi le LinesLeft do
227                          $(   Newline (Pi)
228                               Pi := 0
229                          $)
230                     return
231 
232           case 'pl':
233                     // Set up paper length.
234                     unless NoPaging do Set_param (lv Pl, PL_)
235                     SetLinesLeft ()
236                     return
237 
238 
239           case 'rd':
240                     Nr := ConsoleReadline (Rawchar)
241                     Again := true
242                     return
243 
244           case 'ro':
245                     Roman := true; return
246 
247           case 'rt':
248                     Nr := 0; Nx_close (); return
249 
250           case 'sk':
251                     NNp := NNp + Number (); return
252 
253           case 'sp':
254                     // Leave n lines blank.
255                     Break ()                      // Finish current line.
256                     if Nl = 0 do Spacing ()       // If new page, print header.
257                     Newline (MinI (Number (), LinesLeft))
258                     Need (2)
259                     return
260 
261           case 'sr':
262                     Set_ref ()
263                     return
264 
265           case 'ss':
266                     Break (); Ms := 1; Need (2); return
267 
268           case 'tr':
269                     // Modify character conversion table.
270                     while Nrx < Nr do
271                          $(   TrTable!(Rawchar!Nrx) := Rawchar!(Nrx + 1)
272                               Conv!(Rawchar!Nrx) := DeviceTable!(Rawchar!(Nrx + 1))
273                               Nrx := Nrx + 2
274                          $)
275                     return
276 
277           case 'ts':
278                     if Number () = 0 do Readline (); return           //  Conditional skip.
279 
280           case 'ty':
281                     Typeout (); return
282 
283           case 'un':
284                     // Undent next line n spaces.
285                     Break ()
286                     Un := Nrx ge Nr -> 0, In - Number ()              //  Default is undent to left margin.
287                     if Un < 0 do Un := 0
288                     return
289 
290           case 'ur':
291                     if Nrx < Nr do
292                          $(   let w = vec Maxline
293                               Nr := Use_ref (Rawchar + Nrx - 1, w, Nr - Nrx)
294                               for i = 1 to Nr do Rawchar!i := w!i
295                               Rawchar!(Nr + 1) := '*s'
296                               Again := true
297                          $)
298                     return
299 
300           case 'wt':
301                     Wait (); return
302 
303    }
304 }                   // Control
305 
306 //  This subroutine sets some parameter of runoff to either some value
307 //  or to some offset from its current value. If the operand is omitted
308 //  in the control line, the result is Default. If the operand is signed,
309 //  it is added into the old value. Otherwise the operand field value
310 //  replaces the old value.
311 //  Param is actually the lv of the cell to update.
312 //  This function returns the value of the operand field of a control line.
313 //  If the operand is omitted, it returns one.
314 and Set_param (Param, Default) be
315      $(   Check_ref ()
316           if Nrx ge Nr do
317                $(   rv Param := Default
318                     return
319                $)
320           let OldNrx = Nrx
321           let P = ReadParam (rv Param)
322           if P < 0 do P := 0
323           rv Param := P
324           Nrx := OldNrx
325      $)
326 and Number () = valof
327      $(   if Nrx ge Nr resultis 1
328           Check_ref ()
329           ExpError := false
330           let v = vec Maxline
331           let n = ReadExp (0, v)
332           if ExpError | Nrx < Nr do Report ("Malformed expression")
333           resultis n
334      $)