home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
e
/
index.sno
< prev
next >
Wrap
Text File
|
1994-11-24
|
7KB
|
265 lines
* 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<CC> = 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<CC> = ' ' 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<SW>
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<SW>
DIFFER(T,NULL) :S(KEYADD4)
II = LE(II,1000) II + 1 :S(KEYADD2)
TERMINAL = "** Index overflow - Fatal!" :(END)
* Adding a new one
KEYADD2 IXTB<SW> = II
INDEX<II,1> = KW
INDEX<II,2> = X :(KEYSCAN)
* See if the page reference should be added, and in which form.
KEYADD4
INDEX<T,2> (BLANK | '-') PAGE RPOS(0) :S(KEYSCAN)
INDEX<T,2> LEN(1) . PUNC SPAN(DIGITS) . LAST RPOS(0) :F(KEYADD5)
EQ(PAGE,LAST + 1) :F(KEYADD5)
X = DIFFER(PUNC,'-') '-' PAGE :S(KEYADD5)
INDEX<T,2> LAST RPOS(0) = PAGE :(KEYSCAN)
KEYADD5 INDEX<T,2> = INDEX<T,2> 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<I,2>
K = INDEX<J,1> INDEX<J,2>
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>)
I = LE(I,CC) I + 1 :S(TOCLOOP)
END