cfengine  3.15.4
About: CFEngine is a configuration management system for configuring and maintaining Unix-like computers (using an own high level policy language). Community version.
  Fossies Dox: cfengine-3.15.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

string_lib.c
Go to the documentation of this file.
1 /*
2  Copyright 2020 Northern.tech AS
3 
4  This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6  This program is free software; you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by the
8  Free Software Foundation; version 3.
9 
10  This program 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
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 
19  To the extent this program is licensed as part of the Enterprise
20  versions of CFEngine, the applicable Commercial Open Source License
21  (COSL) may apply to this file if you as a licensee so wish it. See
22  included file COSL.txt.
23 */
24 
25 #include <platform.h>
26 #include <string_lib.h>
27 
28 #include <alloc.h>
29 #include <writer.h>
30 #include <misc_lib.h>
31 #include <logging.h>
32 #include <cleanup.h>
33 #include <definitions.h> // CF_BUFSIZE
34 #include <condition_macros.h> // nt_static_assert()
35 
36 
37 char *StringVFormat(const char *fmt, va_list ap)
38 {
39  char *value;
40  int ret = xvasprintf(&value, fmt, ap);
41  if (ret < 0)
42  {
43  return NULL;
44  }
45  else
46  {
47  return value;
48  }
49 }
50 
51 char *StringFormat(const char *fmt, ...)
52 {
53  va_list ap;
54  va_start(ap, fmt);
55  char *res = StringVFormat(fmt, ap);
56  va_end(ap);
57  return res;
58 }
59 
60 size_t StringCopy(const char *const from, char *const to, const size_t buf_size)
61 {
62  assert(from != NULL);
63  assert(to != NULL);
64  assert(from != to);
65  assert(buf_size >= 0);
66 
67  memset(to, 0, buf_size);
68  strncpy(to, from, buf_size);
69  if (to[buf_size-1] != '\0')
70  {
71  to[buf_size-1] = '\0';
72  return buf_size;
73  }
74  return strlen(to); // TODO - Replace the extra pass by using stpncpy:
75 
76  /*
77  // stpncpy has bad/unsafe behavior when string is too long:
78  // * Does not NUL terminate
79  // * Returns a pointer to potentially invalid memory
80  // These issues have to be handled (even for correct arguments)
81 
82  const char *const end = stpncpy(to, from, buf_size);
83  assert(end >= to);
84  const long len = end - to;
85  to[buf_size] = '\0';
86  return len;
87  */
88 }
89 
90 unsigned int StringHash(const char *str, unsigned int seed)
91 {
92  assert(str != NULL);
93  unsigned const char *p = (unsigned const char *) str;
94  unsigned int h = seed;
95 
96  // NULL is not allowed, but we will prevent segfault anyway:
97  size_t len = (str != NULL) ? strlen(str) : 0;
98 
99  /* https://en.wikipedia.org/wiki/Jenkins_hash_function#one-at-a-time */
100  for (size_t i = 0; i < len; i++)
101  {
102  h += p[i];
103  h += (h << 10);
104  h ^= (h >> 6);
105  }
106 
107  h += (h << 3);
108  h ^= (h >> 11);
109  h += (h << 15);
110 
111  return h;
112 }
113 
114 unsigned int StringHash_untyped(const void *str, unsigned int seed)
115 {
116  return StringHash(str, seed);
117 }
118 
119 char ToLower(char ch)
120 {
121  if (isupper((unsigned char) ch))
122  {
123  return (ch - 'A' + 'a');
124  }
125  else
126  {
127  return (ch);
128  }
129 }
130 
131 /*********************************************************************/
132 
133 char ToUpper(char ch)
134 {
135  if ((isdigit((unsigned char) ch)) || (ispunct((unsigned char) ch)))
136  {
137  return (ch);
138  }
139 
140  if (isupper((unsigned char) ch))
141  {
142  return (ch);
143  }
144  else
145  {
146  return (ch - 'a' + 'A');
147  }
148 }
149 
150 /*********************************************************************/
151 
152 void ToUpperStrInplace(char *str)
153 {
154  for (; *str != '\0'; str++)
155  {
156  *str = ToUpper(*str);
157  }
158 }
159 
160 /*********************************************************************/
161 
162 void ToLowerStrInplace(char *str)
163 {
164  for (; *str != '\0'; str++)
165  {
166  *str = ToLower(*str);
167  }
168 }
169 
170 /*********************************************************************/
171 
172 char *SafeStringDuplicate(const char *str)
173 {
174  if (str == NULL)
175  {
176  return NULL;
177  }
178 
179  return xstrdup(str);
180 }
181 
182 /*********************************************************************/
183 
184 char *SafeStringNDuplicate(const char *str, size_t size)
185 {
186  if (str == NULL)
187  {
188  return NULL;
189  }
190 
191  return xstrndup(str, size);
192 }
193 
194 /*********************************************************************/
195 
196 int SafeStringLength(const char *str)
197 {
198  if (str == NULL)
199  {
200  return 0;
201  }
202 
203  return strlen(str);
204 }
205 
206 // Compare two pointers (strings) where exactly one is NULL
207 static int NullCompare(const void *const a, const void *const b)
208 {
209  assert(a != b);
210  assert(a == NULL || b == NULL);
211 
212  if (a != NULL)
213  {
214  return 1;
215  }
216  if (b != NULL)
217  {
218  return -1;
219  }
220 
221  // Should never happen
222  ProgrammingError("Programming Error: NullCompare failed");
223  return 101;
224 }
225 
226 int StringSafeCompare(const char *const a, const char *const b)
227 {
228  if (a == b) // Same address or both NULL
229  {
230  return 0;
231  }
232  if (a != NULL && b != NULL)
233  {
234  return strcmp(a, b);
235  }
236 
237  // Weird edge cases where one is NULL:
238  return NullCompare(a, b);
239 }
240 
241 int StringSafeCompareN(const char *const a, const char *const b, const size_t n)
242 {
243  if (a == b) // Same address or both NULL
244  {
245  return 0;
246  }
247  if (a != NULL && b != NULL)
248  {
249  return strncmp(a, b, n);
250  }
251 
252  // Weird edge cases where one is NULL:
253  return NullCompare(a, b);
254 }
255 
256 bool StringEqual(const char *const a, const char *const b)
257 {
258  return (StringSafeCompare(a, b) == 0);
259 }
260 
261 bool StringEqualN(const char *const a, const char *const b, const size_t n)
262 {
263  return (StringSafeCompareN(a, b, n) == 0);
264 }
265 
266 int StringSafeCompare_IgnoreCase(const char *const a, const char *const b)
267 {
268  if (a == b) // Same address or both NULL
269  {
270  return 0;
271  }
272  if (a != NULL && b != NULL)
273  {
274  return strcasecmp(a, b);
275  }
276 
277  // Weird edge cases where one is NULL:
278  return NullCompare(a, b);
279 }
280 
281 int StringSafeCompareN_IgnoreCase(const char *const a, const char *const b, const size_t n)
282 {
283  if (a == b) // Same address or both NULL
284  {
285  return 0;
286  }
287  if (a != NULL && b != NULL)
288  {
289  return strncasecmp(a, b, n);
290  }
291 
292  // Weird edge cases where one is NULL:
293  return NullCompare(a, b);
294 }
295 
296 bool StringEqual_IgnoreCase(const char *const a, const char *const b)
297 {
298  return (StringSafeCompare_IgnoreCase(a, b) == 0);
299 }
300 
301 bool StringEqualN_IgnoreCase(const char *const a, const char *const b, const size_t n)
302 {
303  return (StringSafeCompareN_IgnoreCase(a, b, n) == 0);
304 }
305 
306 bool StringEqual_untyped(const void *a, const void *b)
307 {
308  return StringEqual(a, b);
309 }
310 
311 /*********************************************************************/
312 
313 char *SearchAndReplace(const char *source, const char *search, const char *replace)
314 {
315  const char *source_ptr = source;
316 
317  if ((source == NULL) || (search == NULL) || (replace == NULL))
318  {
319  ProgrammingError("Programming error: NULL argument is passed to SearchAndReplace");
320  }
321 
322  if (strcmp(search, "") == 0)
323  {
324  return xstrdup(source);
325  }
326 
327  Writer *w = StringWriter();
328 
329  for (;;)
330  {
331  const char *found_ptr = strstr(source_ptr, search);
332 
333  if (found_ptr == NULL)
334  {
335  WriterWrite(w, source_ptr);
336  return StringWriterClose(w);
337  }
338 
339  WriterWriteLen(w, source_ptr, found_ptr - source_ptr);
340  WriterWrite(w, replace);
341 
342  source_ptr += found_ptr - source_ptr + strlen(search);
343  }
344 }
345 
346 /*********************************************************************/
347 
348 char *StringConcatenate(size_t count, const char *first, ...)
349 {
350  if (count < 1)
351  {
352  return NULL;
353  }
354 
355  size_t total_length = first ? strlen(first) : 0;
356 
357  va_list args;
358  va_start(args, first);
359  for (size_t i = 1; i < count; i++)
360  {
361  const char *arg = va_arg(args, const char*);
362  if (arg)
363  {
364  total_length += strlen(arg);
365  }
366  }
367  va_end(args);
368 
369  char *result = xcalloc(total_length + 1, sizeof(char));
370  if (first)
371  {
372  strcat(result, first);
373  }
374 
375  va_start(args, first);
376  for (size_t i = 1; i < count; i++)
377  {
378  const char *arg = va_arg(args, const char *);
379  if (arg)
380  {
381  strcat(result, arg);
382  }
383  }
384  va_end(args);
385 
386  return result;
387 }
388 
389 /*********************************************************************/
390 
391 char *StringSubstring(const char *source, size_t source_len, int start, int len)
392 {
393  size_t end = -1;
394 
395  if (len == 0)
396  {
397  return SafeStringDuplicate("");
398  }
399  else if (len < 0)
400  {
401  end = source_len + len - 1;
402  }
403  else
404  {
405  end = start + len - 1;
406  }
407 
408  end = MIN(end, source_len - 1);
409 
410  if (start < 0)
411  {
412  start = source_len + start;
413  }
414 
415  if (start >= end)
416  {
417  return NULL;
418  }
419 
420  char *result = xcalloc(end - start + 2, sizeof(char));
421 
422  memcpy(result, source + start, end - start + 1);
423  return result;
424 }
425 
426 /*********************************************************************/
427 
428 bool StringIsNumeric(const char *s)
429 {
430  for (; *s; s++)
431  {
432  if (!isdigit((unsigned char)*s))
433  {
434  return false;
435  }
436  }
437 
438  return true;
439 }
440 
441 bool StringIsPrintable(const char *s)
442 {
443  for (; *s; s++)
444  {
445  if (!isprint((unsigned char)*s))
446  {
447  return false;
448  }
449  }
450 
451  return true;
452 }
453 
454 bool EmptyString(const char *s)
455 {
456  const char *sp;
457 
458  for (sp = s; *sp != '\0'; sp++)
459  {
460  if (!isspace((unsigned char)*sp))
461  {
462  return false;
463  }
464  }
465 
466  return true;
467 }
468 
469 /*********************************************************************/
470 
471 /**
472  * @brief Converts a string of numerals in base 10 to a long integer.
473  *
474  * Result is stored in *value_out, return value should be checked.
475  * On error *value_out is unmodified and an error code is returned.
476  * Leading spaces in input string are skipped.
477  * String numeral must be terminated by NULL byte or space (isspace).
478  *
479  * @see StringToLongExitOnError()
480  * @see StringToLongDefaultOnError()
481  * @param[in] str String with numerals to convert, cannot be NULL
482  * @param[out] value_out Where to store result on success, cannot be NULL
483  * @return 0 on success, error code otherwise (see source code)
484  */
485 int StringToLong(const char *str, long *value_out)
486 {
487  nt_static_assert(ERANGE != 0);
488  assert(str != NULL);
489  assert(value_out != NULL);
490 
491  char *endptr = NULL;
492  long val;
493 
494  errno = 0;
495  val = strtol(str, &endptr, 10);
496 
497  if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)))
498  {
499  return ERANGE; // Overflow or underflow
500  }
501 
502  if (endptr == str)
503  {
504  return -81; // No digits found
505  }
506 
507  if (endptr == NULL)
508  {
509  return -82; // endpointer not set by strtol
510  }
511 
512  if (*endptr != '\0' && !isspace(*endptr))
513  {
514  return -83; // string not properly terminated
515  }
516 
517  if (errno != 0)
518  {
519  return errno; // Unknown error
520  }
521 
522  *value_out = val;
523  return 0;
524 }
525 
526 /**
527  * @brief Log StringToLong conversion error with an identifier for debugging
528  */
529 void LogStringToLongError(const char *str_attempted, const char *id, int error_code)
530 {
531  assert(error_code != 0);
532  const char *error_str = "Unknown";
533  switch (error_code)
534  {
535  case ERANGE:
536  error_str = "Overflow";
537  break;
538  case -81:
539  error_str = "No digits";
540  break;
541  case -82:
542  error_str = "No endpointer";
543  break;
544  case -83:
545  error_str = "Not terminated";
546  break;
547  }
548  Log(LOG_LEVEL_ERR, "Conversion error (%d - %s) on '%s' (%s)", error_code, error_str, str_attempted, id);
549 }
550 
551 /**
552  * @brief Converts a string of numerals in base 10 to a long integer,
553  * uses a default value if errors occur.
554  *
555  * @see StringToLong()
556  * @param[in] str String with numerals to convert, cannot be NULL
557  * @param[in] default_return Value to return on error
558  * @return Result of conversion (or default_return in case of error)
559  */
560 long StringToLongDefaultOnError(const char *str, long default_return)
561 {
562  assert(str != NULL);
563  long result = 0;
564  int return_code = StringToLong(str, &result);
565  if (return_code != 0)
566  {
567  // Do not log anything because this can be used frequently
568  return default_return;
569  }
570  return result;
571 }
572 
573 /**
574  * @brief Converts a string of numerals in base 10 to a long integer, exits on error.
575  *
576  * Only use this function in contexts/components where it is acceptable
577  * to immediately exit when something goes wrong.
578  *
579  * @warning This function can exit the process based on string contents
580  * @see StringToLong()
581  * @param[in] str String with numerals to convert, cannot be NULL
582  * @return Result of conversion
583  */
584 long StringToLongExitOnError(const char *str)
585 {
586  assert(str != NULL);
587  long result;
588  int return_code = StringToLong(str, &result);
589  if (return_code != 0)
590  {
591  LogStringToLongError(str, "StringToLongExitOnError", return_code);
592  DoCleanupAndExit(EXIT_FAILURE);
593  }
594  return result;
595 }
596 
597 /**
598  * @brief Converts a string of numerals in base 10 to 64-bit signed int
599  *
600  * Result is stored in *value_out, return value should be checked.
601  * On error *value_out is unmodified and false is returned.
602  *
603  * @see StringToLong()
604  * @param[in] str String with numerals to convert, cannot be NULL
605  * @param[out] value_out Where to store result on success, cannot be NULL
606  * @return 0 on success, error code otherwise (see source code)
607  */
608 int StringToInt64(const char *str, int64_t *value_out)
609 {
610  nt_static_assert(sizeof(int64_t) == sizeof(intmax_t));
611  nt_static_assert(ERANGE != 0);
612  assert(str != NULL);
613  assert(value_out != NULL);
614 
615  char *endptr = NULL;
616  int64_t val;
617 
618  errno = 0;
619  val = strtoimax(str, &endptr, 10);
620 
621  if ((errno == ERANGE && (val == INTMAX_MAX || val == INTMAX_MIN)))
622  {
623  return ERANGE; // Overflow or underflow
624  }
625 
626  if (endptr == str)
627  {
628  return -81; // No digits found
629  }
630 
631  if (endptr == NULL)
632  {
633  return -82; // endpointer not set by strtol
634  }
635 
636  if (*endptr != '\0' && !isspace(*endptr))
637  {
638  return -83; // string not properly terminated
639  }
640 
641  if (errno != 0)
642  {
643  return errno; // Unknown error
644  }
645 
646  *value_out = val;
647  return 0;
648 }
649 
650 /**
651  * @brief Convert a string to int64_t, exits if parsing fails
652  *
653  * Only use this function in contexts/components where it is acceptable
654  * to immediately exit when something goes wrong.
655  *
656  * @warning This function can exit the process based on string contents
657  * @see StringToInt64()
658  * @see StringToLongExitOnError()
659  * @param[in] str String with numerals to convert, cannot be NULL
660  * @return Result of conversion
661  */
662 int64_t StringToInt64ExitOnError(const char *str)
663 {
664  assert(str != NULL);
665 
666  int64_t result;
667  const int error_code = StringToInt64(str, &result);
668  if (error_code != 0)
669  {
670  LogStringToLongError(str, "StringToInt64ExitOnError", error_code);
671  DoCleanupAndExit(EXIT_FAILURE);
672  }
673  return result;
674 }
675 
676 /**
677  * @brief Converts a string to int64_t, with a default value in case of errors
678  *
679  * @see StringToInt64()
680  * @see StringToLongDefaultOnError()
681  * @param[in] str String with numerals to convert, cannot be NULL
682  * @param[in] default_return Value to return on error
683  * @return Result of conversion
684  */
685 int64_t StringToInt64DefaultOnError(const char *str, int64_t default_return)
686 {
687  assert(str != NULL);
688 
689  int64_t result;
690  const int error_code = StringToInt64(str, &result);
691  if (error_code != 0)
692  {
693  return default_return;
694  }
695  return result;
696 }
697 
698 /**
699  * @brief Convert a string of numerals to a long integer (deprecated).
700  *
701  * @warning This function is deprecated, do not use it
702  * @warning This function can exit the process based on string contents
703  * @see StringToLongExitOnError()
704  * @param[in] str String with numerals to convert, cannot be NULL
705  * @return Result of conversion
706  */
707 long StringToLongUnsafe(const char *str)
708 {
709  assert(str);
710 
711  char *end;
712  long result = strtol(str, &end, 10);
713 
714  // This is bad:
715  assert(!*end && "Failed to convert string to long");
716 
717  return result;
718 }
719 
720 char *StringFromLong(long number)
721 {
722  char *str = xcalloc(32, sizeof(char));
723  snprintf(str, 32, "%ld", number);
724  return str;
725 }
726 
727 /*********************************************************************/
728 
729 double StringToDouble(const char *str)
730 {
731  assert(str);
732 
733  char *end;
734  double result = strtod(str, &end);
735 
736  assert(!*end && "Failed to convert string to double");
737 
738  return result;
739 }
740 
741 char *StringFromDouble(double number)
742 {
743  return StringFormat("%.2f", number);
744 }
745 
746 /*********************************************************************/
747 
748 char *NULLStringToEmpty(char *str)
749 {
750  if(!str)
751  {
752  return "";
753  }
754 
755  return str;
756 }
757 
758 /**
759  * @NOTE this function always '\0'-terminates the destination string #dst.
760  * @return length of written string #dst.
761  */
762 size_t StringBytesToHex(char *dst, size_t dst_size,
763  const unsigned char *src_bytes, size_t src_len)
764 {
765  static const char *const hex_chars = "0123456789abcdef";
766 
767  size_t i = 0;
768  while ((i < src_len) &&
769  (i*2 + 2 < dst_size)) /* room for 2 more hex chars */
770  {
771  dst[2*i] = hex_chars[(src_bytes[i] >> 4) & 0xf];
772  dst[2*i + 1] = hex_chars[src_bytes[i] & 0xf];
773  i++;
774  }
775 
776  assert(2*i < dst_size);
777  dst[2*i] = '\0';
778 
779  return 2*i;
780 }
781 
782 bool IsStrIn(const char *str, const char *const strs[])
783 {
784  int i;
785 
786  for (i = 0; strs[i]; ++i)
787  {
788  if (strcmp(str, strs[i]) == 0)
789  {
790  return true;
791  }
792  }
793  return false;
794 }
795 
796 bool IsStrCaseIn(const char *str, const char *const strs[])
797 {
798  int i;
799 
800  for (i = 0; strs[i]; ++i)
801  {
802  if (strcasecmp(str, strs[i]) == 0)
803  {
804  return true;
805  }
806  }
807  return false;
808 }
809 
810 int CountChar(const char *string, char sep)
811 {
812  int count = 0;
813 
814  if (string == NULL)
815  {
816  return 0;
817  }
818 
819  if (string && (strlen(string) == 0))
820  {
821  return 0;
822  }
823 
824  for (const char *sp = string; *sp != '\0'; sp++)
825  {
826  if ((*sp == '\\') && (*(sp + 1) == sep))
827  {
828  ++sp;
829  }
830  else if (*sp == sep)
831  {
832  count++;
833  }
834  }
835 
836  return count;
837 }
838 
839 void ReplaceChar(char *in, char *out, int outSz, char from, char to)
840 /* Replaces all occurrences of 'from' to 'to' in preallocated
841  * string 'out'. */
842 {
843  int len;
844  int i;
845 
846  memset(out, 0, outSz);
847  len = strlen(in);
848 
849  for (i = 0; (i < len) && (i < outSz - 1); i++)
850  {
851  if (in[i] == from)
852  {
853  out[i] = to;
854  }
855  else
856  {
857  out[i] = in[i];
858  }
859  }
860 }
861 
862 /**
863  * Replace all occurrences of #find with #replace.
864  *
865  * @return the length of #buf or -1 in case of overflow, or 0 if no replace
866  * took place.
867  */
868 ssize_t StringReplace(char *buf, size_t buf_size,
869  const char *find, const char *replace)
870 {
871  assert(find[0] != '\0');
872 
873  char *p = strstr(buf, find);
874  if (p == NULL)
875  {
876  return 0;
877  }
878 
879  size_t find_len = strlen(find);
880  size_t replace_len = strlen(replace);
881  size_t buf_len = strlen(buf);
882  size_t buf_idx = 0;
883  char tmp[buf_size];
884  ssize_t tmp_len = 0;
885 
886  /* Do all replacements we find. */
887  do
888  {
889  size_t buf_newidx = p - buf;
890  size_t prefix_len = buf_newidx - buf_idx;
891 
892  if (tmp_len + prefix_len + replace_len >= buf_size)
893  {
894  return -1;
895  }
896 
897  memcpy(&tmp[tmp_len], &buf[buf_idx], prefix_len);
898  tmp_len += prefix_len;
899 
900  memcpy(&tmp[tmp_len], replace, replace_len);
901  tmp_len += replace_len;
902 
903  buf_idx = buf_newidx + find_len;
904  p = strstr(&buf[buf_idx], find);
905  } while (p != NULL);
906 
907  /* Copy leftover plus terminating '\0'. */
908  size_t leftover_len = buf_len - buf_idx;
909  if (tmp_len + leftover_len >= buf_size)
910  {
911  return -1;
912  }
913  memcpy(&tmp[tmp_len], &buf[buf_idx], leftover_len + 1);
914  tmp_len += leftover_len;
915 
916  /* And finally copy to source, we are supposed to modify it in place. */
917  memcpy(buf, tmp, tmp_len + 1);
918 
919  return tmp_len;
920 }
921 
922 void ReplaceTrailingChar(char *str, char from, char to)
923 /* Replaces any unwanted last char in str. */
924 {
925  int strLen;
926 
927  strLen = SafeStringLength(str);
928 
929  if (strLen == 0)
930  {
931  return;
932  }
933 
934  if (str[strLen - 1] == from)
935  {
936  str[strLen - 1] = to;
937  }
938 }
939 
941 {
942  return (StringRef) { .data = NULL, .len = 0 };
943 }
944 
945 size_t StringCountTokens(const char *str, size_t len, const char *seps)
946 {
947  size_t num_tokens = 0;
948  bool in_token = false;
949 
950  for (size_t i = 0; i < len; i++)
951  {
952  if (strchr(seps, str[i]))
953  {
954  in_token = false;
955  }
956  else
957  {
958  if (!in_token)
959  {
960  num_tokens++;
961  }
962  in_token = true;
963  }
964  }
965 
966  return num_tokens;
967 }
968 
969 static StringRef StringNextToken(const char *str, size_t len, const char *seps)
970 {
971  size_t start = 0;
972  bool found = false;
973  for (size_t i = 0; i < len; i++)
974  {
975  if (strchr(seps, str[i]))
976  {
977  if (found)
978  {
979  assert(i > 0);
980  return (StringRef) { .data = str + start, .len = i - start };
981  }
982  }
983  else
984  {
985  if (!found)
986  {
987  found = true;
988  start = i;
989  }
990  }
991  }
992 
993  if (found)
994  {
995  return (StringRef) { .data = str + start, .len = len - start };
996  }
997  else
998  {
999  return StringRefNull();
1000  }
1001 }
1002 
1003 StringRef StringGetToken(const char *str, size_t len, size_t index, const char *seps)
1004 {
1005  StringRef ref = StringNextToken(str, len, seps);
1006  for (size_t i = 0; i < index; i++)
1007  {
1008  if (!ref.data)
1009  {
1010  return ref;
1011  }
1012 
1013  len = len - (ref.data - str + ref.len);
1014  str = ref.data + ref.len;
1015 
1016  ref = StringNextToken(str, len, seps);
1017  }
1018 
1019  return ref;
1020 }
1021 
1022 char **String2StringArray(const char *str, char separator)
1023 /**
1024  * Parse CSVs into char **.
1025  * MEMORY NOTE: Caller must free return value with FreeStringArray().
1026  **/
1027 {
1028  int i = 0, len;
1029 
1030  if (str == NULL)
1031  {
1032  return NULL;
1033  }
1034 
1035  for (const char *sp = str; *sp != '\0'; sp++)
1036  {
1037  if (*sp == separator)
1038  {
1039  i++;
1040  }
1041  }
1042 
1043  char **arr = (char **) xcalloc(i + 2, sizeof(char *));
1044 
1045  const char *sp = str;
1046  i = 0;
1047 
1048  while (sp)
1049  {
1050  const char *esp = strchr(sp, separator);
1051 
1052  if (esp)
1053  {
1054  len = esp - sp;
1055  esp++;
1056  }
1057  else
1058  {
1059  len = strlen(sp);
1060  }
1061 
1062  arr[i] = xcalloc(len + 1, sizeof(char));
1063  memcpy(arr[i], sp, len);
1064 
1065  sp = esp;
1066  i++;
1067  }
1068 
1069  return arr;
1070 }
1071 
1072 void FreeStringArray(char **strs)
1073 {
1074  int i;
1075 
1076  if (strs == NULL)
1077  {
1078  return;
1079  }
1080 
1081  for (i = 0; strs[i] != NULL; i++)
1082  {
1083  free(strs[i]);
1084  strs[i] = NULL;
1085  }
1086 
1087  free(strs);
1088 }
1089 
1090 
1091 char *EscapeCharCopy(const char *str, char to_escape, char escape_with)
1092 /*
1093  * Escapes the 'to_escape'-chars found in str, by prefixing them with 'escape_with'.
1094  * Returns newly allocated string.
1095  */
1096 {
1097  assert(str);
1098 
1099  size_t in_size = strlen(str);
1100 
1101  if(in_size > (SIZE_MAX / 2) - 1)
1102  {
1103  ProgrammingError("Buffer passed to EscapeCharCopy() too large (in_size=%zd)", in_size);
1104  }
1105 
1106  size_t out_size = in_size + CountChar(str, to_escape) + 1;
1107 
1108  char *out = xcalloc(1, out_size);
1109 
1110  const char *in_pos = str;
1111  char *out_pos = out;
1112 
1113  for(; *in_pos != '\0'; in_pos++, out_pos++)
1114  {
1115  if(*in_pos == to_escape)
1116  {
1117  *out_pos = escape_with;
1118  out_pos++;
1119  }
1120  *out_pos = *in_pos;
1121  }
1122 
1123  return out;
1124 }
1125 
1126 char *ScanPastChars(char *scanpast, char *input)
1127 {
1128  char *pos = input;
1129 
1130  while ((*pos != '\0') && (strchr(scanpast, *pos)))
1131  {
1132  pos++;
1133  }
1134 
1135  return pos;
1136 }
1137 
1138 int StripTrailingNewline(char *str, size_t max_length)
1139 {
1140  if (str)
1141  {
1142  size_t i = strnlen(str, max_length + 1);
1143  if (i > max_length) /* See off-by-one comment below */
1144  {
1145  return -1;
1146  }
1147 
1148  while (i > 0 && str[i - 1] == '\n')
1149  {
1150  i--;
1151  }
1152  assert(str[i] == '\0' || str[i] == '\n');
1153  str[i] = '\0';
1154  }
1155  return 0;
1156 }
1157 
1158 /**
1159  * Removes trailing whitespace from a string.
1160  *
1161  * @WARNING Off-by-one quirk in max_length.
1162  *
1163  * Both StripTrailngNewline() and Chop() have long allowed callers to
1164  * pass (effectively) the strlen(str) rather than the size of memory
1165  * (which is at least strlen() + 1) in the buffer. The present
1166  * incarnation thus reads max_length as max-strlen(), not as size of
1167  * the buffer. It may be sensible to review all callers and change so
1168  * that max_length is the buffer size instead.
1169  *
1170  * TODO change Chop() to accept str_len parameter. It goes without saying that
1171  * the callers should call it as: Chop(s, strlen(s));
1172  */
1173 
1174 int Chop(char *str, size_t max_length)
1175 {
1176  if (str)
1177  {
1178  size_t i = strnlen(str, max_length + 1);
1179  if (i > max_length) /* See off-by-one comment above */
1180  {
1181  /* Given that many callers don't even check Chop's return value,
1182  * we should NULL-terminate the string here. TODO. */
1183  return -1;
1184  }
1185 
1186  while (i > 0 && isspace((unsigned char)str[i-1]))
1187  {
1188  i--;
1189  }
1190  assert(str[i] == '\0' || isspace((unsigned char)str[i]));
1191  str[i] = '\0';
1192  }
1193  return 0;
1194 }
1195 
1196 char *TrimWhitespace(char *s)
1197 {
1198  assert(s);
1199 
1200  // Leading whitespace:
1201  while (isspace(s[0]))
1202  {
1203  ++s;
1204  }
1205 
1206  // Empty string (only whitespace):
1207  if (s[0] == '\0')
1208  {
1209  return s;
1210  }
1211 
1212  // Trailing whitespace:
1213  char *end = s + strlen(s) - 1; // Last byte before '\0'
1214  while ( isspace(end[0]) )
1215  {
1216  --end;
1217  }
1218  end[1] = '\0'; // Null terminate string after last non space char
1219 
1220  return s;
1221 }
1222 
1223 /**
1224  * @brief Remove the CRLF at the end of a CSV line, if it exists
1225  *
1226  * For use in networking / reporting protocols. For old clients which send a
1227  * CRLF it will remove exactly 1 occurence of CRLF. For new clients which
1228  * don't send CRLF, it will remove nothing. Thus, it should be compatible
1229  * with both. Does not trim any other whitespace, because we don't expect any
1230  * other whitespace to be there, and if it did, this could mask important
1231  * errors.
1232  *
1233  * @see CsvWriterNewRecord()
1234  * @param data NUL-terminated string with one line of CSV data, cannot be NULL
1235  * @return strlen(data), after trimming
1236  */
1237 size_t TrimCSVLineCRLF(char *const data)
1238 {
1239  assert(data != NULL);
1240 
1241  size_t length = strlen(data);
1242  assert(data[length] == '\0');
1243 
1244  if (length < 2)
1245  {
1246  return length;
1247  }
1248 
1249  if (data[length - 2] == '\r' && data[length - 1] == '\n')
1250  {
1251  data[length - 2] = '\0';
1252  data[length - 1] = '\0';
1253  length -= 2;
1254  }
1255 
1256  assert(length == strlen(data));
1257 
1258  return length;
1259 }
1260 
1261 /**
1262  * @brief Remove the CRLF at the end of a non-empty CSV line, if it exists
1263  *
1264  * Based on `TrimCSVLineCRLF()`, adds a lot of assertions for bad cases we
1265  * want to detect in testing.
1266  *
1267  * @see TrimCSVLineCRLF()
1268  * @param data NUL-terminated string with one line of CSV data, cannot be NULL
1269  * @return strlen(data), after trimming
1270  */
1271 size_t TrimCSVLineCRLFStrict(char *const data)
1272 {
1273  assert(data != NULL);
1274  assert(strlen(data) > 0);
1275  assert(strlen(data) < 4096);
1276  assert(!isspace(data[0]));
1277 
1278  const size_t length = TrimCSVLineCRLF(data);
1279  assert(length == strlen(data));
1280  assert(length > 0);
1281  assert(!isspace(data[length - 1]));
1282  assert(!isspace(data[0]));
1283 
1284  return length;
1285 }
1286 
1287 void StringCloseHole(char *s, const int start, const int end)
1288 {
1289  assert(s != NULL);
1290  assert(0 <= start && start <= end && end <= strlen(s));
1291  assert((end - start) <= strlen(s));
1292 
1293  if (end > start)
1294  {
1295  memmove(s + start, s + end,
1296  /* The 1+ ensures we copy the final '\0' */
1297  strlen(s + end) + 1);
1298  }
1299 }
1300 
1301 bool StringEndsWithCase(const char *str, const char *suffix, const bool case_fold)
1302 {
1303  size_t str_len = strlen(str);
1304  size_t suffix_len = strlen(suffix);
1305 
1306  if (suffix_len > str_len)
1307  {
1308  return false;
1309  }
1310 
1311  for (size_t i = 0; i < suffix_len; i++)
1312  {
1313  char a = str[str_len - i - 1];
1314  char b = suffix[suffix_len - i - 1];
1315  if (case_fold)
1316  {
1317  a = ToLower(a);
1318  b = ToLower(b);
1319  }
1320 
1321  if (a != b)
1322  {
1323  return false;
1324  }
1325  }
1326 
1327  return true;
1328 }
1329 
1330 bool StringEndsWith(const char *str, const char *suffix)
1331 {
1332  return StringEndsWithCase(str, suffix, false);
1333 }
1334 
1335 bool StringStartsWith(const char *str, const char *prefix)
1336 {
1337  int str_len = strlen(str);
1338  int prefix_len = strlen(prefix);
1339 
1340  if (prefix_len > str_len)
1341  {
1342  return false;
1343  }
1344 
1345  for (int i = 0; i < prefix_len; i++)
1346  {
1347  if (str[i] != prefix[i])
1348  {
1349  return false;
1350  }
1351  }
1352  return true;
1353 }
1354 
1355 
1356 /**
1357  * Returns pointer to the first byte in #buf that is not #c. Returns NULL if
1358  * all of #buf contains only bytes of value #c.
1359  *
1360  * @NOTE this functions complements memchr() from POSIX.
1361  *
1362  * @TODO move to libcompat, it appears to be available in some systems.
1363  */
1364 void *memcchr(const void *buf, int c, size_t buf_size)
1365 {
1366  const char *cbuf = buf;
1367  for (size_t i = 0; i < buf_size; i++)
1368  {
1369  if (cbuf[i] != c)
1370  {
1371  return (void *) &cbuf[i]; /* cast-away const */
1372  }
1373  }
1374  return NULL;
1375 }
1376 
1377 
1378 /*
1379  * @brief extract info from input string given two types of constraints:
1380  * - length of the extracted string is bounded
1381  * - extracted string should stop at first element of an exclude list
1382  *
1383  * @param[in] isp : the string to scan
1384  * @param[in] limit : size limit on the output string (including '\0')
1385  * @param[in] exclude : characters to be excluded from output buffer
1386  * @param[out] obuf : the output buffer
1387  * @retval true if string was capped, false if not
1388  */
1389 bool StringNotMatchingSetCapped(const char *isp, int limit,
1390  const char *exclude, char *obuf)
1391 {
1392  size_t l = strcspn(isp, exclude);
1393 
1394  if (l < limit-1)
1395  {
1396  memcpy(obuf, isp, l);
1397  obuf[l]='\0';
1398  return false;
1399  }
1400  else
1401  {
1402  memcpy(obuf, isp, limit-1);
1403  obuf[limit-1]='\0';
1404  return true;
1405  }
1406 }
1407 
1408 bool StringAppend(char *dst, const char *src, size_t n)
1409 {
1410  int i, j;
1411  n--;
1412  for (i = 0; i < n && dst[i]; i++)
1413  {
1414  }
1415  for (j = 0; i < n && src[j]; i++, j++)
1416  {
1417  dst[i] = src[j];
1418  }
1419  dst[i] = '\0';
1420  return (i < n || !src[j]);
1421 }
1422 
1423 /**
1424  * Canonify #src into #dst.
1425  *
1426  * @WARNING you must make sure sizeof(dst) is adequate!
1427  *
1428  * @return always #dst.
1429  */
1430 char *StringCanonify(char *dst, const char *src)
1431 {
1432  while (*src != '\0')
1433  {
1434  if (isalnum((unsigned char) *src))
1435  {
1436  *dst = *src;
1437  }
1438  else
1439  {
1440  *dst = '_';
1441  }
1442 
1443  src++;
1444  dst++;
1445  }
1446  *dst = '\0';
1447 
1448  return dst;
1449 }
1450 
1451 /**
1452  * Append #sep if not already there, and then append #leaf.
1453  */
1454 bool PathAppend(char *path, size_t path_size, const char *leaf, char sep)
1455 {
1456  size_t path_len = strlen(path);
1457  size_t leaf_len = strlen(leaf);
1458 
1459  if (path_len > 0 && path[path_len - 1] == sep)
1460  {
1461  /* Path already has separator. */
1462  path_len--;
1463  }
1464 
1465  if (path_len + 1 + leaf_len >= path_size)
1466  {
1467  return false; /* overflow */
1468  }
1469 
1470  path[path_len] = sep;
1471  memcpy(&path[path_len + 1], leaf, leaf_len + 1);
1472 
1473  return true;
1474 }
1475 
1476 /**
1477  * Append #src string to #dst, useful for static allocated buffers.
1478  *
1479  * @param #dst_len if not NULL then it must contain the lenth of #dst and must
1480  * return the total needed length of the result in #dst, even
1481  * when truncation occurs.
1482  * @param #src_len if not 0, then this many bytes
1483  * from #src shall be concatenated to #dst.
1484  *
1485  * @NOTE if truncation happened, then the value returned in #dst_len shall be
1486  * greater than or equal to #dst_size (indicating the real size needed
1487  * for successful concatenation), and the real length of the truncated
1488  * string in #dst shall be #dst_size - 1.
1489  *
1490  * @NOTE it is legal for #dst_len to be >= dst_size already when the function
1491  * is called. In that case nothing will be appended, only #dst_len will
1492  * be updated with the extra size needed.
1493  */
1494 void StrCat(char *dst, size_t dst_size, size_t *dst_len,
1495  const char *src, size_t src_len)
1496 {
1497  size_t dlen = (dst_len != NULL) ? *dst_len : strlen(dst);
1498  size_t slen = (src_len != 0) ? src_len : strlen(src);
1499 
1500  size_t needed_len = dlen + slen;
1501 
1502  if (dlen + 1 >= dst_size) /* dst already full or overflown */
1503  {
1504  /* Append nothing, only update *dst_len. */
1505  }
1506  else if (needed_len < dst_size) /* it fits */
1507  {
1508  memcpy(&dst[dlen], src, slen);
1509  dst[needed_len] = '\0';
1510  }
1511  else /* truncation */
1512  {
1513  assert(dlen + slen >= dst_size);
1514  memcpy(&dst[dlen], src, dst_size - dlen - 1);
1515  dst[dst_size - 1] = '\0';
1516  }
1517 
1518  if (dst_len != NULL)
1519  {
1520  *dst_len = needed_len;
1521  }
1522 }
1523 
1524 /**
1525  * Append #src to #dst, delimited with #sep if #dst was not empty.
1526  *
1527  * @param #dst_len In-out parameter. If not NULL it is taken into account as
1528  * the current length of #dst, and updated as such.
1529  *
1530  * @NOTE if after returning *dst_len>=dst_size, this indicates that *nothing
1531  * was appended*, and the value is the size needed for success.
1532  *
1533  */
1534 void StrCatDelim(char *dst, size_t dst_size, size_t *dst_len,
1535  const char *src, char sep)
1536 {
1537  size_t dlen = (dst_len != NULL) ? *dst_len : strlen(dst);
1538  size_t slen = strlen(src);
1539 
1540  size_t needed_len = dlen + slen;
1541  if (dlen > 0)
1542  {
1543  needed_len++; /* separator must be prepended */
1544  }
1545 
1546  if (dlen + 1 >= dst_size) /* dst already full or overflown */
1547  {
1548  /* Append nothing, only update *dst_len. */
1549  }
1550  else if (needed_len < dst_size) /* it fits */
1551  {
1552  /* Prepend separator if not empty. */
1553  if (dlen > 0)
1554  {
1555  dst[dlen] = sep;;
1556  dlen++;
1557  }
1558  memcpy(&dst[dlen], src, slen);
1559  dst[needed_len] = '\0';
1560  }
1561  else /* does not fit */
1562  {
1563  /* Append nothing, only update *dst_len. */
1564  }
1565 
1566  if (dst_len != NULL)
1567  {
1568  *dst_len = needed_len;
1569  }
1570 }
1571 
1572 /*********************************************************************/
1573 
1574 void CanonifyNameInPlace(char *s)
1575 {
1576  for (; *s != '\0'; s++)
1577  {
1578  if (!isalnum((unsigned char) *s))
1579  {
1580  *s = '_';
1581  }
1582  }
1583 }
1584 
1586  const char *const supplied,
1587  const char *const longopt,
1588  const char *const shortopt)
1589 {
1590  assert(supplied != NULL);
1591  assert(shortopt != NULL);
1592  assert(longopt != NULL);
1593  assert(strlen(shortopt) == 2);
1594  assert(strlen(longopt) >= 3);
1595  assert(shortopt[0] == '-' && shortopt[1] != '-');
1596  assert(longopt[0] == '-' && longopt[1] == '-' && longopt[2] != '-');
1597 
1598  const size_t length = strlen(supplied);
1599  if (length <= 1)
1600  {
1601  return false;
1602  }
1603  else if (length == 2)
1604  {
1605  return StringEqual(supplied, shortopt);
1606  }
1607  return StringEqualN_IgnoreCase(supplied, longopt, length);
1608 }
void * xcalloc(size_t nmemb, size_t size)
Definition: alloc-mini.c:51
char * xstrdup(const char *str)
Definition: alloc-mini.c:56
int xvasprintf(char **strp, const char *fmt, va_list ap)
Definition: alloc.c:82
char * xstrndup(const char *str, size_t n)
Definition: alloc.c:61
static int input(void)
Definition: cf3lex.c:2154
void free(void *)
void DoCleanupAndExit(int ret)
Definition: cleanup.c:57
#define nt_static_assert(x)
int errno
#define NULL
Definition: getopt1.c:56
void Log(LogLevel level, const char *fmt,...)
Definition: logging.c:409
@ LOG_LEVEL_ERR
Definition: logging.h:42
#define ProgrammingError(...)
Definition: misc_lib.h:33
#define MIN(a, b)
Definition: platform.h:478
#define ERANGE
Definition: snprintf.c:453
int strcasecmp(const char *s1, const char *s2)
Definition: strcasecmp.c:33
static int NullCompare(const void *const a, const void *const b)
Definition: string_lib.c:207
void ToUpperStrInplace(char *str)
Definition: string_lib.c:152
char * StringFromDouble(double number)
Definition: string_lib.c:741
bool StringEndsWith(const char *str, const char *suffix)
Check if a string ends with the given suffix.
Definition: string_lib.c:1330
bool StringAppend(char *dst, const char *src, size_t n)
Appends src to dst, but will not exceed n bytes in dst, including the terminating null.
Definition: string_lib.c:1408
bool StringStartsWith(const char *str, const char *prefix)
Check if a string starts with the given prefix.
Definition: string_lib.c:1335
char * StringSubstring(const char *source, size_t source_len, int start, int len)
Definition: string_lib.c:391
char * SafeStringDuplicate(const char *str)
Definition: string_lib.c:172
void StrCatDelim(char *dst, size_t dst_size, size_t *dst_len, const char *src, char sep)
Definition: string_lib.c:1534
bool IsStrCaseIn(const char *str, const char *const strs[])
Definition: string_lib.c:796
bool StringNotMatchingSetCapped(const char *isp, int limit, const char *exclude, char *obuf)
Definition: string_lib.c:1389
void * memcchr(const void *buf, int c, size_t buf_size)
Definition: string_lib.c:1364
int64_t StringToInt64DefaultOnError(const char *str, int64_t default_return)
Converts a string to int64_t, with a default value in case of errors.
Definition: string_lib.c:685
int StringSafeCompare_IgnoreCase(const char *const a, const char *const b)
Definition: string_lib.c:266
size_t StringCopy(const char *const from, char *const to, const size_t buf_size)
Copy a string from from to to (a buffer of at least buf_size)
Definition: string_lib.c:60
bool IsStrIn(const char *str, const char *const strs[])
Definition: string_lib.c:782
int StringToInt64(const char *str, int64_t *value_out)
Converts a string of numerals in base 10 to 64-bit signed int.
Definition: string_lib.c:608
bool StringMatchesOption(const char *const supplied, const char *const longopt, const char *const shortopt)
Check if a command line argument matches a short or long option.
Definition: string_lib.c:1585
bool StringEqualN_IgnoreCase(const char *const a, const char *const b, const size_t n)
Definition: string_lib.c:301
bool StringIsNumeric(const char *s)
Definition: string_lib.c:428
bool StringEqualN(const char *const a, const char *const b, const size_t n)
Definition: string_lib.c:261
bool StringEndsWithCase(const char *str, const char *suffix, const bool case_fold)
Check if a string ends with the given suffix.
Definition: string_lib.c:1301
size_t StringCountTokens(const char *str, size_t len, const char *seps)
Definition: string_lib.c:945
bool StringEqual_untyped(const void *a, const void *b)
Definition: string_lib.c:306
char ** String2StringArray(const char *str, char separator)
Definition: string_lib.c:1022
char ToLower(char ch)
Definition: string_lib.c:119
long StringToLongUnsafe(const char *str)
Convert a string of numerals to a long integer (deprecated).
Definition: string_lib.c:707
bool StringEqual(const char *const a, const char *const b)
Definition: string_lib.c:256
int StringToLong(const char *str, long *value_out)
Converts a string of numerals in base 10 to a long integer.
Definition: string_lib.c:485
bool EmptyString(const char *s)
Definition: string_lib.c:454
char * NULLStringToEmpty(char *str)
Definition: string_lib.c:748
size_t TrimCSVLineCRLF(char *const data)
Remove the CRLF at the end of a CSV line, if it exists.
Definition: string_lib.c:1237
char * TrimWhitespace(char *s)
Definition: string_lib.c:1196
static StringRef StringRefNull(void)
Definition: string_lib.c:940
char ToUpper(char ch)
Definition: string_lib.c:133
char * ScanPastChars(char *scanpast, char *input)
Definition: string_lib.c:1126
char * StringCanonify(char *dst, const char *src)
Definition: string_lib.c:1430
static StringRef StringNextToken(const char *str, size_t len, const char *seps)
Definition: string_lib.c:969
int CountChar(const char *string, char sep)
Definition: string_lib.c:810
int Chop(char *str, size_t max_length)
Remove trailing spaces.
Definition: string_lib.c:1174
char * StringVFormat(const char *fmt, va_list ap)
Format string like vsprintf and return formatted string allocated on heap as a return value.
Definition: string_lib.c:37
unsigned int StringHash_untyped(const void *str, unsigned int seed)
Definition: string_lib.c:114
int StripTrailingNewline(char *str, size_t max_length)
Strips the newline character off a string, in place.
Definition: string_lib.c:1138
long StringToLongDefaultOnError(const char *str, long default_return)
Converts a string of numerals in base 10 to a long integer, uses a default value if errors occur.
Definition: string_lib.c:560
double StringToDouble(const char *str)
Definition: string_lib.c:729
void ReplaceTrailingChar(char *str, char from, char to)
Definition: string_lib.c:922
void FreeStringArray(char **strs)
Definition: string_lib.c:1072
int StringSafeCompareN_IgnoreCase(const char *const a, const char *const b, const size_t n)
Definition: string_lib.c:281
bool PathAppend(char *path, size_t path_size, const char *leaf, char sep)
Definition: string_lib.c:1454
void StrCat(char *dst, size_t dst_size, size_t *dst_len, const char *src, size_t src_len)
Definition: string_lib.c:1494
bool StringIsPrintable(const char *s)
Definition: string_lib.c:441
void ReplaceChar(char *in, char *out, int outSz, char from, char to)
Definition: string_lib.c:839
char * StringFromLong(long number)
Definition: string_lib.c:720
void StringCloseHole(char *s, const int start, const int end)
Erase part of a string using memmove()
Definition: string_lib.c:1287
int StringSafeCompare(const char *const a, const char *const b)
Definition: string_lib.c:226
unsigned int StringHash(const char *str, unsigned int seed)
Definition: string_lib.c:90
ssize_t StringReplace(char *buf, size_t buf_size, const char *find, const char *replace)
Definition: string_lib.c:868
void LogStringToLongError(const char *str_attempted, const char *id, int error_code)
Log StringToLong conversion error with an identifier for debugging.
Definition: string_lib.c:529
char * EscapeCharCopy(const char *str, char to_escape, char escape_with)
Definition: string_lib.c:1091
StringRef StringGetToken(const char *str, size_t len, size_t index, const char *seps)
Definition: string_lib.c:1003
char * StringConcatenate(size_t count, const char *first,...)
Definition: string_lib.c:348
int64_t StringToInt64ExitOnError(const char *str)
Convert a string to int64_t, exits if parsing fails.
Definition: string_lib.c:662
char * SafeStringNDuplicate(const char *str, size_t size)
Definition: string_lib.c:184
long StringToLongExitOnError(const char *str)
Converts a string of numerals in base 10 to a long integer, exits on error.
Definition: string_lib.c:584
void CanonifyNameInPlace(char *s)
Definition: string_lib.c:1574
char * StringFormat(const char *fmt,...)
Format string like sprintf and return formatted string allocated on heap as a return value.
Definition: string_lib.c:51
int StringSafeCompareN(const char *const a, const char *const b, const size_t n)
Definition: string_lib.c:241
int SafeStringLength(const char *str)
Definition: string_lib.c:196
bool StringEqual_IgnoreCase(const char *const a, const char *const b)
Definition: string_lib.c:296
size_t TrimCSVLineCRLFStrict(char *const data)
Remove the CRLF at the end of a non-empty CSV line, if it exists.
Definition: string_lib.c:1271
char * SearchAndReplace(const char *source, const char *search, const char *replace)
Definition: string_lib.c:313
void ToLowerStrInplace(char *str)
Definition: string_lib.c:162
size_t StringBytesToHex(char *dst, size_t dst_size, const unsigned char *src_bytes, size_t src_len)
Definition: string_lib.c:762
int strncasecmp(const char *s1, const char *s2)
size_t strnlen(const char *str, size_t maxlen)
Definition: strnlen.c:32
char * strstr(const char *haystack, const char *needle)
Definition: strstr.c:35
size_t len
Definition: string_lib.h:39
const char * data
Definition: string_lib.h:38
Definition: writer.c:45
size_t WriterWrite(Writer *writer, const char *str)
Definition: writer.c:193
char * StringWriterClose(Writer *writer)
Definition: writer.c:262
size_t WriterWriteLen(Writer *writer, const char *str, size_t len)
Definition: writer.c:178
Writer * StringWriter(void)
Definition: writer.c:67