*-- doindex.sno 0.1 *-- Guido Milanese 2005 *-- guido.milanese@unicatt.it *-- Requires: * acc.inc * extrepl.inc * ioerror.inc * Please set tabstop=3 to read * Initializations &MAXLNGTH = 2000000 * If no arguments are given ( + (~(gt((size(host(2,4))),0))) + (terminal = "No file entered. Usage: doindex file.tex") + (terminal = "Help: doindex -help") + ) :s(end) * If help is required ( + ((host(2,4)) ? "-h") + (terminal = "Usage: doindex file.tex") + (terminal = "To exclude words containing non-English characters:" + " doindex file.tex -noacc") + (terminal = "Further options: please read the README file or the other documentation files") + ) :s(end) ******************************************** ** External functions ******************************************** * Accents ( + (((Accopt = host(2,5)) (Accopt ? "-noacc")) (Accopt = "en")), + (Accopt = "XX") + ) * all or english -include "acc.inc" (acc(Accopt) ? break('-') . accmi len(1) rem . accma ) acc = accmi accma * Extended replace -include "extrepl.inc" * Input-output -include "ioerror.inc" *********************************** * Internal functions *********************************** * Index adapt. define("iadapt(Datum)IL,ILK,A,I,Newdatum") Sep = '/' :(iadapt_end) iadapt Datum ? Sep :f(iadapt_rt) IL = Table() ILK = 0 ILK ILK = ILK + 1 ( + (Datum ? break(Sep) . IL[ILK] len(1) rem . Datum) + ) :s(ILK) A = rsort(IL) I = 0 iadapt_p I = I + 1 Newdatum = Newdatum '!' A[I,2] :S(iadapt_p)F(iadapt_nof) iadapt_nof Datum = Datum Newdatum iadapt_rt iadapt = Datum :(return) iadapt_end *************************** * Index Member * Modified version of Member.inc (gm) * Uses iadapt define("imember(Datum,List)I,Check,First") Sep = '/' :(imember_end) imember I = 0 imember_bg I = I + 1 First = &lcase &ucase ;* gives a faked value Check = List[I,2] :f(freturn) * With '@' or Sep ( + (List[I,2] ? break('@' Sep) . First) + (ident(First,Datum)) + ) :s(imember_rt) * Simple ident(List[I,2],Datum) :s(imember_rt)f(imember_bg) imember_rt imember = iadapt(List[I,2]) :(return) imember_end ********************************** *-- Redoin *-- Remove double index entries define("redoin(Pass)dindex1,dindex2") :(redoin_end) redoin redoin_lp ((Pass ? Dindex . VDindex) (ident(dindex1,dindex2)) + (Pass ? VDindex = dindex1)) :s(redoin_lp) redoin_rt redoin = Pass :(return) redoin_end ****************************************** * Patterns ****************************************** PNWord = span(&ucase &lcase acc) PIWord = ("\index" bal) PWord = PIWOrd | PNWord Dindex = (("\index{" break('}') len(1)) . dindex1) + (("\index{" break('}') len(1)) . dindex2) *********************************** * Read LaTeX file LATEXEXT = (".tex" | ".latex" | ".TEX" | ".LATEX") lfile = host(2,4) ;* LaTeX file input lfile ? '' (arb . file) LATEXEXT ifile = file ".wls" ofile = file "-ind.tex" ;* output *-- Input files. Using ERRORS ( (~(input("l_f",1, "B " &MAXLNGTH,lfile))) (ioerror("in",lfile)) ) :s(end) ( (~(input("i_f",2, &MAXLNGTH,ifile))) (ioerror("in",ifile)) ) :s(end) *-- File di output output("w_f",3, "B " &MAXLNGTH,ofile) :f(end) ************************************ * MAIN PROGRAM ************************************ * Text ((Text = l_f) (Terminal = "Read file " lfile ' [' size(Text) ' chars]')) :f(end) * List L = TABLE() LK = 0 LK LK = LK + 1 L[LK] = i_f :s(LK) * Converts to Array A = convert(L,"ARRAY") * Masks () and {} Text = extrepl(Text,'(', "&0028;") Text = extrepl(Text,')', "&0029;") Text = replace(Text,'{}','()') alfa Text2 = Text2 Previous Item Text ? ('' (arb . Previous) (PWord . Item)) rem . Text :f(omega) ( + ((Item ? PIWord) ( )), + ((Item ? PNWord) ( (Indexitem = imember(Item,A)) (Item = Item "\index(" Indexitem ")"))) + ) :(alfa) omega Text2 = Text2 Text * Replaces original () and {} Text2 = replace(Text2,"()","{}") Text2 = extrepl(Text2,"&0028;",'(') Text2 = extrepl(Text2,"&0029;",')') Text2 = redoin(Text2) ((w_f = Text2) (Terminal = "Written file " ofile ' [' size(Text2) ' chars]')) :f(end) end ****************************************** COMMENT (Please set tabstop=3 to read) ** Initializationa and external include files &MAXLNGTH = 2000000 should be enough for any normal LaTeX file -include "acc.inc" to use with non English texts. To exclude it, use the option "-noacc" (only words with no accented letters will be indexed) -include "extrepl.inc" makes possibile to change single chars with a string or vice-versa. -include "ioerror.inc" checks if input-output is correct ** Internal functions * "Index Member" checks if a word is included in the list of pre-indexed words. There are 3 possible situations in the list: (1) the item has '@' as in "cats@cat" (2) the item has a Sep as in "cats/animals" (3) the item is a simple word In the first or second case, the word being checked must be identical to the first part of the list item. E.g., "cats" must be identical, in "cats@cat" to "cats". "cats" must be identical, in "cats/animals" to "cats" In the final case, the list item must be identical to the checked word. * "Index adapt" changes a sequence like "cats/mammals/animals" to this form "animals!mammals!cats" If there is no TAB in the sequence, nothing happens. The trick is done so: (1) a table IL is initialized (2) Datum up to TAB is saved in IL[ILK] (loop) (3) The table is sorted reversed --> array. This array contains therefore the words from the last to the first (4) This array is scanned and the new form is produced. * "Redoin" removes double index entries from a file *** Patterns: A word can be part of an index sequence or not (this is important, because the files may contain already some indexed words): PNWord = span(&ucase &lcase acc) : Normal word PIWord = ("\index" bal) : Indexed word sequence PWord = PIWOrd | PNWord : Both DIndex is defined using break. *** Input-output Quite obvious. Extensions accepted are 'tex' and 'latex', both uppercase and lowercase. Calling the function IOERROR makes it possible to check if a file is really available. The LIST file must have the same name, with extension wls. *** Reading the List The List file must have this form: animals dogs/animals cats house/nouns/english/languages sleeping@sleep évita/Italian/foreign words ça/French/foreign words drücken/German/foreign words where each word is listed as such or as part of a structured index. This syntax seems more natural than the opposite one used by makeindex: for example a DOG is part of the class ANIMALS. This way it is easy to change indexes and adapt them to changing needs. The output of dogs animals will be \index{animals!dogs} ** Temporary protection of {} and () Unfortunately, the very solid Snobol BAL function supports only () pairs. So it is necessary: (1) to protect all the existing () -- they are changed into a XML-Unicode-like string ; (2) to chane all the {} pairs into () pairs. At the end of work, the reverse process is performed. ** Core of the program We must build a new text, called Text2, that is done adding: * the previous condition of Text2 (null string at the first loop) * the new portion of text being extracted at each loop, devided into: * Previous = what is before the word found * Item = the word For example, in "<