Diff for /embedaddon/lighttpd/src/buffer.c between versions 1.1 and 1.1.1.3

version 1.1, 2013/10/14 10:32:47 version 1.1.1.3, 2016/11/02 10:35:00
Line 1 Line 1
   #include "first.h"
   
 #include "buffer.h"  #include "buffer.h"
   
 #include <stdlib.h>  #include <stdlib.h>
Line 7 Line 9
 #include <assert.h>  #include <assert.h>
 #include <ctype.h>  #include <ctype.h>
   
 #if defined HAVE_STDINT_H  
 # include <stdint.h>  
 #elif defined HAVE_INTTYPES_H  
 # include <inttypes.h>  
 #endif  
   
 static const char hex_chars[] = "0123456789abcdef";  static const char hex_chars[] = "0123456789abcdef";
   
   
 /**  /**
  * init the buffer   * init the buffer
  *   *
Line 25  buffer* buffer_init(void) { Line 20  buffer* buffer_init(void) {
         buffer *b;          buffer *b;
   
         b = malloc(sizeof(*b));          b = malloc(sizeof(*b));
        assert(b);        force_assert(b);
   
         b->ptr = NULL;          b->ptr = NULL;
         b->size = 0;          b->size = 0;
Line 34  buffer* buffer_init(void) { Line 29  buffer* buffer_init(void) {
         return b;          return b;
 }  }
   
buffer *buffer_init_buffer(buffer *src) {buffer *buffer_init_buffer(const buffer *src) {
         buffer *b = buffer_init();          buffer *b = buffer_init();
        buffer_copy_string_buffer(b, src);        buffer_copy_buffer(b, src);
         return b;          return b;
 }  }
   
/**buffer *buffer_init_string(const char *str) {
 * free the buffer        buffer *b = buffer_init();
 *        buffer_copy_string(b, str);
 */        return b;
 }
   
 void buffer_free(buffer *b) {  void buffer_free(buffer *b) {
        if (!b) return;        if (NULL == b) return;
   
         free(b->ptr);          free(b->ptr);
         free(b);          free(b);
 }  }
   
 void buffer_reset(buffer *b) {  void buffer_reset(buffer *b) {
        if (!b) return;        if (NULL == b) return;
   
         /* limit don't reuse buffer larger than ... bytes */          /* limit don't reuse buffer larger than ... bytes */
         if (b->size > BUFFER_MAX_REUSE_SIZE) {          if (b->size > BUFFER_MAX_REUSE_SIZE) {
                 free(b->ptr);                  free(b->ptr);
                 b->ptr = NULL;                  b->ptr = NULL;
                 b->size = 0;                  b->size = 0;
        } else if (b->size) {        } else if (b->size > 0) {
                 b->ptr[0] = '\0';                  b->ptr[0] = '\0';
         }          }
   
         b->used = 0;          b->used = 0;
 }  }
   
   void buffer_move(buffer *b, buffer *src) {
           buffer tmp;
   
/**        if (NULL == b) {
 *                buffer_reset(src);
 * allocate (if neccessary) enough space for 'size' bytes and                return;
 * set the 'used' counter to 0        }
 *        buffer_reset(b);
 */        if (NULL == src) return;
   
           tmp = *src; *src = *b; *b = tmp;
   }
   
 #define BUFFER_PIECE_SIZE 64  #define BUFFER_PIECE_SIZE 64
   static size_t buffer_align_size(size_t size) {
           size_t align = BUFFER_PIECE_SIZE - (size % BUFFER_PIECE_SIZE);
           /* overflow on unsinged size_t is defined to wrap around */
           if (size + align < size) return size;
           return size + align;
   }
   
int buffer_prepare_copy(buffer *b, size_t size) {/* make sure buffer is at least "size" big. discard old data */
        if (!b) return -1;static void buffer_alloc(buffer *b, size_t size) {
         force_assert(NULL != b);
         if (0 == size) size = 1;
   
        if ((0 == b->size) ||        if (size <= b->size) return;
            (size > b->size)) { 
                if (b->size) free(b->ptr); 
   
                b->size = size;        if (NULL != b->ptr) free(b->ptr);
   
                 /* always allocate a multiply of BUFFER_PIECE_SIZE */  
                 b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);  
   
                 b->ptr = malloc(b->size);  
                 assert(b->ptr);  
         }  
         b->used = 0;          b->used = 0;
        return 0;        b->size = buffer_align_size(size);
         b->ptr = malloc(b->size);
 
         force_assert(NULL != b->ptr);
 }  }
   
/**/* make sure buffer is at least "size" big. keep old data */
 *static void buffer_realloc(buffer *b, size_t size) {
 * increase the internal buffer (if neccessary) to append another 'size' byte        force_assert(NULL != b);
 * ->used isn't changed        if (0 == size) size = 1;
 * 
 */ 
   
int buffer_prepare_append(buffer *b, size_t size) {        if (size <= b->size) return;
        if (!b) return -1; 
   
        if (0 == b->size) {        b->size = buffer_align_size(size);
                b->size = size;        b->ptr = realloc(b->ptr, b->size);
   
                /* always allocate a multiply of BUFFER_PIECE_SIZE */        force_assert(NULL != b->ptr);
                b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);}
   
                 b->ptr = malloc(b->size);  
                 b->used = 0;  
                 assert(b->ptr);  
         } else if (b->used + size > b->size) {  
                 b->size += size;  
   
                /* always allocate a multiply of BUFFER_PIECE_SIZE */char* buffer_string_prepare_copy(buffer *b, size_t size) {
                b->size += BUFFER_PIECE_SIZE - (b->size % BUFFER_PIECE_SIZE);        force_assert(NULL != b);
         force_assert(size + 1 > size);
   
                b->ptr = realloc(b->ptr, b->size);        buffer_alloc(b, size + 1);
                assert(b->ptr); 
        } 
        return 0; 
} 
   
int buffer_copy_string(buffer *b, const char *s) {        b->used = 1;
        size_t s_len;        b->ptr[0] = '\0';
   
        if (!s || !b) return -1;        return b->ptr;
 }
   
        s_len = strlen(s) + 1;char* buffer_string_prepare_append(buffer *b, size_t size) {
        buffer_prepare_copy(b, s_len);        force_assert(NULL !=  b);
   
        memcpy(b->ptr, s, s_len);        if (buffer_string_is_empty(b)) {
        b->used = s_len;                return buffer_string_prepare_copy(b, size);
         } else {
                 size_t req_size = b->used + size;
   
        return 0;                /* not empty, b->used already includes a terminating 0 */
}                force_assert(req_size >= b->used);
   
int buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {                /* check for overflow: unsigned overflow is defined to wrap around */
        if (!s || !b) return -1;                force_assert(req_size >= b->used);
#if 0 
        /* removed optimization as we have to keep the empty string 
         * in some cases for the config handling 
         * 
         * url.access-deny = ( "" ) 
         */ 
        if (s_len == 0) return 0; 
#endif 
        buffer_prepare_copy(b, s_len + 1); 
   
        memcpy(b->ptr, s, s_len);                buffer_realloc(b, req_size);
        b->ptr[s_len] = '\0'; 
        b->used = s_len + 1; 
   
        return 0;                return b->ptr + b->used - 1;
         }
 }  }
   
int buffer_copy_string_buffer(buffer *b, const buffer *src) {void buffer_string_set_length(buffer *b, size_t len) {
        if (!src) return -1;        force_assert(NULL != b);
         force_assert(len + 1 > len);
   
        if (src->used == 0) {        buffer_realloc(b, len + 1);
                buffer_reset(b);
                return 0;        b->used = len + 1;
        }        b->ptr[len] = '\0';
        return buffer_copy_string_len(b, src->ptr, src->used - 1); 
 }  }
   
int buffer_append_string(buffer *b, const char *s) {void buffer_commit(buffer *b, size_t size)
        size_t s_len;{
         force_assert(NULL != b);
         force_assert(b->size > 0);
   
        if (!s || !b) return -1;        if (0 == b->used) b->used = 1;
   
        s_len = strlen(s);        if (size > 0) {
        buffer_prepare_append(b, s_len + 1);                /* check for overflow: unsigned overflow is defined to wrap around */
        if (b->used == 0)                force_assert(b->used + size > b->used);
                b->used++; 
   
        memcpy(b->ptr + b->used - 1, s, s_len + 1);                force_assert(b->used + size <= b->size);
        b->used += s_len;                b->used += size;
         }
   
        return 0;        b->ptr[b->used - 1] = '\0';
 }  }
   
int buffer_append_string_rfill(buffer *b, const char *s, size_t maxlen) {void buffer_copy_string(buffer *b, const char *s) {
        size_t s_len;        buffer_copy_string_len(b, s, NULL != s ? strlen(s) : 0);
 }
   
        if (!s || !b) return -1;void buffer_copy_string_len(buffer *b, const char *s, size_t s_len) {
         force_assert(NULL != b);
         force_assert(NULL != s || s_len == 0);
   
        s_len = strlen(s);        buffer_string_prepare_copy(b, s_len);
        if (s_len > maxlen)  s_len = maxlen; 
        buffer_prepare_append(b, maxlen + 1); 
        if (b->used == 0) 
                b->used++; 
   
        memcpy(b->ptr + b->used - 1, s, s_len);        if (0 != s_len) memcpy(b->ptr, s, s_len);
        if (maxlen > s_len) {
                memset(b->ptr + b->used - 1 + s_len, ' ', maxlen - s_len);        buffer_commit(b, s_len);
 }
 
 void buffer_copy_buffer(buffer *b, const buffer *src) {
         if (NULL == src || 0 == src->used) {
                 buffer_string_prepare_copy(b, 0);
                 b->used = 0; /* keep special empty state for now */
         } else {
                 buffer_copy_string_len(b, src->ptr, buffer_string_length(src));
         }          }
   }
   
        b->used += maxlen;void buffer_append_string(buffer *b, const char *s) {
        b->ptr[b->used - 1] = '\0';        buffer_append_string_len(b, s, NULL != s ? strlen(s) : 0);
        return 0; 
 }  }
   
 /**  /**
Line 218  int buffer_append_string_rfill(buffer *b, const char * Line 213  int buffer_append_string_rfill(buffer *b, const char *
  * @param s_len size of the string (without the terminating \0)   * @param s_len size of the string (without the terminating \0)
  */   */
   
int buffer_append_string_len(buffer *b, const char *s, size_t s_len) {void buffer_append_string_len(buffer *b, const char *s, size_t s_len) {
        if (!s || !b) return -1;        char *target_buf;
        if (s_len == 0) return 0; 
   
        buffer_prepare_append(b, s_len + 1);        force_assert(NULL != b);
        if (b->used == 0)        force_assert(NULL != s || s_len == 0);
                b->used++; 
   
        memcpy(b->ptr + b->used - 1, s, s_len);        target_buf = buffer_string_prepare_append(b, s_len);
        b->used += s_len; 
        b->ptr[b->used - 1] = '\0'; 
   
        return 0;        if (0 == s_len) return; /* nothing to append */
} 
   
int buffer_append_string_buffer(buffer *b, const buffer *src) {        memcpy(target_buf, s, s_len);
        if (!src) return -1; 
        if (src->used == 0) return 0; 
   
        return buffer_append_string_len(b, src->ptr, src->used - 1);        buffer_commit(b, s_len);
 }  }
   
int buffer_append_memory(buffer *b, const char *s, size_t s_len) {void buffer_append_string_buffer(buffer *b, const buffer *src) {
        if (!s || !b) return -1;        if (NULL == src) {
        if (s_len == 0) return 0;                buffer_append_string_len(b, NULL, 0);
        } else {
        buffer_prepare_append(b, s_len);                buffer_append_string_len(b, src->ptr, buffer_string_length(src));
        memcpy(b->ptr + b->used, s, s_len);        }
        b->used += s_len; 
 
        return 0; 
 }  }
   
int buffer_copy_memory(buffer *b, const char *s, size_t s_len) {void buffer_append_uint_hex(buffer *b, uintmax_t value) {
        if (!s || !b) return -1; 
 
        b->used = 0; 
 
        return buffer_append_memory(b, s, s_len); 
} 
 
int buffer_append_long_hex(buffer *b, unsigned long value) { 
         char *buf;          char *buf;
         int shift = 0;          int shift = 0;
         unsigned long copy = value;  
   
        while (copy) {        {
                copy >>= 4;                uintmax_t copy = value;
                shift++;                do {
                         copy >>= 8;
                         shift += 2; /* counting nibbles (4 bits) */
                 } while (0 != copy);
         }          }
         if (shift == 0)  
                 shift++;  
         if (shift & 0x01)  
                 shift++;  
   
        buffer_prepare_append(b, shift + 1);        buf = buffer_string_prepare_append(b, shift);
        if (b->used == 0)        buffer_commit(b, shift); /* will fill below */
                b->used++; 
        buf = b->ptr + (b->used - 1); 
        b->used += shift; 
   
        shift <<= 2;        shift <<= 2; /* count bits now */
         while (shift > 0) {          while (shift > 0) {
                 shift -= 4;                  shift -= 4;
                 *(buf++) = hex_chars[(value >> shift) & 0x0F];                  *(buf++) = hex_chars[(value >> shift) & 0x0F];
         }          }
        *buf = '\0';}
   
        return 0;static char* utostr(char * const buf_end, uintmax_t val) {
         char *cur = buf_end;
         do {
                 int mod = val % 10;
                 val /= 10;
                 /* prepend digit mod */
                 *(--cur) = (char) ('0' + mod);
         } while (0 != val);
         return cur;
 }  }
   
int LI_ltostr(char *buf, long val) {static char* itostr(char * const buf_end, intmax_t val) {
        char swap;        /* absolute value not defined for INTMAX_MIN, but can take absolute
        char *end;         * value of any negative number via twos complement cast to unsigned.
        int len = 1;         * negative sign is prepended after (now unsigned) value is converted
          * to string */
         uintmax_t uval = val >= 0 ? (uintmax_t)val : ((uintmax_t)~val) + 1;
         char *cur = utostr(buf_end, uval);
         if (val < 0) *(--cur) = '-';
   
        if (val < 0) {        return cur;
                len++;}
                *(buf++) = '-'; 
                val = -val; 
        } 
   
        end = buf;void buffer_append_int(buffer *b, intmax_t val) {
        while (val > 9) {        char buf[LI_ITOSTRING_LENGTH];
                *(end++) = '0' + (val % 10);        char* const buf_end = buf + sizeof(buf);
                val = val / 10;        char *str;
        } 
        *(end) = '0' + val; 
        *(end + 1) = '\0'; 
        len += end - buf; 
   
        while (buf < end) {        force_assert(NULL != b);
                swap = *end; 
                *end = *buf; 
                *buf = swap; 
   
                buf++;        str = itostr(buf_end, val);
                end--;        force_assert(buf_end > str && str >= buf);
        } 
   
        return len;        buffer_append_string_len(b, str, buf_end - str);
 }  }
   
int buffer_append_long(buffer *b, long val) {void buffer_copy_int(buffer *b, intmax_t val) {
        if (!b) return -1;        force_assert(NULL != b);
   
         buffer_prepare_append(b, 32);  
         if (b->used == 0)  
                 b->used++;  
   
         b->used += LI_ltostr(b->ptr + (b->used - 1), val);  
         return 0;  
 }  
   
 int buffer_copy_long(buffer *b, long val) {  
         if (!b) return -1;  
   
         b->used = 0;          b->used = 0;
        return buffer_append_long(b, val);        buffer_append_int(b, val);
 }  }
   
#if !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T)void buffer_append_strftime(buffer *b, const char *format, const struct tm *tm) {
int buffer_append_off_t(buffer *b, off_t val) {        size_t r;
        char swap;        char* buf;
        char *end;        force_assert(NULL != b);
        char *start;        force_assert(NULL != tm);
        int len = 1; 
   
        if (!b) return -1;        if (NULL == format || '\0' == format[0]) {
                 /* empty format */
                 buffer_string_prepare_append(b, 0);
                 return;
         }
   
        buffer_prepare_append(b, 32);        buf = buffer_string_prepare_append(b, 255);
        if (b->used == 0)        r = strftime(buf, buffer_string_space(b), format, tm);
                b->used++; 
   
        start = b->ptr + (b->used - 1);        /* 0 (in some apis buffer_string_space(b)) signals the string may have
        if (val < 0) {         * been too small; but the format could also just have lead to an empty
                len++;         * string
                *(start++) = '-';         */
                val = -val;        if (0 == r || r >= buffer_string_space(b)) {
                 /* give it a second try with a larger string */
                 buf = buffer_string_prepare_append(b, 4095);
                 r = strftime(buf, buffer_string_space(b), format, tm);
         }          }
   
        end = start;        if (r >= buffer_string_space(b)) r = 0;
        while (val > 9) { 
                *(end++) = '0' + (val % 10); 
                val = val / 10; 
        } 
        *(end) = '0' + val; 
        *(end + 1) = '\0'; 
        len += end - start; 
   
        while (start < end) {        buffer_commit(b, r);
                swap   = *end;}
                *end   = *start; 
                *start = swap; 
   
                 start++;  
                 end--;  
         }  
   
        b->used += len;void li_itostrn(char *buf, size_t buf_len, intmax_t val) {
        return 0;        char p_buf[LI_ITOSTRING_LENGTH];
         char* const p_buf_end = p_buf + sizeof(p_buf);
         char* str = p_buf_end - 1;
         *str = '\0';
 
         str = itostr(str, val);
         force_assert(p_buf_end > str && str >= p_buf);
 
         force_assert(buf_len >= (size_t) (p_buf_end - str));
         memcpy(buf, str, p_buf_end - str);
 }  }
   
int buffer_copy_off_t(buffer *b, off_t val) {void li_utostrn(char *buf, size_t buf_len, uintmax_t val) {
        if (!b) return -1;        char p_buf[LI_ITOSTRING_LENGTH];
         char* const p_buf_end = p_buf + sizeof(p_buf);
         char* str = p_buf_end - 1;
         *str = '\0';
   
        b->used = 0;        str = utostr(str, val);
        return buffer_append_off_t(b, val);        force_assert(p_buf_end > str && str >= p_buf);
 
         force_assert(buf_len >= (size_t) (p_buf_end - str));
         memcpy(buf, str, p_buf_end - str);
 }  }
 #endif /* !defined(SIZEOF_LONG) || (SIZEOF_LONG != SIZEOF_OFF_T) */  
   
 char int2hex(char c) {  char int2hex(char c) {
         return hex_chars[(c & 0x0F)];          return hex_chars[(c & 0x0F)];
Line 397  char int2hex(char c) { Line 366  char int2hex(char c) {
  * returns 0xFF on invalid input.   * returns 0xFF on invalid input.
  */   */
 char hex2int(unsigned char hex) {  char hex2int(unsigned char hex) {
        hex = hex - '0';        unsigned char value = hex - '0';
        if (hex > 9) {        if (value > 9) {
                hex = (hex + '0' - 1) | 0x20;                hex |= 0x20; /* to lower case */
                hex = hex - 'a' + 11;                value = hex - 'a' + 10;
                 if (value < 10) value = 0xff;
         }          }
        if (hex > 15)        if (value > 15) value = 0xff;
                hex = 0xFF; 
   
        return hex;        return value;
 }  }
   
   
 /**  
  * init the buffer  
  *  
  */  
   
 buffer_array* buffer_array_init(void) {  
         buffer_array *b;  
   
         b = malloc(sizeof(*b));  
   
         assert(b);  
         b->ptr = NULL;  
         b->size = 0;  
         b->used = 0;  
   
         return b;  
 }  
   
 void buffer_array_reset(buffer_array *b) {  
         size_t i;  
   
         if (!b) return;  
   
         /* if they are too large, reduce them */  
         for (i = 0; i < b->used; i++) {  
                 buffer_reset(b->ptr[i]);  
         }  
   
         b->used = 0;  
 }  
   
   
 /**  
  * free the buffer_array  
  *  
  */  
   
 void buffer_array_free(buffer_array *b) {  
         size_t i;  
         if (!b) return;  
   
         for (i = 0; i < b->size; i++) {  
                 if (b->ptr[i]) buffer_free(b->ptr[i]);  
         }  
         free(b->ptr);  
         free(b);  
 }  
   
 buffer *buffer_array_append_get_buffer(buffer_array *b) {  
         size_t i;  
   
         if (b->size == 0) {  
                 b->size = 16;  
                 b->ptr = malloc(sizeof(*b->ptr) * b->size);  
                 assert(b->ptr);  
                 for (i = 0; i < b->size; i++) {  
                         b->ptr[i] = NULL;  
                 }  
         } else if (b->size == b->used) {  
                 b->size += 16;  
                 b->ptr = realloc(b->ptr, sizeof(*b->ptr) * b->size);  
                 assert(b->ptr);  
                 for (i = b->used; i < b->size; i++) {  
                         b->ptr[i] = NULL;  
                 }  
         }  
   
         if (b->ptr[b->used] == NULL) {  
                 b->ptr[b->used] = buffer_init();  
         }  
   
         b->ptr[b->used]->used = 0;  
   
         return b->ptr[b->used++];  
 }  
   
   
 char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {  char * buffer_search_string_len(buffer *b, const char *needle, size_t len) {
         size_t i;          size_t i;
        if (len == 0) return NULL;        force_assert(NULL != b);
        if (needle == NULL) return NULL;        force_assert(0 != len && NULL != needle); /* empty needles not allowed */
   
         if (b->used < len) return NULL;          if (b->used < len) return NULL;
   
Line 502  char * buffer_search_string_len(buffer *b, const char  Line 393  char * buffer_search_string_len(buffer *b, const char 
         return NULL;          return NULL;
 }  }
   
buffer *buffer_init_string(const char *str) {int buffer_is_empty(const buffer *b) {
        buffer *b = buffer_init();        return NULL == b || 0 == b->used;
 
        buffer_copy_string(b, str); 
 
        return b; 
 }  }
   
int buffer_is_empty(buffer *b) {int buffer_string_is_empty(const buffer *b) {
        if (!b) return 1;        return 0 == buffer_string_length(b);
        return (b->used == 0); 
 }  }
   
 /**  /**
Line 522  int buffer_is_empty(buffer *b) { Line 408  int buffer_is_empty(buffer *b) {
  * alignment properly.   * alignment properly.
  */   */
   
int buffer_is_equal(buffer *a, buffer *b) {int buffer_is_equal(const buffer *a, const buffer *b) {
         force_assert(NULL != a && NULL != b);
 
         if (a->used != b->used) return 0;          if (a->used != b->used) return 0;
         if (a->used == 0) return 1;          if (a->used == 0) return 1;
   
        return (0 == strcmp(a->ptr, b->ptr));        return (0 == memcmp(a->ptr, b->ptr, a->used));
 }  }
   
int buffer_is_equal_string(buffer *a, const char *s, size_t b_len) {int buffer_is_equal_string(const buffer *a, const char *s, size_t b_len) {
        buffer b;        force_assert(NULL != a && NULL != s);
         force_assert(b_len + 1 > b_len);
   
        b.ptr = (char *)s;        if (a->used != b_len + 1) return 0;
        b.used = b_len + 1;        if (0 != memcmp(a->ptr, s, b_len)) return 0;
         if ('\0' != a->ptr[a->used-1]) return 0;
   
        return buffer_is_equal(a, &b);        return 1;
 }  }
   
 /* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */  /* buffer_is_equal_caseless_string(b, CONST_STR_LEN("value")) */
int buffer_is_equal_caseless_string(buffer *a, const char *s, size_t b_len) {int buffer_is_equal_caseless_string(const buffer *a, const char *s, size_t b_len) {
         force_assert(NULL != a);
         if (a->used != b_len + 1) return 0;          if (a->used != b_len + 1) return 0;
           force_assert('\0' == a->ptr[a->used - 1]);
   
         return (0 == strcasecmp(a->ptr, s));          return (0 == strcasecmp(a->ptr, s));
 }  }
Line 554  int buffer_caseless_compare(const char *a, size_t a_le Line 446  int buffer_caseless_compare(const char *a, size_t a_le
                 if (ca == cb) continue;                  if (ca == cb) continue;
   
                 /* always lowercase for transitive results */                  /* always lowercase for transitive results */
 #if 1  
                 if (ca >= 'A' && ca <= 'Z') ca |= 32;                  if (ca >= 'A' && ca <= 'Z') ca |= 32;
                 if (cb >= 'A' && cb <= 'Z') cb |= 32;                  if (cb >= 'A' && cb <= 'Z') cb |= 32;
 #else  
                 /* try to produce code without branching (jumps) */  
                 ca |= ((unsigned char)(ca - (unsigned char)'A') <= (unsigned char)('Z' - 'A')) ? 32 : 0;  
                 cb |= ((unsigned char)(cb - (unsigned char)'A') <= (unsigned char)('Z' - 'A')) ? 32 : 0;  
 #endif  
   
                 if (ca == cb) continue;                  if (ca == cb) continue;
                return ca - cb;                return ((int)ca) - ((int)cb);
         }          }
         if (a_len == b_len) return 0;          if (a_len == b_len) return 0;
        return a_len - b_len;        return a_len < b_len ? -1 : 1;
 }  }
   
/**int buffer_is_equal_right_len(const buffer *b1, const buffer *b2, size_t len) {
 * check if the rightmost bytes of the string are equal.        /* no len -> equal */
 * 
 * 
 */ 
 
int buffer_is_equal_right_len(buffer *b1, buffer *b2, size_t len) { 
        /* no, len -> equal */ 
         if (len == 0) return 1;          if (len == 0) return 1;
   
         /* len > 0, but empty buffers -> not equal */          /* len > 0, but empty buffers -> not equal */
         if (b1->used == 0 || b2->used == 0) return 0;          if (b1->used == 0 || b2->used == 0) return 0;
   
         /* buffers too small -> not equal */          /* buffers too small -> not equal */
        if (b1->used - 1 < len || b1->used - 1 < len) return 0;        if (b1->used - 1 < len || b2->used - 1 < len) return 0;
   
        if (0 == strncmp(b1->ptr + b1->used - 1 - len,        return 0 == memcmp(b1->ptr + b1->used - 1 - len, b2->ptr + b2->used - 1 - len, len);
                         b2->ptr + b2->used - 1 - len, len)) { 
                return 1; 
        } 
 
        return 0; 
 }  }
   
int buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {void li_tohex(char *buf, size_t buf_len, const char *s, size_t s_len) {
         size_t i;          size_t i;
           force_assert(2 * s_len > s_len);
           force_assert(2 * s_len < buf_len);
   
        /* BO protection */        for (i = 0; i < s_len; i++) {
        if (in_len * 2 < in_len) return -1;                buf[2*i] = hex_chars[(s[i] >> 4) & 0x0F];
                buf[2*i+1] = hex_chars[s[i] & 0x0F];
        buffer_prepare_copy(b, in_len * 2 + 1); 
 
        for (i = 0; i < in_len; i++) { 
                b->ptr[b->used++] = hex_chars[(in[i] >> 4) & 0x0F]; 
                b->ptr[b->used++] = hex_chars[in[i] & 0x0F]; 
         }          }
        b->ptr[b->used++] = '\0';        buf[2*s_len] = '\0';
 }
   
        return 0;void buffer_copy_string_hex(buffer *b, const char *in, size_t in_len) {
         /* overflow protection */
         force_assert(in_len * 2 > in_len);
 
         buffer_string_set_length(b, 2 * in_len);
         li_tohex(b->ptr, buffer_string_length(b)+1, in, in_len);
 }  }
   
 /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */  /* everything except: ! ( ) * - . 0-9 A-Z _ a-z */
Line 623  static const char encoded_chars_rel_uri_part[] = { Line 501  static const char encoded_chars_rel_uri_part[] = {
         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */          1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */          1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,  /*  70 -  7F { | } DEL */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
Line 646  static const char encoded_chars_rel_uri[] = { Line 524  static const char encoded_chars_rel_uri[] = {
         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */          1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F @ */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  50 -  5F [ \ ] ^ */
         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */          1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,  /*  70 -  7F { | } ~ DEL */        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,  /*  70 -  7F { | } DEL */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  A0 -  AF */
Line 663  static const char encoded_chars_html[] = { Line 541  static const char encoded_chars_html[] = {
         */          */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
        0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */        0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F " & ' */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  80 -  8F */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  90 -  9F */
Line 685  static const char encoded_chars_minimal_xml[] = { Line 563  static const char encoded_chars_minimal_xml[] = {
         */          */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  00 -  0F control chars */
         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */          1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /*  10 -  1F */
        0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F & */        0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,  /*  20 -  2F " & ' */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  30 -  3F < > */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  40 -  4F */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  50 -  5F */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F */        1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  60 -  6F ` */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,  /*  70 -  7F DEL */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  80 -  8F */
         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  90 -  9F */
Line 747  static const char encoded_chars_http_header[] = { Line 625  static const char encoded_chars_http_header[] = {
   
   
   
int buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {void buffer_append_string_encoded(buffer *b, const char *s, size_t s_len, buffer_encoding_t encoding) {
         unsigned char *ds, *d;          unsigned char *ds, *d;
         size_t d_len, ndx;          size_t d_len, ndx;
         const char *map = NULL;          const char *map = NULL;
   
        if (!s || !b) return -1;        force_assert(NULL != b);
         force_assert(NULL != s || 0 == s_len);
   
        if (b->ptr[b->used - 1] != '\0') {        if (0 == s_len) return;
                SEGFAULT(); 
        } 
   
         if (s_len == 0) return 0;  
   
         switch(encoding) {          switch(encoding) {
         case ENCODING_REL_URI:          case ENCODING_REL_URI:
                 map = encoded_chars_rel_uri;                  map = encoded_chars_rel_uri;
Line 779  int buffer_append_string_encoded(buffer *b, const char Line 654  int buffer_append_string_encoded(buffer *b, const char
         case ENCODING_HTTP_HEADER:          case ENCODING_HTTP_HEADER:
                 map = encoded_chars_http_header;                  map = encoded_chars_http_header;
                 break;                  break;
         case ENCODING_UNSET:  
                 break;  
         }          }
   
        assert(map != NULL);        force_assert(NULL != map);
   
         /* count to-be-encoded-characters */          /* count to-be-encoded-characters */
         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {          for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
Line 801  int buffer_append_string_encoded(buffer *b, const char Line 674  int buffer_append_string_encoded(buffer *b, const char
                         case ENCODING_HEX:                          case ENCODING_HEX:
                                 d_len += 2;                                  d_len += 2;
                                 break;                                  break;
                         case ENCODING_UNSET:  
                                 break;  
                         }                          }
                 } else {                  } else {
                        d_len ++;                        d_len++;
                 }                  }
         }          }
   
        buffer_prepare_append(b, d_len);        d = (unsigned char*) buffer_string_prepare_append(b, d_len);
         buffer_commit(b, d_len); /* fill below */
         force_assert('\0' == *d);
   
        for (ds = (unsigned char *)s, d = (unsigned char *)b->ptr + b->used - 1, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {        for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
                 if (map[*ds]) {                  if (map[*ds]) {
                         switch(encoding) {                          switch(encoding) {
                         case ENCODING_REL_URI:                          case ENCODING_REL_URI:
Line 837  int buffer_append_string_encoded(buffer *b, const char Line 710  int buffer_append_string_encoded(buffer *b, const char
                                 d[d_len++] = *ds;                                  d[d_len++] = *ds;
                                 d[d_len++] = '\t';                                  d[d_len++] = '\t';
                                 break;                                  break;
                         case ENCODING_UNSET:  
                                 break;  
                         }                          }
                 } else {                  } else {
                         d[d_len++] = *ds;                          d[d_len++] = *ds;
                 }                  }
         }          }
   }
   
        /* terminate buffer and calculate new length */void buffer_append_string_c_escaped(buffer *b, const char *s, size_t s_len) {
        b->ptr[b->used + d_len - 1] = '\0';        unsigned char *ds, *d;
         size_t d_len, ndx;
   
        b->used += d_len;        force_assert(NULL != b);
         force_assert(NULL != s || 0 == s_len);
   
        return 0;        if (0 == s_len) return;
 
         /* count to-be-encoded-characters */
         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
                 if ((*ds < 0x20) /* control character */
                                 || (*ds >= 0x7f)) { /* DEL + non-ASCII characters */
                         switch (*ds) {
                         case '\t':
                         case '\r':
                         case '\n':
                                 d_len += 2;
                                 break;
                         default:
                                 d_len += 4; /* \xCC */
                                 break;
                         }
                 } else {
                         d_len++;
                 }
         }
 
         d = (unsigned char*) buffer_string_prepare_append(b, d_len);
         buffer_commit(b, d_len); /* fill below */
         force_assert('\0' == *d);
 
         for (ds = (unsigned char *)s, d_len = 0, ndx = 0; ndx < s_len; ds++, ndx++) {
                 if ((*ds < 0x20) /* control character */
                                 || (*ds >= 0x7f)) { /* DEL + non-ASCII characters */
                         d[d_len++] = '\\';
                         switch (*ds) {
                         case '\t':
                                 d[d_len++] = 't';
                                 break;
                         case '\r':
                                 d[d_len++] = 'r';
                                 break;
                         case '\n':
                                 d[d_len++] = 'n';
                                 break;
                         default:
                                 d[d_len++] = 'x';
                                 d[d_len++] = hex_chars[((*ds) >> 4) & 0x0F];
                                 d[d_len++] = hex_chars[(*ds) & 0x0F];
                                 break;
                         }
                 } else {
                         d[d_len++] = *ds;
                 }
         }
 }  }
   
   
   void buffer_copy_string_encoded_cgi_varnames(buffer *b, const char *s, size_t s_len, int is_http_header) {
           size_t i, j;
   
           force_assert(NULL != b);
           force_assert(NULL != s || 0 == s_len);
   
           buffer_reset(b);
   
           if (is_http_header && NULL != s && 0 != strcasecmp(s, "CONTENT-TYPE")) {
                   buffer_string_prepare_append(b, s_len + 5);
                   buffer_copy_string_len(b, CONST_STR_LEN("HTTP_"));
           } else {
                   buffer_string_prepare_append(b, s_len);
           }
   
           j = buffer_string_length(b);
           for (i = 0; i < s_len; ++i) {
                   unsigned char cr = s[i];
                   if (light_isalpha(cr)) {
                           /* upper-case */
                           cr &= ~32;
                   } else if (!light_isdigit(cr)) {
                           cr = '_';
                   }
                   b->ptr[j++] = cr;
           }
           b->used = j;
           b->ptr[b->used++] = '\0';
   }
   
 /* decodes url-special-chars inplace.  /* decodes url-special-chars inplace.
  * replaces non-printable characters with '_'   * replaces non-printable characters with '_'
  */   */
   
static int buffer_urldecode_internal(buffer *url, int is_query) {static void buffer_urldecode_internal(buffer *url, int is_query) {
         unsigned char high, low;          unsigned char high, low;
        const char *src;        char *src;
         char *dst;          char *dst;
   
        if (!url || !url->ptr) return -1;        force_assert(NULL != url);
         if (buffer_string_is_empty(url)) return;
   
        src = (const char*) url->ptr;        force_assert('\0' == url->ptr[url->used-1]);
        dst = (char*) url->ptr; 
   
        while ((*src) != '\0') {        src = (char*) url->ptr;
 
         while ('\0' != *src) {
                 if ('%' == *src) break;
                 if (is_query && '+' == *src) *src = ' ';
                 src++;
         }
         dst = src;
 
         while ('\0' != *src) {
                 if (is_query && *src == '+') {                  if (is_query && *src == '+') {
                         *dst = ' ';                          *dst = ' ';
                 } else if (*src == '%') {                  } else if (*src == '%') {
                         *dst = '%';                          *dst = '%';
   
                         high = hex2int(*(src + 1));                          high = hex2int(*(src + 1));
                        if (high != 0xFF) {                        if (0xFF != high) {
                                 low = hex2int(*(src + 2));                                  low = hex2int(*(src + 2));
                                if (low != 0xFF) {                                if (0xFF != low) {
                                         high = (high << 4) | low;                                          high = (high << 4) | low;
   
                                         /* map control-characters out */                                          /* map control-characters out */
Line 897  static int buffer_urldecode_internal(buffer *url, int  Line 858  static int buffer_urldecode_internal(buffer *url, int 
   
         *dst = '\0';          *dst = '\0';
         url->used = (dst - url->ptr) + 1;          url->used = (dst - url->ptr) + 1;
   
         return 0;  
 }  }
   
int buffer_urldecode_path(buffer *url) {void buffer_urldecode_path(buffer *url) {
        return buffer_urldecode_internal(url, 0);        buffer_urldecode_internal(url, 0);
 }  }
   
int buffer_urldecode_query(buffer *url) {void buffer_urldecode_query(buffer *url) {
        return buffer_urldecode_internal(url, 1);        buffer_urldecode_internal(url, 1);
 }  }
   
/* Remove "/../", "//", "/./" parts from path./* - special case: empty string returns empty string
  * - on windows or cygwin: replace \ with /
  * - strip leading spaces
  * - prepends "/" if not present already
  * - resolve "/../", "//" and "/./" the usual way:
  *   the first one removes a preceding component, the other two
  *   get compressed to "/".
  * - "/." and "/.." at the end are similar, but always leave a trailing
  *   "/"
  *   *
  * /blah/..         gets  /   * /blah/..         gets  /
  * /blah/../foo     gets  /foo   * /blah/../foo     gets  /foo
Line 920  int buffer_urldecode_query(buffer *url) { Line 887  int buffer_urldecode_query(buffer *url) {
  *       the operation is performed in-place.   *       the operation is performed in-place.
  */   */
   
int buffer_path_simplify(buffer *dest, buffer *src)void buffer_path_simplify(buffer *dest, buffer *src)
 {  {
        int toklen;        /* current character, the one before, and the one before that from input */
        char c, pre1;        char c, pre1, pre2;
         char *start, *slash, *walk, *out;          char *start, *slash, *walk, *out;
         unsigned short pre;  
   
        if (src == NULL || src->ptr == NULL || dest == NULL)        force_assert(NULL != dest && NULL != src);
                return -1; 
   
        if (src == dest)        if (buffer_string_is_empty(src)) {
                buffer_prepare_append(dest, 1);                buffer_string_prepare_copy(dest, 0);
        else                return;
                buffer_prepare_copy(dest, src->used + 1);        }
   
        walk  = src->ptr;        force_assert('\0' == src->ptr[src->used-1]);
        start = dest->ptr; 
        out   = dest->ptr; 
        slash = dest->ptr; 
   
           /* might need one character more for the '/' prefix */
           if (src == dest) {
                   buffer_string_prepare_append(dest, 1);
           } else {
                   buffer_string_prepare_copy(dest, buffer_string_length(src) + 1);
           }
   
 #if defined(__WIN32) || defined(__CYGWIN__)  #if defined(__WIN32) || defined(__CYGWIN__)
        /* cygwin is treating \ and / the same, so we have to that too        /* cygwin is treating \ and / the same, so we have to that too */
         */        {
                char *p;
        for (walk = src->ptr; *walk; walk++) {                for (p = src->ptr; *p; p++) {
                if (*walk == '\\') *walk = '/';                        if (*p == '\\') *p = '/';
                 }
         }          }
         walk = src->ptr;  
 #endif  #endif
   
           walk  = src->ptr;
           start = dest->ptr;
           out   = dest->ptr;
           slash = dest->ptr;
   
           /* skip leading spaces */
         while (*walk == ' ') {          while (*walk == ' ') {
                 walk++;                  walk++;
         }          }
   
        pre1 = *(walk++);        pre2 = pre1 = 0;
        c    = *(walk++);        c = *(walk++);
        pre  = pre1;        /* prefix with '/' if not already present */
        if (pre1 != '/') {        if (c != '/') {
                pre = ('/' << 8) | pre1;                pre1 = '/';
                 *(out++) = '/';                  *(out++) = '/';
         }          }
         *(out++) = pre1;  
   
        if (pre1 == '\0') {        while (c != '\0') {
                dest->used = (out - start) + 1;                /* assert((src != dest || out <= walk) && slash <= out); */
                return 0;                /* the following comments about out and walk are only interesting if
        }                 * src == dest; otherwise the memory areas don't overlap anyway.
                  */
                 pre2 = pre1;
                 pre1 = c;
   
        while (1) {                /* possibly: out == walk - need to read first */
                 c    = *walk;
                 *out = pre1;
 
                 out++;
                 walk++;
                 /* (out <= walk) still true; also now (slash < out) */
 
                 if (c == '/' || c == '\0') {                  if (c == '/' || c == '\0') {
                        toklen = out - slash;                        const size_t toklen = out - slash;
                        if (toklen == 3 && pre == (('.' << 8) | '.')) {                        if (toklen == 3 && pre2 == '.' && pre1 == '.') {
                                 /* "/../" or ("/.." at end of string) */
                                 out = slash;                                  out = slash;
                                   /* if there is something before "/..", there is at least one
                                    * component, which needs to be removed */
                                 if (out > start) {                                  if (out > start) {
                                         out--;                                          out--;
                                        while (out > start && *out != '/') {                                        while (out > start && *out != '/') out--;
                                                out--; 
                                        } 
                                 }                                  }
   
                                if (c == '\0')                                /* don't kill trailing '/' at end of path */
                                        out++;                                if (c == '\0') out++;
                        } else if (toklen == 1 || pre == (('/' << 8) | '.')) {                                /* slash < out before, so out_new <= slash + 1 <= out_before <= walk */
                         } else if (toklen == 1 || (pre2 == '/' && pre1 == '.')) {
                                 /* "//" or "/./" or (("/" or "/.") at end of string) */
                                 out = slash;                                  out = slash;
                                if (c == '\0')                                /* don't kill trailing '/' at end of path */
                                        out++;                                if (c == '\0') out++;
                                 /* slash < out before, so out_new <= slash + 1 <= out_before <= walk */
                         }                          }
   
                         slash = out;                          slash = out;
                 }                  }
   
                 if (c == '\0')  
                         break;  
   
                 pre1 = c;  
                 pre  = (pre << 8) | pre1;  
                 c    = *walk;  
                 *out = pre1;  
   
                 out++;  
                 walk++;  
         }          }
   
        *out = '\0';        buffer_string_set_length(dest, out - start);
        dest->used = (out - start) + 1; 
 
        return 0; 
 }  }
   
 int light_isdigit(int c) {  int light_isdigit(int c) {
Line 1030  int light_isalnum(int c) { Line 1003  int light_isalnum(int c) {
         return light_isdigit(c) || light_isalpha(c);          return light_isdigit(c) || light_isalpha(c);
 }  }
   
int buffer_to_lower(buffer *b) {void buffer_to_lower(buffer *b) {
        char *c;        size_t i;
   
        if (b->used == 0) return 0;        for (i = 0; i < b->used; ++i) {
                char c = b->ptr[i];
        for (c = b->ptr; *c; c++) {                if (c >= 'A' && c <= 'Z') b->ptr[i] |= 0x20;
                if (*c >= 'A' && *c <= 'Z') { 
                        *c |= 32; 
                } 
         }          }
   }
   
        return 0;
 void buffer_to_upper(buffer *b) {
         size_t i;
 
         for (i = 0; i < b->used; ++i) {
                 char c = b->ptr[i];
                 if (c >= 'A' && c <= 'Z') b->ptr[i] &= ~0x20;
         }
 }  }
   
   #ifdef HAVE_LIBUNWIND
   # define UNW_LOCAL_ONLY
   # include <libunwind.h>
   
int buffer_to_upper(buffer *b) {void print_backtrace(FILE *file) {
        char *c;        unw_cursor_t cursor;
         unw_context_t context;
         int ret;
         unsigned int frame = 0;
   
        if (b->used == 0) return 0;        if (0 != (ret = unw_getcontext(&context))) goto error;
         if (0 != (ret = unw_init_local(&cursor, &context))) goto error;
   
        for (c = b->ptr; *c; c++) {        fprintf(file, "Backtrace:\n");
                if (*c >= 'a' && *c <= 'z') {
                        *c &= ~32;        while (0 < (ret = unw_step(&cursor))) {
                 unw_word_t proc_ip = 0;
                 unw_proc_info_t procinfo;
                 char procname[256];
                 unw_word_t proc_offset = 0;
 
                 if (0 != (ret = unw_get_reg(&cursor, UNW_REG_IP, &proc_ip))) goto error;
 
                 if (0 == proc_ip) {
                         /* without an IP the other functions are useless; unw_get_proc_name would return UNW_EUNSPEC */
                         ++frame;
                         fprintf(file, "%u: (nil)\n", frame);
                         continue;
                 }                  }
   
                   if (0 != (ret = unw_get_proc_info(&cursor, &procinfo))) goto error;
   
                   if (0 != (ret = unw_get_proc_name(&cursor, procname, sizeof(procname), &proc_offset))) {
                           switch (-ret) {
                           case UNW_ENOMEM:
                                   memset(procname + sizeof(procname) - 4, '.', 3);
                                   procname[sizeof(procname) - 1] = '\0';
                                   break;
                           case UNW_ENOINFO:
                                   procname[0] = '?';
                                   procname[1] = '\0';
                                   proc_offset = 0;
                                   break;
                           default:
                                   snprintf(procname, sizeof(procname), "?? (unw_get_proc_name error %d)", -ret);
                                   break;
                           }
                   }
   
                   ++frame;
                   fprintf(file, "%u: %s (+0x%x) [%p]\n",
                           frame,
                           procname,
                           (unsigned int) proc_offset,
                           (void*)(uintptr_t)proc_ip);
         }          }
   
        return 0;        if (0 != ret) goto error;
 
         return;
 
 error:
         fprintf(file, "Error while generating backtrace: unwind error %i\n", (int) -ret);
 }
 #else
 void print_backtrace(FILE *file) {
         UNUSED(file);
 }
 #endif
 
 void log_failed_assert(const char *filename, unsigned int line, const char *msg) {
         /* can't use buffer here; could lead to recursive assertions */
         fprintf(stderr, "%s.%u: %s\n", filename, line, msg);
         print_backtrace(stderr);
         fflush(stderr);
         abort();
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.3


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>