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

Generated on Sat Feb 7 10:22:06 2009 for 'LibPst' by  doxygen 1.3.9.1