py-cvs-rel2_1 (Rev 1.2) merge
[python/dscho.git] / Tools / bgen / bgen / bgenOutput.py
blob1a512e5c8b3b064743410ebb0efff9d3a37b26ee
1 """Output primitives for the binding generator classes.
3 This should really be a class, but then everybody would be passing
4 the output object to each other. I chose for the simpler approach
5 of a module with a global variable. Use SetOutputFile() or
6 SetOutputFileName() to change the output file.
7 """
9 _NeedClose = 0
11 def SetOutputFile(file = None, needclose = 0):
12 """Call this with an open file object to make it the output file.
14 Call it without arguments to close the current file (if necessary)
15 and reset it to sys.stdout.
16 If the second argument is true, the new file will be explicitly closed
17 on a subsequence call.
18 """
19 global _File, _NeedClose
20 if _NeedClose:
21 tmp = _File
22 _NeedClose = 0
23 _File = None
24 tmp.close()
25 if file is None:
26 import sys
27 file = sys.stdout
28 _File = file
29 _NeedClose = file and needclose
31 def SetOutputFileName(filename = None):
32 """Call this with a filename to make it the output file.
34 Call it without arguments to close the current file (if necessary)
35 and reset it to sys.stdout.
36 """
37 SetOutputFile()
38 if filename:
39 SetOutputFile(open(filename, 'w'), 1)
41 SetOutputFile() # Initialize _File
43 _Level = 0 # Indentation level
45 def GetLevel():
46 """"Return the current indentation level."""
47 return _Level
49 def SetLevel(level):
50 """Set the current indentation level.
52 This does no type or range checking -- use at own risk.
53 """
54 global _Level
55 _Level = level
57 def Output(format = "", *args):
58 VaOutput(format, args)
60 def VaOutput(format, args):
61 """Call this with a format string and and argument tuple for the format.
63 A newline is always added. Each line in the output is indented
64 to the proper indentation level -- even if the result of the
65 format expansion contains embedded newlines. Exception: lines
66 beginning with '#' are not indented -- these are assumed to be
67 C preprprocessor lines.
68 """
69 text = format % args
70 if _Level > 0:
71 indent = '\t' * _Level
72 import string
73 lines = string.splitfields(text, '\n')
74 for i in range(len(lines)):
75 if lines[i] and lines[i][0] != '#':
76 lines[i] = indent + lines[i]
77 text = string.joinfields(lines, '\n')
78 _File.write(text + '\n')
80 def IndentLevel(by = 1):
81 """Increment the indentation level by one.
83 When called with an argument, adds it to the indentation level.
84 """
85 global _Level
86 if _Level+by < 0:
87 raise Error, "indentation underflow (internal error)"
88 _Level = _Level + by
90 def DedentLevel(by = 1):
91 """Decrement the indentation level by one.
93 When called with an argument, subtracts it from the indentation level.
94 """
95 IndentLevel(-by)
97 def OutIndent(format = "", *args):
98 """Combine Output() followed by IndentLevel().
100 If no text is given, acts like lone IndentLevel().
102 if format: VaOutput(format, args)
103 IndentLevel()
105 def OutDedent(format = "", *args):
106 """Combine Output() followed by DedentLevel().
108 If no text is given, acts like loneDedentLevel().
110 if format: VaOutput(format, args)
111 DedentLevel()
113 def OutLbrace(format = "", *args):
114 """Like Output, but add a '{' and increase the indentation level.
116 If no text is given a lone '{' is output.
118 if format:
119 format = format + " {"
120 else:
121 format = "{"
122 VaOutput(format, args)
123 IndentLevel()
125 def OutRbrace():
126 """Decrease the indentation level and output a '}' on a line by itself."""
127 DedentLevel()
128 Output("}")
130 def OutHeader(text, dash):
131 """Output a header comment using a given dash character."""
132 n = 64 - len(text)
133 Output()
134 Output("/* %s %s %s */", dash * (n/2), text, dash * (n - n/2))
135 Output()
137 def OutHeader1(text):
138 """Output a level 1 header comment (uses '=' dashes)."""
139 OutHeader(text, "=")
141 def OutHeader2(text):
142 """Output a level 2 header comment (uses '-' dashes)."""
143 OutHeader(text, "-")
145 def Out(text):
146 """Output multiline text that's internally indented.
148 Pass this a multiline character string. The whitespace before the
149 first nonblank line of the string will be subtracted from all lines.
150 The lines are then output using Output(), but without interpretation
151 of formatting (if you need formatting you can do it before the call).
152 Recommended use:
154 Out('''
155 int main(argc, argv)
156 int argc;
157 char *argv;
159 printf("Hello, world\\n");
160 exit(0);
162 ''')
164 Caveat: the indentation must be consistent -- if you use three tabs
165 in the first line, (up to) three tabs are removed from following lines,
166 but a line beginning with 24 spaces is not trimmed at all. Don't use
167 this as a feature.
169 # (Don't you love using triple quotes *inside* triple quotes? :-)
171 import string
172 lines = string.splitfields(text, '\n')
173 indent = ""
174 for line in lines:
175 if string.strip(line):
176 for c in line:
177 if c not in string.whitespace:
178 break
179 indent = indent + c
180 break
181 n = len(indent)
182 for line in lines:
183 if line[:n] == indent:
184 line = line[n:]
185 else:
186 for c in indent:
187 if line[:1] <> c: break
188 line = line[1:]
189 VaOutput("%s", line)
192 def _test():
193 """Test program. Run when the module is run as a script."""
194 OutHeader1("test bgenOutput")
195 Out("""
196 #include <Python.h>
197 #include <stdio.h>
199 main(argc, argv)
200 int argc;
201 char **argv;
203 int i;
204 """)
205 IndentLevel()
206 Output("""\
207 /* Here are a few comment lines.
208 Just to test indenting multiple lines.
210 End of the comment lines. */
211 """)
212 Output("for (i = 0; i < argc; i++)")
213 OutLbrace()
214 Output('printf("argv[%%d] = %%s\\n", i, argv[i]);')
215 OutRbrace()
216 Output("exit(0)")
217 OutRbrace()
218 OutHeader2("end test")
220 if __name__ == '__main__':
221 _test()