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