|
|
1.1 root 1: -IN132
2: -TITLE MACRO TEXT PROCESSOR V780-6.12
3: * This program is a document processor based on the principles of
4: * C. Strachey's GPM. All text processor commands consist
5: * of macro calls embedded in the string of text.
6: * There is a reference document which should be consulted for
7: * detailed explanation.
8: *
9: * Neither the author nor any institution which the author may represent
10: * assumes any liability with respect to the use of this program,
11: * or makes any representations as to its fitness or merchantability
12: * for a particular purpose.
13: *
14: * Steven G. Duff
15: * Santa Fe Engineering Services Co.
16: * Research and Development Ax/1
17: * 505 South Main Street
18: * Orange, California 92668 USA
19: * (714) 558-1300
20: *
21: -STITL REVISION HISTORY
22: *
23: * o Rev. 6.12 28-APR-1982 [SGD]:
24: * o Made some rearrangements to startup processing and messages.
25: *
26: * o Rev. 6.11 26-APR-1982 [SGD]:
27: * o Startup command line now processed differently, also errors in
28: * built-in function file now reported.
29: *
30: * o Rev. 6.10 18-JAN-1982 [SGD]:
31: * o Changed interpretation of {D mname}, where mname is a system
32: * macro. This now is the same as {Mname} (rather than "SYSTEM").
33: *
34: * o Rev. 6.02 13-NOV-1981 [SGD]:
35: * o Added BIAS macro.
36: *
37: * o Rev. 6.01 22-SEP-1981 [SGD]:
38: * o Added SKIPTEXT function and macro.
39: * o Modified READ() to use SKIPTEXT() for BEGINTEXT operation.
40: * o Added QUERY output association for prompting.
41: *
42: -STITL PATTERN DEFINITION AND INITIALIZATION
43: * !!!WARNING!!! Note that this initializing code must not contain
44: * any labels, as they would prevent the code blocks from being
45: * garbage collected later.
46: *
47: * To tailor for an individual system, the following initializations
48: * are especially important. The READ function will have to be
49: * modified, and the startup code which contains some I/O
50: * associations will have to be changed.
51: *
52: &TRIM = 1; &ANCHOR = 1; &STLIMIT = 999999999
53: &ALPHABET BREAK('A') LEN(26) . UPLETS BREAK('a') LEN(26) . LOWLETS
54: *
55: * MINLU and MAXLU set the limits on the input logical unit stack.
56: * OUTUNIT is the lun used for output.
57: * QUERYUNIT is the lun used for prompts.
58: *
59: MINLU = 2
60: MAXLU = 15
61: OUTUNIT = 1
62: QUERYUNIT = 16
63: *
64: * BIFFILE is the filespec of the Built-in Function File, read in at startup.
65: * USERSTART gives the spec for the user's autoload library (no error is
66: * issued if this is not found at startup.
67: * The INITIAL... files are the filespecs initially assigned for I/O.
68: * INITIAL_INPUT should be the pre-association for TERMINAL. If not, the
69: * startup message section will have to be patched up.
70: *
71: BIFFILE = 'GPMBIF.GPM'
72: USERSTART = 'GPMSTART'
73: INITIAL_INPUT = '/dev/tty'
74: INITIAL_OUTPUT = '/dev/tty'
75: -EJECT
76: *
77: * BS is the backspace character. It should only be possible to generate
78: * this character with the system function OVER, as other routines assume
79: * a certain 'normalized' distribution of backspaces (see OVER). If no
80: * 'non-normal' characters exist in the host machine character set to be
81: * used for BS, then it should be translated out in GETLINE.
82: *
83: * CS is the control sequence character. It should only be possible to
84: * generate this character with the system function CONTROL_SEQ, as
85: * there is a standard 'normalized' form for these also. A control sequence
86: * is a string that is emitted to the device, but does not figure in
87: * line size computations.
88: *
89: BS = SUBSTR(&ALPHABET,255,1)
90: CS = SUBSTR(&ALPHABET,254,1)
91: BSPATT = BREAK(BS)
92: *
93: * CR is the character used to move to the beginning of a line image, and
94: * LF is used to move to the next physical print line.
95: *
96: &ALPHABET LEN(10) LEN(1) . LF LEN(2) LEN(1) . CR
97: CRLF = CR LF
98: *
99: * COMPLEXLIM is used to compare against &FNCLEVEL in the macro call circuit.
100: * When the function nesting reaches this limit, GPMDOC signals an error
101: * It should be set so that a SPITBOL stack overflow with its attendant
102: * unplesantness cannot occur.
103: *
104: COMPLEXLIM = 1000
105: *
106: * NCSW is the string which, when appended to filenames on OUTPUT calls
107: * will suppress implied carriage control. GPMDOC instead uses
108: * CR, and CRLF combinations at the end of output records explicitly.
109: * This is necessary to support overstrikes.
110: *
111: NCSW = ;* this used to be '/NOCR'
112: -STITL COMMON STRING INITIALIZATION
113: * The reason for the table below is to provide a common string value for
114: * strings referenced within the interpreter. As SPITBOL does not hash
115: * strings, if this were not done, space in dynamic would be lost to multiple
116: * copies of the same strings. At the end of initialization, we set H to
117: * null, effectively losing the table, and as all the initialization code
118: * is also garbage collected away, all string indexes in H are discarded too.
119: * Thus we are left with a single copy of the string. For strings which have
120: * name with the same text (either functions or variables), we use a CONVERT
121: * of the name to string to gain access to the string referenced by the name.
122: * This may seem involved, but it reclaims a substantial amount of space that
123: * would otherwise be wasted, and space is at a premium in some versions.
124: *
125: H = TABLE(31)
126: H['BEGINTEXT'] = CONVERT(.BEGINTEXT,.STRING)
127: H['BIAS'] = CONVERT(.BIAS,.STRING)
128: H['BSLACK'] = CONVERT(.BSLACK,.STRING)
129: H['CODE'] = CONVERT(.CODE,.STRING)
130: H['COND'] = CONVERT(.COND,.STRING)
131: H['DIFFER'] = CONVERT(.DIFFER,.STRING)
132: H['DOPROP'] = CONVERT(.DOPROP,.STRING)
133: H['DOWHILE'] = CONVERT(.DOWHILE,.STRING)
134: H['END'] = CONVERT(.END,.STRING)
135: H['ENDTEXT'] = CONVERT(.ENDTEXT,.STRING)
136: H['FILL'] = CONVERT(.FILL,.STRING)
137: H['HS'] = CONVERT(.HS,.STRING)
138: H['IDENT'] = CONVERT(.IDENT,.STRING)
139: H['INFORMAT'] = CONVERT(.INFORMAT,.STRING)
140: H['INPUT'] = CONVERT(.INPUT,.STRING)
141: H['JUST'] = CONVERT(.JUST,.STRING)
142: H['LINELENGTH'] = CONVERT(.LINELENGTH,.STRING)
143: H['LINENUM'] = CONVERT(.LINENUM,.STRING)
144: H['LMG'] = CONVERT(.LMG,.STRING)
145: H['NEWLINE'] = CONVERT(.NEWLINE,.STRING)
146: H['OUTOS'] = CONVERT(.OUTOS,.STRING)
147: H['OUTPUT'] = CONVERT(.OUTPUT,.STRING)
148: H['PAGELENGTH'] = CONVERT(.PAGELENGTH,.STRING)
149: H['PRINT'] = 'PRINT'
150: H['RESTORE'] = CONVERT(.RESTORE,.STRING)
151: H['RMG'] = CONVERT(.RMG,.STRING)
152: H['SET'] = CONVERT(.SET,.STRING)
153: H['SETQ'] = 'SETQ'
154: H['SETV'] = 'SETV'
155: H['SKIPTEXT'] = CONVERT(.SKIPTEXT,.STRING)
156: H['SPACING'] = CONVERT(.SPACING,.STRING)
157: H['TSET'] = CONVERT(.TSET,.STRING)
158: H['TSETQ'] = 'TSETQ'
159: H['TSETV'] = 'TSETV'
160: H['{'] = '{'
161: H['}'] = '}'
162: H['<'] = '<'
163: H['>'] = '>'
164: *
165: * The blank is referenced frequently outside of the initializing code,
166: * so we give it permanent status
167: *
168: SP = ' '
169: -STITL FUNCTION DEFINITION AND FUNCTION DATA
170: DEFINE('COND()T')
171: *
172: DEFINE('CONTROL_SEQ(STR)T')
173: *
174: DEFINE('DIAG(FNAME,TAG)OLDEXIT,CARD')
175: *
176: DEFINE('DOPROP(PROP,BODY,ORDER)T,I,ARGLIST')
177: *
178: DEFINE('DOWHILE(PRED,BODY)')
179: *
180: DEFINE('DUMPTEXT(STR)IMAGES,I')
181: *
182: DEFINE('END()')
183: *
184: DEFINE('GETLINE()T')
185: GL.P1 = RTAB(1) . GETLINE '-'
186: GL.P2 = SPAN(SP ' ')
187: *
188: DEFINE('GPMIFY(MSTR,ARGLIST)POS,PREFIX,QS')
189: QSPOS = ((H['<'] *QBAL $ QS H['>']) | H['<'] $ QS) @POS
190: QBAL = BREAK('<>') ((H['<'] *QBAL H['>'] *QBAL) | '')
191: NULLARGS = TABLE(3)
192: GPMSTRING = TAB(*POS) BREAKX('{<') $ PREFIX
193: + ((H['{'] @POS *?(GPMIFY = GPMIFY PREFIX MACCALL())) |
194: + (*QSPOS *?(GPMIFY = GPMIFY PREFIX QS)))
195: + *GPMSTRING |
196: + *?(GPMIFY = GPMIFY SUBSTR(MSTR,POS + 1,SIZE(MSTR) - POS))
197: *
198: DEFINE('GPMPRINT(MSTR,ARGLIST)POS,PREFIX,QS')
199: GPMSTRPNT = TAB(*POS) BREAK('{<') $ PREFIX
200: + *(IDENT(PREFIX),PUTCHARS(PREFIX))
201: + ((H['{'] @POS *MACCALL(1)) | (*QSPOS *PUTCHARS(QS)))
202: + *GPMSTRPNT |
203: + *PUTCHARS(SUBSTR(MSTR,POS + 1,SIZE(MSTR) - POS))
204: -EJECT
205: DEFINE('IMAGES(STR)I,T,POS,COUNT')
206: IM.P1 = TAB(*POS)
207: + ((BREAK(BS CS) $ T *?(COUNT = COUNT + SIZE(T))
208: + *?(IMAGES[0] = IMAGES[0] T)
209: + ((BS ('' $ I) *IM.P2) | (CS BS *IM.P3)) @POS *IM.P1) | '')
210: IM.P2 = LEN(1) $ T
211: + *?(IMAGES[I = I + 1] = RPAD(IMAGES[I],COUNT - 1) T)
212: + ((BS *IM.P2) | '')
213: IM.P3 = (NOTANY(CS) $ T BS *?(IMAGES[0] = IMAGES[0] T) *IM.P3) | ''
214: *
215: DEFINE('IN_SET(TS,INNAME)NEW_INUNIT,ISNAME,ISVALUE,ISINDEX')
216: IS_ALPATT = BREAK('=') . ISNAME LEN(1) REM . ISVALUE
217: *
218: DEFINE('IN_READ(INUNIT,INNAME)INSET_PEND')
219: *
220: DEFINE('JUST(JUST,LEN,T)POS,PREFIX')
221: JU.P1 = *GE(LEN = LEN - 1) ((TAB(*POS) | TAB(POS = 0)) LEN(1)
222: + BREAK(SP) SPAN(SP)) . PREFIX @POS
223: *
224: DEFINE('LSIZE(STR)T')
225: *
226: DEFINE('LSUBSTR(STR,N,LEN)T')
227: LS.P1 = LEN(1) ((BS (*LS.P1 | '')) | *?(T = T + 1))
228: LS.P2 = ARBNO(LS.P1) *EQ(T,N - 1) *?(T = 0) ARBNO(LS.P1) . LSUBSTR
229: + *EQ(T,LEN)
230: *
231: DEFINE('MACCALL(PFLG)AL1,AL2,AL,T,MACNAME,MACRO,STPOS,SETNAME'
232: + ',SETTYPE,QN,ARG')
233: MC.P1 = TAB(*POS) *MBAL H['}'] @POS
234: MBAL = BREAK('{}<') ((H['{'] *MBAL H['}'] *MBAL) |
235: + (H['<'] *QBAL H['>'] *MBAL) | '')
236: GPMNAME = TAB(*POS) BREAK('{< }') $ PREFIX
237: + ((((H['{'] @POS *?(MACNAME = MACNAME PREFIX MACCALL())) |
238: + (*QSPOS *?(MACNAME = MACNAME PREFIX QS)))
239: + *GPMNAME) |
240: + *?(MACNAME = REPLACE(MACNAME PREFIX,LOWLETS,UPLETS)))
241: GPMARG = TAB(*POS) BREAK('{<,}') $ PREFIX
242: + ((((H['{'] @POS ((*IDENT(QN) *?(ARG = ARG PREFIX MACCALL())) |
243: + (*DIFFER(QN) (*MBAL H['}']) $ QS @POS
244: + *?(ARG = ARG PREFIX '{' QS)))) |
245: + (*QSPOS *?(ARG = ARG PREFIX
246: + (IDENT(QN) QS, '<' QS '>'))))
247: + *GPMARG) | *?(ARG = ARG PREFIX))
248: GPMARG1 = ('@' @POS *GPMARG *?(ARG = MACDEF(ARG))) | *GPMARG
249: GPMARGS = H['}'] | ',' @POS '' $ ARG *GPMARG1
250: + *?(AL[T = T + 1] = ARG) *GPMARGS
251: GPMCALL = *GPMNAME *?(AL = TABLE(3))
252: + *?(MACNAME ? MC.DOTNAME = '', '') (H['}'] | SPAN(SP)
253: + @POS FENCE *?(QN = AEPROP[MACNAME])
254: + *GPMARG1 *?(AL[T = 1] = ARG) *GPMARGS) @POS
255: MC.DOTNAME = (('SET' | 'TSET') ('V' | '')) . SETTYPE '.'
256: *
257: DEFINE('MACDEF(MNAME)PROP,T')
258: PROPPATT = BREAK('\') . MNAME LEN(1) REM . PROP
259: *
260: DEFINE('OVER(STR,STR2)P,P2,T,T2')
261: OV.P0 = LEN(1) ((BS *OV.P0) | '')
262: OV.P1 = TAB(*P) (*OV.P0 | '') $ T @P
263: OV.P2 = TAB(*P2) (*OV.P0 | *DIFFER(T)) $ T2 @P2
264: *
265: DEFINE('PAGEIT(T)LINE,NOPAGE')
266: *
267: DEFINE('PUTBLANK(T)')
268: *
269: DEFINE('PUTBREAK(T)')
270: *
271: DEFINE('PUTCHARS(STR)T,P,CNT')
272: PC.P0 = *(PC.BS = ) BREAK(BS) *?(PC.BS = 1)
273: PC.P1 = TAB(*$LINELENGTH) $ T (*IDENT(PC.BS) | *?(CNT = LSIZE(T))
274: + (*EQ(CNT,$LINELENGTH) |
275: + ARB LEN(1) $ T *EQ(CNT = CNT + (IDENT(T,BS) -1,1),
276: + $LINELENGTH))) @P
277: PC.P2 = (TAB(*(SIZE(LINE) - P)) (BREAK(SP) | '')) $ LINE
278: + (SPAN(SP) | '') REM $ STR
279: *
280: DEFINE('PUTLINE(LINE)')
281: *
282: DEFINE('READ()T')
283: *
284: DEFINE('RESTORE()T')
285: *
286: DEFINE('STT(MNAME,VAL,TS)PROP,T')
287: PROPVALS = TABLE()
288: PROPSTKS = TABLE()
289: DATA('STKITM(VAL,NEXT)')
290: TSETSTK = TABLE(31)
291: PROPSTKS[''] = TSETSTK
292: *
293: DEFINE('SKIPTEXT(STR)T')
294: -STITL DEFINE THE BASE MACROS
295: SETTRAP = TABLE(17)
296: FAILEXP = *EQ(1,0)
297: GT0EXP = *((VAL = CONVERT(VAL,.INTEGER)) GT(VAL,0))
298: GE0EXP = *((VAL = CONVERT(VAL,.INTEGER)) GE(VAL,0))
299: PRED = *(APPLY(MACNAME,AL1,AL2),'1')
300: MACROS = TABLE(181)
301: AEPROP = TABLE(81)
302: PROPVALS[''] = MACROS
303: PROPVALS['*'] = AEPROP
304: SETTRAP[H['BIAS']] = *(INTEGER(VAL) GE($LMG - 1 + VAL,0)
305: + (LMGCHARS = DUPL(SP,$LMG - 1 + VAL)))
306: MACROS['BRK'] = *PUTBREAK(0)
307: SETTRAP[H['BSLACK']] = GE0EXP
308: MACROS['CAB'] = H['>']
309: MACROS[H['CODE']] = *?(MACROS[REPLACE(AL1,LOWLETS,UPLETS)] =
310: + CONVERT(AL2,.EXPRESSION))
311: MACROS[H['COND']] = *COND()
312: AEPROP[H['COND']] = 1
313: MACROS['CREPROP'] = *?(DIFFER(AL1) (PROPVALS[AL1] = TABLE(AL2)),
314: + &ERRTYPE = 307)
315: MACROS['CS'] = *CONTROL_SEQ(AL1)
316: MACROS['D'] = *(CONVERT(MACDEF(AL1),.STRING),
317: + APPLY((DIFFER(PFLG) .GPMPRINT, .GPMIFY), '{' AL1 '}',
318: + NULLARGS))
319: MACROS['DELPROP'] = *?(DIFFER(AL1) (PROPVALS[AL1] = ),
320: + &ERRTYPE = 307)
321: MACROS['DIAG'] = *DIAG()
322: MACROS[H['DIFFER']] = PRED
323: MACROS[H['DOPROP']] = *DOPROP(GPMIFY(AL1),AL2,GPMIFY(AL[3]))
324: AEPROP[H['DOPROP']] = 1
325: MACROS[H['DOWHILE']] = *DOWHILE(AL1,AL2)
326: AEPROP[H['DOWHILE']] = 1
327: MACROS[H['END']] = *END()
328: MACROS['EQ'] = PRED
329: MACROS['EVEN'] = *(EQ(REMDR(AL1,2),0), 1)
330: MACROS['GE'] = PRED
331: MACROS['GT'] = PRED
332: MACROS[H['HS']] = '~'
333: SETTRAP[H['HS']] = *(HS = SUBSTR(VAL,1,1))
334: MACROS[H['IDENT']] = PRED
335: SETTRAP[H['INPUT']] = *(?(T[MNAME] = VAL) ?(MNAME = FAILEXP)
336: + ?IN_STT(TS,AL2))
337: SETTRAP[H['LINELENGTH']] = *(STT('RMG',CONVERT(VAL,.INTEGER) +
338: + $LMG - 1) ?(MNAME = FAILEXP))
339: MACROS['LE'] = PRED
340: MACROS['LEQ'] = PRED
341: MACROS['LGE'] = PRED
342: MACROS['LGT'] = PRED
343: MACROS['OUTSTREAM'] = *LINE
344: SETTRAP['OUTSTREAM'] = *(?(LINE = VAL) ?(MNAME = FAILEXP))
345: MACROS[H['LINENUM']] = 1
346: SETTRAP[H['LINENUM']] = *(?PUTBREAK(0)
347: + (GE(VAL,$LINENUM), PUTBREAK(30000))
348: + ?PUTBREAK(VAL - $LINENUM)
349: + ?(MNAME = FAILEXP))
350: SETTRAP[H['LMG']] = *(INTEGER(VAL) GT(VAL + $BIAS,0)
351: + LE(VAL,$RMG)
352: + ?($LINELENGTH = $RMG - VAL + 1)
353: + (LMGCHARS = DUPL(SP,VAL - 1 + $BIAS)))
354: -EJECT
355: MACROS['LLE'] = PRED
356: MACROS['LLT'] = PRED
357: MACROS['LNE'] = PRED
358: MACROS['LS'] = *PUTBREAK((CONVERT(AL1,.INTEGER), &ERRTYPE = 303))
359: MACROS['LT'] = PRED
360: MACROS['NE'] = PRED
361: MACROS['OAB'] = H['<']
362: MACROS['ODD'] = *(NE(REMDR(AL1,2),0), 1)
363: SETTRAP[H['OUTPUT']] = *(ENDFILE(1)
364: + OUTPUT(.OUTVAR,1,REPLACE(VAL,LOWLETS,UPLETS)
365: + (DIFFER($OUTOS), NCSW)))
366: MACROS['OS'] = *OVER(AL1,AL2)
367: SETTRAP[H['PAGELENGTH']] = GT0EXP
368: SETTRAP['PAGENUM'] = GE0EXP
369: MACROS[H['PRINT']] = *GPMPRINT(AL1,ARGLIST)
370: AEPROP[H['PRINT']] = 1
371: MACROS[H['RESTORE']] = *RESTORE()
372: SETTRAP[H['RMG']] = *(INTEGER(VAL) GE(VAL,$LMG)
373: + ($LINELENGTH = VAL - $LMG + 1))
374: MACROS[H['SET']] = *STT(AL1,AL2)
375: MACROS[H['SETQ']] = MACROS['SET']
376: AEPROP[H['SETQ']] = 1
377: MACROS[H['SETV']] = *(?STT(AL1,AL2) AL2)
378: MACROS[H['SKIPTEXT']] = *?SKIPTEXT(AL1)
379: MACROS[H['SPACING']] = 1
380: SETTRAP[H['SPACING']] = GT0EXP
381: MACROS[H['TSET']] = *STT(AL1,AL2,'T')
382: MACROS[H['TSETQ']] = MACROS[H['TSET']]
383: AEPROP[H['TSETQ']] = 1
384: MACROS[H['TSETV']] = *(?STT(AL1,AL2,'T') AL2)
385: SETTRAP[H['TSETV']] = FAILEXP
386: -EJECT
387: * Define some names for fast access.
388: *
389: BEGINTEXT = .MACROS[H['BEGINTEXT']]
390: BIAS = .MACROS[H['BIAS']]
391: BSLACK = .MACROS[H['BSLACK']]
392: ENDTEXT = .MACROS[H['ENDTEXT']]
393: FILL = .MACROS[H['FILL']]
394: INFORMAT = .MACROS[H['INFORMAT']]
395: JUST = .MACROS[H['JUST']]
396: LINELENGTH = .MACROS[H['LINELENGTH']]
397: LINENUM = .MACROS[H['LINENUM']]
398: LMG = .MACROS[H['LMG']]
399: NEWLINE = .MACROS[H['NEWLINE']]
400: OUTOS = .MACROS[H['OUTOS']]
401: PAGELENGTH = .MACROS[H['PAGELENGTH']]
402: RMG = .MACROS[H['RMG']]
403: SPACING = .MACROS[H['SPACING']]
404: -STITL INITIALIZING CODE...
405: H =
406: &ERRLIMIT = 9999
407: SETEXIT(.ERROR)
408: *
409: * This defines the GPMDOC-specific errors. They can be nulled if
410: * space is critical.
411: *
412: ERRMSGS = ARRAY('300:310')
413: ERRMSGS[300] = 'No Such File'
414: ERRMSGS[301] = 'Undefined Property'
415: ERRMSGS[302] = 'Too Many Nested Calls (Over ' COMPLEXLIM ')'
416: ERRMSGS[303] = 'Value Must Be Numeric'
417: ERRMSGS[304] = 'Too Many Open Files (Over ' MAXLU - MINLU + 1 ')'
418: ERRMSGS[305] = 'Illegal Value'
419: ERRMSGS[306] = 'No Value To RESTORE'
420: ERRMSGS[307] = 'Illegal Property'
421: *
422: * Set the free LUN stack
423: *
424: GPMIFY('{SET RMG,75}{SET LMG,10}{SET BSLACK,0}{SET PAGELENGTH,55}'
425: + '{SET BIAS,0}{SET SPACING,1}{SET PAGENUM,1}{SET HS,~}'
426: + ,NULLARGS)
427: CURRLU = MAXLU
428: INIT00 CURRLU = GT(CURRLU,MINLU) CURRLU - 1 :F(INIT00A)
429: TSETSTK[.FREELUNS] = STKITM(CURRLU + 1,TSETSTK[.FREELUNS]) :(INIT00)
430: *
431: * Try to read the startup built-in function file
432: *
433: INIT00A IN_READ(CURRLU,BIFFILE) :F(INIT01)
434: GPMIFY('{RESET}',NULLARGS) :(INIT02)
435: *
436: * Here if the startup function file can't be found - Just set essentials
437: *
438: INIT01 TERMINAL = "Warning - Can't Load Startup File " BIFFILE
439: *
440: * Merge from above to try to read the GPMSTART file if it is there
441: *
442: INIT02
443: * EXIT(-2)
444: CMD_LINE = &ERRTEXT
445: *
446: * Try to get in the justify external function
447: *
448: SETEXIT()
449: JUSTIFY_AVAIL = LOAD('JUSTIFY(STRING,STRING,STRING,INTEGER,INTEGER,'
450: + 'STRING)STRING','SYS$LIBRARY:JUSTIFY') 1
451: JUSTIFY_BUFF = DIFFER(JUSTIFY_AVAIL) DUPL(' ',250)
452: SETEXIT(.ERROR)
453: *
454: * Error handling set up. Ready to do initial I/O
455: *
456: OUTPUT(.OUTVAR, OUTUNIT, (MACROS['OUTPUT'] = INITIAL_OUTPUT) NCSW)
457: OUTPUT(.QUERY,QUERYUNIT,INITIAL_OUTPUT NCSW)
458: OUTVAR = CRLF 'GPMDOC V780-6.12/' COLLECT() SP
459: IN_READ(CURRLU,USERSTART)
460: *
461: * We try to pick up the command line text in double quotes,
462: * or failing that, issue a read to the terminal.
463: *
464: CMD_LINE (BREAK('"') LEN(1) SPAN(' ')
465: + (LEN(1) REM) . CMD) :F(INIT04)
466: OUTVAR = ' Processing...'
467: GPMPRINT(CMD,NULLARGS)
468: EOF_FLAG =
469: IN_READ(CURRLU,INSET_PEND) :F(INIT04B)
470: *
471: * Here when finished processing
472: *
473: INIT03 PUTBREAK(0) :(END)
474: *
475: * Come here when there is no initial command to process
476: *
477: INIT04 OUTVAR = ' Ready.'
478: OUTVAR = CRLF
479: *
480: * Loop here until READ cycle completes normally
481: *
482: INIT04A INPUT(.INFILE,CURRLU,INITIAL_INPUT) :F(INIT04C)
483: IN_READ(CURRLU) :S(INIT05)
484: *
485: * Merge here on SET chain failure
486: *
487: INIT04B TERMINAL = 'Requested File Is Not Available'
488: TERMINAL = 'Command Input Established'
489: PUTBREAK(0) :(INIT04A)
490: *
491: * Here when attachment to initial file fails
492: *
493: INIT04C TERMINAL = '* Cannot Read From Command Input *'
494: TERMINAL = ' * Dying in Shame *'
495: INIT05 :(END)
496: -STITL "COND()" - SUPPORT FOR COND MACRO
497: * The COND macro takes the form {COND p1,v1,p2,v2,...,pn,vn} .
498: * Evaluation of COND consists of evaluating each p(i) (predicate) until one
499: * is found that evaluates null. The evaluation of the following v(i) (value)
500: * is then returned as the value of COND . COND is a special form
501: * and thus it is not necessary to quote the predicates or values under normal
502: * circumstances.
503: *
504: COND T = DIFFER(GPMIFY(AL[T + 1],ARGLIST)) T + 2 :S(COND)
505: COND = (DIFFER(PFLG) GPMPRINT(AL[T + 2],ARGLIST),
506: + GPMIFY(AL[T + 2],ARGLIST)) :(RETURN)
507: -STITL "CONTROL_SEQ(STR)" - TURN STR INTO A CONTROL SEQUENCE
508: * A control sequence from STR consists of <BS> characters placed after
509: * each character of STR, making a normalized overstrike sequence , and this
510: * is then preceeded by a <CS><BS> sequence.
511: * The <CS> is to identify a control sequence to the IMAGES routine,
512: * and the backspaces are to force the LSIZE length of the control
513: * sequence to be effectively zero.
514: *
515: CONTROL_SEQ STR (ARB LEN(1) $ T *?(CONTROL_SEQ = CONTROL_SEQ T BS) FAIL)
516: CONTROL_SEQ = (CS BS) CONTROL_SEQ :(RETURN)
517: -STITL "DOWHILE(PRED,BODY)" - SUPPORT FOR DOWHILE MACRO
518: * This routine is called to evaluate BODY repeatedly. The given predicate
519: * PRED is evaluated repeatedly prior to the evaluation of BODY.
520: * The loop continues as long as the predicate evaluates true (null).
521: * The value of DOWHILE is the successive right-concatenations of the
522: * results.
523: *
524: DOWHILE IDENT(GPMIFY(PRED,ARGLIST)) :F(RETURN)
525: DOWHILE = DOWHILE (IDENT(PFLG) GPMIFY(BODY,ARGLIST),
526: + GPMPRINT(BODY,ARGLIST)) :(DOWHILE)
527: -STITL "DOPROP(PROP,BODY,ORDER)" - SUPPORT FOR DOPROP MACRO
528: * o This routine is called to apply the entries in the property
529: * table for property PROP to the macro BODY one at a time.
530: * The body is evaluated in a context where the first argument
531: * is the index name for the property, and the second argument
532: * is the corresponding value.
533: *
534: * o ORDER gives the order in which the entries are presented to
535: * BODY. If, when evaluated, ORDER gives "UP", the entries
536: * are presented in ascending order. Similar remarks apply for
537: * "DOWN". Anything else implies no order.
538: *
539: * o Note that DOPROP should be defined with the AE property, and
540: * PROP and ORDER evaluated before entering this routine.
541: *
542: * o As with DOWHILE, this routine returns the successive concatenations
543: * of the repeated evaluations. (This will be null in the context of
544: * non-null PFLG, since the evaluation is done by GPMPRINT which
545: * returns null.)
546: *
547: DOPROP T = PROPVALS[PROP]
548: *
549: * The null property (MACROS) is illegal (it contains funny stuff),
550: * and so is an undefined property.
551: *
552: (DIFFER(PROP) DIFFER(T), &ERRTYPE = 307)
553: *
554: * A-OK. Convert to an array and sort if necessary.
555: *
556: ORDER = REPLACE(ORDER,LOWLETS,UPLETS)
557: T = CONVERT(T,.ARRAY) :F(RETURN)
558: T = (IDENT(ORDER,'UP') SORT(T,1),
559: + IDENT(ORDER,'DOWN') RSORT(T,1))
560: *
561: * Loop to invoke the body.
562: *
563: I =
564: ARGLIST = TABLE(3)
565: DOP01 I = I + 1
566: ARGLIST[1] = T[I,1] :F(RETURN)
567: ARGLIST[2] = T[I,2]
568: DOPROP = DOPROP (IDENT(PFLG) GPMIFY(BODY,ARGLIST),
569: + GPMPRINT(BODY,ARGLIST)) :(DOP01)
570: -STITL "DUMPTEXT(STR)" - PUT LINE ON OUTPUT FILE
571: * This module puts out a line on the unit attached to OUTVAR. It
572: * checks for begin/end page and handles the multiple printing of
573: * overstruck images.
574: *
575: * First, check for a NEWPAGE condition.
576: *
577: DUMPTEXT (EQ($LINENUM,1) IDENT(NOPAGE) PAGEIT('NEWPAGE'))
578: *
579: * Get rid of hard spaces
580: *
581: STR = REPLACE(STR,HS,SP)
582: *
583: * Check for overstrikes in STR. If so, IMAGES is called to generate
584: * a table containing all the overstrike images of the line (IMAGES[0]=
585: * Principal image). Note that the principal image is always output last.
586: * This is so CRT's will show something reasonable.
587: *
588: STR BSPATT :F(DT02)
589: *
590: * Overstrikes in line. Get all the print images in IMAGES table.
591: *
592: IMAGES = IMAGES(STR)
593: STR = IMAGES[0]
594: *
595: * Loop to dump out the overstrike images (unless OUTOS is disabled)
596: *
597: DT01 OUTVAR = IDENT($OUTOS) DIFFER(IMAGES[I = I + 1])
598: + IMAGES[I] CR :S(DT01)
599: *
600: * Merge here to print the principal image in STR, and force a new line.
601: *
602: DT02 OUTVAR = STR (DIFFER($OUTOS),CRLF)
603: *
604: * Bump LINENUM. If we have reached the end of a page (and paging is
605: * permitted via NOPAGE) then flag and process an endpage condition.
606: *
607: $LINENUM = $LINENUM + 1
608: (LE($LINENUM,$PAGELENGTH), DIFFER(NOPAGE)) :S(RETURN)
609: MACROS['PAGENUM'] = ?PAGEIT('ENDPAGE')
610: + MACROS['PAGENUM'] + 1 :(RETURN)
611: -STITL "GETLINE()" - READ A LOGICAL LINE OF INPUT
612: * o This module returns a single line of GPMDOC input from the unit attached
613: * to INFILE. Logical lines are equivalent to physical lines unless the
614: * physical lines are 'continued' with hyphens at the end. In such cases,
615: * the returned logical lines are the physical lines concatenated together
616: * without the hyphens, and with leading blanks and tabs at the beginning
617: * of continuation lines removed. Logical lines beginning with "!" are
618: * presumed to be comments, and are discarded. If the line read is null,
619: * a single hard space is returned so that no-fill works correctly.
620: *
621: * o The code here also translates tabs to blanks under the fixed assumption
622: * that tabs are set at (input) columns 9, 9+8, 9+2*8, ...
623: *
624: * o The global EOF_FLAG can be set non-null to force a simulated endfile.
625: * If this is done, it will be reset before FRETURNing.
626: *
627: * o If the ENDTEXT macro is non-null, and GETLINE sees the line, it
628: * simulates an end-of-file (FRETURNs)
629: *
630: * o If the INFORMAT macro is non-null (false) then the line is returned as
631: * read, without logical line processing.
632: *
633: * Read the first input line, and fail if no more exist.
634: *
635: GETLINE EOF_FLAG = DIFFER(EOF_FLAG) :S(FRETURN)
636: GETLINE = INFILE :F(FRETURN)
637: *
638: * If the endtext macro is non-null, and this is it, then fail.
639: * Endtext is toggled null when this happens.
640: *
641: $ENDTEXT = DIFFER($ENDTEXT) IDENT(GETLINE,$ENDTEXT) :S(FRETURN)
642: *
643: * If the line is empty, set it to a hard space and return
644: *
645: GETLINE = IDENT(GETLINE) HS :S(RETURN)
646: *
647: * If INFORMAT is non-null, then return the line.
648: *
649: DIFFER($INFORMAT) :S(RETURN)
650: *
651: * Examine the line for a continuation hyphen at the end, and go to the
652: * exit point if not there. If it is, this pattern removes it, and
653: * we merge into the continuation line loop.
654: *
655: GETLINE GL.P1 :F(GL02)
656: *
657: * Loop here on successive continuation lines.
658: *
659: GL01 T = INFILE :F(FRETURN)
660: T GL.P2 =
661: GETLINE = GETLINE T
662: GETLINE GL.P1 :S(GL01)
663: *
664: * Return unless this is a comment line, in which case get the next line.
665: *
666: GL02 GETLINE ANY('!') :S(GETLINE)
667: *
668: * Merge to change tabs to blanks and return
669: *
670: GL03 GETLINE (BREAK(' ') . T LEN(1)) =
671: + RPAD(T,(SIZE(T) / 8) * 8 + 8) :S(GL03)F(RETURN)
672: -STITL "GPMIFY(MSTR,ARGLIST)"
673: * o This routine evaluates MSTR according to GPMDOC rules. They are:
674: * o Ordinary text stands for itself.
675: * o {name arg,arg,...} is a macro call. The actual processing
676: * of the macro call is handled by the pattern calling MACCALL,
677: * with POS pointing past the open brace. The text returned by
678: * MACCALL is appended to the result, with POS having been set
679: * past the close brace, so the scan can continue uninterrupted
680: * inside the same pattern match.
681: * o Material in quotes as: <...material...> is not examined further,
682: * but the outer quotes "<>" are stripped away before material is
683: * appended to the result.
684: * All of this takes place inside of a single pattern match, which is
685: * forming the result in GPMIFY as it goes, by using embedded assignments.
686: * o Note that this whole process is recursive, since the pattern can call
687: * MACCALL, which in turn can call for a GPMIFY, etc.
688: * o ARGLIST is the table of arguments passed through, to be handed to
689: * MACCALL in case a macro call is seen.
690: *
691: GPMIFY MSTR GPMSTRING :(RETURN)
692: -STITL "GPMPRINT(MSTR,ARGLIST)"
693: * o GPMPRINT is just like GPMIFY, except that the result is null, all
694: * evaluations are sent to PUTCHARS as they are scanned out. It is called
695: * when the result of the evaluation is to be printed, and not used further.
696: *
697: GPMPRINT MSTR GPMSTRPNT :(RETURN)
698: -STITL "IMAGES(STR)" - GENERATE TABLE OF OVERSTRIKE IMAGES OF STR
699: * This module returns a TABLE indexed numerically starting from zero (integer).
700: * Each element contains one overstrike image of STR. If STR contains no
701: * overstrikes, element 0 would contain just the given STR. If there were
702: * overstrikes, then element 0 would contain the 'principal image' of STR,
703: * and successively higher table elements would contain the higher orders
704: * of overstrikes. The first null value in element "i" marks the end
705: * of the images. Note that the images are not right padded to the same
706: * lengths.
707: *
708: IMAGES IMAGES = TABLE(1)
709: IM01 STR IM.P1
710: IMAGES[0] = IMAGES[0] SUBSTR(STR,POS + 1) :(RETURN)
711: -STITL "IN_READ(INUNIT,INNAME)" - Access initial input files
712: * o This module provides access to the READ routine given a unit (INUNIT)
713: * and file (INNAME). If INNAME is null, the current binding is assumed,
714: * and no initial association is set.
715: *
716: * o INSET_PEND is set by IN_SET when a "real" input SET is performed to
717: * give the name of the next file to associate. This routine
718: * handles it by looping on input associations until it is null.
719: *
720: * o This routine fails if an association cannot be made because of
721: * association failure. No error is flagged.
722: *
723: IN_READ (IDENT(INNAME), INPUT(.INFILE,INUNIT,INNAME)) :F(FRETURN)
724: INSET_PEND =
725: READ()
726: INNAME = DIFFER(INSET_PEND) INSET_PEND :S(IN_READ)F(RETURN)
727: -STITL "IN_STT(TS,INNAME)" - SET INPUT FILE
728: * o This routine is called as a result of the SETTRAP on INPUT.
729: * It will be called for SET, TSET or RESTORE on the INPUT macro.
730: *
731: * o TS provides the type of set (ref. routine SET).
732: *
733: * o INNAME is the second argument of the set (filename). If it is
734: * null, then this is a "pseudo-read", implying no new association
735: * is to be made.
736: *
737: * o There are three globals used by this routine:
738: *
739: * o INUNIT is the current logical unit number. NEW_INUNIT is a
740: * local which is assigned INUNIT (again) if this is a pseudo-read
741: * and passed to IN_READ.
742: *
743: * o INSET_PEND is used for SETs to communicate the SET filename
744: * to IN_READ.
745: *
746: * o EOF_FLAG is used to signal GETLINE to force an EOF on the
747: * next call.
748: *
749: * First, set the error return point, and check for TSETs and RESTOREs
750: * A forced RESTORE is handled by simply setting the EOF_FLAG to tell
751: * GETLINE to simulate an EOF on the next read.
752: *
753: IN_SET EOF_FLAG = IDENT(TS,'R') 1 :S(RETURN)
754: IDENT(TS,'T') :S(IS01)
755: *
756: * This is a standard SET. The way this is handled is to set EOF_FLAG
757: * to force close-out of the current read, and to save the SET filename
758: * in INSET_PEND. When the current READ returns (below), INSET_PEND
759: * is checked, and if there is a SET pending, the TSET logic is
760: * followed to open the new file instead of reverting to the old one.
761: * Of course, if the SET filename is null, we are just setting
762: * the current file (stupid) and a simple return is sufficient.
763: *
764: EOF_FLAG = DIFFER(INNAME) 1
765: INSET_PEND = INNAME :(RETURN)
766: -EJECT
767: *
768: * This is a TSET. Arguments (3,4,...) are now processed until a null
769: * argument is found. These arguments are of the form NAME=VALUE and
770: * cause an automatic TSET of the given macro name with the indicated value.
771: * The corresponding RESTORE is also automatic when the READ finishes.
772: *
773: IS01 ISINDEX = 3
774: IS00 IDENT(AL[ISINDEX]) :S(IS02)
775: AL[ISINDEX] IS_ALPATT :F(IS00A)
776: STT(ISNAME,ISVALUE,'T')
777: IS00A ISINDEX = ISINDEX + 1 :(IS00)
778: *
779: * Here for TSET. The process is essentially just to call IN_READ.
780: * If this is not a pseudo-read, then we unstack a free unit to give
781: * it, otherwise, its a pseudo-read, and we give it the one being
782: * used now.
783: *
784: IS02 NEW_INUNIT = IDENT(INNAME) INUNIT :S(IS03)
785: (DIFFER(TSETSTK[.FREELUNS]), &ERRTYPE = 304) :F(RETURN)
786: NEW_INUNIT = VAL(TSETSTK[.FREELUNS])
787: TSETSTK[.FREELUNS] = NEXT(TSETSTK[.FREELUNS])
788: *
789: * Merge here for pseudo-read to issue the call to IN_READ.
790: *
791: IS03 (IN_READ(NEW_INUNIT, INNAME), &ERRTYPE = 305) :F(IS04)
792: (DIFFER(INNAME) ENDFILE(NEW_INUNIT))
793: *
794: * Merge here after read error to restack the old lun if not pseudo-read,
795: * then restore the old environment.
796: *
797: IS04 TSETSTK[.FREELUNS] = DIFFER(INNAME)
798: + STKITM(NEW_INUNIT,TSETSTK[.FREELUNS])
799: INPUT(.INFILE,INUNIT)
800: *
801: * Now the entry keyword arguments are restored
802: *
803: IS05 ISINDEX = GE(ISINDEX,3) ISINDEX - 1 :F(RETURN)
804: AL[ISINDEX] IS_ALPATT :F(IS05)
805: STT(ISNAME,,'R') :(IS05)
806: -STITL "JUST(JUST,LEN,T)"
807: * o JUST is called to justify a string JUST with LEN additional
808: * blanks.
809: *
810: * o If T is non-zero, then the 'odd' blanks are padded on the right.
811: * Otherwise they are jammed in from the left.
812: *
813: JUST JUST = NE(T,0) REVERSE(JUST)
814: JU01 JUST JU.P1 = PREFIX SP :S(JU01)
815: JUST = NE(T,0) REVERSE(JUST) :(RETURN)
816: -STITL "LSIZE(STR)"
817: * o LSIZE returns the number of the final print position of STR (including
818: * backspace characters). If there are no backspace characters in STR,
819: * then this is the same as SIZE(STR). If there are no trailing backspaces
820: * and STR is normalized, then LSIZE gives the number of print positions
821: *
822: LSIZE STR BREAKX(BS) *?(T = T + 1) FAIL
823: LSIZE = SIZE(STR) - 2 * T :(RETURN)
824: -STITL "LSUBSTR(STR,N,LEN)" - TAKE SUBSTRING WITH BACKSPACING
825: * o LSUBSTR semantics are the same as SPITBOL's SUBSTR function,
826: * except that it accounts for backspace characters.
827: *
828: LSUBSTR LEN = EQ(LEN,0) LSIZE(STR) - N + 1
829: STR LS.P2 :S(RETURN)F(FRETURN)
830: -STITL "MACCALL(PFLG)" - EVALUATE A MACRO CALL
831: * This is the heart of the GPMDOC interpreter in that it processes macro
832: * calls ({Name Arg1,Arg2,...}). PFLG is the stream indicator. If it is
833: * null, the result is to be returned as a string. If PFLG is nonnull, then
834: * the results are going to the PUTCHARS output stream and null is returned.
835: * This module is entered from GPMIFY or GPMPRINT when they encounter a macro
836: * call open brace. The global (to MACCALL) variable POS is set to the
837: * character index in the global STR where the macro call begins. MACCALL
838: * returns with POS set to the index in MSTR past the macro call.
839: *
840: * Save the starting index in case a error occurs in any of the evaluations
841: * or scans, then check to be sure we haven't exceeded the recursion limit
842: * in COMPLEXLIM. If so, then we scan for a matching close brace for this
843: * call, which sets POS for the error routine, and then flag an error 302.
844: *
845: MACCALL STPOS = POS - 1
846: LT(&FNCLEVEL, COMPLEXLIM) :S(MC01)
847: MSTR MC.P1
848: &ERRTYPE = 302
849: *
850: * Here we match out the name and arguments. If the scan fails then we
851: * get out. Note that this pattern can recurse on MACCALL if the macro
852: * call being scanned contains embedded macro calls.
853: * This pattern also processes extended SETs by placing the type of
854: * extended set (SET,TSET,SETV or TSETV) in SETTYPE and the extension
855: * in MACNAME. Later on we switch things around and loop back to do the
856: * set.
857: *
858: MC01 MSTR GPMCALL :F(MC07)
859: *
860: * Check for an extended SET.
861: SETNAME = DIFFER(SETTYPE) AL[1] :F(MC02)
862: *
863: * Got one. Look up the definition of the first arg to be applied
864: * in the macro call, and evaluate it in case it turns out to be expression-
865: * valued.
866: *
867: AL[1] = MACDEF(AL[1])
868: AL[1] = IDENT(DATATYPE(AL[1]),'EXPRESSION') EVAL(AL[1])
869: *
870: * Merge here when the arguments and macro name are correctly set for
871: * evaluation. Look up the definition of MACNAME, and if it is not
872: * a system macro (datatype Expression), go evaluate the string.
873: *
874: MC02 IDENT(DATATYPE(MACRO = MACDEF(MACNAME)),'EXPRESSION') :F(MC04)
875: *
876: * Come here to evaluate a macro that is an expression (merge from extended
877: * set looping back to do the final set). We set AL1 and AL2 to the first
878: * and second arguments in order to save some time and space since they are
879: * so frequently referenced in the system macros. Then we evaluate the
880: * expression and if results are going to the output stream (PFLG=nonnull) then
881: * we send them there.
882: *
883: MC03 AL1 = AL[1]; AL2 = AL[2]
884: MACCALL = EVAL(MACRO)
885: (DIFFER(PFLG) DIFFER(MACCALL) IDENT(SETTYPE) PUTCHARS(MACCALL))
886: + :(MC05)
887: -EJECT
888: *
889: * Come here when MACRO is set to a string to be evaluated. We call either
890: * GPMIFY or GPMPRINT depending on where the output is to go.
891: *
892: MC04 MACCALL = ((IDENT(PFLG), DIFFER(SETTYPE))
893: + GPMIFY(MACRO,AL), GPMPRINT(MACRO,AL))
894: *
895: * Merge here to check for an extended set in progress. If we don't need
896: * to process the second part of an extended set, we just go to the exit
897: * point.
898: *
899: MC05 MACRO = DIFFER(SETTYPE) MACROS[SETTYPE] :F(MC06)
900: *
901: * We need to loop back to process the SET part of an extended set.
902: * Switch around the arguments to make things work out. Then loop back.
903: *
904: SETTYPE = ; AL[1] = SETNAME ; AL[2] = MACCALL :(MC03)
905: *
906: * Come here to exit, setting the result null if the result was printed.
907: *
908: MC06 MACCALL = DIFFER(PFLG) :(RETURN)
909: *
910: * Come here when the macro scan fails. We reset the scan pointer and FRETURN.
911: *
912: MC07 POS = STPOS :(FRETURN)
913: -STITL "MACDEF(MNAME)" - RETURN DEFINITION OF A MACRO.
914: * o This routine is invoked by MACCALL and some of the system macros to
915: * look up the definition of a given macro name MNAME.
916: *
917: * Try for an argument, and if not that then get the definition from the
918: * MACROS table.
919: *
920: MACDEF MNAME PROPPATT
921: T = PROPVALS[PROP]
922: (DIFFER(T), &ERRTYPE = 301) :F(FRETURN)
923: MACDEF = (IDENT(PROP) INTEGER(MNAME) ARGLIST[CONVERT(MNAME,.INTEGER)],
924: + T[REPLACE(MNAME,LOWLETS,UPLETS)]) :(RETURN)
925: -STITL "OVER(STR,STR2)" - OVERSTRIKE TWO STRINGS
926: * This module returns STR overstruck by STR2. It insures that the result
927: * string is properly aligned on the right if STR and STR2 are of different
928: * lengths. It also insures that no two backspace characters appear
929: * consecutively, and that no overstruck blanks are introduced into the
930: * result image. This is the form assumed by the other system routines,
931: * so this should be the only routine capable of introducing backspace
932: * characters into the text.
933: *
934: * Since STR and STR2 may contain backspaces themselves, we loop
935: * here to match out the next run of characters from STR and STR2
936: * that 'map' visually into a single character. If the STR2 match
937: * fails, then we have reached the end of both strings and we return.
938: * Otherwise, we append the characters, checking for nulls (end of string),
939: * and blanks.
940: *
941: OVER STR OV.P1
942: STR2 OV.P2 :F(RETURN)
943: OVER = OVER (IDENT(T) T2, IDENT(T2) T, IDENT(T,SP) T2,
944: + IDENT(T2,SP) T, T BS T2) :(OVER)
945: -STITL "PAGEIT(T)" - PROCESS NEWPAGE/ENDPAGE CONDITIONS
946: * o This module is entered to process a page event in GPMDOC.
947: *
948: * o "T" is either to "NEWPAGE" or "ENDPAGE" as appropriate.
949: *
950: * o The routine stacks NEWLINE, SPACING, LMG and RMG, and sets
951: * NOPAGE to a non-null value to prevent recursive page conditions
952: * from occurring. $LINENUM is set to one both before
953: * and after the page condition. Processing the
954: * condition itself consists of evaluating the appropriate macro.
955: *
956: * o LINE is local here, since we need a separate output stream for
957: * the page evaluation.
958: *
959: PAGEIT (STT('NEWLINE',,'T') ?STT('SPACING',1,'T')
960: + ?STT('LMG',10,'T') ?STT('RMG',75,'T'))
961: NOPAGE = 1
962: (GPMPRINT(MACROS[T],NULLARGS) ?PUTBREAK(0))
963: $LINENUM = IDENT(T,'ENDPAGE') 1
964: (STT('NEWLINE',,'R') ?STT('SPACING',,'R')
965: + ?STT('LMG',,'R') ?STT('RMG',,'R')) :(RETURN)
966: -STITL "PUTBLANK(T)" - EMIT BLANK LINES
967: * This module is entered to send "T" blank lines to the document.
968: * It performs checking to see when a new page has occurred ($LINENUM = 1),
969: * and stops there, regardless.
970: *
971: PUTBLANK T = GT(T,0) GT($LINENUM,1) ?DUMPTEXT() T - 1 :F(RETURN)S(PUTBLANK)
972: -STITL "PUTBREAK(T)" - PERFORM A LINE BREAK WITH SPACING
973: * This module will break the current text in "LINE" to the output, and
974: * if T is greater than zero, will put out "T" additional blank lines.
975: * If blank lines are emitted, the BSLACK condition is checked after the
976: * spacing is performed, and if less than $BSLACK lines remain, the page
977: * is run out. Note that if T>0, at least one blank line is emitted -
978: * this is so spacing can occur at the top of a page which would otherwise
979: * be defeated by PUTBLANK.
980: *
981: PUTBREAK LINE = TRIM(LINE)
982: (DIFFER(LINE) PUTLINE(LINE) ?(LINE = ))
983: (GT(T,0) ?DUMPTEXT() ?PUTBLANK(T - 1)
984: + ?(GE($PAGELENGTH - $LINENUM, $BSLACK), DIFFER(NOPAGE),
985: + PUTBLANK(30000)))
986: + :(RETURN)
987: -STITL "PUTCHARS(STR)" - APPEND CHARACTERS TO OUTPUT STREAM
988: * This module suffixes STR to the current LINE, and breaks off a chunk for
989: * printing if its LSIZE becomes greater than $LINESIZE.
990: *
991: * First, suffix on the characters
992: *
993: PUTCHARS LINE = DIFFER(STR) LINE STR :F(RETURN)
994: *
995: * Check to see if LINE could possibly (ignoring possible backspaces) be too big
996: *
997: PC01 LE(SIZE(LINE), $LINELENGTH) :S(RETURN)
998: *
999: * Set the BS flag (PC.BS) according to whether LINE contains any
1000: * backspace characters
1001: *
1002: LINE PC.P0 :F(PC02)
1003: *
1004: * LINE contains backspace characters, check the LSIZE to see if it is
1005: * really too big.
1006: *
1007: LE(LSIZE(LINE), $LINELENGTH) :S(RETURN)
1008: *
1009: * Merge here to print a chunk. Locate a suitable breakpoint (preferably at
1010: * the closest blank). First set P to be the position of the first
1011: * printing character at line position $LINELENGTH.
1012: *
1013: PC02 LINE PC.P1
1014: *
1015: * OK. Now find the suitable breakpoint by scanning backwards in the
1016: * LINE for a blank, starting at P. (We can't really scan backwards,
1017: * so we reverse LINE instead.
1018: *
1019: REVERSE(LINE) PC.P2
1020: LINE = REVERSE(TRIM(LINE))
1021: STR = TRIM(REVERSE(STR))
1022: *
1023: * STR now has the text for printing that was split off from LINE. Justify
1024: * if called for.
1025: *
1026: STR = IDENT($JUST)
1027: + (DIFFER(JUSTIFY_AVAIL)
1028: + JUSTIFY(STR,JUSTIFY_BUFF,
1029: + JUSTIFY_BUFF,$LINELENGTH,
1030: + PC.FLIP = 1 - PC.FLIP,BS),
1031: + JUST(STR,
1032: + $LINELENGTH - APPLY((DIFFER(PC.BS) .LSIZE, .SIZE),STR),
1033: + PC.FLIP = 1 - PC.FLIP))
1034: *
1035: * Now print the text
1036: *
1037: PUTLINE(STR) :(PC01)
1038: -STITL "PUTLINE(LINE)" - EMIT TEXT.
1039: * o This module sends "LINE" to DUMPTEXT after appending the left margin and
1040: * evaluating any NEWLINE event that exists. It also handles SPACING if
1041: * if it is greater than 1.
1042: *
1043: PUTLINE (DIFFER(LINE) DUMPTEXT(LMGCHARS (IDENT($NEWLINE),
1044: + ?GPMIFY($NEWLINE,NULLARGS)) LINE)
1045: + ?(LE($SPACING,1), PUTBLANK($SPACING - 1))) :(RETURN)
1046: -STITL "READ()" - READ FROM A FILE
1047: * o This routine reads from the current input file, and ships the text
1048: * to the macro evaluator. (If the INFORMAT macro is non-null, then
1049: * the text is sent straight to PUTCHARS withou processing.)
1050: * It returns when GETLINE signals an EOF.
1051: *
1052: * o The data read is passed to the evaluator for printing. The line
1053: * fill macro is examined here, and a space or a line break given
1054: * at the end of each line depending on its setting.
1055: *
1056: * o If the BEGINTEXT macro is non-null, then text is skipped to the
1057: * line following. When this happens, STARTTEXT is toggled null.
1058: *
1059: READ
1060: *
1061: * If BEGINTEXT is non-null, read lines until we have it.
1062: *
1063: (DIFFER($BEGINTEXT) SKIPTEXT($BEGINTEXT))
1064: *
1065: * Loop here on input lines
1066: *
1067: RE01 T = GETLINE() :F(RETURN)
1068: (DIFFER($INFORMAT) PUTCHARS(T) PUTBREAK(0),
1069: + GPMPRINT(T,NULLARGS)
1070: + ?(IDENT(LINE), IDENT($FILL) PUTCHARS(SP),
1071: + PUTBREAK(0))) :(RE01)
1072: -STITL "RESTORE()" - SUPPORT FOR THE RESTORE MACRO
1073: * o This routine will call for a restore-type set for each argument
1074: * mname until a null one is encountered.
1075: *
1076: RESTORE STT(DIFFER(AL[T = T + 1]) AL[T],,'R') :S(RESTORE)F(RETURN)
1077: -STITL "STT(MNAME,VAL,TS)" - SET MACRO VALUE
1078: * o This is the central logic for all SET, TSET and RESTORE macro forms.
1079: *
1080: * o MNAME is the name of the macro, which is translated to upper case.
1081: *
1082: * o VAL is the value to be set; it is ignored for RESTORE.
1083: *
1084: * o TS is the Type-of-Set-FLAG. It is null for regular SETs, or 'T' or
1085: * 'R' respectively. The flag is used to control processing within
1086: * this routine, and also can be used by code executed by SETTRAPs.
1087: *
1088: * o If a SETTRAP entry is defined for the macro, it is evaluated before
1089: * the value is set. This evaluation must succeed or a bad value error
1090: * is signalled.
1091: *
1092: STT MNAME = REPLACE(MNAME,LOWLETS,UPLETS)
1093: MNAME PROPPATT
1094: T = PROPVALS[PROP]
1095: (DIFFER(T), &ERRTYPE = 301) :F(RETURN)
1096: DIFFER(TS,'T') :S(SET01)
1097: PROPSTKS[PROP] = IDENT(PROPSTKS[PROP]) TABLE()
1098: PROPSTKS[PROP][MNAME] = STKITM(T[MNAME],PROPSTKS[PROP][MNAME])
1099: *
1100: * Merge after TSET (if any) has been pushed.
1101: *
1102: SET01 DIFFER(TS,'R') :S(SET02)
1103: (DIFFER(PROPSTKS[PROP][MNAME]), &ERRTYPE = 306) :F(RETURN)
1104: VAL = VAL(PROPSTKS[PROP][MNAME])
1105: PROPSTKS[PROP][MNAME] = NEXT(PROPSTKS[PROP][MNAME])
1106: *
1107: * Here after RESTORE (if any) has been popped.
1108: *
1109: SET02 (DIFFER(PROP), IDENT(SETTRAP[MNAME]),
1110: + EVAL(SETTRAP[MNAME]), &ERRTYPE = 305) :F(RETURN)
1111: T[MNAME] = VAL :(RETURN)
1112: -STITL "SKIPTEXT(STR)" - SKIP INPUT LINES
1113: * o This routine is called to read and skip input text lines until
1114: * one is found that matches STR.
1115: *
1116: SKIPTEXT T = INFILE :F(RETURN)
1117: IDENT(T,STR) :S(RETURN)F(SKIPTEXT)
1118: -STITL ERROR PROCESSING APPENDAGE
1119: * o This error appendage is always executed in the local context of whatever
1120: * procedure caused it to be invoked
1121: *
1122: ERROR LAST = &LASTNO :(TRAP)
1123: TRAP &ERRTEXT = GT(&ERRTYPE,300) ERRMSGS[&ERRTYPE]
1124: TERMINAL = 'Error on Page: ' MACROS['PAGENUM'] ', Line: '
1125: + $LINENUM ' [' LAST ']' ' ... '
1126: PUTCHARS(TERMINAL = SUBSTR(MSTR, STPOS + 1, POS - STPOS) '-'
1127: + &ERRTEXT)
1128: SETEXIT(.ERROR)
1129: :(CONTINUE)
1130: *
1131: * This appendage is useful for debugging purposes
1132: *
1133: DIAG TERMINAL = 'Debugger (From: ' FNAME '; Tag: ' TAG
1134: + ') - Control-Z to continue'
1135: OLDEXIT = SETEXIT(.DIAG03)
1136: DIAG01 SETEXIT(.DIAG03)
1137: CARD = TERMINAL :F(DIAG02)
1138: TERMINAL = EVAL(CARD) :(DIAG01)
1139: DIAG02 SETEXIT(OLDEXIT) :(RETURN)
1140: DIAG03 TERMINAL = &ERRTEXT :(DIAG01)
1141: *
1142: END
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.