UniRec  3.3.2
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 
var-len fields (string where only printable characters are expected; &#39;\0&#39; at the end should NOT be in...
Definition: unirec.h:96
#define UR_FIELD_ID_MAX
Max ID of a field.
Definition: unirec.h:70
INLINE_IMPL void mac_to_bytes(const mac_addr_t *addr, uint8_t *array)
Definition: macaddr.h:144
int (8b)
Definition: unirec.h:102
float (32b)
Definition: unirec.h:107
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_E_INVALID_FIELD_ID
The field ID is not present in a template.
Definition: unirec.h:85
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
INLINE_IMPL ip_addr_t ip_from_16_bytes_be(const char b[16])
Definition: ipaddr.h:236
int (8b) array
Definition: unirec.h:115
ur_tmplt_direction direction
Direction of data input, output, bidirection, no direction.
Definition: unirec.h:198
Sorting fields structure This structure is used to sort fields by their size and name. The structure is passed to the sorting algorithm.
Definition: unirec.h:182
#define ur_get_type(field_id)
Get type of UniRec field Get type of any UniRec defined field.
Definition: unirec.h:388
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_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
input direction
Definition: unirec.h:131
uint8_t ur_time_from_string(ur_time_t *ur, const char *str)
Definition: unirec.c:1612
#define ur_get_name(field_id)
Get name of UniRec field Get name of any UniRec defined field.
Definition: unirec.h:380
ur_field_id_t ur_allocated_fields
Definition: unirec.h:173
#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
MAC address (48b) array.
Definition: unirec.h:125
int (64b)
Definition: unirec.h:106
ur_field_id_t id
ID of a field.
Definition: unirec.h:185
int ur_get_empty_id()
Return first empty id for new UniRec field Return first empty id for new UniRec field. If there is no space in the UniRec structures, it will increase space in the existing structures.
Definition: unirec.c:292
#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
char * name
Name of Value.
Definition: ur_values.h:15
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
#define UR_INITIAL_SIZE_FIELDS_TABLE
Initial size of free space in fields tables.
Definition: unirec.h:69
char * description
Description of Value.
Definition: ur_values.h:16
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
unsigned int (16b)
Definition: unirec.h:101
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_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
#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
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
#define ur_is_array(field_id)
Definition: unirec.h:526
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
INLINE_IMPL ip_addr_t ip_from_16_bytes_le(const char b[16])
Definition: ipaddr.h:249
short * ur_field_sizes
Array of sizes of fields.
Definition: unirec.h:166
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
char * ur_cpy_string(const char *str)
Duplicates given string. Helper function which returns pointer to duplicated string. New string has to be freed by user.
Definition: unirec.c:1661
short * ur_field_sizes
Array of sizes of fields.
Definition: unirec.h:154
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
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
bidirection
Definition: unirec.h:133
int ur_field_array_elem_type[]
UniRec array element data types.
Definition: unirec.c:172
MAC address (48b)
Definition: unirec.h:110
#define UR_INITIALIZED
Indicator if the UniRec has been initialized by calling function ur_init.
Definition: unirec.h:81
INLINE_IMPL void mac_to_str(const mac_addr_t *addr, char *str)
Definition: macaddr.h:129
IP address (128b) array.
Definition: unirec.h:124
#define UR_MAX_SIZE
Definition: unirec.h:1013
#define UR_OK
No problem.
Definition: unirec.h:90
#define ur_is_static(field_id)
Alias for ur_is_fixlen (for backwards compatibility only)
Definition: unirec.h:662
#define UR_E_INVALID_PARAMETER
The given parameter is wrong.
Definition: unirec.h:84
char ** ur_field_names
Array of names of fields.
Definition: unirec.h:165
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
#define UR_ARRAY_ALLOC
Default alloc size increment for ur_set_array_from_string.
Definition: unirec.h:73
char ** ur_field_names
Array of names of fields.
Definition: unirec.h:153
#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
INLINE_IMPL int ip_from_str(const char *str, ip_addr_t *addr)
Definition: ipaddr.h:301
char * name
Name of a field.
Definition: unirec.h:183
#define INLINE_IMPL
Definition: inline.h:13
#define UR_ITER_BEGIN
First value in iterating through the fields.
Definition: unirec.h:75
INLINE_IMPL int ip_cmp(const ip_addr_t *addr1, const ip_addr_t *addr2)
Definition: ipaddr.h:266
UniRec default field list It contains all fields which are specified statically in source code of a m...
Definition: unirec.h:152
unsigned int (64b) array
Definition: unirec.h:120
int (32b)
Definition: unirec.h:104
#define UR_E_MEMORY
Problem during allocating memory.
Definition: unirec.h:89
const int ur_field_type_size[]
Sizes of UniRec data types.
Definition: unirec.c:98
int ur_get_field_type_from_str(const char *type)
Definition: unirec.c:359
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
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
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
#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
void ur_finalize()
Deallocate UniRec structures Deallocate UniRec structures at the end of a program. This function SHOULD be called after all UniRec functions and macros invocations, typically during a cleanup phase before the program&#39;s end. This function has to be called if some fields are defined during run-time, otherwise this function is needless.
Definition: unirec.c:740
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
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
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
IP address (128b)
Definition: unirec.h:109
#define UR_ARRAY_DELIMITER
Delimiter of array elements in string.
Definition: unirec.h:72
unsigned int (32b) array
Definition: unirec.h:118
unsigned int (64b)
Definition: unirec.h:105
const ur_values_t ur_values[]
Definition: ur_values.c:6
template is not used for sending data
Definition: unirec.h:130
#define UR_E_TYPE_MISMATCH
The type of a field is different.
Definition: unirec.h:86
#define ur_array_allocate(tmplt, rec, field_id, elem_cnt)
Preallocates UniRec array field to have requested number of elements.
Definition: unirec.h:629
#define UR_COUNT_OF_TYPES
Constants for all possible types of UniRec fields.
Definition: unirec.h:94
ur_field_type_t * ur_field_types
Array of types of fields.
Definition: unirec.h:167
ur_field_specs_t ur_field_specs
Structure that lists UniRec field specifications such as names, types, id.
Definition: unirec.c:205
mac_addr_t
Definition: macaddr.h:75
#define UR_E_INVALID_TYPE
The type of a field is not defined.
Definition: unirec.h:88
#define ur_array_get_elem_size(field_id)
Get size of a single element of UniRec field.
Definition: unirec.h:535
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_create_record(const ur_template_t *tmplt, uint16_t max_var_size)
Definition: unirec.c:1220
uint16_t count
Count of fields in template.
Definition: unirec.h:196
INLINE_IMPL mac_addr_t mac_from_bytes(const uint8_t *array)
Definition: macaddr.h:83
#define UR_DEFAULT_LENGTH_OF_TEMPLATE
Definition: unirec.h:66
unsigned int (16b) array
Definition: unirec.h:116
#define UR_E_INVALID_NAME
The given name is not present in a template.
Definition: unirec.h:87
UniRec fields structure It contains all fields which are statically defined by UR_FIELDS(...) and run-time generated fields. This structure can be modified during run-time by generating new fields and erasing existing fields.
Definition: unirec.h:164
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_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
double (64b)
Definition: unirec.h:108
#define UR_NO_DYNAMIC_VALUES
Value of variable "first_dynamic" if no dynamic values are present.
Definition: unirec.h:79
int16_t * ids
Array of ids in template.
Definition: unirec.h:194
#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
INLINE_IMPL uint32_t ip_get_v4_as_int(const ip_addr_t *addr)
Definition: ipaddr.h:157
#define UR_ITER_END
Last value in iterating through the fields.
Definition: unirec.h:76
#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
int (8b) array
Definition: unirec.h:117
void ur_free_record(void *record)
Definition: unirec.c:1229
int16_t ur_field_id_t
Type of UniRec field identifiers.
Definition: unirec.h:136
#define UR_INVALID_OFFSET
Default value of all offsets (value is not in the record)
Definition: unirec.h:78
INLINE_IMPL ip_addr_t ip_from_int(uint32_t i)
Definition: ipaddr.h:183
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
int (32b) array
Definition: unirec.h:119
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
ur_field_id_t ur_last_id
Last specified ID.
Definition: unirec.h:156
Definition of UniRec structures and functions.
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_get_elem_cnt(tmplt, rec, field_id)
Get number of elements stored in an UniRec array.
Definition: unirec.h:546
INLINE_IMPL int ip_is6(const ip_addr_t *addr)
Definition: ipaddr.h:143
#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
INLINE_IMPL int mac_cmp(const mac_addr_t *addr1, const mac_addr_t *addr2)
Definition: macaddr.h:118
var-len fields (generic string of bytes)
Definition: unirec.h:97
uint16_t static_size
Size of static part.
Definition: unirec.h:197
uint32_t ifc_out
output interface number (stored only if the direction == UR_TMPLT_DIRECTION_BI)
Definition: unirec.h:199
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
int size
Size of a field.
Definition: unirec.h:184
#define ur_time_from_sec_nsec(sec, nsec)
Convert seconds and nanoseconds to ur_time_t.
Definition: ur_time.h:100
double (64b) array
Definition: unirec.h:123
ur_field_id_t ur_last_statically_defined_id
Last statically defined field by UR_FIELDS(...)
Definition: unirec.h:168
unsigned int (8b) array
Definition: unirec.h:114
ur_field_id_t ur_last_id
The highest ID of a field + 1.
Definition: unirec.h:169
unsigned int (32b)
Definition: unirec.h:103
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
INLINE_IMPL ip_addr_t ip_from_4_bytes_le(const char b[4])
Definition: ipaddr.h:218
#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
#define MAX(A, B)
Definition: unirec.c:65
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
ur_field_id_t ur_iter_t
Type for identifying iteration id through all fields.
Definition: unirec.h:137
ur_field_type_t
Definition: unirec.h:95
#define UR_DEFAULT_LENGTH_OF_FIELD_TYPE
Definition: unirec.h:68
INLINE_IMPL int mac_from_str(const char *str, mac_addr_t *addr)
Definition: macaddr.h:99
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
ur_field_id_linked_list_t * ur_undefine_fields
linked list of free (undefined) IDs
Definition: unirec.h:174
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
INLINE_IMPL void ip_to_str(const ip_addr_t *addr, char *str)
Definition: ipaddr.h:325
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
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
uint16_t * offset
Table of offsets.
Definition: unirec.h:192
#define UR_UNINITIALIZED
Indicator if the UniRec has not been initialized by calling function ur_init.
Definition: unirec.h:80
uint8_t intialized
If the UniRec is initialized by function ur_init variable is set to UR_INITIALIZED, otherwise 0.
Definition: unirec.h:175
uint16_t first_dynamic
First dynamic (variable-length) field. Index to the ids array.
Definition: unirec.h:195
int (64b) array
Definition: unirec.h:121
ur_field_type_t * ur_field_types
Array of types of fields.
Definition: unirec.h:155
time (64b)
Definition: unirec.h:111
INLINE_IMPL int ip_is4(const ip_addr_t *addr)
Definition: ipaddr.h:131
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
void ur_var_change_size(const ur_template_t *tmplt, void *rec, int field_id, int new_val_len)
Definition: unirec.c:1132
char
Definition: unirec.h:98
#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
unsigned int (8b)
Definition: unirec.h:99
UniRec template. It contains a table mapping a field to its position in an UniRec record...
Definition: unirec.h:191
time (64b) array
Definition: unirec.h:126
const char UR_MEMORY_ERROR[]
Definition: unirec.c:208
#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
ur_tmplt_direction
Definition: unirec.h:129
int (8b)
Definition: unirec.h:100
uint16_t offset_size
size of offset table.
Definition: unirec.h:193
INLINE_IMPL ip_addr_t ip_from_4_bytes_be(const char b[4])
Definition: ipaddr.h:199
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
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
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
const char * ur_field_type_str[]
UniRec data types.
Definition: unirec.c:137
#define UR_DEFAULT_LENGTH_OF_FIELD_NAME
Definition: unirec.h:67
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. This function returns name of specified value and field, which is defined in values file. Function needs start and end index of a field.
Definition: unirec.c:1672
#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
ouput direction
Definition: unirec.h:132
INLINE_IMPL char * ip_get_v4_as_bytes(const ip_addr_t *addr)
Definition: ipaddr.h:171
float (32b) array
Definition: unirec.h:122