1 /*
2    String utility functions
3    Copyright (C) 1999-2003, Joe Orton <joe@manyfish.co.uk>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18    MA 02111-1307, USA
19 
20 */
21 
22 #include "config.h"
23 
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_STRING_H
28 #include <string.h>
29 #endif
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 
34 #include <ctype.h> /* for isprint() etc in ne_strclean() */
35 
36 #include "ne_alloc.h"
37 #include "ne_string.h"
38 
ne_token(char ** str,char separator)39 char *ne_token(char **str, char separator)
40 {
41     char *ret = *str, *pnt = strchr(*str, separator);
42 
43     if (pnt) {
44 	*pnt = '\0';
45 	*str = pnt + 1;
46     } else {
47 	/* no separator found: return end of string. */
48 	*str = NULL;
49     }
50 
51     return ret;
52 }
53 
ne_qtoken(char ** str,char separator,const char * quotes)54 char *ne_qtoken(char **str, char separator, const char *quotes)
55 {
56     char *pnt, *ret = NULL;
57 
58     for (pnt = *str; *pnt != '\0'; pnt++) {
59 	char *quot = strchr(quotes, *pnt);
60 
61 	if (quot) {
62 	    char *qclose = strchr(pnt+1, *quot);
63 
64 	    if (!qclose) {
65 		/* no closing quote: invalid string. */
66 		return NULL;
67 	    }
68 
69 	    pnt = qclose;
70 	} else if (*pnt == separator) {
71 	    /* found end of token. */
72 	    *pnt = '\0';
73 	    ret = *str;
74 	    *str = pnt + 1;
75 	    return ret;
76 	}
77     }
78 
79     /* no separator found: return end of string. */
80     ret = *str;
81     *str = NULL;
82     return ret;
83 }
84 
ne_shave(char * str,const char * whitespace)85 char *ne_shave(char *str, const char *whitespace)
86 {
87     char *pnt, *ret = str;
88 
89     while (*ret != '\0' && strchr(whitespace, *ret) != NULL) {
90 	ret++;
91     }
92 
93     /* pnt points at the NUL terminator. */
94     pnt = &ret[strlen(ret)];
95 
96     while (pnt > ret && strchr(whitespace, *(pnt-1)) != NULL) {
97 	pnt--;
98     }
99 
100     *pnt = '\0';
101     return ret;
102 }
103 
104 /* TODO: deprecate all these and use ne_token() instead. */
105 
split_string(const char * str,const char separator,const char * quotes,const char * whitespace)106 char **split_string(const char *str, const char separator,
107 		     const char *quotes, const char *whitespace)
108 {
109     return split_string_c(str, separator, quotes, whitespace, NULL);
110 }
111 
split_string_c(const char * str,const char separator,const char * quotes,const char * whitespace,int * give_count)112 char **split_string_c(const char *str, const char separator,
113 		      const char *quotes, const char *whitespace,
114 		      int *give_count)
115 {
116     char **comps;
117     const char *pnt, *quot = NULL,
118 	*start, *end; /* The start of the current component */
119     int count, /* The number of components */
120 	iswhite, /* is it whitespace */
121 	issep, /* is it the separator */
122 	curr, /* current component index */
123 	length, /* length of component */
124 	leading_wspace; /* in leading whitespace still? */
125 
126     /* Inefficient, but easier - first off, count the number of
127      * components we have. */
128     count = 1;
129     for (pnt = str; *pnt!='\0'; pnt++) {
130 	if (quotes != NULL) {
131 	    quot = strchr(quotes, *pnt);
132 	}
133 	if (quot != NULL) {
134 	    /* We found a quote, so skip till the next quote */
135 	    for (pnt++; (*pnt!=*quot) && (*pnt!='\0'); pnt++)
136 		/* nullop */;
137 	} else if (*pnt == separator) {
138 	    count++;
139 	}
140     }
141 
142     if (give_count) {
143 	/* Write the count */
144 	*give_count = count;
145     }
146 
147     /* Now, have got the number of components.
148      * Allocate the comps array. +1 for the NULL */
149     comps = ne_malloc(sizeof(char *) * (count + 1));
150 
151     comps[count] = NULL;
152 
153     quot = end = start = NULL;
154     curr = 0;
155     leading_wspace = 1;
156 
157     /* Now fill in the array */
158     for (pnt = str; *pnt != '\0'; pnt++) {
159 	/* What is the current character - quote, whitespace, separator? */
160 	if (quotes != NULL) {
161 	    quot = strchr(quotes, *pnt);
162 	}
163 	iswhite = (whitespace!=NULL) &&
164 	    (strchr(whitespace, *pnt) != NULL);
165 	issep = (*pnt == separator);
166 	/* What to do? */
167 	if (leading_wspace) {
168 	    if (quot!=NULL) {
169 		/* Quoted bit */
170 		start = pnt;
171 		length = 1;
172 		leading_wspace = 0;
173 	    } else if (issep) {
174 		/* Zero-length component */
175 		comps[curr++] = ne_strdup("");
176 	    } else if (!iswhite) {
177 		start = end = pnt;
178 		length = 1;
179 		leading_wspace = 0;
180 	    }
181 	} else {
182 	    if (quot!=NULL) {
183 		/* Quoted bit */
184 		length++;
185 	    } else if (issep) {
186 		/* End of component - enter it into the array */
187 		length = (end - start) + 1;
188 		comps[curr] = ne_malloc(length+1);
189 		memcpy(comps[curr], start, length);
190 		comps[curr][length] = '\0';
191 		curr++;
192 		leading_wspace = 1;
193 	    } else if (!iswhite) {
194 		/* Not whitespace - update end marker */
195 		end = pnt;
196 	    }
197 	}
198 	if (quot != NULL) {
199 	    /* Skip to closing quote */
200 	    for (pnt++; *pnt!=*quot && *pnt != '\0'; ++pnt)
201 		/* nullop */;
202 	    /* Last non-wspace char is closing quote */
203 	    end = pnt;
204 	}
205     }
206     /* Handle final component */
207     if (leading_wspace) {
208 	comps[curr] = ne_strdup("");
209     } else {
210 	/* End of component - enter it into the array */
211 	length = (end - start) + 1;
212 	comps[curr] = ne_malloc(length+1);
213 	memcpy(comps[curr], start, length);
214 	comps[curr][length] = '\0';
215     }
216     return comps;
217 }
218 
pair_string(const char * str,const char compsep,const char kvsep,const char * quotes,const char * whitespace)219 char **pair_string(const char *str, const char compsep, const char kvsep,
220 		 const char *quotes, const char *whitespace)
221 {
222     char **comps, **pairs, *split;
223     int count = 0, n, length;
224     comps = split_string_c(str, compsep, quotes, whitespace, &count);
225     /* Allocate space for 2* as many components as split_string returned,
226      * +2 for the NULLS. */
227     pairs = ne_malloc((2*count+2) * sizeof(char *));
228     if (pairs == NULL) {
229 	return NULL;
230     }
231     for (n = 0; n < count; n++) {
232 	/* Find the split */
233 	split = strchr(comps[n], kvsep);
234 	if (split == NULL) {
235 	    /* No seperator found */
236 	    length = strlen(comps[n]);
237 	} else {
238 	    length = split-comps[n];
239 	}
240 	/* Enter the key into the array */
241 	pairs[2*n] = comps[n];
242 	/* Null-terminate the key */
243 	pairs[2*n][length] = '\0';
244 	pairs[2*n+1] = split?(split + 1):NULL;
245     }
246     ne_free(comps);
247     pairs[2*count] = pairs[2*count+1] = NULL;
248     return pairs;
249 }
250 
split_string_free(char ** components)251 void split_string_free(char **components)
252 {
253     char **pnt = components;
254     while (*pnt != NULL) {
255 	ne_free(*pnt);
256 	pnt++;
257     }
258     ne_free(components);
259 }
260 
pair_string_free(char ** pairs)261 void pair_string_free(char **pairs)
262 {
263     int n;
264     for (n = 0; pairs[n] != NULL; n+=2) {
265 	ne_free(pairs[n]);
266     }
267     ne_free(pairs);
268 }
269 
ne_buffer_clear(ne_buffer * buf)270 void ne_buffer_clear(ne_buffer *buf)
271 {
272     memset(buf->data, 0, buf->length);
273     buf->used = 1;
274 }
275 
276 /* Grows for given size, returns 0 on success, -1 on error. */
ne_buffer_grow(ne_buffer * buf,size_t newsize)277 void ne_buffer_grow(ne_buffer *buf, size_t newsize)
278 {
279 #define NE_BUFFER_GROWTH 512
280     if (newsize > buf->length) {
281 	/* If it's not big enough already... */
282 	buf->length = ((newsize / NE_BUFFER_GROWTH) + 1) * NE_BUFFER_GROWTH;
283 
284 	/* Reallocate bigger buffer */
285 	buf->data = ne_realloc(buf->data, buf->length);
286     }
287 }
288 
count_concat(va_list * ap)289 static size_t count_concat(va_list *ap)
290 {
291     size_t total = 0;
292     char *next;
293 
294     while ((next = va_arg(*ap, char *)) != NULL)
295 	total += strlen(next);
296 
297     return total;
298 }
299 
do_concat(char * str,va_list * ap)300 static void do_concat(char *str, va_list *ap)
301 {
302     char *next;
303 
304     while ((next = va_arg(*ap, char *)) != NULL) {
305 #ifdef HAVE_STPCPY
306         str = stpcpy(str, next);
307 #else
308 	size_t len = strlen(next);
309 	memcpy(str, next, len);
310 	str += len;
311 #endif
312     }
313 }
314 
ne_buffer_concat(ne_buffer * buf,...)315 void ne_buffer_concat(ne_buffer *buf, ...)
316 {
317     va_list ap;
318     ssize_t total;
319 
320     va_start(ap, buf);
321     total = buf->used + count_concat(&ap);
322     va_end(ap);
323 
324     /* Grow the buffer */
325     ne_buffer_grow(buf, total);
326 
327     va_start(ap, buf);
328     do_concat(buf->data + buf->used - 1, &ap);
329     va_end(ap);
330 
331     buf->used = total;
332     buf->data[total - 1] = '\0';
333 }
334 
ne_concat(const char * str,...)335 char *ne_concat(const char *str, ...)
336 {
337     va_list ap;
338     size_t total, slen = strlen(str);
339     char *ret;
340 
341     va_start(ap, str);
342     total = slen + count_concat(&ap);
343     va_end(ap);
344 
345     ret = memcpy(ne_malloc(total + 1), str, slen);
346 
347     va_start(ap, str);
348     do_concat(ret + slen, &ap);
349     va_end(ap);
350 
351     ret[total] = '\0';
352     return ret;
353 }
354 
355 /* Append zero-terminated string... returns 0 on success or -1 on
356  * realloc failure. */
ne_buffer_zappend(ne_buffer * buf,const char * str)357 void ne_buffer_zappend(ne_buffer *buf, const char *str)
358 {
359     ne_buffer_append(buf, str, strlen(str));
360 }
361 
ne_buffer_append(ne_buffer * buf,const char * data,size_t len)362 void ne_buffer_append(ne_buffer *buf, const char *data, size_t len)
363 {
364     ne_buffer_grow(buf, buf->used + len);
365     memcpy(buf->data + buf->used - 1, data, len);
366     buf->used += len;
367     buf->data[buf->used - 1] = '\0';
368 }
369 
ne_buffer_create(void)370 ne_buffer *ne_buffer_create(void)
371 {
372     return ne_buffer_ncreate(512);
373 }
374 
ne_buffer_ncreate(size_t s)375 ne_buffer *ne_buffer_ncreate(size_t s)
376 {
377     ne_buffer *buf = ne_malloc(sizeof(*buf));
378     buf->data = ne_malloc(s);
379     buf->data[0] = '\0';
380     buf->length = s;
381     buf->used = 1;
382     return buf;
383 }
384 
ne_buffer_destroy(ne_buffer * buf)385 void ne_buffer_destroy(ne_buffer *buf)
386 {
387     ne_free(buf->data);
388     ne_free(buf);
389 }
390 
ne_buffer_finish(ne_buffer * buf)391 char *ne_buffer_finish(ne_buffer *buf)
392 {
393     char *ret = buf->data;
394     ne_free(buf);
395     return ret;
396 }
397 
ne_buffer_altered(ne_buffer * buf)398 void ne_buffer_altered(ne_buffer *buf)
399 {
400     buf->used = strlen(buf->data) + 1;
401 }
402 
403 static const char *b64_alphabet =
404     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
405     "abcdefghijklmnopqrstuvwxyz"
406     "0123456789+/=";
407 
ne_base64(const unsigned char * text,size_t inlen)408 char *ne_base64(const unsigned char *text, size_t inlen)
409 {
410     /* The tricky thing about this is doing the padding at the end,
411      * doing the bit manipulation requires a bit of concentration only */
412     char *buffer, *point;
413     size_t outlen;
414 
415     /* Use 'buffer' to store the output. Work out how big it should be...
416      * This must be a multiple of 4 bytes */
417 
418     outlen = (inlen*4)/3;
419     if ((inlen % 3) > 0) /* got to pad */
420 	outlen += 4 - (inlen % 3);
421 
422     buffer = ne_malloc(outlen + 1); /* +1 for the \0 */
423 
424     /* now do the main stage of conversion, 3 bytes at a time,
425      * leave the trailing bytes (if there are any) for later */
426 
427     for (point=buffer; inlen>=3; inlen-=3, text+=3) {
428 	*(point++) = b64_alphabet[ (*text)>>2 ];
429 	*(point++) = b64_alphabet[ ((*text)<<4 & 0x30) | (*(text+1))>>4 ];
430 	*(point++) = b64_alphabet[ ((*(text+1))<<2 & 0x3c) | (*(text+2))>>6 ];
431 	*(point++) = b64_alphabet[ (*(text+2)) & 0x3f ];
432     }
433 
434     /* Now deal with the trailing bytes */
435     if (inlen > 0) {
436 	/* We always have one trailing byte */
437 	*(point++) = b64_alphabet[ (*text)>>2 ];
438 	*(point++) = b64_alphabet[ (((*text)<<4 & 0x30) |
439 				     (inlen==2?(*(text+1))>>4:0)) ];
440 	*(point++) = (inlen==1?'=':b64_alphabet[ (*(text+1))<<2 & 0x3c ]);
441 	*(point++) = '=';
442     }
443 
444     /* Null-terminate */
445     *point = '\0';
446 
447     return buffer;
448 }
449 
450 /* VALID_B64: fail if 'ch' is not a valid base64 character */
451 #define VALID_B64(ch) (((ch) >= 'A' && (ch) <= 'Z') || \
452                        ((ch) >= 'a' && (ch) <= 'z') || \
453                        ((ch) >= '0' && (ch) <= '9') || \
454                        (ch) == '/' || (ch) == '+' || (ch) == '=')
455 
456 /* DECODE_B64: decodes a valid base64 character. */
457 #define DECODE_B64(ch) ((ch) >= 'a' ? ((ch) + 26 - 'a') : \
458                         ((ch) >= 'A' ? ((ch) - 'A') : \
459                          ((ch) >= '0' ? ((ch) + 52 - '0') : \
460                           ((ch) == '+' ? 62 : 63))))
461 
ne_unbase64(const char * data,unsigned char ** out)462 size_t ne_unbase64(const char *data, unsigned char **out)
463 {
464     size_t inlen = strlen(data);
465     unsigned char *outp;
466     const unsigned char *in;
467 
468     if (inlen == 0 || (inlen % 4) != 0) return 0;
469 
470     outp = *out = ne_malloc(inlen * 3 / 4);
471 
472     for (in = (const unsigned char *)data; *in; in += 4) {
473         unsigned int tmp;
474         if (!VALID_B64(in[0]) || !VALID_B64(in[1]) || !VALID_B64(in[2]) ||
475             !VALID_B64(in[3]) || in[0] == '=' || in[1] == '=' ||
476             (in[2] == '=' && in[3] != '=')) {
477             ne_free(*out);
478             return 0;
479         }
480         tmp = (DECODE_B64(in[0]) & 0x3f) << 18 |
481             (DECODE_B64(in[1]) & 0x3f) << 12;
482         *outp++ = (tmp >> 16) & 0xff;
483         if (in[2] != '=') {
484             tmp |= (DECODE_B64(in[2]) & 0x3f) << 6;
485             *outp++ = (tmp >> 8) & 0xff;
486             if (in[3] != '=') {
487                 tmp |= DECODE_B64(in[3]) & 0x3f;
488                 *outp++ = tmp & 0xff;
489             }
490         }
491     }
492 
493     return outp - *out;
494 }
495 
ne_strclean(char * str)496 char *ne_strclean(char *str)
497 {
498     char *pnt;
499     for (pnt = str; *pnt; pnt++)
500         if (iscntrl(*pnt) || !isprint(*pnt)) *pnt = ' ';
501     return str;
502 }
503 
ne_strerror(int errnum,char * buf,size_t buflen)504 char *ne_strerror(int errnum, char *buf, size_t buflen)
505 {
506 #ifdef HAVE_STRERROR_R
507 #ifdef STRERROR_R_CHAR_P
508     /* glibc-style strerror_r which may-or-may-not use provided buffer. */
509     char *ret = strerror_r(errnum, buf, buflen);
510     if (ret != buf)
511 	ne_strnzcpy(buf, ret, buflen);
512 #else /* POSIX-style strerror_r: */
513     strerror_r(errnum, buf, buflen);
514 #endif
515 #else /* no strerror_r: */
516     ne_strnzcpy(buf, strerror(errnum), buflen);
517 #endif
518     return buf;
519 }
520