summaryrefslogtreecommitdiff
path: root/indexing/forindex/source/doindex.sno
blob: 2a93225bf248a9a48e6b6593aa1d3028c012d4a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
*-- 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 "<<This": '<<' is Previous, 'This' is Item.
		Previous is not analyzed any more, Item is sent to the following analysis
		process.
Code:
*******
alfa
	Text2 = Text2 Previous Item
*******

Now the procedure to extract single words:
	In Text, what is found before a Word, and call it Previous. a Word is found
	if corresponds to the pattern PWord, and saved as Item. What remains is
	called again Text, in order to make the loop possible. If the pattern
	matching fails, it means that Text is exausted, and we leave the loop.
Code:	
	Text ? ('' (arb . Previous) (PWord . Item)) rem . Text :f(omega)

Now the scanning of Item. The code says:
		if Item is an indexed sequence (as "\index{rose}"), do not do anything
		if Item is a word, check if it is a member of the list of words to be
		indexed passed to the program. If so, all the procedures of IMEMBER and
		IADAPT will be called. If it is not a member of the list, IMEMBER fails an
		nothing happens.
Code:
*********
	(
+		((Item ? PIWord) ( )),
+	((Item ? PNWord) ( (Indexitem = imember(Item,A)) (Item = Item "\index(" Indexitem ")")))
+	)	:(alfa)
*********

At the end, Text2 receives the final portion of Text (if any). For example, if a
		  text end with the string "animals." the string "animal" will be recognized as a
		  Word, but the remaining protion, i.e. the final full stop, will be not
		  analyzed any further. Therefore, this portion of thext must be added.
Code:
********
omega
	Text2 = Text2 Text
********

Possible double index entries are removed.

Finally, the replacement od () and {} pairs is performed, and Text2 written in
the output file, with some additional info to the user.

Genoa, Italy, 26th of January 2005