Main Page | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

vbuf.c

Go to the documentation of this file.
00001 
00002 #include "define.h"
00003 
00004 
00005 #define ASSERT(x,...) { if( !(x) ) DIE(( __VA_ARGS__)); }
00006 
00007 
00008 int skip_nl(char *s)
00009 {
00010     if (s[0] == '\n')
00011         return 1;
00012     if (s[0] == '\r' && s[1] == '\n')
00013         return 2;
00014     if (s[0] == '\0')
00015         return 0;
00016     return -1;
00017 }
00018 
00019 
00020 int find_nl(vstr * vs)
00021 {
00022     char *nextr, *nextn;
00023 
00024     nextr = memchr(vs->b, '\r', vs->dlen);
00025     nextn = memchr(vs->b, '\n', vs->dlen);
00026 
00027     //case 1: UNIX, we find \n first
00028     if (nextn && (!nextr || (nextr > nextn))) {
00029         return nextn - vs->b;
00030     }
00031     //case 2: DOS, we find \r\n
00032     if (nextr && nextn && (nextn-nextr == 1)) {
00033         return nextr - vs->b;
00034     }
00035     //case 3: we find nothing
00036 
00037     return -1;
00038 }
00039 
00040 
00041 //  UTF8 <-> UTF16 <-> ISO8859 Character set conversion functions and (ack) their globals
00042 
00043 static int unicode_up = 0;
00044 static iconv_t i16to8;
00045 static const char *target_charset = NULL;
00046 static int         target_open_from = 0;
00047 static int         target_open_to   = 0;
00048 static iconv_t     i8totarget = (iconv_t)-1;
00049 static iconv_t     target2i8  = (iconv_t)-1;
00050 
00051 
00052 void unicode_init()
00053 {
00054     if (unicode_up) unicode_close();
00055     i16to8 = iconv_open("utf-8", "utf-16le");
00056     if (i16to8 == (iconv_t)-1) {
00057         WARN(("Couldn't open iconv descriptor for utf-16le to utf-8.\n"));
00058         exit(1);
00059     }
00060     unicode_up = 1;
00061 }
00062 
00063 
00064 void unicode_close()
00065 {
00066     iconv_close(i16to8);
00067     if (target_open_from) iconv_close(i8totarget);
00068     if (target_open_to)   iconv_close(target2i8);
00069     if (target_charset)   free((char *)target_charset);
00070     target_charset   = NULL;
00071     target_open_from = 0;
00072     target_open_to   = 0;
00073     unicode_up = 0;
00074 }
00075 
00076 
00077 int utf16_is_terminated(const char *str, int length)
00078 {
00079     VSTR_STATIC(errbuf, 100);
00080     int len = -1;
00081     int i;
00082     for (i = 0; i < length; i += 2) {
00083         if (str[i] == 0 && str[i + 1] == 0) {
00084             len = i;
00085         }
00086     }
00087 
00088     if (-1 == len) {
00089         vshexdump(errbuf, str, 0, length, 1);
00090         DEBUG_WARN(("String is not zero terminated (probably broken data from registry) %s.\n", errbuf->b));
00091     }
00092 
00093     return (-1 == len) ? 0 : 1;
00094 }
00095 
00096 
00097 size_t vb_utf16to8(vbuf *dest, const char *inbuf, int iblen)
00098 {
00099     size_t inbytesleft  = iblen;
00100     size_t icresult     = (size_t)-1;
00101     size_t outbytesleft = 0;
00102     char *outbuf        = NULL;
00103     int   myerrno;
00104 
00105     ASSERT(unicode_up, "vb_utf16to8() called before unicode started.");
00106     vbresize(dest, iblen);
00107 
00108     //Bad Things can happen if a non-zero-terminated utf16 string comes through here
00109     if (!utf16_is_terminated(inbuf, iblen))
00110         return (size_t)-1;
00111 
00112     do {
00113         outbytesleft = dest->blen - dest->dlen;
00114         outbuf = dest->b + dest->dlen;
00115         icresult = iconv(i16to8, (ICONV_CONST char**)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
00116         myerrno  = errno;
00117         dest->dlen = outbuf - dest->b;
00118         if (inbytesleft) vbgrow(dest, inbytesleft);
00119     } while ((size_t)-1 == icresult && E2BIG == myerrno);
00120 
00121     if (icresult == (size_t)-1) {
00122         DEBUG_WARN(("iconv failure: %s\n", strerror(myerrno)));
00123         unicode_init();
00124         return (size_t)-1;
00125     }
00126     return (icresult) ? (size_t)-1 : 0;
00127 }
00128 
00129 
00130 static void open_targets(const char* charset);
00131 static void open_targets(const char* charset)
00132 {
00133     if (!target_charset || strcasecmp(target_charset, charset)) {
00134         if (target_open_from) iconv_close(i8totarget);
00135         if (target_open_to)   iconv_close(target2i8);
00136         if (target_charset)   free((char *)target_charset);
00137         target_charset   = strdup(charset);
00138         target_open_from = 1;
00139         target_open_to   = 1;
00140         i8totarget = iconv_open(target_charset, "utf-8");
00141         if (i8totarget == (iconv_t)-1) {
00142             target_open_from = 0;
00143             WARN(("Couldn't open iconv descriptor for utf-8 to %s.\n", target_charset));
00144         }
00145         target2i8 = iconv_open("utf-8", target_charset);
00146         if (target2i8 == (iconv_t)-1) {
00147             target_open_to = 0;
00148             WARN(("Couldn't open iconv descriptor for %s to utf-8.\n", target_charset));
00149         }
00150     }
00151 }
00152 
00153 
00154 static size_t sbcs_conversion(vbuf *dest, const char *inbuf, int iblen, iconv_t conversion);
00155 static size_t sbcs_conversion(vbuf *dest, const char *inbuf, int iblen, iconv_t conversion)
00156 {
00157     size_t inbytesleft  = iblen;
00158     size_t icresult     = (size_t)-1;
00159     size_t outbytesleft = 0;
00160     char *outbuf        = NULL;
00161     int   myerrno;
00162 
00163     vbresize(dest, 2*iblen);
00164 
00165     do {
00166         outbytesleft = dest->blen - dest->dlen;
00167         outbuf = dest->b + dest->dlen;
00168         icresult = iconv(conversion, (ICONV_CONST char**)&inbuf, &inbytesleft, &outbuf, &outbytesleft);
00169         myerrno  = errno;
00170         dest->dlen = outbuf - dest->b;
00171         if (inbytesleft) vbgrow(dest, 2*inbytesleft);
00172     } while ((size_t)-1 == icresult && E2BIG == myerrno);
00173 
00174     if (icresult == (size_t)-1) {
00175         DEBUG_WARN(("iconv failure: %s\n", strerror(myerrno)));
00176         unicode_init();
00177         return (size_t)-1;
00178     }
00179     return (icresult) ? (size_t)-1 : 0;
00180 }
00181 
00182 
00183 size_t vb_utf8to8bit(vbuf *dest, const char *inbuf, int iblen, const char* charset)
00184 {
00185     open_targets(charset);
00186     if (!target_open_from) return (size_t)-1;   // failure to open the target
00187     return sbcs_conversion(dest, inbuf, iblen, i8totarget);
00188 }
00189 
00190 
00191 size_t vb_8bit2utf8(vbuf *dest, const char *inbuf, int iblen, const char* charset)
00192 {
00193     open_targets(charset);
00194     if (!target_open_to) return (size_t)-1;     // failure to open the target
00195     return sbcs_conversion(dest, inbuf, iblen, target2i8);
00196 }
00197 
00198 
00199 vbuf *vballoc(size_t len)
00200 {
00201     struct varbuf *result = malloc(sizeof(struct varbuf));
00202     if (result) {
00203         result->dlen = 0;
00204         result->blen = 0;
00205         result->buf = NULL;
00206         vbresize(result, len);
00207     }
00208     else DIE(("malloc() failure"));
00209     return result;
00210 }
00211 
00212 
00213 void vbcheck(vbuf * vb)
00214 {
00215     ASSERT(vb->b >= vb->buf, "vbcheck(): data not inside buffer");
00216     ASSERT((size_t)(vb->b - vb->buf) <= vb->blen, "vbcheck(): vb->b outside of buffer range.");
00217     ASSERT(vb->dlen <= vb->blen, "vbcheck(): data length > buffer length.");
00218     ASSERT(vb->blen < 1024 * 1024, "vbcheck(): blen is a bit large...hmmm.");
00219 }
00220 
00221 
00222 void vbfree(vbuf * vb)
00223 {
00224     free(vb->buf);
00225     free(vb);
00226 }
00227 
00228 
00229 void vbclear(struct varbuf *vb) // ditch the data, keep the buffer
00230 {
00231     vbresize(vb, 0);
00232 }
00233 
00234 
00235 void vbresize(struct varbuf *vb, size_t len)    // DESTRUCTIVELY grow or shrink buffer
00236 {
00237     vb->dlen = 0;
00238 
00239     if (vb->blen >= len) {
00240         vb->b = vb->buf;
00241         return;
00242     }
00243 
00244     vb->buf  = realloc(vb->buf, len);
00245     vb->b    = vb->buf;
00246     vb->blen = len;
00247 }
00248 
00249 
00250 size_t vbavail(vbuf * vb)
00251 {
00252     return vb->blen  - vb->dlen - (size_t)(vb->b - vb->buf);
00253 }
00254 
00255 
00256 void vbgrow(struct varbuf *vb, size_t len)      // out: vbavail(vb) >= len, data are preserved
00257 {
00258     if (0 == len)
00259         return;
00260 
00261     if (0 == vb->blen) {
00262         vbresize(vb, len);
00263         return;
00264     }
00265 
00266     if (vb->dlen + len > vb->blen) {
00267         if (vb->dlen + len < vb->blen * 1.5)
00268             len = vb->blen * 1.5;
00269         char *nb = malloc(vb->blen + len);
00270         if (!nb) DIE(("malloc() failure"));
00271         vb->blen = vb->blen + len;
00272         memcpy(nb, vb->b, vb->dlen);
00273 
00274         free(vb->buf);
00275         vb->buf = nb;
00276         vb->b = vb->buf;
00277     } else {
00278         if (vb->b != vb->buf)
00279             memcpy(vb->buf, vb->b, vb->dlen);
00280     }
00281 
00282     vb->b = vb->buf;
00283 
00284     ASSERT(vbavail(vb) >= len, "vbgrow(): I have failed in my mission.");
00285 }
00286 
00287 
00288 void vbset(vbuf * vb, void *b, size_t len)      // set vbuf b size=len, resize if necessary, relen = how much to over-allocate
00289 {
00290     vbresize(vb, len);
00291     memcpy(vb->b, b, len);
00292     vb->dlen = len;
00293 }
00294 
00295 
00296 void vsskipws(vstr * vs)
00297 {
00298     char *p = vs->b;
00299     while ((size_t)(p - vs->b) < vs->dlen && isspace(p[0]))
00300         p++;
00301 
00302     vbskip((vbuf *) vs, p - vs->b);
00303 }
00304 
00305 
00306 // append len bytes of b to vbuf, resize if necessary
00307 void vbappend(struct varbuf *vb, void *b, size_t len)
00308 {
00309     if (0 == vb->dlen) {
00310         vbset(vb, b, len);
00311         return;
00312     }
00313     vbgrow(vb, len);
00314     memcpy(vb->b + vb->dlen, b, len);
00315     vb->dlen += len;
00316 }
00317 
00318 
00319 // dumps the first skip bytes from vbuf
00320 void vbskip(struct varbuf *vb, size_t skip)
00321 {
00322     ASSERT(skip <= vb->dlen, "vbskip(): Attempt to seek past end of buffer.");
00323     vb->b += skip;
00324     vb->dlen -= skip;
00325 }
00326 
00327 
00328 // overwrite vbdest with vbsrc
00329 void vboverwrite(struct varbuf *vbdest, struct varbuf *vbsrc)
00330 {
00331     vbresize(vbdest, vbsrc->blen);
00332     memcpy(vbdest->b, vbsrc->b, vbsrc->dlen);
00333     vbdest->blen = vbsrc->blen;
00334     vbdest->dlen = vbsrc->dlen;
00335 }
00336 
00337 
00338 vstr *vsalloc(size_t len)
00339 {
00340     vstr *result = (vstr *) vballoc(len + 1);
00341     vsset(result, "");
00342     return result;
00343 }
00344 
00345 
00346 char *vsstr(vstr * vs)
00347 {
00348     return vs->b;
00349 }
00350 
00351 
00352 size_t vslen(vstr * vs)
00353 {
00354     return strlen(vsstr(vs));
00355 }
00356 
00357 
00358 void vsfree(vstr * vs)
00359 {
00360     vbfree((vbuf *) vs);
00361 }
00362 
00363 
00364 void vscharcat(vstr * vb, int ch)
00365 {
00366     vbgrow((vbuf *) vb, 1);
00367     vb->b[vb->dlen - 1] = ch;
00368     vb->b[vb->dlen] = '\0';
00369     vb->dlen++;
00370 }
00371 
00372 
00373 // prependappend string str to vbuf, vbuf must already contain a valid string
00374 void vsnprepend(vstr * vb, char *str, size_t len)
00375 {
00376     ASSERT(vb->b[vb->dlen - 1] == '\0', "vsncat(): attempt to append string to non-string.");
00377     size_t sl = strlen(str);
00378     size_t n = (sl < len) ? sl : len;
00379     vbgrow((vbuf *) vb, n + 1);
00380     memmove(vb->b + n, vb->b, vb->dlen - 1);
00381     memcpy(vb->b, str, n);
00382     vb->dlen += n;
00383     vb->b[vb->dlen - 1] = '\0';
00384 }
00385 
00386 
00387 // len < dlen-1 -> skip len chars, else DIE
00388 void vsskip(vstr * vs, size_t len)
00389 {
00390     ASSERT(len < vs->dlen - 1, "Attempt to skip past end of string");
00391     vbskip((vbuf *) vs, len);
00392 }
00393 
00394 
00395 // in: vb->b == "stuff\nmore_stuff"; out: vb->b == "more_stuff"
00396 int vsskipline(vstr * vs)
00397 {
00398     int nloff = find_nl(vs);
00399     int nll   = skip_nl(vs->b + nloff);
00400 
00401     if (nloff < 0) {
00402         //TODO: error
00403         printf("vb_skipline(): there seems to be no newline here.\n");
00404         return -1;
00405     }
00406     if (nll < 0) {
00407         //TODO: error
00408         printf("vb_skipline(): there seems to be no newline here...except there should be. :P\n");
00409         return -1;
00410     }
00411 
00412     memmove(vs->b, vs->b + nloff + nll, vs->dlen - nloff - nll);
00413 
00414     vs->dlen -= nloff + nll;
00415 
00416     return 0;
00417 }
00418 
00419 
00420 int vscatprintf(vstr * vs, char *fmt, ...)
00421 {
00422     int size;
00423     va_list ap;
00424 
00425     /* Guess we need no more than 100 bytes. */
00426     //vsresize( vb, 100 );
00427     if (!vs->b || vs->dlen == 0) {
00428         vsset(vs, "");
00429     }
00430 
00431     while (1) {
00432         /* Try to print in the allocated space. */
00433         va_start(ap, fmt);
00434         size = vsnprintf(vs->b + vs->dlen - 1, vs->blen - vs->dlen, fmt, ap);
00435         va_end(ap);
00436 
00437         /* If that worked, return the string. */
00438         if ((size > -1) && ((size_t)size < vs->blen - vs->dlen)) {
00439             vs->dlen += size;
00440             return size;
00441         }
00442         /* Else try again with more space. */
00443         if (size >= 0)          /* glibc 2.1 */
00444             vbgrow((vbuf *) vs, size + 1);      /* precisely what is needed */
00445         else                    /* glibc 2.0 */
00446             vbgrow((vbuf *) vs, vs->blen);
00447     }
00448 }
00449 
00450 
00451 //  returns the last character stored in a vstr
00452 int vslast(vstr * vs)
00453 {
00454     if (vs->dlen < 1)
00455         return -1;
00456     if (vs->b[vs->dlen - 1] != '\0')
00457         return -1;
00458     if (vs->dlen == 1)
00459         return '\0';
00460     return vs->b[vs->dlen - 2];
00461 }
00462 
00463 
00464 //  print over vb
00465 void vs_printf(vstr * vs, char *fmt, ...)
00466 {
00467     int size;
00468     va_list ap;
00469 
00470     /* Guess we need no more than 100 bytes. */
00471     vbresize((vbuf *) vs, 100);
00472 
00473     while (1) {
00474         /* Try to print in the allocated space. */
00475         va_start(ap, fmt);
00476         size = vsnprintf(vs->b, vs->blen, fmt, ap);
00477         va_end(ap);
00478 
00479         /* If that worked, return the string. */
00480         if ((size > -1) && ((size_t)size < vs->blen)) {
00481             vs->dlen = size + 1;
00482             return;
00483         }
00484         /* Else try again with more space. */
00485         if (size >= 0)          /* glibc 2.1 */
00486             vbresize((vbuf *) vs, size + 1);    /* precisely what is needed */
00487         else                    /* glibc 2.0 */
00488             vbresize((vbuf *) vs, vs->blen * 2);
00489     }
00490 }
00491 
00492 
00493 // printf append to vs
00494 void vs_printfa(vstr * vs, char *fmt, ...)
00495 {
00496     int size;
00497     va_list ap;
00498 
00499     if (vs->blen - vs->dlen < 50)
00500         vbgrow((vbuf *) vs, 100);
00501 
00502     while (1) {
00503         /* Try to print in the allocated space. */
00504         va_start(ap, fmt);
00505         size = vsnprintf(vs->b + vs->dlen - 1, vs->blen - vs->dlen + 1, fmt, ap);
00506         va_end(ap);
00507 
00508         /* If that worked, return the string. */
00509         if ((size > -1) && ((size_t)size < vs->blen)) {
00510             vs->dlen += size;
00511             return;
00512         }
00513         /* Else try again with more space. */
00514         if (size >= 0)          /* glibc 2.1 */
00515             vbgrow((vbuf *) vs, size + 1 - vs->dlen);   /* precisely what is needed */
00516         else                    /* glibc 2.0 */
00517             vbgrow((vbuf *) vs, size);
00518     }
00519 }
00520 
00521 
00522 void vshexdump(vstr * vs, const char *b, size_t start, size_t stop, int ascii)
00523 {
00524     char c;
00525     int diff, i;
00526 
00527     while (start < stop) {
00528         diff = stop - start;
00529         if (diff > 16)
00530             diff = 16;
00531 
00532         vs_printfa(vs, ":%08X  ", start);
00533 
00534         for (i = 0; i < diff; i++) {
00535             if (8 == i)
00536                 vs_printfa(vs, " ");
00537             vs_printfa(vs, "%02X ", (unsigned char) *(b + start + i));
00538         }
00539         if (ascii) {
00540             for (i = diff; i < 16; i++)
00541                 vs_printfa(vs, "   ");
00542             for (i = 0; i < diff; i++) {
00543                 c = *(b + start + i);
00544                 vs_printfa(vs, "%c", isprint(c) ? c : '.');
00545             }
00546         }
00547         vs_printfa(vs, "\n");
00548         start += 16;
00549     }
00550 }
00551 
00552 
00553 void vsset(vstr * vs, char *s)  // Store string s in vs
00554 {
00555     vsnset(vs, s, strlen(s));
00556 }
00557 
00558 
00559 void vsnset(vstr * vs, char *s, size_t n)       // Store string s in vs
00560 {
00561     vbresize((vbuf *) vs, n + 1);
00562     memcpy(vs->b, s, n);
00563     vs->b[n] = '\0';
00564     vs->dlen = n + 1;
00565 }
00566 
00567 
00568 void vsgrow(vstr * vs, size_t len)      // grow buffer by len bytes, data are preserved
00569 {
00570     vbgrow((vbuf *) vs, len);
00571 }
00572 
00573 
00574 size_t vsavail(vstr * vs)
00575 {
00576     return vbavail((vbuf *) vs);
00577 }
00578 
00579 
00580 void vsnset16(vstr * vs, char *s, size_t len)   // Like vbstrnset, but for UTF16
00581 {
00582     vbresize((vbuf *) vs, len + 1);
00583     memcpy(vs->b, s, len);
00584 
00585     vs->b[len] = '\0';
00586     vs->dlen = len + 1;
00587     vs->b[len] = '\0';
00588 }
00589 
00590 
00591 void vscat(vstr * vs, char *str)
00592 {
00593     vsncat(vs, str, strlen(str));
00594 }
00595 
00596 
00597 int vscmp(vstr * vs, char *str)
00598 {
00599     return strcmp(vs->b, str);
00600 }
00601 
00602 
00603 void vsncat(vstr * vs, char *str, size_t len)   // append string str to vstr, vstr must already contain a valid string
00604 {
00605     ASSERT(vs->b[vs->dlen - 1] == '\0', "vsncat(): attempt to append string to non-string.");
00606     size_t sl = strlen(str);
00607     size_t n = (sl < len) ? sl : len;
00608     //string append
00609     vbgrow((vbuf *) vs, n + 1);
00610     memcpy(vs->b + vs->dlen - 1, str, n);
00611     vs->dlen += n;
00612     vs->b[vs->dlen - 1] = '\0';
00613 }
00614 
00615 
00616 void vstrunc(vstr * v, size_t off) // Drop chars [off..dlen]
00617 {
00618     if (off >= v->dlen - 1)
00619         return;                 //nothing to do
00620     v->b[off] = '\0';
00621     v->dlen = off + 1;
00622 }
00623 
00624 

Generated on Thu Mar 19 16:39:26 2009 for 'LibPst' by  doxygen 1.3.9.1