# $Id: StringBuffer.py,v 1.9 2004/04/13 13:40:34 graham Exp $ # # RDF StringBuffer class for generating formatted output # #--------+---------+---------+---------+---------+---------+---------+---------+ # # Copyright (c) 2002, G. KLYNE # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. The name of the author may not be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # #--------+---------+---------+---------+---------+---------+---------+---------+ # $Source: /file/cvsdev/PythonN3/StringBuffer.py,v $ # $Author: graham $ # $Revision: 1.9 $ $Date: 2004/04/13 13:40:34 $ #--------+---------+---------+---------+---------+---------+---------+---------+ # 1 2 3 4 5 6 7 8 #import os #import re import sys import string #--------+---------+---------+---------+---------+---------+---------+---------+ # StringBuffer - a buffer used for assembling formatted string values # class StringBuffer: """ Represents a string buffer. """ # Node constructor def __init__( self, Val=None ): """ Construct a StringBuffer object. """ self.Left = 0 self.Wrap = 0 self.Pos = 0 self.EndWS = 0 # Final segment whitespace? self.DefVal = None if Val: self.Buffer = [Val] self.Pos = len(Val) else: self.Buffer = [] return def __eq__( self, Comp ): """ Compare for equality with another StringBuffer. """ if Comp: return self.Buffer == Comp.buffer return 0 def __ne__( self, Node ): """ Compare for inequality with another StringBuffer. (Complement of __eq__ above.) """ return not self.__eq__( Node ) def __str__( self ): """ Return content of buffer as string. """ return self.getString() def __repr__( self ): """ Return content of buffer as Python string literal. """ return repr( self.getString() ) def setLeft( self, Pos ): """ Set left margin. """ self.Left = Pos return def setWrap( self, Pos ): """ Set right margin for word-wrapping. """ self.Wrap = Pos return def getString( self ): """ Return content of buffer as string. """ if self.EndWS: return string.join( self.Buffer[:-1], "" ) else: return string.join( self.Buffer, "" ) def tab( self, Pos ): """ Tab to specified position on line. """ if Pos > self.Pos: self.flush() self.Buffer.append( ' '*(Pos-self.Pos) ) self.Pos = Pos self.EndWS = 1 return def tabsp( self, Pos ): """ Tab to specified position on line, inserting at least one space """ if Pos <= self.Pos: Pos = self.Pos + 1 self.tab( Pos ) return def tabnl( self, Pos ): """ Tab to specified position on line, inserting a newline if necessary to arrive at that position. """ if Pos <= self.Pos: self.newline() self.tab( Pos ) return def trim( self ): """ Trim trailing spaces from the last entry in the buffer. """ if len( self.Buffer ) > 0: self.Buffer[-1] = self.Buffer[-1].rstrip() return def indent( self, Dif ): """ Indent left margin from current position. Negative value moves margin to the left. """ self.Left += Dif self.tab( self.Left ) return def newline( self ): """ Append newline to buffer. This method handles indentation/left margin settings. """ self.flush() self.Buffer.append( '\n' ) self.Pos = 0 self.EndWS = 0 if self.Left: self.tab( self.Left ) return def append( self, Val ): """ Append string to buffer. NOTE: this method will detect isolated newline characters, but not newlines embedded in in strings. Using method newline() is the preferred way of including newlines in the output. """ self.flush() if Val == '\n': self.newline() elif self.Wrap: Words = Val.split() for w in Words: if self.Pos+len(w) >= self.Wrap: self.newline() else: if not self.EndWS: self.Buffer.append( " " ) self.Pos += 1 self.Buffer.append( w ) self.Pos += len(w) self.EndWS = 0 else: self.Buffer.append( Val ) self.Pos += len(Val) self.EndWS = 0 return def defer( self, StrVal ): """ Set deferred output, used for generating separator text (e.g. commas between address lines, and a full stop at the end, without knowing which parts are actually present.) This method replaces the current deferred output with the supplied value. See also method flush(). Any outstanding deferred output is appended to the main buffer before any new value is added. """ self.DefVal = StrVal return def flush( self, Terminator=None ): """ Flush out and reset any current deferred output. If 'Terminator' is specified, it is used in place of any deferred output already saved, but is not used if there is no deferred output. E.g. Terminator='.' could be used to specify a final '.' in place of a deferred ', ' separator. """ if self.DefVal: if Terminator: val = Terminator else: val = self.DefVal self.DefVal = None # Use self.append() so defered newlines can be recognized: self.append( val ) return def write( self, str ): """ Write buffer to supplied stream, not including trailing whitespace. """ for s in self.Buffer[:-1]: str.write( s ) if len( self.Buffer ) > 0: if not self.EndWS: str.write( self.Buffer[-1] ) str.flush() return def debug( self, msg ): sys.stdout.write( "StringBuffer: "+msg+"\n" ) return # End of StringBuffer #--------+---------+---------+---------+---------+---------+---------+---------+ # # Stand-alone test code follows: # if __name__ == '__main__': sys.stdout.write( "StringBuffer tests\n" ) a1 = "abcdef ghi\n ghi\n" b1 = StringBuffer( "abc" ) b1.append( "def" ) b1.tab( 8 ) b1.append( "ghi" ) b1.newline() b1.tab( 8 ) b1.append( "ghi" ) b1.newline() if str(b1) == a1: sys.stdout.write( "String b1 OK\n" ) else: sys.stdout.write( "String b1 error:\n" ) sys.stdout.write( " Expected: "+repr(a1)+"\n" ) sys.stdout.write( " Obtained: "+repr(b1)+"\n" ) a2 = "abcdef ghi\n ghi\n" b2 = StringBuffer() b2.append( "abc" ) b2.append( "def" ) b2.tab( 8 ) b2.setLeft( 8 ) b2.append( "ghi" ) b2.newline() b2.append( "gh " ) b2.trim() b2.append( "i" ) b2.newline() if str(b2) == a2: sys.stdout.write( "String b2 OK\n" ) else: sys.stdout.write( "String b2 error:\n" ) sys.stdout.write( " Expected: "+repr(a2)+"\n" ) sys.stdout.write( " Obtained: "+repr(b2)+"\n" ) a3 = "abcdef ghi jkl mno\n pqr stu\n" b3 = StringBuffer() b3.append( "abc" ) b3.append( "def" ) b3.tab( 8 ) b3.setLeft( 4 ) b3.indent( 4 ) b3.setWrap( 19 ) b3.append( "ghi jkl mno pqr stu" ) b3.newline() if str(b3) == a3: sys.stdout.write( "String b3 OK\n" ) else: sys.stdout.write( "String b3 error:\n" ) sys.stdout.write( " Expected: "+repr(a3)+"\n" ) sys.stdout.write( " Obtained: "+repr(b3)+"\n" ) a4 = "abcdef ghi jkl\n mno pqr\n stu\n" b4 = StringBuffer() b4.append( "abc" ) b4.append( "def" ) b4.tab( 8 ) b4.setLeft( 12 ) b4.indent( -4 ) b4.setWrap( 18 ) b4.append( "ghi jkl mno pqr stu" ) b4.newline() if str(b4) == a4: sys.stdout.write( "String b4 OK\n" ) else: sys.stdout.write( "String b4 error:\n" ) sys.stdout.write( " Expected: "+repr(a4)+"\n" ) sys.stdout.write( " Obtained: "+repr(b4)+"\n" ) a5 = "abcdef ghi jkl\n mno pqr stu\n" b5 = StringBuffer() b5.append( "abc" ) b5.append( "def" ) b5.tabnl( 8 ) b5.append( "ghi jkl" ) b5.tabnl( 8 ) b5.append( "mno pqr" ) b5.tabsp( 8 ) b5.append( "stu" ) b5.newline() if str(b5) == a5: sys.stdout.write( "String b5 OK\n" ) else: sys.stdout.write( "String b5 error:\n" ) sys.stdout.write( " Expected: "+repr(a5)+"\n" ) sys.stdout.write( " Obtained: "+repr(b5)+"\n" ) a6 = "List 1: a(a), c(c), d.\nList 2: \n" b6 = StringBuffer() b6.append( "List 1: " ) b6.defer( None ) b6.append( "a" ) b6.defer( "(a), " ) if 0: b6.append( "b" ) b6.defer( "(b), " ) b6.append( "c" ) b6.defer( "(c), " ) b6.append( "d" ) b6.defer( "(d), " ) b6.flush( "." ) b6.newline() b6.append( "List 2: " ) b6.defer( None ) b6.flush( "." ) b6.newline() if str(b6) == a6: sys.stdout.write( "String b6 OK\n" ) else: sys.stdout.write( "String b6 error:\n" ) sys.stdout.write( " Expected: "+repr(a6)+"\n" ) sys.stdout.write( " Obtained: "+repr(b6)+"\n" ) sys.stdout.write( "Check writing:\n" ) sys.stdout.write( ">>>\n" ) b4.write( sys.stdout ) sys.stdout.write( "<<<\n" ) sys.stdout.write( "Exiting\n" ) #--------+---------+---------+---------+---------+---------+---------+---------+ # # $Log: StringBuffer.py,v $ # Revision 1.9 2004/04/13 13:40:34 graham # Fix index range error when writing empty StyringBuffer. # # Revision 1.8 2004/02/17 23:37:57 graham # Sync # # Revision 1.7 2002/06/05 15:26:33 graham # Option to trim spaces from formatted values # # Revision 1.6 2002/05/21 20:50:36 graham # Fix error in XML output when comments missing # Allow multiple authors for header field # # Revision 1.5 2002/05/10 11:08:19 graham # Added deferred output features to handle list separators # # Revision 1.4 2002/05/08 16:46:35 graham # Add StringBuffer tabsp() and tabnl() methods. # # Revision 1.3 2002/05/03 14:49:55 graham # Added conditional and alternative features to query pattern and formatter templates # # Revision 1.2 2002/05/01 15:43:48 graham # Cleanup small details # # Revision 1.1 2002/05/01 14:24:21 graham # Add StringBuffer formatting helper module # #