1 /*
2  *	C-string functions
3  *	Copyright Jan Engelhardt, 1999-2010
4  *
5  *	This file is part of libHX. libHX is free software; you can
6  *	redistribute it and/or modify it under the terms of the GNU Lesser
7  *	General Public License as published by the Free Software Foundation;
8  *	either version 2.1 or (at your option) any later version.
9  */
10 #include <errno.h>
11 #include <stdbool.h>
12 #include <stddef.h>
13 #include <stdint.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <libHX/ctype_helper.h>
18 #include <libHX/string.h>
19 #include "internal.h"
20 
21 /**
22  * %HXQUOTE_ACCEPT:	the listed characters are passed through,
23  * 			all others need to be quoted
24  * %HXQUOTE_REJECT:	the listed characters need to be quoted,
25  * 			all others pass through
26  */
27 enum HX_quote_selector {
28 	HXQUOTE_ACCEPT,
29 	HXQUOTE_REJECT,
30 };
31 
32 /**
33  * @selector:	whether this rule is accept- or reject-based
34  * @qchars:	characters that need (no) quoting
35  */
36 struct HX_quote_rule {
37 	char selector;
38 	const char *chars;
39 };
40 
41 static const char HX_hexenc[16] = "0123456789ABCDEF";
42 
min_uint(unsigned int a,unsigned int b)43 static __inline__ unsigned int min_uint(unsigned int a, unsigned int b)
44 {
45 	return (a < b) ? a : b;
46 }
47 
HX_basename(const char * s)48 EXPORT_SYMBOL char *HX_basename(const char *s)
49 {
50 	const char *p;
51 	/* ignore trailing slashes */
52 	for (p = s + strlen(s) - 1; p >= s && *p == '/'; --p)
53 		;
54 	if (p < s)
55 		/*
56 		 * String contained only slashes - this must be the root
57 		 * directory. Since we have the opportunity, rather than
58 		 * returning "////", just give the cleaned-up "/".
59 		 */
60 		return const_cast1(char *, s + strlen(s) - 1);
61 	if ((p = HX_strbchr(s, p, '/')) != NULL)
62 		return const_cast1(char *, p + 1);
63 	return const_cast1(char *, s);
64 }
65 
HX_basename_exact(const char * s)66 EXPORT_SYMBOL char *HX_basename_exact(const char *s)
67 {
68 	const char *start, *end;
69 	char *ret;
70 	int len;
71 
72 	if (*s == '\0')
73 		return HX_strdup(".");
74 	/* ignore trailing slashes */
75 	for (end = s + strlen(s) - 1; end >= s && *end == '/'; --end)
76 		;
77 	if (end < s)
78 		/* string consisted of only slashes */
79 		return HX_strdup("/");
80 
81 	start = HX_strbchr(s, end, '/');
82 	if (start == NULL) {
83 		len = end - s + 1;
84 		ret = HX_memdup(s, len + 1);
85 	} else {
86 		++start;
87 		len = end - start + 1;
88 		ret = HX_memdup(start, len + 1);
89 	}
90 	if (ret == NULL)
91 		return NULL;
92 	ret[len] = '\0';
93 	return ret;
94 }
95 
HX_chomp(char * s)96 EXPORT_SYMBOL char *HX_chomp(char *s)
97 {
98 	char *p = s + strlen(s) - 1;
99 	while (p >= s) {
100 		if (*p != '\n' && *p != '\r')
101 			break;
102 		*p-- = '\0';
103 	}
104 	return s;
105 }
106 
HX_dirname(const char * s)107 EXPORT_SYMBOL char *HX_dirname(const char *s)
108 {
109 	const char *last, *stop;
110 	char *p;
111 
112 	if (*s == '\0')
113 		return HX_strdup(".");
114 
115 	for (last = s + strlen(s) - 1; last > s && *last == '/'; --last)
116 		;
117 
118 	if ((stop = HX_strbchr(s, last, '/')) == NULL)
119 		return HX_strdup(".");
120 
121 	for (; stop > s && *stop == '/'; --stop)
122 		;
123 
124 	p = HX_memdup(s, stop - s + 2);
125 	p[stop-s+1] = '\0';
126 	return p;
127 }
128 
HX_getl(hxmc_t ** ptr,FILE * fp)129 EXPORT_SYMBOL hxmc_t *HX_getl(hxmc_t **ptr, FILE *fp)
130 {
131 	/* Read a whole line into a dynamic buffer. */
132 	char temp[MAXLNLEN];
133 
134 	if (fgets(temp, sizeof(temp), fp) == NULL)
135 		return NULL;
136 
137 	if (*ptr == NULL) {
138 		*ptr = HXmc_meminit(NULL, 0);
139 		if (*ptr == NULL)
140 			return NULL;
141 	} else {
142 		HXmc_trunc(ptr, 0);
143 	}
144 
145 	do {
146 		if (HXmc_strcat(ptr, temp) == NULL)
147 			return *ptr;
148 		if (strchr(temp, '\n') != NULL)
149 			break;
150 	} while (fgets(temp, sizeof(temp), fp) != NULL);
151 
152 	return *ptr;
153 }
154 
HX_memmem(const void * vspace,size_t spacesize,const void * vpoint,size_t pointsize)155 EXPORT_SYMBOL void *HX_memmem(const void *vspace, size_t spacesize,
156     const void *vpoint, size_t pointsize)
157 {
158 	const char *space = vspace, *point = vpoint;
159 	const char *head, *end;
160 	size_t tailsize;
161 	char *tail;
162 
163 	if (pointsize == 0)
164 		return const_cast1(void *, vspace);
165 	if (pointsize > spacesize)
166 		return NULL;
167 
168 	/* Do a BM-style trailer search and reduce calls to memcmp */
169 	head = space + (pointsize - 1);
170 	tail = memchr(head, point[pointsize-1], spacesize - (pointsize - 1));
171 	if (tail == NULL || pointsize == 1)
172 		return tail;
173 	end = space + spacesize;
174 	do {
175 		head = tail - pointsize + 1;
176 		if (memcmp(head, point, pointsize) == 0)
177 			return const_cast(char *, head);
178 		++tail;
179 		tailsize = end - tail;
180 		tail = memchr(tail, point[pointsize-1], tailsize);
181 	} while (tail != NULL);
182 	return NULL;
183 }
184 
HX_split(const char * str,const char * delim,int * cp,int max)185 EXPORT_SYMBOL char **HX_split(const char *str, const char *delim,
186     int *cp, int max)
187 {
188 	/*
189 	 * @countp can be NULL in case you are not interested in the number of
190 	 * fields. In either case, you can find out the number of fields by
191 	 * scanning through the resulting vector.
192 	 */
193 	int count = 0;
194 	char **ret;
195 
196 	if (cp == NULL)
197 		cp = &count;
198 	*cp = 1;
199 
200 	{
201 		const char *wp = str;
202 		while ((wp = strpbrk(wp, delim)) != NULL) {
203 			if (++*cp >= max && max > 0) {
204 				*cp = max;
205 				break;
206 			}
207 			++wp;
208 		}
209 	}
210 
211 	if (max == 0 || *cp < max)
212 		max = *cp;
213 	else if (*cp > max)
214 		*cp = max;
215 
216 	ret = malloc(sizeof(char *) * (*cp + 1));
217 	ret[*cp] = NULL;
218 
219 	{
220 		char *seg, *wp = HX_strdup(str), *bg = wp;
221 		size_t i = 0;
222 
223 		while (--max > 0) {
224 			seg      = HX_strsep(&wp, delim);
225 			ret[i++] = HX_strdup(seg);
226 		}
227 
228 		ret[i++] = HX_strdup(wp);
229 		free(bg);
230 	}
231 
232 	return ret;
233 }
234 
HX_split_inplace(char * s,const char * delim,int * fld,int max)235 EXPORT_SYMBOL char **HX_split_inplace(char *s, const char *delim, int *fld, int max)
236 {
237 	char **stk;
238 	const char *p = s;
239 	int count = 1;
240 
241 	for (p = strpbrk(p, delim); p != NULL; p = strpbrk(++p, delim))
242 		if (++count >= max && max > 0) {
243 			count = max;
244 			break;
245 		}
246 
247 	stk = malloc(sizeof(char *) * (count + 1));
248 	if (stk == NULL)
249 		return NULL;
250 	stk[count] = NULL;
251 	count = HX_split_fixed(s, delim, count, stk);
252 	if (fld != NULL)
253 		*fld = count;
254 	return stk;
255 }
256 
HX_split_fixed(char * s,const char * delim,int max,char ** stk)257 EXPORT_SYMBOL int HX_split_fixed(char *s, const char *delim, int max, char **stk)
258 {
259 	/*
260 	 * HX_split_fixed - the "stack split" (we try to avoid using the heap):
261 	 * Split @s (modifies it, so must be writable!) at @delim with at most
262 	 * @max fields and putting the results into @stk[0..@max-1].
263 	 *
264 	 * Example on @max:
265 	 *	char *stk[max];
266 	 *	HX_split_fixed(s, delim, max, stk);
267 	 */
268 	int i = 0;
269 	char *p;
270 
271 	while (--max > 0) {
272 		if ((p = strpbrk(s, delim)) == NULL)
273 			break;
274 		stk[i++] = s;
275 		*p = '\0';
276 		s  = p + 1;
277 	}
278 
279 	stk[i++] = s;
280 	return i;
281 }
282 
HX_strbchr(const char * start,const char * now,char d)283 EXPORT_SYMBOL char *HX_strbchr(const char *start, const char *now, char d)
284 {
285 	/* Find the last occurrence of @d within @start and (including) @now. */
286 	while (now >= start)
287 		if (*now-- == d)
288 			return const_cast1(char *, ++now);
289 	return NULL;
290 }
291 
292 /**
293  * This is the counterpart to strpbrk(). Returns a pointer to the first
294  * character not in @accept, or otherwise %NULL.
295  */
HX_strchr2(const char * s,const char * accept)296 EXPORT_SYMBOL char *HX_strchr2(const char *s, const char *accept)
297 {
298 	size_t seg = strspn(s, accept);
299 
300 	if (s[seg] == '\0')
301 		return NULL;
302 	return const_cast1(char *, s + seg);
303 }
304 
HX_strclone(char ** pa,const char * pb)305 EXPORT_SYMBOL char *HX_strclone(char **pa, const char *pb)
306 {
307 	if (*pa == pb)
308 		return *pa;
309 	if (*pa != NULL) {
310 		free(*pa);
311 		*pa = NULL;
312 	}
313 	if (pb == NULL)
314 		return NULL;
315 	if ((*pa = malloc(strlen(pb) + 1)) == NULL)
316 		return NULL;
317 	strcpy(*pa, pb);
318 	return *pa;
319 }
320 
HX_strdup(const char * src)321 EXPORT_SYMBOL char *HX_strdup(const char *src)
322 {
323 	if (src == NULL)
324 		return NULL;
325 	/* return HX_strndup(src, SIZE_MAX); */
326 	return HX_memdup(src, strlen(src) + 1);
327 }
328 
HX_strlcat(char * dest,const char * src,size_t len)329 EXPORT_SYMBOL char *HX_strlcat(char *dest, const char *src, size_t len)
330 {
331 	ssize_t x = len - strlen(dest) - 1;
332 	if (x <= 0)
333 		return dest;
334 	return strncat(dest, src, x);
335 }
336 
HX_strlcpy(char * dest,const char * src,size_t n)337 EXPORT_SYMBOL char *HX_strlcpy(char *dest, const char *src, size_t n)
338 {
339 	if (n == 0)
340 		return dest;
341 	strncpy(dest, src, n);
342 	dest[n-1] = '\0';
343 	return dest;
344 }
345 
HX_strlncat(char * dest,const char * src,size_t dlen,size_t slen)346 EXPORT_SYMBOL char *HX_strlncat(char *dest, const char *src, size_t dlen,
347     size_t slen)
348 {
349 	ssize_t x = dlen - strlen(dest) - 1;
350 	if (x <= 0)
351 		return dest;
352 	x = ((ssize_t)slen < x) ? (ssize_t)slen : x;
353 	return strncat(dest, src, x);
354 }
355 
HX_strlower(char * orig)356 EXPORT_SYMBOL char *HX_strlower(char *orig)
357 {
358 	char *expr;
359 	for (expr = orig; *expr != '\0'; ++expr)
360 		*expr = HX_tolower(*expr);
361 	return orig;
362 }
363 
HX_strltrim(char * expr)364 EXPORT_SYMBOL size_t HX_strltrim(char *expr)
365 {
366 	char *travp;
367 	size_t diff = 0;
368 	travp = expr;
369 
370 	while (HX_isspace(*travp))
371 		++travp;
372 	if ((diff = travp - expr) > 0)
373 		memmove(expr, travp, strlen(travp) + 1);
374 	return diff;
375 }
376 
HX_stpltrim(const char * p)377 EXPORT_SYMBOL char *HX_stpltrim(const char *p)
378 {
379 	while (HX_isspace(*p))
380 		++p;
381 	return const_cast1(char *, p);
382 }
383 
384 /* supports negative offsets like scripting languages */
HX_strmid(const char * expr,long offset,long length)385 EXPORT_SYMBOL char *HX_strmid(const char *expr, long offset, long length)
386 {
387 	char *buffer;
388 
389 	if (offset < 0)
390 		offset = strlen(expr) + offset;
391 	if (length < 0)
392 		length = strlen(expr) - offset + length;
393 	if ((buffer = malloc(length + 1)) == NULL)
394 		return NULL;
395 
396 	expr += offset;
397 	return HX_strlcpy(buffer, expr, length + 1);
398 }
399 
HX_strndup(const char * src,size_t size)400 EXPORT_SYMBOL char *HX_strndup(const char *src, size_t size)
401 {
402 	char *ret;
403 	size_t z;
404 
405 	if (src == NULL)
406 		return NULL;
407 	z = strlen(src);
408 	if (z < size)
409 		size = z;
410 	if ((ret = malloc(size + 1)) == NULL)
411 		return NULL;
412 	memcpy(ret, src, size);
413 	ret[size] = '\0';
414 	return ret;
415 }
416 
HX_strnlen(const char * src,size_t size)417 EXPORT_SYMBOL size_t HX_strnlen(const char *src, size_t size)
418 {
419 	const char *ptr = src;
420 	for (; *ptr != '\0' && size > 0; --size, ++ptr)
421 		;
422 	return ptr - src;
423 }
424 
HX_strrcspn(const char * s,const char * rej)425 EXPORT_SYMBOL size_t HX_strrcspn(const char *s, const char *rej)
426 {
427 	size_t n = strlen(s);
428 	const char *p = s + n;
429 	while (--p >= s)
430 		if (strchr(rej, *p) != NULL)
431 			return p - s;
432 	return n;
433 }
434 
HX_strrev(char * s)435 EXPORT_SYMBOL char *HX_strrev(char *s)
436 {
437 	size_t i, z = strlen(s)-1, z2 = z / 2;
438 
439 	for (i = 0; i < z2; ++i) {
440 		char temp;
441 		temp = s[i];
442 		s[i] = s[z-i];
443 		s[z-i] = temp;
444 	}
445 
446 	return s;
447 }
448 
HX_strrtrim(char * expr)449 EXPORT_SYMBOL size_t HX_strrtrim(char *expr)
450 {
451 	int i = strlen(expr), s = 0;
452 	while (i-- && HX_isspace(expr[i]))
453 		++s;
454 	expr[++i] = '\0';
455 	return s;
456 }
457 
HX_strsep(char ** sp,const char * d)458 EXPORT_SYMBOL char *HX_strsep(char **sp, const char *d)
459 {
460 	char *begin, *end;
461 
462 	if (*sp == NULL || **sp == '\0')
463 		return NULL;
464 	begin = *sp;
465 
466 	if (d[0] == '\0' || d[1] == '\0') {
467 		if (*begin == *d)
468 			end = begin;
469 		else if (*begin == '\0')
470 			end = NULL;
471 		else
472 			end = strchr(begin + 1, *d);
473 	} else {
474 		end = strpbrk(begin, d);
475 	}
476 
477 	if (end == NULL) {
478 		*sp = NULL;
479 	} else {
480 		*end++ = '\0';
481 		*sp = end;
482 	}
483 
484 	return begin;
485 }
486 
HX_strsep2(char ** wp,const char * str)487 EXPORT_SYMBOL char *HX_strsep2(char **wp, const char *str)
488 {
489 	char *ptr, *ret;
490 	if (*wp == NULL)
491 		return NULL;
492 	ret = *wp;
493 	if ((ptr = strstr(*wp, str)) == NULL) {
494 		*wp = NULL;
495 		return ret;
496 	}
497 	*ptr = '\0';
498 	*wp  = ptr + strlen(str);
499 	return ret;
500 }
501 
502 static const struct HX_quote_rule HX_quote_rules[] = {
503 	[HXQUOTE_SQUOTE]  = {HXQUOTE_REJECT, "'\\"},
504 	[HXQUOTE_DQUOTE]  = {HXQUOTE_REJECT, "\"\\"},
505 	[HXQUOTE_HTML]    = {HXQUOTE_REJECT, "\"&<>"},
506 	[HXQUOTE_LDAPFLT] = {HXQUOTE_REJECT, "\n*()\\"},
507 	[HXQUOTE_LDAPRDN] = {HXQUOTE_REJECT, "\n \"#+,;<=>\\"},
508 	[HXQUOTE_URIENC]  = {HXQUOTE_ACCEPT, "-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~"},
509 	[HXQUOTE_SQLSQUOTE] = {HXQUOTE_REJECT, "'"},
510 	[HXQUOTE_SQLBQUOTE] = {HXQUOTE_REJECT, "`"},
511 };
512 
513 /**
514  * HX_qsize_bsa - calculate length of statically expanded string (for accepts)
515  * @s:		input string
516  * @qchars:	characters that need quoting
517  * @cost:	quoting cost per quoted character
518  *
519  * The cost depends on the quote format. Typical values:
520  * 	1	when "&" becomes "\&" (programming language-like)
521  * 	2	when "&" becomes "\26" (LDAPRDN/HTTPURI-like hex encoding)
522  * 	3	when "&" becomes "\x26" (hex encoding for programming)
523  */
524 static size_t
HX_qsize_bsa(const char * s,const char * qchars,unsigned int cost)525 HX_qsize_bsa(const char *s, const char *qchars, unsigned int cost)
526 {
527 	const char *p = s;
528 	size_t n = strlen(s);
529 
530 	while ((p = HX_strchr2(p, qchars)) != NULL) {
531 		n += cost;
532 		++p;
533 	}
534 	return n;
535 }
536 
537 /**
538  * HX_qsize_bsr - calculate length of statically expanded string (for rejects)
539  * @s:		input string
540  * @qchars:	characters that need quoting
541  * @cost:	quoting cost per quoted character
542  *
543  * Same as for HX_qsize_bsa, but for HXQUOTE_REJECT-type rules.
544  */
545 static size_t
HX_qsize_bsr(const char * s,const char * qchars,unsigned int cost)546 HX_qsize_bsr(const char *s, const char *qchars, unsigned int cost)
547 {
548 	const char *p = s;
549 	size_t n = strlen(s);
550 
551 	while ((p = strpbrk(p, qchars)) != NULL) {
552 		n += cost;
553 		++p;
554 	}
555 	return n;
556 }
557 
HX_quote_backslash(char * dest,const char * src,const char * qc)558 static char *HX_quote_backslash(char *dest, const char *src, const char *qc)
559 {
560 	char *ret = dest;
561 	size_t len;
562 
563 	while (*src != '\0') {
564 		len = strcspn(src, qc);
565 		if (len > 0) {
566 			memcpy(dest, src, len);
567 			dest += len;
568 			src  += len;
569 			if (*src == '\0')
570 				break;
571 		}
572 		*dest++ = '\\';
573 		*dest++ = *src++;
574 	}
575 
576 	*dest = '\0';
577 	return ret;
578 }
579 
580 static char *
HX_quote_sqlbackslash(char * dest,const char * src,const char * trm)581 HX_quote_sqlbackslash(char *dest, const char *src, const char *trm)
582 {
583 	char *ret = dest;
584 	size_t len;
585 
586 	while (*src != '\0') {
587 		len = strcspn(src, trm);
588 		if (len > 0) {
589 			memcpy(dest, src, len);
590 			dest += len;
591 			src  += len;
592 			if (*src == '\0')
593 				break;
594 		}
595 		*dest++ = *trm;
596 		*dest++ = *trm;
597 		++src;
598 	}
599 
600 	*dest = '\0';
601 	return ret;
602 }
603 
604 /**
605  * Encode @src into BASE-64 according to RFC 4648 and write result to @dest,
606  * which must be of appropriate size, plus one for a trailing NUL.
607  */
HX_quote_base64(char * d,const char * s)608 static char *HX_quote_base64(char *d, const char *s)
609 {
610 	static const char a[] =
611 		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
612 		"abcdefghijklmnopqrstuvwxyz0123456789+/";
613 	size_t len = strlen(s);
614 	char *ret = d;
615 
616 	while (len > 0) {
617 		if (len >= 3) {
618 			len -= 3;
619 			d[0] = a[(s[0] & 0xFC) >> 2];
620 			d[1] = a[((s[0] & 0x03) << 4) | ((s[1] & 0xF0) >> 4)];
621 			d[2] = a[((s[1] & 0x0F) << 2) | ((s[2] & 0xC0) >> 6)];
622 			d[3] = a[s[2] & 0x3F];
623 		} else if (len == 2) {
624 			len = 0;
625 			d[0] = a[(s[0] & 0xFC) >> 2];
626 			d[1] = a[((s[0] & 0x03) << 4) | ((s[1] & 0xF0) >> 4)];
627 			d[2] = a[(s[1] & 0x0F) << 2];
628 			d[3] = '=';
629 		} else if (len == 1) {
630 			len = 0;
631 			d[0] = a[(s[0] & 0xFC) >> 2];
632 			d[1] = a[(s[0] & 0x03) << 4];
633 			d[2] = '=';
634 			d[3] = '=';
635 		}
636 		s += 3;
637 		d += 4;
638 	}
639 	*d = '\0';
640 	return ret;
641 }
642 
HX_qsize_html(const char * s)643 static size_t HX_qsize_html(const char *s)
644 {
645 	const char *p = s;
646 	size_t n = strlen(s);
647 
648 	while ((p = strpbrk(p, HX_quote_rules[HXQUOTE_HTML].chars)) != NULL) {
649 		switch (*p) {
650 		/* minus 2: \0 and the original char */
651 		case '"':
652 			n += sizeof("&quot;") - 2;
653 			break;
654 		case '&':
655 			n += sizeof("&amp;") - 2;
656 			break;
657 		case '<':
658 		case '>':
659 			n += sizeof("&lt;") - 2;
660 			break;
661 		}
662 		++p;
663 	}
664 	return n;
665 }
666 
HX_quote_html(char * dest,const char * src)667 static char *HX_quote_html(char *dest, const char *src)
668 {
669 #define put(s) do { \
670 	memcpy(dest, (s), sizeof(s) - 1); \
671 	dest += sizeof(s) - 1; \
672 } while (false);
673 
674 	char *ret = dest;
675 
676 	while (*src != '\0') {
677 		size_t len = strcspn(src, HX_quote_rules[HXQUOTE_HTML].chars);
678 		if (len > 0) {
679 			memcpy(dest, src, len);
680 			dest += len;
681 			src  += len;
682 			if (*src == '\0')
683 				break;
684 		}
685 		switch (*src++) {
686 		case '"': put("&quot;"); break;
687 		case '&': put("&amp;"); break;
688 		case '<': put("&lt;"); break;
689 		case '>': put("&gt;"); break;
690 		}
691 	}
692 	*dest = '\0';
693 	return ret;
694 #undef put
695 }
696 
HX_quote_ldap(char * dest,const char * src,const char * qc)697 static char *HX_quote_ldap(char *dest, const char *src, const char *qc)
698 {
699 	char *ret = dest;
700 	size_t len;
701 
702 	while (*src != '\0') {
703 		len = strcspn(src, qc);
704 		if (len > 0) {
705 			memcpy(dest, src, len);
706 			dest += len;
707 			src  += len;
708 			if (*src == '\0')
709 				break;
710 		}
711 		*dest++ = '\\';
712 		*dest++ = HX_hexenc[(*src >> 4) & 0x0F];
713 		*dest++ = HX_hexenc[*src++ & 0x0F];
714 	}
715 
716 	*dest = '\0';
717 	return ret;
718 }
719 
HX_quote_urlenc(char * dest,const char * src)720 static char *HX_quote_urlenc(char *dest, const char *src)
721 {
722 	char *ret = dest;
723 	size_t len;
724 
725 	while (*src != '\0') {
726 		len = strspn(src, HX_quote_rules[HXQUOTE_URIENC].chars);
727 		if (len > 0) {
728 			memcpy(dest, src, len);
729 			dest += len;
730 			src  += len;
731 			if (*src == '\0')
732 				break;
733 		}
734 		*dest++ = '%';
735 		*dest++ = HX_hexenc[(*src >> 4) & 0x0F];
736 		*dest++ = HX_hexenc[*src++ & 0x0F];
737 	}
738 
739 	*dest = '\0';
740 	return ret;
741 }
742 
743 /**
744  * HX_quoted_size -
745  * @s:		string to analyze
746  * @type:	quoting method
747  *
748  * Returns the size of the string @s when quoted.
749  */
HX_quoted_size(const char * s,unsigned int type)750 static size_t HX_quoted_size(const char *s, unsigned int type)
751 {
752 	switch (type) {
753 	case HXQUOTE_SQUOTE:
754 	case HXQUOTE_DQUOTE:
755 	case HXQUOTE_SQLSQUOTE:
756 	case HXQUOTE_SQLBQUOTE:
757 		return HX_qsize_bsr(s, HX_quote_rules[type].chars, 1);
758 	case HXQUOTE_HTML:
759 		return HX_qsize_html(s);
760 	case HXQUOTE_LDAPFLT:
761 	case HXQUOTE_LDAPRDN:
762 		return HX_qsize_bsr(s, HX_quote_rules[type].chars, 2);
763 	case HXQUOTE_BASE64:
764 		return (strlen(s) + 2) / 3 * 4;
765 	case HXQUOTE_URIENC:
766 		return HX_qsize_bsa(s, HX_quote_rules[type].chars, 2);
767 	default:
768 		return strlen(s);
769 	}
770 }
771 
HX_strquote(const char * src,unsigned int type,char ** free_me)772 EXPORT_SYMBOL char *HX_strquote(const char *src, unsigned int type,
773     char **free_me)
774 {
775 	const struct HX_quote_rule *rule;
776 	bool do_quote;
777 	char *tmp;
778 
779 	if (type >= _HXQUOTE_MAX) {
780 		errno = EINVAL;
781 		return NULL;
782 	}
783 	/* If quote_chars is NULL, it is clear all chars are to be encoded. */
784 	rule = &HX_quote_rules[type];
785 	if (type >= ARRAY_SIZE(HX_quote_rules) || rule->chars == NULL)
786 		do_quote = true;
787 	else if (rule->selector == HXQUOTE_REJECT)
788 		do_quote = strpbrk(src, rule->chars) != NULL;
789 	else if (rule->selector == HXQUOTE_ACCEPT)
790 		do_quote = HX_strchr2(src, rule->chars) != NULL;
791 	else
792 		do_quote = false;
793 	/*
794 	 * free_me == NULL implies that we always allocate, even if
795 	 * there is nothing to quote.
796 	 */
797 	if (free_me != NULL) {
798 		free(*free_me);
799 		*free_me = NULL;
800 		if (!do_quote)
801 			return const_cast1(char *, src);
802 	} else {
803 		if (!do_quote)
804 			return HX_strdup(src);
805 		free_me = &tmp;
806 	}
807 
808 	*free_me = malloc(HX_quoted_size(src, type) + 1);
809 	if (*free_me == NULL)
810 		return NULL;
811 
812 	switch (type) {
813 	case HXQUOTE_SQUOTE:
814 	case HXQUOTE_DQUOTE:
815 		return HX_quote_backslash(*free_me, src, rule->chars);
816 	case HXQUOTE_HTML:
817 		return HX_quote_html(*free_me, src);
818 	case HXQUOTE_LDAPFLT:
819 	case HXQUOTE_LDAPRDN:
820 		return HX_quote_ldap(*free_me, src, rule->chars);
821 	case HXQUOTE_BASE64:
822 		return HX_quote_base64(*free_me, src);
823 	case HXQUOTE_URIENC:
824 		return HX_quote_urlenc(*free_me, src);
825 	case HXQUOTE_SQLSQUOTE:
826 	case HXQUOTE_SQLBQUOTE:
827 		return HX_quote_sqlbackslash(*free_me, src, rule->chars);
828 	}
829 	return NULL;
830 }
831 
HX_strupper(char * orig)832 EXPORT_SYMBOL char *HX_strupper(char *orig)
833 {
834 	char *expr;
835 	for (expr = orig; *expr != '\0'; ++expr)
836 		*expr = HX_toupper(*expr);
837 	return orig;
838 }
839