1 /* gensi.hpp -- generic char buffer and I/O facilities
2  * by pts@fazekas.hu at Sun Feb 24 15:56:02 CET 2002
3  */
4 /* Imp: get rid of gensio.o (Buffer::Writable::printf requires B...) */
5 
6 #ifdef __GNUC__
7 #ifndef __clang__
8 #pragma interface
9 #endif
10 #endif
11 
12 #ifndef GENSI_HPP
13 #define GENSI_HPP 1
14 
15 #include "config2.h"
16 #include <stdarg.h> /* va_list */
17 
18 #if 'a'!=97 || '!'!=33
19 #error You need an ASCII system to compile this.
20 #endif
21 
22 /** A very generic, abstract char (pure 8-bit octet) buffer class. This class
23  * doesn't have any attributes.
24  */
25 class GenBuffer {
26  public:
~GenBuffer()27   virtual inline ~GenBuffer() {}
hexc2n(char c)28   static inline unsigned hexc2n(char c) {
29     return ((unsigned char)(c-'0')<=(unsigned char)('9'-'0')) ? c-'0'
30          : ((unsigned char)(c-'A')<=(unsigned char)('F'-'A')) ? c-'A'+10
31          : ((unsigned char)(c-'a')<=(unsigned char)('f'-'a')) ? c-'a'+10
32          : 16;
33   }
34   /** English ASCII letters [a-zA-Z] */
35   static void tolower_memcpy(char *dst, char const*s, slen_t slen);
36   /** English ASCII letters [a-zA-Z] */
37   static void toupper_memcpy(char *dst, char const*s, slen_t slen);
38   /** All letters treated as lower case. @return -1, 0 or 1 */
39   static int nocase_memcmp(char const*a, char const *s, slen_t slen);
40   static int nocase_strcmp(char const*a, char const *b);
41   /** All letters treated as lower case. @return -1, 0 or 1 */
42   static bool nocase_strbegins(char const*a, char const *with);
43   static bool strbegins(char const*a, char const *with);
44   static bool parseBool(char const *s, slen_t slen);
45 
46   /* Imp: convert usage of each_sub to first_sub+next_sub */
47   typedef void (*block_sub_t)(char const*beg, slen_t len, void *data);
48   typedef void (*block_char_t)(char c, void *data);
49   struct Sub {
50     char const*beg;
51     slen_t len;
52     void *data, *data2;
53   };
54   /** Writable. */
55   struct SubW {
56     char *beg;
57     slen_t len;
58     void *data, *data2;
59   };
60   virtual slen_t getLength() const =0;
61   /** Iterates through each subrange of (this), and calls param `block'
62    * for each range. Must call block with positive `len's, and -- as a final
63    * call -- with len==0.
64    * @param data arbitrary data, to be passed to param `block'
65    */
66   virtual void each_sub(block_sub_t block, void *data) const =0;
67   /** Iterates through each character of (this), and calls param `block'
68    * for each char. Implemented by calling (this).each_sub
69    */
70   /** Produces sub.len==0 if empty. */
71   virtual void first_sub(Sub &sub) const =0;
72   /** Produces sub.len==0 if no more subs.
73    * @param sub fields `beg' and `len' are assumed to contain garbage (!)
74    *            before invocation. Only `data' and `data2' can be relied upon.
75    */
76   virtual void next_sub(Sub &sub) const =0;
each_char(block_char_t block,void * data) const77   inline void each_char(block_char_t block, void *data) const {
78     void *t[2]= { data, (void*)(long)block };
79     each_sub(iter_char_sub, (void*)t);
80   }
isEmpty() const81   inline bool isEmpty() const { return getLength()==0; }
82   /** @return true iff not empty */
operator void*() const83   inline virtual operator void*() const { return (void*)(getLength()!=0); }
84   /** @return true iff not empty; pacify VC6.0 */
85   // inline virtual operator bool() const { return (void*)(getLength()!=0); }
86   // inline virtual operator bool() const { return getLength()!=0; }
87   /** @return true iff empty */
operator !() const88   inline virtual bool operator!() const { return getLength()==0; }
89   /** @return getLength() */
90   virtual slen_t copyRange(char *to, slen_t cfrom, slen_t clen) const;
91   /** @return true on conversion error */
92   bool toBool(bool &dst);
93   /** @return true on conversion error (overflow etc.) */
94   bool toInteger(unsigned long &dst);
95   /** @return true on conversion error (overflow etc.) */
96   bool toInteger(signed long &dst);
97   #if HAVE_LONG_LONG && NEED_LONG_LONG
98     /** @return true on conversion error (overflow etc.) */
99     bool toInteger(unsigned PTS_CFG_LONGEST &dst);
100     /** @return true on conversion error (overflow etc.) */
101     bool toInteger(signed PTS_CFG_LONGEST &dst);
102   #endif
103   /* Zero-initialize to pacify gcc-4.2.1 by giving initial value */
toInteger(unsigned short & i)104   inline bool toInteger(unsigned short &i) { unsigned long l = 0; bool b=toInteger(l); i=l; return b; }
toInteger(signed short & i)105   inline bool toInteger(  signed short &i) {   signed long l = 0; bool b=toInteger(l); i=l; return b; }
toInteger(unsigned int & i)106   inline bool toInteger(unsigned int   &i) { unsigned long l = 0; bool b=toInteger(l); i=l; return b; }
toInteger(signed int & i)107   inline bool toInteger(  signed int   &i) {   signed long l = 0; bool b=toInteger(l); i=l; return b; }
108   /** Allocates a fresh new, null-terminated string. @return true */
109   bool toCString(char *&dst);
110   /** @return negative iff (this)<s2, positive iff (this)>s2 */
111   virtual int cmp(GenBuffer const& s2) const;
112   /** @return negative iff (this)<s2, positive iff (this)>s2 */
113   virtual int cmp(char const* s2, slen_t len) const;
114   /** Null-terminated, calls cmp(char const* s2, slen_t len). */
115   int cmp(char const* s2) const;
116   friend bool operator==(const GenBuffer& s1, const GenBuffer& s2);
117   friend bool operator==(const char *s1, const GenBuffer& s2);
118   friend bool operator==(const GenBuffer& s1, const char *s2);
119   /* vvv G++ 2.91 doesn't autodetect these 15 operators :-( */
120   friend bool operator!=(const GenBuffer& s1, const GenBuffer& s2);
121   friend bool operator!=(const char *s1, const GenBuffer& s2);
122   friend bool operator!=(const GenBuffer& s1, const char *s2);
123   friend bool operator<=(const GenBuffer& s1, const GenBuffer& s2);
124   friend bool operator<=(const char *s1, const GenBuffer& s2);
125   friend bool operator<=(const GenBuffer& s1, const char *s2);
126   friend bool operator<(const GenBuffer& s1, const GenBuffer& s2);
127   friend bool operator<(const char *s1, const GenBuffer& s2);
128   friend bool operator<(const GenBuffer& s1, const char *s2);
129   friend bool operator>=(const GenBuffer& s1, const GenBuffer& s2);
130   friend bool operator>=(const char *s1, const GenBuffer& s2);
131   friend bool operator>=(const GenBuffer& s1, const char *s2);
132   friend bool operator>(const GenBuffer& s1, const GenBuffer& s2);
133   friend bool operator>(const char *s1, const GenBuffer& s2);
134   friend bool operator>(const GenBuffer& s1, const char *s2);
135 
136   /** A very generic, abstract char (pure 8-bit octet) output (encoding
137    * stream, filter) class. Writing always succeeds, all data gets written.
138    * No attributes.
139    */
140   class Writable {
141    public:
142     virtual void vi_write(char const*, slen_t) =0;
143     virtual void vi_putcc(char) =0;
operator <<(GenBuffer const & b)144     inline Writable &operator <<(GenBuffer const& b) {
145       b.each_sub(iter_write_sub, this);
146       return*this;
147     }
operator <<(char c)148     inline Writable &operator <<(char c) { vi_putcc(c); return*this; }
149     /** Outputs a null-terminated, C string. Not `inline' because the use
150      * of strlen().
151      */
~Writable()152     virtual inline ~Writable() {}
153     Writable& operator <<(char const*);
154     Writable& operator <<(void const*);
operator <<(signed short n)155     inline Writable& operator <<(  signed short n) { write_num((signed long)n); return*this; }
operator <<(signed int n)156     inline Writable& operator <<(  signed int   n) { write_num((signed long)n); return*this; }
operator <<(signed long n)157     inline Writable& operator <<(  signed long  n) { write_num(n); return*this; }
operator <<(unsigned short n)158     inline Writable& operator <<(unsigned short n) { write_num((unsigned long)n); return*this; }
operator <<(unsigned int n)159     inline Writable& operator <<(unsigned int   n) { write_num((unsigned long)n); return*this; }
operator <<(unsigned long n)160     inline Writable& operator <<(unsigned long  n) { write_num(n); return*this; }
161     #if HAVE_LONG_LONG && NEED_LONG_LONG
operator <<(signed long long n)162       inline Writable &operator <<(signed long long n) { write_num(n); return*this; }
operator <<(unsigned long long n)163       inline Writable &operator <<(unsigned long long n) { write_num(n); return*this; }
164     #endif
operator <<(bool b)165     inline Writable& operator <<(bool b) {
166       if (b) vi_write("true", 4);
167         else vi_write("false", 5);
168       return*this;
169     }
170 
171     /** appends at most `n' chars; uses SimBuffer::B::vformat as temp */
172     virtual Writable& vformat(slen_t n, char const *fmt, va_list ap);
173     /** appends; uses SimBuffer::B::vformat as temp */
174     virtual Writable& vformat(char const *fmt, va_list ap);
175     /** appends; calls vformat */
176     Writable& format(slen_t n, char const *fmt, ...);
177     /** appends; calls vformat */
178     Writable& format(char const *fmt, ...);
179 
180     void write_num(signed long n);
181     void write_num(unsigned long n);
182     #if HAVE_LONG_LONG && NEED_LONG_LONG
183       void write_num(signed PTS_CFG_LONGEST n);
184       void write_num(unsigned PTS_CFG_LONGEST n);
185     #endif
186     /** @param zdigits specifies the exact number of digits to be appended.
187      * Zeroes are prepended if necessary.
188      */
189     void write_num(unsigned long n, unsigned zdigits);
190     #if HAVE_LONG_LONG && NEED_LONG_LONG
191       void write_num(unsigned PTS_CFG_LONGEST n, unsigned zdigits);
192     #endif
193    protected:
194     static void iter_write_sub(char const*beg, slen_t len, void *data);
195   };
196 
197   /** Interface for a stream of characters. Similar to ISimplyiChar in
198    * CHsplit. No attributes.
199    */
200   class Readable {
201   public:
202     /** @return -1 on EOF/error, a char (0..255) otherwise.
203      */
204     virtual int vi_getcc() =0;
205     /** Does a single blocking read. Default functionality: calls vi_getcc()
206      * repeatedly.
207      * @return 0 on EOF/error, positive otherwise: number of characters
208      * successfully read.
209      */
210     virtual slen_t vi_read(char *to_buf, slen_t max);
211     /** Does multiple blocking reads, tries to fill `to_buf'. Calls vi_read()
212      * repeatedly.
213      */
214     int readFill(char *to_buf, slen_t max);
215     /** Returns a number not larger than the bytes available _altogether_
216      * from this stream. The default implementation returns 0, which is
217      * always safe. For regular files, the method should return the size
218      * of the file (unless the size is too large to be represented as an
219      * slen_t), for pipes and sockets, the method should return 0.
220      */
vi_availh()221     inline virtual slen_t vi_availh() { return 0; }
222     inline bool equal_content(Readable &other);
223     /** Does nothing or rewinds the stream to the beginning, so it can be
224      * read again. The default implementation does nothing.
225      */
vi_rewind()226     inline virtual void vi_rewind() {}
~Readable()227     virtual inline ~Readable() {}
228   };
229 
230  protected:
231   static void iter_char_sub(char const*beg, slen_t len, void *data);
232 };
233 
234 // vvv Doesn't work in gcc 2.95 since we have abstract methods :-(. Must be
235 //     declared inside class { ... };
236 ///GenBuffer::Writable &operator <<(GenBuffer::Writable a, GenBuffer b);
237 
238 /** Collection of some simplistic GenBuffer implementations. */
239 class SimBuffer {
240  public:
241   class B;
242   /** A flat buffer, i.e occupying consecutive bytes in memory. This class is
243    * useless by itself since memory management (allocation and deletion of the
244    * memory area) isn't implemented. Example of virtual inheritance: needed
245    * because of SimBuffer::B.
246    */
247   class Flat: virtual public GenBuffer {
248    protected:
249     friend class /*SimBuffer::*/B; /* can read `beg' and `len' */
250     const char *beg;
251     slen_t len;
252    public:
getLength() const253     inline virtual slen_t getLength() const { return len; }
each_sub(block_sub_t block,void * data) const254     virtual void each_sub(block_sub_t block, void *data) const {
255       if (len!=0) block(beg,len,data);
256       block(0,0,data);
257     }
first_sub(Sub & sub) const258     inline virtual void first_sub(Sub &sub) const { sub.beg=beg; sub.len=len; };
next_sub(Sub & sub) const259     inline virtual void next_sub(Sub &sub) const { sub.len=0; }
getCString() const260     inline char const*getCString() const { return beg; }
operator ()() const261     inline char const*operator()() const { return beg; }
begin_() const262     inline char const*begin_() const { return beg; }
end_() const263     inline char const*end_() const { return beg+len; }
264     // inline operator char const*() const { return beg; } /* would kill void* */
265     /** @param idx would cause overload conflict if declared len_t. No range check */
operator [](slendiff_t idx) const266     inline char const&operator[](slendiff_t idx) const { return beg[idx]; }
267     /** @return true iff not empty */
operator void*() const268     inline virtual operator void*() const { return (void*)(len!=0); }
269     // inline operator bool() const { return len!=0; }
270     /** @return true iff empty */
operator !() const271     inline virtual bool operator!() const { return len==0; }
272     /**
273      * This is deliberatly not an `operator char'
274      * to avoid the ambiguity of implicit auto-conversion.
275      * @return 1st char or 0.
276      */
toChar(char & ret) const277     inline void toChar(char &ret) const {
278       ret= len==0 ? 0 : *beg;
279     }
280     /** Overridden. */
281     virtual slen_t copyRange(char *to, slen_t cfrom, slen_t clen) const;
282     /** @return getLength() if not found, offset otherwise */
283     slen_t findLast(char const c) const;
284     /** @return getLength() if not found, offset otherwise */
285     slen_t findFirst(char const c) const;
286     /** @return getLength() if not found, offset otherwise */
287     slen_t findFirst(char const* s, slen_t slen) const;
288     int cmpFlat(Flat const& s2) const;
289     virtual int cmp(char const* s2, slen_t len) const;
290     /** @param fallback default: '\0'
291      * @return if idx is too large: `fallback', otherwise: the asked char
292      */
getAt0(slen_t idx,char fallback='\\0')293     virtual inline char getAt0(slen_t idx, char fallback='\0') {
294       return idx>=len ? fallback : beg[idx];
295     }
296     /* Dat: pacify VC6.0: use of undefined type 'SimBuffer' */
297     friend /*SimBuffer::*/B operator+(const /*SimBuffer::*/Flat& s1, const /*SimBuffer::*/Flat& s2);
298     friend /*SimBuffer::*/B operator+(const char *s1, const /*SimBuffer::*/Flat& s2);
299     friend /*SimBuffer::*/B operator+(const /*SimBuffer::*/Flat& s1, const char *s2);
300   };
301 
302   /** A statically allocated, read-only char buffer, probably inside the TEXT
303    * section (program code). Needs no delete()ing. `Does' memory management by
304    * not doing anything: statically allocated memory belongs to whole lifetime
305    * of the process, so it doesn't have to be freed.
306    */
307   class Static: public Flat {
308    public:
309     Static(char const*);
Static(char const * beg_,slen_t len_)310     Static(char const*beg_,slen_t len_) { beg=beg_; len=len_; }
311   };
312 
313   /** A flat buffer of fixed length. Not particularly useful, try
314    * SimBuffer::B instead.
315    */
316   class Fixed: public Flat {
317    public:
Fixed(slen_t len_)318     inline Fixed(slen_t len_) { beg=new char[len_]; len=len_; }
~Fixed()319     virtual inline ~Fixed() {
320       delete [] const_cast<char*>(beg); /* Dat: const_cast: pacify VC6.0 */
321     }
322    private:
323     /** Disable this. */
operator =(Fixed const &)324     inline Fixed& operator=(Fixed const&) {return*this;}
325   };
326 
327 #if 0
328   /** Fixed-length, writable */
329   class FixWrite: public GenBuffer {
330    public:
331   };
332 #endif
333 
334   /** Abstract class. Example of virtual inheritance, needed because of
335    * SimBuffer::B.
336    */
337   class Appendable: virtual public GenBuffer, public GenBuffer::Writable {
338    public:
339     /** Makes room for `len' more chars at the end of the string, and returns
340      * a pointer to the beginning of that location. Should be efficient.
341      */
342     virtual char *vi_mkend(slen_t) =0;
343     /** Makes room for `len' more chars at the end of the string, and returns
344      * a pointer to the beginning of that location. May be inefficient.
345      */
346     virtual char *vi_mkbeg(slen_t) =0;
347     /** Use this instead of append(...). */
348     virtual void vi_write(char const*, slen_t);
vi_putcc(char c)349     inline virtual void vi_putcc(char c) { vi_mkend(1)[0]=c; }
350     /** There is no append(...) method. Use vi_write() instead. */
351     void prepend(char const*, slen_t);
352   };
353 
354   /** A one-way linked list of flat strings. Quickest for long memory appends.
355    * Does memory management.
356    */
357   class Linked: public Appendable {
358    public:
359     struct Node {
360       char *beg;
361       slen_t len;
362       /** May be NULL. */
363       Node *next;
364     };
365     Node *first, *last;
Linked()366     inline Linked(): first(0), last(0) {}
367     virtual ~Linked();
368     Linked(GenBuffer const& other);
369     Linked(char const*);
370     Linked& operator=(GenBuffer const& other);
371     Linked& operator=(Linked const& other);
372     virtual slen_t getLength() const;
373     virtual void each_sub(block_sub_t block, void *data) const;
374     virtual void first_sub(Sub &sub) const;
375     virtual void next_sub(Sub &sub) const;
376     virtual char *vi_mkend(slen_t len);
377     virtual char *vi_mkbeg(slen_t len);
378   };
379 
380   /* Abstract class. */
381   class Resizable: public Appendable { public:
382     /** Grows the string by the specified `left' and `right' amount on the
383      * sides. The amounts may be positive, zero or negative. For a negative
384      * amount, the `?beg' will be rendered invalid. For a nonnegative amount,
385      * `?beg' will point to the beginning of the new, uninitialized part of the
386      * buffer.
387      */
388     virtual void vi_grow2(slendiff_t left, slendiff_t right, char **lbeg, char **rbeg) =0;
389     Resizable& operator=(GenBuffer const& other);
clearFree()390     inline void clearFree() { vi_grow2(0, -(slendiff_t)getLength(), 0, 0); }
forgetAll()391     inline void forgetAll() { vi_grow2(0, -(slendiff_t)getLength(), 0, 0); }
392     /** If howmuch>getLength(), then clears the string. */
forgetLast(slen_t howmuch)393     inline void forgetLast(slen_t howmuch) { vi_grow2(0, -(slendiff_t)howmuch, 0, 0); }
forgetFirst(slen_t howmuch)394     inline void forgetFirst(slen_t howmuch) { vi_grow2(-(slendiff_t)howmuch, 0, 0, 0); }
395     void keepLeft(slen_t howmuch);
396     void keepRight(slen_t howmuch);
397     void keepSubstr(slen_t from_offset, slen_t slen);
vi_mkend(slen_t howmuch)398     inline virtual char *vi_mkend(slen_t howmuch) { char *s; vi_grow2(0, howmuch, 0, &s); return s; }
vi_mkbeg(slen_t howmuch)399     inline virtual char *vi_mkbeg(slen_t howmuch) { char *s; vi_grow2(howmuch, 0, &s, 0); return s; }
400   };
401 
402   /** A simple, non-shared, writable, flat memory buffer of bytes. Supports
403    * fast appends (with rare memory-rallocations) by pre-allocating at most
404    * twice as much memory. Prepends are
405    * slow, because they always include memory allocation and copying.
406    * Does memory management.
407    * Imp: check when `len' overflows (i.e 2*alloced etc.)
408    */
409   class B: public Resizable, public Flat {
410    /* BUGFIX at Tue Sep  3 18:04:34 CEST 2002:
411     * original order was: public Flat, public Resizable, but I got the
412     * error message from gcc-3.2: gensi.hpp:398: sorry, not implemented: adjusting pointers for covariant returns
413     */
414    protected:
415     /** Number of bytes preallocated. */
416     slen_t alloced;
417     char small[8];
418    public:
419     /** Overridden. */
420     virtual void vi_grow2(slendiff_t left, slendiff_t right, char **lbeg, char **rbeg);
421 
422     /** Destructor: must be virtual since we have virtual methods. */
~B()423     virtual ~B() {
424       if (beg!=small) delete [] const_cast<char*>(beg);
425       /* ^^^ Dat: const_cast: pacify VC6.0 */
426     }
427     /** Constructor: the empty buffer. */
B()428     inline B(): alloced(sizeof(small)) { beg=small; len=0; }
429     /** Constructor: copy data from a null-terminated C string. */
430     B(char const*);
431     /** Constructor: copy data from a memory buffer. */
432     B(char const*,slen_t);
433     /** Constructor: copy-constructor */
434     B(B const&);
435     /** Constructor: copy data from a Flat buffer. */
436     B(Flat const&);
437     /** Constructor: copy data from a Flat buffer, term0(). */
438     B(Flat const&,int);
439     /** Constructor: copy data from a GenBuffer. */
440     B(GenBuffer const&);
441     /** Constructor: copy (consume) data from a readable stream. */
442     B(GenBuffer::Readable &);
443     /** Constructor: concatenate two (2) memory buffers. */
444     B(char const*,slen_t, char const*,slen_t);
445     /** Constructor: concatenate two (2) memory buffers, term0(). */
446     B(char const*,slen_t, char const*,slen_t,int);
447     /** Constructor: concatenate two GenBuffers. */
448     B(GenBuffer const&, GenBuffer const&);
449     /** Constructor: concatenate three (3) memory buffers. */
450     B(char const*,slen_t, char const*,slen_t, char const*,slen_t);
451     /** Constructor: concatenate three (3) GenBuffers. */
452     B(GenBuffer const&, GenBuffer const&, GenBuffer const&);
453     /** Constructor: concatenate a flat buffer and a C string */
454     B(Flat const&, char const*);
455     /** Constructor: concatenate three ... */
456     B(char const*, Flat const&, char const*);
457     /** Constructor: a substring of a Flat buffer */
458     B(Flat const&, slen_t from_offset, slen_t slen);
459 
460     /** Works even when other==&(this). @return (this) */
461     B& operator=(/*SimBuffer::*/Flat const& other);
462     /** C++ SUXX: type conversion (Flat& -> B&) doesn't work as expected.
463      * Works even when other==&(this). @return (this)
464      */
465     B& operator=(/*SimBuffer::*/B const& other);
466     /** @return (this) */
467     B& operator=(char const*);
468     /** Reads (consumes) the whole `stream', and appends the bytes to (this).
469      * @return (this) declaring `operator<<' inside would ruin inherited `operator<<'s
470      */
471     /* GenBuffer::Writable& operator<<(GenBuffer::Readable &stream); */
472 
473     /** Pacify VC6.0 multiple inheritance*/
operator void*() const474     inline virtual operator void*() const { return (void*)(len!=0); }
475     /** Pacify VC6.0 multiple inheritance */
operator !() const476     inline virtual bool operator!() const { return len==0; }
477 
478     friend /*SimBuffer::*/B& operator<<(/*SimBuffer::*/B& self, GenBuffer::Readable &stream);
479     /** Specific operators for faster implementation */
480     B& operator<<(char c);
481     B& operator<<(char const* s);
482     /** Works even when other==&(this). @return (this) */
483     B& operator<<(Flat const&);
484     /* C++ inheritance SUXXXX: now I have to re-define _every_ operator<< in GenBuffer::Writable... */
485     B& operator <<(void const*);
operator <<(signed short n)486     inline B& operator <<(  signed short n) { write_num((signed long)n); return*this; }
operator <<(signed int n)487     inline B& operator <<(  signed int   n) { write_num((signed long)n); return*this; }
operator <<(signed long n)488     inline B& operator <<(  signed long  n) { write_num(n); return*this; }
operator <<(unsigned short n)489     inline B& operator <<(unsigned short n) { write_num((unsigned long)n); return*this; }
operator <<(unsigned int n)490     inline B& operator <<(unsigned int   n) { write_num((unsigned long)n); return*this; }
operator <<(unsigned long n)491     inline B& operator <<(unsigned long  n) { write_num(n); return*this; }
492     #if HAVE_LONG_LONG && NEED_LONG_LONG
operator <<(signed long long n)493       inline B &operator <<(signed long long n) { write_num(n); return*this; }
operator <<(unsigned long long n)494       inline B &operator <<(unsigned long long n) { write_num(n); return*this; }
495     #endif
operator <<(bool b)496     inline B& operator <<(bool b) { GenBuffer::Writable::operator<<(b); return*this; }
497 
498 #if 0
499     friend SimBuffer::B& operator<<(SimBuffer::B& self, char const*s);
500     friend SimBuffer::B& operator<<(SimBuffer::B& self, char c);
501 #endif
502 
begin_() const503     inline char *begin_() const { return const_cast<char*>(beg); }
end_() const504     inline char *end_  () const { return const_cast<char*>(beg)+len; }
isFull() const505     inline bool isFull() const { return len==alloced; }
506     /** Ensures beg[len]=='\0'. @return (this) */
507     B& term0();
508     /** @param idx would cause overload conflict if declared len_t. No range check */
operator [](slendiff_t idx) const509     inline char &operator[](slendiff_t idx) const { return const_cast<char*>(beg)[idx]; }
510     /** @param lendiff if negative, then makes the buffer shorter */
511     void grow_set0_by(slendiff_t lendiff);
512     /** Grows the buffer if necessary, fills with '\0' */
513     char getAt(slen_t idx);
514     /** Doesn't free unnecessary memory. */
clear()515     inline void clear() { len=0; }
516     /** Removes oldmuch chars from index first, and makes place for newmuch
517      * chars there. Returns the beginning of the new place. Calls memmove().
518      * Tue Jun 11 15:33:33 CEST 2002
519      */
520     char *substr_grow(slen_t first, slen_t oldmuch, slen_t newmuch);
521     B substr(slen_t first, slen_t howmuch) const;
522     B substr(slen_t first) const;
523     B right(slen_t howmuch) const;
524     B left(slen_t howmuch) const;
525     static void space_pad_cpy(char *dst, char const*src, slen_t pad);
526 
527     /* vi_write() doesn't work if s is inside (this).
528      * There is no append(...) method. Use vi_write() instead.
529      */
530     // void append(char const*s, const slen_t len_);
531     virtual void vi_write(char const*, slen_t);
532 
533     /* Original: B& vformat(slen_t n, char const *fmt, va_list ap);
534      * Pacify VC6.0: error C2555: 'SimBuffer::B::vformat' : overriding virtual function differs from 'GenBuffer::Writable::vformat' only by return type or calling convention
535      */
536     /** appends at most `n' chars, no trailing '\0'. This is different from
537      * ANSI (old and C99) stdio.h, because those insert at most `n-1' chars
538      * (not counting the '\0'), _and_ a trailing '\0'. Truncates the output
539      * to `n' chars if it would be longer. (Truncation semantics changed at
540      * Tue Jun 11 14:27:12 CEST 2002. Old: truncate to no chars if longer)
541      */
542     GenBuffer::Writable& vformat(slen_t n, char const *fmt, va_list ap);
543     /** appends as many chars as requrested */
544     GenBuffer::Writable& vformat(char const *fmt, va_list ap);
545     /** appends; calls vformat(n); mandatorly non-inline because of ... */
546     GenBuffer::Writable& format(slen_t n, char const *fmt, ...);
547     /** appends; calls vformat(); mandatorly non-inline because of ... */
548     GenBuffer::Writable& format(char const *fmt, ...);
549 
550     /*
551      * Name: NonPathMeta
552      * Input: any binary
553      * Output: non-path characters pre-backslashed
554      * Description: Places backslashes in front of non-path characters:
555      *   [^-_./a-zA-Z0-9].
556      * Compatibility: UNIX shells: sh (Bourne Shell), bash, ksh, zsh. Use this in
557      *   a shell script to protect a string from word splitting, variable
558      *   substitution and everything else. Note that there will be problems
559      *   only with \0 (depends on the shell) and \n (will be simply removed by
560      *   the shell!). See also Quote::QShell for full shell compatility.
561      * Valid input type: binary
562      * Valid input: any binary
563      * On invalid input: impossible
564      * Inverse of valid: lossy: Quote::UnMeta
565      * Validity indicator: implemented
566      * Output type: some binary
567      * Direction: encode
568      * Method: each_byte
569      * Dependencies: -
570      */
571     B& appendNpmq(const Flat &other, bool dq=false);
572     /** Quotes a filename (actually a pathname since it may include
573      * (sub)directories) specified in param `other' to be passed to the
574      * most common shell of the host operating system (/bin/sh, COMMAND.COM,
575      * CMD.EXE etc.) as a separate command line argument for a command
576      * invoked from the shell.
577      *
578      * Under UNIX, this differs from appendNpmq only when treating [\n\0].
579      * Under Win32, the filename is surrounded by double quotes. Double quotes
580      * inside the filename are skipped. Other systems than Win32 are treated
581      * like UNIX.
582      * @param preminus prefix filenames starting with `-' with `./' ?
583      */
584     B& appendFnq(const Flat &other, bool preminus=false);
585     /**
586      * Name: Quote::NonPathOctal; from quote.rb
587      * Input: any binary
588      * Output: non-path characters converted to octal
589      * Description: Converts non-path characters ([^-_./a-zA-Z0-9]) in
590      *   a string to their prebackslashed, 3-digit octal representation (i.e
591      *   \123).
592      * Compatibility: Ruby, ANSI C, K&R C, C++, Java (without \u....),
593      *   TCL double quotes (without \u....), TCL unquoted strings (without
594      *   \u....), Perl5, Pike, AWK, PostScript Level 1, bc. See also
595      *   Quote::*Octal.
596      * Valid input type: binary
597      * Valid input: any binary
598      * On invalid input: impossible
599      * Inverse of valid: lossy: Quote::UnSlash
600      * Validity indicator: implemented
601      * Output type: \A[-\\._/a-zA-Z0-9]*\z
602      * Direction: encode
603      * Method: each_byte
604      * Dependencies: -
605      */
606     B& appendDump(const Flat &other, bool dq=false);
607     B& appendDump(const char c, bool dq=false);
608     /**
609      * Name: Quote::Unslash
610      * Input: a double-quoted (backslashed) version of a string without
611      *   the double quotes themselves
612      * Output: the original, unquoted (possibly binary) string
613      * Description: Converts a string expressed inside double quotes of some
614      *   programming language (e.g Ruby, C, Java, Perl, Ruby) to its original,
615      *   unquoted state. Transformation is done only after backslashes. The
616      *   following `common' transformations are supported: \0, \00, \000
617      *   (octal), \a (alarm bell), \b (backslash), \e (escape), \f (form feed),
618      *   \n (newline), \r (carriage return), \t (horizontal tab), \v (verical
619      *   tab) \x61, \c[, \l (lowercase), \u (upper case), \NL (skip this),
620      *   \", \\, \... .
621      * Compatibility: Ruby, ANSI C, C++, Java (without \u....), TCL double
622      *   quotes (without \u....), TCL unquoted strings, Perl5, Pike, AWK,
623      *   PostScript Level 1, bc, PHP.
624      *   See also Quote::UnSlashPHPC for full PHP:StripCSlashes() compatibility.
625      *   See also Quote::UnSlashKnr. Compatible with PHP stripcslashes().
626      *   See also Quote::UnSlashKnr. Differs from Quote::UnslashMiddle by not
627      *   removing the double quotes from string edges.
628      * Valid input type: binary
629      * Valid input: any binary
630      * On invalid input: impossible
631      * Inverse of valid: lossy: Quote::NonPathOctal
632      * Validity indicator: implemented
633      * Output type: any binary
634      * Direction: decode
635      * Method: gsub
636      * Dependencies: -
637      *
638      * @param iniq the char that surrounds the quoted param `other'
639      * @param other a quoted string
640      * @return an empty string if iniq<256 and param `other' not delimited by iniq
641      */
642     B& appendUnslash(const Flat &other, int iniq);
643     /** Appends as a C (double-quoted) string. */
644     B& appendDumpC  (const Flat &other, bool dq=false);
645     /** Appends as a PostScript (paren-quoted) string. */
646     B& appendDumpPS (const Flat &other, bool dq=false);
647     /** Make `other' upper case (English), plus change all non-alpha chars
648      * to underscore.
649      */
650     B& appendHppq(const Flat &other);
651 
652    protected:
grow_by(slen_t howmuch)653     inline char *grow_by(slen_t howmuch) { char *s; vi_grow2(0, howmuch, 0, &s); return s; }
654     /*SimBuffer::*/B& B_append(GenBuffer::Readable &stream);
655 #if 0
656     SimBuffer::B& B_append(char c);
657     SimBuffer::B& B_append(char const*s);
658 #endif
659   };
660 };
661 
operator <<(SimBuffer::B & self,GenBuffer::Readable & stream)662 inline SimBuffer::B& operator<<(SimBuffer::B& self, GenBuffer::Readable &stream) { return self.B_append(stream); }
663 #if 0
664 inline SimBuffer::B& operator<<(SimBuffer::B& self, char const*s) { return self.B_append(s); }
665 inline SimBuffer::B& operator<<(SimBuffer::B& self, char c) { return self.B_append(c); }
666 #endif
667 
668 /** Shorthand synonym */
669 typedef SimBuffer::B Buffer;
670 
operator ==(const GenBuffer & s1,const GenBuffer & s2)671 inline bool operator ==(const GenBuffer& s1, const GenBuffer& s2) {
672   return 0==s1.cmp(s2);
673 }
operator ==(const char * s1,const GenBuffer & s2)674 inline bool operator ==(const char *s1, const GenBuffer& s2) {
675   return 0==s2.cmp(s1);
676 }
operator ==(const GenBuffer & s1,const char * s2)677 inline bool operator ==(const GenBuffer& s1, const char *s2) {
678   return 0==s1.cmp(s2);
679 }
operator <(const GenBuffer & s1,const GenBuffer & s2)680 inline bool operator <(const GenBuffer& s1, const GenBuffer& s2) {
681   return 0>s1.cmp(s2);
682 }
operator <(const char * s1,const GenBuffer & s2)683 inline bool operator <(const char *s1, const GenBuffer& s2) {
684   return 0<s2.cmp(s1);
685 }
operator <(const GenBuffer & s1,const char * s2)686 inline bool operator <(const GenBuffer& s1, const char *s2) {
687   return 0>s1.cmp(s2);
688 }
operator >(const GenBuffer & s1,const GenBuffer & s2)689 inline bool operator >(const GenBuffer& s1, const GenBuffer& s2) {
690   return 0<s1.cmp(s2);
691 }
operator >(const char * s1,const GenBuffer & s2)692 inline bool operator >(const char *s1, const GenBuffer& s2) {
693   return 0>s2.cmp(s1);
694 }
operator >(const GenBuffer & s1,const char * s2)695 inline bool operator >(const GenBuffer& s1, const char *s2) {
696   return 0<s1.cmp(s2);
697 }
operator <=(const GenBuffer & s1,const GenBuffer & s2)698 inline bool operator <=(const GenBuffer& s1, const GenBuffer& s2) {
699   return 0>=s1.cmp(s2);
700 }
operator <=(const char * s1,const GenBuffer & s2)701 inline bool operator <=(const char *s1, const GenBuffer& s2) {
702   return 0<=s2.cmp(s1);
703 }
operator <=(const GenBuffer & s1,const char * s2)704 inline bool operator <=(const GenBuffer& s1, const char *s2) {
705   return 0>=s1.cmp(s2);
706 }
operator >=(const GenBuffer & s1,const GenBuffer & s2)707 inline bool operator >=(const GenBuffer& s1, const GenBuffer& s2) {
708   return 0<=s1.cmp(s2);
709 }
operator >=(const char * s1,const GenBuffer & s2)710 inline bool operator >=(const char *s1, const GenBuffer& s2) {
711   return 0>=s2.cmp(s1);
712 }
operator >=(const GenBuffer & s1,const char * s2)713 inline bool operator >=(const GenBuffer& s1, const char *s2) {
714   return 0<=s1.cmp(s2);
715 }
operator !=(const GenBuffer & s1,const GenBuffer & s2)716 inline bool operator !=(const GenBuffer& s1, const GenBuffer& s2) {
717   return 0!=s1.cmp(s2);
718 }
operator !=(const char * s1,const GenBuffer & s2)719 inline bool operator !=(const char *s1, const GenBuffer& s2) {
720   return 0!=s2.cmp(s1);
721 }
operator !=(const GenBuffer & s1,const char * s2)722 inline bool operator !=(const GenBuffer& s1, const char *s2) {
723   return 0!=s1.cmp(s2);
724 }
725 
726 #endif
727