home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / e / index.sno < prev    next >
Text File  |  2020-01-01  |  7KB  |  265 lines

  1. * INDEX.SNO
  2. *
  3. * Formats a mail digest file for printing.  Does pagination, produces a
  4. * Table of Contents and an Index.  The Index is based on entries in the
  5. * message headers of the form
  6. *
  7. * Keywords: xxxx, xxxx, xxxx, "xxx, xxxx", xxxx
  8. * Cross-Ref: string
  9. *
  10. * A list of zero or more keywords may be included, separated by commas.
  11. * If the keyword itself is to contain a comma, it is enclosed in doublequotes.
  12. * The cross ref string is entered literally in the index.  Examples:
  13. *
  14. * Keywords: Blort
  15. * Keywords: Foo, Bar, This and That, "Law, Murphy's", Baz
  16. * Cross-Ref: Murphy's Law, see Law, Murphy's
  17. *
  18. * Any particular Cross-Reference need be entered in the file only once.
  19. * The index is sorted in ASCII order, so alphabetic case matters.
  20. *
  21. * The table of contents depends on the subject of each digest containing
  22. * the words "Info-Kermit Digest Vx #y", where x & y are the vol/issue number.
  23. * The end of a digest is detected by "End of InfoxxxxxDigest" where a
  24. * digest message header would start.
  25. *
  26. * F. da Cruz, C. Gianone, CUCCA, May 1986
  27. *
  28. * Modified May 88 to work with VAX spitbol
  29. * Modified Nov 88 to work with UNIX MM mail format
  30. * Modified Oct 91 to allow XREF as synonym for CROSS-REF
  31.  
  32.     &TRIM = 1
  33.     PAGEWID = 79
  34.     PAGELEN = 58
  35.  
  36. * Patterns
  37.  
  38.     NULL =
  39.     &ALPHABET POS(13) (LEN(1) . CR)
  40.     &ALPHABET POS(10) (LEN(1) . LF)
  41.     CRLF = CR LF
  42.     &ALPHABET POS(34) (LEN(1) . DQ)
  43.     BLANK = ' '
  44.     &ALPHABET POS(9) (LEN(1) . HT)
  45.     WS = BLANK HT
  46.     &ALPHABET POS(12) (LEN(1) . FF)
  47.     LOWER = 'abcdefghijklmnopqrstuvwxyz'
  48.     UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  49.     DIGITS = '0123456789'
  50.  
  51.     KEYS = 'Keywords' | 'Keyword' | 'KEYWORDS' | 'KEYWORD'
  52. +        | 'keywords' | 'keyword'
  53.     REFS = 'Cross-Ref' | 'Cross-Reference' | 'CROSS-REF'
  54. +        | 'XREF' | 'Xref' | 'xref'
  55.     KEYW = POS(0) KEYS ':' BREAK(WS) REM . KEY
  56.     XREF = POS(0) REFS ':' BREAK(WS) REM . SEE
  57.  
  58.     SUBJ = POS(0) 'SUBJECT:' BREAK(WS) REM . TITLE
  59.     ISUB = 'INFO' LEN(1) 'KERMIT' LEN(1) 'DIGEST V'
  60. +        SPAN(DIGITS) . VOLUME SPAN(BLANK) '#' SPAN(DIGITS) . ISSUE
  61.     ASUB = POS(0) 'subject:' | 'SUBJECT:' | 'Subject:' SPAN(WS) REM . SUB
  62.  
  63. * Table, array declarations
  64.  
  65.     IXTB = TABLE()
  66.     CONTENTS = ARRAY(500)
  67.     INDEX = ARRAY('1000,2')    
  68.     II = 0
  69.     CC = 0
  70.  
  71. * Newpage function definition.  Starts a new page, puts heading on top
  72. * composed of current digest title and page number.  Set PAGE = -1 to
  73. * disable page number.  Reverses page headings.
  74.  
  75.     DEFINE('NEWPAGE()')                :(NEWPAGX)
  76. NEWPAGE    OUTPUT = FF
  77.     GE(PAGE,0)                    :S(NEWP2)
  78.     OUTPUT = TITLE
  79.     OUTPUT =                     :(NEWP4)
  80. NEWP2    PAGE = PAGE + 1
  81.     X = 'Page ' PAGE
  82.     EQ(REMDR(PAGE,2),1)                :S(NEWP3)
  83.     OUTPUT = X LPAD(TITLE,PAGEWID - SIZE(X))    :(NEWP4)
  84. NEWP3    OUTPUT = TITLE LPAD(X,PAGEWID - SIZE(TITLE))
  85. NEWP4    OUTPUT =
  86.     LC = 3                        :(RETURN)
  87. NEWPAGX
  88.  
  89. * Function to output a line.  If the line is longer than the page
  90. * width, it is broken at the nearest blank, and two (or more) lines are
  91. * output.  If the bottom of the page is reached, a new page is started.
  92.  
  93.     DEFINE('OUTLIN(S)')                :(OUTLINX)
  94. OUTLIN                            :(OUTLIN2)
  95. OUTLOOP    IDENT(S,NULL)                    :S(RETURN)
  96. OUTLIN2    P = PAGEWID
  97.     P = GE(P,SIZE(S)) SIZE(S)            :S(OUTGB2)
  98.  
  99. OUTFB    S POS(P) BLANK                    :S(OUTGB)
  100.     P = GT(P,0) P - 1                :S(OUTFB)
  101.  
  102. OUTGB    P = EQ(P,0) PAGEWID
  103.     P = GE(P,SIZE(S)) SIZE(S)
  104.  
  105. OUTGB2    S LEN(P) . S1 = NULL
  106.     OUTPUT = S1
  107.     LC = LT(LC,PAGELEN) LC + 1            :S(OUTLOOP)
  108.     NEWPAGE()                    :(OUTLOOP)
  109. OUTMORE
  110.                             :(OUTLIN)
  111. OUTLINX                
  112.  
  113. * Program start
  114.  
  115. START    PAGE = 0
  116.     LC = 0
  117.  
  118. * Here to initialize a new digest issue
  119.  
  120. INITISS    TITLE = NULL
  121.     VOLUME = 0
  122.     ISSUE = 0
  123.     
  124. * New issue, discard mail header.
  125.  
  126. BIGHDR    LINE = INPUT                    :F(DONE)
  127.     IDENT(LINE,NULL)                :S(BODY)
  128.     TEMP = REPLACE(LINE,LOWER,UPPER)
  129.     TEMP SUBJ
  130.     TITLE POS(0) SPAN(WS) = NULL            :(BIGHDR)
  131.  
  132. * Body of message, starts with "table of contents" (list of subjects)
  133.  
  134. BODY    TITLE ISUB                    :F(INITISS)
  135.     NEWPAGE()
  136.     TERMINAL = '** V' VOLUME ' #' ISSUE
  137.     X = 'Volume ' VOLUME ', Number ' ISSUE
  138.     CC = CC + 1
  139.     CONTENTS<CC> = X LPAD(PAGE,PAGEWID - SIZE(X))
  140.  
  141. TOC    LINE = INPUT                    :F(DONE)
  142.     OUTLIN(LINE)
  143. TOC2    LINE POS(0) '---'                :F(TOC)
  144.  
  145. * Here for digest messages.
  146.  
  147. MSG0    LINE = INPUT                    :F(DONE)
  148.     TEMP = REPLACE(LINE,LOWER,UPPER)
  149.     OUTLIN(LINE)
  150.     IDENT(LINE,NULL)                :S(MSG0)
  151.  
  152. * Look for message header with keywords, or else end of digest.
  153.  
  154. MSGS    TEMP POS(0) 'END' LEN(1) 'OF' LEN(1) 'INFO' ARB 'DIGEST'
  155. +                            :F(MSGHDX)
  156.  
  157. * Here for end of digest.  Gobble up junk until next digest.
  158.     
  159. EOD    LINE = INPUT                    :F(DONE)
  160.     LINE POS(0) 'From '                :F(EOD)S(INITISS)
  161.  
  162. * New message in current digest.  Read headers, looking for keywords.
  163.  
  164. MSGHDX    LINE = INPUT                    :F(DONE)
  165.     OUTLIN(LINE)
  166.     IDENT(LINE,NULL)                :S(MSGBODY)
  167.     TEMP = REPLACE(LINE,LOWER,UPPER)
  168.     LINE ASUB                    :F(MSGHDY)
  169.     TEMP POS(0) 'RE:'                :S(MSGHDY)
  170.     TEMP 'NEW ' | 'ANNOUNC' | 'AVAILAB' | 'RELEAS' | 'PROPOS' | 'UPDATE'
  171. +     | 'REPLAC' | ' BETA '                :F(MSGHDY)
  172.     CC = CC + 1
  173.     CONTENTS<CC> = '  ' SUB LPAD(PAGE,PAGEWID - SIZE(SUB) - 2)
  174.                             :(MSGS)
  175. MSGHDY    LINE KEYW                    :S(KEYWORD)
  176.     LINE XREF                    :F(MSGS)
  177.  
  178. * Got a cross reference to enter.
  179.  
  180.     SEE POS(0) SPAN(WS) = NULL
  181.     KW = SEE
  182.     SW = SEE
  183.     REPLACE(SW,LOWER,UPPER)
  184.  
  185. REFADD    T = IXTB<SW>
  186.     X = BLANK
  187.     DIFFER(T,NULL)                    :S(KEYSCAN)
  188.     II = LE(II,1000) II + 1                :S(KEYADD2)
  189.     TERMINAL = "** Index overflow - Fatal!"        :(END)
  190.  
  191. * Got keyword header, enter into index.
  192.  
  193. KEYWORD    KEY = KEY ','
  194.  
  195. * Get next keyword from list.
  196.  
  197. KEYSCAN    KEY POS(0) SPAN(WS) = NULL
  198.     IDENT(KEY,NULL)                    :S(MSGS)
  199.     KEY POS(0) (DQ (BREAK(DQ) . KW) DQ ',') = NULL     :S(KEYINDX)
  200.     KEY (BREAK(',') . KW ',') = NULL        :F(MSGS)
  201.  
  202. * Make an all uppercase sort key from the keyword, and a trial page ref.
  203.  
  204. KEYINDX    KW = TRIM(KW)
  205.     SW = REPLACE(KW,LOWER,UPPER)
  206.     X = ', ' PAGE
  207.  
  208. * See if this is a new item.  If so, create a new array entry.
  209.  
  210. KEYADD    T = IXTB<SW>
  211.     DIFFER(T,NULL)                    :S(KEYADD4)
  212.     II = LE(II,1000) II + 1                :S(KEYADD2)
  213.     TERMINAL = "** Index overflow - Fatal!"        :(END)
  214.  
  215. * Adding a new one
  216.  
  217. KEYADD2    IXTB<SW> = II    
  218.     INDEX<II,1> = KW
  219.     INDEX<II,2> = X                    :(KEYSCAN)
  220.  
  221. * See if the page reference should be added, and in which form.
  222.  
  223. KEYADD4
  224.     INDEX<T,2> (BLANK | '-') PAGE RPOS(0)        :S(KEYSCAN)
  225.     INDEX<T,2> LEN(1) . PUNC SPAN(DIGITS) . LAST RPOS(0) :F(KEYADD5)
  226.     EQ(PAGE,LAST + 1)                :F(KEYADD5)
  227.     X = DIFFER(PUNC,'-') '-' PAGE            :S(KEYADD5)
  228.     INDEX<T,2> LAST RPOS(0) = PAGE            :(KEYSCAN)
  229. KEYADD5    INDEX<T,2> = INDEX<T,2> X             :(KEYSCAN)
  230.  
  231. * Now read and output the message body.
  232.  
  233. MSGBODY    LINE = INPUT                    :F(DONE)
  234.     OUTLIN(LINE)
  235.     LINE POS(0) '---'                :S(MSG0)
  236.                             :(MSGBODY)
  237. * End of input file.  Now output the index.
  238.  
  239. DONE
  240. ***    TERMINAL = '** Input complete, sorting Index...'
  241.     A = SORT(IXTB)                    :S(IDXOUT)
  242.     TERMINAL = '** Error converting index table'    :(TOCOUT)
  243.  
  244. IDXOUT    EQ(REMDR(PAGE,2),1) NEWPAGE()
  245.     TITLE = 'Index'
  246.     NEWPAGE()
  247.     I = 1
  248.  
  249. IDXLOOP    J = A<I,2>
  250.     K = INDEX<J,1> INDEX<J,2>
  251.     OUTLIN(K)
  252.     I = LT(I,II) I + 1                :S(IDXLOOP)
  253.  
  254. * And put the table of contents on the end.
  255.  
  256. TOCOUT    EQ(REMDR(PAGE,2),1) NEWPAGE()
  257.     PAGE = -1
  258.     TITLE = 'Table of Contents'
  259.     NEWPAGE()
  260.     I = 0
  261. TOCLOOP    OUTLIN(CONTENTS<I>)
  262.     I = LE(I,CC) I + 1                :S(TOCLOOP)
  263.  
  264. END
  265.