1 //  This is the command interface for runoff.
  2 //  Last modified on 06/23/74 at 19:16:49 by R F Mabee.
  3 //
  4 //  Routines defined herein are:
  5 //        RunoffCommand       This implements the runoff command described in the MPM.
  6 //        RfEntry             For the command abbreviation "rf". Ugh.
  7 //        FindInput           To open an input stream. Removes .runoff suffix.
  8 //        PrintErrorFile      Dump out error messages saved during console output.
  9 //        Cleanup             Close streams, delete temporaries, etc.
 10 //  The last two mentioned are not external to this part of the program.
 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"
 19 get "head"
 20 
 21 external
 22      $(   RunoffCommand = "runoff"
 23           RfEntry = "rf"
 24           TtyInfo = "user_info_$tty_data"
 25           IosWritePtr = "ios_$write_ptr"
 26      $)
 27 global
 28      $(   Streams : 300
 29           EntryNames : 301
 30           Sn : 302
 31 
 32           ArgITS : 26                   //  Multics save sequence leaves argument list pointer here (two words).
 33      $)
 34 
 35 //  This routine is called directly from command level to execute the runoff command.
 36 //  Its parameters (all character strings) are intermingled options and pathnames of
 37 //  source files.  Its usage is described in the MPM runoff command writeup.
 38 
 39 let RunoffCommand () be main
 40      $(   MONITOR := Open (StreamName + Write, "error_output")        //  Errors, etc. written here.
 41           OUTPUT, CONSOLE, ChStream, Errorstream := 0, 0, 0, 0
 42           Errcode, ProgramID := 0, "runoff"
 43           From, To, Start, Stopsw, Charsw, Device := 1, 999999, 1, false, false, 0
 44           NoPaging, Hyphenating, Passes, Waitsw := false, false, 1, false
 45           PrintLineNumbers, ExtraMargin, Parameter := false, -1, ""
 46           NoControl, NoFill := false, false
 47           Filesw := false
 48           Streams, EntryNames, Sn := vec 100, vec 100, 0
 49           ErrorTempID := 0
 50           let Xvec = vec 10000
 51           NewvecInit (Xvec, 10000)
 52           let w = vec 2
 53           TimeNow := TimeToSeconds (RawClockTime (w))
 54 
 55           let Cvec = vec 20
 56           SetHandler ("cleanup", Cleanup, Cvec)   //  Set up for release of streams.
 57 
 58 //  Scan command arguments.
 59 
 60           ArgIndex := 1
 61           let Names = list "file", "segment", "sm", "chars", "character",
 62                               "ch", "stop", "sp", "wait", "wt",
 63                               "pagination", "pgnt", "npgn", "hyphenate", "hph",
 64                               "number", "nb", "control", "fill", "parameter",
 65                               "pm", "pass", "margin", "indent", "in",
 66                               "from", "fm", "to", "start", "page",
 67                               "pg", "ball", "bl", "device", "dv"
 68           and Pointers = list lv Filesw, lv Filesw, lv Filesw, lv Charsw, lv Charsw,
 69                               lv Charsw, lv Stopsw, lv Stopsw, lv Waitsw, lv Waitsw,
 70                               lv NoPaging, lv NoPaging, lv NoPaging, lv Hyphenating, lv Hyphenating,
 71                               lv PrintLineNumbers, lv PrintLineNumbers, lv NoControl, lv NoFill, DoParam,
 72                               DoParam, lv Passes, lv ExtraMargin, lv ExtraMargin, lv ExtraMargin,
 73                               lv From, lv From, lv To, lv Start, lv Start,
 74                               lv Start, lv Device, lv Device, lv Device, lv Device
 75           and Flags = table OptNegatable, OptNegatable, OptNegatable, OptNegatable, OptNegatable,
 76                               OptNegatable, OptNegatable, OptNegatable, OptNegatable, OptNegatable,
 77                               OptNegatable | OptNegate, OptNegatable | OptNegate, 0, OptNegatable, OptNegatable,
 78                               OptNegatable, OptNegatable, OptNegatable | OptNegate, OptNegatable | OptNegate, OptCallOut | OptGetNext,
 79                               OptCallOut | OptGetNext, OptConvert, OptConvert, OptConvert, OptConvert,
 80                               OptConvert, OptConvert, OptConvert, OptConvert, OptConvert,
 81                               OptConvert, OptConvert, OptConvert, OptConvert, OptConvert
 82 
 83           OptionParse (GetNextCommandArg, 35, Names, Pointers, Flags, DoName)
 84 
 85           if Sn = 0 do Complain ("Pathnames of input segments expected.  Options:*n^a*n^a",
 86                                  "-file  -stop  -wait  -chars  -no_pagination  -hyphenate  -number  -no_control  -no_fill",
 87                                  "-from <n>  -to <n>  -start <n>  -device <n>  -pass <n>  -margin <n>")
 88 
 89 
 90 //  Determine default device type.
 91 
 92           test Filesw
 93           then $(   if Device = 0 do Device := 202
 94                     Errorstream := MONITOR
 95                $)
 96           or   $(   OUTPUT := Open (StreamName + Write, "user_output", 1000, 0) //  Big buffer, no delimiter.
 97                     unless Errcode = 0 do Complain ("user_output")
 98                     if Device = 0 do
 99                          $(   let x, y = 0, 0
100                               call TtyInfo (lv x char 0, lv y)
101                               Device := y le 2 | y = 6 -* 963, 37
102                          $)
103                $)
104 
105           if ExtraMargin < 0 do ExtraMargin := (Device = 202 | Device = 300) & Filesw -> 20, 0
106 
107           unless Device = 1050 | Device = 2741 | Device = 963                   //  "Normal" IBM type codes.
108                | Device = 012 | Device = 015 | Device = 041           //  IBM terminal with office typewriter element.
109                | Device = 088
110                | Device = 37 | Device = 202 | Device = 300 do                   //  Full ASCII device.
111                     Complain ("Illegal device type specified.  Legal devices:*n1050 2741 37 202 300 963 012 015 041 088")
112 
113           let FromX, ToX, StartX, StopswX, CharswX, DeviceX = From, To, Start, Stopsw, Charsw, Device
114           and NoPagingX, HyphenatingX, PassesX, WaitswX = NoPaging, Hyphenating, Passes, Waitsw
115           and PrintLineNumbersX, ExtraMarginX, ParameterX = PrintLineNumbers, ExtraMargin, Parameter
116           and NoControlX, NoFillX = NoControl, NoFill
117 
118 //  Process input files, one at a time.
119 
120           for i = 1 to Sn do
121                $(   FileName := EntryNames!i
122                     if Filesw do
123                          $(   let w = vec 20
124                               OUTPUT := Open (EntryName + Write + MultiSegmentFile, Concatenate (w, 32, FileName, ".runout"))
125                               unless Errcode = 0 do Complain (w)
126                          $)
127 
128                     From, To, Start, Stopsw, Charsw, Device := FromX, ToX, StartX, StopswX, CharswX, DeviceX
129                     NoPaging, Hyphenating, Passes := NoPagingX, HyphenatingX, PassesX
130                     PrintLineNumbers, ExtraMargin := PrintLineNumbersX, ExtraMarginX
131                     Parameter := StoreString (ParameterX)
132                     NoControl, NoFill := NoControlX, NoFillX
133                     Waitsw := WaitswX | StopswX
134 
135           //  Invoke runoff main program for each source segment.
136 
137                     Roff (lv Streams!(i - 1), 1, OUTPUT)
138 
139                     if Filesw do
140                          $(   Close (OUTPUT)
141                               OUTPUT := 0
142                          $)
143 
144                     unless ChStream = 0 do
145                          $(   Close (ChStream)
146                               ChStream := 0
147                          $)
148                $)
149 
150 //  Finished with all source files, clean up and return to command level.
151 
152           if Stopsw do Wait ()
153 
154           unless Filesw do
155                $(   Close (OUTPUT)
156                     OUTPUT := 0
157                $)
158 
159           PrintErrorFile ()
160 
161           Cleanup ()
162      $)
163 and RfEntry () be main
164           Pl1Call (RunoffCommand, BCPLaddr (lv ArgITS))
165 
166 and DoName (Arg) be                     //  Called by OptionParse to process file-name argument.
167      $(   Streams!(Sn + 1) := FindInput (Arg, 0)
168           Sn := Sn + 1
169           unless Errcode = 0 do Complain ("^a.runoff", Arg)
170           let w, D, E = vec 50, vec 50, vec 10
171           SplitPathname (ExpandPathname (Arg, w), D, E)
172           EntryNames!Sn := StoreString (MakeBcplString (E, 32, w))
173      $)
174 and DoParam (Arg) be                              //  Called by OptionParse to process "-parameter" option.
175           Parameter := StoreString (Arg)
176 
177 and FindInput (Name, ParentStream) = valof                  //  BEWARE! This routine is defined to update its argument.
178      $(   let v = vec 50
179           let l = Length (Name)
180           if l ge 8 do
181                $(   Substr (v, Name, l - 6)
182                     if EqualString (v, ".runoff") do
183                          $(   Substr (v, Name, 1, l - 7)
184                               CopyString (v, Name)
185                          $)
186                $)
187 
188           Concatenate (v, 168, Name, ".runoff")
189           resultis ParentStream = 0 -> Open (PathName + Read + MultiSegmentFile, v),
190                                         Open (SearchName + Read + MultiSegmentFile, v, ParentStream)
191      $)
192 and PrintErrorFile () be
193      $(   if Errorstream = 0 | Filesw return
194           unless OUTPUT = 0 do Writeout (OUTPUT)
195           let l = StreamOffset (Errorstream)
196           Close (Errorstream)
197           Errorstream := 0
198           let v, Zero = vec 2, 0
199           call IosWritePtr (ITS (ErrorfilePointer, v), lv Zero, lv l)
200      $)
201 
202 and Cleanup () be
203      $(   while Sn > 0 do
204                $(   Sn := Sn - 1
205                     Close (Streams!(Sn + 1))
206                $)
207           unless OUTPUT = 0 | Filesw do
208                $(   ResetStream (OUTPUT, 0)
209                     Close (OUTPUT)
210                     OUTPUT := 0
211                $)
212           unless CONSOLE = 0 do Close (CONSOLE)
213           CONSOLE := 0
214           ChStream := 0
215           unless Errorstream = 0 | Filesw do Close (Errorstream)
216           Errorstream := 0
217           Close (MONITOR)
218           NewvecCleanup ()
219           unless ErrorTempID = 0 do DeleteTempSeg (ErrorTempID, "error_messages")
220      $)