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

Generated on Tue Aug 5 12:06:14 2008 for 'LibPst' by  doxygen 1.3.9.1