libamxc  1.10.3
C Generic Data Containers
amxc_string.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <stdarg.h>
58 #include <string.h>
59 #include <ctype.h>
60 
61 #include <amxc/amxc_variant.h>
62 #include <amxc/amxc_string.h>
63 #include <amxc/amxc_macros.h>
64 
72 static const char* const s_supported_format_placeholders[] = { "%s", "%d", "%lld", "%ld", "%i",
73  "%lli", "%li", "%u", "%llu", "%lu", "%x", "%llx", "%lx", "%%", "%c", "%f", "%F", "%X"};
74 
75 static int amxc_string_realloc(amxc_string_t* string, const size_t length) {
76  char* new_buffer = NULL;
77  int retval = -1;
78 
79  if(length == 0) {
80  free(string->buffer);
81  string->buffer = NULL;
82  string->length = 0;
83  retval = 0;
84  } else if(string->buffer != NULL) {
85  new_buffer = (char*) realloc(string->buffer, sizeof(char) * length + 1);
86  } else {
87  new_buffer = (char*) calloc(length + 1, sizeof(char));
88  }
89  if(new_buffer != NULL) {
90  string->buffer = new_buffer;
91  string->length = length;
92  string->last_used = string->last_used >= length ? length - 1 : string->last_used;
93  string->buffer[string->last_used] = 0;
94  retval = 0;
95  }
96 
97  return retval;
98 }
99 
104 static const char* s_get_format_placeholder(const char* input) {
105  size_t nb_supported = 0;
106  when_null(input, error);
107  nb_supported = sizeof(s_supported_format_placeholders) / sizeof(s_supported_format_placeholders[0]);
108  for(size_t i = 0; i < nb_supported; i++) {
109  const char* const candidate = s_supported_format_placeholders[i];
110  if(0 == strncmp(candidate, input, strlen(candidate))) {
111  return candidate;
112  }
113  }
114 error:
115  return NULL;
116 }
117 
118 int amxc_string_new(amxc_string_t** string, const size_t length) {
119  int retval = -1;
120  when_null(string, exit);
121 
122  /* allocate the array structure */
123  *string = (amxc_string_t*) calloc(1, sizeof(amxc_string_t));
124  when_null(*string, exit);
125 
126  /* set the number of items in the array */
127  (*string)->length = length;
128  (*string)->last_used = 0;
129 
130  /* if no buffer needs to pre-allocated, leave */
131  if(length == 0) {
132  retval = 0;
133  goto exit;
134  }
135 
136  /* allocate the buffer */
137  amxc_string_realloc(*string, length);
138  when_null(*string, exit);
139 
140  retval = 0;
141 
142 exit:
143  if((retval != 0) && (string != NULL)) {
144  free(*string);
145  *string = NULL;
146  }
147  return retval;
148 }
149 
151  when_null(string, exit);
152  when_null((*string), exit);
153 
154  amxc_llist_it_take(&(*string)->it);
155  free((*string)->buffer);
156  free(*string);
157  *string = NULL;
158 
159 exit:
160  return;
161 }
162 
163 int amxc_string_init(amxc_string_t* const string, const size_t length) {
164  int retval = -1;
165  when_null(string, exit);
166 
167  string->buffer = NULL;
168  string->length = 0;
169  string->last_used = 0;
170 
171  amxc_llist_it_init(&string->it);
172 
173  // if no items need to be pre-allocated, leave
174  if(length == 0) {
175  retval = 0;
176  goto exit;
177  }
178 
179  amxc_string_realloc(string, length);
180  when_null(string->buffer, exit);
181  string->length = length;
182 
183  retval = 0;
184 
185 exit:
186  return retval;
187 }
188 
189 void amxc_string_clean(amxc_string_t* const string) {
190  when_null(string, exit);
191 
192  amxc_llist_it_take(&string->it);
193 
194  free(string->buffer);
195  string->buffer = NULL;
196  string->last_used = 0;
197  string->length = 0;
198 
199 exit:
200  return;
201 }
202 
203 void amxc_string_reset(amxc_string_t* const string) {
204  when_null(string, exit);
205 
206  if(string->buffer) {
207  string->buffer[0] = 0;
208  }
209  string->last_used = 0;
210 
211 exit:
212  return;
213 }
214 
216  const amxc_string_t* const src) {
217  int retval = -1;
218  when_null(dest, exit);
219  when_null(src, exit);
220 
221  amxc_string_reset(dest);
222 
223  if(src->length == 0) {
224  dest->last_used = 0;
225  retval = 0;
226  goto exit;
227  }
228 
229  amxc_string_realloc(dest, src->length);
230  when_null(dest->buffer, exit);
231  memcpy(dest->buffer, src->buffer, src->length);
232  dest->last_used = src->last_used;
233 
234  retval = 0;
235 
236 exit:
237  return retval;
238 }
239 
240 int amxc_string_grow(amxc_string_t* const string, const size_t length) {
241  int retval = -1;
242  size_t old_length = 0;
243  when_null(string, exit);
244 
245  if(length == 0) {
246  retval = 0;
247  goto exit;
248  }
249 
250  old_length = string->length;
251  when_failed(amxc_string_realloc(string, old_length + length), exit);
252  when_null(string->buffer, exit);
253  memset(string->buffer + old_length, 0, length);
254  retval = 0;
255 
256 exit:
257  return retval;
258 }
259 
260 int amxc_string_shrink(amxc_string_t* const string, const size_t length) {
261  int retval = -1;
262  when_null(string, exit);
263  when_true(length > string->length, exit); // out of range
264 
265  if(length == 0) {
266  retval = 0;
267  goto exit;
268  }
269 
270  retval = amxc_string_realloc(string, string->length - length);
271 
272 exit:
273  return retval;
274 }
275 
277  const size_t pos,
278  const char* const text,
279  const size_t length,
280  const amxc_string_flags_t flags) {
281  int retval = -1;
282  when_null(string, exit);
283  when_null(text, exit);
284  when_true(length == 0, exit);
285  when_true(pos > string->last_used, exit);
286 
288  if(pos + length > string->length) {
290  pos + length), exit);
291  when_null(string->buffer, exit);
292  }
293  string->last_used = pos + length > string->last_used ? pos + length : string->last_used;
294  } else {
295  if(length + string->last_used >= string->length) {
297  length + string->last_used + 1), exit);
298  when_null(string->buffer, exit);
299  }
300  memmove(string->buffer + pos + length,
301  string->buffer + pos,
302  string->last_used - pos);
303  string->last_used += length;
304  }
305 
306  memcpy(string->buffer + pos, text, length);
307  string->buffer[string->last_used] = 0;
308  retval = 0;
309 
310 exit:
311  return retval;
312 }
313 
315  const size_t pos,
316  size_t length) {
317  int retval = -1;
318  size_t bytes_to_move = 0;
319  when_null(string, exit);
320  when_null(string->buffer, exit);
321  when_true(length == 0, exit);
322  when_true(pos > string->last_used, exit);
323 
324  if((length == SIZE_MAX) ||
325  ( pos + length > string->last_used)) {
326  length = string->last_used - pos;
327  }
328 
329  bytes_to_move = string->last_used - (pos + length);
330  memmove(string->buffer + pos, string->buffer + pos + length, bytes_to_move);
331  string->last_used -= length;
332  string->buffer[string->last_used] = 0;
333  retval = 0;
334 
335 exit:
336  return retval;
337 }
338 
339 const char* amxc_string_get(const amxc_string_t* const string,
340  const size_t offset) {
341  const char* text = NULL;
342  when_null(string, exit);
343  when_true(string->buffer != NULL && offset > string->last_used, exit);
344 
345  if(string->buffer == NULL) {
346  text = "";
347  } else {
348  string->buffer[string->last_used] = 0;
349  text = string->buffer + offset;
350  }
351 
352 exit:
353  return text;
354 }
355 
357  char* buffer = NULL;
358  when_null(string, exit);
359 
360  if(string->buffer != NULL) {
361  string->buffer[string->last_used] = 0;
362  }
363  buffer = string->buffer;
364  string->buffer = NULL;
365  string->last_used = 0;
366  string->length = 0;
367 
368 exit:
369  return buffer;
370 }
371 
373  char* buffer,
374  size_t length) {
375  int retval = -1;
376  char* original = NULL;
377  when_null(string, exit);
378 
379  original = string->buffer;
380 
381  if(buffer != NULL) {
382  when_true(length < strlen(buffer) + 1, exit);
383  string->buffer = buffer;
384  string->last_used = strlen(buffer);
385  string->length = length;
386  } else {
387  string->buffer = NULL;
388  string->last_used = 0;
389  string->length = 0;
390  }
391 
392  free(original);
393 
394  retval = 0;
395 
396 exit:
397  return retval;
398 }
399 
400 char* amxc_string_dup(const amxc_string_t* const string,
401  const size_t start,
402  size_t length) {
403 
404  char* text = NULL;
405  when_null(string, exit);
406  when_true(start > string->last_used, exit);
407  when_true(length == 0, exit);
408 
409  if((length == SIZE_MAX) ||
410  ( start + length > string->last_used)) {
411  length = string->last_used - start;
412  }
413 
414  text = (char*) calloc(length + 1, sizeof(char));
415  when_null(text, exit);
416  memcpy(text, string->buffer + start, length);
417  text[length] = 0;
418 
419 exit:
420  return text;
421 }
422 
424  uint32_t pos = 0;
425  when_null(string, exit);
426  when_true(string->last_used == 0, exit);
427 
428  if(fn == NULL) {
429  fn = isspace;
430  }
431 
432  while(pos <= string->last_used &&
433  fn(string->buffer[pos]) != 0) {
434  pos++;
435  }
436 
437  if(pos >= string->last_used) {
438  string->last_used = 0;
439  string->buffer[0] = 0;
440  goto exit;
441  }
442 
443  if(pos > 0) {
444  memmove(string->buffer, string->buffer + pos, string->last_used - pos);
445  string->last_used -= pos;
446  }
447  string->buffer[string->last_used] = 0;
448 
449 exit:
450  return;
451 }
452 
454  when_null(string, exit);
455  when_true(string->last_used == 0, exit);
456 
457  if(fn == NULL) {
458  fn = isspace;
459  }
460 
461  while(string->last_used > 0 &&
462  fn(string->buffer[string->last_used - 1]) != 0) {
463  string->last_used--;
464  }
465  string->buffer[string->last_used] = 0;
466 
467 exit:
468  return;
469 }
470 
472  amxc_string_trimr(string, fn);
473  amxc_string_triml(string, fn);
474 }
475 
477  const char* fmt,
478  va_list args) {
479  int retval = -1;
480 
481  when_null(string, exit);
482  when_null(fmt, exit);
483 
484  amxc_string_reset(string);
485  retval = amxc_string_vappendf(string, fmt, args);
486 
487 exit:
488  return retval;
489 }
490 
491 int amxc_string_setf(amxc_string_t* const string, const char* fmt, ...) {
492  va_list args;
493  int retval = -1;
494  when_null(string, exit);
495  when_null(fmt, exit);
496 
497  va_start(args, fmt);
498  retval = amxc_string_vsetf(string, fmt, args);
499  va_end(args);
500 
501 exit:
502  return retval;
503 }
504 
506  amxc_string_is_safe_cb_t is_safe_cb,
507  const char* fmt,
508  va_list args) {
509  int retval = -1;
510 
511  when_null(string, exit);
512  when_null(fmt, exit);
513 
514  amxc_string_reset(string);
515  retval = amxc_string_vappendf_checked(string, is_safe_cb, fmt, args);
516 
517 exit:
518  return retval;
519 }
520 
522  amxc_string_is_safe_cb_t is_safe_cb,
523  const char* fmt, ...) {
524  va_list args;
525  int retval = -1;
526  when_null(target_string, exit);
527  when_null(fmt, exit);
528 
529  va_start(args, fmt);
530  retval = amxc_string_vsetf_checked(target_string, is_safe_cb, fmt, args);
531  va_end(args);
532 
533 exit:
534  return retval;
535 }
536 
538  const char* fmt,
539  va_list args) {
540 
541  int retval = -1;
542  int size_needed = 0;
543  va_list copy;
544 
545  when_null(string, exit);
546  when_null(fmt, exit);
547 
548  va_copy(copy, args);
549  size_needed = vsnprintf(NULL, 0, fmt, args) + 1;
550 
551  if(string->length < string->last_used + size_needed) {
552  size_t grow = (string->last_used + size_needed - string->length);
553  when_failed(amxc_string_grow(string, grow), exit);
554  }
555 
556  size_needed = vsnprintf(string->buffer + string->last_used,
557  size_needed,
558  fmt,
559  copy);
560  string->buffer[string->length] = 0;
561 
562  string->last_used += size_needed;
563 
564  retval = 0;
565 
566 exit:
567  return retval;
568 }
569 
570 int amxc_string_appendf(amxc_string_t* const string, const char* fmt, ...) {
571  va_list args;
572  int retval = -1;
573  when_null(string, exit);
574  when_null(fmt, exit);
575 
576  va_start(args, fmt);
577  retval = amxc_string_vappendf(string, fmt, args);
578  va_end(args);
579 
580 exit:
581  return retval;
582 }
583 
585 static bool s_replace_percentage(amxc_string_t* string, const char* actual_placeholder, int* status) {
586  if(0 == strcmp(actual_placeholder, "%%")) {
587  *status = amxc_string_append(string, "%", 1);
588  return true;
589  } else {
590  return false;
591  }
592 }
593 
595 #define REPLACE_PLACEHOLDER(string, actual_placeholder, status, args, searched_placeholder, type) \
596  (0 == strcmp(actual_placeholder, searched_placeholder) \
597  ? status = amxc_string_appendf(string, actual_placeholder, va_arg(args, type)), true \
598  : false)
599 
601  const char* fmt, va_list args) {
602 
603  const char* pos = fmt;
604  int status = -1;
605  when_null(string, error);
606  when_null(fmt, error);
607  while(*pos != '\0') {
608  size_t len_pos_old = 0;
609  size_t len_new_fixed = 0;
610  const char* placeholder = NULL;
611  const char* placeholder_in_pos = strchr(pos, '%');
612  bool placeholder_handled = false;
613 
614  // If no "%" left, add all the rest:
615  if(placeholder_in_pos == NULL) {
616  status = amxc_string_append(string, pos, strlen(pos));
617  when_failed(status, error);
618  return 0;
619  }
620 
621  // Add the fixed part, i.e. until "%":
622  len_new_fixed = placeholder_in_pos - pos;
623  if(len_new_fixed != 0) {
624  status = amxc_string_append(string, pos, len_new_fixed);
625  when_failed(status, error);
626  }
627 
628  // Identify placeholder (e.g. "%i"):
629  placeholder = s_get_format_placeholder(placeholder_in_pos);
630  if(placeholder == NULL) {
631  goto error; // unsupported placeholder.
632  }
633  len_pos_old = amxc_string_text_length(string);
634 
635  // Add replacement
636  // Note: Unfortunately, we cannot make this more clean by splitting off functions
637  // because "If [the va_list] is passed to a function that uses va_arg(ap,type), then
638  // the value of ap is undefined after the return of that function." (man va_arg(3))
639  // and because getting an item from a va_list requires hardcoding its type.
640  placeholder_handled = REPLACE_PLACEHOLDER(string, placeholder, status, args, "%s", const char*)
641  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%d", int)
642  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%lld", long long int)
643  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%ld", long int)
644  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%i", int)
645  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%lli", long long int)
646  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%li", long int)
647  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%u", unsigned int)
648  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%llu", long long unsigned int)
649  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%lu", long unsigned int)
650  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%x", unsigned int)
651  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%llx", long long unsigned int)
652  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%lx", long unsigned int)
653  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%c", int) // unsigned char promoted to int
654  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%f", double)
655  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%F", double)
656  || REPLACE_PLACEHOLDER(string, placeholder, status, args, "%X", unsigned int)
657  || s_replace_percentage(string, placeholder, &status);
658 
659  when_false(placeholder_handled, error);
660 
661  when_failed(status, error);
662 
663  // Check if added string safe:
664  if((is_safe_cb != NULL) && !is_safe_cb(amxc_string_get(string, len_pos_old))) {
665  goto error;
666  }
667 
668  pos += len_new_fixed + strlen(placeholder);
669  }
670  return 0;
671 
672 error:
673  amxc_string_clean(string);
674  return -1;
675 }
676 
678  const char* fmt, ...) {
679  va_list args;
680  int retval = -1;
681  when_null(target_string, exit);
682  when_null(fmt, exit);
683 
684  va_start(args, fmt);
685  retval = amxc_string_vappendf_checked(target_string, is_safe_cb, fmt, args);
686  va_end(args);
687 
688 exit:
689  return retval;
690 }
691 
693  const char* fmt,
694  va_list args) {
695 
696  int retval = -1;
697  int size_needed = 0;
698  char first_char = 0;
699  va_list copy;
700 
701  when_null(string, exit);
702  when_null(fmt, exit);
703 
704  va_copy(copy, args);
705  size_needed = vsnprintf(NULL, 0, fmt, args) + 1;
706 
707  if(string->length < string->last_used + size_needed) {
708  size_t grow = (string->last_used + size_needed - string->length);
709  when_failed(amxc_string_grow(string, grow), exit);
710  }
711  first_char = string->buffer[0];
712 
713  if(string->last_used > 0) {
714  memmove(string->buffer + size_needed - 1,
715  string->buffer,
716  string->last_used);
717  }
718 
719  size_needed = vsnprintf(string->buffer,
720  size_needed,
721  fmt,
722  copy);
723  string->buffer[size_needed] = first_char;
724  string->last_used += size_needed;
725 
726  retval = 0;
727 
728 exit:
729  return retval;
730 }
731 
732 int amxc_string_prependf(amxc_string_t* const string, const char* fmt, ...) {
733  va_list args;
734  int retval = -1;
735  when_null(string, exit);
736  when_null(fmt, exit);
737 
738  va_start(args, fmt);
739  retval = amxc_string_vprependf(string, fmt, args);
740  va_end(args);
741 
742 exit:
743  return retval;
744 }
745 
746 bool amxc_string_is_numeric(const amxc_string_t* const string) {
747  bool retval = false;
748  char* data = NULL;
749 
750  when_true(amxc_string_is_empty(string), exit);
751 
752  data = string->buffer;
753  while((*data) != '\0') {
754  if(isdigit(*data) == 0) {
755  goto exit;
756  }
757  data++;
758  }
759 
760  retval = true;
761 exit:
762  return retval;
763 }
764 
765 int amxc_string_search(const amxc_string_t* const string,
766  const char* needle,
767  uint32_t start_pos) {
768  int retval = -1;
769  size_t needle_len = 0;
770  const char* needle_loc = NULL;
771 
772  when_null(string, exit);
773  when_null(string->buffer, exit);
774  when_true(string->last_used == 0, exit);
775  when_true(needle == NULL || *needle == 0, exit);
776 
777  needle_len = strlen(needle);
778  when_true(start_pos + needle_len > string->last_used, exit);
779 
780  needle_loc = strstr(string->buffer + start_pos, needle);
781  if(needle_loc != NULL) {
782  retval = needle_loc - string->buffer;
783  }
784 
785 exit:
786  return retval;
787 }
788 
790  const char* needle,
791  const char* newstr,
792  uint32_t max) {
793  int retval = 0;
794  int pos = 0;
795  size_t needle_len = 0;
796  size_t newstr_len = 0;
797 
798  when_null(string, exit);
799  when_null(string->buffer, exit);
800  when_true(string->last_used == 0, exit);
801  when_true(needle == NULL || *needle == 0, exit);
802  when_null(newstr, exit);
803 
804  needle_len = strlen(needle);
805  newstr_len = strlen(newstr);
806 
807  when_true(needle_len > string->last_used, exit);
808 
809  pos = amxc_string_search(string, needle, pos);
810  while(pos != -1 && max > 0) {
811  amxc_string_remove_at(string, pos, needle_len);
812  if(newstr_len != 0) {
813  amxc_string_insert_at(string, pos, newstr, newstr_len);
814  }
815  retval++;
816  if(max != UINT32_MAX) {
817  max--;
818  }
819  pos = amxc_string_search(string, needle, pos + newstr_len);
820  }
821 
822 exit:
823  return retval;
824 }
825 
826 size_t amxc_string_set(amxc_string_t* const string, const char* data) {
827  size_t retval = 0;
828 
829  when_null(string, exit);
830  amxc_string_reset(string);
831  when_null(data, exit);
832 
833  retval = strlen(data);
834  if(amxc_string_insert_at(string, 0, data, retval) != 0) {
835  retval = 0;
836  }
837 
838 exit:
839  return retval;
840 }
841 
843  int retval = -1;
844 
845  when_null(string, exit);
846 
847  for(uint32_t i = 0; i <= string->last_used; i++) {
848  string->buffer[i] = toupper(string->buffer[i]);
849  }
850  retval = 0;
851 
852 exit:
853  return retval;
854 }
855 
857  int retval = -1;
858 
859  when_null(string, exit);
860 
861  for(uint32_t i = 0; i <= string->last_used; i++) {
862  string->buffer[i] = tolower(string->buffer[i]);
863  }
864  retval = 0;
865 
866 exit:
867  return retval;
868 }
869 
871  const char bytes[],
872  const uint32_t len,
873  const char* sep) {
874  int retval = -1;
875  const char* s = "";
876 
877  when_null(string, exit);
878 
879  amxc_string_reset(string);
880 
881  when_null(bytes, exit);
882  when_true(len == 0, exit);
883 
884  for(uint32_t i = 0; i < len; i++) {
885  retval = amxc_string_appendf(string, "%s%2.2X", s, (unsigned char) bytes[i]);
886  if(retval != 0) {
887  amxc_string_reset(string);
888  goto exit;
889  }
890  if(sep != NULL) {
891  s = sep;
892  }
893  }
894 
895  retval = 0;
896 
897 exit:
898  return retval;
899 }
900 
902  char** bytes,
903  uint32_t* len,
904  const char* sep) {
905  int retval = -1;
906  uint32_t str_len = 0;
907  uint32_t pos = 0;
908  uint32_t sep_count = 0;
909  const char* hex_binary = NULL;
910  uint32_t sep_len = sep == NULL ? 0 : strlen(sep);
911  char* buffer = NULL;
912 
913  when_true(amxc_string_is_empty(string), exit);
914  when_null(bytes, exit);
915  when_null(len, exit);
916 
917  str_len = amxc_string_text_length(string);
918  *len = (str_len + 1) >> 1;
919  buffer = (char*) calloc(1, *len);
920 
921  when_null(buffer, exit);
922  hex_binary = amxc_string_get(string, 0);
923 
924  for(uint32_t i = 0; i < str_len; i++) {
925  int shift = 0;
926  if((sep != NULL) && (sep_len != 0) &&
927  ( strncmp(hex_binary + i, sep, sep_len) == 0)) {
928  sep_count++;
929  continue;
930  }
931  if(((i - sep_count) % 2 == 0) && ((i + 1) != str_len)) {
932  shift = 4;
933  }
934  if((hex_binary[i] >= '0') && (hex_binary[i] <= '9')) {
935  buffer[pos] |= (hex_binary[i] - '0') << shift;
936  } else if((hex_binary[i] >= 'A') && (hex_binary[i] <= 'F')) {
937  buffer[pos] |= (hex_binary[i] - 'A' + 10) << shift;
938  } else if((hex_binary[i] >= 'a') && (hex_binary[i] <= 'f')) {
939  buffer[pos] |= (hex_binary[i] - 'a' + 10) << shift;
940  } else {
941  // invalid character
942  goto exit;
943  }
944  if((i - sep_count) % 2 != 0) {
945  pos++;
946  }
947  }
948 
949  if(sep_count != 0) {
950  char* tmp = NULL;
951  *len -= (((sep_len * sep_count) + 1) >> 1);
952  *bytes = buffer;
953  tmp = (char*) realloc(buffer, *len);
954  if(tmp != NULL) {
955  *bytes = tmp;
956  }
957  } else {
958  *bytes = buffer;
959  }
960  retval = 0;
961 
962 exit:
963  if(retval != 0) {
964  free(buffer);
965  if(bytes != NULL) {
966  *bytes = NULL;
967  }
968  if(len != NULL) {
969  *len = 0;
970  }
971  }
972  return retval;
973 }
974 
#define when_failed(x, l)
Definition: amxc_macros.h:142
#define when_true(x, l)
Definition: amxc_macros.h:134
#define when_null(x, l)
Definition: amxc_macros.h:126
#define when_false(x, l)
Definition: amxc_macros.h:138
int amxc_string_prependf(amxc_string_t *const string, const char *fmt,...)
Definition: amxc_string.c:732
int amxc_string_setf_checked(amxc_string_t *target_string, amxc_string_is_safe_cb_t is_safe_cb, const char *fmt,...)
Definition: amxc_string.c:521
static bool s_replace_percentage(amxc_string_t *string, const char *actual_placeholder, int *status)
Definition: amxc_string.c:585
static int amxc_string_realloc(amxc_string_t *string, const size_t length)
Definition: amxc_string.c:75
int amxc_string_appendf(amxc_string_t *const string, const char *fmt,...)
Definition: amxc_string.c:570
int amxc_string_appendf_checked(amxc_string_t *target_string, amxc_string_is_safe_cb_t is_safe_cb, const char *fmt,...)
Definition: amxc_string.c:677
static const char * s_get_format_placeholder(const char *input)
Definition: amxc_string.c:104
static const char *const s_supported_format_placeholders[]
Definition: amxc_string.c:72
int amxc_string_setf(amxc_string_t *const string, const char *fmt,...)
Definition: amxc_string.c:491
#define REPLACE_PLACEHOLDER(string, actual_placeholder, status, args, searched_placeholder, type)
Definition: amxc_string.c:595
Ambiorix string API header file.
Ambiorix variant API header file.
int amxc_llist_it_init(amxc_llist_it_t *const it)
Initializes a linked list iterator.
Definition: amxc_llist_it.c:89
void amxc_llist_it_take(amxc_llist_it_t *const it)
Removes the iterator from the list.
void amxc_string_delete(amxc_string_t **string)
Frees the previously allocated string.
Definition: amxc_string.c:150
const char * amxc_string_get(const amxc_string_t *const string, const size_t offset)
Gets the content of the string buffer.
Definition: amxc_string.c:339
int amxc_string_to_lower(amxc_string_t *const string)
Converts all upper case characters to lower case.
Definition: amxc_string.c:856
int amxc_string_bytes_2_hex_binary(amxc_string_t *const string, const char bytes[], const uint32_t len, const char *sep)
Creates a hexbinary string from an array of bytes.
Definition: amxc_string.c:870
int amxc_string_vsetf_checked(amxc_string_t *const string, amxc_string_is_safe_cb_t is_safe_cb, const char *fmt, va_list args)
va_list version of amxc_string_setf_checked
Definition: amxc_string.c:505
int amxc_string_push_buffer(amxc_string_t *const string, char *buffer, size_t length)
Sets the string buffer.
Definition: amxc_string.c:372
int amxc_string_vsetf(amxc_string_t *const string, const char *fmt, va_list args)
Sets the content of the string using printf like formatting.
Definition: amxc_string.c:476
size_t amxc_string_set(amxc_string_t *const string, const char *data)
Sets a 0 terminated string in the string buffer.
Definition: amxc_string.c:826
AMXC_INLINE int amxc_string_append(amxc_string_t *const string, const char *const text, const size_t length)
Appends text to the end of the current content of the string buffer.
Definition: amxc_string.h:920
int amxc_string_replace(amxc_string_t *const string, const char *needle, const char *newstr, uint32_t max)
Replaces a number of sub-string occurrences in a string.
Definition: amxc_string.c:789
char * amxc_string_dup(const amxc_string_t *const string, const size_t start, size_t length)
Creates a full or partial copy of the text in the string buffer.
Definition: amxc_string.c:400
void amxc_string_reset(amxc_string_t *const string)
Resets the buffer, reset the content to all 0.
Definition: amxc_string.c:203
int amxc_string_to_upper(amxc_string_t *const string)
Converts all lower case characters to upper case.
Definition: amxc_string.c:842
int amxc_string_copy(amxc_string_t *const dest, const amxc_string_t *const src)
Copies the content.
Definition: amxc_string.c:215
AMXC_INLINE int amxc_string_insert_at(amxc_string_t *const string, const size_t pos, const char *text, size_t length)
Inserts a string of the given length into a string at a certain position.
Definition: amxc_string.h:1035
int amxc_string_new(amxc_string_t **string, const size_t length)
Allocates a string.
Definition: amxc_string.c:118
AMXC_INLINE size_t amxc_string_text_length(const amxc_string_t *const string)
Gets the current size of the used string buffer.
Definition: amxc_string.h:997
bool(* amxc_string_is_safe_cb_t)(const char *replacement)
Checks if given replacement is safe to be included in a bigger string in a particular language.
Definition: amxc_string.h:158
int amxc_string_search(const amxc_string_t *const string, const char *needle, uint32_t start_pos)
Searches a sub-string in a string.
Definition: amxc_string.c:765
int amxc_string_vappendf(amxc_string_t *const string, const char *fmt, va_list args)
Appends a formatted string to a string.
Definition: amxc_string.c:537
int amxc_string_vappendf_checked(amxc_string_t *string, amxc_string_is_safe_cb_t is_safe_cb, const char *fmt, va_list args)
va_list version of amxc_string_appendf_checked
Definition: amxc_string.c:600
int amxc_string_grow(amxc_string_t *const string, const size_t length)
Grows the string buffer.
Definition: amxc_string.c:240
int amxc_string_vprependf(amxc_string_t *const string, const char *fmt, va_list args)
Prepends a formatted string to a string.
Definition: amxc_string.c:692
int amxc_string_shrink(amxc_string_t *const string, const size_t length)
Shrinks the string buffer.
Definition: amxc_string.c:260
int(* amxc_string_is_char_fn_t)(int c)
Definition of the signature of the "is char" callback function.
Definition: amxc_string.h:145
void amxc_string_trim(amxc_string_t *const string, amxc_string_is_char_fn_t fn)
Trim.
Definition: amxc_string.c:471
int amxc_string_init(amxc_string_t *const string, const size_t length)
Initializes a string.
Definition: amxc_string.c:163
enum _amxc_string_flags amxc_string_flags_t
amxc_string_set_at possible flags
int amxc_string_remove_at(amxc_string_t *const string, const size_t pos, size_t length)
Removes part of the text in the string buffer.
Definition: amxc_string.c:314
int amxc_string_set_at(amxc_string_t *const string, const size_t pos, const char *const text, const size_t length, const amxc_string_flags_t flags)
Set text in the string buffer at a certain position.
Definition: amxc_string.c:276
int amxc_string_hex_binary_2_bytes(const amxc_string_t *const string, char **bytes, uint32_t *len, const char *sep)
Creates an array of bytes from a hex binary string.
Definition: amxc_string.c:901
void amxc_string_triml(amxc_string_t *const string, amxc_string_is_char_fn_t fn)
Trim left.
Definition: amxc_string.c:423
void amxc_string_trimr(amxc_string_t *const string, amxc_string_is_char_fn_t fn)
Trim right.
Definition: amxc_string.c:453
bool amxc_string_is_numeric(const amxc_string_t *const string)
Checks if a string is fully numeric.
Definition: amxc_string.c:746
AMXC_INLINE bool amxc_string_is_empty(const amxc_string_t *const string)
Checks if the string is empty.
Definition: amxc_string.h:1015
void amxc_string_clean(amxc_string_t *const string)
Frees the string buffer and reset length attributes.
Definition: amxc_string.c:189
char * amxc_string_take_buffer(amxc_string_t *const string)
Takes the string buffer.
Definition: amxc_string.c:356
@ amxc_string_overwrite
Definition: amxc_string.h:123
The string structure.
Definition: amxc_string.h:103
char * buffer
Definition: amxc_string.h:104
amxc_llist_it_t it
Definition: amxc_string.h:108
size_t last_used
Definition: amxc_string.h:106
size_t length
Definition: amxc_string.h:105
char data[]