1# -*- python -*- 2# Package : omniidl 3# output.py Created on: 1999/10/27 4# Author : Duncan Grisby (dpg1) 5# 6# Copyright (C) 2011 Apasphere Ltd 7# Copyright (C) 1999 AT&T Laboratories Cambridge 8# 9# This file is part of omniidl. 10# 11# omniidl is free software; you can redistribute it and/or modify it 12# under the terms of the GNU General Public License as published by 13# the Free Software Foundation; either version 2 of the License, or 14# (at your option) any later version. 15# 16# This program is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 19# General Public License for more details. 20# 21# You should have received a copy of the GNU General Public License 22# along with this program. If not, see http://www.gnu.org/licenses/ 23# 24# Description: 25# 26# IDL compiler output functions 27 28"""Output stream 29 30Class: 31 32 Stream -- output stream which outputs templates, performing 33 key/value substitution and indentation.""" 34 35def dummy(): pass 36 37StringType = type("") 38FuncType = type(dummy) 39 40class Stream: 41 """IDL Compiler output stream class 42 43The output stream takes a template string containing keys enclosed in 44'@' characters and replaces the keys with their associated values. It 45also provides counted indentation levels. 46 47 eg. Given the template string: 48 49 template = \"\"\"\\ 50class @id@ { 51public: 52 @id@(@type@ a) : a_(a) {} 53 54private: 55 @type@ a_; 56};\"\"\" 57 58 Calling s.out(template, id="foo", type="int") results in: 59 60 class foo { 61 public: 62 foo(int a) : a_(a) {} 63 64 private: 65 int a_; 66 }; 67 68 69Functions: 70 71 __init__(file, indent_size) -- Initialise the stream with the 72 given file and indent size. 73 inc_indent() -- Increment the indent level. 74 dec_indent() -- Decrement the indent level. 75 out(template, key=val, ...) -- Output the given template with 76 key/value substitution and 77 indenting. 78 niout(template, key=val, ...) -- As out(), but with no indenting.""" 79 80 81 def __init__(self, file, indent_size = 2): 82 self.file = file 83 self.indent_size = indent_size 84 self.indent = 0 85 self.do_indent = 1 86 87 def inc_indent(self): self.indent = self.indent + self.indent_size 88 def dec_indent(self): self.indent = self.indent - self.indent_size 89 90 def out(self, text, ldict={}, **dict): 91 """Output a multi-line string with indentation and @@ substitution.""" 92 93 dict.update(ldict) 94 95 pos = 0 96 tlist = text.split("@") 97 ltlist = len(tlist) 98 i = 0 99 while i < ltlist: 100 101 # Output plain text 102 pos = self.olines(pos, self.indent, tlist[i]) 103 104 i = i + 1 105 if i == ltlist: break 106 107 # Evaluate @ expression 108 try: 109 expr = dict[tlist[i]] 110 except: 111 # If a straight look-up failed, try evaluating it 112 if tlist[i] == "": 113 expr = "@" 114 else: 115 expr = eval(tlist[i], globals(), dict) 116 117 if type(expr) is StringType: 118 pos = self.olines(pos, pos, expr) 119 elif type(expr) is FuncType: 120 oindent = self.indent 121 self.indent = pos 122 apply(expr) 123 self.indent = oindent 124 else: 125 pos = self.olines(pos, pos, str(expr)) 126 127 i = i + 1 128 129 self.odone() 130 131 def niout(self, text, ldict={}, **dict): 132 """Output a multi-line string without indentation.""" 133 134 dict.update(ldict) 135 136 pos = 0 137 tlist = text.split("@") 138 ltlist = len(tlist) 139 i = 0 140 while i < ltlist: 141 142 # Output plain text 143 pos = self.olines(pos, 0, tlist[i]) 144 145 i = i + 1 146 if i == ltlist: break 147 148 # Evaluate @ expression 149 try: 150 expr = dict[tlist[i]] 151 except: 152 # If a straight look-up failed, try evaluating it 153 if tlist[i] == "": 154 expr = "@" 155 else: 156 expr = eval(tlist[i], globals(), dict) 157 158 if type(expr) is StringType: 159 pos = self.olines(pos, pos, expr) 160 elif type(expr) is FuncType: 161 oindent = self.indent 162 self.indent = pos 163 apply(expr) 164 self.indent = oindent 165 else: 166 pos = self.olines(pos, pos, str(expr)) 167 168 i = i + 1 169 170 self.odone() 171 172 173 def olines(self, pos, indent, text): 174 istr = " " * indent 175 write = self.file.write 176 177 stext = text.split("\n") 178 lines = len(stext) 179 line = stext[0] 180 181 if self.do_indent: 182 pos = indent 183 write(istr) 184 185 write(line) 186 187 for i in range(1, lines): 188 line = stext[i] 189 write("\n") 190 if line: 191 pos = indent 192 write(istr) 193 write(line) 194 195 if lines > 1 and not line: # Newline at end of text 196 self.do_indent = 1 197 return self.indent 198 199 self.do_indent = 0 200 return pos + len(line) 201 202 def odone(self): 203 self.file.write("\n") 204 self.do_indent = 1 205 206 207class StringStream(Stream): 208 """Writes to a string buffer rather than a file.""" 209 def __init__(self, indent_size = 2): 210 Stream.__init__(self, self, indent_size) 211 self.buffer = [] 212 213 def write(self, text): 214 self.buffer.append(text) 215 216 def __str__(self): 217 return "".join(self.buffer) 218