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

Generated on Thu Feb 26 13:40:07 2009 for 'LibPst' by  doxygen 1.3.9.1