|
|
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('SET(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_SET(TS,AL2)) ! 337: SETTRAP[H['LINELENGTH']] = *(SET('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']] = *SET(AL1,AL2) ! 375: MACROS[H['SETQ']] = MACROS['SET'] ! 376: AEPROP[H['SETQ']] = 1 ! 377: MACROS[H['SETV']] = *(?SET(AL1,AL2) AL2) ! 378: MACROS[H['SKIPTEXT']] = *?SKIPTEXT(AL1) ! 379: MACROS[H['SPACING']] = 1 ! 380: SETTRAP[H['SPACING']] = GT0EXP ! 381: MACROS[H['TSET']] = *SET(AL1,AL2,'T') ! 382: MACROS[H['TSETQ']] = MACROS[H['TSET']] ! 383: AEPROP[H['TSETQ']] = 1 ! 384: MACROS[H['TSETV']] = *(?SET(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 = 999999 ! 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_SET(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: SET(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: SET(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 (SET('NEWLINE',,'T') ?SET('SPACING',1,'T') ! 960: + ?SET('LMG',10,'T') ?SET('RMG',75,'T')) ! 961: NOPAGE = 1 ! 962: (GPMPRINT(MACROS[T],NULLARGS) ?PUTBREAK(0)) ! 963: $LINENUM = IDENT(T,'ENDPAGE') 1 ! 964: (SET('NEWLINE',,'R') ?SET('SPACING',,'R') ! 965: + ?SET('LMG',,'R') ?SET('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 SET(DIFFER(AL[T = T + 1]) AL[T],,'R') :S(RESTORE)F(RETURN) ! 1077: -STITL "SET(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: SET 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.