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

octstr.c

Go to the documentation of this file.
00001 /* ====================================================================
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * octstr.c - implementation of Octet strings
00059  *
00060  * See octstr.h for explanations of what public functions should do.
00061  *
00062  * Lars Wirzenius
00063  */
00064 
00065 
00066 #include <ctype.h>
00067 #include <limits.h>
00068 #include <errno.h>
00069 #include <stdlib.h>
00070 #include <string.h>
00071 #include <unistd.h>
00072 #include <sys/types.h>
00073 #include <sys/socket.h>
00074 #include <netinet/in.h>
00075 
00076 #include "gwlib.h"
00077 
00078 /* 
00079  * Unfortunately some platforms base va_list an an array type
00080  * which makes passing of the &args a bit tricky 
00081  */
00082 #if (defined(__linux__) && (defined(__powerpc__) || defined(__s390__) || defined(__x86_64))) || \
00083     (defined(__FreeBSD__) && defined(__amd64__))
00084 #define VARGS(x)   (x)
00085 #define VALPARM(y) va_list y
00086 #define VALST(z)   (z)
00087 #else
00088 #define VARGS(x)   (&x)
00089 #define VALPARM(y) va_list *y
00090 #define VALST(z)   (*z)
00091 #endif
00092 
00093 
00094 /***********************************************************************
00095  * Definitions of data structures. These are not visible to the external
00096  * world -- they may be accessed only via the functions declared in
00097  * octstr.h. This ensures they really are abstract.
00098  */
00099 
00100 /*
00101  * The octet string.
00102  *
00103  * `data' is a pointer to dynamically allocated memory are where the 
00104  * octets in the string. It may be bigger than the actual length of the
00105  * string.
00106  *
00107  * `len' is the length of the string.
00108  *
00109  * `size' is the size of the memory area `data' points at.
00110  *
00111  * When `size' is greater than zero, it is at least `len+1', and the
00112  * character at `len' is '\0'. This is so that octstr_get_cstr will
00113  * always work.
00114  *
00115  * `immutable' defines whether the octet string is immutable or not.
00116  */
00117 struct Octstr
00118 {
00119     unsigned char *data;
00120     long len;
00121     long size;
00122     int immutable;
00123 };
00124 
00125 
00126 /**********************************************************************
00127  * Hash table of immutable octet strings.
00128  */
00129 
00130 #define MAX_IMMUTABLES 1024
00131 
00132 static Octstr *immutables[MAX_IMMUTABLES];
00133 static Mutex immutables_mutex;
00134 static int immutables_init = 0;
00135 
00136 static char is_safe[UCHAR_MAX + 1];
00137 
00138 /*
00139  * Convert a pointer to a C string literal to a long that can be used
00140  * for hashing. This is done by converting the pointer into an integer
00141  * and discarding the lowest to bits to get rid of typical alignment
00142  * bits.
00143  */
00144 #define CSTR_TO_LONG(ptr)   (((long) ptr) >> 2)
00145 
00146 
00147 /*
00148  * HEX to ASCII preprocessor macro
00149  */
00150 #define H2B(a) (a >= '0' && a <= '9' ? \
00151     a - '0' : (a >= 'a' && a <= 'f' ? \
00152         a - 'a' + 10 : (a >= 'A' && a <= 'F' ? a - 'A' + 10 : -1) \
00153         ) \
00154     )
00155 
00156 
00157 /***********************************************************************
00158  * Declarations of internal functions. These are defined at the end of
00159  * the file.
00160  */
00161 
00162 
00163 static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno,
00164                              const char *function);
00165 #ifdef NO_GWASSERT
00166 #define seems_valid(ostr)
00167 #else
00168 #define seems_valid(ostr) \
00169     (seems_valid_real(ostr, __FILE__, __LINE__, __func__))
00170 #endif
00171 
00172 
00173 /***********************************************************************
00174  * Implementations of the functions declared in octstr.h. See the
00175  * header for explanations of what they should do.
00176  */
00177 
00178 
00179 /* Reserve space for at least 'size' octets */
00180 static void octstr_grow(Octstr *ostr, long size)
00181 {
00182     gw_assert(!ostr->immutable);
00183     seems_valid(ostr);
00184     gw_assert(size >= 0);
00185 
00186     size++;   /* make room for the invisible terminating NUL */
00187 
00188     if (size > ostr->size) {
00189         /* always reallocate in 1kB chunks */
00190         size += 1024 - (size % 1024);
00191         ostr->data = gw_realloc(ostr->data, size);
00192         ostr->size = size;
00193     }
00194 }
00195 
00196 
00197 /*
00198  * Fill is_safe table. is_safe[c] means that c can be left as such when
00199  * url-encoded.
00200  * RFC 2396 defines the list of characters that need to be encoded.
00201  * Space is treated as an exception by the encoding routine;
00202  * it's listed as safe here, but is actually changed to '+'.
00203  */
00204 static void urlcode_init(void)
00205 {
00206     int i;
00207 
00208     unsigned char *safe = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00209     "abcdefghijklmnopqrstuvwxyz-_.!~*'()";
00210     for (i = 0; safe[i] != '\0'; ++i)
00211     is_safe[safe[i]] = 1;
00212 }
00213 
00214 
00215 void octstr_init(void)
00216 {
00217     urlcode_init();
00218     mutex_init_static(&immutables_mutex);
00219     immutables_init = 1;
00220 }
00221 
00222 
00223 void octstr_shutdown(void)
00224 {
00225     long i, n;
00226 
00227     n = 0;
00228     for (i = 0; i < MAX_IMMUTABLES; ++i) {
00229         if (immutables[i] != NULL) {
00230         gw_free(immutables[i]);
00231             ++n;
00232         }
00233     }
00234     if(n>0)
00235         debug("gwlib.octstr", 0, "Immutable octet strings: %ld.", n);
00236     mutex_destroy(&immutables_mutex);
00237 }
00238 
00239 
00240 Octstr *octstr_create_real(const char *cstr, const char *file, long line,
00241                            const char *func)
00242 {
00243     gw_assert(cstr != NULL);
00244     return octstr_create_from_data_trace(cstr, strlen(cstr), file, line, func);
00245 }
00246 
00247 Octstr *octstr_create_from_data_real(const char *data, long len, const char *file,
00248                                      long line, const char *func)
00249 {
00250     Octstr *ostr;
00251 
00252     gw_assert(len >= 0);
00253     if (data == NULL)
00254         gw_assert(len == 0);
00255 
00256     /* if gw_assert is disabled just return NULL
00257      * and caller will check for NULL or just crash.
00258      */
00259     if (len < 0 || (data == NULL && len != 0))
00260         return NULL;
00261 
00262     ostr = gw_malloc_trace(sizeof(*ostr), file, line, func);
00263     if (len == 0) {
00264         ostr->len = 0;
00265         ostr->size = 0;
00266         ostr->data = NULL;
00267     } else {
00268         ostr->len = len;
00269         ostr->size = len + 1;
00270         ostr->data = gw_malloc_trace(ostr->size, file, line, func);
00271         memcpy(ostr->data, data, len);
00272         ostr->data[len] = '\0';
00273     }
00274     ostr->immutable = 0;
00275     seems_valid(ostr);
00276     return ostr;
00277 }
00278 
00279 
00280 Octstr *octstr_imm(const char *cstr)
00281 {
00282     Octstr *os;
00283     long i, index;
00284     unsigned char *data;
00285 
00286     gw_assert(immutables_init);
00287     gw_assert(cstr != NULL);
00288 
00289     index = CSTR_TO_LONG(cstr) % MAX_IMMUTABLES;
00290     data = (unsigned char *) cstr;
00291 
00292     mutex_lock(&immutables_mutex);
00293     i = index;
00294     for (; ; ) {
00295     if (immutables[i] == NULL || immutables[i]->data == data)
00296             break;
00297         i = (i + 1) % MAX_IMMUTABLES;
00298         if (i == index)
00299             panic(0, "Too many immutable strings.");
00300     }
00301     os = immutables[i];
00302     if (os == NULL) {
00303     /*
00304      * Can't use octstr_create() because it copies the string,
00305      * which would break our hashing.
00306      */
00307     os = gw_malloc(sizeof(*os));
00308         os->data = data;
00309         os->len = strlen(data);
00310         os->size = os->len + 1;
00311         os->immutable = 1;
00312     immutables[i] = os;
00313     seems_valid(os);
00314     }
00315     mutex_unlock(&immutables_mutex);
00316 
00317     return os;
00318 }
00319 
00320 
00321 void octstr_destroy(Octstr *ostr)
00322 {
00323     if (ostr != NULL) {
00324         seems_valid(ostr);
00325     if (!ostr->immutable) {
00326             gw_free(ostr->data);
00327             gw_free(ostr);
00328         }
00329     }
00330 }
00331 
00332 
00333 void octstr_destroy_item(void *os)
00334 {
00335     octstr_destroy(os);
00336 }
00337 
00338 
00339 long octstr_len(const Octstr *ostr)
00340 {
00341     if (ostr == NULL)
00342         return 0;
00343     seems_valid(ostr);
00344     return ostr->len;
00345 }
00346 
00347 
00348 Octstr *octstr_copy_real(const Octstr *ostr, long from, long len, const char *file, long line,
00349                          const char *func)
00350 {
00351     seems_valid(ostr);
00352     gw_assert(from >= 0);
00353     gw_assert(len >= 0);
00354 
00355     if (from >= ostr->len)
00356         return octstr_create("");
00357 
00358     if (len > ostr->len - from)
00359         len = ostr->len - from;
00360 
00361     return octstr_create_from_data_trace(ostr->data + from, len, file,
00362                                          line, func);
00363 }
00364 
00365 
00366 
00367 Octstr *octstr_duplicate_real(const Octstr *ostr, const char *file, long line,
00368                               const char *func)
00369 {
00370     if (ostr == NULL)
00371         return NULL;
00372     seems_valid(ostr);
00373     return octstr_create_from_data_trace(ostr->data, ostr->len, file, line, func);
00374 }
00375 
00376 
00377 Octstr *octstr_cat(Octstr *ostr1, Octstr *ostr2)
00378 {
00379     Octstr *ostr;
00380 
00381     seems_valid(ostr1);
00382     seems_valid(ostr2);
00383     gw_assert(!ostr1->immutable);
00384 
00385     ostr = octstr_create("");
00386     ostr->len = ostr1->len + ostr2->len;
00387     ostr->size = ostr->len + 1;
00388     ostr->data = gw_malloc(ostr->size);
00389 
00390     if (ostr1->len > 0)
00391         memcpy(ostr->data, ostr1->data, ostr1->len);
00392     if (ostr2->len > 0)
00393         memcpy(ostr->data + ostr1->len, ostr2->data, ostr2->len);
00394     ostr->data[ostr->len] = '\0';
00395 
00396     seems_valid(ostr);
00397     return ostr;
00398 }
00399 
00400 
00401 int octstr_get_char(const Octstr *ostr, long pos)
00402 {
00403     seems_valid(ostr);
00404     if (pos >= ostr->len || pos < 0)
00405         return -1;
00406     return ostr->data[pos];
00407 }
00408 
00409 
00410 void octstr_set_char(Octstr *ostr, long pos, int ch)
00411 {
00412     seems_valid(ostr);
00413     gw_assert(!ostr->immutable);
00414     if (pos < ostr->len)
00415         ostr->data[pos] = ch;
00416     seems_valid(ostr);
00417 }
00418 
00419 
00420 void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
00421 {
00422     gw_assert(buf != NULL);
00423     seems_valid(ostr);
00424 
00425     if (pos >= ostr->len)
00426         return;
00427     if (pos + len > ostr->len)
00428         len = ostr->len - pos;
00429     if (len > 0)
00430         memcpy(buf, ostr->data + pos, len);
00431 }
00432 
00433 
00434 char *octstr_get_cstr_real(const Octstr *ostr, const char *file, long line, 
00435                            const char *func)
00436 {
00437     if (!ostr)
00438         return "(null)";
00439     seems_valid_real(ostr, file, line, func);
00440     if (ostr->len == 0)
00441         return "";
00442     return ostr->data;
00443 }
00444 
00445 
00446 void octstr_append_from_hex(Octstr *ostr, char *hex)
00447 {
00448     Octstr *output;
00449     
00450     seems_valid(ostr);
00451     gw_assert(!ostr->immutable);
00452     
00453     output = octstr_create(hex);
00454     octstr_hex_to_binary(output);
00455     octstr_append(ostr, output);
00456     octstr_destroy(output);
00457 }
00458 
00459 
00460 void octstr_binary_to_hex(Octstr *ostr, int uppercase)
00461 {
00462     unsigned char *hexits;
00463     long i, tmp;
00464 
00465     seems_valid(ostr);
00466     gw_assert(!ostr->immutable);
00467     if (ostr->len == 0)
00468         return;
00469 
00470     hexits = uppercase ? "0123456789ABCDEF" : "0123456789abcdef";
00471     octstr_grow(ostr, ostr->len * 2);
00472 
00473     /* In-place modification must be done back-to-front to avoid
00474      * overwriting the data while we read it.  Even the order of
00475      * the two assignments is important, to get i == 0 right. */
00476     for (i = ostr->len - 1; i >= 0; i--) {
00477         tmp = i << 1; /* tmp = i * 2; */
00478         ostr->data[tmp + 1] = hexits[ostr->data[i] & 0xf];
00479         ostr->data[tmp] = hexits[ostr->data[i] >> 4];
00480     }
00481 
00482     ostr->len = ostr->len * 2;
00483     ostr->data[ostr->len] = '\0';
00484 
00485     seems_valid(ostr);
00486 }
00487 
00488 
00489 int octstr_hex_to_binary(Octstr *ostr)
00490 {
00491     long len, i;
00492     unsigned char *p;
00493 
00494     seems_valid(ostr);
00495     gw_assert(!ostr->immutable);
00496 
00497     if (ostr->len == 0)
00498         return 0;
00499 
00500     /* Check if it's in the right format */
00501     if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit))
00502         return -1;
00503 
00504     len = ostr->len;
00505 
00506     /* Convert ascii data to binary values */
00507     for (i = 0, p = ostr->data; i < len; i++, p++) {
00508         if (*p >= '0' && *p <= '9')
00509             *p -= '0';
00510         else if (*p >= 'a' && *p <= 'f')
00511             *p = *p - 'a' + 10;
00512         else if (*p >= 'A' && *p <= 'F')
00513             *p = *p - 'A' + 10;
00514         else {
00515             /* isxdigit checked the whole string, so we should
00516              * not be able to get here. */
00517             gw_assert(0);
00518             *p = 0;
00519         }
00520     }
00521 
00522     /* De-hexing will compress data by factor of 2 */
00523     len = ostr->len / 2;
00524 
00525     for (i = 0; i < len; i++) {
00526         ostr->data[i] = ostr->data[i * 2] * 16 | ostr->data[i * 2 + 1];
00527     }
00528 
00529     ostr->len = len;
00530     ostr->data[len] = '\0';
00531 
00532     seems_valid(ostr);
00533     return 0;
00534 }
00535 
00536 
00537 void octstr_binary_to_base64(Octstr *ostr)
00538 {
00539     static const unsigned char base64[64] =
00540         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00541     long triplets;
00542     long lines;
00543     long orig_len;
00544     unsigned char *data;
00545     long from, to;
00546     int left_on_line;
00547 
00548     seems_valid(ostr);
00549     gw_assert(!ostr->immutable);
00550 
00551     if (ostr->len == 0) {
00552         /* Always terminate with CR LF */
00553         octstr_insert(ostr, octstr_imm("\015\012"), 0);
00554         return;
00555     }
00556 
00557     /* The lines must be 76 characters each (or less), and each
00558      * triplet will expand to 4 characters, so we can fit 19
00559      * triplets on one line.  We need a CR LF after each line,
00560      * which will add 2 octets per 19 triplets (rounded up). */
00561     triplets = (ostr->len + 2) / 3;   /* round up */
00562     lines = (triplets + 18) / 19;
00563 
00564     octstr_grow(ostr, triplets * 4 + lines * 2);
00565     orig_len = ostr->len;
00566     data = ostr->data;
00567 
00568     ostr->len = triplets * 4 + lines * 2;
00569     data[ostr->len] = '\0';
00570 
00571     /* This function works back-to-front, so that encoded data will
00572      * not overwrite source data.
00573      * from points to the start of the last triplet (which may be
00574      * an odd-sized one), and to points to the start of where the
00575      * last quad should go.  */
00576     from = (triplets - 1) * 3;
00577     to = (triplets - 1) * 4 + (lines - 1) * 2;
00578 
00579     /* First write the CR LF after the last quad */
00580     data[to + 5] = 10;   /* LF */
00581     data[to + 4] = 13;   /* CR */
00582     left_on_line = triplets - ((lines - 1) * 19);
00583 
00584     /* base64 encoding is in 3-octet units.  To handle leftover
00585      * octets, conceptually we have to zero-pad up to the next
00586      * 6-bit unit, and pad with '=' characters for missing 6-bit
00587      * units.
00588      * We do it by first completing the first triplet with 
00589      * zero-octets, and after the loop replacing some of the
00590      * result characters with '=' characters.
00591      * There is enough room for this, because even with a 1 or 2
00592      * octet source string, space for four octets of output
00593      * will be reserved.
00594      */
00595     switch (orig_len % 3) {
00596     case 0:
00597         break;
00598     case 1:
00599         data[orig_len] = 0;
00600         data[orig_len + 1] = 0;
00601         break;
00602     case 2:
00603         data[orig_len + 1] = 0;
00604         break;
00605     }
00606 
00607     /* Now we only have perfect triplets. */
00608     while (from >= 0) {
00609         long whole_triplet;
00610 
00611         /* Add a newline, if necessary */
00612         if (left_on_line == 0) {
00613             to -= 2;
00614             data[to + 5] = 10;  /* LF */
00615             data[to + 4] = 13;  /* CR */
00616             left_on_line = 19;
00617         }
00618 
00619         whole_triplet = (data[from] << 16) |
00620                         (data[from + 1] << 8) |
00621                         data[from + 2];
00622         data[to + 3] = base64[whole_triplet % 64];
00623         data[to + 2] = base64[(whole_triplet >> 6) % 64];
00624         data[to + 1] = base64[(whole_triplet >> 12) % 64];
00625         data[to] = base64[(whole_triplet >> 18) % 64];
00626 
00627         to -= 4;
00628         from -= 3;
00629         left_on_line--;
00630     }
00631 
00632     gw_assert(left_on_line == 0);
00633     gw_assert(from == -3);
00634     gw_assert(to == -4);
00635 
00636     /* Insert padding characters in the last quad.  Remember that
00637      * there is a CR LF between the last quad and the end of the
00638      * string. */
00639     switch (orig_len % 3) {
00640     case 0:
00641         break;
00642     case 1:
00643         gw_assert(data[ostr->len - 3] == 'A');
00644         gw_assert(data[ostr->len - 4] == 'A');
00645         data[ostr->len - 3] = '=';
00646         data[ostr->len - 4] = '=';
00647         break;
00648     case 2:
00649         gw_assert(data[ostr->len - 3] == 'A');
00650         data[ostr->len - 3] = '=';
00651         break;
00652     }
00653 
00654     seems_valid(ostr);
00655 }
00656 
00657 
00658 void octstr_base64_to_binary(Octstr *ostr)
00659 {
00660     long triplet;
00661     long pos, len;
00662     long to;
00663     int quadpos = 0;
00664     int warned = 0;
00665     unsigned char *data;
00666 
00667     seems_valid(ostr);
00668     gw_assert(!ostr->immutable);
00669 
00670     len = ostr->len;
00671     data = ostr->data;
00672 
00673     if (len == 0)
00674         return;
00675 
00676     to = 0;
00677     triplet = 0;
00678     quadpos = 0;
00679     for (pos = 0; pos < len; pos++) {
00680         int c = data[pos];
00681         int sixbits;
00682 
00683         if (c >= 'A' && c <= 'Z') {
00684             sixbits = c - 'A';
00685         } else if (c >= 'a' && c <= 'z') {
00686             sixbits = 26 + c - 'a';
00687         } else if (c >= '0' && c <= '9') {
00688             sixbits = 52 + c - '0';
00689         } else if (c == '+') {
00690             sixbits = 62;
00691         } else if (c == '/') {
00692             sixbits = 63;
00693         } else if (c == '=') {
00694             /* These can only occur at the end of encoded
00695              * text.  RFC 2045 says we can assume it really
00696              * is the end. */
00697             break;
00698         } else if (isspace(c)) {
00699             /* skip whitespace */
00700             continue;
00701         } else {
00702             if (!warned) {
00703                 warning(0, "Unusual characters in base64 "
00704                         "encoded text.");
00705                 warned = 1;
00706             }
00707             continue;
00708         }
00709 
00710         triplet = (triplet << 6) | sixbits;
00711         quadpos++;
00712 
00713         if (quadpos == 4) {
00714             data[to++] = (triplet >> 16) & 0xff;
00715             data[to++] = (triplet >> 8) & 0xff;
00716             data[to++] = triplet & 0xff;
00717             quadpos = 0;
00718         }
00719     }
00720 
00721     /* Deal with leftover octets */
00722     switch (quadpos) {
00723     case 0:
00724         break;
00725     case 3:  /* triplet has 18 bits, we want the first 16 */
00726         data[to++] = (triplet >> 10) & 0xff;
00727         data[to++] = (triplet >> 2) & 0xff;
00728         break;
00729     case 2:  /* triplet has 12 bits, we want the first 8 */
00730         data[to++] = (triplet >> 4) & 0xff;
00731         break;
00732     case 1:
00733         warning(0, "Bad padding in base64 encoded text.");
00734         break;
00735     }
00736 
00737     ostr->len = to;
00738     data[to] = '\0';
00739 
00740     seems_valid(ostr);
00741 }
00742 
00743 
00744 long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
00745 {
00746     /* strtol wants a char *, and we have to compare the result to
00747      * an unsigned char *.  The easiest way to avoid warnings without
00748      * introducing typecasts is to use two variables. */
00749     char *endptr;
00750     unsigned char *endpos;
00751     long number;
00752 
00753     seems_valid(ostr);
00754     gw_assert(nump != NULL);
00755     gw_assert(base == 0 || (base >= 2 && base <= 36));
00756 
00757     if (pos >= ostr->len) {
00758         errno = EINVAL;
00759         return -1;
00760     }
00761 
00762     errno = 0;
00763     number = strtol(ostr->data + pos, &endptr, base);
00764     endpos = endptr;
00765     if (errno == ERANGE)
00766         return -1;
00767     if (endpos == ostr->data + pos) {
00768         errno = EINVAL;
00769         return -1;
00770     }
00771 
00772     *nump = number;
00773     return endpos - ostr->data;
00774 }
00775 
00776 
00777 long octstr_parse_double(double *nump, Octstr *ostr, long pos)
00778 {
00779     /* strtod wants a char *, and we have to compare the result to
00780      * an unsigned char *.  The easiest way to avoid warnings without
00781      * introducing typecasts is to use two variables. */
00782     char *endptr;
00783     unsigned char *endpos;
00784     double number;
00785 
00786     seems_valid(ostr);
00787     gw_assert(nump != NULL);
00788 
00789     if (pos >= ostr->len) {
00790         errno = EINVAL;
00791         return -1;
00792     }
00793 
00794     errno = 0;
00795     number = strtod(ostr->data + pos, &endptr);
00796     endpos = endptr;
00797     if (errno == ERANGE)
00798         return -1;
00799     if (endpos == ostr->data + pos) {
00800         errno = EINVAL;
00801         return -1;
00802     }
00803 
00804     *nump = number;
00805     return endpos - ostr->data;
00806 }
00807 
00808 
00809 int octstr_check_range(Octstr *ostr, long pos, long len,
00810                        octstr_func_t filter)
00811 {
00812     long end = pos + len;
00813 
00814     seems_valid(ostr);
00815     gw_assert(len >= 0);
00816 
00817     if (pos >= ostr->len)
00818         return 1;
00819     if (end > ostr->len)
00820         end = ostr->len;
00821 
00822     for ( ; pos < end; pos++) {
00823         if (!filter(ostr->data[pos]))
00824             return 0;
00825     }
00826 
00827     return 1;
00828 }
00829 
00830 
00831 void octstr_convert_range(Octstr *ostr, long pos, long len,
00832                           octstr_func_t map)
00833 {
00834     long end = pos + len;
00835 
00836     seems_valid(ostr);
00837     gw_assert(!ostr->immutable);
00838     gw_assert(len >= 0);
00839 
00840     if (pos >= ostr->len)
00841         return;
00842     if (end > ostr->len)
00843         end = ostr->len;
00844 
00845     for ( ; pos < end; pos++) {
00846         ostr->data[pos] = map(ostr->data[pos]);
00847     }
00848 
00849     seems_valid(ostr);
00850 }
00851 
00852 
00853 static int inline make_printable(int c)
00854 {
00855     return isprint(c) ? c : '.';    
00856 }
00857 
00858 
00859 void octstr_convert_printable(Octstr *ostr)
00860 {
00861     octstr_convert_range(ostr, 0, ostr->len, make_printable);
00862 }
00863 
00864 
00865 
00866 int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
00867 {
00868     int ret;
00869     long len;
00870 
00871     seems_valid(ostr1);
00872     seems_valid(ostr2);
00873 
00874     if (ostr1->len < ostr2->len)
00875         len = ostr1->len;
00876     else
00877         len = ostr2->len;
00878 
00879     if (len == 0) {
00880     if (ostr1->len == 0 && ostr2->len > 0)
00881         return -1;
00882     if (ostr1->len > 0 && ostr2->len == 0)
00883         return 1;
00884         return 0;
00885     }
00886 
00887     ret = memcmp(ostr1->data, ostr2->data, len);
00888     if (ret == 0) {
00889         if (ostr1->len < ostr2->len)
00890             ret = -1;
00891         else if (ostr1->len > ostr2->len)
00892             ret = 1;
00893     }
00894     return ret;
00895 }
00896 
00897 
00898 int octstr_case_compare(const Octstr *os1, const Octstr *os2)
00899 {
00900     int c1, c2;
00901     long i, len;
00902 
00903     seems_valid(os1);
00904     seems_valid(os2);
00905 
00906     if (os1->len < os2->len)
00907         len = os1->len;
00908     else
00909         len = os2->len;
00910 
00911     if (len == 0) {
00912         if (os1->len == 0 && os2->len > 0)
00913             return -1;
00914         if (os1->len > 0 && os2->len == 0)
00915             return 1;
00916         return 0;
00917     }
00918 
00919     c1 = c2 = 0;
00920     for (i = 0; i < len; ++i) {
00921         c1 = toupper(os1->data[i]);
00922         c2 = toupper(os2->data[i]);
00923         if (c1 != c2)
00924             break;
00925     }
00926 
00927     if (i == len) {
00928         if (i == os1->len && i == os2->len)
00929             return 0;
00930         if (i == os1->len)
00931             return -1;
00932         return 1;
00933     } else {
00934         /*
00935         c1 = toupper(os1->data[i]);
00936         c2 = toupper(os2->data[i]);
00937         */
00938         if (c1 < c2)
00939             return -1;
00940         if (c1 == c2)
00941             return 0;
00942         return 1;
00943     }
00944 }
00945 
00946 
00947 int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
00948 {
00949     long len;
00950 
00951     seems_valid(ostr1);
00952     seems_valid(ostr2);
00953 
00954     if ((ostr1->len < ostr2->len) && (ostr1->len < n))
00955         len = ostr1->len;
00956     else if ((ostr2->len < ostr1->len) && (ostr2->len < n))
00957         len = ostr2->len;
00958     else
00959         len = n;
00960 
00961     if (len == 0)
00962         return 0;
00963 
00964     return memcmp(ostr1->data, ostr2->data, len);
00965 }
00966 
00967 
00968 int octstr_str_compare(const Octstr *ostr, const char *str)
00969 {
00970     seems_valid(ostr);
00971 
00972     if (str == NULL)
00973         return -1;
00974     if (ostr->data == NULL)
00975     return strcmp("", str);
00976 
00977     return strcmp(ostr->data, str);
00978 }
00979 
00980 
00981 int octstr_str_case_compare(const Octstr *ostr, const char *str)
00982 {
00983     seems_valid(ostr);
00984 
00985     if (str == NULL)
00986         return -1;
00987     if (ostr->data == NULL)
00988        return strcasecmp("", str);
00989 
00990     return strcasecmp(ostr->data, str);
00991 }
00992 
00993 
00994 int octstr_str_ncompare(const Octstr *ostr, const char *str, long n)
00995 {
00996     seems_valid(ostr);
00997 
00998     if (str == NULL)
00999         return -1;
01000     if (ostr->data == NULL)
01001         return 1; /* str grater */
01002 
01003     return strncmp(ostr->data, str, n);
01004 }
01005 
01006 
01007 int octstr_search_char(const Octstr *ostr, int ch, long pos)
01008 {
01009     unsigned char *p;
01010 
01011     seems_valid(ostr);
01012     gw_assert(ch >= 0);
01013     gw_assert(ch <= UCHAR_MAX);
01014     gw_assert(pos >= 0);
01015 
01016     if (pos >= ostr->len)
01017         return -1;
01018 
01019     p = memchr(ostr->data + pos, ch, ostr->len - pos);
01020     if (!p)
01021         return -1;
01022     return p - ostr->data;
01023 }
01024 
01025 
01026 int octstr_search_chars(const Octstr *ostr, const Octstr *chars, long pos)
01027 {
01028     long i, j;
01029 
01030     seems_valid(ostr);
01031     seems_valid(chars);
01032     gw_assert(pos >= 0);
01033 
01034     for (i = 0; i < octstr_len(chars); i++) {
01035     j = octstr_search_char(ostr, octstr_get_char(chars, i), pos);
01036     if (j != -1)
01037         return j;
01038     }
01039 
01040     return -1;
01041 }
01042 
01043 
01044 int octstr_search(const Octstr *haystack, const Octstr *needle, long pos)
01045 {
01046     int first;
01047 
01048     seems_valid(haystack);
01049     seems_valid(needle);
01050     gw_assert(pos >= 0);
01051 
01052     /* Always "find" an empty string */
01053     if (needle->len == 0)
01054         return 0;
01055 
01056     if (needle->len == 1)
01057         return octstr_search_char(haystack, needle->data[0], pos);
01058 
01059     /* For each occurrence of needle's first character in ostr,
01060      * check if the rest of needle follows.  Stop if there are no
01061      * more occurrences, or if the rest of needle can't possibly
01062      * fit in the haystack. */
01063     first = needle->data[0];
01064     pos = octstr_search_char(haystack, first, pos);
01065     while (pos >= 0 && haystack->len - pos >= needle->len) {
01066         if (memcmp(haystack->data + pos,
01067                    needle->data, needle->len) == 0)
01068             return pos;
01069         pos = octstr_search_char(haystack, first, pos + 1);
01070     }
01071 
01072     return -1;
01073 }
01074 
01075 
01076 int octstr_case_search(const Octstr *haystack, const Octstr *needle, long pos)
01077 {
01078     long i, j;
01079     int c1, c2;
01080 
01081     seems_valid(haystack);
01082     seems_valid(needle);
01083     gw_assert(pos >= 0);
01084 
01085     /* Always "find" an empty string */
01086     if (needle->len == 0)
01087         return 0;
01088 
01089     for (i = pos; i <= haystack->len - needle->len; ++i) {
01090     for (j = 0; j < needle->len; ++j) {
01091         c1 = toupper(haystack->data[i + j]);
01092         c2 = toupper(needle->data[j]);
01093         if (c1 != c2)
01094             break;
01095     }
01096     if (j == needle->len)
01097         return i;
01098     }
01099 
01100     return -1;    
01101 }
01102 
01103 int octstr_case_nsearch(const Octstr *haystack, const Octstr *needle, long pos, long n)
01104 {
01105     long i, j;
01106     int c1, c2;
01107 
01108     seems_valid(haystack);
01109     seems_valid(needle);
01110     gw_assert(pos >= 0);
01111 
01112     /* Always "find" an empty string */
01113     if (needle->len == 0)
01114         return 0;
01115 
01116     for (i = pos; i <= haystack->len - needle->len && i < n; ++i) {
01117         for (j = 0; j < needle->len && j < n; ++j) {
01118             c1 = toupper(haystack->data[i + j]);
01119             c2 = toupper(needle->data[j]);
01120             if (c1 != c2)
01121                 break;
01122         }
01123         if (j == needle->len)
01124             return i;
01125     }
01126 
01127     return -1;
01128 }
01129 
01130 
01131 int octstr_print(FILE *f, Octstr *ostr)
01132 {
01133     gw_assert(f != NULL);
01134     seems_valid(ostr);
01135 
01136     if (ostr->len == 0)
01137         return 0;
01138     if (fwrite(ostr->data, ostr->len, 1, f) != 1) {
01139         error(errno, "Couldn't write all of octet string to file.");
01140         return -1;
01141     }
01142     return 0;
01143 }
01144 
01145 
01146 int octstr_pretty_print(FILE *f, Octstr *ostr)
01147 {
01148     unsigned char *p;
01149     long i;
01150 
01151     gw_assert(f != NULL);
01152     seems_valid(ostr);
01153 
01154     p = ostr->data;
01155     for (i = 0; i < ostr->len; ++i, ++p) {
01156         if (isprint(*p))
01157             fprintf(f, "%c", *p);
01158         else
01159             fprintf(f, "\\x%02x", *p);
01160     }
01161     if (ferror(f))
01162         return -1;
01163     return 0;
01164 }
01165 
01166 
01167 int octstr_write_to_socket(int socket, Octstr *ostr)
01168 {
01169     long len;
01170     unsigned char *data;
01171     int ret;
01172 
01173     gw_assert(socket >= 0);
01174     seems_valid(ostr);
01175 
01176     data = ostr->data;
01177     len = ostr->len;
01178     while (len > 0) {
01179         ret = write(socket, data, len);
01180         if (ret == -1) {
01181             if (errno != EINTR) {
01182                 error(errno, "Writing to socket failed");
01183                 return -1;
01184             }
01185         } else {
01186             /* ret may be less than len */
01187             len -= ret;
01188             data += ret;
01189         }
01190     }
01191     return 0;
01192 }
01193 
01194 
01195 long octstr_write_data(Octstr *ostr, int fd, long from)
01196 {
01197     long ret;
01198 
01199     gw_assert(fd >= 0);
01200     gw_assert(from >= 0);
01201     seems_valid(ostr);
01202 
01203     if (from >= ostr->len)
01204         return 0;
01205 
01206     ret = write(fd, ostr->data + from, ostr->len - from);
01207 
01208     if (ret < 0) {
01209         if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
01210             return 0;
01211         error(errno, "Error writing %ld octets to fd %d:",
01212               ostr->len - from, fd);
01213         return -1;
01214     }
01215 
01216     return ret;
01217 }
01218 
01219 
01220 int octstr_append_from_socket(Octstr *ostr, int socket)
01221 {
01222     unsigned char buf[4096];
01223     int len;
01224 
01225     seems_valid(ostr);
01226     gw_assert(!ostr->immutable);
01227 
01228 again:
01229     len = recv(socket, buf, sizeof(buf), 0);
01230     if (len < 0 && errno == EINTR)
01231         goto again;
01232 
01233     if (len < 0) {
01234         error(errno, "Could not read from socket %d", socket);
01235         return -1;
01236     }
01237 
01238     octstr_append_data(ostr, buf, len);
01239     return len;
01240 }
01241 
01242 
01243 void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
01244 {
01245     if (ostr2 == NULL)
01246         return;
01247 
01248     seems_valid(ostr1);
01249     seems_valid(ostr2);
01250     gw_assert(pos <= ostr1->len);
01251     gw_assert(!ostr1->immutable);
01252 
01253     if (ostr2->len == 0)
01254         return;
01255 
01256     octstr_grow(ostr1, ostr1->len + ostr2->len);
01257     memmove(ostr1->data + pos + ostr2->len, ostr1->data + pos,
01258             ostr1->len - pos);
01259     memcpy(ostr1->data + pos, ostr2->data, ostr2->len);
01260     ostr1->len += ostr2->len;
01261     ostr1->data[ostr1->len] = '\0';
01262 
01263     seems_valid(ostr1);
01264 }
01265 
01266 
01267 void octstr_truncate(Octstr *ostr, int new_len)
01268 {
01269     if (ostr == NULL)
01270         return;
01271         
01272     seems_valid(ostr);
01273     gw_assert(!ostr->immutable);
01274     gw_assert(new_len >= 0);
01275 
01276     if (new_len >= ostr->len)
01277         return;
01278 
01279     ostr->len = new_len;
01280     ostr->data[new_len] = '\0';
01281 
01282     seems_valid(ostr);
01283 }
01284 
01285 
01286 void octstr_strip_blanks(Octstr *text)
01287 {
01288     int start = 0, end, len = 0;
01289 
01290     seems_valid(text);
01291     gw_assert(!text->immutable);
01292 
01293     /* Remove white space from the beginning of the text */
01294     while (isspace(octstr_get_char(text, start)) && 
01295        start <= octstr_len(text))
01296         start ++;
01297 
01298     if (start > 0)
01299         octstr_delete(text, 0, start);
01300 
01301     /* and from the end. */
01302 
01303     if ((len = octstr_len(text)) > 0) {
01304         end = len = len - 1;
01305         while (isspace(octstr_get_char(text, end)) && end >= 0)
01306             end--;
01307         octstr_delete(text, end + 1, len - end);
01308     }
01309 
01310     seems_valid(text);
01311 }
01312 
01313 static int iscrlf(unsigned char c)
01314 {
01315     return c == '\n' || c == '\r';
01316 }
01317 
01318 void octstr_strip_crlfs(Octstr *text)
01319 {
01320     int start = 0, end, len = 0;
01321 
01322     seems_valid(text);
01323     gw_assert(!text->immutable);
01324 
01325     /* Remove white space from the beginning of the text */
01326     while (iscrlf(octstr_get_char(text, start)) && 
01327        start <= octstr_len(text))
01328         start ++;
01329 
01330     if (start > 0)
01331         octstr_delete(text, 0, start);
01332 
01333     /* and from the end. */
01334 
01335     if ((len = octstr_len(text)) > 0) {
01336         end = len = len - 1;
01337         while (iscrlf(octstr_get_char(text, end)) && end >= 0)
01338             end--;
01339         octstr_delete(text, end + 1, len - end);
01340     }
01341 
01342     seems_valid(text);
01343 }
01344 
01345 void octstr_strip_nonalphanums(Octstr *text)
01346 {
01347     int start = 0, end, len = 0;
01348 
01349     seems_valid(text);
01350     gw_assert(!text->immutable);
01351 
01352     /* Remove white space from the beginning of the text */
01353     while (!isalnum(octstr_get_char(text, start)) && 
01354        start <= octstr_len(text))
01355         start ++;
01356 
01357     if (start > 0)
01358         octstr_delete(text, 0, start);
01359 
01360     /* and from the end. */
01361 
01362     if ((len = octstr_len(text)) > 0) {
01363         end = len = len - 1;
01364         while (!isalnum(octstr_get_char(text, end)) && end >= 0)
01365             end--;
01366         octstr_delete(text, end + 1, len - end);
01367     }
01368 
01369     seems_valid(text);
01370 }
01371 
01372 
01373 void octstr_shrink_blanks(Octstr *text)
01374 {
01375     int i, j, end;
01376 
01377     seems_valid(text);
01378     gw_assert(!text->immutable);
01379 
01380     end = octstr_len(text);
01381 
01382     /* Shrink white spaces to one  */
01383     for (i = 0; i < end; i++) {
01384         if (isspace(octstr_get_char(text, i))) {
01385             /* Change the remaining space into single space. */
01386             if (octstr_get_char(text, i) != ' ')
01387                 octstr_set_char(text, i, ' ');
01388 
01389             j = i = i + 1;
01390             while (isspace(octstr_get_char(text, j)))
01391                 j ++;
01392             if (j - i > 1)
01393                 octstr_delete(text, i, j - i);
01394         }
01395     }
01396 
01397     seems_valid(text);
01398 }
01399 
01400 
01401 void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
01402 {
01403     seems_valid(ostr);
01404     gw_assert(!ostr->immutable);
01405     gw_assert(pos <= ostr->len);
01406 
01407     if (len == 0)
01408         return;
01409 
01410     octstr_grow(ostr, ostr->len + len);
01411     if (ostr->len > pos) {  /* only if neccessary*/
01412         memmove(ostr->data + pos + len, ostr->data + pos, ostr->len - pos);
01413     }
01414     memcpy(ostr->data + pos, data, len);
01415     ostr->len += len;
01416     ostr->data[ostr->len] = '\0';
01417 
01418     seems_valid(ostr);
01419 }
01420 
01421 void octstr_insert_char(Octstr *ostr, long pos, const char c)
01422 {
01423     seems_valid(ostr);
01424     gw_assert(!ostr->immutable);
01425     gw_assert(pos <= ostr->len);
01426     
01427     octstr_grow(ostr, ostr->len + 1);
01428     if (ostr->len > pos)
01429         memmove(ostr->data + pos + 1, ostr->data + pos, ostr->len - pos);
01430     memcpy(ostr->data + pos, &c, 1);
01431     ostr->len += 1;
01432     ostr->data[ostr->len] = '\0';
01433     
01434     seems_valid(ostr);
01435 }
01436 
01437 void octstr_append_data(Octstr *ostr, const char *data, long len)
01438 {
01439     gw_assert(ostr != NULL);
01440     octstr_insert_data(ostr, ostr->len, data, len);
01441 }
01442 
01443 
01444 void octstr_append(Octstr *ostr1, const Octstr *ostr2)
01445 {
01446     gw_assert(ostr1 != NULL);
01447     octstr_insert(ostr1, ostr2, ostr1->len);
01448 }
01449 
01450 
01451 void octstr_append_cstr(Octstr *ostr, const char *cstr)
01452 {
01453     octstr_insert_data(ostr, ostr->len, cstr, strlen(cstr));
01454 }
01455 
01456 
01457 void octstr_append_char(Octstr *ostr, int ch)
01458 {
01459     unsigned char c = ch;
01460 
01461     gw_assert(ch >= 0);
01462     gw_assert(ch <= UCHAR_MAX);
01463     octstr_insert_data(ostr, ostr->len, &c, 1);
01464 }
01465 
01466 
01467 void octstr_delete(Octstr *ostr1, long pos, long len)
01468 {
01469     seems_valid(ostr1);
01470     gw_assert(!ostr1->immutable);
01471 
01472     if (pos > ostr1->len)
01473         pos = ostr1->len;
01474     if (pos + len > ostr1->len)
01475         len = ostr1->len - pos;
01476     if (len > 0) {
01477         memmove(ostr1->data + pos, ostr1->data + pos + len,
01478                 ostr1->len - pos - len);
01479         ostr1->len -= len;
01480         ostr1->data[ostr1->len] = '\0';
01481     }
01482 
01483     seems_valid(ostr1);
01484 }
01485 
01486 
01487 
01488 Octstr *octstr_read_file(const char *filename)
01489 {
01490     FILE *f;
01491     Octstr *os;
01492     char buf[4096];
01493     long n;
01494 
01495     gw_assert(filename != NULL);
01496 
01497     f = fopen(filename, "r");
01498     if (f == NULL) {
01499         error(errno, "fopen failed: couldn't open `%s'", filename);
01500         return NULL;
01501     }
01502 
01503     os = octstr_create("");
01504     if (os == NULL)
01505         goto error;
01506 
01507     while ((n = fread(buf, 1, sizeof(buf), f)) > 0)
01508         octstr_insert_data(os, octstr_len(os), buf, n);
01509 
01510     (void) fclose(f);
01511     return os;
01512 
01513 error:
01514     (void) fclose(f);
01515     octstr_destroy(os);
01516     return NULL;
01517 }
01518 
01519 
01520 Octstr *octstr_read_pipe(FILE *f)
01521 {
01522     Octstr *os;
01523     char buf[4096];
01524 
01525     gw_assert(f != NULL);
01526 
01527     os = octstr_create("");
01528     if (os == NULL)
01529         goto error;
01530 
01531     while (fgets(buf, sizeof(buf), f) != NULL)
01532         octstr_append_data(os, buf, strlen(buf));
01533 
01534     return os;
01535 
01536 error:
01537     octstr_destroy(os);
01538     return NULL;
01539 }
01540 
01541 
01542 List *octstr_split_words(const Octstr *ostr)
01543 {
01544     unsigned char *p;
01545     List *list;
01546     Octstr *word;
01547     long i, start, end;
01548 
01549     seems_valid(ostr);
01550 
01551     list = gwlist_create();
01552 
01553     p = ostr->data;
01554     i = 0;
01555     for (; ; ) {
01556         while (i < ostr->len && isspace(*p)) {
01557             ++p;
01558             ++i;
01559         }
01560         start = i;
01561 
01562         while (i < ostr->len && !isspace(*p)) {
01563             ++p;
01564             ++i;
01565         }
01566         end = i;
01567 
01568         if (start == end)
01569             break;
01570 
01571         word = octstr_create_from_data(ostr->data + start,
01572                                        end - start);
01573         gwlist_append(list, word);
01574     }
01575 
01576     return list;
01577 }
01578 
01579 
01580 List *octstr_split(const Octstr *os, const Octstr *sep)
01581 {
01582     List *list;
01583     long next, pos, seplen;
01584     
01585     list = gwlist_create();
01586     pos = 0;
01587     seplen = octstr_len(sep);
01588 
01589     while ((next = octstr_search(os, sep, pos)) >= 0) {
01590         gwlist_append(list, octstr_copy(os, pos, next - pos));
01591         pos = next + seplen;
01592     }
01593     
01594     if (pos < octstr_len(os))
01595         gwlist_append(list, octstr_copy(os, pos, octstr_len(os)));
01596     
01597     return list;
01598 }
01599 
01600 
01601 int octstr_item_match(void *item, void *pattern)
01602 {
01603     return octstr_compare(item, pattern) == 0;
01604 }
01605 
01606 
01607 int octstr_item_case_match(void *item, void *pattern)
01608 {
01609     return octstr_case_compare(item, pattern) == 0;
01610 }
01611 
01612 
01613 void octstr_url_encode(Octstr *ostr)
01614 {
01615     long i, n, len = 0;
01616     int all_safe;
01617     unsigned char c, *str, *str2, *res, *hexits;
01618 
01619     if (ostr == NULL)
01620         return;
01621 
01622     seems_valid(ostr);
01623     gw_assert(!ostr->immutable);
01624 
01625     if (ostr->len == 0)
01626         return;
01627 
01628     /* calculate new length */
01629     for (i = n = 0, str = ostr->data, all_safe = 1; i < ostr->len; i++) {
01630         c = *str++;
01631     
01632         if (c == ' ') {
01633             all_safe = 0;
01634             continue;
01635         }
01636 
01637         if (!is_safe[c]) {
01638         n++;
01639             all_safe = 0;
01640         }
01641      }
01642 
01643     if (all_safe) /* we are done, all chars are safe */
01644        return;
01645 
01646     hexits = "0123456789ABCDEF";
01647 
01648     /*
01649      * no need to reallocate if n == 0, so we make replace in place.
01650      * NOTE: we don't do if (xxx) ... else ... because conditional jump
01651      * is not so fast as just compare (alex).
01652      */
01653     res = str2 = (n ? gw_malloc((len = ostr->len + 2 * n + 1)) : ostr->data);
01654 
01655     for (i = 0, str = ostr->data; i < ostr->len; i++) {
01656         c = *str++;
01657 
01658         if (c == ' ') {
01659             *str2++ = '+';
01660             continue;
01661         }
01662 
01663         if (!is_safe[c]) {
01664             *str2++ = '%';
01665             *str2++ = hexits[c >> 4 & 0xf];
01666             *str2++ = hexits[c & 0xf];
01667             continue;
01668         }
01669 
01670         *str2++ = c;
01671     }
01672     *str2 = 0;
01673     
01674     /* we made replace in place */
01675     if (n) {
01676         gw_free(ostr->data);
01677         ostr->data = res;
01678         ostr->size = len;
01679         ostr->len = len - 1;
01680     }
01681 
01682     seems_valid(ostr);
01683 }
01684 
01685 
01686 int octstr_url_decode(Octstr *ostr)
01687 {
01688     unsigned char *string = ostr->data;
01689     unsigned char *dptr = ostr->data;
01690     int code, code2, ret = 0;
01691 
01692     if (ostr == NULL)
01693         return 0;
01694 
01695     seems_valid(ostr);
01696     gw_assert(!ostr->immutable);
01697 
01698     if (ostr->len == 0)
01699         return 0;
01700 
01701     do {
01702         if (*string == '%') {
01703             if (*(string + 1) == '\0' || *(string + 2) == '\0') {
01704                 warning(0, "octstr_url_decode: corrupted end-of-string <%s>", string);
01705                 ret = -1;
01706                 break;
01707             }
01708 
01709             code = H2B(*(string + 1));
01710             code2 = H2B(*(string + 2));
01711 
01712             if (code == -1 || code2 == -1) {
01713                 warning(0, "octstr_url_decode: garbage detected (%c%c%c) skipping.",
01714                             *string, *(string + 1), *(string + 2));
01715                 *dptr++ = *string++;
01716                 *dptr++ = *string++;
01717                 *dptr++ = *string++;
01718                 ret = -1;
01719                 continue;
01720             }
01721 
01722             *dptr++ = code << 4 | code2;
01723             string += 3;
01724         }
01725         else if (*string == '+') {
01726             *dptr++ = ' ';
01727             string++;
01728         } else
01729             *dptr++ = *string++;
01730     } while (*string);  /* we stop here because it terimates encoded string */
01731 
01732     *dptr = '\0';
01733     ostr->len = (dptr - ostr->data);
01734 
01735     seems_valid(ostr);
01736     return ret;
01737 }
01738 
01739 
01740 long octstr_get_bits(Octstr *ostr, long bitpos, int numbits)
01741 {
01742     long pos;
01743     long result;
01744     int mask;
01745     int shiftwidth;
01746 
01747     seems_valid(ostr);
01748     gw_assert(bitpos >= 0);
01749     gw_assert(numbits <= 32);
01750     gw_assert(numbits >= 0);
01751 
01752     pos = bitpos / 8;
01753     bitpos = bitpos % 8;
01754 
01755     /* This also takes care of the len == 0 case */
01756     if (pos >= ostr->len)
01757         return 0;
01758 
01759     mask = (1 << numbits) - 1;
01760 
01761     /* It's easy if the range fits in one octet */
01762     if (bitpos + numbits <= 8) {
01763         /* shiftwidth is the number of bits to ignore on the right.
01764          * bitpos 0 is the leftmost bit. */
01765         shiftwidth = 8 - (bitpos + numbits);
01766         return (ostr->data[pos] >> shiftwidth) & mask;
01767     }
01768 
01769     /* Otherwise... */
01770     result = 0;
01771     while (bitpos + numbits > 8) {
01772         result = (result << 8) | ostr->data[pos];
01773         numbits -= (8 - bitpos);
01774         bitpos = 0;
01775         pos++;
01776         if (pos >= ostr->len)
01777             return (result << numbits) & mask;
01778     }
01779 
01780     gw_assert(bitpos == 0);
01781     result <<= numbits;
01782     result |= ostr->data[pos] >> (8 - numbits);
01783     return result & mask;
01784 }
01785 
01786 void octstr_set_bits(Octstr *ostr, long bitpos, int numbits,
01787                      unsigned long value)
01788 {
01789     long pos;
01790     unsigned long mask;
01791     int shiftwidth;
01792     int bits;
01793     int maxlen;
01794     int c;
01795 
01796     seems_valid(ostr);
01797     gw_assert(!ostr->immutable);
01798     gw_assert(bitpos >= 0);
01799     gw_assert(numbits <= 32);
01800     gw_assert(numbits >= 0);
01801 
01802     maxlen = (bitpos + numbits + 7) / 8;
01803     if (maxlen > ostr->len) {
01804         octstr_grow(ostr, maxlen);
01805         /* Make sure the new octets start out with value 0 */
01806         for (pos = ostr->len; pos < maxlen; pos++) {
01807             ostr->data[pos] = 0;
01808         }
01809         ostr->len = maxlen;
01810         ostr->data[maxlen] = 0;
01811     }
01812 
01813     mask = (1 << numbits) - 1;
01814     /* mask is also the largest value that fits */
01815     gw_assert(value <= mask);
01816 
01817     pos = bitpos / 8;
01818     bitpos = bitpos % 8;
01819 
01820     /* Does the range fit in one octet? */
01821     if (bitpos + numbits <= 8) {
01822         /* shiftwidth is the number of bits to ignore on the right.
01823          * bitpos 0 is the leftmost bit. */
01824         shiftwidth = 8 - (bitpos + numbits);
01825         /* Extract the bits we don't want to affect */
01826         c = ostr->data[pos] & ~(mask << shiftwidth);
01827         c |= value << shiftwidth;
01828         gw_assert(pos < ostr->len);
01829         ostr->data[pos] = c;
01830         return;
01831     }
01832 
01833     /* Otherwise... */
01834     /* If speed is a problem here, we could have separate cases for
01835      * the first octet (which may have bitpos > 0), and the rest,
01836      * which don't. */
01837     while (bitpos + numbits > 8) {
01838         /* We want this many bits from the value */
01839         bits = 8 - bitpos;
01840         /* There are this many bits to their right in the value */
01841         shiftwidth = numbits - bits;
01842         /* Construct a mask for "bits" bits on the far right */
01843         mask = (1 << bits) - 1;
01844         /* Get the bits we want */
01845         c = (value >> shiftwidth) & mask;
01846         /* Merge them with the bits that are already there */
01847         gw_assert(pos < ostr->len);
01848         ostr->data[pos] = (ostr->data[pos] & ~mask) | c;
01849         numbits -= (8 - bitpos);
01850         bitpos = 0;
01851         pos++;
01852     }
01853 
01854     gw_assert(bitpos == 0);
01855     gw_assert(pos < ostr->len);
01856     /* Set remaining bits.  This is just like the single-octet case
01857      * before the loop, except that we know bitpos is 0. */
01858     mask = (1 << numbits) - 1;
01859     shiftwidth = 8 - numbits;
01860     c = ostr->data[pos] & ~(mask << shiftwidth);
01861     c |= value << shiftwidth;
01862     ostr->data[pos] = c;
01863 
01864     seems_valid(ostr);
01865 }
01866 
01867 
01868 void octstr_append_uintvar(Octstr *ostr, unsigned long value)
01869 {
01870     /* A uintvar is defined to be up to 32 bits large, so it will
01871      * fit in 5 octets. */
01872     unsigned char octets[5];
01873     int i;
01874     int start;
01875 
01876     /* Handle last byte separately; it has no continuation bit,
01877      * and must be encoded even if value is 0. */
01878     octets[4] = value & 0x7f;
01879     value >>= 7;
01880 
01881     for (i = 3; value > 0 && i >= 0; i--) {
01882         octets[i] = 0x80 | (value & 0x7f);
01883         value >>= 7;
01884     }
01885     start = i + 1;
01886 
01887     octstr_append_data(ostr, octets + start, 5 - start);
01888 }
01889 
01890 
01891 long octstr_extract_uintvar(Octstr *ostr, unsigned long *value, long pos)
01892 {
01893     int c;
01894     int count;
01895     unsigned long ui;
01896 
01897     ui = 0;
01898     for (count = 0; count < 5; count++) {
01899         c = octstr_get_char(ostr, pos + count);
01900         if (c < 0)
01901             return -1;
01902         ui = (ui << 7) | (c & 0x7f);
01903         if (!(c & 0x80)) {
01904             *value = ui;
01905             return pos + count + 1;
01906         }
01907     }
01908 
01909     return -1;
01910 }
01911 
01912 
01913 void octstr_append_decimal(Octstr *ostr, long value)
01914 {
01915     char tmp[128];
01916 
01917     sprintf(tmp, "%ld", value);
01918     octstr_append_cstr(ostr, tmp);
01919 }
01920 
01921 
01922 
01923 /**********************************************************************
01924  * octstr_dump... and related private functions
01925  */
01926 
01927 static void octstr_dump_debug(const Octstr *ostr, int level)
01928 {
01929     unsigned char *p, *d, buf[1024], charbuf[256];
01930     long pos;
01931     const int octets_per_line = 16;
01932     int c, this_line_begins_at;
01933     
01934     if (ostr == NULL)
01935         return;
01936 
01937     seems_valid(ostr);
01938 
01939     debug("gwlib.octstr", 0, "%*sOctet string at %p:", level, "",
01940           (void *) ostr);
01941     debug("gwlib.octstr", 0, "%*s  len:  %lu", level, "",
01942           (unsigned long) ostr->len);
01943     debug("gwlib.octstr", 0, "%*s  size: %lu", level, "",
01944           (unsigned long) ostr->size);
01945     debug("gwlib.octstr", 0, "%*s  immutable: %d", level, "",
01946           ostr->immutable);
01947 
01948     buf[0] = '\0';
01949     p = buf;
01950     d = charbuf;
01951     this_line_begins_at = 0;
01952     for (pos = 0; pos < octstr_len(ostr); ) {
01953         c = octstr_get_char(ostr, pos);
01954         sprintf(p, "%02x ", c);
01955         p = strchr(p, '\0');
01956         if (isprint(c))
01957             *d++ = c;
01958         else
01959             *d++ = '.';
01960         ++pos;
01961         if (pos - this_line_begins_at == octets_per_line) {
01962             *d = '\0';
01963             debug("gwlib.octstr", 0, "%*s  data: %s  %s", level, "",
01964                   buf, charbuf);
01965             buf[0] = '\0';
01966             charbuf[0] = '\0';
01967             p = buf;
01968             d = charbuf;
01969             this_line_begins_at = pos;
01970         }
01971     }
01972     if (pos - this_line_begins_at > 0) {
01973         *d = '\0';
01974         debug("gwlib.octstr", 0, "%*s  data: %-*.*s  %s", level, "",
01975               octets_per_line*3,
01976               octets_per_line*3, buf, charbuf);
01977     }
01978 
01979     debug("gwlib.octstr", 0, "%*sOctet string dump ends.", level, "");
01980 }
01981 
01982 
01983 /*
01984  * We do some pre-processor mangling here in order to reduce code for 
01985  * the 3 log levels info(), warning() and error() that have the same
01986  * argument list.
01987  * We need to map the function calls via ## concatenation and revert
01988  * to the orginal function call by a define.
01989  * The do-while loop emulates a function call.
01990  */
01991 
01992 #define LLinfo info
01993 #define LLwarning warning
01994 #define LLerror error
01995 
01996 #define octstr_dump_LOGLEVEL(loglevel, ostr, level) \
01997 do { \
01998     unsigned char *p, *d, buf[1024], charbuf[256]; \
01999     long pos; \
02000     const int octets_per_line = 16; \
02001     int c, this_line_begins_at; \
02002     \
02003     if (ostr == NULL) \
02004         return; \
02005     \
02006     seems_valid(ostr); \
02007     \
02008     LL##loglevel(0, "%*sOctet string at %p:", level, "", \
02009           (void *) ostr); \
02010     LL##loglevel(0, "%*s  len:  %lu", level, "", \
02011           (unsigned long) ostr->len); \
02012     LL##loglevel(0, "%*s  size: %lu", level, "", \
02013           (unsigned long) ostr->size); \
02014     LL##loglevel(0, "%*s  immutable: %d", level, "", \
02015           ostr->immutable); \
02016     \
02017     buf[0] = '\0'; \
02018     p = buf; \
02019     d = charbuf; \
02020     this_line_begins_at = 0; \
02021     for (pos = 0; pos < octstr_len(ostr); ) { \
02022         c = octstr_get_char(ostr, pos); \
02023         sprintf(p, "%02x ", c); \
02024         p = strchr(p, '\0'); \
02025         if (isprint(c)) \
02026             *d++ = c; \
02027         else \
02028             *d++ = '.'; \
02029         ++pos; \
02030         if (pos - this_line_begins_at == octets_per_line) { \
02031             *d = '\0'; \
02032             LL##loglevel(0, "%*s  data: %s  %s", level, "", \
02033                   buf, charbuf); \
02034             buf[0] = '\0'; \
02035             charbuf[0] = '\0'; \
02036             p = buf; \
02037             d = charbuf; \
02038             this_line_begins_at = pos; \
02039         } \
02040     } \
02041     if (pos - this_line_begins_at > 0) { \
02042         *d = '\0'; \
02043         LL##loglevel(0, "%*s  data: %-*.*s  %s", level, "", \
02044               octets_per_line*3, \
02045               octets_per_line*3, buf, charbuf); \
02046     } \
02047     \
02048     LL##loglevel(0, "%*sOctet string dump ends.", level, ""); \
02049 } while (0)
02050 
02051 
02052 void octstr_dump_real(const Octstr *ostr, int level, ...)
02053 {
02054     va_list p;
02055     unsigned int loglevel;
02056     
02057     va_start(p, level);
02058     loglevel = va_arg(p, unsigned int);
02059     va_end(p);
02060     
02061     switch (loglevel) {
02062         case GW_DEBUG:
02063             octstr_dump_debug(ostr, level);
02064             break;
02065         case GW_INFO:
02066             octstr_dump_LOGLEVEL(info, ostr, level);
02067             break;
02068         case GW_WARNING:
02069             octstr_dump_LOGLEVEL(warning, ostr, level);
02070             break;
02071         case GW_ERROR:
02072             octstr_dump_LOGLEVEL(error, ostr, level);
02073             break;
02074         default:
02075             octstr_dump_debug(ostr, level);
02076             break;
02077     }
02078 }                             
02079 
02080 
02081 void octstr_dump_short(Octstr *ostr, int level, const char *name)
02082 {
02083     char buf[100];
02084     char *p;
02085     long i;
02086     int c;
02087 
02088     if (ostr == NULL) {
02089         debug("gwlib.octstr", 0, "%*s%s: NULL", level, "", name);
02090         return;
02091     }
02092 
02093     seems_valid(ostr);
02094 
02095     if (ostr->len < 20) {
02096         p = buf;
02097         for (i = 0; i < ostr->len; i++) {
02098             c = ostr->data[i];
02099             if (c == '\n') {
02100                 *p++ = '\\';
02101                 *p++ = 'n';
02102             } else if (!isprint(c)) {
02103                 break;
02104             } else if (c == '"') {
02105                 *p++ = '\\';
02106                 *p++ = '"';
02107             } else if (c == '\\') {
02108                 *p++ = '\\';
02109                 *p++ = '\\';
02110             } else {
02111                 *p++ = c;
02112             }
02113         }
02114         if (i == ostr->len) {
02115             *p++ = 0;
02116             /* We got through the loop without hitting nonprintable
02117              * characters. */
02118             debug("gwlib.octstr", 0, "%*s%s: \"%s\"", level, "", name, buf);
02119             return;
02120         }
02121     }
02122 
02123     debug("gwlib.octstr", 0, "%*s%s:", level, "", name);
02124     octstr_dump(ostr, level + 1);
02125 }
02126 
02127 
02128 /**********************************************************************
02129  * octstr_format and related private functions
02130  */
02131 
02132 
02133 /*
02134  * A parsed form of the format string. This struct has been carefully
02135  * defined so that it can be initialized with {0} and it will have 
02136  * the correct defaults.
02137  */
02138 struct format
02139 {
02140     int minus;
02141     int zero;
02142 
02143     long min_width;
02144 
02145     int has_prec;
02146     long prec;
02147 
02148     long type;
02149 };
02150 
02151 
02152 static void format_flags(struct format *format, const char **fmt)
02153 {
02154     int done;
02155 
02156     done = 0;
02157     do
02158     {
02159         switch (**fmt) {
02160         case '-':
02161             format->minus = 1;
02162             break;
02163 
02164         case '0':
02165             format->zero = 1;
02166             break;
02167 
02168         default:
02169             done = 1;
02170         }
02171 
02172         if (!done)
02173             ++(*fmt);
02174     } while (!done);
02175 }
02176 
02177 
02178 static void format_width(struct format *format, const char **fmt,
02179                          VALPARM(args))
02180 {
02181     char *end;
02182 
02183     if (**fmt == '*')
02184     {
02185         format->min_width = va_arg(VALST(args), int);
02186         ++(*fmt);
02187     } else if (isdigit(**(const unsigned char **) fmt))
02188     {
02189         format->min_width = strtol(*fmt, &end, 10);
02190         *fmt = end;
02191         /* XXX error checking is missing from here */
02192     }
02193 }
02194 
02195 
02196 static void format_prec(struct format *format, const char **fmt,
02197                         VALPARM(args))
02198 {
02199     char *end;
02200 
02201     if (**fmt != '.')
02202         return;
02203     ++(*fmt);
02204     if (**fmt == '*')
02205     {
02206         format->has_prec = 1;
02207         format->prec = va_arg(VALST(args), int);
02208         ++(*fmt);
02209     } else if (isdigit(**(const unsigned char **) fmt))
02210     {
02211         format->has_prec = 1;
02212         format->prec = strtol(*fmt, &end, 10);
02213         *fmt = end;
02214         /* XXX error checking is missing from here */
02215     }
02216 }
02217 
02218 
02219 static void format_type(struct format *format, const char **fmt)
02220 {
02221     switch (**fmt)
02222     {
02223     case 'h':
02224     case 'l':
02225         format->type = **fmt;
02226         ++(*fmt);
02227         break;
02228     }
02229 }
02230 
02231 
02232 static void convert(Octstr *os, struct format *format, const char **fmt,
02233                     VALPARM(args))
02234 {
02235     Octstr *new;
02236     char *s, *pad;
02237     long n;
02238     unsigned long u;
02239     char tmpfmt[1024];
02240     char tmpbuf[1024];
02241     char c;
02242     void *p;
02243 
02244     new = NULL;
02245 
02246     switch (**fmt)
02247     {
02248     case 'c':
02249         c = va_arg(VALST(args), int);
02250         new = octstr_create_from_data(&c, 1);
02251         break;
02252 
02253     case 'd':
02254     case 'i':
02255         switch (format->type) {
02256         case 'l':
02257             n = va_arg(VALST(args), long);
02258             break;
02259         case 'h':
02260             n = (short) va_arg(VALST(args), int);
02261             break;
02262         default:
02263             n = va_arg(VALST(args), int);
02264             break;
02265         }
02266         new = octstr_create("");
02267         octstr_append_decimal(new, n);
02268         break;
02269 
02270     case 'o':
02271     case 'u':
02272     case 'x':
02273     case 'X':
02274     switch (format->type) {
02275     case 'l':
02276         u = va_arg(VALST(args), unsigned long);
02277         break;
02278         case 'h':
02279             u = (unsigned short) va_arg(VALST(args), unsigned int);
02280             break;
02281         default:
02282             u = va_arg(VALST(args), unsigned int);
02283             break;
02284         }
02285         tmpfmt[0] = '%';
02286     tmpfmt[1] = 'l';
02287     tmpfmt[2] = **fmt;
02288     tmpfmt[3] = '\0';
02289     sprintf(tmpbuf, tmpfmt, u);
02290         new = octstr_create(tmpbuf);
02291         break;
02292 
02293     case 'e':
02294     case 'f':
02295     case 'g':
02296         sprintf(tmpfmt, "%%");
02297         if (format->minus)
02298             strcat(tmpfmt, "-");
02299         if (format->zero)
02300             strcat(tmpfmt, "0");
02301         if (format->min_width > 0)
02302             sprintf(strchr(tmpfmt, '\0'),
02303                     "%ld", format->min_width);
02304         if (format->has_prec)
02305             sprintf(strchr(tmpfmt, '\0'),
02306                     ".%ld", format->prec);
02307         if (format->type != '\0')
02308             sprintf(strchr(tmpfmt, '\0'),
02309                     "%c", (int) format->type);
02310         sprintf(strchr(tmpfmt, '\0'), "%c", **fmt);
02311         snprintf(tmpbuf, sizeof(tmpbuf),
02312                  tmpfmt, va_arg(VALST(args), double));
02313         new = octstr_create(tmpbuf);
02314         break;
02315 
02316     case 's':
02317         s = va_arg(VALST(args), char *);
02318         if (format->has_prec && format->prec < (long) strlen(s))
02319             n = format->prec;
02320         else
02321             n = (long) strlen(s);
02322         new = octstr_create_from_data(s, n);
02323         break;
02324 
02325     case 'p':
02326         p = va_arg(VALST(args), void *);
02327     sprintf(tmpfmt, "%p", p);
02328     new = octstr_create(tmpfmt);
02329     break;
02330 
02331     case 'S':
02332         new = octstr_duplicate(va_arg(VALST(args), Octstr *));
02333         if (!new)
02334             new = octstr_create("(null)");
02335         if (format->has_prec)
02336             octstr_truncate(new, format->prec);
02337         break;
02338 
02339     case 'E':
02340         new = octstr_duplicate(va_arg(VALST(args), Octstr *));
02341         if (!new)
02342             new = octstr_create("(null)");
02343         octstr_url_encode(new);
02344         /*
02345          * note: we use blind truncate - encoded character can get cut half-way.
02346          */
02347         if (format->has_prec)
02348             octstr_truncate(new, format->prec);
02349         break;
02350 
02351     case 'H':
02352         new = octstr_duplicate(va_arg(VALST(args), Octstr *));
02353         if (!new)
02354             new = octstr_create("(null)");
02355         /* upper case */
02356         octstr_binary_to_hex(new, 1);
02357         if (format->has_prec)
02358             octstr_truncate(new, (format->prec % 2 ? format->prec - 1 : format->prec));
02359         break;
02360 
02361     case '%':
02362         new = octstr_create("%");
02363         break;
02364 
02365     default:
02366         panic(0, "octstr_format format string syntax error.");
02367     }
02368 
02369     if (format->zero)
02370         pad = "0";
02371     else
02372         pad = " ";
02373 
02374     if (format->minus) {
02375         while (format->min_width > octstr_len(new))
02376             octstr_append_data(new, pad, 1);
02377     } else {
02378         while (format->min_width > octstr_len(new))
02379             octstr_insert_data(new, 0, pad, 1);
02380     }
02381 
02382     octstr_append(os, new);
02383     octstr_destroy(new);
02384 
02385     if (**fmt != '\0')
02386         ++(*fmt);
02387 }
02388 
02389 
02390 Octstr *octstr_format(const char *fmt, ...)
02391 {
02392     Octstr *os;
02393     va_list args;
02394 
02395     va_start(args, fmt);
02396     os = octstr_format_valist(fmt, args);
02397     va_end(args);
02398     return os;
02399 }
02400 
02401 
02402 Octstr *octstr_format_valist_real(const char *fmt, va_list args)
02403 {
02404     Octstr *os;
02405     size_t n;
02406 
02407     os = octstr_create("");
02408 
02409     while (*fmt != '\0') {
02410         struct format format = { 0, };
02411 
02412         n = strcspn(fmt, "%");
02413         octstr_append_data(os, fmt, n);
02414         fmt += n;
02415 
02416         gw_assert(*fmt == '%' || *fmt == '\0');
02417         if (*fmt == '\0')
02418             continue;
02419 
02420         ++fmt;
02421         format_flags(&format, &fmt);
02422         format_width(&format, &fmt, VARGS(args));
02423         format_prec(&format, &fmt, VARGS(args));
02424         format_type(&format, &fmt);
02425         convert(os, &format, &fmt, VARGS(args));
02426     }
02427 
02428     seems_valid(os);
02429     return os;
02430 }
02431 
02432 
02433 void octstr_format_append(Octstr *os, const char *fmt, ...)
02434 {
02435     Octstr *temp;
02436     va_list args;
02437 
02438     va_start(args, fmt);
02439     temp = octstr_format_valist(fmt, args);
02440     va_end(args);
02441     octstr_append(os, temp);
02442     octstr_destroy(temp);
02443 }
02444 
02445 
02446 unsigned long octstr_hash_key(Octstr *ostr)
02447 {
02448     unsigned long key = 0;
02449     long i;
02450 
02451     if (ostr == NULL)
02452     return 0;
02453 
02454     for (i = 0; i < octstr_len(ostr); i++)
02455     key = key + octstr_get_char(ostr, i);
02456 
02457     return key;
02458 }
02459 
02460 
02461 /**********************************************************************
02462  * Local functions.
02463  */
02464 
02465 static void seems_valid_real(const Octstr *ostr, const char *filename, long lineno,
02466                              const char *function)
02467 {
02468     gw_assert(immutables_init);
02469     gw_assert_place(ostr != NULL,
02470                     filename, lineno, function);
02471     gw_assert_allocated(ostr,
02472                         filename, lineno, function);
02473     gw_assert_place(ostr->len >= 0,
02474                     filename, lineno, function);
02475     gw_assert_place(ostr->size >= 0,
02476                     filename, lineno, function);
02477     if (ostr->size == 0) {
02478         gw_assert_place(ostr->len == 0,
02479                         filename, lineno, function);
02480         gw_assert_place(ostr->data == NULL,
02481                         filename, lineno, function);
02482     } else {
02483         gw_assert_place(ostr->len + 1 <= ostr->size,
02484                         filename, lineno, function);
02485         gw_assert_place(ostr->data != NULL,
02486                         filename, lineno, function);
02487     if (!ostr->immutable)
02488             gw_assert_allocated(ostr->data,
02489                                 filename, lineno, function);
02490         gw_assert_place(ostr->data[ostr->len] == '\0',
02491                         filename, lineno, function);
02492     }
02493 }
02494 
02495 int
02496 octstr_recode (Octstr *tocode, Octstr *fromcode, Octstr *orig)
02497 {
02498     Octstr *octstr_utf8 = NULL;
02499     Octstr *octstr_final = NULL;
02500     int resultcode = 0;
02501     
02502     if (octstr_case_compare(tocode, fromcode) == 0) {
02503     goto cleanup_and_exit;
02504     }
02505 
02506     if ((octstr_case_compare(fromcode, octstr_imm ("UTF-8")) != 0) &&
02507     (octstr_case_compare(fromcode, octstr_imm ("UTF8")) != 0)) {
02508     if (charset_to_utf8(orig, &octstr_utf8, fromcode) < 0) {
02509         resultcode = -1;
02510         goto cleanup_and_exit;
02511     }
02512     } else {
02513     octstr_utf8 = octstr_duplicate(orig);
02514     }
02515 
02516     if ((octstr_case_compare(tocode, octstr_imm ("UTF-8")) != 0) &&
02517     (octstr_case_compare(tocode, octstr_imm ("UTF8")) != 0)) {
02518     if (charset_from_utf8(octstr_utf8, &octstr_final, tocode) < 0) {
02519         resultcode = -1;
02520         goto cleanup_and_exit;
02521     }
02522     } else {
02523     octstr_final = octstr_duplicate(octstr_utf8);
02524     }
02525 
02526     octstr_truncate(orig, 0);
02527     octstr_append(orig, octstr_final);
02528 
02529  cleanup_and_exit:
02530     octstr_destroy (octstr_utf8);
02531     octstr_destroy (octstr_final);
02532 
02533     return resultcode;
02534 }
02535 
02536 void octstr_strip_char(Octstr *text, char ch)
02537 {
02538     int start = 0;
02539 
02540     seems_valid(text);
02541     gw_assert(!text->immutable);
02542 
02543     /* Remove char from the beginning of the text */
02544     while ((ch == octstr_get_char(text, start)) &&
02545            start <= octstr_len(text))
02546         start ++;
02547 
02548     if (start > 0)
02549         octstr_delete(text, 0, start);
02550 
02551     seems_valid(text);
02552 }
02553 
02554 int octstr_isnum(Octstr *ostr1)
02555 {
02556     int start = 0;
02557     char c;
02558 
02559     seems_valid(ostr1);
02560     while (start < octstr_len(ostr1)) {
02561         c = octstr_get_char(ostr1, start);
02562         if (!isdigit(c) && (c!='+'))
02563             return 0;
02564         start++;
02565     }
02566     return 1;
02567 }
02568 
02569 void octstr_replace(Octstr *haystack, Octstr *needle, Octstr *repl)
02570 {
02571     int p = 0;
02572     long len, repl_len;
02573 
02574     len = octstr_len(needle);
02575     repl_len = octstr_len(repl);
02576 
02577     while ((p = octstr_search(haystack, needle, p)) != -1) {
02578         octstr_delete(haystack, p, len);
02579         octstr_insert(haystack, repl, p);
02580         p += repl_len;
02581     }
02582 }
02583 
02584 int octstr_symbolize(Octstr *ostr)
02585 {
02586     long len, i;
02587 
02588     seems_valid(ostr);
02589     gw_assert(!ostr->immutable);
02590 
02591     if (ostr->len == 0)
02592         return 0;
02593 
02594     /* Check if it's in the right format */
02595     if (!octstr_check_range(ostr, 0, ostr->len, gw_isxdigit))
02596         return -1;
02597 
02598     len = ostr->len + (ostr->len/2);
02599     octstr_grow(ostr, ostr->len * 2);
02600 
02601     for (i = 0; i < len; i += 3)
02602         octstr_insert_data(ostr, i, "%", 1);
02603 
02604     return 1;
02605 }
02606 
02607 void octstr_delete_matching(Octstr *haystack, Octstr *needle)
02608 {
02609     int p = 0;
02610     long len;
02611 
02612     seems_valid(haystack);
02613     seems_valid(needle);
02614     gw_assert(!haystack->immutable);
02615     len = octstr_len(needle);
02616 
02617     while ((p = octstr_search(haystack, needle, p)) != -1) {
02618         octstr_delete(haystack, p, len);
02619     }
02620 }
02621  
02622 int octstr_is_all_hex(Octstr *os)      
02623 {
02624     long len, i;
02625     int ch;
02626 
02627     seems_valid(os);
02628     len = octstr_len(os);
02629     for (i = 0; i < len; ++i) {
02630         ch = octstr_get_char(os, i);
02631         if (!gw_isxdigit(ch))
02632             return 0;
02633     }
02634 
02635     return 1;
02636 }
02637 
02638 /*
02639  * function octstr_convert_to_html_entities()
02640  *      make data HTML safe by converting appropriate characters to HTML entities
02641  * Input: data to be inserted in HTML
02642  **/
02643 void octstr_convert_to_html_entities(Octstr* input)
02644 {
02645     int i;
02646 
02647     for (i = 0; i < octstr_len(input); ++i) {
02648         switch (octstr_get_char(input, i)) {
02649 #define ENTITY(a,b) \
02650     case a: \
02651     octstr_delete(input, i, 1); \
02652     octstr_insert(input, octstr_imm("&" b ";"), i); \
02653     i += sizeof(b); break;
02654 #include "gwlib/html-entities.def"
02655 #undef ENTITY
02656         }
02657     }
02658 }
02659 
02660 /*
02661  * This function is meant to find html entities in an octstr.
02662  * The html-entities.def file must be sorted alphabetically for
02663  * this function to work (according to current Locale in use).
02664 */
02665 static int octstr_find_entity(Octstr* input, int startfind, int endfind)
02666 {
02667 #define ENTITY(a,b) { a, b },
02668     struct entity_struct {
02669         int entity;
02670         char *entity_str;
02671     };
02672     const struct entity_struct entities[] = {
02673 #include "html-entities.def"
02674         { -1, "" } /* pivot */
02675     };
02676 #undef ENTITY
02677     int center;         /* position in table that we are about to compare */
02678     int matchresult;    /* result of match agains found entity name. indicates less, equal or greater */
02679 
02680     if (endfind == 0) {
02681         /* when calling this function we do not (nor even want to) know the
02682          * sizeof(entities). Hence this check. */
02683         endfind = (sizeof(entities) / sizeof(struct entity_struct)) - 1;
02684     }
02685     center = startfind + ((endfind - startfind) / 2);
02686     matchresult = octstr_str_compare(input, entities[center].entity_str);
02687     if (matchresult == 0) {
02688         return entities[center].entity;
02689     }
02690     if (endfind - startfind <= 1) {
02691         /* we are at the end of our results */
02692         return -1;
02693     }
02694     if  (matchresult < 0) {
02695         /* keep searching in first part of the table */
02696         return octstr_find_entity(input, startfind, center);
02697     } else {
02698         /* keep searching in last part of the table */
02699         return octstr_find_entity(input, center, endfind);
02700     }
02701 }
02702 
02703 /*
02704  * function octstr_convert_from_html_entities()
02705  *   convert HTML safe data back to binary data by replacing HTML entities with their
02706  *   respective character values
02707  * Input: data to be inserted in HTML
02708  **/
02709 void octstr_convert_from_html_entities(Octstr* input)
02710 {
02711     int startpos = 0, endpos;
02712     int entity;
02713     Octstr *match;
02714 
02715     while ((startpos = octstr_search_char(input, '&', startpos)) != -1) {
02716         endpos = octstr_search_char(input, ';', startpos + 1);
02717         if (endpos >= 0) {
02718             match = octstr_copy(input, startpos + 1, endpos - startpos - 1);
02719             entity = octstr_find_entity(match, 0, 0);
02720             if (entity >= 0) {
02721                 octstr_delete(input, startpos, endpos - startpos + 1);
02722                 octstr_insert_char(input, startpos, entity);
02723             }
02724             octstr_destroy(match);
02725         }
02726         startpos++;
02727     }
02728 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.