1/* 2 String utility functions 3 Copyright (C) 1999-2007, 2009, 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 42char *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 57char *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 88char *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 107void 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. */ 114void 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 126static 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 137static 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 152void 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 172char *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. */ 194void ne_buffer_zappend(ne_buffer *buf, const char *str) 195{ 196 ne_buffer_append(buf, str, strlen(str)); 197} 198 199void 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 207size_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 222ne_buffer *ne_buffer_create(void) 223{ 224 return ne_buffer_ncreate(512); 225} 226 227ne_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 237void ne_buffer_destroy(ne_buffer *buf) 238{ 239 ne_free(buf->data); 240 ne_free(buf); 241} 242 243char *ne_buffer_finish(ne_buffer *buf) 244{ 245 char *ret = buf->data; 246 ne_free(buf); 247 return ret; 248} 249 250void ne_buffer_altered(ne_buffer *buf) 251{ 252 buf->used = strlen(buf->data) + 1; 253} 254 255 256/* ascii_quote[n] gives the number of bytes needed by 257 * ne_buffer_qappend() to append character 'n'. */ 258static const unsigned char ascii_quote[256] = { 259 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 260 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 261 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 262 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 263 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 264 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 265 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 267 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 268 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 269 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 270 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 271 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 272 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 273 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 274 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 275}; 276 277static const char hex_chars[16] = "0123456789ABCDEF"; 278 279/* Return the expected number of bytes needed to append the string 280 * beginning at byte 's', where 'send' points to the last byte after 281 * 's'. */ 282static size_t qappend_count(const unsigned char *s, const unsigned char *send) 283{ 284 const unsigned char *p; 285 size_t ret; 286 287 for (p = s, ret = 0; p < send; p++) { 288 ret += ascii_quote[*p]; 289 } 290 291 return ret; 292} 293 294/* Append the string 's', up to but not including 'send', to string 295 * 'dest', quoting along the way. Returns pointer to NUL. */ 296static char *quoted_append(char *dest, const unsigned char *s, 297 const unsigned char *send) 298{ 299 const unsigned char *p; 300 char *q = dest; 301 302 for (p = s; p < send; p++) { 303 if (ascii_quote[*p] == 1) { 304 *q++ = *p; 305 } 306 else { 307 *q++ = '\\'; 308 *q++ = 'x'; 309 *q++ = hex_chars[(*p >> 4) & 0x0f]; 310 *q++ = hex_chars[*p & 0x0f]; 311 } 312 } 313 314 /* NUL terminate after the last character */ 315 *q = '\0'; 316 317 return q; 318} 319 320void ne_buffer_qappend(ne_buffer *buf, const unsigned char *data, size_t len) 321{ 322 const unsigned char *dend = data + len; 323 char *q, *qs; 324 325 ne_buffer_grow(buf, buf->used + qappend_count(data, dend)); 326 327 /* buf->used >= 1, so this is safe. */ 328 qs = buf->data + buf->used - 1; 329 330 q = quoted_append(qs, data, dend); 331 332 /* used already accounts for a NUL, so increment by number of 333 * characters appended, *before* the NUL. */ 334 buf->used += q - qs; 335} 336 337char *ne_strnqdup(const unsigned char *data, size_t len) 338{ 339 const unsigned char *dend = data + len; 340 char *dest = malloc(qappend_count(data, dend) + 1); 341 342 quoted_append(dest, data, dend); 343 344 return dest; 345} 346 347static const char b64_alphabet[] = 348 "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 349 "abcdefghijklmnopqrstuvwxyz" 350 "0123456789+/="; 351 352char *ne_base64(const unsigned char *text, size_t inlen) 353{ 354 /* The tricky thing about this is doing the padding at the end, 355 * doing the bit manipulation requires a bit of concentration only */ 356 char *buffer, *point; 357 size_t outlen; 358 359 /* Use 'buffer' to store the output. Work out how big it should be... 360 * This must be a multiple of 4 bytes */ 361 362 outlen = (inlen*4)/3; 363 if ((inlen % 3) > 0) /* got to pad */ 364 outlen += 4 - (inlen % 3); 365 366 buffer = ne_malloc(outlen + 1); /* +1 for the \0 */ 367 368 /* now do the main stage of conversion, 3 bytes at a time, 369 * leave the trailing bytes (if there are any) for later */ 370 371 for (point=buffer; inlen>=3; inlen-=3, text+=3) { 372 *(point++) = b64_alphabet[ (*text)>>2 ]; 373 *(point++) = b64_alphabet[ ((*text)<<4 & 0x30) | (*(text+1))>>4 ]; 374 *(point++) = b64_alphabet[ ((*(text+1))<<2 & 0x3c) | (*(text+2))>>6 ]; 375 *(point++) = b64_alphabet[ (*(text+2)) & 0x3f ]; 376 } 377 378 /* Now deal with the trailing bytes */ 379 if (inlen > 0) { 380 /* We always have one trailing byte */ 381 *(point++) = b64_alphabet[ (*text)>>2 ]; 382 *(point++) = b64_alphabet[ (((*text)<<4 & 0x30) | 383 (inlen==2?(*(text+1))>>4:0)) ]; 384 *(point++) = (inlen==1?'=':b64_alphabet[ (*(text+1))<<2 & 0x3c ]); 385 *(point++) = '='; 386 } 387 388 /* Null-terminate */ 389 *point = '\0'; 390 391 return buffer; 392} 393 394/* VALID_B64: fail if 'ch' is not a valid base64 character */ 395#define VALID_B64(ch) (((ch) >= 'A' && (ch) <= 'Z') || \ 396 ((ch) >= 'a' && (ch) <= 'z') || \ 397 ((ch) >= '0' && (ch) <= '9') || \ 398 (ch) == '/' || (ch) == '+' || (ch) == '=') 399 400/* DECODE_B64: decodes a valid base64 character. */ 401#define DECODE_B64(ch) ((ch) >= 'a' ? ((ch) + 26 - 'a') : \ 402 ((ch) >= 'A' ? ((ch) - 'A') : \ 403 ((ch) >= '0' ? ((ch) + 52 - '0') : \ 404 ((ch) == '+' ? 62 : 63)))) 405 406size_t ne_unbase64(const char *data, unsigned char **out) 407{ 408 size_t inlen = strlen(data); 409 unsigned char *outp; 410 const unsigned char *in; 411 412 if (inlen == 0 || (inlen % 4) != 0) return 0; 413 414 outp = *out = ne_malloc(inlen * 3 / 4); 415 416 for (in = (const unsigned char *)data; *in; in += 4) { 417 unsigned int tmp; 418 if (!VALID_B64(in[0]) || !VALID_B64(in[1]) || !VALID_B64(in[2]) || 419 !VALID_B64(in[3]) || in[0] == '=' || in[1] == '=' || 420 (in[2] == '=' && in[3] != '=')) { 421 ne_free(*out); 422 return 0; 423 } 424 tmp = (DECODE_B64(in[0]) & 0x3f) << 18 | 425 (DECODE_B64(in[1]) & 0x3f) << 12; 426 *outp++ = (tmp >> 16) & 0xff; 427 if (in[2] != '=') { 428 tmp |= (DECODE_B64(in[2]) & 0x3f) << 6; 429 *outp++ = (tmp >> 8) & 0xff; 430 if (in[3] != '=') { 431 tmp |= DECODE_B64(in[3]) & 0x3f; 432 *outp++ = tmp & 0xff; 433 } 434 } 435 } 436 437 return outp - *out; 438} 439 440/* Character map array; ascii_clean[n] = isprint(n) ? n : 0x20. Used 441 * by ne_strclean as a locale-independent isprint(). */ 442static const unsigned char ascii_clean[256] = { 443 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 444 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 445 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 446 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 447 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 448 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 449 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 450 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 451 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 452 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 453 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 454 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 455 0x60, 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, 0x7b, 0x7c, 0x7d, 0x7e, 0x20, 459 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 460 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 461 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 462 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 463 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 464 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 465 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 466 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 467 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 468 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 469 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 470 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 471 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 472 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 473 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 474 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 475}; 476 477char *ne_strclean(char *str) 478{ 479 unsigned char *pnt; 480 481 for (pnt = (unsigned char *)str; *pnt; pnt++) 482 *pnt = (char)ascii_clean[*pnt]; 483 484 return str; 485} 486 487char *ne_strerror(int errnum, char *buf, size_t buflen) 488{ 489#ifdef HAVE_STRERROR_R 490#ifdef STRERROR_R_CHAR_P 491 /* glibc-style strerror_r which may-or-may-not use provided buffer. */ 492 char *ret = strerror_r(errnum, buf, buflen); 493 if (ret != buf) 494 ne_strnzcpy(buf, ret, buflen); 495#else /* POSIX-style strerror_r: */ 496 char tmp[256]; 497 498 if (strerror_r(errnum, tmp, sizeof tmp) == 0) 499 ne_strnzcpy(buf, tmp, buflen); 500 else 501 ne_snprintf(buf, buflen, "Unknown error %d", errnum); 502#endif 503#else /* no strerror_r: */ 504 ne_strnzcpy(buf, strerror(errnum), buflen); 505#endif 506 return buf; 507} 508 509 510/* Wrapper for ne_snprintf. */ 511size_t ne_snprintf(char *str, size_t size, const char *fmt, ...) 512{ 513 va_list ap; 514 va_start(ap, fmt); 515#ifdef HAVE_TRIO 516 trio_vsnprintf(str, size, fmt, ap); 517#else 518 vsnprintf(str, size, fmt, ap); 519#endif 520 va_end(ap); 521 str[size-1] = '\0'; 522 return strlen(str); 523} 524 525/* Wrapper for ne_vsnprintf. */ 526size_t ne_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) 527{ 528#ifdef HAVE_TRIO 529 trio_vsnprintf(str, size, fmt, ap); 530#else 531 vsnprintf(str, size, fmt, ap); 532#endif 533 str[size-1] = '\0'; 534 return strlen(str); 535} 536 537/* Locale-independent strcasecmp implementations. */ 538static const unsigned char ascii_tolower[256] = { 5390x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 5400x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 5410x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 5420x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 5430x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 5440x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 5450x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 5460x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 5470x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 5480x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 5490x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 5500x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 5510x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 5520x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 5530x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 5540x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 5550x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 5560x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 5570x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 5580x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 5590xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 5600xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 5610xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 5620xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 5630xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 5640xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 5650xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 5660xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 5670xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 5680xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 5690xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 5700xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 571}; 572 573#define TOLOWER(ch) ascii_tolower[ch] 574 575const unsigned char *ne_tolower_array(void) 576{ 577 return ascii_tolower; 578} 579 580int ne_strcasecmp(const char *s1, const char *s2) 581{ 582 const unsigned char *p1 = (const unsigned char *) s1; 583 const unsigned char *p2 = (const unsigned char *) s2; 584 unsigned char c1, c2; 585 586 if (p1 == p2) 587 return 0; 588 589 do { 590 c1 = TOLOWER(*p1++); 591 c2 = TOLOWER(*p2++); 592 if (c1 == '\0') 593 break; 594 } while (c1 == c2); 595 596 return c1 - c2; 597} 598 599int ne_strncasecmp(const char *s1, const char *s2, size_t n) 600{ 601 const unsigned char *p1 = (const unsigned char *) s1; 602 const unsigned char *p2 = (const unsigned char *) s2; 603 unsigned char c1, c2; 604 605 if (p1 == p2 || n == 0) 606 return 0; 607 608 do { 609 c1 = TOLOWER(*p1++); 610 c2 = TOLOWER(*p2++); 611 if (c1 == '\0' || c1 != c2) 612 return c1 - c2; 613 } while (--n > 0); 614 615 return c1 - c2; 616} 617