refer.py: New app, close to working. To identify
[dwarf-doc.git] / dwarf5 / tools / fileio.py
1 # Copyright 2012 DWARF Debugging Information Format Committee
2
3 # All the little classes used in storing latex source data.
4 # Reads in the tex source and builds internal lists of the
5 # tokenized source.  The tokenization is adequate
6 # for our purposes, but just barely adequate.
7
8 import sys
9
10 # Keep if  "k" 
11 # Otherwise delete.
12 global keepcomments
13 keepcomments = "k"
14
15 def isIdStart(c):
16   if isIndivid(c) == "y":
17     return "n"
18   if  ord(c) >= ord('a') and ord(c) <= ord('z'):
19     return "y"
20   if  ord(c) >= ord('A') and ord(c) <= ord('Z'):
21     return "y"
22   # It is tex/latex, so backslash starts a word.
23   if c == "\\":
24     return "y"
25   if c == "_":
26     return "y"
27   return "n"
28
29 def isIdNext(c):
30   if isIndivid(c) == "y":
31     return "n"
32   if  ord(c) >= ord('a') and ord(c) <= ord('z'):
33     return "y"
34   if  ord(c) >= ord('A') and ord(c) <= ord('Z'):
35     return "y"
36   if  ord(c) >= ord('0') and ord(c) <= ord('9'):
37     return "y"
38   # This is so we allow the colon in our tags
39   # Unfortunately, this gives trouble if we have a
40   # : at the end of a DW* name on input.
41   if c == ":":
42     return "y"
43   # Do not allow \ in the middle of a name.
44   if c == "\\":
45     return "n"
46   if c == "-":
47     return "y"
48   if c == "_":
49     return "y"
50   return "n"
51 def isShift(c):
52   if ord(c) >= 128:
53     return "y"
54   return "n"
55 def isIndivid(c):
56   if c == "[":
57     return "y"
58   if c == "]":
59     return "y"
60   if c == "{":
61     return "y"
62   if c == "}":
63     return "y"
64   if c == " ":
65     return "y"
66   if c == "\t":
67     return "y"
68   return "n"
69
70 # self._tex        DW\-\_ATE and the like
71 # self._underbar   DW\_ATE  and the like
72 # self._std   the way a DW_ATE and the like looks in the standard
73 # self._label With all _ and - removed.  Like DWATE
74
75 class dwtoken:
76   """ Token types: 
77   id: identifier
78   ind: a character taken as an individual character.
79   none: No characters seen yet.
80   shift: A character with the high bit of 8 bits set, not something we expect.
81   -      In DW4 these high-bit-chars are special 3-character left and right quotes.
82   -      charfix.py  can replace these with Latex ascii quotes.
83   other: Some other character, but ascii, seemingly.  """
84   def __init__(self):
85     self._tex = []
86     self._underbar = []
87     self._std = []
88     self._label = []
89     # Class is "id", "ind","other","shift","none"
90     self._class = "none"
91   def insertid(self,string):
92     self._class =  "id"
93     self._tex = list(string)
94     self._underbar = self._tex
95     self._std = self._tex
96     self._label = self._tex
97   def setIndivid(self,c):
98     self._tex = [c]
99     self._underbar = [c]
100     self._std = [c]
101     self._label = [c]
102     self._class =  "ind"
103   def setInitialIdChar(self,c):
104     self._tex = [c]
105     self._class =  "id"
106   def setNextIdChar(self,c):
107     self._tex += [c]
108
109   def setInitialShift(self,c):
110     self._tex = [c]
111     self._underbar = [c]
112     self._std = [c]
113     self._label = [c]
114     self._class =  "shift"
115   def setNextShift(self,c):
116     self._tex += [c]
117     self._underbar += [c]
118     self._std += [c]
119     self._label += [c]
120     self._class =  "shift"
121   def setInitialOther(self,c):
122     self._tex = [c]
123     self._underbar = [c]
124     self._std = [c]
125     self._label = [c]
126     self._class =  "other"
127   def setNextOther(self,c):
128     self._tex += [c]
129     self._underbar += [c]
130     self._std += [c]
131     self._label += [c]
132     self._class =  "other"
133   def finishUpId(self):
134     """ This transforms the strings from the input form into
135         the internal forms we want.
136     """
137     self._underbar = []
138     self._std = []
139     self._label = []
140     n = 0
141     # Drop \-
142     while int(n) < len(self._tex):
143       c = self._tex[n]
144       if n < (len (self._tex) - 1) and c == "\\" and self._tex[n+1] == "-":
145         n = n +2
146         continue
147       self._underbar += [c]
148       n = n +1
149     # Drop \ from \_
150     n = 0
151     while int(n) < len(self._underbar):
152       c = self._underbar[n]
153       if n < (len (self._underbar) - 1) and c == "\\" and self._underbar[n+1] == "_":
154         n = n +1
155         continue
156       self._std += [c]
157       n = n +1
158     # Drop  underbar
159     n = 0
160     while int(n) < len(self._std):
161       c = self._std[n]
162       if  c == "_":
163         n = n +1
164         continue
165       self._label += [c]
166       n = n +1
167
168   def dwprintquotedshortform(self,d):
169       print "'",self.shortform(d),"'",
170   def shortform(self,d):
171       return ''.join(d)
172   def dwprint(self):
173     if self._class == "ind":
174       print self._class, 
175       self.dwprintquotedshortform(self._tex)
176       print ""
177     else:
178       # This prints the token with end-line oddly.
179       print self._class, 
180       self.dwprintquotedshortform(self._tex)
181       self.dwprintquotedshortform(self._underbar)
182       self.dwprintquotedshortform(self._std)
183       self.dwprintquotedshortform(self._label)
184       print ""
185   def dwwrite(self,outfile):
186     for x in self._tex:
187       outfile.write(x)
188
189 class  dwline:
190   """using an input line, create a list of tokens for the line.
191      Legal class transitions in tokenize() are:
192      none->shift
193      none->other
194      none->id
195      none->ind
196
197      other->ind
198      other->id
199      other->shift
200
201      shift->id
202      shift->ind
203      shift->other
204
205      id->ind
206      id->other
207      id->shift
208   """
209   def __init__(self):
210     # list of dwtoken.
211     self._toks = []
212
213   
214   def tokenize(self,rec,filename,linenum):
215     """using an input line, create a list of tokens for the line.
216        Legal class transitions in tokenize() are:
217        none->other
218        none->id
219        none->ind
220        other->ind
221        other->id
222        id->ind
223        id->other
224     """
225     dwclass = "none"
226     combotok = dwtoken()
227     charnum= -1 
228     global keepcomments
229     for c in rec:
230       charnum = charnum +1
231       if ord(c) >= 128:
232         print " Warning: encountered character ord:",ord(c), "at offset",charnum,"line",linenum,filename
233       if keepcomments == "d" and c == "%" and ( charnum == 0 or rec[charnum - 1] != "\\" ):  
234         # Not keeping comments. We drop % and following to end of line 
235         # unless preceeded by \ 
236         break
237
238       if c == "\n" or c == "\r":
239           # Just drop these for now. Allowing them
240           # would not be harmful.
241           continue
242       elif dwclass == "none" or dwclass == "ind":
243         if isShift(c) == "y":
244           combotok.setInitialShift(c)
245           dwclass = "shift"
246           continue
247         if isIndivid(c) == "y":
248           a = dwtoken()
249           a.setIndivid(c);
250           self._toks += [a]
251           continue
252         if isIdStart(c) == "y":
253           combotok.setInitialIdChar(c)
254           dwclass = "id"
255           continue
256         # is "other"
257         combotok.setInitialOther(c)
258         dwclass = "other"
259         continue
260       elif dwclass == "id": 
261         if isIdNext(c) == "y":
262           combotok.setNextIdChar(c)
263           continue
264         if isShift(c) == "y":
265           combotok.finishUpId()
266           self._toks += [combotok]
267           combotok = dwtoken()
268           combotok.setInitialShift(c);
269           dwclass = "shift"
270           continue
271         if isIndivid(c) == "y":
272           combotok.finishUpId()
273           self._toks += [combotok]
274           combotok = dwtoken()
275           a = dwtoken()
276           a.setIndivid(c);
277           dwclass = "ind"
278           self._toks += [a]
279           continue
280         # Other class input, other starts here.
281         combotok.finishUpId()
282         self._toks += [combotok]
283         combotok = dwtoken()
284         combotok.setInitialOther(c);
285         dwclass = "other"
286         continue
287       elif dwclass == "shift":
288         if isShift(c) == "y":
289           combotok.setNextShift(c);
290           continue
291         if isIndivid(c) == "y":
292           self._toks += [combotok]
293           combotok = dwtoken()
294           a = dwtoken()
295           a.setIndivid(c);
296           dwclass = "ind"
297           self._toks += [a]
298           continue
299         if isIdStart(c) == "y":
300           self._toks += [combotok]
301           combotok = dwtoken()
302           combotok.setInitialIdChar(c);
303           dwclass = "id"
304           continue
305         # Shift class input, other starts here.
306         self._toks += [combotok]
307         combotok = dwtoken()
308         combotok.setInitialOther(c);
309         dwclass = "other"
310         continue
311       elif dwclass == "other":
312         if isShift(c) == "y":
313           self._toks += [combotok]
314           combotok = dwtoken()
315           combotok.setInitialShift(c);
316           dwclass = "shift"
317           continue
318         if isIndivid(c) == "y":
319           self._toks += [combotok]
320           combotok = dwtoken()
321           a = dwtoken()
322           a.setIndivid(c);
323           dwclass = "ind"
324           self._toks += [a]
325           continue
326         if isIdStart(c) == "y":
327           self._toks += [combotok]
328           combotok = dwtoken()
329           combotok.setInitialIdChar(c);
330           dwclass = "id"
331           continue
332         combotok.setNextOther(c);
333         continue
334       # Else case impossible.
335      
336     #Finish up final non-empty other or id token
337     if dwclass == "id":
338       combotok.finishUpId()
339       self._toks += [combotok]
340       dwclass = "none"
341     if dwclass == "shift":
342       self._toks += [combotok]
343       dwclass = "none"
344     if dwclass == "other":
345       self._toks += [combotok]
346       dwclass = "none"
347   def dwprint(self,linenum):
348     print "Number of tokens in line ",linenum," : ",len(self._toks)
349     if len(self._toks) == 0:
350       #Just print an empty line.
351       print ""
352     else:
353       for t in self._toks:
354         t.dwprint()
355   def dwwrite(self, outfile, linenum):
356     for t in self._toks:
357       t.dwwrite(outfile)
358     outfile.write("\n")
359   def dwtransformline(self,callfunc,myfile,lnum):
360     toks = callfunc(self._toks,myfile,lnum)
361     self._toks = toks
362     
363
364 class dwfile:
365   def __init__(self,name):
366     # list of dwline.
367     self._name = name
368     # Name of the file.
369     self._lines = []
370     try:
371       file = open(name,"r");
372     except IOError, message:
373       print >> sys.stderr , "File could not be opened: ", name
374       sys.exit(1)
375     linenum=0
376     while 1:
377       try:
378         rec = file.readline()
379       except EOFError:
380         break
381       if len(rec) < 1:
382         # eof
383         break
384       linenum = linenum +1
385       aline = dwline()
386       aline.tokenize(rec,name,linenum)
387       self._lines += [aline]
388
389   def dwprint(self):
390     print "Number of lines in ", self._name, ":  ",len(self._lines)
391     lnum = 1
392     for l in self._lines:
393        l.dwprint(lnum)
394        lnum = lnum + 1
395   def dwwrite(self):
396     # The lnum is just for debugging messages.
397
398     outname = self._name + ".out"
399     print outname
400     try:
401       outfile = open(outname,"w");
402     except IOError, message:
403       print >> sys.stderr , "Output File could not be opened: ", name
404       sys.exit(1)
405     lnum = 1
406     for l in self._lines:
407       l.dwwrite(outfile,lnum)
408       lnum = lnum + 1
409   def dwtransformline(self,callfunc,myfile):
410     lnum=1
411     for l in self._lines:
412       l.dwtransformline(callfunc,myfile,lnum)
413       lnum = lnum + 1
414     
415
416
417 class dwfiles:
418   def __init__(self):
419     # list of dwfile.
420     self._files = []
421
422   def addFile(self,name):
423     f = dwfile(name)
424     self._files += [f]
425     
426   def dwprint(self):
427     print "Number of files: ",len(self._files);
428     for f in self._files:
429       f.dwprint()
430   def dwwrite(self):
431     for f in self._files:
432       f.dwwrite()
433   def dwtransformline(self,callfunc):
434     for f in self._files:
435       f.dwtransformline(callfunc,f)
436
437
438 def setkeepordeletecomments(val):
439   """ Pass in "k" or "d" to keep or delete comments, respectively """
440   global keepcomments
441   keepcomments = val
442
443 def readFilelist(filelist):
444   dwf = dwfiles()
445   for f in filelist:
446     dwf.addFile(f)
447   return dwf
448