* INDEX.SNO * * Formats a mail digest file for printing. Does pagination, produces a * Table of Contents and an Index. The Index is based on entries in the * message headers of the form * * Keywords: xxxx, xxxx, xxxx, "xxx, xxxx", xxxx * Cross-Ref: string * * A list of zero or more keywords may be included, separated by commas. * If the keyword itself is to contain a comma, it is enclosed in doublequotes. * The cross ref string is entered literally in the index. Examples: * * Keywords: Blort * Keywords: Foo, Bar, This and That, "Law, Murphy's", Baz * Cross-Ref: Murphy's Law, see Law, Murphy's * * Any particular Cross-Reference need be entered in the file only once. * The index is sorted in ASCII order, so alphabetic case matters. * * The table of contents depends on the subject of each digest containing * the words "Info-Kermit Digest Vx #y", where x & y are the vol/issue number. * The end of a digest is detected by "End of InfoxxxxxDigest" where a * digest message header would start. * * F. da Cruz, C. Gianone, CUCCA, May 1986 * * Modified May 88 to work with VAX spitbol * Modified Nov 88 to work with UNIX MM mail format * Modified Oct 91 to allow XREF as synonym for CROSS-REF &TRIM = 1 PAGEWID = 79 PAGELEN = 58 * Patterns NULL = &ALPHABET POS(13) (LEN(1) . CR) &ALPHABET POS(10) (LEN(1) . LF) CRLF = CR LF &ALPHABET POS(34) (LEN(1) . DQ) BLANK = ' ' &ALPHABET POS(9) (LEN(1) . HT) WS = BLANK HT &ALPHABET POS(12) (LEN(1) . FF) LOWER = 'abcdefghijklmnopqrstuvwxyz' UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' DIGITS = '0123456789' KEYS = 'Keywords' | 'Keyword' | 'KEYWORDS' | 'KEYWORD' + | 'keywords' | 'keyword' REFS = 'Cross-Ref' | 'Cross-Reference' | 'CROSS-REF' + | 'XREF' | 'Xref' | 'xref' KEYW = POS(0) KEYS ':' BREAK(WS) REM . KEY XREF = POS(0) REFS ':' BREAK(WS) REM . SEE SUBJ = POS(0) 'SUBJECT:' BREAK(WS) REM . TITLE ISUB = 'INFO' LEN(1) 'KERMIT' LEN(1) 'DIGEST V' + SPAN(DIGITS) . VOLUME SPAN(BLANK) '#' SPAN(DIGITS) . ISSUE ASUB = POS(0) 'subject:' | 'SUBJECT:' | 'Subject:' SPAN(WS) REM . SUB * Table, array declarations IXTB = TABLE() CONTENTS = ARRAY(500) INDEX = ARRAY('1000,2') II = 0 CC = 0 * Newpage function definition. Starts a new page, puts heading on top * composed of current digest title and page number. Set PAGE = -1 to * disable page number. Reverses page headings. DEFINE('NEWPAGE()') :(NEWPAGX) NEWPAGE OUTPUT = FF GE(PAGE,0) :S(NEWP2) OUTPUT = TITLE OUTPUT = :(NEWP4) NEWP2 PAGE = PAGE + 1 X = 'Page ' PAGE EQ(REMDR(PAGE,2),1) :S(NEWP3) OUTPUT = X LPAD(TITLE,PAGEWID - SIZE(X)) :(NEWP4) NEWP3 OUTPUT = TITLE LPAD(X,PAGEWID - SIZE(TITLE)) NEWP4 OUTPUT = LC = 3 :(RETURN) NEWPAGX * Function to output a line. If the line is longer than the page * width, it is broken at the nearest blank, and two (or more) lines are * output. If the bottom of the page is reached, a new page is started. DEFINE('OUTLIN(S)') :(OUTLINX) OUTLIN :(OUTLIN2) OUTLOOP IDENT(S,NULL) :S(RETURN) OUTLIN2 P = PAGEWID P = GE(P,SIZE(S)) SIZE(S) :S(OUTGB2) OUTFB S POS(P) BLANK :S(OUTGB) P = GT(P,0) P - 1 :S(OUTFB) OUTGB P = EQ(P,0) PAGEWID P = GE(P,SIZE(S)) SIZE(S) OUTGB2 S LEN(P) . S1 = NULL OUTPUT = S1 LC = LT(LC,PAGELEN) LC + 1 :S(OUTLOOP) NEWPAGE() :(OUTLOOP) OUTMORE :(OUTLIN) OUTLINX * Program start START PAGE = 0 LC = 0 * Here to initialize a new digest issue INITISS TITLE = NULL VOLUME = 0 ISSUE = 0 * New issue, discard mail header. BIGHDR LINE = INPUT :F(DONE) IDENT(LINE,NULL) :S(BODY) TEMP = REPLACE(LINE,LOWER,UPPER) TEMP SUBJ TITLE POS(0) SPAN(WS) = NULL :(BIGHDR) * Body of message, starts with "table of contents" (list of subjects) BODY TITLE ISUB :F(INITISS) NEWPAGE() TERMINAL = '** V' VOLUME ' #' ISSUE X = 'Volume ' VOLUME ', Number ' ISSUE CC = CC + 1 CONTENTS = X LPAD(PAGE,PAGEWID - SIZE(X)) TOC LINE = INPUT :F(DONE) OUTLIN(LINE) TOC2 LINE POS(0) '---' :F(TOC) * Here for digest messages. MSG0 LINE = INPUT :F(DONE) TEMP = REPLACE(LINE,LOWER,UPPER) OUTLIN(LINE) IDENT(LINE,NULL) :S(MSG0) * Look for message header with keywords, or else end of digest. MSGS TEMP POS(0) 'END' LEN(1) 'OF' LEN(1) 'INFO' ARB 'DIGEST' + :F(MSGHDX) * Here for end of digest. Gobble up junk until next digest. EOD LINE = INPUT :F(DONE) LINE POS(0) 'From ' :F(EOD)S(INITISS) * New message in current digest. Read headers, looking for keywords. MSGHDX LINE = INPUT :F(DONE) OUTLIN(LINE) IDENT(LINE,NULL) :S(MSGBODY) TEMP = REPLACE(LINE,LOWER,UPPER) LINE ASUB :F(MSGHDY) TEMP POS(0) 'RE:' :S(MSGHDY) TEMP 'NEW ' | 'ANNOUNC' | 'AVAILAB' | 'RELEAS' | 'PROPOS' | 'UPDATE' + | 'REPLAC' | ' BETA ' :F(MSGHDY) CC = CC + 1 CONTENTS = ' ' SUB LPAD(PAGE,PAGEWID - SIZE(SUB) - 2) :(MSGS) MSGHDY LINE KEYW :S(KEYWORD) LINE XREF :F(MSGS) * Got a cross reference to enter. SEE POS(0) SPAN(WS) = NULL KW = SEE SW = SEE REPLACE(SW,LOWER,UPPER) REFADD T = IXTB X = BLANK DIFFER(T,NULL) :S(KEYSCAN) II = LE(II,1000) II + 1 :S(KEYADD2) TERMINAL = "** Index overflow - Fatal!" :(END) * Got keyword header, enter into index. KEYWORD KEY = KEY ',' * Get next keyword from list. KEYSCAN KEY POS(0) SPAN(WS) = NULL IDENT(KEY,NULL) :S(MSGS) KEY POS(0) (DQ (BREAK(DQ) . KW) DQ ',') = NULL :S(KEYINDX) KEY (BREAK(',') . KW ',') = NULL :F(MSGS) * Make an all uppercase sort key from the keyword, and a trial page ref. KEYINDX KW = TRIM(KW) SW = REPLACE(KW,LOWER,UPPER) X = ', ' PAGE * See if this is a new item. If so, create a new array entry. KEYADD T = IXTB DIFFER(T,NULL) :S(KEYADD4) II = LE(II,1000) II + 1 :S(KEYADD2) TERMINAL = "** Index overflow - Fatal!" :(END) * Adding a new one KEYADD2 IXTB = II INDEX = KW INDEX = X :(KEYSCAN) * See if the page reference should be added, and in which form. KEYADD4 INDEX (BLANK | '-') PAGE RPOS(0) :S(KEYSCAN) INDEX LEN(1) . PUNC SPAN(DIGITS) . LAST RPOS(0) :F(KEYADD5) EQ(PAGE,LAST + 1) :F(KEYADD5) X = DIFFER(PUNC,'-') '-' PAGE :S(KEYADD5) INDEX LAST RPOS(0) = PAGE :(KEYSCAN) KEYADD5 INDEX = INDEX X :(KEYSCAN) * Now read and output the message body. MSGBODY LINE = INPUT :F(DONE) OUTLIN(LINE) LINE POS(0) '---' :S(MSG0) :(MSGBODY) * End of input file. Now output the index. DONE *** TERMINAL = '** Input complete, sorting Index...' A = SORT(IXTB) :S(IDXOUT) TERMINAL = '** Error converting index table' :(TOCOUT) IDXOUT EQ(REMDR(PAGE,2),1) NEWPAGE() TITLE = 'Index' NEWPAGE() I = 1 IDXLOOP J = A K = INDEX INDEX OUTLIN(K) I = LT(I,II) I + 1 :S(IDXLOOP) * And put the table of contents on the end. TOCOUT EQ(REMDR(PAGE,2),1) NEWPAGE() PAGE = -1 TITLE = 'Table of Contents' NEWPAGE() I = 0 TOCLOOP OUTLIN(CONTENTS) I = LE(I,CC) I + 1 :S(TOCLOOP) END