UniRec  3.0.0
unirec.c
Go to the documentation of this file.
1 
8 /*
9  * Copyright (C) 2015 CESNET
10 
11  *
12  * LICENSE TERMS
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  * notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  * notice, this list of conditions and the following disclaimer in
21  * the documentation and/or other materials provided with the
22  * distribution.
23  * 3. Neither the name of the Company nor the names of its contributors
24  * may be used to endorse or promote products derived from this
25  * software without specific prior written permission.
26  *
27  * ALTERNATIVELY, provided that this notice is retained in full, this
28  * product may be distributed under the terms of the GNU General Public
29  * License (GPL) version 2 or later, in which case the provisions
30  * of the GPL apply INSTEAD OF those given above.
31  *
32  * This software is provided ``as is'', and any express or implied
33  * warranties, including, but not limited to, the implied warranties of
34  * merchantability and fitness for a particular purpose are disclaimed.
35  * In no event shall the company or contributors be liable for any
36  * direct, indirect, incidental, special, exemplary, or consequential
37  * damages (including, but not limited to, procurement of substitute
38  * goods or services; loss of use, data, or profits; or business
39  * interruption) however caused and on any theory of liability, whether
40  * in contract, strict liability, or tort (including negligence or
41  * otherwise) arising in any way out of the use of this software, even
42  * if advised of the possibility of such damage.
43  *
44  */
45 
46 #define _DEFAULT_SOURCE
47 #define _BSD_SOURCE
48 #define _XOPEN_SOURCE
49 #define __USE_XOPEN
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <inttypes.h>
53 #include <time.h>
54 #include <string.h>
55 #include <regex.h>
56 #include <assert.h>
57 #include <ctype.h>
58 #include <unirec/unirec.h>
59 #include <unirec/inline.h>
60 #include <libtrap/trap.h>
61 #include <inttypes.h>
63 
64 #ifndef MAX
65 #define MAX(A, B) ((A >= B) ? (A) : (B))
66 #endif
67 
68 // All inline functions from ipaddr.h must be declared again with "extern"
69 // in exactly one translation unit (it generates externally linkable code of
70 // these function)
71 // See this for explanation (Nemo's answer):
72 // http://stackoverflow.com/questions/6312597/is-inline-without-static-or-extern-ever-useful-in-c99
73 INLINE_IMPL int ip_is4(const ip_addr_t *addr);
74 INLINE_IMPL int ip_is6(const ip_addr_t *addr);
75 INLINE_IMPL uint32_t ip_get_v4_as_int(const ip_addr_t *addr);
76 INLINE_IMPL char *ip_get_v4_as_bytes(const ip_addr_t *addr);
80 INLINE_IMPL ip_addr_t ip_from_16_bytes_be(const char b[16]);
81 INLINE_IMPL ip_addr_t ip_from_16_bytes_le(const char b[16]);
82 INLINE_IMPL int ip_cmp(const ip_addr_t *addr1, const ip_addr_t *addr2);
83 INLINE_IMPL int ip_from_str(const char *str, ip_addr_t *addr);
84 INLINE_IMPL void ip_to_str(const ip_addr_t *addr, char *str);
85 
86 INLINE_IMPL mac_addr_t mac_from_bytes(const uint8_t *array);
87 INLINE_IMPL int mac_from_str(const char *str, mac_addr_t *addr);
88 INLINE_IMPL int mac_cmp(const mac_addr_t *addr1, const mac_addr_t *addr2);
89 INLINE_IMPL void mac_to_str(const mac_addr_t *addr, char *str);
90 INLINE_IMPL void mac_to_bytes(const mac_addr_t *addr, uint8_t *array);
91 
92 
98 const int ur_field_type_size[] = {
99  -1, /*UR_TYPE_STRING*/
100  -1, /*UR_TYPE_BYTES*/
101  1, /*UR_TYPE_CHAR*/
102  1, /*UR_TYPE_UINT8*/
103  1, /*UR_TYPE_INT8*/
104  2, /*UR_TYPE_UINT16*/
105  2, /*UR_TYPE_INT16*/
106  4, /*UR_TYPE_UINT32*/
107  4, /*UR_TYPE_INT32*/
108  8, /*UR_TYPE_UINT64*/
109  8, /*UR_TYPE_INT64*/
110  4, /*UR_TYPE_FLOAT*/
111  8, /*UR_TYPE_DOUBLE*/
112  16, /*UR_TYPE_IP*/
113  6, /*UR_TYPE_MAC*/
114  8, /*UR_TYPE_TIME*/
115 
116  // arrays
117  -1, /*UR_TYPE_A_UINT8*/
118  -1, /*UR_TYPE_A_INT8*/
119  -2, /*UR_TYPE_A_UINT16*/
120  -2, /*UR_TYPE_A_INT16*/
121  -4, /*UR_TYPE_A_UINT32*/
122  -4, /*UR_TYPE_A_INT32*/
123  -8, /*UR_TYPE_A_UINT64*/
124  -8, /*UR_TYPE_A_INT64*/
125  -4, /*UR_TYPE_A_FLOAT*/
126  -8, /*UR_TYPE_A_DOUBLE*/
127  -16, /*UR_TYPE_A_IP*/
128  -6, /*UR_TYPE_A_MAC*/
129  -8, /*UR_TYPE_A_TIME*/
130 };
131 
137 const char *ur_field_type_str[] = {
138  "string", /*UR_TYPE_STRING*/
139  "bytes", /*UR_TYPE_BYTES*/
140  "char", /*UR_TYPE_CHAR*/
141  "uint8", /*UR_TYPE_UINT8*/
142  "int8", /*UR_TYPE_INT8*/
143  "uint16", /*UR_TYPE_UINT16*/
144  "int16", /*UR_TYPE_INT16*/
145  "uint32", /*UR_TYPE_UINT32*/
146  "int32", /*UR_TYPE_INT32*/
147  "uint64", /*UR_TYPE_UINT64*/
148  "int64", /*UR_TYPE_INT64*/
149  "float", /*UR_TYPE_FLOAT*/
150  "double", /*UR_TYPE_DOUBLE*/
151  "ipaddr", /*UR_TYPE_IP*/
152  "macaddr", /*UR_TYPE_MAC*/
153  "time", /*UR_TYPE_TIME*/
154  "uint8*", /*UR_TYPE_A_UINT8*/
155  "int8*", /*UR_TYPE_A_INT8*/
156  "uint16*", /*UR_TYPE_A_UINT16*/
157  "int16*", /*UR_TYPE_A_INT16*/
158  "uint32*", /*UR_TYPE_A_UINT32*/
159  "int32*", /*UR_TYPE_A_INT32*/
160  "uint64*", /*UR_TYPE_A_UINT64*/
161  "int64*", /*UR_TYPE_A_INT64*/
162  "float*", /*UR_TYPE_A_FLOAT*/
163  "double*", /*UR_TYPE_A_DOUBLE*/
164  "ipaddr*", /*UR_TYPE_A_IP*/
165  "macaddr*", /*UR_TYPE_A_MAC*/
166  "time*", /*UR_TYPE_A_TIME*/
167 };
168 
173  UR_TYPE_STRING, /* UR_TYPE_STRING */
174  UR_TYPE_BYTES, /* UR_TYPE_BYTES */
175  UR_TYPE_CHAR, /* UR_TYPE_CHAR */
176  UR_TYPE_UINT8, /* UR_TYPE_UINT8 */
177  UR_TYPE_INT8, /* UR_TYPE_INT8 */
178  UR_TYPE_UINT16, /* UR_TYPE_UINT16 */
179  UR_TYPE_INT16, /* UR_TYPE_INT16 */
180  UR_TYPE_UINT32, /* UR_TYPE_UINT32 */
181  UR_TYPE_INT32, /* UR_TYPE_INT32 */
182  UR_TYPE_UINT64, /* UR_TYPE_UINT64 */
183  UR_TYPE_INT64, /* UR_TYPE_INT64 */
184  UR_TYPE_FLOAT, /* UR_TYPE_FLOAT */
185  UR_TYPE_DOUBLE, /* UR_TYPE_DOUBLE */
186  UR_TYPE_IP, /* UR_TYPE_IP */
187  UR_TYPE_MAC, /* UR_TYPE_MAC */
188  UR_TYPE_TIME, /* UR_TYPE_TIME */
189  UR_TYPE_UINT8, /* UR_TYPE_A_UINT8 */
190  UR_TYPE_INT8, /* UR_TYPE_A_INT8 */
191  UR_TYPE_UINT16, /* UR_TYPE_A_UINT16 */
192  UR_TYPE_INT16, /* UR_TYPE_A_INT16 */
193  UR_TYPE_UINT32, /* UR_TYPE_A_UINT32 */
194  UR_TYPE_INT32, /* UR_TYPE_A_INT32 */
195  UR_TYPE_UINT64, /* UR_TYPE_A_UINT64 */
196  UR_TYPE_INT64, /* UR_TYPE_A_INT64 */
197  UR_TYPE_FLOAT, /* UR_TYPE_A_FLOAT */
198  UR_TYPE_DOUBLE, /* UR_TYPE_A_DOUBLE */
199  UR_TYPE_IP, /* UR_TYPE_A_IP */
200  UR_TYPE_MAC, /* UR_TYPE_A_MAC */
201  UR_TYPE_TIME, /* UR_TYPE_A_TIME */
202 };
203 
204 
207 
208 const char UR_MEMORY_ERROR[] = "Memory allocation error";
209 
210 int ur_init(ur_static_field_specs_t field_specs_static)
211 {
212  int i, j;
214  return UR_OK;
215  }
216  //copy size
218  ur_field_specs.ur_last_id = field_specs_static.ur_last_id;
220  //copy field type
222  if (ur_field_specs.ur_field_types == NULL) {
223  return UR_E_MEMORY;
224  }
225  memcpy(ur_field_specs.ur_field_types, field_specs_static.ur_field_types, sizeof(ur_field_type_t) * field_specs_static.ur_last_id);
226  //copy field sizes
227  ur_field_specs.ur_field_sizes = (short *) calloc(sizeof(short), ur_field_specs.ur_allocated_fields);
228  if (ur_field_specs.ur_field_sizes == NULL) {
230  return UR_E_MEMORY;
231  }
232  memcpy(ur_field_specs.ur_field_sizes, field_specs_static.ur_field_sizes, sizeof(short) * field_specs_static.ur_last_id);
233  //copy field names
234  ur_field_specs.ur_field_names = (char **) calloc(sizeof(char *), ur_field_specs.ur_allocated_fields);
235  if (ur_field_specs.ur_field_names == NULL) {
238  return UR_E_MEMORY;
239  }
240  for (i = 0; i < field_specs_static.ur_last_id; i++) {
241  ur_field_specs.ur_field_names[i] = (char *) calloc(sizeof(char), strlen(field_specs_static.ur_field_names[i]) + 1);
242  if (ur_field_specs.ur_field_names[i] == NULL) {
245  for (j = 0; j < i; j++) {
247  }
249  return UR_E_MEMORY;
250  }
251  strcpy(ur_field_specs.ur_field_names[i], field_specs_static.ur_field_names[i]);
252  }
254  return UR_OK;
255 }
256 
257 char *ur_template_string_delimiter(const ur_template_t *tmplt, int delimiter)
258 {
259  char *str = NULL, *strmove = NULL, *str_new = NULL;
260  int len = UR_DEFAULT_LENGTH_OF_TEMPLATE, act_len = 0;
261 
262  if (tmplt == NULL) {
263  return NULL;
264  }
265 
266  str = (char *) calloc(sizeof(char), len);
267  if (str == NULL) {
268  return NULL;
269  }
270  strmove = str;
271  for (int i = 0; i < tmplt->count; i++) {
272  act_len += strlen(ur_field_type_str[ur_get_type(tmplt->ids[i])]) + strlen(ur_get_name(tmplt->ids[i])) + 2;
273  if (act_len >= len) {
274  len *= 2;
275  str_new = (char *) realloc(str, sizeof(char) * len);
276  if (str_new == NULL) {
277  free(str);
278  return NULL;
279  }
280  strmove = str_new + (strmove - str);
281  str = str_new;
282  }
283  sprintf(strmove, "%s %s%c", ur_field_type_str[ur_get_type(tmplt->ids[i])], ur_get_name(tmplt->ids[i]), delimiter);
284  strmove += strlen(strmove);
285  }
286  if (tmplt->count != 0) {
287  strmove[-1] = '\0';
288  }
289  return str;
290 }
291 
293 {
294  ur_field_id_linked_list_t * first;
295  //check if UniRec is initialized, if not initialize it
297  int init_val = ur_init(UR_FIELD_SPECS_STATIC);
298  if (init_val != UR_OK) {
299  return init_val;
300  }
301  }
302  //check undefined fields
303  if (ur_field_specs.ur_undefine_fields != NULL) {
304  //resuse old undefined fields
305  int id;
308  id = first->id;
309  free(first);
310  return id;
311  } else {
312  //take new id
314  //take value from remaining space
315  return ur_field_specs.ur_last_id++;
317  //increase space for fields
318  int new_size;
319 
320  char **ur_field_names_new;
321  short *ur_field_sizes_new;
322  ur_field_type_t *ur_field_types_new;
323 
325 
326  //copy field type
327  ur_field_types_new = (ur_field_type_t *) realloc(ur_field_specs.ur_field_types, sizeof(ur_field_type_t) * new_size);
328  if (ur_field_types_new == NULL) {
329  return UR_E_MEMORY;
330  }
331 
332  //copy field sizes
333  ur_field_sizes_new = (short *) realloc(ur_field_specs.ur_field_sizes, sizeof(short) * new_size);
334  if (ur_field_sizes_new == NULL) {
335  free(ur_field_types_new);
336  return UR_E_MEMORY;
337  }
338 
339  //copy field names
340  ur_field_names_new = (char **) realloc(ur_field_specs.ur_field_names, sizeof(char *) * new_size);
341  if (ur_field_names_new == NULL) {
342  free(ur_field_types_new);
343  free(ur_field_sizes_new);
344  return UR_E_MEMORY;
345  }
346  //replace for new values
347  ur_field_specs.ur_field_names = ur_field_names_new;
348  ur_field_specs.ur_field_sizes = ur_field_sizes_new;
349  ur_field_specs.ur_field_types = ur_field_types_new;
351  return ur_field_specs.ur_last_id++;
352  } else {
353  //no more space for new fields
354  return UR_E_MEMORY;
355  }
356  }
357 }
358 
359 int ur_get_field_type_from_str(const char *type)
360 {
361  if (type == NULL) {
362  return UR_E_INVALID_TYPE;
363  }
364  for (int i = 0; i < UR_COUNT_OF_TYPES; i++) {
365  if (strcmp(type, ur_field_type_str[i]) == 0) {
366  return i;
367  }
368  }
369  return UR_E_INVALID_TYPE;
370 }
371 
372 const char *ur_get_type_and_name_from_string(const char *source, char **name, char **type, int *length_name, int *length_type)
373 {
374  int length_type_2 = 0, length_name_2 = 0;
375  const char *source_cpy;
376  /* skip white spaces */
377  while (*source != 0 && isspace(*source)) {
378  source++;
379  }
380  /* start of type */
381  source_cpy = source;
382  while (*source != 0 && !isspace(*source)) {
383  length_type_2++;
384  source++;
385  }
386  /* end of type */
387 
388  /* copy "type" string (realloc destination if needed) */
389  if (length_type_2 >= *length_type) {
390  if (*type != NULL) {
391  free(*type);
392  }
393  *type = (char *) malloc(sizeof(char) * (length_type_2 + 1));
394  if (*type == NULL) {
395  return NULL;
396  }
397  *length_type = length_type_2 + 1;
398  }
399  memcpy(*type, source_cpy, length_type_2);
400  (*type)[length_type_2] = 0;
401 
402  /* skip white spaces */
403  while (*source != 0 && isspace(*source)) {
404  source++;
405  }
406  /* start of name */
407  source_cpy = source;
408  while (*source != 0 && !isspace(*source) && *source != ',') {
409  length_name_2++;
410  source++;
411  }
412  /* end of name */
413 
414  /* copy "name" string (realloc destination if needed) */
415  if (length_name_2 >= *length_name) {
416  if (*name != NULL) {
417  free(*name);
418  }
419  *name = (char *) malloc(sizeof(char) * (length_name_2 + 1));
420  if (*name == NULL) {
421  return NULL;
422  }
423  *length_name = length_name_2 + 1;
424  }
425  memcpy(*name, source_cpy, length_name_2);
426  (*name)[length_name_2] = 0;
427  /* skip white spaces */
428  while (*source != 0 && isspace(*source)) {
429  source++;
430  }
431  /* skip comma */
432  if (*source == ',') {
433  source++;
434  }
435  return source;
436 }
437 
438 char *ur_ifc_data_fmt_to_field_names(const char *ifc_data_fmt)
439 {
440  const char *source_cpy = NULL, *p = ifc_data_fmt;
441  char *out_str;
442  int name_len = 0, act_len = 0, str_len;
443  str_len = strlen(ifc_data_fmt);
444  out_str = (char *) calloc(str_len + 1, sizeof(char));
445  if (out_str == NULL) {
446  return NULL;
447  }
448  while (*p != 0) {
449  /* skip white spaces */
450  while (*p != 0 && isspace(*p)) {
451  p++;
452  }
453  /* field type */
454  while (*p != 0 && *p != ' ') {
455  p++;
456  }
457  /* skip white spaces */
458  while (*p != 0 && isspace(*p)) {
459  p++;
460  }
461 
462  //copy name
463  source_cpy = p;
464  name_len = 0;
465  while (*p != 0 && *p != ',' && !isspace(*p)) {
466  name_len++;
467  p++;
468  }
469  assert(name_len + act_len + 1 <= str_len);
470  memcpy(out_str + act_len, source_cpy, name_len);
471  act_len += name_len;
472  /* skip white spaces */
473  while (*p != 0 && isspace(*p)) {
474  p++;
475  }
476  if (*p == ',') {
477  p++;
478  } else if (*p == 0) {
479  break;
480  } else {
481  free(out_str);
482  return NULL; /* name must be followed by a comma or end of string */
483  }
484  out_str[act_len] = ',';
485  act_len++;
486  }
487  return out_str;
488 }
489 
490 ur_template_t *ur_expand_template(const char *ifc_data_fmt, ur_template_t *tmplt)
491 {
492  int name_len = 0, act_len = 0, concat_str_len = strlen(ifc_data_fmt);
493  char *concat_str;
494  const char *source_cpy, *p = ifc_data_fmt;
496  uint32_t ifc_out = 0;
497  concat_str = (char *) malloc(sizeof(char) * concat_str_len);
498  if (concat_str == NULL) {
499  return NULL;
500  }
501  while (*p != 0) {
502  while (*p != 0 && !isspace(*p)) {
503  p++;
504  }
505  p++;
506  //copy name
507  source_cpy = p;
508  name_len = 0;
509  while (*p != 0 && *p != ',') {
510  name_len++;
511  p++;
512  }
513  if (name_len + act_len + 1 > concat_str_len) {
514  char *str_new;
515  size_t req_size = MAX(name_len + act_len + 1, (concat_str_len * 2));
516  str_new = (char *) realloc(concat_str, sizeof(char) * req_size);
517  if (str_new == NULL) {
518  /* XXX memory leak original concat_str? */
519  return NULL;
520  }
521  concat_str_len = req_size;
522  concat_str = str_new;
523  }
524  memcpy(concat_str + act_len, source_cpy, name_len);
525  act_len += name_len;
526  concat_str[act_len] = ',';
527  act_len++;
528  }
529  if (tmplt != NULL) {
530  direction = tmplt->direction;
531  ifc_out = tmplt->ifc_out;
532  for (int i = 0; i < tmplt->count; i++) {
533  const char *f_name = ur_get_name(tmplt->ids[i]);
534  name_len = strlen(f_name);
535  if (name_len + act_len + 1 > concat_str_len) {
536  char *str_new;
537  size_t req_size = MAX(name_len + act_len + 1, (concat_str_len * 2));
538  str_new = (char *) realloc(concat_str, sizeof(char) * req_size);
539  if (str_new == NULL) {
540  /* XXX memory leak original concat_str? */
541  return NULL;
542  }
543  concat_str_len = req_size;
544  concat_str = str_new;
545  }
546  memcpy(concat_str + act_len, f_name, name_len);
547  act_len += name_len;
548  *(concat_str + act_len) = ',';
549  act_len++;
550  }
551  ur_free_template(tmplt);
552  }
553  if (act_len > 0) {
554  act_len--;
555  concat_str[act_len] = 0;
556  }
557  tmplt = ur_create_template(concat_str, NULL);
558  tmplt->direction = direction;
559  tmplt->ifc_out = ifc_out;
560  free(concat_str);
561  return tmplt;
562 }
563 
564 int ur_define_set_of_fields(const char *ifc_data_fmt)
565 {
566  const char *new_fields_move;
567  new_fields_move = ifc_data_fmt;
568  char *field_name, *field_type;
569  int field_name_length = UR_DEFAULT_LENGTH_OF_FIELD_NAME, field_type_length = UR_DEFAULT_LENGTH_OF_FIELD_TYPE;
570  int field_id = 0, field_type_id = 0;
571  field_name = (char *) malloc(sizeof(char) * field_name_length);
572  if (field_name == NULL) {
573  return UR_E_MEMORY;
574  }
575  field_type = (char *) malloc(sizeof(char) * field_type_length);
576  if (field_type == NULL) {
577  free(field_name);
578  return UR_E_MEMORY;
579  }
580  while (*new_fields_move != 0) {
581  new_fields_move = ur_get_type_and_name_from_string(new_fields_move, &field_name, &field_type, &field_name_length, &field_type_length);
582  if (new_fields_move == NULL) {
583  if (field_name != NULL) {
584  free(field_name);
585  }
586  if (field_type != NULL) {
587  free(field_type);
588  }
589  return UR_E_MEMORY;
590  }
591  //through all fields of receiver
592  field_type_id = ur_get_field_type_from_str(field_type);
593  if (field_type_id < 0) {
594  if (field_name != NULL) {
595  free(field_name);
596  }
597  free(field_type);
598  return field_type_id;
599  }
600  field_id = ur_define_field(field_name, field_type_id);
601  if (field_id < 0) {
602  if (field_name != NULL) {
603  free(field_name);
604  }
605  free(field_type);
606  return field_id;
607  }
608  }
609  if (field_name != NULL) {
610  free(field_name);
611  }
612  free(field_type);
613  return UR_OK;
614 }
615 
617 {
618  ur_template_t *new_tmplt;
619  if (ur_define_set_of_fields(ifc_data_fmt) < 0) {
620  return NULL;
621  }
622  new_tmplt = ur_create_template_from_ifc_spec(ifc_data_fmt);
623  if (new_tmplt != NULL && tmplt != NULL) {
624  new_tmplt->ifc_out = tmplt->ifc_out;
625  new_tmplt->direction = tmplt->direction;
626  ur_free_template(tmplt);
627  }
628  return new_tmplt;
629 }
630 
632 {
633  char *field_names = ur_ifc_data_fmt_to_field_names(ifc_data_fmt);
634  if (field_names == NULL) {
635  return NULL;
636  }
637  ur_template_t *new_tmplt = ur_create_template(field_names, NULL);
638  free(field_names);
639  return new_tmplt;
640 }
641 
642 int ur_define_field(const char *name, ur_field_type_t type)
643 {
644  int insert_id;
645  char * name_copy;
646  int name_len;
647  if (name == NULL) {
648  return UR_E_INVALID_NAME;
649  }
650  //check the regural expression of a name
651  name_len = strlen(name);
652  if (name_len == 0) {
653  return UR_E_INVALID_NAME;
654  }
655  if (!((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z'))) {
656  return UR_E_INVALID_NAME;
657  }
658  for (int i = 1; i < name_len; i++) {
659  if (!((name[i] >= 'A' && name[i] <= 'Z') || (name[i] >= 'a' && name[i] <= 'z') || (name[i] >= '0' && name[i] <= '9') || name[i] == '_')) {
660  return UR_E_INVALID_NAME;
661  }
662  }
663  // If this is the first dynamically allocated field, call ur_init
665  int init_val = ur_init(UR_FIELD_SPECS_STATIC);
666  if (init_val != 0) {
667  return init_val;
668  }
669  }
670  //check if the field is already defined
671  for (int i = 0; i < ur_field_specs.ur_last_id; i++) {
672  if (ur_field_specs.ur_field_names[i] != NULL && strcmp(name, ur_field_specs.ur_field_names[i]) == 0) {
673  if (type == ur_field_specs.ur_field_types[i]) {
674  //name exists and type is equal
675  return i;
676  } else {
677  //name exists, but type is different
678  return UR_E_TYPE_MISMATCH;
679  }
680  }
681  }
682  //create new field
683  name_copy = (char *) calloc(sizeof(char), strlen(name) + 1);
684  if (name_copy == NULL) {
685  //error during allocation
686  return UR_E_MEMORY;
687  }
688  strcpy(name_copy, name);
689  insert_id = ur_get_empty_id();
690  if (insert_id < 0) {
691  //error
692  free(name_copy);
693  return insert_id;
694  }
695  ur_field_specs.ur_field_names[insert_id] = name_copy;
696  ur_field_specs.ur_field_sizes[insert_id] = ur_size_of(type);
697  ur_field_specs.ur_field_types[insert_id] = type;
698  return insert_id;
699 }
700 
702 {
703  if (field_id < ur_field_specs.ur_last_statically_defined_id || field_id >= ur_field_specs.ur_last_id) {
704  //id is invalid
705  return UR_E_INVALID_PARAMETER;
706  } else if (ur_field_specs.ur_field_names[field_id] == NULL) {
707  //ID is already undefined
708  return UR_E_INVALID_PARAMETER;
709  } else {
710  //undefine field
711  ur_field_id_linked_list_t *undefined_item;
712  undefined_item = (ur_field_id_linked_list_t *) calloc(sizeof(ur_field_id_linked_list_t), 1);
713  if (undefined_item == NULL) {
714  //error during allocation
715  return UR_E_MEMORY;
716  }
717  free(ur_field_specs.ur_field_names[field_id]);
718  ur_field_specs.ur_field_names[field_id] = NULL;
719  undefined_item->id = field_id;
720  undefined_item->next = ur_field_specs.ur_undefine_fields;
721  ur_field_specs.ur_undefine_fields = undefined_item;
722  }
723  return UR_OK;
724 }
725 
726 int ur_undefine_field(const char *name)
727 {
728  int i;
729  //find id of field
731  if (ur_field_specs.ur_field_names[i] != NULL && strcmp(name, ur_field_specs.ur_field_names[i]) == 0) {
732  return ur_undefine_field_by_id(i);
733  }
734  }
735  //field with given name was not found
736  return UR_E_INVALID_NAME;
737 }
738 
739 
741 {
743  //there is no need for deallocation, because nothing has been allocated.
744  return;
745  }
746  if (ur_field_specs.ur_field_names != NULL) {
747  for (int i=0; i < ur_field_specs.ur_last_id; i++) {
748  if (ur_field_specs.ur_field_names[i] != NULL) {
750  }
751  }
753  }
754  if (ur_field_specs.ur_undefine_fields != NULL) {
755  ur_field_id_linked_list_t *next, * act_del;
757  while (act_del != NULL) {
758  next = act_del->next;
759  free(act_del);
760  act_del = next;
761  }
762  }
763  if (ur_field_specs.ur_field_sizes != NULL) {
765  }
766  if (ur_field_specs.ur_field_types != NULL) {
768  }
777 }
778 
779 // Find field ID given its name
780 int ur_get_id_by_name(const char *name)
781 {
782  for (int id = 0; id < ur_field_specs.ur_last_id; id++) {
783  if (ur_field_specs.ur_field_names[id] != NULL && strcmp(name, ur_field_specs.ur_field_names[id]) == 0) {
784  return id;
785  }
786  }
787  return UR_E_INVALID_NAME;
788 }
789 
790 // Return -1 if f1 should go before f2, 0 if f1 is the same as f2, 1 otherwise
791 int compare_fields(const void *field1, const void *field2)
792 {
793  const field_spec_t *f1 = field1;
794  const field_spec_t *f2 = field2;
795  if (f1->size > f2->size) {
796  return -1;
797  } else if (f1->size < f2->size) {
798  return 1;
799  } else {
800  return strcmp(f1->name, f2->name);
801  }
802 }
803 
804 ur_template_t *ur_ctx_create_input_template(trap_ctx_t *ctx, int ifc, const char *fields, char **errstr)
805 {
806  ur_template_t *tmplt = ur_create_template(fields, errstr);
807  if (tmplt == NULL) {
808  return NULL;
809  }
810  if (ur_ctx_set_input_template(ctx, ifc, tmplt) != UR_OK) {
811  if (errstr != NULL) {
812  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
813  if (*errstr != NULL) {
814  strcpy(*errstr, UR_MEMORY_ERROR);
815  }
816  }
817  ur_free_template(tmplt);
818  return NULL;
819  }
820  return tmplt;
821 }
822 
823 ur_template_t *ur_ctx_create_output_template(trap_ctx_t *ctx, int ifc, const char *fields, char **errstr)
824 {
825  ur_template_t *tmplt = ur_create_template(fields, errstr);
826  if (tmplt == NULL) {
827  return NULL;
828  }
829  if (ur_ctx_set_output_template(ctx, ifc, tmplt) != UR_OK) {
830  if (errstr != NULL) {
831  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
832  if (*errstr != NULL) {
833  strcpy(*errstr, UR_MEMORY_ERROR);
834  }
835  }
836  ur_free_template(tmplt);
837  return NULL;
838  }
839  return tmplt;
840 }
841 
842 int ur_ctx_set_output_template(trap_ctx_t *ctx, int ifc, ur_template_t *tmplt)
843 {
844  if (tmplt == NULL) {
845  return UR_OK;
846  }
847  if (tmplt->direction == UR_TMPLT_DIRECTION_IN) {
849  } else {
851  }
852  tmplt->ifc_out = ifc;
853  char * tmplt_str = ur_template_string(tmplt);
854  if (tmplt_str == NULL) {
855  return UR_E_MEMORY;
856  }
857  trap_ctx_set_data_fmt(ctx, ifc, TRAP_FMT_UNIREC, tmplt_str);
858  free(tmplt_str);
859  return UR_OK;
860 }
861 
862 int ur_ctx_set_input_template(trap_ctx_t *ctx, int ifc, ur_template_t *tmplt)
863 {
864  if (tmplt == NULL) {
865  return UR_OK;
866  }
867  if (tmplt->direction == UR_TMPLT_DIRECTION_OUT) {
869  } else {
871  }
872  char * tmplt_str = ur_template_string(tmplt);
873  if (tmplt_str == NULL) {
874  return UR_E_MEMORY;
875  }
876  trap_ctx_set_required_fmt(ctx, ifc, TRAP_FMT_UNIREC, tmplt_str);
877  free(tmplt_str);
878  return UR_OK;
879 }
880 
881 ur_template_t *ur_ctx_create_bidirectional_template(trap_ctx_t *ctx, int ifc_in, int ifc_out, const char *fields, char **errstr)
882 {
883  ur_template_t *tmplt = ur_create_template(fields, errstr);
884  if (tmplt == NULL) {
885  return NULL;
886  }
888  tmplt->ifc_out = ifc_out;
889  char * tmplt_str = ur_template_string(tmplt);
890  if (tmplt_str == NULL) {
891  if (errstr != NULL) {
892  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
893  if (*errstr != NULL) {
894  strcpy(*errstr, UR_MEMORY_ERROR);
895  }
896  }
897  ur_free_template(tmplt);
898  return NULL;
899  }
900  trap_ctx_set_required_fmt(ctx, ifc_in, TRAP_FMT_UNIREC, tmplt_str);
901  trap_ctx_set_data_fmt(ctx, ifc_out, TRAP_FMT_UNIREC, tmplt_str);
902  free(tmplt_str);
903  return tmplt;
904 }
905 
906 ur_template_t *ur_create_template(const char *fields, char **errstr)
907 {
908  // Count number of fields
909  int n_fields = 0, written_fields = 0;
910  if (fields) {
911  /* skip leading spaces */
912  while (*fields != '\0' && isspace(*fields)) {
913  fields++;
914  }
915  /* Count number of fields */
916  if (*fields != '\0') {
917  n_fields = 1;
918  const char *tmp = fields;
919  while (*tmp != '\0') {
920  if (*(tmp++) == ',') {
921  n_fields++;
922  }
923  }
924  }
925  }
926  // Allocate array of field_spec structs
927  field_spec_t *fields_spec = malloc(n_fields * sizeof(field_spec_t));
928  if (fields_spec == NULL && n_fields > 0) {
929  if (errstr != NULL) {
930  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
931  if (*errstr != NULL) {
932  strcpy(*errstr, UR_MEMORY_ERROR);
933  }
934  }
935  return NULL;
936  }
937  // Parse fields and fill the array
938  const char *start_ptr = fields;
939  const char *end_ptr;
940  for (int i = 0; i < n_fields; i++) {
941  // Get field name
942  end_ptr = start_ptr;
943  /* go to the first space / comma / end-of-string */
944  while (!isspace(*end_ptr) && *end_ptr != ',' && *end_ptr != '\0') {
945  end_ptr++;
946  }
947  int len = end_ptr - start_ptr;
948  fields_spec[written_fields].name = malloc(len + 1);
949  if (fields_spec[written_fields].name == NULL) {
950  if (errstr != NULL) {
951  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
952  if (*errstr != NULL) {
953  strcpy(*errstr, UR_MEMORY_ERROR);
954  }
955  }
956  for (int j = 0; j < i; j++) {
957  free(fields_spec[j].name);
958  }
959  free(fields_spec);
960  return NULL;
961  }
962  memcpy(fields_spec[written_fields].name, start_ptr, len);
963  fields_spec[written_fields].name[len] = 0;
964  start_ptr = end_ptr;
965  while ((isspace(*start_ptr) || *start_ptr == ',') && *start_ptr != '\0') {
966  start_ptr++;
967  }
968  // Get field ID
969  int id_by_name = ur_get_id_by_name(fields_spec[written_fields].name);
970  if (id_by_name == UR_E_INVALID_NAME) {
971  // Unknown field name
972  if (errstr != NULL) {
973  *errstr = (char *) malloc(100);
974  if (*errstr != NULL) {
975  int n;
976  n = snprintf(*errstr, 100, "field: %s is not defined.", fields_spec[written_fields].name);
977  if (n >= 100) {
978  strcpy(*errstr, "given field is not defined");
979  }
980  }
981  }
982  for (int j = 0; j <= written_fields; j++) {
983  free(fields_spec[j].name);
984  }
985  free(fields_spec);
986  return NULL;
987  }
988  //check if the field is not in the template.
989  int in_the_template = 0;
990  for (int j = 0; j < written_fields; j++) {
991  if (fields_spec[j].id == id_by_name) {
992  in_the_template = 1;
993  break;
994  }
995  }
996  //if the field is not already int the template, copy values and move the index, otherwise just free the string with name.
997  if (in_the_template == 0) {
998  fields_spec[written_fields].id = id_by_name;
999  // Get field size
1000  fields_spec[written_fields].size = ur_get_size(fields_spec[written_fields].id);
1001  written_fields++;
1002  } else {
1003  free(fields_spec[written_fields].name);
1004  fields_spec[written_fields].name = NULL;
1005  }
1006  }
1007  // Sort fields according to UniRec specification (by size and names)
1008  if (n_fields > 0) {
1009  qsort(fields_spec, written_fields, sizeof(field_spec_t), compare_fields);
1010  }
1011  // Allocate memory for the template
1012  ur_template_t *tmplt = (ur_template_t *) calloc(sizeof(ur_template_t), 1);
1013  if (tmplt == NULL) {
1014  for (int i = 0; i < written_fields; i++) {
1015  free(fields_spec[i].name);
1016  }
1017  free(fields_spec);
1018  if (errstr != NULL) {
1019  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
1020  if (*errstr != NULL) {
1021  strcpy(*errstr, UR_MEMORY_ERROR);
1022  }
1023  }
1024  return NULL;
1025  }
1026  //set no direction to the template
1028  //allocate memory for offset table
1030  tmplt->offset = malloc(ur_field_specs.ur_last_id * sizeof(uint16_t));
1031  if (tmplt->offset == NULL) {
1032  for (int i = 0; i < written_fields; i++) {
1033  free(fields_spec[i].name);
1034  }
1035  free(fields_spec);
1036  free(tmplt);
1037  if (errstr != NULL) {
1038  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
1039  if (*errstr != NULL) {
1040  strcpy(*errstr, UR_MEMORY_ERROR);
1041  }
1042  }
1043  return NULL;
1044  }
1045  // Set all fields to invalid offset
1046  memset(tmplt->offset, 0xff, ur_field_specs.ur_last_id * sizeof(uint16_t));
1047  // Fill offsets of all fields into the table
1048  uint16_t offset = 0;
1049  uint16_t first_dynamic = UR_NO_DYNAMIC_VALUES;
1050  for (int i = 0; i < written_fields; i++) {
1051  // Set offset
1052  if (fields_spec[i].size < 0) { // dynamic field
1053  tmplt->offset[fields_spec[i].id] = offset;
1054  offset += 4;
1055  if (first_dynamic == UR_NO_DYNAMIC_VALUES) {
1056  first_dynamic = i;
1057  }
1058  } else { // static field
1059  tmplt->offset[fields_spec[i].id] = offset;
1060  offset += fields_spec[i].size;
1061  }
1062  }
1063  tmplt->first_dynamic = first_dynamic;
1064  tmplt->static_size = offset;
1065 
1066  //save ids to template
1067  tmplt->ids = (ur_field_id_t *) malloc(sizeof(ur_field_id_t) * written_fields);
1068  if (tmplt->ids == NULL) {
1069  for (int i = 0; i < written_fields; i++) {
1070  free(fields_spec[i].name);
1071  }
1072  free(fields_spec);
1073  free(tmplt);
1074  if (errstr != NULL) {
1075  *errstr = (char *) malloc(strlen(UR_MEMORY_ERROR) + 1);
1076  if (*errstr != NULL) {
1077  strcpy(*errstr, UR_MEMORY_ERROR);
1078  }
1079  }
1080  return NULL;
1081  }
1082  tmplt->count = written_fields;
1083  for (int i = 0; i < written_fields; i++) {
1084  tmplt->ids[i] = fields_spec[i].id;
1085  }
1086  // Free array of field specs
1087  for (int i = 0; i < written_fields; i++) {
1088  free(fields_spec[i].name);
1089  }
1090  free(fields_spec);
1091  return tmplt;
1092 }
1093 
1095  if (tmplt == NULL) {
1096  return;
1097  }
1098  //free offset table
1099  if (tmplt->offset != NULL) {
1100  free(tmplt->offset);
1101  }
1102  //free ids
1103  if (tmplt->ids != NULL) {
1104  free(tmplt->ids);
1105  }
1106  free(tmplt);
1107 }
1108 
1109 // Compare fields of two templates
1110 int ur_template_compare(const ur_template_t *tmpltA, const ur_template_t *tmpltB)
1111 {
1112  if (tmpltA->count == tmpltB->count) {
1113  return memcmp(tmpltA->ids, tmpltB->ids, sizeof(uint16_t) * tmpltA->count) == 0;
1114  } else {
1115  return 0;
1116  }
1117 }
1118 
1119 
1120 // Print template
1122 {
1123  printf("static_size: %hu, first_dynamic: ", tmplt->static_size);
1124  (tmplt->first_dynamic == UR_NO_DYNAMIC_VALUES) ? (printf("-")) : (printf("%d", tmplt->ids[tmplt->first_dynamic]));
1125  printf(", offsets:\n"
1126  "ID\t%-30s\toffset\n","name");
1127  for (int i = 0; i < tmplt->count; i++) {
1128  printf("%d\t%-30s\t%6hu\n", tmplt->ids[i], ur_field_specs.ur_field_names[tmplt->ids[i]], tmplt->offset[tmplt->ids[i]]);
1129  }
1130 }
1131 
1132 void ur_var_change_size(const ur_template_t *tmplt, void *rec, int field_id, int new_val_len)
1133 {
1134  // pointer to field and size of a field
1135  char *out_ptr = ur_get_ptr_by_id(tmplt, rec, field_id);
1136  int old_size_of_field = ur_get_len(tmplt, rec, field_id);
1137  //if the size is different, move following fields
1138  if (old_size_of_field != new_val_len) {
1139  uint16_t size = new_val_len;
1140  uint16_t offset_static = ur_get_var_offset(tmplt, rec, field_id);
1141  int index = 0;
1142  //find index of changed field in record array
1143  for (int i = 0; i< tmplt->count; i++) {
1144  if (field_id == tmplt->ids[i]) {
1145  index = i;
1146  }
1147  }
1148  //set new offset for dynamic fields which are situated behind changed field
1149  for (int i = index + 1; i < tmplt->count; i++) {
1150  ur_set_var_offset(tmplt, rec, tmplt->ids[i], offset_static + size);
1151  size += ur_get_len(tmplt, rec, tmplt->ids[i]);
1152  }
1153  memmove(out_ptr + new_val_len, out_ptr + old_size_of_field, size - new_val_len);
1154  ur_set_var_len(tmplt, rec, field_id, new_val_len);
1155  }
1156 }
1157 
1158 int ur_set_var(const ur_template_t *tmplt, void *rec, int field_id, const void *val_ptr, int val_len)
1159 {
1160  if (tmplt->offset[field_id] == UR_INVALID_OFFSET) {
1161  return UR_E_INVALID_FIELD_ID;
1162  }
1163  // wrong parameters or template does not contain dynamic fields
1164  if (tmplt->first_dynamic == UR_NO_DYNAMIC_VALUES || ur_is_static(field_id)) {
1165  return UR_E_INVALID_FIELD_ID;
1166  }
1167  // pointer to field and size of a field
1168  char * out_ptr = ur_get_ptr_by_id(tmplt, rec, field_id);
1169  //change size of a variable length field
1170  ur_var_change_size(tmplt, rec, field_id, val_len);
1171  //copy new value
1172  memcpy(out_ptr, val_ptr, val_len);
1173  return UR_OK;
1174 }
1175 
1176 int ur_array_resize(const ur_template_t *tmplt, void *rec, int field_id, int len)
1177 {
1178  if (tmplt->offset[field_id] == UR_INVALID_OFFSET) {
1179  return UR_E_INVALID_FIELD_ID;
1180  }
1181  // wrong parameters or template does not contain dynamic fields
1182  if (tmplt->first_dynamic == UR_NO_DYNAMIC_VALUES || ur_is_static(field_id)) {
1183  return UR_E_INVALID_FIELD_ID;
1184  }
1185  //change size of a variable length field
1186  ur_var_change_size(tmplt, rec, field_id, len);
1187  return UR_OK;
1188 }
1189 
1190 char *ur_array_append_get_ptr(const ur_template_t *tmplt, void *rec, int field_id)
1191 {
1192  int elem_cnt = ur_array_get_elem_cnt(tmplt, rec, field_id);
1193  int elem_size = ur_array_get_elem_size(field_id);
1194  if (ur_array_resize(tmplt, rec, field_id, (elem_cnt + 1) * elem_size) == UR_OK) {
1195  return (char *) ur_get_ptr_by_id(tmplt, rec, field_id) + elem_cnt * elem_size;
1196  } else {
1197  return NULL;
1198  }
1199 }
1200 
1201 void ur_clear_varlen(const ur_template_t * tmplt, void *rec)
1202 {
1203  //set null offset and length for all dynamic fields
1204  for (int i = tmplt->first_dynamic; i < tmplt->count; i++) {
1205  ur_set_var_offset(tmplt, rec, tmplt->ids[i], 0);
1206  ur_set_var_len(tmplt, rec, tmplt->ids[i], 0);
1207  }
1208 }
1209 
1210 uint16_t ur_rec_varlen_size(const ur_template_t *tmplt, const void *rec)
1211 {
1212  int size = 0;
1213  for (int i = tmplt->first_dynamic; i < tmplt->count; i++) {
1214  size += ur_get_var_len(tmplt, rec, tmplt->ids[i]);
1215  }
1216  return size;
1217 }
1218 
1219 // Allocate memory for UniRec record
1220 void *ur_create_record(const ur_template_t *tmplt, uint16_t max_var_size)
1221 {
1222  unsigned int size = (unsigned int)tmplt->static_size + max_var_size;
1223  if (size > UR_MAX_SIZE)
1224  size = UR_MAX_SIZE;
1225  return (void *) calloc(size, 1);
1226 }
1227 
1228 // Free UniRec record
1229 void ur_free_record(void *record)
1230 {
1231  free(record);
1232 }
1233 
1234 // Get dynamic field as C string (allocate, copy and append '\0')
1235 char *ur_get_var_as_str(const ur_template_t *tmplt, const void *rec, ur_field_id_t field_id)
1236 {
1237  uint16_t size = ur_get_var_len(tmplt, rec, field_id);
1238  char *str = malloc(size + 1);
1239  if (str == NULL)
1240  return NULL;
1241  if (size > 0) {
1242  const char *p = ur_get_ptr_by_id(tmplt, rec, field_id);
1243  memcpy(str, p, size);
1244  }
1245  str[size] = '\0';
1246  return str;
1247 }
1248 
1249 inline void *ur_clone_record(const ur_template_t *tmplt, const void *src)
1250 {
1251  uint16_t varsize = ur_rec_varlen_size(tmplt, src);
1252  void *copy = ur_create_record(tmplt, varsize);
1253  if (copy) {
1254  memcpy(copy, src, ur_rec_fixlen_size(tmplt) + varsize);
1255  }
1256  return copy;
1257 }
1258 
1259 void ur_copy_fields(const ur_template_t *dst_tmplt, void *dst, const ur_template_t *src_tmplt, const void *src)
1260 {
1261  int size_of_field = 0;
1262  void * ptr_dst = NULL;
1263  void * ptr_src = NULL;
1264  uint16_t size = src_tmplt->offset_size < dst_tmplt->offset_size ? src_tmplt->offset_size : dst_tmplt->offset_size;
1265  //Fields with same template can be copied by fully by memcpy
1266  if (src_tmplt == dst_tmplt) {
1267  memcpy(dst, src, ur_rec_size(src_tmplt, src));
1268  return;
1269 
1270  }
1271  // minimal value from offset table size
1272  for (int i = 0; i < size; i++) {
1273  // if two templates have the same field
1274  if (src_tmplt->offset[i] != UR_INVALID_OFFSET && dst_tmplt->offset[i] != UR_INVALID_OFFSET) {
1275  size_of_field = ur_get_size(i);
1276  if (size_of_field > 0) {
1277  // static fields
1278  ptr_dst = ur_get_ptr_by_id(dst_tmplt, dst, i);
1279  ptr_src = ur_get_ptr_by_id(src_tmplt, src, i);
1280  memcpy(ptr_dst, ptr_src, size_of_field);
1281  } else {
1282  // variable-size fields
1283  ptr_src = ur_get_ptr_by_id(src_tmplt, src, i);
1284  size_of_field = ur_get_var_len(src_tmplt, src, i);
1285  ur_set_var(dst_tmplt, dst, i, ptr_src, size_of_field);
1286  }
1287  }
1288  }
1289 }
1290 
1291 // Function for iterating over all fields in a given template
1293 {
1294  // Set first ID to check
1295  if (id == UR_ITER_BEGIN) {
1296  id = 0;
1297  } else {
1298  id++;
1299  }
1300  // Find first ID which is present in the template
1301  while (id < tmplt->offset_size) {
1302  if (tmplt->offset[id] != UR_INVALID_OFFSET) {
1303  return id;
1304  }
1305  id++;
1306  }
1307  return UR_ITER_END;
1308 }
1309 
1310 // Function for iterating over all fields in a given template. Fields are in the same
1311 // order like in record
1313 {
1314  // Set first ID to check
1315  if (index >= tmplt->count || index < 0) {
1316  return UR_ITER_END;
1317  }
1318  return tmplt->ids[index];
1319 }
1320 
1321 int ur_set_array_from_string(const ur_template_t *tmpl, void *data, ur_field_id_t f_id, const char *v)
1322 {
1323  ip_addr_t addr;
1324  mac_addr_t macaddr;
1325  int rv = 0;
1326  ur_time_t urtime = 0;
1327  void *ptr = ur_get_ptr_by_id(tmpl, data, f_id);
1328  int elems_parsed = 0;
1329  int elems_allocated = UR_ARRAY_ALLOC;
1330  const char *scan_format = NULL;
1331  const int element_size = ur_array_get_elem_size(f_id);
1332 
1333  if (ur_is_present(tmpl, f_id) == 0 || !ur_is_array(f_id)) {
1334  return 1;
1335  }
1336  if (ur_array_allocate(tmpl, data, f_id, elems_allocated) != UR_OK) {
1337  return 1;
1338  }
1339  while (v && *v == UR_ARRAY_DELIMITER) {
1340  v++; // Skip the delimiter, move to beginning of the next value
1341  }
1342  switch (ur_get_type(f_id)) {
1343  case UR_TYPE_A_UINT8:
1344  scan_format = "%" SCNu8;
1345  break;
1346  case UR_TYPE_A_UINT16:
1347  scan_format = "%" SCNu16;
1348  break;
1349  case UR_TYPE_A_UINT32:
1350  scan_format = "%" SCNu32;
1351  break;
1352  case UR_TYPE_A_UINT64:
1353  scan_format = "%" SCNu64;
1354  break;
1355  case UR_TYPE_A_INT8:
1356  scan_format = "%" SCNi8;
1357  break;
1358  case UR_TYPE_A_INT16:
1359  scan_format = "%" SCNi16;
1360  break;
1361  case UR_TYPE_A_INT32:
1362  scan_format = "%" SCNi32;
1363  break;
1364  case UR_TYPE_A_INT64:
1365  scan_format = "%" SCNi64;
1366  break;
1367  case UR_TYPE_A_FLOAT:
1368  scan_format = "%f";
1369  break;
1370  case UR_TYPE_A_DOUBLE:
1371  scan_format = "%lf";
1372  break;
1373  case UR_TYPE_A_IP:
1374  // IP address - convert to human-readable format
1375  while (v && *v) {
1376  char tmp[64];
1377  const char *ip = tmp;
1378  char *end;
1379  end = strchr(v, UR_ARRAY_DELIMITER);
1380  if (end == NULL) {
1381  ip = v;
1382  if (*v == 0) {
1383  break;
1384  }
1385  } else {
1386  memcpy(tmp, v, end - v);
1387  tmp[end - v] = 0;
1388  }
1389  v = end;
1390  if (ip_from_str(ip, &addr) == 0) {
1391  rv = 1;
1392  break;
1393  }
1394  ((ip_addr_t *) ptr)[elems_parsed] = addr;
1395  elems_parsed++;
1396  if (elems_parsed >= elems_allocated) {
1397  elems_allocated += UR_ARRAY_ALLOC;
1398  if (ur_array_allocate(tmpl, data, f_id, elems_allocated) != UR_OK) {
1399  return 1;
1400  }
1401  }
1402  while (v && *v == UR_ARRAY_DELIMITER) {
1403  v++; // Skip the delimiter, move to beginning of the next value
1404  }
1405  }
1406  break;
1407  case UR_TYPE_A_MAC:
1408  // MAC address - convert to human-readable format
1409  while (v && *v) {
1410  if (mac_from_str(v, &macaddr) == 0) {
1411  rv = 1;
1412  break;
1413  }
1414  ((mac_addr_t *) ptr)[elems_parsed] = macaddr;
1415  elems_parsed++;
1416  if (elems_parsed >= elems_allocated) {
1417  elems_allocated += UR_ARRAY_ALLOC;
1418  if (ur_array_allocate(tmpl, data, f_id, elems_allocated) != UR_OK) {
1419  return 1;
1420  }
1421  }
1422  v = strchr(v, UR_ARRAY_DELIMITER);
1423  while (v && *v == UR_ARRAY_DELIMITER) {
1424  v++; // Skip the delimiter, move to beginning of the next value
1425  }
1426  }
1427  break;
1428  case UR_TYPE_A_TIME:
1429  // Timestamp - convert from human-readable format
1430  while (v && *v) {
1431  char tmp[64];
1432  const char *time = tmp;
1433  char *end;
1434  end = strchr(v, UR_ARRAY_DELIMITER);
1435  if (end == NULL) {
1436  time = v;
1437  if (*v == 0) {
1438  break;
1439  }
1440  } else {
1441  memcpy(tmp, v, end - v);
1442  tmp[end - v] = 0;
1443  }
1444  if (ur_time_from_string(&urtime, time) != 0) {
1445  rv = 1;
1446  break;
1447  }
1448  ((ur_time_t *) ptr)[elems_parsed] = urtime;
1449  elems_parsed++;
1450  if (elems_parsed >= elems_allocated) {
1451  elems_allocated += UR_ARRAY_ALLOC;
1452  if (ur_array_allocate(tmpl, data, f_id, elems_allocated) != UR_OK) {
1453  return 1;
1454  }
1455  }
1456  v = strchr(v, UR_ARRAY_DELIMITER);
1457  while (v && *v == UR_ARRAY_DELIMITER) {
1458  v++; // Skip the delimiter, move to beginning of the next value
1459  }
1460  }
1461  break;
1462  default:
1463  fprintf(stderr, "Unsupported UniRec field type, skipping.\n");
1464  ur_array_allocate(tmpl, data, f_id, 0);
1465  break;
1466  }
1467 
1468  if (scan_format != NULL) {
1469  while (v && *v) {
1470  if (sscanf(v, scan_format, (void *) ((char*) ptr + elems_parsed * element_size)) != 1) {
1471  rv = 1;
1472  break;
1473  }
1474  elems_parsed++;
1475  if (elems_parsed >= elems_allocated) {
1476  elems_allocated += UR_ARRAY_ALLOC;
1477  if (ur_array_allocate(tmpl, data, f_id, elems_allocated) != UR_OK) {
1478  return 1;
1479  }
1480  }
1481  v = strchr(v, UR_ARRAY_DELIMITER);
1482  while (v && *v == UR_ARRAY_DELIMITER) {
1483  v++; // Skip the delimiter, move to beginning of the next value
1484  }
1485  }
1486  }
1487 
1488  if (elems_allocated > elems_parsed) {
1489  ur_array_allocate(tmpl, data, f_id, elems_parsed);
1490  }
1491  return rv;
1492 }
1493 int ur_set_from_string(const ur_template_t *tmpl, void *data, ur_field_id_t f_id, const char *v)
1494 {
1495  ip_addr_t *addr_p = NULL, addr;
1496  mac_addr_t *macaddr_p = NULL, macaddr;
1497  int rv = 0;
1498  ur_time_t urtime = 0;
1499  void *ptr = ur_get_ptr_by_id(tmpl, data, f_id);
1500 
1501  if (ur_is_present(tmpl, f_id) == 0) {
1502  return 1;
1503  }
1504  switch (ur_get_type(f_id)) {
1505  case UR_TYPE_UINT8:
1506  if (sscanf(v, "%" SCNu8, (uint8_t *) ptr) != 1) {
1507  rv = 1;
1508  }
1509  break;
1510  case UR_TYPE_UINT16:
1511  if (sscanf(v, "%" SCNu16 , (uint16_t *) ptr) != 1) {
1512  rv = 1;
1513  }
1514  break;
1515  case UR_TYPE_UINT32:
1516  if (sscanf(v, "%" SCNu32, (uint32_t *) ptr) != 1) {
1517  rv = 1;
1518  }
1519  break;
1520  case UR_TYPE_UINT64:
1521  if (sscanf(v, "%" SCNu64, (uint64_t *) ptr) != 1) {
1522  rv = 1;
1523  }
1524  break;
1525  case UR_TYPE_INT8:
1526  if (sscanf(v, "%" SCNi8, (int8_t *) ptr) != 1) {
1527  rv = 1;
1528  }
1529  break;
1530  case UR_TYPE_INT16:
1531  if (sscanf(v, "%" SCNi16, (int16_t *) ptr) != 1) {
1532  rv = 1;
1533  }
1534  break;
1535  case UR_TYPE_INT32:
1536  if (sscanf(v, "%" SCNi32, (int32_t *) ptr) != 1) {
1537  rv = 1;
1538  }
1539  break;
1540  case UR_TYPE_INT64:
1541  if (sscanf(v, "%" SCNi64, (int64_t *) ptr) != 1) {
1542  rv = 1;
1543  }
1544  break;
1545  case UR_TYPE_CHAR:
1546  if (sscanf(v, "%c", (char *) ptr) != 1) {
1547  rv = 1;
1548  }
1549  break;
1550  case UR_TYPE_FLOAT:
1551  if (sscanf(v, "%f", (float *) ptr) != 1) {
1552  rv = 1;
1553  }
1554  break;
1555  case UR_TYPE_DOUBLE:
1556  if (sscanf(v, "%lf", (double *) ptr) != 1) {
1557  rv = 1;
1558  }
1559  break;
1560  case UR_TYPE_IP:
1561  // IP address - convert to human-readable format
1562  if (ip_from_str(v, &addr) == 0) {
1563  rv = 1;
1564  break;
1565  }
1566  addr_p = (ip_addr_t *) ptr;
1567  (*addr_p) = addr;
1568  break;
1569  case UR_TYPE_MAC:
1570  // MAC address - convert to human-readable format
1571  if (mac_from_str(v, &macaddr) == 0) {
1572  rv = 1;
1573  break;
1574  }
1575  macaddr_p = (mac_addr_t *) ptr;
1576  (*macaddr_p) = macaddr;
1577  break;
1578  case UR_TYPE_TIME:
1579  // Timestamp - convert from human-readable format
1580  if (ur_time_from_string(&urtime, v) != 0) {
1581  fprintf(stderr, "Failed to parse time.\n");
1582  }
1583  (*(ur_time_t *) ptr) = urtime;
1584  break;
1585  case UR_TYPE_STRING:
1586  // Printable string
1587  ur_set_var(tmpl, data, f_id, v, strlen(v));
1588  break;
1589  case UR_TYPE_BYTES:
1590  {
1591  // Generic string of bytes
1592  int size = strlen(v)/2;
1593  ur_var_change_size(tmpl, data, f_id, size);
1594  unsigned char *data_ptr = ur_get_ptr_by_id(tmpl, data, f_id);
1595  for ( ; size > 0; --size, v += 2, ++data_ptr) {
1596  if (sscanf(v, "%2hhx", data_ptr) != 1) {
1597  rv = 1;
1598  }
1599  }
1600  }
1601  break;
1602  default:
1603  if (ur_is_array(f_id)) {
1604  return ur_set_array_from_string(tmpl, data, f_id, v);
1605  }
1606  fprintf(stderr, "Unsupported UniRec field type, skipping.\n");
1607  break;
1608  }
1609  return rv;
1610 }
1611 
1612 uint8_t ur_time_from_string(ur_time_t *ur, const char *str)
1613 {
1614  struct tm t;
1615  time_t sec = -1;
1616  uint64_t nsec = 0;
1617  char *res = NULL;
1618 
1619  if (ur == NULL || str == NULL) {
1620  return 2;
1621  }
1622 
1623  res = strptime(str, "%Y-%m-%dT%T", &t);
1624  /* parsed to sec - msec delimiter */
1625  if ((res != NULL) && ((*res == '.') || (*res == 0) || (*res == 'z') || (*res == 'Z'))) {
1626  sec = timegm(&t);
1627  if (sec != -1) {
1628  if (*res != 0 && *++res != 0) {
1629  char frac_buffer[10];
1630  memset(frac_buffer, '0', 9);
1631  frac_buffer[9] = 0;
1632 
1633  // now "res" points to the beginning of the fractional part or 'Z' for UTC timezone,
1634  // which have at least one char.
1635  // Expand the number by zeros to the right to get it in ns
1636  // (if there are more than 9 digits, truncate the rest)
1637  size_t frac_len = strlen(res);
1638  if (frac_len > 0 && (res[frac_len - 1] == 'z' || res[frac_len - 1] == 'Z')) {
1639  frac_len--;
1640  }
1641  if (frac_len > 9) {
1642  frac_len = 9;
1643  }
1644  memcpy(frac_buffer, res, frac_len);
1645  nsec = strtoul(frac_buffer, NULL, 10); // returns 0 on error - that's OK
1646  }
1647  *ur = ur_time_from_sec_nsec((uint64_t) sec, nsec);
1648  } else {
1649  goto failed_time_parsing;
1650  }
1651  /* success */
1652  return 0;
1653  } else {
1654 failed_time_parsing:
1655  *ur = (ur_time_t) 0;
1656  /* parsing error */
1657  return 1;
1658  }
1659 }
1660 
1661 char *ur_cpy_string(const char *str)
1662 {
1663  int str_len = strlen(str) + 1;
1664  char *new_str = malloc(sizeof(char) * str_len);
1665  if (new_str == NULL) {
1666  return NULL;
1667  }
1668  memcpy(new_str, str, str_len);
1669  return new_str;
1670 }
1671 
1672 const char *ur_values_get_name_start_end(uint32_t start, uint32_t end, int32_t value)
1673 {
1674  for (int i = start; i < end; i++) {
1675  if (ur_values[i].value == value) {
1676  return ur_values[i].name;
1677  }
1678  }
1679  return NULL;
1680 }
1681 
1682 const char *ur_values_get_description_start_end(uint32_t start, uint32_t end, int32_t value)
1683 {
1684  for (int i = start; i < end; i++) {
1685  if (ur_values[i].value == value) {
1686  return ur_values[i].description;
1687  }
1688  }
1689  return NULL;
1690 }
1691 // *****************************************************************************
1692 // ** "Links" part - set of functions for handling LINK_BIT_FIELD
1693 
1694 // Create and initialize links structure.
1695 ur_links_t *ur_create_links(const char *mask)
1696 {
1697  uint64_t checker;
1698  unsigned int indexer;
1699  ur_links_t *lm;
1700 
1701  // Allocate memory for structure.
1702  lm = (ur_links_t *) malloc(sizeof(ur_links_t));
1703  if (lm == NULL) {
1704  return NULL;
1705  }
1706 
1707  // Try to convert passed mask in string to uint64_t.
1708  if (sscanf(mask, "%"SCNx64, &lm->link_mask) < 1) {
1709  free(lm);
1710  return NULL;
1711  }
1712 
1713  // Get link count.
1714  lm->link_count = 0;
1715  checker = 1;
1716  for (int i = 0; i < MAX_LINK_COUNT; ++i) {
1717  if (lm->link_mask & checker) {
1718  lm->link_count++;
1719  }
1720  checker <<= 1;
1721  }
1722  if (lm->link_count == 0) {
1723  free(lm);
1724  return NULL;
1725  }
1726  // Allocate array for link indexes
1727  lm->link_indexes = (uint64_t *) malloc(lm->link_count * sizeof(uint64_t));
1728  if (lm->link_indexes == NULL) {
1729  free(lm);
1730  return NULL;
1731  }
1732 
1733  // Fill link indexes
1734  indexer = 0;
1735  checker = 1;
1736  for (int i = 0; i < MAX_LINK_COUNT; ++i) {
1737  if (lm->link_mask & checker) {
1738  lm->link_indexes[indexer++] = i;
1739  }
1740  checker <<= 1;
1741  }
1742 
1743  return lm;
1744 }
1745 
1746 // Destroy links structure.
1748 {
1749  if (links != NULL) {
1750  free(links->link_indexes);
1751  free(links);
1752  }
1753 }
1754 // Following functions are defined in links.h
1755 // (their headers are repeated here with INLINE_IMPL to generate externally
1756 // linkable code)
1757 
1758 // Get index of link (0 - (link_count-1))
1759 INLINE_IMPL int ur_get_link_index(ur_links_t *links, uint64_t link_bit_field);
1760 
1761 // Get position in link_bit_field of link
1762 INLINE_IMPL uint64_t ur_get_link_bit_field_position(ur_links_t *links, unsigned int index);
1763 
1764 // Get link mask.
1765 INLINE_IMPL uint64_t ur_get_link_mask(ur_links_t *links);
1766 
1767 // Get link count.
1768 INLINE_IMPL unsigned int ur_get_link_count(ur_links_t *links);
1769 
1770 // END OF "Links" part *********************************************************
1771 // *****************************************************************************
1772 
INLINE_IMPL ip_addr_t ip_from_16_bytes_be(const char b[16])
Definition: ipaddr.h:236
INLINE_IMPL void ip_to_str(const ip_addr_t *addr, char *str)
Definition: ipaddr.h:325
INLINE_IMPL ip_addr_t ip_from_4_bytes_le(const char b[4])
Definition: ipaddr.h:218
INLINE_IMPL int ip_cmp(const ip_addr_t *addr1, const ip_addr_t *addr2)
Definition: ipaddr.h:266
INLINE_IMPL ip_addr_t ip_from_16_bytes_le(const char b[16])
Definition: ipaddr.h:249
INLINE_IMPL int ip_is4(const ip_addr_t *addr)
Definition: ipaddr.h:131
INLINE_IMPL char * ip_get_v4_as_bytes(const ip_addr_t *addr)
Definition: ipaddr.h:171
INLINE_IMPL ip_addr_t ip_from_int(uint32_t i)
Definition: ipaddr.h:183
INLINE_IMPL int ip_from_str(const char *str, ip_addr_t *addr)
Definition: ipaddr.h:301
INLINE_IMPL int ip_is6(const ip_addr_t *addr)
Definition: ipaddr.h:143
INLINE_IMPL uint32_t ip_get_v4_as_int(const ip_addr_t *addr)
Definition: ipaddr.h:157
INLINE_IMPL ip_addr_t ip_from_4_bytes_be(const char b[4])
Definition: ipaddr.h:199
int ur_undefine_field_by_id(ur_field_id_t field_id)
Undefine UniRec field by its id Undefine UniRec field created at run-time. It erases given field from...
Definition: unirec.c:701
void ur_print_template(ur_template_t *tmplt)
Print UniRec template Print static_size, first_dynamic and table of offsets to stdout (for debugging)...
Definition: unirec.c:1121
char * ur_cpy_string(const char *str)
Duplicates given string. Helper function which returns pointer to duplicated string....
Definition: unirec.c:1661
#define ur_rec_fixlen_size(tmplt)
Get size of fixed-length part of UniRec record Get total size of UniRec record except variable-length...
Definition: unirec.h:671
#define ur_set_var_offset(tmplt, rec, field_id, offset_val)
Set offset of variable-length field in the record. Set offset of specified variable-length field in t...
Definition: unirec.h:496
void ur_clear_varlen(const ur_template_t *tmplt, void *rec)
Clear variable-length part of a record. For better performance of setting content to variable-length ...
Definition: unirec.c:1201
int ur_init(ur_static_field_specs_t field_specs_static)
Initialize UniRec structures Initialize UniRec structures. Function is called during defining first o...
Definition: unirec.c:210
const char * ur_values_get_description_start_end(uint32_t start, uint32_t end, int32_t value)
Returns description of specified value (Helper function) Helper function for ur_values_get_descriptio...
Definition: unirec.c:1682
const char * ur_field_type_str[]
UniRec data types.
Definition: unirec.c:137
char * ur_ifc_data_fmt_to_field_names(const char *ifc_data_fmt)
Parses field names from data format Function parses field names from data format and returns pointer ...
Definition: unirec.c:438
int ur_undefine_field(const char *name)
Undefine UniRec field by its name Undefine UniRec field created at run-time. It erases given field fr...
Definition: unirec.c:726
ur_template_t * ur_define_fields_and_update_template(const char *ifc_data_fmt, ur_template_t *tmplt)
Defined new fields and expand an UniRec template Define new fields (function ur_define_set_of_fields)...
Definition: unirec.c:616
uint16_t ur_rec_varlen_size(const ur_template_t *tmplt, const void *rec)
Get size of variable sized part of UniRec record Get total size of all variable-length fields in an U...
Definition: unirec.c:1210
ur_template_t * ur_ctx_create_bidirectional_template(trap_ctx_t *ctx, int ifc_in, int ifc_out, const char *fields, char **errstr)
Create UniRec template and set it to input and output interface on specified context Creates UniRec t...
Definition: unirec.c:881
#define ur_array_allocate(tmplt, rec, field_id, elem_cnt)
Preallocates UniRec array field to have requested number of elements.
Definition: unirec.h:629
int ur_array_resize(const ur_template_t *tmplt, void *rec, int field_id, int len)
Change length of a array field.
Definition: unirec.c:1176
#define ur_is_array(field_id)
Definition: unirec.h:526
#define ur_get_var_offset(tmplt, rec, field_id)
Get offset of variable-length field in the record. Get offset of a specified variable-length field in...
Definition: unirec.h:464
ur_static_field_specs_t UR_FIELD_SPECS_STATIC
Structure that lists staticaly defined UniRec field specifications such as names, types,...
Definition: unirec.c:206
void ur_free_template(ur_template_t *tmplt)
Destroy UniRec template Free all memory allocated for a template created previously by ur_create_temp...
Definition: unirec.c:1094
#define ur_rec_size(tmplt, rec)
Get size of UniRec record (static and variable length) Get total size of whole UniRec record.
Definition: unirec.h:680
char * ur_array_append_get_ptr(const ur_template_t *tmplt, void *rec, int field_id)
Allocate new element at the end of array and return its pointer.
Definition: unirec.c:1190
#define ur_get_size(field_id)
Get size of UniRec field Get size of a fixed-length UniRec field. When variable-length field is passe...
Definition: unirec.h:405
void ur_finalize()
Deallocate UniRec structures Deallocate UniRec structures at the end of a program....
Definition: unirec.c:740
#define ur_template_string(tmplt)
Get string of a template Get names and sizes of fields separated by comma. Return string has to be fr...
Definition: unirec.h:364
void * ur_create_record(const ur_template_t *tmplt, uint16_t max_var_size)
Definition: unirec.c:1220
const int ur_field_type_size[]
Sizes of UniRec data types.
Definition: unirec.c:98
#define UR_MAX_SIZE
Definition: unirec.h:1013
ur_iter_t ur_iter_fields_record_order(const ur_template_t *tmplt, int index)
Iterate over fields of a template This function can be used to iterate over all fields of a given tem...
Definition: unirec.c:1312
char * ur_get_var_as_str(const ur_template_t *tmplt, const void *rec, ur_field_id_t field_id)
Get variable-length UniRec field as a C string Copy data of a variable-length field from UniRec recor...
Definition: unirec.c:1235
ur_field_specs_t ur_field_specs
Structure that lists UniRec field specifications such as names, types, id.
Definition: unirec.c:205
int ur_get_empty_id()
Return first empty id for new UniRec field Return first empty id for new UniRec field....
Definition: unirec.c:292
int ur_ctx_set_input_template(trap_ctx_t *ctx, int ifc, ur_template_t *tmplt)
Set UniRec template to input interface on specified context.
Definition: unirec.c:862
int ur_ctx_set_output_template(trap_ctx_t *ctx, int ifc, ur_template_t *tmplt)
Set UniRec template to ouput interface on specified context.
Definition: unirec.c:842
#define ur_size_of(type)
Get size of UniRec type Get size of fixed-length UniRec type. For variable-length type return value <...
Definition: unirec.h:372
#define ur_get_var_len(tmplt, rec, field_id)
Get size of a variable sized field in the record. Get size of a variable-length field in the record....
Definition: unirec.h:474
#define ur_is_static(field_id)
Alias for ur_is_fixlen (for backwards compatibility only)
Definition: unirec.h:662
int ur_template_compare(const ur_template_t *tmpltA, const ur_template_t *tmpltB)
Compares fields of two UniRec templates Function compares only sets of UniRec fields (direction is no...
Definition: unirec.c:1110
int ur_field_array_elem_type[]
UniRec array element data types.
Definition: unirec.c:172
void * ur_clone_record(const ur_template_t *tmplt, const void *src)
Create new UniRec and copy the source UniRec into it. Function creates new UniRec record and fills it...
Definition: unirec.c:1249
ur_template_t * ur_ctx_create_output_template(trap_ctx_t *ctx, int ifc, const char *fields, char **errstr)
Create UniRec template and set it to output interface on specified context Creates UniRec template,...
Definition: unirec.c:823
ur_template_t * ur_ctx_create_input_template(trap_ctx_t *ctx, int ifc, const char *fields, char **errstr)
Create UniRec template and set it to input interface on specified context Creates UniRec template,...
Definition: unirec.c:804
char * ur_template_string_delimiter(const ur_template_t *tmplt, int delimiter)
Get UniRec specifier of the tmplt template with delimiter between fields.
Definition: unirec.c:257
ur_template_t * ur_expand_template(const char *ifc_data_fmt, ur_template_t *tmplt)
Expand UniRec template Expand existing UniRec template by a string containing types and names of its ...
Definition: unirec.c:490
#define ur_array_get_elem_cnt(tmplt, rec, field_id)
Get number of elements stored in an UniRec array.
Definition: unirec.h:546
#define ur_array_get_elem_size(field_id)
Get size of a single element of UniRec field.
Definition: unirec.h:535
#define ur_set_var_len(tmplt, rec, field_id, len)
Set size of variable-length field in the record. Set size of specified variable-length field in the r...
Definition: unirec.h:485
#define ur_get_len(tmplt, rec, field)
Get length of UniRec field Get actual length of fixed or variable-length UniRec field.
Definition: unirec.h:506
#define ur_get_name(field_id)
Get name of UniRec field Get name of any UniRec defined field.
Definition: unirec.h:380
const char * ur_values_get_name_start_end(uint32_t start, uint32_t end, int32_t value)
Returns name of specified value (Helper function) Helper function for ur_values_get_name....
Definition: unirec.c:1672
int ur_set_var(const ur_template_t *tmplt, void *rec, int field_id, const void *val_ptr, int val_len)
Set content of variable-length UniRec field Copy given data into variable-length UniRec field,...
Definition: unirec.c:1158
int ur_define_set_of_fields(const char *ifc_data_fmt)
Define set of new UniRec fields Define new UniRec fields at run-time. It adds new fields into existin...
Definition: unirec.c:564
void ur_copy_fields(const ur_template_t *dst_tmplt, void *dst, const ur_template_t *src_tmplt, const void *src)
Copy data from one UniRec record to another. Copies all fields present in both templates from src to ...
Definition: unirec.c:1259
int ur_get_id_by_name(const char *name)
Get ID of a field by its name Get ID of a field by its name.
Definition: unirec.c:780
ur_template_t * ur_create_template_from_ifc_spec(const char *ifc_data_fmt)
Create UniRec template from data format string. Creates new UniRec template (function ur_create_templ...
Definition: unirec.c:631
int ur_set_array_from_string(const ur_template_t *tmpl, void *data, ur_field_id_t f_id, const char *v)
Set value of a UniRec array field.
Definition: unirec.c:1321
#define ur_get_type(field_id)
Get type of UniRec field Get type of any UniRec defined field.
Definition: unirec.h:388
int ur_get_field_type_from_str(const char *type)
Definition: unirec.c:359
int ur_set_from_string(const ur_template_t *tmpl, void *data, ur_field_id_t f_id, const char *v)
Set value of a UniRec field.
Definition: unirec.c:1493
int ur_define_field(const char *name, ur_field_type_t type)
Define new UniRec field Define new UniRec field at run-time. It adds new field into existing structur...
Definition: unirec.c:642
ur_template_t * ur_create_template(const char *fields, char **errstr)
Create UniRec template Create new UniRec template specified by a string containing names of its field...
Definition: unirec.c:906
void ur_free_record(void *record)
Definition: unirec.c:1229
int compare_fields(const void *field1, const void *field2)
Compare fields Compare two fields. This function is for sorting the fields in the right order....
Definition: unirec.c:791
#define ur_get_ptr_by_id(tmplt, data, field_id)
Get pointer to UniRec field Get pointer to fixed or varible length UniRec field. In contrast to ur_ge...
Definition: unirec.h:442
ur_iter_t ur_iter_fields(const ur_template_t *tmplt, ur_iter_t id)
Iterate over fields of a template in order of a record This function can be used to iterate over all ...
Definition: unirec.c:1292
#define ur_is_present(tmplt, field_id)
Is given field present in given template? Return true (non-zero value) if given template contains fie...
Definition: unirec.h:638
uint64_t ur_time_t
Type of timestamps used in UniRec Timestamps in UniRec are stored as number of seconds from Unix epoc...
Definition: ur_time.h:61
uint8_t ur_time_from_string(ur_time_t *ur, const char *str)
Definition: unirec.c:1612
#define ur_time_from_sec_nsec(sec, nsec)
Convert seconds and nanoseconds to ur_time_t.
Definition: ur_time.h:100
#define INLINE_IMPL
Definition: inline.h:13
mac_addr_t
Definition: macaddr.h:75
const char * ur_get_type_and_name_from_string(const char *source, char **name, char **type, int *length_name, int *length_type)
Definition: unirec.c:372
INLINE_IMPL void mac_to_str(const mac_addr_t *addr, char *str)
Definition: macaddr.h:129
INLINE_IMPL void mac_to_bytes(const mac_addr_t *addr, uint8_t *array)
Definition: macaddr.h:144
INLINE_IMPL int mac_cmp(const mac_addr_t *addr1, const mac_addr_t *addr2)
Definition: macaddr.h:118
void ur_var_change_size(const ur_template_t *tmplt, void *rec, int field_id, int new_val_len)
Definition: unirec.c:1132
INLINE_IMPL int mac_from_str(const char *str, mac_addr_t *addr)
Definition: macaddr.h:99
const char UR_MEMORY_ERROR[]
Definition: unirec.c:208
#define MAX(A, B)
Definition: unirec.c:65
INLINE_IMPL mac_addr_t mac_from_bytes(const uint8_t *array)
Definition: macaddr.h:83
Definition of UniRec structures and functions.
ur_field_type_t
Definition: unirec.h:95
@ UR_TYPE_A_UINT32
unsigned int (32b) array
Definition: unirec.h:118
@ UR_TYPE_UINT64
unsigned int (64b)
Definition: unirec.h:105
@ UR_TYPE_A_UINT16
unsigned int (16b) array
Definition: unirec.h:116
@ UR_TYPE_A_INT64
int (64b) array
Definition: unirec.h:121
@ UR_TYPE_A_DOUBLE
double (64b) array
Definition: unirec.h:123
@ UR_TYPE_A_IP
IP address (128b) array.
Definition: unirec.h:124
@ UR_TYPE_INT16
int (8b)
Definition: unirec.h:102
@ UR_TYPE_A_INT32
int (32b) array
Definition: unirec.h:119
@ UR_TYPE_A_INT8
int (8b) array
Definition: unirec.h:115
@ UR_TYPE_A_INT16
int (8b) array
Definition: unirec.h:117
@ UR_TYPE_IP
IP address (128b)
Definition: unirec.h:109
@ UR_TYPE_INT8
int (8b)
Definition: unirec.h:100
@ UR_TYPE_CHAR
char
Definition: unirec.h:98
@ UR_TYPE_A_UINT8
unsigned int (8b) array
Definition: unirec.h:114
@ UR_TYPE_DOUBLE
double (64b)
Definition: unirec.h:108
@ UR_TYPE_A_FLOAT
float (32b) array
Definition: unirec.h:122
@ UR_TYPE_A_UINT64
unsigned int (64b) array
Definition: unirec.h:120
@ UR_TYPE_A_MAC
MAC address (48b) array.
Definition: unirec.h:125
@ UR_TYPE_TIME
time (64b)
Definition: unirec.h:111
@ UR_TYPE_UINT8
unsigned int (8b)
Definition: unirec.h:99
@ UR_TYPE_INT64
int (64b)
Definition: unirec.h:106
@ UR_TYPE_STRING
var-len fields (string where only printable characters are expected; '\0' at the end should NOT be in...
Definition: unirec.h:96
@ UR_TYPE_A_TIME
time (64b) array
Definition: unirec.h:126
@ UR_TYPE_INT32
int (32b)
Definition: unirec.h:104
@ UR_TYPE_UINT16
unsigned int (16b)
Definition: unirec.h:101
@ UR_TYPE_UINT32
unsigned int (32b)
Definition: unirec.h:103
@ UR_TYPE_MAC
MAC address (48b)
Definition: unirec.h:110
@ UR_TYPE_BYTES
var-len fields (generic string of bytes)
Definition: unirec.h:97
@ UR_TYPE_FLOAT
float (32b)
Definition: unirec.h:107
ur_field_id_t ur_last_id
The highest ID of a field + 1.
Definition: unirec.h:169
#define UR_UNINITIALIZED
Indicator if the UniRec has not been initialized by calling function ur_init.
Definition: unirec.h:80
ur_tmplt_direction direction
Direction of data input, output, bidirection, no direction.
Definition: unirec.h:198
ur_field_id_t ur_iter_t
Type for identifying iteration id through all fields.
Definition: unirec.h:137
#define UR_E_MEMORY
Problem during allocating memory.
Definition: unirec.h:89
int16_t ur_field_id_t
Type of UniRec field identifiers.
Definition: unirec.h:136
#define UR_ITER_BEGIN
First value in iterating through the fields.
Definition: unirec.h:75
#define UR_DEFAULT_LENGTH_OF_FIELD_TYPE
Definition: unirec.h:68
#define UR_OK
No problem.
Definition: unirec.h:90
#define UR_INITIALIZED
Indicator if the UniRec has been initialized by calling function ur_init.
Definition: unirec.h:81
uint8_t intialized
If the UniRec is initialized by function ur_init variable is set to UR_INITIALIZED,...
Definition: unirec.h:175
int size
Size of a field.
Definition: unirec.h:184
ur_field_id_linked_list_t * ur_undefine_fields
linked list of free (undefined) IDs
Definition: unirec.h:174
#define UR_ARRAY_DELIMITER
Delimiter of array elements in string.
Definition: unirec.h:72
#define UR_E_TYPE_MISMATCH
The type of a field is different.
Definition: unirec.h:86
ur_field_id_t ur_last_statically_defined_id
Last statically defined field by UR_FIELDS(...)
Definition: unirec.h:168
#define UR_E_INVALID_NAME
The given name is not present in a template.
Definition: unirec.h:87
uint16_t count
Count of fields in template.
Definition: unirec.h:196
ur_field_type_t * ur_field_types
Array of types of fields.
Definition: unirec.h:167
char * name
Name of a field.
Definition: unirec.h:183
uint16_t first_dynamic
First dynamic (variable-length) field. Index to the ids array.
Definition: unirec.h:195
#define UR_DEFAULT_LENGTH_OF_FIELD_NAME
Definition: unirec.h:67
uint16_t * offset
Table of offsets.
Definition: unirec.h:192
uint32_t ifc_out
output interface number (stored only if the direction == UR_TMPLT_DIRECTION_BI)
Definition: unirec.h:199
uint16_t static_size
Size of static part.
Definition: unirec.h:197
#define UR_DEFAULT_LENGTH_OF_TEMPLATE
Definition: unirec.h:66
#define UR_ARRAY_ALLOC
Default alloc size increment for ur_set_array_from_string.
Definition: unirec.h:73
ur_field_id_t id
ID of a field.
Definition: unirec.h:185
short * ur_field_sizes
Array of sizes of fields.
Definition: unirec.h:154
#define UR_INVALID_OFFSET
Default value of all offsets (value is not in the record)
Definition: unirec.h:78
ur_field_id_t ur_last_id
Last specified ID.
Definition: unirec.h:156
ur_tmplt_direction
Definition: unirec.h:129
@ UR_TMPLT_DIRECTION_IN
input direction
Definition: unirec.h:131
@ UR_TMPLT_DIRECTION_NO
template is not used for sending data
Definition: unirec.h:130
@ UR_TMPLT_DIRECTION_OUT
ouput direction
Definition: unirec.h:132
@ UR_TMPLT_DIRECTION_BI
bidirection
Definition: unirec.h:133
#define UR_NO_DYNAMIC_VALUES
Value of variable "first_dynamic" if no dynamic values are present.
Definition: unirec.h:79
short * ur_field_sizes
Array of sizes of fields.
Definition: unirec.h:166
char ** ur_field_names
Array of names of fields.
Definition: unirec.h:153
#define UR_COUNT_OF_TYPES
Constants for all possible types of UniRec fields.
Definition: unirec.h:94
char ** ur_field_names
Array of names of fields.
Definition: unirec.h:165
#define UR_INITIAL_SIZE_FIELDS_TABLE
Initial size of free space in fields tables.
Definition: unirec.h:69
#define UR_FIELD_ID_MAX
Max ID of a field.
Definition: unirec.h:70
#define UR_E_INVALID_PARAMETER
The given parameter is wrong.
Definition: unirec.h:84
#define UR_E_INVALID_TYPE
The type of a field is not defined.
Definition: unirec.h:88
ur_field_id_t ur_allocated_fields
Definition: unirec.h:173
#define UR_ITER_END
Last value in iterating through the fields.
Definition: unirec.h:76
int16_t * ids
Array of ids in template.
Definition: unirec.h:194
ur_field_type_t * ur_field_types
Array of types of fields.
Definition: unirec.h:155
uint16_t offset_size
size of offset table.
Definition: unirec.h:193
#define UR_E_INVALID_FIELD_ID
The field ID is not present in a template.
Definition: unirec.h:85
Sorting fields structure This structure is used to sort fields by their size and name....
Definition: unirec.h:182
UniRec fields structure It contains all fields which are statically defined by UR_FIELDS(....
Definition: unirec.h:164
UniRec default field list It contains all fields which are specified statically in source code of a m...
Definition: unirec.h:152
UniRec template. It contains a table mapping a field to its position in an UniRec record.
Definition: unirec.h:191
const ur_values_t ur_values[]
Definition: ur_values.c:6
char * name
Name of Value.
Definition: ur_values.h:15
char * description
Description of Value.
Definition: ur_values.h:16