OpenVPN
buffer.c
Go to the documentation of this file.
1 /*
2  * OpenVPN -- An application to securely tunnel IP networks
3  * over a single UDP port, with support for SSL/TLS-based
4  * session authentication and key exchange,
5  * packet encryption, packet authentication, and
6  * packet compression.
7  *
8  * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2
12  * as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include "syshead.h"
29 
30 #include "common.h"
31 #include "buffer.h"
32 #include "error.h"
33 #include "mtu.h"
34 #include "misc.h"
35 
36 #include "memdbg.h"
37 
38 #include <wchar.h>
39 
40 size_t
41 array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
42 {
43  const size_t limit = 0xFFFFFFFF;
44  unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra;
45  if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit))
46  {
47  msg(M_FATAL, "attempted allocation of excessively large array");
48  }
49  return (size_t) res;
50 }
51 
52 void
53 buf_size_error(const size_t size)
54 {
55  msg(M_FATAL, "fatal buffer size error, size=%lu", (unsigned long)size);
56 }
57 
58 struct buffer
59 #ifdef DMALLOC
60 alloc_buf_debug(size_t size, const char *file, int line)
61 #else
62 alloc_buf(size_t size)
63 #endif
64 {
65  struct buffer buf;
66 
67  if (!buf_size_valid(size))
68  {
69  buf_size_error(size);
70  }
71  buf.capacity = (int)size;
72  buf.offset = 0;
73  buf.len = 0;
74 #ifdef DMALLOC
75  buf.data = openvpn_dmalloc(file, line, size);
76 #else
77  buf.data = calloc(1, size);
78 #endif
80 
81  return buf;
82 }
83 
84 struct buffer
85 #ifdef DMALLOC
86 alloc_buf_gc_debug(size_t size, struct gc_arena *gc, const char *file, int line)
87 #else
88 alloc_buf_gc(size_t size, struct gc_arena *gc)
89 #endif
90 {
91  struct buffer buf;
92  if (!buf_size_valid(size))
93  {
94  buf_size_error(size);
95  }
96  buf.capacity = (int)size;
97  buf.offset = 0;
98  buf.len = 0;
99 #ifdef DMALLOC
100  buf.data = (uint8_t *) gc_malloc_debug(size, false, gc, file, line);
101 #else
102  buf.data = (uint8_t *) gc_malloc(size, false, gc);
103 #endif
104  if (size)
105  {
106  *buf.data = 0;
107  }
108  return buf;
109 }
110 
111 struct buffer
112 #ifdef DMALLOC
113 clone_buf_debug(const struct buffer *buf, const char *file, int line)
114 #else
115 clone_buf(const struct buffer *buf)
116 #endif
117 {
118  struct buffer ret;
119  ret.capacity = buf->capacity;
120  ret.offset = buf->offset;
121  ret.len = buf->len;
122 #ifdef DMALLOC
123  ret.data = (uint8_t *) openvpn_dmalloc(file, line, buf->capacity);
124 #else
125  ret.data = (uint8_t *) malloc(buf->capacity);
126 #endif
128  memcpy(BPTR(&ret), BPTR(buf), BLEN(buf));
129  return ret;
130 }
131 
132 #ifdef BUF_INIT_TRACKING
133 
134 bool
135 buf_init_debug(struct buffer *buf, int offset, const char *file, int line)
136 {
137  buf->debug_file = file;
138  buf->debug_line = line;
139  return buf_init_dowork(buf, offset);
140 }
141 
142 static inline int
143 buf_debug_line(const struct buffer *buf)
144 {
145  return buf->debug_line;
146 }
147 
148 static const char *
149 buf_debug_file(const struct buffer *buf)
150 {
151  return buf->debug_file;
152 }
153 
154 #else /* ifdef BUF_INIT_TRACKING */
155 
156 #define buf_debug_line(buf) 0
157 #define buf_debug_file(buf) "[UNDEF]"
158 
159 #endif /* ifdef BUF_INIT_TRACKING */
160 
161 void
162 buf_clear(struct buffer *buf)
163 {
164  if (buf->capacity > 0)
165  {
166  secure_memzero(buf->data, buf->capacity);
167  }
168  buf->len = 0;
169  buf->offset = 0;
170 }
171 
172 bool
173 buf_assign(struct buffer *dest, const struct buffer *src)
174 {
175  if (!buf_init(dest, src->offset))
176  {
177  return false;
178  }
179  return buf_write(dest, BPTR(src), BLEN(src));
180 }
181 
182 void
183 free_buf(struct buffer *buf)
184 {
185  free(buf->data);
186  CLEAR(*buf);
187 }
188 
189 static void
190 free_buf_gc(struct buffer *buf, struct gc_arena *gc)
191 {
192  if (gc)
193  {
194  struct gc_entry **e = &gc->list;
195 
196  while (*e)
197  {
198  /* check if this object is the one we want to delete */
199  if ((uint8_t *)(*e + 1) == buf->data)
200  {
201  struct gc_entry *to_delete = *e;
202 
203  /* remove element from linked list and free it */
204  *e = (*e)->next;
205  free(to_delete);
206 
207  break;
208  }
209 
210  e = &(*e)->next;
211  }
212  }
213 
214  CLEAR(*buf);
215 }
216 
217 /*
218  * Return a buffer for write that is a subset of another buffer
219  */
220 struct buffer
221 buf_sub(struct buffer *buf, int size, bool prepend)
222 {
223  struct buffer ret;
224  uint8_t *data;
225 
226  CLEAR(ret);
227  data = prepend ? buf_prepend(buf, size) : buf_write_alloc(buf, size);
228  if (data)
229  {
230  ret.capacity = size;
231  ret.data = data;
232  }
233  return ret;
234 }
235 
236 /*
237  * printf append to a buffer with overflow check
238  */
239 bool
240 buf_printf(struct buffer *buf, const char *format, ...)
241 {
242  int ret = false;
243  if (buf_defined(buf))
244  {
245  va_list arglist;
246  uint8_t *ptr = BEND(buf);
247  int cap = buf_forward_capacity(buf);
248 
249  if (cap > 0)
250  {
251  int stat;
252  va_start(arglist, format);
253  stat = vsnprintf((char *)ptr, cap, format, arglist);
254  va_end(arglist);
255  *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
256  buf->len += (int) strlen((char *)ptr);
257  if (stat >= 0 && stat < cap)
258  {
259  ret = true;
260  }
261  }
262  }
263  return ret;
264 }
265 
266 bool
267 buf_puts(struct buffer *buf, const char *str)
268 {
269  int ret = false;
270  uint8_t *ptr = BEND(buf);
271  int cap = buf_forward_capacity(buf);
272  if (cap > 0)
273  {
274  strncpynt((char *)ptr, str, cap);
275  *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
276  buf->len += (int) strlen((char *)ptr);
277  ret = true;
278  }
279  return ret;
280 }
281 
282 /*
283  * write a string to the end of a buffer that was
284  * truncated by buf_printf
285  */
286 void
287 buf_catrunc(struct buffer *buf, const char *str)
288 {
289  if (buf_forward_capacity(buf) <= 1)
290  {
291  size_t len = strlen(str) + 1;
292  if (len < buf_forward_capacity_total(buf))
293  {
294  memcpy(buf->data + buf->capacity - len, str, len);
295  }
296  }
297 }
298 
299 /*
300  * convert a multi-line output to one line
301  */
302 void
304 {
305  uint8_t *cp = BPTR(buf);
306  int len = BLEN(buf);
307  while (len--)
308  {
309  if (*cp == '\n')
310  {
311  *cp = '|';
312  }
313  ++cp;
314  }
315 }
316 
317 bool
318 buffer_write_file(const char *filename, const struct buffer *buf)
319 {
320  bool ret = false;
321  int fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY,
322  S_IRUSR | S_IWUSR);
323  if (fd == -1)
324  {
325  msg(M_ERRNO, "Cannot open file '%s' for write", filename);
326  return false;
327  }
328 
329  const int size = write(fd, BPTR(buf), BLEN(buf));
330  if (size != BLEN(buf))
331  {
332  msg(M_ERRNO, "Write error on file '%s'", filename);
333  goto cleanup;
334  }
335 
336  ret = true;
337 cleanup:
338  if (close(fd) < 0)
339  {
340  msg(M_ERRNO, "Close error on file %s", filename);
341  ret = false;
342  }
343  return ret;
344 }
345 
346 /*
347  * Garbage collection
348  */
349 
350 void *
351 #ifdef DMALLOC
352 gc_malloc_debug(size_t size, bool clear, struct gc_arena *a, const char *file, int line)
353 #else
354 gc_malloc(size_t size, bool clear, struct gc_arena *a)
355 #endif
356 {
357  void *ret;
358  if (a)
359  {
360  struct gc_entry *e;
361 #ifdef DMALLOC
362  e = (struct gc_entry *) openvpn_dmalloc(file, line, size + sizeof(struct gc_entry));
363 #else
364  e = (struct gc_entry *) malloc(size + sizeof(struct gc_entry));
365 #endif
367  ret = (char *) e + sizeof(struct gc_entry);
368  e->next = a->list;
369  a->list = e;
370  }
371  else
372  {
373 #ifdef DMALLOC
374  ret = openvpn_dmalloc(file, line, size);
375 #else
376  ret = malloc(size);
377 #endif
378  check_malloc_return(ret);
379  }
380 #ifndef ZERO_BUFFER_ON_ALLOC
381  if (clear)
382 #endif
383  memset(ret, 0, size);
384  return ret;
385 }
386 
387 void *
388 gc_realloc(void *ptr, size_t size, struct gc_arena *a)
389 {
390  void *ret = realloc(ptr, size);
391  check_malloc_return(ret);
392  if (a)
393  {
394  if (ptr && ptr != ret)
395  {
396  /* find the old entry and modify it if realloc changed
397  * the pointer */
398  struct gc_entry_special *e = NULL;
399  for (e = a->list_special; e != NULL; e = e->next)
400  {
401  if (e->addr == ptr)
402  {
403  break;
404  }
405  }
406  ASSERT(e);
407  ASSERT(e->addr == ptr);
408  e->addr = ret;
409  }
410  else if (!ptr)
411  {
412  /* sets e->addr to newptr */
413  gc_addspecial(ret, free, a);
414  }
415  }
416 
417  return ret;
418 }
419 
420 void
421 x_gc_free(struct gc_arena *a)
422 {
423  struct gc_entry *e;
424  e = a->list;
425  a->list = NULL;
426 
427  while (e != NULL)
428  {
429  struct gc_entry *next = e->next;
430  free(e);
431  e = next;
432  }
433 }
434 
435 /*
436  * Functions to handle special objects in gc_entries
437  */
438 
439 void
441 {
442  struct gc_entry_special *e;
443  e = a->list_special;
444  a->list_special = NULL;
445 
446  while (e != NULL)
447  {
448  struct gc_entry_special *next = e->next;
449  e->free_fnc(e->addr);
450  free(e);
451  e = next;
452  }
453 }
454 
455 void
456 gc_addspecial(void *addr, void (*free_function)(void *), struct gc_arena *a)
457 {
458  ASSERT(a);
459  struct gc_entry_special *e;
460 #ifdef DMALLOC
461  e = (struct gc_entry_special *) openvpn_dmalloc(file, line, sizeof(struct gc_entry_special));
462 #else
463  e = (struct gc_entry_special *) malloc(sizeof(struct gc_entry_special));
464 #endif
466  e->free_fnc = free_function;
467  e->addr = addr;
468 
469  e->next = a->list_special;
470  a->list_special = e;
471 }
472 
473 
474 /*
475  * Transfer src arena to dest, resetting src to an empty arena.
476  */
477 void
478 gc_transfer(struct gc_arena *dest, struct gc_arena *src)
479 {
480  if (dest && src)
481  {
482  struct gc_entry *e = src->list;
483  if (e)
484  {
485  while (e->next != NULL)
486  {
487  e = e->next;
488  }
489  e->next = dest->list;
490  dest->list = src->list;
491  src->list = NULL;
492  }
493  }
494 }
495 
496 /*
497  * Hex dump -- Output a binary buffer to a hex string and return it.
498  */
499 
500 char *
501 format_hex_ex(const uint8_t *data, int size, int maxoutput,
502  unsigned int space_break_flags, const char *separator,
503  struct gc_arena *gc)
504 {
505  const size_t bytes_per_hexblock = space_break_flags & FHE_SPACE_BREAK_MASK;
506  const size_t separator_len = separator ? strlen(separator) : 0;
507  static_assert(INT_MAX <= SIZE_MAX, "Code assumes INT_MAX <= SIZE_MAX");
508  const size_t out_len = maxoutput > 0 ? maxoutput :
509  ((size * 2) + ((size / bytes_per_hexblock) * separator_len) + 2);
510 
511  struct buffer out = alloc_buf_gc(out_len, gc);
512  for (int i = 0; i < size; ++i)
513  {
514  if (separator && i && !(i % bytes_per_hexblock))
515  {
516  buf_printf(&out, "%s", separator);
517  }
518  if (space_break_flags & FHE_CAPS)
519  {
520  buf_printf(&out, "%02X", data[i]);
521  }
522  else
523  {
524  buf_printf(&out, "%02x", data[i]);
525  }
526  }
527  buf_catrunc(&out, "[more...]");
528  return (char *)out.data;
529 }
530 
531 /*
532  * remove specific trailing character
533  */
534 
535 void
536 buf_rmtail(struct buffer *buf, uint8_t remove)
537 {
538  uint8_t *cp = BLAST(buf);
539  if (cp && *cp == remove)
540  {
541  *cp = '\0';
542  --buf->len;
543  }
544 }
545 
546 /*
547  * force a null termination even it requires
548  * truncation of the last char.
549  */
550 void
552 {
553  char *last = (char *) BLAST(buf);
554  if (last && *last == '\0') /* already terminated? */
555  {
556  return;
557  }
558 
559  if (!buf_safe(buf, 1)) /* make space for trailing null */
560  {
561  buf_inc_len(buf, -1);
562  }
563 
564  buf_write_u8(buf, 0);
565 }
566 
567 /*
568  * Remove trailing \r and \n chars and ensure
569  * null termination.
570  */
571 void
572 buf_chomp(struct buffer *buf)
573 {
574  while (true)
575  {
576  char *last = (char *) BLAST(buf);
577  if (!last)
578  {
579  break;
580  }
581  if (char_class(*last, CC_CRLF|CC_NULL))
582  {
583  if (!buf_inc_len(buf, -1))
584  {
585  break;
586  }
587  }
588  else
589  {
590  break;
591  }
592  }
593  buf_null_terminate(buf);
594 }
595 
596 const char *
597 skip_leading_whitespace(const char *str)
598 {
599  while (*str)
600  {
601  const char c = *str;
602  if (!(c == ' ' || c == '\t'))
603  {
604  break;
605  }
606  ++str;
607  }
608  return str;
609 }
610 
611 /*
612  * like buf_null_terminate, but operate on strings
613  */
614 void
615 string_null_terminate(char *str, int len, int capacity)
616 {
617  ASSERT(len >= 0 && len <= capacity && capacity > 0);
618  if (len < capacity)
619  {
620  *(str + len) = '\0';
621  }
622  else if (len == capacity)
623  {
624  *(str + len - 1) = '\0';
625  }
626 }
627 
628 /*
629  * Remove trailing \r and \n chars.
630  */
631 void
632 chomp(char *str)
633 {
634  rm_trailing_chars(str, "\r\n");
635 }
636 
637 /*
638  * Remove trailing chars
639  */
640 void
641 rm_trailing_chars(char *str, const char *what_to_delete)
642 {
643  bool modified;
644  do
645  {
646  const size_t len = strlen(str);
647  modified = false;
648  if (len > 0)
649  {
650  char *cp = str + (len - 1);
651  if (strchr(what_to_delete, *cp) != NULL)
652  {
653  *cp = '\0';
654  modified = true;
655  }
656  }
657  } while (modified);
658 }
659 
660 /*
661  * Allocate a string
662  */
663 char *
664 #ifdef DMALLOC
665 string_alloc_debug(const char *str, struct gc_arena *gc, const char *file, int line)
666 #else
667 string_alloc(const char *str, struct gc_arena *gc)
668 #endif
669 {
670  if (str)
671  {
672  const size_t n = strlen(str) + 1;
673  char *ret;
674 
675  if (gc)
676  {
677 #ifdef DMALLOC
678  ret = (char *) gc_malloc_debug(n, false, gc, file, line);
679 #else
680  ret = (char *) gc_malloc(n, false, gc);
681 #endif
682  }
683  else
684  {
685  /* If there are no garbage collector available, it's expected
686  * that the caller cleans up afterwards. This is coherent with the
687  * earlier behaviour when gc_malloc() would be called with gc == NULL
688  */
689 #ifdef DMALLOC
690  ret = openvpn_dmalloc(file, line, n);
691 #else
692  ret = calloc(1, n);
693 #endif
694  check_malloc_return(ret);
695  }
696  memcpy(ret, str, n);
697  return ret;
698  }
699  else
700  {
701  return NULL;
702  }
703 }
704 
705 /*
706  * Erase all characters in a string
707  */
708 void
709 string_clear(char *str)
710 {
711  if (str)
712  {
713  secure_memzero(str, strlen(str));
714  }
715 }
716 
717 /*
718  * Return the length of a string array
719  */
720 int
721 string_array_len(const char **array)
722 {
723  int i = 0;
724  if (array)
725  {
726  while (array[i])
727  {
728  ++i;
729  }
730  }
731  return i;
732 }
733 
734 char *
735 print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
736 {
737  struct buffer out = alloc_buf_gc(256, gc);
738  int i = 0;
739  for (;; )
740  {
741  const char *cp = *p++;
742  if (!cp)
743  {
744  break;
745  }
746  if (i)
747  {
748  buf_printf(&out, " ");
749  }
750  if (flags & PA_BRACKET)
751  {
752  buf_printf(&out, "[%s]", cp);
753  }
754  else
755  {
756  buf_printf(&out, "%s", cp);
757  }
758  ++i;
759  }
760  return BSTR(&out);
761 }
762 
763 /*
764  * Allocate a string inside a buffer
765  */
766 struct buffer
767 #ifdef DMALLOC
768 string_alloc_buf_debug(const char *str, struct gc_arena *gc, const char *file, int line)
769 #else
770 string_alloc_buf(const char *str, struct gc_arena *gc)
771 #endif
772 {
773  struct buffer buf;
774 
775  ASSERT(str);
776 
777 #ifdef DMALLOC
778  buf_set_read(&buf, (uint8_t *) string_alloc_debug(str, gc, file, line), strlen(str) + 1);
779 #else
780  buf_set_read(&buf, (uint8_t *) string_alloc(str, gc), strlen(str) + 1);
781 #endif
782 
783  if (buf.len > 0) /* Don't count trailing '\0' as part of length */
784  {
785  --buf.len;
786  }
787 
788  return buf;
789 }
790 
791 /*
792  * String comparison
793  */
794 
795 bool
796 buf_string_match_head_str(const struct buffer *src, const char *match)
797 {
798  const size_t size = strlen(match);
799  if (size > src->len)
800  {
801  return false;
802  }
803  return memcmp(BPTR(src), match, size) == 0;
804 }
805 
806 bool
807 buf_string_compare_advance(struct buffer *src, const char *match)
808 {
809  if (buf_string_match_head_str(src, match))
810  {
811  buf_advance(src, (int)strlen(match));
812  return true;
813  }
814  else
815  {
816  return false;
817  }
818 }
819 
820 int
821 buf_substring_len(const struct buffer *buf, int delim)
822 {
823  int i = 0;
824  struct buffer tmp = *buf;
825  int c;
826 
827  while ((c = buf_read_u8(&tmp)) >= 0)
828  {
829  ++i;
830  if (c == delim)
831  {
832  return i;
833  }
834  }
835  return -1;
836 }
837 
838 /*
839  * String parsing
840  */
841 
842 bool
843 buf_parse(struct buffer *buf, const int delim, char *line, const int size)
844 {
845  bool eol = false;
846  int n = 0;
847  int c;
848 
849  ASSERT(size > 0);
850 
851  do
852  {
853  c = buf_read_u8(buf);
854  if (c < 0)
855  {
856  eol = true;
857  }
858  if (c <= 0 || c == delim)
859  {
860  c = 0;
861  }
862  if (n >= size)
863  {
864  break;
865  }
866  line[n++] = c;
867  }
868  while (c);
869 
870  line[size-1] = '\0';
871  return !(eol && !strlen(line));
872 }
873 
874 /*
875  * Print a string which might be NULL
876  */
877 const char *
878 np(const char *str)
879 {
880  if (str)
881  {
882  return str;
883  }
884  else
885  {
886  return "[NULL]";
887  }
888 }
889 
890 /*
891  * Classify and mutate strings based on character types.
892  */
893 
894 bool
895 char_class(const unsigned char c, const unsigned int flags)
896 {
897  if (!flags)
898  {
899  return false;
900  }
901  if (flags & CC_ANY)
902  {
903  return true;
904  }
905 
906  if ((flags & CC_NULL) && c == '\0')
907  {
908  return true;
909  }
910 
911  if ((flags & CC_ALNUM) && isalnum(c))
912  {
913  return true;
914  }
915  if ((flags & CC_ALPHA) && isalpha(c))
916  {
917  return true;
918  }
919  if ((flags & CC_ASCII) && isascii(c))
920  {
921  return true;
922  }
923  if ((flags & CC_CNTRL) && iscntrl(c))
924  {
925  return true;
926  }
927  if ((flags & CC_DIGIT) && isdigit(c))
928  {
929  return true;
930  }
931  if ((flags & CC_PRINT) && (c >= 32 && c != 127)) /* allow ascii non-control and UTF-8, consider DEL to be a control */
932  {
933  return true;
934  }
935  if ((flags & CC_PUNCT) && ispunct(c))
936  {
937  return true;
938  }
939  if ((flags & CC_SPACE) && isspace(c))
940  {
941  return true;
942  }
943  if ((flags & CC_XDIGIT) && isxdigit(c))
944  {
945  return true;
946  }
947 
948  if ((flags & CC_BLANK) && (c == ' ' || c == '\t'))
949  {
950  return true;
951  }
952  if ((flags & CC_NEWLINE) && c == '\n')
953  {
954  return true;
955  }
956  if ((flags & CC_CR) && c == '\r')
957  {
958  return true;
959  }
960 
961  if ((flags & CC_BACKSLASH) && c == '\\')
962  {
963  return true;
964  }
965  if ((flags & CC_UNDERBAR) && c == '_')
966  {
967  return true;
968  }
969  if ((flags & CC_DASH) && c == '-')
970  {
971  return true;
972  }
973  if ((flags & CC_DOT) && c == '.')
974  {
975  return true;
976  }
977  if ((flags & CC_COMMA) && c == ',')
978  {
979  return true;
980  }
981  if ((flags & CC_COLON) && c == ':')
982  {
983  return true;
984  }
985  if ((flags & CC_SLASH) && c == '/')
986  {
987  return true;
988  }
989  if ((flags & CC_SINGLE_QUOTE) && c == '\'')
990  {
991  return true;
992  }
993  if ((flags & CC_DOUBLE_QUOTE) && c == '\"')
994  {
995  return true;
996  }
997  if ((flags & CC_REVERSE_QUOTE) && c == '`')
998  {
999  return true;
1000  }
1001  if ((flags & CC_AT) && c == '@')
1002  {
1003  return true;
1004  }
1005  if ((flags & CC_EQUAL) && c == '=')
1006  {
1007  return true;
1008  }
1009  if ((flags & CC_LESS_THAN) && c == '<')
1010  {
1011  return true;
1012  }
1013  if ((flags & CC_GREATER_THAN) && c == '>')
1014  {
1015  return true;
1016  }
1017  if ((flags & CC_PIPE) && c == '|')
1018  {
1019  return true;
1020  }
1021  if ((flags & CC_QUESTION_MARK) && c == '?')
1022  {
1023  return true;
1024  }
1025  if ((flags & CC_ASTERISK) && c == '*')
1026  {
1027  return true;
1028  }
1029 
1030  return false;
1031 }
1032 
1033 static inline bool
1034 char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
1035 {
1036  return char_class(c, inclusive) && !char_class(c, exclusive);
1037 }
1038 
1039 bool
1040 string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
1041 {
1042  char c;
1043  ASSERT(str);
1044  while ((c = *str++))
1045  {
1046  if (!char_inc_exc(c, inclusive, exclusive))
1047  {
1048  return false;
1049  }
1050  }
1051  return true;
1052 }
1053 
1054 /*
1055  * Modify string in place.
1056  * Guaranteed to not increase string length.
1057  */
1058 bool
1059 string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
1060 {
1061  const char *in = str;
1062  bool ret = true;
1063 
1064  ASSERT(str);
1065 
1066  while (true)
1067  {
1068  char c = *in++;
1069  if (c)
1070  {
1071  if (!char_inc_exc(c, inclusive, exclusive))
1072  {
1073  c = replace;
1074  ret = false;
1075  }
1076  if (c)
1077  {
1078  *str++ = c;
1079  }
1080  }
1081  else
1082  {
1083  *str = '\0';
1084  break;
1085  }
1086  }
1087  return ret;
1088 }
1089 
1090 bool
1091 string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
1092 {
1093  ASSERT(buf);
1094 
1095  for (int i = 0; i < BLEN(buf); i++)
1096  {
1097  char c = BSTR(buf)[i];
1098 
1099  if (!char_inc_exc(c, inclusive, exclusive))
1100  {
1101  return false;
1102  }
1103  }
1104  return true;
1105 }
1106 
1107 const char *
1108 string_mod_const(const char *str,
1109  const unsigned int inclusive,
1110  const unsigned int exclusive,
1111  const char replace,
1112  struct gc_arena *gc)
1113 {
1114  if (str)
1115  {
1116  char *buf = string_alloc(str, gc);
1117  string_mod(buf, inclusive, exclusive, replace);
1118  return buf;
1119  }
1120  else
1121  {
1122  return NULL;
1123  }
1124 }
1125 
1126 void
1127 string_replace_leading(char *str, const char match, const char replace)
1128 {
1129  ASSERT(match != '\0');
1130  while (*str)
1131  {
1132  if (*str == match)
1133  {
1134  *str = replace;
1135  }
1136  else
1137  {
1138  break;
1139  }
1140  ++str;
1141  }
1142 }
1143 
1144 #ifdef VERIFY_ALIGNMENT
1145 void
1146 valign4(const struct buffer *buf, const char *file, const int line)
1147 {
1148  if (buf && buf->len)
1149  {
1150  int msglevel = D_ALIGN_DEBUG;
1151  const unsigned int u = (unsigned int) BPTR(buf);
1152 
1153  if (u & (PAYLOAD_ALIGN-1))
1154  {
1155  msglevel = D_ALIGN_ERRORS;
1156  }
1157 
1158  msg(msglevel, "%sAlignment at %s/%d ptr=" ptr_format " OLC=%d/%d/%d I=%s/%d",
1159  (msglevel == D_ALIGN_ERRORS) ? "ERROR: " : "",
1160  file,
1161  line,
1162  (ptr_type)buf->data,
1163  buf->offset,
1164  buf->len,
1165  buf->capacity,
1166  buf_debug_file(buf),
1167  buf_debug_line(buf));
1168  }
1169 }
1170 #endif /* ifdef VERIFY_ALIGNMENT */
1171 
1172 /*
1173  * struct buffer_list
1174  */
1175 struct buffer_list *
1177 {
1178  struct buffer_list *ret;
1179  ALLOC_OBJ_CLEAR(ret, struct buffer_list);
1180  ret->size = 0;
1181  return ret;
1182 }
1183 
1184 void
1186 {
1187  if (ol)
1188  {
1189  buffer_list_reset(ol);
1190  free(ol);
1191  }
1192 }
1193 
1194 bool
1196 {
1197  return ol && ol->head != NULL;
1198 }
1199 
1200 void
1202 {
1203  struct buffer_entry *e = ol->head;
1204  while (e)
1205  {
1206  struct buffer_entry *next = e->next;
1207  free_buf(&e->buf);
1208  free(e);
1209  e = next;
1210  }
1211  ol->head = ol->tail = NULL;
1212  ol->size = 0;
1213 }
1214 
1215 void
1216 buffer_list_push(struct buffer_list *ol, const char *str)
1217 {
1218  if (str)
1219  {
1220  const size_t len = strlen((const char *)str);
1221  struct buffer_entry *e = buffer_list_push_data(ol, str, len+1);
1222  if (e)
1223  {
1224  e->buf.len = (int)len; /* Don't count trailing '\0' as part of length */
1225  }
1226  }
1227 }
1228 
1229 struct buffer_entry *
1230 buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
1231 {
1232  struct buffer_entry *e = NULL;
1233  if (data)
1234  {
1235  ALLOC_OBJ_CLEAR(e, struct buffer_entry);
1236 
1237  ++ol->size;
1238  if (ol->tail)
1239  {
1240  ASSERT(ol->head);
1241  ol->tail->next = e;
1242  }
1243  else
1244  {
1245  ASSERT(!ol->head);
1246  ol->head = e;
1247  }
1248  e->buf = alloc_buf(size);
1249  memcpy(e->buf.data, data, size);
1250  e->buf.len = (int)size;
1251  ol->tail = e;
1252  }
1253  return e;
1254 }
1255 
1256 struct buffer *
1258 {
1259  if (ol && ol->head)
1260  {
1261  return &ol->head->buf;
1262  }
1263  else
1264  {
1265  return NULL;
1266  }
1267 }
1268 
1269 void
1270 buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len,
1271  const char *sep)
1272 {
1273  const size_t sep_len = strlen(sep);
1274  struct buffer_entry *more = bl->head;
1275  size_t size = 0;
1276  int count = 0;
1277  for (count = 0; more; ++count)
1278  {
1279  size_t extra_len = BLEN(&more->buf) + sep_len;
1280  if (size + extra_len > max_len)
1281  {
1282  break;
1283  }
1284 
1285  size += extra_len;
1286  more = more->next;
1287  }
1288 
1289  if (count >= 2)
1290  {
1291  struct buffer_entry *f;
1292  ALLOC_OBJ_CLEAR(f, struct buffer_entry);
1293  f->buf = alloc_buf(size + 1); /* prevent 0-byte malloc */
1294 
1295  struct buffer_entry *e = bl->head;
1296  for (size_t i = 0; e && i < count; ++i)
1297  {
1298  struct buffer_entry *next = e->next;
1299  buf_copy(&f->buf, &e->buf);
1300  buf_write(&f->buf, sep, sep_len);
1301  free_buf(&e->buf);
1302  free(e);
1303  e = next;
1304  }
1305  bl->head = f;
1306  bl->size -= count - 1;
1307  f->next = more;
1308  if (!more)
1309  {
1310  bl->tail = f;
1311  }
1312  }
1313 }
1314 
1315 void
1316 buffer_list_aggregate(struct buffer_list *bl, const size_t max)
1317 {
1318  buffer_list_aggregate_separator(bl, max, "");
1319 }
1320 
1321 void
1323 {
1324  if (ol && ol->head)
1325  {
1326  struct buffer_entry *e = ol->head->next;
1327  free_buf(&ol->head->buf);
1328  free(ol->head);
1329  ol->head = e;
1330  --ol->size;
1331  if (!e)
1332  {
1333  ol->tail = NULL;
1334  }
1335  }
1336 }
1337 
1338 void
1340 {
1341  if (ol->head)
1342  {
1343  struct buffer *buf = &ol->head->buf;
1344  ASSERT(buf_advance(buf, n));
1345  if (!BLEN(buf))
1346  {
1347  buffer_list_pop(ol);
1348  }
1349  }
1350 }
1351 
1352 struct buffer_list *
1353 buffer_list_file(const char *fn, int max_line_len)
1354 {
1355  FILE *fp = platform_fopen(fn, "r");
1356  struct buffer_list *bl = NULL;
1357 
1358  if (fp)
1359  {
1360  char *line = (char *) malloc(max_line_len);
1361  if (line)
1362  {
1363  bl = buffer_list_new();
1364  while (fgets(line, max_line_len, fp) != NULL)
1365  {
1366  buffer_list_push(bl, line);
1367  }
1368  free(line);
1369  }
1370  fclose(fp);
1371  }
1372  return bl;
1373 }
1374 
1375 struct buffer
1376 buffer_read_from_file(const char *filename, struct gc_arena *gc)
1377 {
1378  struct buffer ret = { 0 };
1379 
1380  platform_stat_t file_stat = { 0 };
1381  if (platform_stat(filename, &file_stat) < 0)
1382  {
1383  return ret;
1384  }
1385 
1386  FILE *fp = platform_fopen(filename, "r");
1387  if (!fp)
1388  {
1389  return ret;
1390  }
1391 
1392  const size_t size = file_stat.st_size;
1393  ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */
1394  size_t read_size = fread(BPTR(&ret), 1, size, fp);
1395  if (read_size == 0)
1396  {
1397  free_buf_gc(&ret, gc);
1398  goto cleanup;
1399  }
1400  ASSERT(buf_inc_len(&ret, (int)read_size));
1401  buf_null_terminate(&ret);
1402 
1403 cleanup:
1404  fclose(fp);
1405  return ret;
1406 }
PA_BRACKET
#define PA_BRACKET
Definition: buffer.h:144
gc_arena::list
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition: buffer.h:118
buf_safe
static bool buf_safe(const struct buffer *buf, size_t len)
Definition: buffer.h:525
buffer_write_file
bool buffer_write_file(const char *filename, const struct buffer *buf)
Write buffer contents to file.
Definition: buffer.c:318
buffer_read_from_file
struct buffer buffer_read_from_file(const char *filename, struct gc_arena *gc)
buffer_read_from_file - copy the content of a file into a buffer
Definition: buffer.c:1376
CC_BACKSLASH
#define CC_BACKSLASH
backslash
Definition: buffer.h:905
buf_rmtail
void buf_rmtail(struct buffer *buf, uint8_t remove)
Definition: buffer.c:536
error.h
gc_addspecial
void gc_addspecial(void *addr, void(*free_function)(void *), struct gc_arena *a)
Definition: buffer.c:456
string_array_len
int string_array_len(const char **array)
Definition: buffer.c:721
M_ERRNO
#define M_ERRNO
Definition: error.h:94
buf_forward_capacity_total
static int buf_forward_capacity_total(const struct buffer *buf)
Definition: buffer.h:564
CC_SLASH
#define CC_SLASH
slash
Definition: buffer.h:911
buffer::len
int len
Length in bytes of the actual content within the allocated memory.
Definition: buffer.h:66
M_FATAL
#define M_FATAL
Definition: error.h:89
BLAST
#define BLAST(buf)
Definition: buffer.h:126
unlikely
#define unlikely(x)
Definition: syshead.h:36
gc_entry::next
struct gc_entry * next
Pointer to the next item in the linked list.
Definition: buffer.h:89
buf_init
#define buf_init(buf, offset)
Definition: buffer.h:209
CC_UNDERBAR
#define CC_UNDERBAR
underscore
Definition: buffer.h:906
static_assert
#define static_assert(expr, diagnostic)
Definition: error.h:212
BSTR
#define BSTR(buf)
Definition: buffer.h:129
buf_size_valid
static bool buf_size_valid(const size_t size)
Definition: buffer.h:285
CC_ASTERISK
#define CC_ASTERISK
asterisk
Definition: buffer.h:921
rm_trailing_chars
void rm_trailing_chars(char *str, const char *what_to_delete)
Definition: buffer.c:641
array_mult_safe
size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra)
Definition: buffer.c:41
buffer::capacity
int capacity
Size in bytes of memory allocated by malloc().
Definition: buffer.h:62
alloc_buf_gc
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Definition: buffer.c:88
buf_null_terminate
void buf_null_terminate(struct buffer *buf)
Definition: buffer.c:551
CC_CRLF
#define CC_CRLF
carriage return or newline
Definition: buffer.h:925
CC_DASH
#define CC_DASH
dash
Definition: buffer.h:907
gc_entry
Garbage collection entry for one dynamically allocated block of memory.
Definition: buffer.h:87
buffer_list_peek
struct buffer * buffer_list_peek(struct buffer_list *ol)
Retrieve the head buffer.
Definition: buffer.c:1257
buffer_list_aggregate_separator
void buffer_list_aggregate_separator(struct buffer_list *bl, const size_t max_len, const char *sep)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition: buffer.c:1270
buf_sub
struct buffer buf_sub(struct buffer *buf, int size, bool prepend)
Definition: buffer.c:221
buf_clear
void buf_clear(struct buffer *buf)
Definition: buffer.c:162
buf_copy
static bool buf_copy(struct buffer *dest, const struct buffer *src)
Definition: buffer.h:717
format_hex_ex
char * format_hex_ex(const uint8_t *data, int size, int maxoutput, unsigned int space_break_flags, const char *separator, struct gc_arena *gc)
Definition: buffer.c:501
BEND
#define BEND(buf)
Definition: buffer.h:125
clone_buf
struct buffer clone_buf(const struct buffer *buf)
Definition: buffer.c:115
CC_COLON
#define CC_COLON
colon
Definition: buffer.h:910
gc_entry_special::free_fnc
void(* free_fnc)(void *)
Definition: buffer.h:101
gc_arena::list_special
struct gc_entry_special * list_special
Definition: buffer.h:120
CC_ALNUM
#define CC_ALNUM
alphanumeric isalnum()
Definition: buffer.h:891
D_ALIGN_DEBUG
#define D_ALIGN_DEBUG
Definition: errlevel.h:142
buffer_list_push_data
struct buffer_entry * buffer_list_push_data(struct buffer_list *ol, const void *data, size_t size)
Allocates and appends a new buffer containing data of length size.
Definition: buffer.c:1230
x_gc_freespecial
void x_gc_freespecial(struct gc_arena *a)
Definition: buffer.c:440
CLEAR
#define CLEAR(x)
Definition: basic.h:33
CC_NEWLINE
#define CC_NEWLINE
newline
Definition: buffer.h:902
mtu.h
buffer_list_file
struct buffer_list * buffer_list_file(const char *fn, int max_line_len)
Definition: buffer.c:1353
CC_DOUBLE_QUOTE
#define CC_DOUBLE_QUOTE
double quote
Definition: buffer.h:913
platform_stat_t
struct _stat platform_stat_t
Definition: platform.h:146
string_alloc
char * string_alloc(const char *str, struct gc_arena *gc)
Definition: buffer.c:667
secure_memzero
static void secure_memzero(void *data, size_t len)
Securely zeroise memory.
Definition: buffer.h:414
ASSERT
#define ASSERT(x)
Definition: error.h:195
string_clear
void string_clear(char *str)
Definition: buffer.c:709
string_replace_leading
void string_replace_leading(char *str, const char match, const char replace)
Definition: buffer.c:1127
buffer_entry::buf
struct buffer buf
Definition: buffer.h:1121
buf_chomp
void buf_chomp(struct buffer *buf)
Definition: buffer.c:572
buf_advance
static bool buf_advance(struct buffer *buf, int size)
Definition: buffer.h:623
buf_size_error
void buf_size_error(const size_t size)
Definition: buffer.c:53
buf_inc_len
static bool buf_inc_len(struct buffer *buf, int inc)
Definition: buffer.h:595
CC_QUESTION_MARK
#define CC_QUESTION_MARK
question mark
Definition: buffer.h:920
CC_SINGLE_QUOTE
#define CC_SINGLE_QUOTE
single quote
Definition: buffer.h:912
write
@ write
Definition: interactive.c:219
BLEN
#define BLEN(buf)
Definition: buffer.h:127
buf_debug_file
#define buf_debug_file(buf)
Definition: buffer.c:157
buf_write_u8
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Definition: buffer.h:697
buf_assign
bool buf_assign(struct buffer *dest, const struct buffer *src)
Definition: buffer.c:173
CC_PRINT
#define CC_PRINT
printable (>= 32, != 127)
Definition: buffer.h:896
string_mod
bool string_mod(char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace)
Modifies a string in place by replacing certain classes of characters of it with a specified characte...
Definition: buffer.c:1059
buffer_entry::next
struct buffer_entry * next
Definition: buffer.h:1122
misc.h
buffer_list_push
void buffer_list_push(struct buffer_list *ol, const char *str)
Allocates and appends a new buffer containing str as data to ol.
Definition: buffer.c:1216
CC_LESS_THAN
#define CC_LESS_THAN
less than sign
Definition: buffer.h:917
FHE_CAPS
#define FHE_CAPS
Definition: buffer.h:503
CC_GREATER_THAN
#define CC_GREATER_THAN
greater than sign
Definition: buffer.h:918
CC_CR
#define CC_CR
carriage return
Definition: buffer.h:903
char_class
bool char_class(const unsigned char c, const unsigned int flags)
Definition: buffer.c:895
convert_to_one_line
void convert_to_one_line(struct buffer *buf)
Definition: buffer.c:303
CC_PIPE
#define CC_PIPE
pipe
Definition: buffer.h:919
CC_EQUAL
#define CC_EQUAL
equal sign
Definition: buffer.h:916
gc_transfer
void gc_transfer(struct gc_arena *dest, struct gc_arena *src)
Definition: buffer.c:478
CC_REVERSE_QUOTE
#define CC_REVERSE_QUOTE
reverse quote
Definition: buffer.h:914
string_check_buf
bool string_check_buf(struct buffer *buf, const unsigned int inclusive, const unsigned int exclusive)
Check a buffer if it only consists of allowed characters.
Definition: buffer.c:1091
CC_DIGIT
#define CC_DIGIT
digit isdigit()
Definition: buffer.h:895
CC_BLANK
#define CC_BLANK
space or tab
Definition: buffer.h:901
CC_AT
#define CC_AT
at sign
Definition: buffer.h:915
buffer
Wrapper structure for dynamically allocated memory.
Definition: buffer.h:60
buffer_list::size
int size
Definition: buffer.h:1129
buffer_list_new
struct buffer_list * buffer_list_new(void)
Allocate an empty buffer list of capacity max_size.
Definition: buffer.c:1176
CC_SPACE
#define CC_SPACE
whitespace isspace()
Definition: buffer.h:898
CC_ASCII
#define CC_ASCII
ASCII character.
Definition: buffer.h:893
CC_COMMA
#define CC_COMMA
comma
Definition: buffer.h:909
buf_write
static bool buf_write(struct buffer *dest, const void *src, size_t size)
Definition: buffer.h:673
CC_ANY
#define CC_ANY
any character
Definition: buffer.h:888
buffer.h
syshead.h
platform_fopen
FILE * platform_fopen(const char *path, const char *mode)
Definition: platform.c:514
BPTR
#define BPTR(buf)
Definition: buffer.h:124
CC_DOT
#define CC_DOT
dot
Definition: buffer.h:908
np
const char * np(const char *str)
Definition: buffer.c:878
CC_ALPHA
#define CC_ALPHA
alphabetic isalpha()
Definition: buffer.h:892
gc_arena
Garbage collection arena used to keep track of dynamically allocated memory.
Definition: buffer.h:116
free_buf_gc
static void free_buf_gc(struct buffer *buf, struct gc_arena *gc)
Definition: buffer.c:190
string_class
bool string_class(const char *str, const unsigned int inclusive, const unsigned int exclusive)
Definition: buffer.c:1040
CC_PUNCT
#define CC_PUNCT
punctuation ispunct()
Definition: buffer.h:897
buffer::offset
int offset
Offset in bytes of the actual content within the allocated memory.
Definition: buffer.h:64
strncpynt
static void strncpynt(char *dest, const char *src, size_t maxlen)
Definition: buffer.h:361
buf_init_dowork
static bool buf_init_dowork(struct buffer *buf, int offset)
Definition: buffer.h:319
buf_prepend
static uint8_t * buf_prepend(struct buffer *buf, int size)
Definition: buffer.h:611
buffer_list::tail
struct buffer_entry * tail
Definition: buffer.h:1128
buffer_list_pop
void buffer_list_pop(struct buffer_list *ol)
Definition: buffer.c:1322
gc_entry_special
Garbage collection entry for a specially allocated structure that needs a custom free function to be ...
Definition: buffer.h:98
platform_stat
int platform_stat(const char *path, platform_stat_t *buf)
Definition: platform.c:540
buf_puts
bool buf_puts(struct buffer *buf, const char *str)
Definition: buffer.c:267
free_buf
void free_buf(struct buffer *buf)
Definition: buffer.c:183
common.h
string_null_terminate
void string_null_terminate(char *str, int len, int capacity)
Definition: buffer.c:615
buf_string_match_head_str
bool buf_string_match_head_str(const struct buffer *src, const char *match)
Definition: buffer.c:796
chomp
void chomp(char *str)
Definition: buffer.c:632
PAYLOAD_ALIGN
#define PAYLOAD_ALIGN
Definition: mtu.h:91
FHE_SPACE_BREAK_MASK
#define FHE_SPACE_BREAK_MASK
Definition: buffer.h:502
buf_string_compare_advance
bool buf_string_compare_advance(struct buffer *src, const char *match)
Definition: buffer.c:807
buffer_list_advance
void buffer_list_advance(struct buffer_list *ol, int n)
Definition: buffer.c:1339
gc_malloc
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Definition: buffer.c:354
ptr_type
unsigned long ptr_type
Definition: common.h:58
x_gc_free
void x_gc_free(struct gc_arena *a)
Definition: buffer.c:421
string_alloc_buf
struct buffer string_alloc_buf(const char *str, struct gc_arena *gc)
Definition: buffer.c:770
buffer_list_defined
bool buffer_list_defined(const struct buffer_list *ol)
Checks if the list is valid and non-empty.
Definition: buffer.c:1195
ALLOC_OBJ_CLEAR
#define ALLOC_OBJ_CLEAR(dptr, type)
Definition: buffer.h:1065
gc_entry_special::next
struct gc_entry_special * next
Definition: buffer.h:100
buf_write_alloc
static uint8_t * buf_write_alloc(struct buffer *buf, size_t size)
Definition: buffer.h:640
config.h
D_ALIGN_ERRORS
#define D_ALIGN_ERRORS
Definition: errlevel.h:70
buffer_list_free
void buffer_list_free(struct buffer_list *ol)
Frees a buffer list and all the buffers in it.
Definition: buffer.c:1185
buffer_list_aggregate
void buffer_list_aggregate(struct buffer_list *bl, const size_t max)
Aggregates as many buffers as possible from bl in a new buffer of maximum length max_len .
Definition: buffer.c:1316
gc_entry_special::addr
void * addr
Definition: buffer.h:102
CC_NULL
#define CC_NULL
null character \0
Definition: buffer.h:889
CC_XDIGIT
#define CC_XDIGIT
hex digit isxdigit()
Definition: buffer.h:899
check_malloc_return
static void check_malloc_return(void *p)
Definition: buffer.h:1108
buf_debug_line
#define buf_debug_line(buf)
Definition: buffer.c:156
buf_substring_len
int buf_substring_len(const struct buffer *buf, int delim)
Definition: buffer.c:821
buf_read_u8
static int buf_read_u8(struct buffer *buf)
Definition: buffer.h:795
platform_open
int platform_open(const char *path, int flags, int mode)
Definition: platform.c:527
buf_forward_capacity
static int buf_forward_capacity(const struct buffer *buf)
Definition: buffer.h:546
print_argv
char * print_argv(const char **p, struct gc_arena *gc, const unsigned int flags)
Definition: buffer.c:735
CC_CNTRL
#define CC_CNTRL
control character iscntrl()
Definition: buffer.h:894
char_inc_exc
static bool char_inc_exc(const char c, const unsigned int inclusive, const unsigned int exclusive)
Definition: buffer.c:1034
alloc_buf
struct buffer alloc_buf(size_t size)
Definition: buffer.c:62
memdbg.h
buffer_list_reset
void buffer_list_reset(struct buffer_list *ol)
Empty the list ol and frees all the contained buffers.
Definition: buffer.c:1201
skip_leading_whitespace
const char * skip_leading_whitespace(const char *str)
Definition: buffer.c:597
buffer_list
Definition: buffer.h:1125
string_mod_const
const char * string_mod_const(const char *str, const unsigned int inclusive, const unsigned int exclusive, const char replace, struct gc_arena *gc)
Returns a copy of a string with certain classes of characters of it replaced with a specified charact...
Definition: buffer.c:1108
msg
#define msg(flags,...)
Definition: error.h:144
gc_realloc
void * gc_realloc(void *ptr, size_t size, struct gc_arena *a)
allows to realloc a pointer previously allocated by gc_malloc or gc_realloc
Definition: buffer.c:388
buffer_entry
Definition: buffer.h:1119
buf_defined
static bool buf_defined(const struct buffer *buf)
Definition: buffer.h:228
http-client.f
string f
Definition: http-client.py:6
buf_printf
bool buf_printf(struct buffer *buf, const char *format,...)
Definition: buffer.c:240
ptr_format
#define ptr_format
Definition: common.h:49
buffer_list::head
struct buffer_entry * head
Definition: buffer.h:1127
buf_set_read
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Definition: buffer.h:348
buffer::data
uint8_t * data
Pointer to the allocated memory.
Definition: buffer.h:68
buf_catrunc
void buf_catrunc(struct buffer *buf, const char *str)
Definition: buffer.c:287
buf_parse
bool buf_parse(struct buffer *buf, const int delim, char *line, const int size)
Definition: buffer.c:843
cleanup
static int cleanup(void **state)
Definition: test_pkcs11.c:280