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