"Fossies" - the Fresh Open Source Software Archive

Member "sitecopy-0.16.6/lib/neon/ne_string.c" (4 Mar 2008, 14272 Bytes) of archive /linux/www/sitecopy-0.16.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ne_string.c" see the Fossies "Dox" file reference documentation.

    1 /* 
    2    String utility functions
    3    Copyright (C) 1999-2007, Joe Orton <joe@manyfish.co.uk>
    4    strcasecmp/strncasecmp implementations are:
    5    Copyright (C) 1991, 1992, 1995, 1996, 1997 Free Software Foundation, Inc.
    6    This file is part of the GNU C Library.
    7 
    8    This library is free software; you can redistribute it and/or
    9    modify it under the terms of the GNU Library General Public
   10    License as published by the Free Software Foundation; either
   11    version 2 of the License, or (at your option) any later version.
   12    
   13    This library is distributed in the hope that it will be useful,
   14    but WITHOUT ANY WARRANTY; without even the implied warranty of
   15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16    Library General Public License for more details.
   17 
   18    You should have received a copy of the GNU Library General Public
   19    License along with this library; if not, write to the Free
   20    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
   21    MA 02111-1307, USA
   22 
   23 */
   24 
   25 #include "config.h"
   26 
   27 #ifdef HAVE_STDLIB_H
   28 #include <stdlib.h>
   29 #endif
   30 #ifdef HAVE_STRING_H
   31 #include <string.h>
   32 #endif
   33 #ifdef HAVE_UNISTD_H
   34 #include <unistd.h>
   35 #endif
   36 
   37 #include <stdio.h>
   38 
   39 #include "ne_alloc.h"
   40 #include "ne_string.h"
   41 
   42 char *ne_token(char **str, char separator)
   43 {
   44     char *ret = *str, *pnt = strchr(*str, separator);
   45 
   46     if (pnt) {
   47     *pnt = '\0';
   48     *str = pnt + 1;
   49     } else {
   50     /* no separator found: return end of string. */
   51     *str = NULL;
   52     }
   53     
   54     return ret;
   55 }
   56 
   57 char *ne_qtoken(char **str, char separator, const char *quotes)
   58 {
   59     char *pnt, *ret = NULL;
   60 
   61     for (pnt = *str; *pnt != '\0'; pnt++) {
   62     char *quot = strchr(quotes, *pnt);
   63     
   64     if (quot) {
   65         char *qclose = strchr(pnt+1, *quot);
   66         
   67         if (!qclose) {
   68         /* no closing quote: invalid string. */
   69         return NULL;
   70         }
   71         
   72         pnt = qclose;
   73     } else if (*pnt == separator) {
   74         /* found end of token. */
   75         *pnt = '\0';
   76         ret = *str;
   77         *str = pnt + 1;
   78         return ret;
   79     }
   80     }
   81 
   82     /* no separator found: return end of string. */
   83     ret = *str;
   84     *str = NULL;
   85     return ret;
   86 }
   87 
   88 char *ne_shave(char *str, const char *whitespace)
   89 {
   90     char *pnt, *ret = str;
   91 
   92     while (*ret != '\0' && strchr(whitespace, *ret) != NULL) {
   93     ret++;
   94     }
   95 
   96     /* pnt points at the NUL terminator. */
   97     pnt = &ret[strlen(ret)];
   98     
   99     while (pnt > ret && strchr(whitespace, *(pnt-1)) != NULL) {
  100     pnt--;
  101     }
  102 
  103     *pnt = '\0';
  104     return ret;
  105 }
  106 
  107 void ne_buffer_clear(ne_buffer *buf) 
  108 {
  109     memset(buf->data, 0, buf->length);
  110     buf->used = 1;
  111 }  
  112 
  113 /* Grows for given size, returns 0 on success, -1 on error. */
  114 void ne_buffer_grow(ne_buffer *buf, size_t newsize) 
  115 {
  116 #define NE_BUFFER_GROWTH 512
  117     if (newsize > buf->length) {
  118     /* If it's not big enough already... */
  119     buf->length = ((newsize / NE_BUFFER_GROWTH) + 1) * NE_BUFFER_GROWTH;
  120     
  121     /* Reallocate bigger buffer */
  122     buf->data = ne_realloc(buf->data, buf->length);
  123     }
  124 }
  125 
  126 static size_t count_concat(va_list *ap)
  127 {
  128     size_t total = 0;
  129     char *next;
  130 
  131     while ((next = va_arg(*ap, char *)) != NULL)
  132     total += strlen(next);
  133 
  134     return total;
  135 }
  136 
  137 static void do_concat(char *str, va_list *ap) 
  138 {
  139     char *next;
  140 
  141     while ((next = va_arg(*ap, char *)) != NULL) {
  142 #ifdef HAVE_STPCPY
  143         str = stpcpy(str, next);
  144 #else
  145     size_t len = strlen(next);
  146     memcpy(str, next, len);
  147     str += len;
  148 #endif
  149     }
  150 }
  151 
  152 void ne_buffer_concat(ne_buffer *buf, ...)
  153 {
  154     va_list ap;
  155     ssize_t total;
  156 
  157     va_start(ap, buf);
  158     total = buf->used + count_concat(&ap);
  159     va_end(ap);    
  160 
  161     /* Grow the buffer */
  162     ne_buffer_grow(buf, total);
  163     
  164     va_start(ap, buf);    
  165     do_concat(buf->data + buf->used - 1, &ap);
  166     va_end(ap);    
  167 
  168     buf->used = total;
  169     buf->data[total - 1] = '\0';
  170 }
  171 
  172 char *ne_concat(const char *str, ...)
  173 {
  174     va_list ap;
  175     size_t total, slen = strlen(str);
  176     char *ret;
  177 
  178     va_start(ap, str);
  179     total = slen + count_concat(&ap);
  180     va_end(ap);
  181 
  182     ret = memcpy(ne_malloc(total + 1), str, slen);
  183 
  184     va_start(ap, str);
  185     do_concat(ret + slen, &ap);
  186     va_end(ap);
  187 
  188     ret[total] = '\0';
  189     return ret;    
  190 }
  191 
  192 /* Append zero-terminated string... returns 0 on success or -1 on
  193  * realloc failure. */
  194 void ne_buffer_zappend(ne_buffer *buf, const char *str) 
  195 {
  196     ne_buffer_append(buf, str, strlen(str));
  197 }
  198 
  199 void ne_buffer_append(ne_buffer *buf, const char *data, size_t len) 
  200 {
  201     ne_buffer_grow(buf, buf->used + len);
  202     memcpy(buf->data + buf->used - 1, data, len);
  203     buf->used += len;
  204     buf->data[buf->used - 1] = '\0';
  205 }
  206 
  207 size_t ne_buffer_snprintf(ne_buffer *buf, size_t max, const char *fmt, ...)
  208 {
  209     va_list ap;
  210     size_t ret;
  211 
  212     ne_buffer_grow(buf, buf->used + max);
  213 
  214     va_start(ap, fmt);
  215     ret = ne_vsnprintf(buf->data + buf->used - 1, max, fmt, ap);
  216     va_end(ap);
  217     buf->used += ret;
  218 
  219     return ret;    
  220 }
  221 
  222 ne_buffer *ne_buffer_create(void) 
  223 {
  224     return ne_buffer_ncreate(512);
  225 }
  226 
  227 ne_buffer *ne_buffer_ncreate(size_t s) 
  228 {
  229     ne_buffer *buf = ne_malloc(sizeof(*buf));
  230     buf->data = ne_malloc(s);
  231     buf->data[0] = '\0';
  232     buf->length = s;
  233     buf->used = 1;
  234     return buf;
  235 }
  236 
  237 void ne_buffer_destroy(ne_buffer *buf) 
  238 {
  239     ne_free(buf->data);
  240     ne_free(buf);
  241 }
  242 
  243 char *ne_buffer_finish(ne_buffer *buf)
  244 {
  245     char *ret = buf->data;
  246     ne_free(buf);
  247     return ret;
  248 }
  249 
  250 void ne_buffer_altered(ne_buffer *buf)
  251 {
  252     buf->used = strlen(buf->data) + 1;
  253 }
  254 
  255 static const char b64_alphabet[] =  
  256     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  257     "abcdefghijklmnopqrstuvwxyz"
  258     "0123456789+/=";
  259     
  260 char *ne_base64(const unsigned char *text, size_t inlen)
  261 {
  262     /* The tricky thing about this is doing the padding at the end,
  263      * doing the bit manipulation requires a bit of concentration only */
  264     char *buffer, *point;
  265     size_t outlen;
  266     
  267     /* Use 'buffer' to store the output. Work out how big it should be...
  268      * This must be a multiple of 4 bytes */
  269 
  270     outlen = (inlen*4)/3;
  271     if ((inlen % 3) > 0) /* got to pad */
  272     outlen += 4 - (inlen % 3);
  273     
  274     buffer = ne_malloc(outlen + 1); /* +1 for the \0 */
  275     
  276     /* now do the main stage of conversion, 3 bytes at a time,
  277      * leave the trailing bytes (if there are any) for later */
  278 
  279     for (point=buffer; inlen>=3; inlen-=3, text+=3) {
  280     *(point++) = b64_alphabet[ (*text)>>2 ]; 
  281     *(point++) = b64_alphabet[ ((*text)<<4 & 0x30) | (*(text+1))>>4 ]; 
  282     *(point++) = b64_alphabet[ ((*(text+1))<<2 & 0x3c) | (*(text+2))>>6 ];
  283     *(point++) = b64_alphabet[ (*(text+2)) & 0x3f ];
  284     }
  285 
  286     /* Now deal with the trailing bytes */
  287     if (inlen > 0) {
  288     /* We always have one trailing byte */
  289     *(point++) = b64_alphabet[ (*text)>>2 ];
  290     *(point++) = b64_alphabet[ (((*text)<<4 & 0x30) |
  291                      (inlen==2?(*(text+1))>>4:0)) ]; 
  292     *(point++) = (inlen==1?'=':b64_alphabet[ (*(text+1))<<2 & 0x3c ]);
  293     *(point++) = '=';
  294     }
  295 
  296     /* Null-terminate */
  297     *point = '\0';
  298 
  299     return buffer;
  300 }
  301 
  302 /* VALID_B64: fail if 'ch' is not a valid base64 character */
  303 #define VALID_B64(ch) (((ch) >= 'A' && (ch) <= 'Z') || \
  304                        ((ch) >= 'a' && (ch) <= 'z') || \
  305                        ((ch) >= '0' && (ch) <= '9') || \
  306                        (ch) == '/' || (ch) == '+' || (ch) == '=')
  307 
  308 /* DECODE_B64: decodes a valid base64 character. */
  309 #define DECODE_B64(ch) ((ch) >= 'a' ? ((ch) + 26 - 'a') : \
  310                         ((ch) >= 'A' ? ((ch) - 'A') : \
  311                          ((ch) >= '0' ? ((ch) + 52 - '0') : \
  312                           ((ch) == '+' ? 62 : 63))))
  313 
  314 size_t ne_unbase64(const char *data, unsigned char **out)
  315 {
  316     size_t inlen = strlen(data);
  317     unsigned char *outp;
  318     const unsigned char *in;
  319 
  320     if (inlen == 0 || (inlen % 4) != 0) return 0;
  321     
  322     outp = *out = ne_malloc(inlen * 3 / 4);
  323 
  324     for (in = (const unsigned char *)data; *in; in += 4) {
  325         unsigned int tmp;
  326         if (!VALID_B64(in[0]) || !VALID_B64(in[1]) || !VALID_B64(in[2]) ||
  327             !VALID_B64(in[3]) || in[0] == '=' || in[1] == '=' ||
  328             (in[2] == '=' && in[3] != '=')) {
  329             ne_free(*out);
  330             return 0;
  331         }
  332         tmp = (DECODE_B64(in[0]) & 0x3f) << 18 |
  333             (DECODE_B64(in[1]) & 0x3f) << 12;
  334         *outp++ = (tmp >> 16) & 0xff;
  335         if (in[2] != '=') {
  336             tmp |= (DECODE_B64(in[2]) & 0x3f) << 6;
  337             *outp++ = (tmp >> 8) & 0xff;
  338             if (in[3] != '=') {
  339                 tmp |= DECODE_B64(in[3]) & 0x3f;
  340                 *outp++ = tmp & 0xff;
  341             }
  342         }
  343     }
  344 
  345     return outp - *out;
  346 }
  347 
  348 /* Character map array; array[n] = isprint(n) ? 0x20 : n.  Used by
  349  * ne_strclean as a locale-independent isprint(). */
  350 static const unsigned char ascii_printable[256] = {
  351     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  352     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  353     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  354     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  355     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 
  356     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 
  357     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 
  358     0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 
  359     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 
  360     0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 
  361     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 
  362     0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 
  363     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 
  364     0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 
  365     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 
  366     0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x20, 
  367     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  368     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  369     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  370     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  371     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  372     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  373     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  374     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  375     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  376     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  377     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  378     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  379     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  380     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  381     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 
  382     0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
  383 };
  384 
  385 char *ne_strclean(char *str)
  386 {
  387     unsigned char *pnt;
  388 
  389     for (pnt = (unsigned char *)str; *pnt; pnt++)
  390         *pnt = (char)ascii_printable[*pnt];
  391 
  392     return str;
  393 }
  394 
  395 char *ne_strerror(int errnum, char *buf, size_t buflen)
  396 {
  397 #ifdef HAVE_STRERROR_R
  398 #ifdef STRERROR_R_CHAR_P
  399     /* glibc-style strerror_r which may-or-may-not use provided buffer. */
  400     char *ret = strerror_r(errnum, buf, buflen);
  401     if (ret != buf)
  402     ne_strnzcpy(buf, ret, buflen);
  403 #else /* POSIX-style strerror_r: */
  404     char tmp[256];
  405 
  406     if (strerror_r(errnum, tmp, sizeof tmp) == 0)
  407         ne_strnzcpy(buf, tmp, buflen);
  408     else
  409         ne_snprintf(buf, buflen, "Unknown error %d", errnum);
  410 #endif
  411 #else /* no strerror_r: */
  412     ne_strnzcpy(buf, strerror(errnum), buflen);
  413 #endif
  414     return buf;
  415 }
  416 
  417 
  418 /* Wrapper for ne_snprintf. */
  419 size_t ne_snprintf(char *str, size_t size, const char *fmt, ...)
  420 {
  421     va_list ap;
  422     va_start(ap, fmt);
  423 #ifdef HAVE_TRIO
  424     trio_vsnprintf(str, size, fmt, ap);
  425 #else
  426     vsnprintf(str, size, fmt, ap);
  427 #endif
  428     va_end(ap);
  429     str[size-1] = '\0';
  430     return strlen(str);
  431 }
  432 
  433 /* Wrapper for ne_vsnprintf. */
  434 size_t ne_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
  435 {
  436 #ifdef HAVE_TRIO
  437     trio_vsnprintf(str, size, fmt, ap);
  438 #else
  439     vsnprintf(str, size, fmt, ap);
  440 #endif
  441     str[size-1] = '\0';
  442     return strlen(str);
  443 }
  444 
  445 /* Locale-independent strcasecmp implementations. */
  446 static const unsigned char ascii_tolower[256] = {
  447 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  448 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
  449 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
  450 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
  451 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
  452 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
  453 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
  454 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
  455 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
  456 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
  457 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
  458 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
  459 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
  460 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
  461 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
  462 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
  463 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
  464 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
  465 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
  466 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
  467 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
  468 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
  469 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
  470 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
  471 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
  472 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
  473 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
  474 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
  475 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
  476 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
  477 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
  478 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
  479 };    
  480 
  481 #define TOLOWER(ch) ascii_tolower[ch]
  482 
  483 const unsigned char *ne_tolower_array(void)
  484 {
  485     return ascii_tolower;
  486 }
  487 
  488 int ne_strcasecmp(const char *s1, const char *s2)
  489 {
  490     const unsigned char *p1 = (const unsigned char *) s1;
  491     const unsigned char *p2 = (const unsigned char *) s2;
  492     unsigned char c1, c2;
  493 
  494     if (p1 == p2)
  495         return 0;
  496     
  497     do {
  498         c1 = TOLOWER(*p1++);
  499         c2 = TOLOWER(*p2++);
  500         if (c1 == '\0')
  501             break;
  502     } while (c1 == c2);
  503     
  504     return c1 - c2;
  505 }
  506 
  507 int ne_strncasecmp(const char *s1, const char *s2, size_t n)
  508 {
  509     const unsigned char *p1 = (const unsigned char *) s1;
  510     const unsigned char *p2 = (const unsigned char *) s2;
  511     unsigned char c1, c2;
  512     
  513     if (p1 == p2 || n == 0)
  514         return 0;
  515     
  516     do {
  517         c1 = TOLOWER(*p1++);
  518         c2 = TOLOWER(*p2++);
  519         if (c1 == '\0' || c1 != c2)
  520             return c1 - c2;
  521     } while (--n > 0);
  522     
  523     return c1 - c2;
  524 }