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(""") - 2;
653 break;
654 case '&':
655 n += sizeof("&") - 2;
656 break;
657 case '<':
658 case '>':
659 n += sizeof("<") - 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("""); break;
687 case '&': put("&"); break;
688 case '<': put("<"); break;
689 case '>': put(">"); 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