1 /*
2  * gensi.cpp
3  * by pts@fazekas.hu at Tue Feb 26 13:28:12 CET 2002
4  */
5 
6 #ifdef __GNUC__
7 #ifndef __clang__
8 #pragma implementation
9 #endif
10 #endif
11 
12 #include "gensi.hpp"
13 #include <string.h> /* strlen() */
14 // #include <stdarg.h> /* va_list */
15 
iter_char_sub(char const * beg,slen_t len,void * data)16 void GenBuffer::iter_char_sub(char const*beg, slen_t len, void *data) {
17   while (len--!=0) (1[(block_char_t**)data][0])(*beg++, 0[(void**)data]);
18 }
19 
20 struct copydata_t {
21   char *to;
22   slen_t cfrom;
23   slen_t clen;
24   slen_t sumlen;
25 };
26 #define CD static_cast<copydata_t*>(data)
iter_copy_sub(char const * beg,slen_t len,void * data)27 static void iter_copy_sub(char const*beg, slen_t len, void *data) {
28   slen_t i;
29   CD->sumlen+=len;
30   if (CD->clen==0) return;
31   i=CD->cfrom;
32   if (i>=len) { CD->cfrom-=len; return; }
33   if (i>0) { CD->cfrom=0; beg+=i; len-=i; }
34   if (len>=CD->clen) { memcpy(CD->to, beg, CD->clen); CD->clen=0; return; }
35   memcpy(CD->to, beg, len);
36   CD->to+=len; CD->clen-=len;
37 }
38 // #include <stdio.h>
copyRange(char * to,slen_t cfrom,slen_t clen) const39 slen_t GenBuffer::copyRange(char *to, slen_t cfrom, slen_t clen) const {
40   if (clen==0) return getLength();
41   copydata_t cd= { to, cfrom, clen, 0 };
42   each_sub(iter_copy_sub, &cd);
43 #if 1
44   while (cd.clen--!=0) *cd.to++='\0'; /* padding */
45 #else
46   fprintf(stderr,"cd.clen=%d\n", cd.clen);
47   while (cd.clen--!=0) {
48     fprintf(stderr,"padded.\n");
49     *cd.to++='\0'; /* padding */
50   }
51 #endif
52   return cd.sumlen;
53 }
54 
55 #if HAVE_LONG_LONG && NEED_LONG_LONG
56 #  define LONGEXT PTS_CFG_LONGEST
57 #else
58 #  define LONGEXT long
59 #endif
60 
61 /* Imp: ensure reentrace. Maybe vi_write wants to output a number which would
62  *      overwrite ours...
63  */
64 static char numtmp[sizeof(LONGEXT)*3+2];
65 
toBool(bool & dst)66 bool GenBuffer::toBool(bool &dst) {
67   /* on  1 true  yes ja   igen igaz  be oui vrai: 1tyjibov */
68   /* off 0 false no  nein nem  hamis ki non --  : 0fnhk */
69   slen_t len=copyRange(numtmp, 0, 3);
70   numtmp[0]|=32; numtmp[1]|=32; numtmp[2]|=32; /* poor man's uppercase */
71   dst=true;
72   if (len==0) return true;
73   if ((numtmp[0]=='o' && numtmp[1]=='f' && numtmp[2]=='f')
74    || numtmp[0]=='0' || numtmp[0]=='f' || numtmp[0]=='n' || numtmp[0]=='h'
75    || numtmp[0]=='k') dst=false;
76   else if ((numtmp[0]<'0' || numtmp[0]>'9') && (numtmp[0]<'a' || numtmp[0]>'z')) return true;
77   return false;
78 }
79 
80 // #include <stdio.h>
81 
toInteger(unsigned long & dst)82 bool GenBuffer::toInteger(unsigned long &dst) {
83   /* Imp: several bases (2, 8, 10 and 16), ignore _too_long_ */
84   /* Imp: check for overflow! */
85   slen_t len=copyRange(numtmp, 0, sizeof(numtmp));
86   // fprintf(stderr,"len=%d\n", len);
87   if (len>=sizeof(numtmp)) return true; /* too long */
88   /* ASSERT(numtmp null-terminated) */
89   char *p=numtmp;
90   if (*p=='+') p++;
91   unsigned long i=0;
92   while (1) {
93     // fprintf(stderr,"toInteger'%c'\n", *p);
94     if (*p<'0' || *p>'9') break;
95     i=10*i+(*p-'0');
96     p++;
97   }
98   dst=i;
99   return *p!='\0'; /* a non-digit arrived */
100 }
toInteger(signed long & dst)101 bool GenBuffer::toInteger(signed long &dst) {
102   /* Imp: several bases (2, 8, 10 and 16), ignore _too_long_ */
103   slen_t len=copyRange(numtmp, 0, sizeof(numtmp));
104   if (len>=sizeof(numtmp)) return true; /* too long */
105   /* ASSERT(numtmp null-terminated) */
106   char *p=numtmp;
107   bool neg=false;
108   if (*p=='+') p++;
109   else if (*p=='-') { neg=true; p++; }
110   unsigned long i=0;
111   while (1) {
112     if (*p<'0' || *p>'9') break;
113     i=10*i+(*p-'0');
114     p++;
115   }
116   dst=neg?-(long)i:i;
117   return *p!='\0'; /* a non-digit arrived */
118 }
119 #if HAVE_LONG_LONG && NEED_LONG_LONG
toInteger(unsigned PTS_CFG_LONGEST & dst)120 bool GenBuffer::toInteger(unsigned PTS_CFG_LONGEST &dst) {
121   /* Imp: several bases (2, 8, 10 and 16), ignore _too_long_ */
122   slen_t len=copyRange(numtmp, 0, sizeof(numtmp));
123   if (len>=sizeof(numtmp)) return true; /* too long */
124   /* ASSERT(numtmp null-terminated) */
125   char *p=numtmp;
126   if (*p=='+') p++;
127   unsigned PTS_CFG_LONGEST i=0;
128   while (1) {
129     if (*p<'0' || *p>'9') break;
130     i=10*i+(*p-'0');
131     p++;
132   }
133   dst=i;
134   return *p!='\0'; /* a non-digit arrived */
135 }
toInteger(signed PTS_CFG_LONGEST & dst)136 bool GenBuffer::toInteger(signed PTS_CFG_LONGEST &dst) {
137   /* Imp: several bases (2, 8, 10 and 16), ignore _too_long_ */
138   slen_t len=copyRange(numtmp, 0, sizeof(numtmp));
139   if (len>=sizeof(numtmp)) return true; /* too long */
140   /* ASSERT(numtmp null-terminated) */
141   char *p=numtmp;
142   bool neg=false;
143   if (*p=='+') p++;
144   else if (*p=='-') { neg=true; p++; }
145   unsigned PTS_CFG_LONGEST i=0;
146   while (1) {
147     if (*p<'0' || *p>'9') break;
148     i=10*i+(*p-'0');
149     p++;
150   }
151   dst=neg?-i:i;
152   return *p!='\0'; /* a non-digit arrived */
153 }
154 #endif
toCString(char * & dst)155 bool GenBuffer::toCString(char *&dst) {
156   slen_t len=getLength();
157   dst=new char[len+1];
158   copyRange(dst, 0, len+1); /* copies the terminating '\0' automatically. */
159   return false;
160 }
161 
cmp(GenBuffer const & s2) const162 int GenBuffer::cmp(GenBuffer const& s2) const {
163   Sub u1, u2;
164   slen_t m;
165   int i;
166   first_sub(u1);
167   s2.first_sub(u2);
168   while (1) {
169     if (u1.len==0 && u2.len==0) return 0;  /* (*this) == s2 */
170     else if (u1.len==0) return -1;         /* (*this) < s2  */
171     else if (u2.len==0) return  1;         /* (*this) > s2  */
172     m=(u1.len<u2.len)?u1.len:u2.len;
173     if (0!=(i=memcmp(u1.beg,u2.beg,m))) return i;
174     if (0==(u1.len-=m))    next_sub(u1); else u1.beg+=m;
175     if (0==(u2.len-=m)) s2.next_sub(u2); else u2.beg+=m;
176   }
177 }
178 
cmp(char const * u2beg,slen_t u2len) const179 int GenBuffer::cmp(char const* u2beg, slen_t u2len) const {
180   Sub u1;
181   slen_t m;
182   int i;
183   first_sub(u1);
184   while (1) {
185     if (u1.len==0 && u2len==0) return 0;   /* (*this) == s2 */
186     else if (u1.len==0) return -1;         /* (*this) < s2  */
187     else if (u2len ==0) return  1;         /* (*this) > s2  */
188     m=(u1.len<u2len)?u1.len:u2len;
189     if (0!=(i=memcmp(u1.beg,u2beg,m))) return i;
190     if (0==(u1.len-=m))    next_sub(u1); else u1.beg+=m;
191     u2len-=m; u2beg+=m;
192   }
193 }
194 
cmp(char const * u2beg) const195 int GenBuffer::cmp(char const* u2beg) const {
196   return cmp(u2beg, strlen(u2beg));
197 }
198 
199 /* --- */
200 
equal_content(GenBuffer::Readable & other)201 bool GenBuffer::Readable::equal_content(GenBuffer::Readable &other) {
202   int i1, i2;
203   while (((i1=vi_getcc())&255) == ((i2=other.vi_getcc())&255) && i1!=-1) ;
204   return i1==i2;
205 }
206 
vi_read(char * to_buf,slen_t max)207 slen_t GenBuffer::Readable::vi_read(char *to_buf, slen_t max) {
208   register char *p=to_buf;
209   char *end=to_buf+max;
210   int c;
211   while (p!=end && 0<=(c=vi_getcc())) *p++=c;
212   return p-to_buf;
213 }
214 
readFill(char * to_buf,slen_t max)215 int GenBuffer::Readable::readFill(char *to_buf, slen_t max) {
216   slen_t got, sum=0;
217   while (max>0 && 0<(got=vi_read(to_buf, max))) { to_buf+=got; sum+=got; max-=got; }
218   return sum;
219 }
220 
221 /* --- */
222 
iter_write_sub(char const * beg,slen_t len,void * data)223 void GenBuffer::Writable::iter_write_sub(char const*beg, slen_t len, void *data) {
224   if (len!=0) static_cast<GenBuffer::Writable*>(data)->vi_write(beg, len);
225 }
226 
operator <<(char const * cstr)227 GenBuffer::Writable& GenBuffer::Writable::operator <<(char const*cstr) {
228   assert(cstr!=0);
229   vi_write(cstr, strlen(cstr));
230   return*this;
231 }
232 
operator <<(void const * ptr)233 GenBuffer::Writable& GenBuffer::Writable::operator <<(void const*ptr) {
234   if (ptr==0) vi_write("(null)", 6);
235   else {
236     vi_write("(0d", 3);
237     /* Imp: hexadecimal pointer output */
238     *this << (PTS_INTP_T)ptr;
239     vi_putcc(')');
240   }
241   return*this;
242 }
243 
write_num(unsigned long n,unsigned zdigits)244 void GenBuffer::Writable::write_num(unsigned long n, unsigned zdigits) {
245   if (zdigits>=sizeof(numtmp)) {
246     memset(numtmp,'0',sizeof(numtmp));
247     while (zdigits>2*sizeof(numtmp)) {
248       vi_write(numtmp, sizeof(numtmp));
249       zdigits-=sizeof(numtmp);
250     }
251     vi_write(numtmp, zdigits-sizeof(numtmp));
252     zdigits=sizeof(numtmp);
253   }
254   char *j=numtmp+sizeof(numtmp), *jend=j-zdigits;
255   while (j!=jend) { *--j='0'+n%10; n/=10; }
256   vi_write(j, zdigits);
257 }
258 #if HAVE_LONG_LONG && NEED_LONG_LONG
write_num(unsigned PTS_CFG_LONGEST n,unsigned zdigits)259 void GenBuffer::Writable::write_num(unsigned PTS_CFG_LONGEST n, unsigned zdigits) {
260   if (zdigits>=sizeof(numtmp)) {
261     memset(numtmp,'0',sizeof(numtmp));
262     while (zdigits>2*sizeof(numtmp)) {
263       vi_write(numtmp, sizeof(numtmp));
264       zdigits-=sizeof(numtmp);
265     }
266     vi_write(numtmp, zdigits-sizeof(numtmp));
267     zdigits=sizeof(numtmp);
268   }
269   char *j=numtmp+sizeof(numtmp), *jend=j-zdigits;
270   while (j!=jend) { *--j='0'+n%10; n/=10; }
271   vi_write(j, zdigits);
272 }
273 #endif
274 
write_num(unsigned long n)275 void GenBuffer::Writable::write_num(unsigned long n) {
276   char *j=numtmp+sizeof(numtmp);
277   do *--j='0'+n%10; while ((n/=10)!=0);
278   vi_write(j, numtmp+sizeof(numtmp)-j);
279 }
write_num(signed long nn)280 void GenBuffer::Writable::write_num(signed long nn) {
281   register unsigned long n;
282   char *j=numtmp+sizeof(numtmp);
283   if (nn<0) {
284     n=-nn; do *--j='0'+n%10; while ((n/=10)!=0);
285     *--j='-';
286   } else {
287     n=nn; do *--j='0'+n%10; while ((n/=10)!=0);
288   }
289   vi_write(j, numtmp+sizeof(numtmp)-j);
290 }
291 #if HAVE_LONG_LONG && NEED_LONG_LONG
write_num(unsigned PTS_CFG_LONGEST n)292 void GenBuffer::Writable::write_num(unsigned PTS_CFG_LONGEST n) {
293   char *j=numtmp+sizeof(numtmp);
294   do *--j='0'+n%10; while ((n/=10)!=0);
295   vi_write(j, numtmp+sizeof(numtmp)-j);
296 }
write_num(signed PTS_CFG_LONGEST nn)297 void GenBuffer::Writable::write_num(signed PTS_CFG_LONGEST nn) {
298   register unsigned PTS_CFG_LONGEST n;
299   char *j=numtmp+sizeof(numtmp);
300   if (nn<0) {
301     n=-nn; do *--j='0'+n%10; while ((n/=10)!=0);
302     *--j='-';
303   } else {
304     n=nn;
305     do *--j='0'+n%10; while ((n/=10)!=0);
306   }
307   vi_write(j, numtmp+sizeof(numtmp)-j);
308 }
309 #endif
310 
vformat(slen_t n,char const * fmt,va_list ap)311 GenBuffer::Writable& GenBuffer::Writable::vformat(slen_t n, char const *fmt, va_list ap) {
312   SimBuffer::B buf;
313   buf.vformat(n, fmt, ap);
314   vi_write(buf(), buf.getLength());
315   return*this;
316 }
vformat(char const * fmt,va_list ap)317 GenBuffer::Writable& GenBuffer::Writable::vformat(char const *fmt, va_list ap) {
318   SimBuffer::B buf;
319   buf.vformat(fmt, ap);
320   vi_write(buf(), buf.getLength());
321   return*this;
322 }
format(slen_t n,char const * fmt,...)323 GenBuffer::Writable& GenBuffer::Writable::format(slen_t n, char const *fmt, ...) {
324   va_list ap;
325   PTS_va_start(ap, fmt);
326   vformat(n, fmt, ap);
327   va_end(ap);
328   return *this;
329 }
format(char const * fmt,...)330 GenBuffer::Writable& GenBuffer::Writable::format(char const *fmt, ...) {
331   va_list ap;
332   PTS_va_start(ap, fmt);
333   vformat(fmt, ap);
334   va_end(ap);
335   return *this;
336 }
337 
338 /* --- */
339 
copyRange(char * to,slen_t cfrom,slen_t clen) const340 slen_t SimBuffer::Flat::copyRange(char *to, slen_t cfrom, slen_t clen) const {
341   if (cfrom<len) { /* added padding BUGFIX at Fri Mar  7 20:30:07 CET 2003 */
342     slen_t dlen;
343     memcpy(to, beg+cfrom, dlen=cfrom+clen>len ? len-cfrom : clen);
344     to+=dlen;
345   }
346   while (clen--!=0) *to++='\0'; /* padding */
347   return len;
348 }
349 
findLast(char const c) const350 slen_t SimBuffer::Flat::findLast(char const c) const {
351   char const*p;
352   for (p=beg+len;p>=beg;p--) if (*p==c) return p-beg;
353   return len;
354 }
355 
findFirst(char const c) const356 slen_t SimBuffer::Flat::findFirst(char const c) const {
357   char const*p, *end=beg+len;
358   for (p=beg;p!=end;p++) if (*p==c) return p-beg;
359   return len;
360 }
361 
findFirst(char const * s,slen_t slen) const362 slen_t SimBuffer::Flat::findFirst(char const* s, slen_t slen) const {
363   if (slen==0) return 0; /* found */
364   if (slen>len) return len; /* not found */
365   char const c=*s;
366   char const*p=beg, *end=beg+len-slen+1;
367   if (slen==1) {
368     for (;p!=end;p++) if (*p==c) return p-beg;
369   } else {
370     for (;p!=end;p++) if (*p==c && 0==memcmp(p,s,slen)) return p-beg;
371   }
372   return len;
373 }
374 
cmpFlat(SimBuffer::Flat const & s2) const375 int SimBuffer::Flat::cmpFlat(SimBuffer::Flat const& s2) const {
376   return memcmp(beg, s2.beg, len<s2.len?len:s2.len) || (len>s2.len)-(len<s2.len);
377 }
378 
cmp(char const * s2beg,slen_t s2len) const379 int SimBuffer::Flat::cmp(char const* s2beg, slen_t s2len) const {
380   return memcmp(beg, s2beg, len<s2len?len:s2len) || (len>s2len)-(len<s2len);
381 }
382 
383 /* --- */
384 
Static(char const * cstr)385 SimBuffer::Static::Static(char const*cstr) { beg=cstr; len=strlen(cstr); }
386 
387 /* --- */
388 
vi_write(char const * str,slen_t slen)389 void SimBuffer::Appendable::vi_write(char const*str, slen_t slen) {
390   if (slen>0) {
391     char *p=vi_mkend(slen);
392     memcpy(p, str, slen);
393   }
394 }
prepend(char const * str,slen_t slen)395 void SimBuffer::Appendable::prepend(char const*str, slen_t slen) {
396   if (slen>0) {
397     char *p=vi_mkbeg(slen);
398     memcpy(p, str, slen);
399   }
400 }
401 
402 /* inlined.
403 void SimBuffer::Appendable::vi_putcc(char c) {
404   vi_mkend(1)[0]=c;
405 }*/
406 
407 /* --- */
408 
~Linked()409 SimBuffer::Linked::~Linked() {
410   Node *n;
411   while (first!=0) {
412     if (first->beg!=(char*)(first+1)) delete [] first->beg;
413     n=first->next; delete [] first; first=n;
414   }
415 }
416 
getLength() const417 slen_t SimBuffer::Linked::getLength() const {
418   slen_t len=0;
419   Node *n=first;
420   while (n!=0) { len+=n->len; n=n->next; }
421   return len;
422 }
423 
Linked(GenBuffer const & other)424 SimBuffer::Linked::Linked(GenBuffer const& other) {
425   slen_t len=other.getLength();
426   Node *n=static_cast<Node*>(static_cast<void*>(new char[sizeof(Node)+len]));
427   n->beg=(char*)(n+1);
428   other.copyRange(n->beg, 0, len);
429   n->len=len;
430   n->next=0;
431   first=last=n;
432 }
Linked(char const * str)433 SimBuffer::Linked::Linked(char const*str) {
434   slen_t len=strlen(str);
435   Node *n=static_cast<Node*>(static_cast<void*>(new char[sizeof(Node)+len]));
436   n->beg=(char*)(n+1);
437   memcpy(n->beg, str, len);
438   n->len=len;
439   n->next=0;
440   first=last=n;
441 }
operator =(GenBuffer const & other)442 SimBuffer::Linked& SimBuffer::Linked::operator=(GenBuffer const& other) {
443   slen_t len=other.getLength();
444   Node *n=static_cast<Node*>(static_cast<void*>(new char[sizeof(Node)+len]));
445   n->beg=(char*)(n+1);
446   other.copyRange(n->beg, 0, len);
447   n->len=len;
448   n->next=0;
449   first=last=n;
450   return *this;
451 }
operator =(SimBuffer::Linked const & other)452 SimBuffer::Linked& SimBuffer::Linked::operator=(SimBuffer::Linked const& other) {
453   /* Imp: avoid code repeat */
454   slen_t len=other.getLength();
455   Node *n=static_cast<Node*>(static_cast<void*>(new char[sizeof(Node)+len]));
456   n->beg=(char*)(n+1);
457   other.copyRange(n->beg, 0, len);
458   n->len=len;
459   n->next=0;
460   first=last=n;
461   return *this;
462 }
463 
each_sub(GenBuffer::block_sub_t block,void * data) const464 void SimBuffer::Linked::each_sub(GenBuffer::block_sub_t block, void *data) const {
465   Node *n=first;
466   while (n!=0) { block(n->beg, n->len, data); n=n->next; }
467 }
first_sub(Sub & sub) const468 void SimBuffer::Linked::first_sub(Sub &sub) const {
469   if (first!=0) {
470     sub.data=first->next;
471     sub.beg=first->beg;
472     sub.len=first->len;
473   } else sub.len=0;
474 }
next_sub(Sub & sub) const475 void SimBuffer::Linked::next_sub(Sub &sub) const {
476   if (sub.data!=0) {
477     sub.beg=static_cast<Node*>(sub.data)->beg;
478     sub.len=static_cast<Node*>(sub.data)->len;
479     sub.data=static_cast<Node*>(sub.data)->next;
480   } else sub.len=0;
481 }
vi_mkend(slen_t len)482 char *SimBuffer::Linked::vi_mkend(slen_t len) {
483   Node *n=static_cast<Node*>(static_cast<void*>(new char[sizeof(Node)+len]));
484   n->beg=(char*)(n+1);
485   n->len=len;
486   n->next=0;
487   if (last==0) first=last=n;
488           else { last->next=n; last=n; }
489   return n->beg;
490 }
vi_mkbeg(slen_t len)491 char *SimBuffer::Linked::vi_mkbeg(slen_t len) {
492   Node *n=static_cast<Node*>(static_cast<void*>(new char[sizeof(Node)+len]));
493   n->beg=(char*)(n+1);
494   n->len=len;
495   n->next=first;
496   first=n;
497   if (last==0) last=n;
498   return n->beg;
499 }
500 
501 /* --- */
502 
operator =(GenBuffer const & s2)503 SimBuffer::Resizable& SimBuffer::Resizable::operator=(GenBuffer const& s2) {
504   vi_grow2(0, s2.getLength()-getLength(), 0, 0);
505   assert(getLength()==s2.getLength());
506 
507   Sub u1, u2;
508   slen_t m;
509   first_sub(u1);
510   s2.first_sub(u2);
511   assert(!((u1.len==0) ^ (u2.len==0))); /* s1 and s2 end in the same time */
512   while (u1.len!=0) {
513     m=(u1.len<u2.len)?u1.len:u2.len;
514     memcpy(const_cast<char*>(u1.beg), u2.beg, m);
515     if (0==(u1.len-=m))    next_sub(u1); else u1.beg+=m;
516     if (0==(u2.len-=m)) s2.next_sub(u2); else u2.beg+=m;
517     assert(!((u1.len==0) ^ (u2.len==0))); /* s1 and s2 end in the same time */
518   }
519   return*this;
520 }
521 
522 //void SimBuffer::Resizable::clear() { /* Inlined. */
523 //  vi_grow2(0, -getLength(), 0, 0);
524 //}
525 
keepLeft(slen_t howmuch)526 void SimBuffer::Resizable::keepLeft(slen_t howmuch) {
527   slen_t len=getLength();
528   vi_grow2(0, len>howmuch?0-len+howmuch:-(slendiff_t)len, 0, 0);
529   /* ^^^ BUGFIX at Tue Jun 11 19:57:03 CEST 2002 */
530 }
keepRight(slen_t howmuch)531 void SimBuffer::Resizable::keepRight(slen_t howmuch) {
532   slen_t len=getLength();
533   vi_grow2(len>howmuch?0-len+howmuch:-(slendiff_t)len, 0, 0, 0);
534   /* ^^^ BUGFIX at Tue Jun 11 19:57:03 CEST 2002 */
535 }
keepSubstr(slen_t from_offset,slen_t slen)536 void SimBuffer::Resizable::keepSubstr(slen_t from_offset, slen_t slen) {
537   slen_t len=getLength();
538   if (from_offset>=len) vi_grow2(0, -(slendiff_t)len, 0, 0);
539   else if (from_offset+slen>=len) vi_grow2(-(slendiff_t)from_offset, 0, 0, 0);
540   else vi_grow2(-(slendiff_t)from_offset, len-from_offset-slen, 0, 0);
541 }
542 
543 /* --- */
544 
vi_grow2(slendiff_t left,slendiff_t right,char ** lbeg,char ** rbeg)545 void SimBuffer::B::vi_grow2(slendiff_t left, slendiff_t right, char **lbeg, char **rbeg) {
546   assert(alloced>=len);
547   char *origbeg=const_cast<char*>(beg);
548   if (left<0)  { if (len<=(slen_t)-left) len=0; else beg-=left; left=0; } /* ! */
549   if (right<0) { if (len<=(slen_t)-right)len=0; else len+=right;right=0; }
550   /* ^^^ BUGFIX at Tue Jun 11 16:07:56 CEST 2002 */
551   assert(left>=0);
552   assert(right>=0);
553   slen_t newlen=left+right+len;
554   assert(newlen>=len);
555   char *newbeg;
556   assert(alloced>=sizeof(small)/1);
557   if (beg==small) {
558     assert(alloced==sizeof(small));
559     if (newlen>sizeof(small)) {
560       assert(newlen>len);
561       newbeg=new char[alloced=2*newlen];
562       memcpy(newbeg+left, beg, len);
563       beg=newbeg;
564     }
565   } else { /* beg!=small */
566     // assert(len>=alloced/2); /* -- may not always be true, especially not after appending a `long' */
567     if (newlen<alloced/2) { /* shrink */
568       // assert(newlen<=len); /* filled-expectations are true _after_ vi_grow2, not before */
569       if (newlen>sizeof(small)) {
570         newbeg=new char[alloced=newlen];
571         memcpy(newbeg+left, beg, len);
572       } else {
573         memcpy((newbeg=small)+left, beg, len);
574         delete [] origbeg;
575         alloced=sizeof(small);
576       }
577       beg=newbeg;
578     } else if (newlen>alloced) { /* grow */
579       assert(newlen>sizeof(small));
580       assert(newlen>len);
581       newbeg=new char[alloced=2*newlen];
582       memcpy(newbeg+left, beg, len);
583       delete [] origbeg;
584       beg=newbeg;
585     } else if (beg!=origbeg) { /* called with negative `left' @param */
586       assert(left==0);
587       memmove(origbeg, beg, len); /* Slow, may move the whole buffer. */
588     }
589   }
590   // fprintf(stderr, "newlen=%u\n", newlen);
591   len=newlen;
592   if (lbeg) *lbeg=const_cast<char*>(beg);
593   if (rbeg) *rbeg=const_cast<char*>(beg+newlen-right);
594   assert(alloced==sizeof(small) || (alloced>sizeof(small) && len>=alloced/2));
595   assert(alloced>=len);
596 }
597 
B(char const * cstr)598 SimBuffer::B::B(char const* cstr): alloced(sizeof(small)) {
599   beg=small;
600   slen_t len_=strlen(cstr);
601   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
602                      else len=len_;
603   assert(len==len_);
604   memcpy(const_cast<char*>(beg), cstr, len);
605 }
606 
B(char const * str,slen_t len_)607 SimBuffer::B::B(char const* str, slen_t len_): alloced(sizeof(small)) {
608   beg=small;
609   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
610                      else len=len_;
611   assert(len==len_);
612   memcpy(const_cast<char*>(beg), str, len);
613 }
614 
B(SimBuffer::B const & other)615 SimBuffer::B::B(SimBuffer::B const& other): GenBuffer(), SimBuffer::Resizable(), SimBuffer::Flat(), alloced(sizeof(small)) {
616   beg=small;
617   if (other.len>sizeof(small)) { len=0; vi_grow2(0, other.len, 0, 0); }
618                      else len=other.len;
619   assert(len==other.len);
620   memcpy(const_cast<char*>(beg), other.beg, len);
621 }
622 
B(SimBuffer::Flat const & other)623 SimBuffer::B::B(SimBuffer::Flat const& other): alloced(sizeof(small)) {
624   beg=small;
625   if (other.len>sizeof(small)) { len=0; vi_grow2(0, other.len, 0, 0); }
626                      else len=other.len;
627   assert(len==other.len);
628   memcpy(const_cast<char*>(beg), other.beg, len);
629 }
630 
B(SimBuffer::Flat const & other,int)631 SimBuffer::B::B(SimBuffer::Flat const& other,int): alloced(sizeof(small)) {
632   beg=small;
633   if (other.len>=sizeof(small)) { len=0; vi_grow2(0, other.len+1, 0, 0); len--; }
634                      else len=other.len;
635   assert(len==other.len);
636   memcpy(const_cast<char*>(beg), other.beg, len);
637   const_cast<char*>(beg)[len]='\0';
638 }
639 
B(SimBuffer::Flat const & other,slen_t from_offset,slen_t len_)640 SimBuffer::B::B(SimBuffer::Flat const& other, slen_t from_offset, slen_t len_): alloced(sizeof(small)) {
641   /* substr */
642   beg=small;
643   if (from_offset<other.len) {
644     if (from_offset+len_>other.len) len_=other.len-from_offset;
645     if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
646                        else len=len_;
647     assert(len==len_);
648     memcpy(const_cast<char*>(beg), other.beg+from_offset, len);
649   } else len=0;
650 }
651 
B(GenBuffer const & other)652 SimBuffer::B::B(GenBuffer const& other): alloced(sizeof(small)) {
653   slen_t len_=other.getLength();
654   beg=small;
655   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
656                      else len=len_;
657   assert(len==len_);
658   other.copyRange(const_cast<char*>(beg), 0, len_);
659 }
660 
661 /** Constructor: copy (consume) data from a readable stream. */
B(GenBuffer::Readable & other)662 SimBuffer::B::B(GenBuffer::Readable &other): alloced(sizeof(small)) {
663   beg=small;
664   len=0;
665 #if 000
666   operator <<(other);
667 #else
668   B_append(other);
669 #endif
670 }
671 
B(char const * as,slen_t al,char const * bs,slen_t bl)672 SimBuffer::B::B(char const* as,slen_t al, char const* bs,slen_t bl): alloced(sizeof(small)) {
673   slen_t len_=al+bl;
674   beg=small;
675   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
676                      else len=len_;
677   assert(len==len_);
678   memcpy(const_cast<char*>(beg), as, al);
679   memcpy(const_cast<char*>(beg)+al, bs, bl);
680 }
681 
B(char const * as,slen_t al,char const * bs,slen_t bl,int)682 SimBuffer::B::B(char const* as,slen_t al, char const* bs,slen_t bl,int): alloced(sizeof(small)) {
683   slen_t len_=al+bl;
684   beg=small;
685   if (len_>=sizeof(small)) { len=0; vi_grow2(0, len_+1, 0, 0); len--; }
686                       else len=len_;
687   assert(len==len_);
688   memcpy(const_cast<char*>(beg), as, al);
689   memcpy(const_cast<char*>(beg)+al, bs, bl);
690   const_cast<char*>(beg)[al+bl]='\0';
691 }
692 
B(GenBuffer const & a,GenBuffer const & b)693 SimBuffer::B::B(GenBuffer const& a, GenBuffer const& b): alloced(sizeof(small)) {
694   slen_t al=a.getLength();
695   slen_t bl=b.getLength();
696   slen_t len_=al+bl;
697   beg=small;
698   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
699                      else len=len_;
700   assert(len==len_);
701   a.copyRange(const_cast<char*>(beg), 0, al);
702   b.copyRange(const_cast<char*>(beg)+al, 0, bl);
703 }
704 
B(GenBuffer const & a,GenBuffer const & b,GenBuffer const & c)705 SimBuffer::B::B(GenBuffer const& a, GenBuffer const& b, GenBuffer const& c): alloced(sizeof(small)) {
706   slen_t al=a.getLength();
707   slen_t bl=b.getLength();
708   slen_t cl=c.getLength();
709   slen_t len_=al+bl;
710   beg=small;
711   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
712                      else len=len_;
713   assert(len==len_);
714   a.copyRange(const_cast<char*>(beg), 0, al);
715   b.copyRange(const_cast<char*>(beg)+al, 0, bl);
716   c.copyRange(const_cast<char*>(beg)+al+bl, 0, cl);
717 }
718 
B(char const * as,slen_t al,char const * bs,slen_t bl,char const * cs,slen_t cl)719 SimBuffer::B::B(char const* as,slen_t al, char const* bs,slen_t bl, char const* cs,slen_t cl): alloced(sizeof(small)) {
720   slen_t len_=al+bl+cl;
721   beg=small;
722   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
723                      else len=len_;
724   assert(len==len_);
725   memcpy(const_cast<char*>(beg), as, al);
726   memcpy(const_cast<char*>(beg)+al, bs, bl);
727   memcpy(const_cast<char*>(beg)+al+bl, cs, cl);
728 }
729 
B(Flat const & b,char const * cs)730 SimBuffer::B::B(Flat const&b, char const*cs): alloced(sizeof(small)) {
731   slen_t cl=strlen(cs);
732   slen_t len_=b.len+cl;
733   beg=small;
734   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
735                      else len=len_;
736   assert(len==len_);
737   memcpy(const_cast<char*>(beg), b.beg, b.len);
738   memcpy(const_cast<char*>(beg)+b.len, cs, cl);
739 }
740 
B(char const * as,Flat const & b,char const * cs)741 SimBuffer::B::B(char const*as, Flat const&b, char const*cs): alloced(sizeof(small)) {
742   slen_t al=strlen(as);
743   slen_t cl=strlen(cs);
744   slen_t len_=al+b.len+cl;
745   beg=small;
746   if (len_>sizeof(small)) { len=0; vi_grow2(0, len_, 0, 0); }
747                      else len=len_;
748   assert(len==len_);
749   memcpy(const_cast<char*>(beg), as, al);
750   memcpy(const_cast<char*>(beg)+al, b.beg, b.len);
751   memcpy(const_cast<char*>(beg)+al+b.len, cs, cl);
752 }
753 
754 /* SimBuffer::B& operator<<(SimBuffer::B& self, GenBuffer::Readable &stream); */
B_append(GenBuffer::Readable & stream)755 SimBuffer::B& SimBuffer::B::B_append(GenBuffer::Readable &stream) {
756   assert(alloced>=len);
757   slen_t oldlen, ask;
758   ask=stream.vi_availh();
759   if (ask>0) { oldlen=len; vi_grow2(0, ask+1, 0, 0); len=oldlen; }
760   if (alloced!=len) len+=stream.readFill(const_cast<char*>(beg+len), alloced-len);
761   while (alloced==len) { /* more data to be read */
762     oldlen=len; vi_grow2(0, alloced, 0, 0); len=oldlen;
763     stream.readFill(const_cast<char*>(beg+len), alloced-len);
764   }
765   return *this;
766 }
767 
term0()768 SimBuffer::B& SimBuffer::B::term0() {
769   if (len==alloced) { vi_grow2(0,1,0,0); len--; }
770   const_cast<char*>(beg)[len]='\0';
771   return *this;
772 }
773 
grow_set0_by(slendiff_t lendiff)774 void SimBuffer::B::grow_set0_by(slendiff_t lendiff) {
775   char *rbeg;
776   vi_grow2(0, lendiff, 0, &rbeg);
777   if (lendiff>0) memset(rbeg, '\0', lendiff);
778 }
779 
getAt(slen_t idx)780 char SimBuffer::B::getAt(slen_t idx) {
781   if (idx<len) return beg[idx];
782   /* grow_set0_by(idx+1-len); */
783   char *rbeg;
784   vi_grow2(0, idx-len+1, 0, &rbeg);
785   memset(rbeg, '\0', idx-len+1);
786   return '\0';
787 }
788 
operator =(SimBuffer::Flat const & other)789 SimBuffer::B& SimBuffer::B::operator=(SimBuffer::Flat const& other) {
790   if (&other!=this) {
791     len=0;
792     vi_grow2(0, other.len, 0, 0);
793     memcpy(const_cast<char*>(beg), other.beg, len);
794   }
795   return*this;
796 }
797 
operator =(SimBuffer::B const & other)798 SimBuffer::B& SimBuffer::B::operator=(SimBuffer::B const& other) {
799   if (&other!=this) {
800     len=0;
801     vi_grow2(0, other.len, 0, 0);
802     memcpy(const_cast<char*>(beg), other.beg, len);
803   }
804   return*this;
805 }
806 
operator =(char const * cstr)807 SimBuffer::B& SimBuffer::B::operator=(char const* cstr) {
808   slen_t slen=strlen(cstr);
809   len=0;
810   vi_grow2(0, slen, 0, 0);
811   memcpy(const_cast<char*>(beg), cstr, slen);
812   return*this;
813 }
814 
substr(slen_t first,slen_t howmuch) const815 SimBuffer::B SimBuffer::B::substr(slen_t first, slen_t howmuch) const {
816   return SimBuffer::B(*this, first, howmuch);
817 }
substr(slen_t first) const818 SimBuffer::B SimBuffer::B::substr(slen_t first) const {
819   /* Actually, this will probably be shorter than end-begin */
820   return SimBuffer::B(*this, first, len);
821 }
right(slen_t howmuch) const822 SimBuffer::B SimBuffer::B::right(slen_t howmuch) const {
823   return SimBuffer::B(*this, len<=howmuch?0:len-howmuch, howmuch);
824 }
left(slen_t howmuch) const825 SimBuffer::B SimBuffer::B::left(slen_t howmuch) const {
826   return SimBuffer::B(*this, 0, howmuch);
827 }
828 
829 #if 0
830 void SimBuffer::B::append(char const*s, const slen_t len_) {
831   char *rbeg;
832   vi_grow2(0, len_, 0, &rbeg);
833   memcpy(rbeg, s, len_);
834 }
835 #endif
836 
operator +(const SimBuffer::Flat & s1,const SimBuffer::Flat & s2)837 SimBuffer::B operator+(const SimBuffer::Flat& s1, const SimBuffer::Flat& s2) {
838   return SimBuffer::B(s1.beg, s1.len, s2.beg, s2.len);
839 }
operator +(const char * s1,const SimBuffer::Flat & s2)840 SimBuffer::B operator+(const char *s1, const SimBuffer::Flat& s2) {
841   return SimBuffer::B(s1, strlen(s1), s2.beg, s2.len);
842 }
operator +(const SimBuffer::Flat & s1,const char * s2)843 SimBuffer::B operator+(const SimBuffer::Flat& s1, const char *s2) {
844   return SimBuffer::B(s1.beg, s1.len, s2, strlen(s2));
845 }
846 
operator <<(SimBuffer::Flat const & other)847 SimBuffer::B& SimBuffer::B::operator<<(SimBuffer::Flat const& other) {
848   char *d;
849   vi_grow2(0, other.len, 0, &d);
850   memcpy(d,other.beg,other.len);
851   return*this;
852 }
853 
operator <<(char c)854 SimBuffer::B& SimBuffer::B::operator<<(char c) {
855   if (len==alloced) { vi_grow2(0, 1, 0, 0); const_cast<char*>(beg)[len-1]=c; }
856                else const_cast<char*>(beg)[len++]=c;
857   return*this;
858 }
operator <<(char const * s)859 SimBuffer::B& SimBuffer::B::operator<<(char const *s) {
860   char *d;
861   slen_t slen=strlen(s);
862   vi_grow2(0, slen, 0, &d);
863   memcpy(d,s,slen);
864   return*this;
865 }
vi_write(char const * str,slen_t slen)866 void SimBuffer::B::vi_write(char const*str, slen_t slen) {
867   if (slen>0) {
868     char *p; vi_grow2(0, slen, 0, &p);
869     memcpy(p, str, slen);
870   }
871 }
872 
873 #define USGE(a,b) ((unsigned char)(a))>=((unsigned char)(b))
is_path(char const c)874 static inline bool is_path(char const c) {
875  return c=='-' || c=='.' || c=='_' || c=='/'
876      || USGE('z'-'a',c-'a')
877      || USGE('Z'-'A',c-'A')
878      || USGE('9'-'0',c-'0');
879 }
is_safe_c(char const c)880 static inline bool is_safe_c(char const c) {
881   return c!='\\' && c!='\'' && c!='\"' && USGE('~'-' ',c-' ');
882 }
is_safe_ps(char const c)883 static inline bool is_safe_ps(char const c) {
884   return c!='\\' && c!='('  && c!=')'  && USGE('~'-' ',c-' ');
885 }
886 
appendDump(const char c,bool dq)887 SimBuffer::B& SimBuffer::B::appendDump(const char c, bool dq) {
888   char t[7]; register char *p=t;
889   if (dq) *p++='\'';
890   if (is_path(c)) {
891     *p++=c;
892   } else {
893     *p++='\\';
894     *p++=('0'+((c>>6)&3));
895     *p++=('0'+((c>>3)&7));
896     *p++=('0'+(c&7));
897   }
898   if (dq) *p++='\'';
899   vi_write(t, p-t);
900   return*this;
901 }
902 
903 
appendDump(const SimBuffer::Flat & other,bool dq)904 SimBuffer::B& SimBuffer::B::appendDump(const SimBuffer::Flat &other, bool dq) {
905   slen_t rlen=dq?2:0;
906   register char c; register char const*p;
907   char const *pend; char *dst;
908   for (p=other.beg,pend=p+other.len; p!=pend; p++) rlen+=is_path(*p)?1:4;
909   vi_grow2(0, rlen, 0, &dst);
910   if (dq) *dst++='"';
911   for (p=other.beg,pend=p+other.len; p!=pend; p++) {
912     if (is_path(c=*p)) {
913       *dst++=c;
914     } else {
915       *dst++='\\';
916       *dst++=('0'+((c>>6)&3));
917       *dst++=('0'+((c>>3)&7));
918       *dst++=('0'+(c&7));
919     }
920   }
921   if (dq) *dst++='"';
922   assert(dst==end_());
923   return*this;
924 }
925 
appendNpmq(const SimBuffer::Flat & other,bool dq)926 SimBuffer::B& SimBuffer::B::appendNpmq(const SimBuffer::Flat &other, bool dq) {
927   slen_t rlen=dq?2:0;
928   register char c; register char const*p;
929   char const *pend; char *dst;
930   for (p=other.beg,pend=p+other.len; p!=pend; p++) rlen+=is_path(*p)?1:2;
931   vi_grow2(0, rlen, 0, &dst);
932   if (dq) *dst++='"';
933   for (p=other.beg,pend=p+other.len; p!=pend; p++) {
934     if (is_path(c=*p)) {
935       *dst++=c;
936     } else {
937       *dst++='\\';
938       *dst++=c;
939     }
940   }
941   if (dq) *dst++='"';
942   assert(dst==end_());
943   return*this;
944 }
945 
appendDumpC(const SimBuffer::Flat & other,bool dq)946 SimBuffer::B& SimBuffer::B::appendDumpC  (const SimBuffer::Flat &other, bool dq) {
947   slen_t rlen=dq?2:0;
948   register char c; register char const*p;
949   char const *pend; char *dst;
950   for (p=other.beg,pend=p+other.len; p!=pend; p++) rlen+=is_safe_c(*p)?1:4;
951   vi_grow2(0, rlen, 0, &dst);
952   if (dq) *dst++='"';
953   for (p=other.beg,pend=p+other.len; p!=pend; p++) {
954     if (is_safe_c(c=*p)) {
955       *dst++=c;
956     } else {
957       *dst++='\\';
958       *dst++=('0'+((c>>6)&3));
959       *dst++=('0'+((c>>3)&7));
960       *dst++=('0'+(c&7));
961     }
962   }
963   if (dq) *dst++='"';
964   assert(dst==end_());
965   return*this;
966 }
967 
appendFnq(const SimBuffer::Flat & other,bool preminus)968 SimBuffer::B& SimBuffer::B::appendFnq(const SimBuffer::Flat &other, bool preminus) {
969   slen_t rlen=0;
970   register char c; register char const*p;
971   char const *pend; char *dst;
972   if (OS_COTY==COTY_WINNT || OS_COTY==COTY_WIN9X) {
973     for (p=other.beg,pend=p+other.len; p!=pend; p++) {
974       if ('\0'==(c=*p) || c=='"') break;
975       rlen++;
976     }
977     if (preminus && rlen!=0 && other.beg[0]=='-') rlen+=2; /* .\ */
978     vi_grow2(0, rlen+2, 0, &dst);
979     *dst++='"'; /* Dat: "ab"c" ""def" is perfectly legal and parses to: `abc def' */
980     p=other.beg;
981     if (preminus && other.beg[0]=='-') { *dst++='.'; *dst++='\\'; }
982     for (p=other.beg,pend=p+other.len; p!=pend; p++) {
983       if ('\0'==(c=*p) || c=='"') break;
984       *dst++=c;
985     }
986     *dst++='"';
987   } else { /* Everything else is treated as UNIX */
988     for (p=other.beg,pend=p+other.len; p!=pend; p++) {
989       if ('\0'==(c=*p)) break;
990       rlen+=is_path(c)?1: c=='\n'?3:2;
991     }
992     if (preminus && rlen!=0 && other.beg[0]=='-') rlen+=2; /* ./ */
993     vi_grow2(0, rlen, 0, &dst);
994     if (preminus && other.beg[0]=='-') { *dst++='.'; *dst++='/'; }
995     for (p=other.beg,pend=p+other.len; p!=pend; p++) {
996       if ('\0'==(c=*p)) break;
997       if (is_path(c)) *dst++=c;
998       else if (c=='\n') { *dst++='"'; *dst++='\n'; *dst++='"'; }
999       else { *dst++='\\'; *dst++=c; }
1000     }
1001   } /* IF OS_COTY... */
1002   assert(dst==end_());
1003   return*this;
1004 }
1005 
appendDumpPS(const SimBuffer::Flat & other,bool dq)1006 SimBuffer::B& SimBuffer::B::appendDumpPS  (const SimBuffer::Flat &other, bool dq) {
1007   slen_t rlen=dq?2:0;
1008   register char c; register char const*p;
1009   char const *pend;
1010   for (p=other.beg,pend=p+other.len; p!=pend; p++) rlen+=is_safe_ps(*p)?1:4;
1011   char *dst; vi_grow2(0, rlen, 0, &dst);
1012   if (dq) *dst++='(';
1013   for (p=other.beg,pend=p+other.len; p!=pend; p++) {
1014     if (is_safe_ps(c=*p)) {
1015       *dst++=c;
1016     } else {
1017       *dst++='\\';
1018       *dst++=('0'+((c>>6)&3));
1019       *dst++=('0'+((c>>3)&7));
1020       *dst++=('0'+(c&7));
1021     }
1022   }
1023   if (dq) *dst++=')';
1024   assert(dst==end_());
1025   return*this;
1026 }
1027 
appendHppq(const SimBuffer::Flat & other)1028 SimBuffer::B& SimBuffer::B::appendHppq(const SimBuffer::Flat &other) {
1029   vi_grow2(0, other.len, 0, 0);
1030   char *pend=const_cast<char*>(beg)+len;
1031   register char c, *p=pend-other.len;
1032   memcpy(p, other.beg, other.len);
1033   for (;p!=pend;pend++) {
1034     c=*p;
1035     *p++=(
1036       (c>='a' && c<='z') ? (char)(c-'a'+'A') :
1037       (c>='A' && c<='Z') ? c :
1038                            '_'
1039     );
1040   }
1041   return *this;
1042 }
1043 
appendUnslash(const SimBuffer::Flat & other,int iniq)1044 SimBuffer::B& SimBuffer::B::appendUnslash(const SimBuffer::Flat &other, int iniq) {
1045   slen_t rlen=0;
1046   slen_t left=other.len;
1047   register char c; register char const*p=other.beg;
1048   if (iniq<=256) {
1049     if (left<2 || *p!=iniq || p[left-1]!=iniq) return*this;
1050     /* ^^^ return empty string */
1051     p++; left-=2;
1052   }
1053   while (0!=left) { /* Calculate lengths */
1054     c=*p++;
1055     if (c!='\\' || left==1) { rlen++; left--; continue; }
1056     c=*p++;
1057     if (c>='0' && c<='7') {
1058       rlen++;
1059       if (left>=3 && p[0]>='0' && p[0]<='7') {
1060         if (left>=4 && p[1]>='0' && p[1]<='7') { p+=2; left-=4; }
1061                                           else { p+=1; left-=3; }
1062       } else left-=2;
1063     } else if ((c=='x' || c=='X') && left>=3 && 16!=(hexc2n(p[0]))) {
1064       rlen++;
1065       if (left>=4 && 16!=(hexc2n(p[1]))) { p+=2; left-=4; }
1066                                     else { p+=1; left-=2; }
1067     } else if ((c=='c' || c=='C') && left>=4 && (p[0]=='-' || p[0]=='[')) {
1068       rlen++; left-=4; p+=2;
1069     } else if (c=='l' && left>=3) {
1070       rlen++; left-=3; p++;
1071     } else if (c=='u' && left>=3) {
1072       rlen++; left-=3; p++;
1073     } else if (c=='\n') {
1074       left-=2;
1075     } else { /* backslash is used for escaping a single char */
1076       rlen++; left-=2;
1077     }
1078   }
1079 
1080   char *dst; vi_grow2(0, rlen, 0, &dst);
1081   unsigned tmp1, tmp2;
1082   left=other.len; p=other.beg;
1083   if (iniq<=256) {
1084     assert(!(left<2 || *p!=iniq || p[left-1]!=iniq));
1085     p++; left-=2;
1086   }
1087   while (0!=left) {
1088     c=*p++;
1089     if (c!='\\' || left==1) { *dst++=(c); left--; continue; }
1090     c=*p++;
1091     if (c>='0' && c<='7') {
1092       if (left>=3 && p[0]>='0' && p[0]<='7') {
1093         if (left>=4 && p[1]>='0' && p[1]<='7') {
1094           *dst++=((char)((c<<6)+(p[0]<<3)+p[1]-'0'*73));
1095           p+=2; left-=4;
1096         } else {
1097           *dst++=((char)((c<<3)+p[0]-'0'*9));
1098           p+=1; left-=3;
1099         }
1100       } else {
1101         *dst++=((char)(c-'0'));
1102         left-=2;
1103       }
1104     } else if ((c=='x' || c=='X') && left>=3 && 16!=(tmp1=hexc2n(p[0]))) {
1105       if (left>=4 && 16!=(tmp2=hexc2n(p[1]))) {
1106         *dst++=((char)((tmp1<<4)+tmp2));
1107         p+=2; left-=4;
1108       } else {
1109         *dst++=((char)tmp1);
1110         p+=1; left-=2;
1111       }
1112     } else if ((c=='c' || c=='C') && left>=4 && (p[0]=='-' || p[0]=='[')) {
1113       *dst++=((char)(p[1]>='a' && p[1]<='z' ? (p[1]+'A'-'a')^64 : p[1]^64));
1114       left-=4; p+=2;
1115     } else if (c=='l' && left>=3) {
1116       *dst++=((char)(p[0]>='A' && p[0]<='Z' ? p[0]+'a'-'A' : p[0]));
1117       left-=3; p++;
1118     } else if (c=='u' && left>=3) {
1119       *dst++=((char)(p[0]>='a' && p[0]<='z' ? p[0]+'A'-'a' : p[0]));
1120       left-=3; p++;
1121     } else if (c=='\n') {
1122       left-=2;
1123     } else { /* backslash is used for escaping a single char */
1124            if (c=='a') c=007; // \x07 (alarm bell)
1125       else if (c=='b') c=010; // \x08 (backspace) (_not_ alarm bell)
1126       else if (c=='e') c=033; // \x1B (escape)
1127       else if (c=='f') c=014; // \x0C (form feed)
1128       else if (c=='n') c=012; // \x0A (newline, line feed)
1129       else if (c=='r') c=015; // \x0D (carriage return)
1130       else if (c=='t') c=011; // \x09 (horizontal tab)
1131       else if (c=='v') c=013; // \x0B (vertical tab)
1132       *dst++=(c); left-=2;
1133       // if (0!=left--) { *dst++=(*p++); left--; } /* already escaped 1 */
1134     }
1135   }
1136   return*this;
1137 }
1138 
space_pad_cpy(char * dst,char const * src,slen_t pad)1139 void SimBuffer::B::space_pad_cpy(char *dst, char const*src, slen_t pad) {
1140   while (pad!=0 && src[0]!='\0') { *dst++=*src++; pad--; }
1141   while (pad--!=0) *dst++=' ';
1142 }
1143 
1144 // #include <stdio.h>
1145 
substr_grow(slen_t first,slen_t oldmuch,slen_t newmuch)1146 char *SimBuffer::B::substr_grow(slen_t first, slen_t oldmuch, slen_t newmuch) {
1147   slen_t idx=first;
1148   if (first<len) {
1149     if (first+oldmuch>len) oldmuch=len-first;
1150     if (newmuch<oldmuch) { first+=newmuch; oldmuch-=newmuch; newmuch=0; }
1151     else if (newmuch>oldmuch) { first+=oldmuch; newmuch-=oldmuch; oldmuch=0; }
1152     else return const_cast<char*>(beg)+first;
1153   } else {
1154     len=first=idx=oldmuch=0;
1155     if (newmuch==0) { vi_grow2(0,0,0,0); return const_cast<char*>(beg); }
1156   }
1157   // fprintf(stderr, "newmuch=%u oldmuch=%u len=%u\n", newmuch, oldmuch, len);
1158   if (newmuch>0) {
1159     vi_grow2(0,newmuch,0,0);
1160     char *p=const_cast<char*>(beg)+first; /* after vi_grow2() */
1161     memmove(p+newmuch, p, len-first-newmuch);
1162   } else if (oldmuch>0) {
1163     char *p=const_cast<char*>(beg)+first; /* before vi_grow2() */
1164     memmove(p, p+oldmuch, len-first-oldmuch);
1165     vi_grow2(0,-(slendiff_t)oldmuch,0,0);
1166   } else assert(0);
1167   // fprintf(stderr, "len=%u oldmuch=%u\n", len, oldmuch);
1168   return const_cast<char*>(beg)+idx;
1169 }
1170 
1171 /* --- Tue Jul  2 10:47:14 CEST 2002 */
1172 
tolower_memcpy(char * dst,char const * s,slen_t slen)1173 void GenBuffer::tolower_memcpy(char *dst, char const*s, slen_t slen) {
1174   while (slen--!=0) *dst++=USGE('Z'-'A',*s-'A') ? *s+++'a'-'A' : *s++;
1175 }
toupper_memcpy(char * dst,char const * s,slen_t slen)1176 void GenBuffer::toupper_memcpy(char *dst, char const*s, slen_t slen) {
1177   while (slen--!=0) *dst++=USGE('z'-'a',*s-'a') ? *s+++'A'-'a' : *s++;
1178 }
1179 
nocase_memcmp(char const * a,char const * s,slen_t slen)1180 int GenBuffer::nocase_memcmp(char const*a, char const *s, slen_t slen) {
1181   int i;
1182   while (slen--!=0) {
1183     i=(USGE('Z'-'A',*a-'A') ? *a+++'a'-'A' : *a++)
1184      -(USGE('Z'-'A',*s-'A') ? *s+++'a'-'A' : *s++);
1185     if (i>0) return 1;
1186     if (i<0) return -1;
1187   }
1188   return 0;
1189 }
nocase_strcmp(char const * a,char const * b)1190 int GenBuffer::nocase_strcmp(char const*a, char const*b) {
1191   slen_t alen=strlen(a), blen=strlen(b), min=alen<blen?alen:blen;
1192   int ret=nocase_memcmp(a, b, min);
1193   return ret!=0 || alen==blen ? ret : alen<blen ? -1 : 1;
1194 }
1195 
parseBool(char const * s,slen_t slen)1196 bool GenBuffer::parseBool(char const *s, slen_t slen) {
1197   if (slen==0) return true;
1198   char c=s[0];
1199   if ((slen==2 && (c=='o' || c=='O') && (s[1]=='n' || s[1]=='N'))
1200    || (slen==3 && (c=='o' || c=='O') && (s[1]=='u' || s[1]=='U'))
1201      ) return true;
1202   /* on  true  yes ja   igen oui enable  1 true  vrai? right sure allowed
1203    * off false no  nein nem  non disable 0 false faux? wrong nope disallowed
1204    */
1205   return c!='f' && c!='n' && c!='d' && c!='w' && c!='0'
1206       && c!='F' && c!='N' && c!='D' && c!='W';
1207 }
1208 
strbegins(char const * a,char const * with)1209 bool GenBuffer::strbegins(char const*a, char const *with) {
1210   while (*with!='\0') if (*a++!=*with++) return false;
1211   return true;
1212 }
1213 
nocase_strbegins(char const * a,char const * with)1214 bool GenBuffer::nocase_strbegins(char const*a, char const *with) {
1215   while (*with!='\0')
1216     if ((USGE('Z'-'A',*a-'A') ? *a+++'a'-'A' : *a++)
1217       !=(USGE('Z'-'A',*with-'A') ? *with+++'a'-'A' : *with++)
1218        ) return false;
1219   return true;
1220 }
1221 
1222 /* __END__ */
1223