Path: utzoo!utgpu!jarvis.csri.toronto.edu!clyde.concordia.ca!uunet!odi!benson From: benson@odi.com (Benson I. Margulies) Newsgroups: comp.lang.c++ Subject: Re: Newline hook needed in streams Message-ID: <1989Dec22.124143.19874@odi.com> Date: 22 Dec 89 12:41:43 GMT References: <1989Dec18.132745.5187@odi.com> <9804@ardent.UUCP> Reply-To: benson@odi.com (Benson I. Margulies) Organization: Object Design Inc., Burlington, MA Lines: 84 In article <9804@ardent.UUCP> jss@jra.ardent.com () writes: >In article <1989Dec18.132745.5187@odi.com> benson@odi.com (Benson I. Margulies) writes: >>I've needed to implement two special kinds of ostreams that seem to >>need "line buffering" support. That is, I need to have code of mine >>get control (via virtual function or function pointer) whenever >>a newline is inserted into the buffer. >> >>The two examples are an indenting stream (add a settable amount >>of indentation to the left margin) and a syslog stream. >>The indenting stream needs to know newline boundaries to know >>when to insert the indentation. The syslog stream wants to >>actually call syslog(3) for each line of output. >> > >This request came up a lot while I was designing iostreams, but >I was never able to solve the fundamental problem that doing >line bufferring required some action on every character >to check if it is a newline and (since there are already complaints >about the amount of code inlined by put) would amount to making >the stream unbuffered. > >That does not mean there is no way to solve the problems, but >it means you have to do some extra work. I will describe one >approach that I have found useful. > >First, the easiest place to do this kind of thing is in the >streambuf, rather than the ostream class. What I have typically >done is derive a new class from filebuf with a redefined "flush" >member. This member does whatever extra processing it required >and then call filebuf::flush to really output the data. This approach >will probably be sufficient for the syslog. > That's exactly what I did, except that I didn't use filebuf. I used streambuf directly. Unfortunately, it isn't good enough for syslog. It is not acceptible to wait for a flush to get the log messages out. They have to get out as generated. >For an indenting ostream this is not adequate since some means >is probably required to tell the streambuf the current indent >The amount ought to be kept as formatting information associated >with the ostream (use xalloc and iword) and passed on to the >streambuf as appropriate (presumably using a member function). >Also it is a bit restrictive to assume that the indenting >can only be done on a file, so rather than deriveng a new >class derived from filebuf, it might be better to have a >more general approach that would allow indenting to be >inserted between the ostream and an abritrary streambuf. > >I'd be interested to hear from anybody who has written this >kind of streambuf class about what approaches they have taken. > >Some easily overlooked parts of the iostream library that >are relevant to these problems. > > There is a "unitbuf" flag in the ios interface. > When this is set it causes flush() to be called > frequently (although not on every character). > Unfortunately, ostream_withassign::operator= busts this. It runs the non-virtual function "init" on the streambuf, which clears unitbuf. > There is an ostream constructor that takes an explicit > streambuf as an argument. It is therefore not necessary > to declare a new ostream class in order to use a streambuf > that does something special. > > streambuf::flush is not required to consume data. If > it is called while there is still room for more characters in > the arrays it can return without doing anything. > In general, a half-dozen "virtual" markings in streambufs and streams would make this sort of thing trivial. Since the stream library is supposed to be the basis of whatever wild flights of imagination the rest of us can come up with, IMHO allmost everything should be virtual. -- Benson I. Margulies