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