libamxc  1.10.3
C Generic Data Containers
amxc_string_split.c File Reference

Ambiorix string API implementation. More...

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <amxc/amxc_common.h>
#include <amxc/amxc_variant.h>
#include <amxc/amxc_string_split.h>
#include <amxc/amxc_utils.h>
#include <amxc/amxc_macros.h>

Go to the source code of this file.

Data Structures

struct  _string_word_flags
 

Macros

#define _GNU_SOURCE
 

Typedefs

typedef struct _string_word_flags amxc_string_word_flags_t
 
typedef int(* amxc_string_create_part_t) (const amxc_string_t *const string, amxc_llist_t *const list, const size_t start_pos, const size_t length)
 
typedef bool(* amxc_string_check_delimiter_t) (amxc_llist_t *list, const char delimiter)
 

Functions

static void amxc_trim_llist (amxc_llist_t *const list)
 
static int amxc_string_create_part (const amxc_string_t *const string, amxc_llist_t *const list, const size_t start_pos, const size_t length)
 
static bool amxc_string_split_update_status (const amxc_string_t *const string, size_t i, amxc_string_word_flags_t *flags)
 
static amxc_string_split_status_t amxc_string_split_word_is_valid (amxc_string_word_flags_t *flags, const char **reason)
 
static bool amxc_need_to_add_delimiter (amxc_llist_t *list, const char delimiter)
 
static amxc_string_split_status_t amxc_string_split_words_internal (const amxc_string_t *const string, amxc_llist_t *list, amxc_string_create_part_t create, amxc_string_check_delimiter_t check, const char **reason)
 
static amxc_string_split_status_t amxc_build_csv_var_list (amxc_llist_t *all, amxc_var_t *csv_list)
 
static amxc_string_split_status_t amxc_build_ssv_var_list (amxc_llist_t *all, amxc_var_t *ssv_list)
 
amxc_string_split_status_t amxc_string_split_word (const amxc_string_t *const string, amxc_llist_t *list, const char **reason)
 Split a string in individual words or punctuation signs. More...
 
amxc_string_split_status_t amxc_string_split (const amxc_string_t *const string, amxc_var_t *var, amxc_string_split_builder_t fn, const char **reason)
 Split a string in individual words or punctuation signs. More...
 
amxc_string_split_status_t amxc_string_csv_to_var (const amxc_string_t *const string, amxc_var_t *var, const char **reason)
 Split a string in individual parts assuming that the string contains comma separated values. More...
 
amxc_string_split_status_t amxc_string_ssv_to_var (const amxc_string_t *const string, amxc_var_t *var, const char **reason)
 Split a string in individual parts assuming that the string contains space separated values. More...
 
amxc_string_split_status_t amxc_string_split_to_llist (const amxc_string_t *const string, amxc_llist_t *list, const char separator)
 Simple split function using a single character separator. More...
 
amxc_string_tamxc_string_get_from_llist (const amxc_llist_t *const llist, const unsigned int index)
 Helper function to be used with amxc_string_split_llist. More...
 
const char * amxc_string_get_text_from_llist (const amxc_llist_t *const llist, const unsigned int index)
 Helper function to be used with amxc_string_split_llist. More...
 

Detailed Description

Ambiorix string API implementation.

Definition in file amxc_string_split.c.

Macro Definition Documentation

◆ _GNU_SOURCE

#define _GNU_SOURCE

Definition at line 56 of file amxc_string_split.c.

Typedef Documentation

◆ amxc_string_check_delimiter_t

typedef bool(* amxc_string_check_delimiter_t) (amxc_llist_t *list, const char delimiter)

Definition at line 90 of file amxc_string_split.c.

◆ amxc_string_create_part_t

typedef int(* amxc_string_create_part_t) (const amxc_string_t *const string, amxc_llist_t *const list, const size_t start_pos, const size_t length)

Definition at line 85 of file amxc_string_split.c.

◆ amxc_string_word_flags_t

Function Documentation

◆ amxc_build_csv_var_list()

static amxc_string_split_status_t amxc_build_csv_var_list ( amxc_llist_t all,
amxc_var_t csv_list 
)
static

Definition at line 347 of file amxc_string_split.c.

347  {
349  bool quotes = false;
350  bool sqbrackets = false;
351  bool add_empty = true;
352  bool last_is_comma = false;
353  amxc_string_t csv_part;
354 
356 
357  amxc_string_init(&csv_part, 0);
358  amxc_llist_for_each(it, all) {
360  const char* txt_part = amxc_string_get(part, 0);
361  last_is_comma = false;
362  if(amxc_string_text_length(part) == 1) {
363  switch(txt_part[0]) {
364  case '"':
365  case '\'':
366  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
367  quotes = !quotes;
368  break;
369  case '[':
370  if(amxc_string_is_empty(&csv_part)) {
371  csv_list = amxc_var_add(amxc_llist_t, csv_list, NULL);
372  sqbrackets = !sqbrackets;
373  } else {
374  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
375  }
376  break;
377  case ']':
378  if(sqbrackets) {
379  if(amxc_string_text_length(&csv_part) > 0) {
380  amxc_var_t* item = amxc_var_add_new(csv_list);
381  amxc_string_trim(&csv_part, NULL);
383  }
384  if(csv_list != NULL) {
385  csv_list = amxc_container_of(csv_list->lit.llist, amxc_var_t, data);
386  }
387  sqbrackets = !sqbrackets;
388  add_empty = false;
389  } else {
390  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
391  }
392  break;
393  case ',':
394  if(quotes) {
395  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
396  } else {
397  if(amxc_string_text_length(&csv_part) > 0) {
398  amxc_var_t* item = amxc_var_add_new(csv_list);
399  amxc_string_trim(&csv_part, NULL);
401  } else if(add_empty) {
402  amxc_var_t* item = amxc_var_add_new(csv_list);
403  amxc_var_set(cstring_t, item, "");
404  }
405  add_empty = true;
406  }
407  last_is_comma = true;
408  break;
409  case ' ':
410  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
411  break;
412  default:
413  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
414  break;
415  }
416  } else {
417  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
418  }
419  }
420  if(amxc_string_text_length(&csv_part) > 0) {
421  amxc_var_t* item = amxc_var_add_new(csv_list);
422  amxc_string_trim(&csv_part, NULL);
424  } else if(last_is_comma && add_empty) {
425  amxc_var_add(cstring_t, csv_list, "");
426  }
427  amxc_string_clean(&csv_part);
428 
429  retval = AMXC_STRING_SPLIT_OK;
430 
431  return retval;
432 }
#define cstring_t
Convenience macro.
Definition: amxc_variant.h:584
#define amxc_container_of(addr, type, member)
Calculates the address of the containing structure.
Definition: amxc_common.h:83
#define amxc_llist_for_each(it, list)
Loops over the list from head to tail.
Definition: amxc_llist.h:253
enum _amxc_string_split_status amxc_string_split_status_t
The possible string split errors.
@ AMXC_STRING_SPLIT_OK
@ AMXC_ERROR_STRING_SPLIT_INVALID_INPUT
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
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
#define amxc_string_from_llist_it(ll_it)
Get the pointer to a string structure from an amxc linked list iterator.
Definition: amxc_string.h:95
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
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
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
#define AMXC_VAR_ID_LIST
Ambiorix Linked List variant id.
Definition: amxc_variant.h:206
#define amxc_var_add(type, var, data)
Convenience macro for adding a variant to composite variant type.
Definition: amxc_variant.h:618
int amxc_var_set_type(amxc_var_t *const var, const uint32_t type)
Change the variant data type.
Definition: amxc_variant.c:261
amxc_var_t * amxc_var_add_new(amxc_var_t *const var)
Adds a new variant to a composite variant.
Definition: amxc_variant.c:551
#define amxc_var_push(type, var, val)
Pushes a value into the variant.
Definition: amxc_variant.h:780
#define amxc_var_set(type, var, data)
Convenience macro for setting a value in a variant.
Definition: amxc_variant.h:609
struct _amxc_llist * llist
Definition: amxc_llist.h:220
The linked list structure.
Definition: amxc_llist.h:228
The string structure.
Definition: amxc_string.h:103
The variant struct definition.
Definition: amxc_variant.h:861
amxc_llist_it_t lit
Definition: amxc_variant.h:862
char data[]
static amxc_htable_it_t it[2000]

◆ amxc_build_ssv_var_list()

static amxc_string_split_status_t amxc_build_ssv_var_list ( amxc_llist_t all,
amxc_var_t ssv_list 
)
static

Definition at line 435 of file amxc_string_split.c.

435  {
437  bool quotes = false;
438  bool sqbrackets = false;
439  amxc_string_t csv_part;
440 
442 
443  amxc_string_init(&csv_part, 0);
444  amxc_llist_for_each(it, all) {
446  const char* txt_part = amxc_string_get(part, 0);
447  if(amxc_string_text_length(part) == 1) {
448  switch(txt_part[0]) {
449  case '"':
450  case '\'':
451  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
452  quotes = !quotes;
453  break;
454  case '[':
455  ssv_list = amxc_var_add(amxc_llist_t, ssv_list, NULL);
456  sqbrackets = !sqbrackets;
457  break;
458  case ']':
459  if(amxc_string_text_length(&csv_part) > 0) {
460  amxc_var_t* item = amxc_var_add_new(ssv_list);
462  }
463  if(ssv_list != NULL) {
464  ssv_list = amxc_container_of(ssv_list->lit.llist, amxc_var_t, data);
465  }
466  sqbrackets = !sqbrackets;
467  break;
468  case ' ':
469  if(quotes) {
470  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
471  } else {
472  if(amxc_string_text_length(&csv_part) > 0) {
473  amxc_var_t* item = amxc_var_add_new(ssv_list);
475  }
476  amxc_string_reset(&csv_part);
477  }
478  break;
479  default:
480  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
481  break;
482  }
483  } else {
484  amxc_string_append(&csv_part, txt_part, amxc_string_text_length(part));
485  }
486  }
487  if(amxc_string_text_length(&csv_part) > 0) {
488  amxc_var_t* item = amxc_var_add_new(ssv_list);
490  }
491  amxc_string_clean(&csv_part);
492 
493  retval = AMXC_STRING_SPLIT_OK;
494 
495  return retval;
496 }
void amxc_string_reset(amxc_string_t *const string)
Resets the buffer, reset the content to all 0.
Definition: amxc_string.c:203

◆ amxc_need_to_add_delimiter()

static bool amxc_need_to_add_delimiter ( amxc_llist_t list,
const char  delimiter 
)
static

Definition at line 253 of file amxc_string_split.c.

254  {
255  bool retval = false;
257  amxc_string_t* str_part = NULL;
258  const char* part = NULL;
259 
260  if(it == NULL) {
261  retval = (isspace(delimiter) == 0);
262  goto exit;
263  }
264 
265  str_part = amxc_string_from_llist_it(it);
266  part = amxc_string_get(str_part, 0);
267 
268  retval = true;
269 
270  if(amxc_string_text_length(str_part) == 1) {
271  if(isspace(part[0]) != 0) {
272  if((isspace(delimiter) != 0) && (delimiter != '\n')) {
273  retval = false;
274  }
275  }
276  }
277 
278 exit:
279  return retval;
280 }
AMXC_INLINE amxc_llist_it_t * amxc_llist_get_last(const amxc_llist_t *const llist)
Gets the last item of the linked list.
Definition: amxc_llist.h:732
The linked list iterator structure.
Definition: amxc_llist.h:215

◆ amxc_string_create_part()

static int amxc_string_create_part ( const amxc_string_t *const  string,
amxc_llist_t *const  list,
const size_t  start_pos,
const size_t  length 
)
static

Definition at line 127 of file amxc_string_split.c.

130  {
131  int retval = -1;
132  amxc_string_t* part = NULL;
133  char* buffer = NULL;
134 
135  buffer = amxc_string_dup(string, start_pos, length);
136  when_null(buffer, exit);
137  when_failed(amxc_string_new(&part, 0), exit);
138  if((length == 1) && isspace(buffer[0])) {
139  amxc_string_set_at(part, 0, buffer, 1, amxc_string_no_flags);
140  free(buffer);
141  } else {
142  when_failed(amxc_string_push_buffer(part, buffer, length + 1), exit);
143  }
144  amxc_llist_append(list, &part->it);
145 
146  retval = 0;
147 
148 exit:
149  if(retval != 0) {
150  free(buffer);
151  amxc_string_delete(&part);
152  }
153  return retval;
154 }
#define when_failed(x, l)
Definition: amxc_macros.h:142
#define when_null(x, l)
Definition: amxc_macros.h:126
int amxc_llist_append(amxc_llist_t *const llist, amxc_llist_it_t *const it)
Adds an item to the end of the linked list.
Definition: amxc_llist.c:169
void amxc_string_delete(amxc_string_t **string)
Frees the previously allocated string.
Definition: amxc_string.c:150
int amxc_string_push_buffer(amxc_string_t *const string, char *buffer, size_t length)
Sets the string buffer.
Definition: amxc_string.c:372
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
int amxc_string_new(amxc_string_t **string, const size_t length)
Allocates a string.
Definition: amxc_string.c:118
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
@ amxc_string_no_flags
Definition: amxc_string.h:121
amxc_llist_it_t it
Definition: amxc_string.h:108

◆ amxc_string_split_update_status()

static bool amxc_string_split_update_status ( const amxc_string_t *const  string,
size_t  i,
amxc_string_word_flags_t flags 
)
static

Definition at line 156 of file amxc_string_split.c.

158  {
159  bool skip = false;
160  if(string->buffer[i] == '\\') {
161  flags->escape = true;
162  skip = true;
163  }
164  flags->start_quote = false;
165  if(!flags->between_single_quotes && (string->buffer[i] == '"')) {
167  flags->start_quote = flags->between_double_quotes;
168  }
169  if(!flags->between_double_quotes && (string->buffer[i] == '\'')) {
171  flags->start_quote = flags->between_single_quotes;
172  }
173  if(!(flags->between_double_quotes || flags->between_single_quotes)) {
174  switch(string->buffer[i]) {
175  case '(':
176  flags->round_brackets++;
177  break;
178  case ')':
179  flags->round_brackets--;
180  break;
181  case '{':
182  flags->curly_brackets++;
183  break;
184  case '}':
185  flags->curly_brackets--;
186  break;
187  case '[':
188  flags->square_brackets++;
189  break;
190  case ']':
191  flags->square_brackets--;
192  break;
193  }
194  }
195 
196  return skip;
197 }
char * buffer
Definition: amxc_string.h:104

◆ amxc_string_split_word_is_valid()

static amxc_string_split_status_t amxc_string_split_word_is_valid ( amxc_string_word_flags_t flags,
const char **  reason 
)
static

Definition at line 200 of file amxc_string_split.c.

201  {
203  const char* msg = "";
204 
205  if(flags->between_double_quotes) {
207  msg = "Missing closing double quote - \"";
208  goto exit;
209  }
210  if(flags->between_single_quotes) {
212  msg = "Missing closing single quote - '";
213  goto exit;
214  }
215  if(flags->round_brackets > 0) {
217  msg = "Missing closing round bracket - )";
218  goto exit;
219  }
220  if(flags->round_brackets < 0) {
222  msg = "Missing open round bracket - (";
223  goto exit;
224  }
225  if(flags->curly_brackets > 0) {
227  msg = "Missing closing curly bracket - }";
228  goto exit;
229  }
230  if(flags->curly_brackets < 0) {
232  msg = "Missing opening curly bracket - {";
233  goto exit;
234  }
235  if(flags->square_brackets > 0) {
237  msg = "Missing closing square bracket - ]";
238  goto exit;
239  }
240  if(flags->square_brackets < 0) {
242  msg = "Missing opening square bracket - [";
243  goto exit;
244  }
245 
246 exit:
247  if(reason != NULL) {
248  *reason = msg;
249  }
250  return retval;
251 }
@ AMXC_ERROR_STRING_MISSING_CBRACKET
@ AMXC_ERROR_STRING_MISSING_RBRACKET
@ AMXC_ERROR_STRING_MISSING_SQUOTE
@ AMXC_ERROR_STRING_MISSING_DQUOTE
@ AMXC_ERROR_STRING_MISSING_SBRACKET

◆ amxc_string_split_words_internal()

static amxc_string_split_status_t amxc_string_split_words_internal ( const amxc_string_t *const  string,
amxc_llist_t list,
amxc_string_create_part_t  create,
amxc_string_check_delimiter_t  check,
const char **  reason 
)
static

Definition at line 283 of file amxc_string_split.c.

287  {
289  size_t start_pos = 0;
290  size_t i = 0;
292 
293  flags.start_quote = false;
294  flags.between_double_quotes = false;
295  flags.between_single_quotes = false;
296  flags.escape = false;
297  flags.round_brackets = 0;
298  flags.curly_brackets = 0;
299  flags.square_brackets = 0;
300 
301  for(i = 0; i < string->last_used; i++) {
302  if(flags.escape == false) {
303  if(amxc_string_split_update_status(string, i, &flags) == true) {
304  continue;
305  }
306  }
307 
308  flags.escape = false;
309 
310  if(((flags.between_double_quotes == false) &&
311  (flags.between_single_quotes == false)) ||
312  ( flags.start_quote == true)) {
313  if(isspace(string->buffer[i])) {
314  if(i - start_pos > 0) {
315  when_failed(create(string, list, start_pos, i - start_pos), exit);
316  }
317  if(check(list, string->buffer[i])) {
318  when_failed(create(string, list, i, 1), exit);
319  }
320  start_pos = i + 1;
321  continue;
322  }
323  if(ispunct(string->buffer[i])) {
324  if(i - start_pos > 0) {
325  when_failed(create(string, list, start_pos, i - start_pos), exit);
326  }
327  if(check(list, string->buffer[i])) {
328  when_failed(create(string, list, i, 1), exit);
329  }
330  start_pos = i + 1;
331  continue;
332  }
333  }
334  }
335 
336  if(i - start_pos != 0) {
337  when_failed(create(string, list, start_pos, i - start_pos), exit);
338  }
339 
340  retval = amxc_string_split_word_is_valid(&flags, reason);
341 
342 exit:
343  return retval;
344 }
static bool amxc_string_split_update_status(const amxc_string_t *const string, size_t i, amxc_string_word_flags_t *flags)
static amxc_string_split_status_t amxc_string_split_word_is_valid(amxc_string_word_flags_t *flags, const char **reason)

◆ amxc_trim_llist()

static void amxc_trim_llist ( amxc_llist_t *const  list)
static

Definition at line 93 of file amxc_string_split.c.

93  {
96  if(amxc_string_text_length(part) != 1) {
97  break;
98  }
99  if(isspace(part->buffer[0]) == 0) {
100  break;
101  }
102  amxc_string_delete(&part);
103  }
104 
105  while(true) {
107  amxc_llist_it_t* last = amxc_llist_get_last(list);
108 
109  if((first != NULL) && (last != NULL)) {
112 
113  if((amxc_string_text_length(fpart) == 1) &&
114  ( amxc_string_text_length(lpart) == 1)) {
115  if((fpart->buffer[0] == '[') &&
116  ( lpart->buffer[0] == ']')) {
117  amxc_string_delete(&fpart);
118  amxc_string_delete(&lpart);
119  continue;
120  }
121  }
122  }
123  break;
124  }
125 }
#define amxc_llist_for_each_reverse(it, list)
Loops over the list from tail to head.
Definition: amxc_llist.h:287
AMXC_INLINE amxc_llist_it_t * amxc_llist_get_first(const amxc_llist_t *const llist)
Gets the first item of the linked list.
Definition: amxc_llist.h:713
static amxc_var_t * first
Definition: test_issue_59.c:81