UniRec  2.9.3
unirec2csv.c
Go to the documentation of this file.
1 #include <stdint.h>
2 #include <inttypes.h>
3 #include <ctype.h>
4 #include <time.h>
5 #include "unirec2csv.h"
6 
7 urcsv_t *urcsv_init(ur_template_t *tmplt, char delimiter)
8 {
9  if (tmplt == NULL) {
10  return NULL;
11  }
12  urcsv_t *s = malloc(sizeof(urcsv_t));
13  if (s != NULL) {
14  s->tmplt = tmplt;
15  s->delimiter = delimiter;
16  /* default size of buffer */
17  s->buffer_size = 4096;
18  s->free_space = s->buffer_size;
19  s->buffer = calloc(s->buffer_size, sizeof(s->buffer[0]));
20  if (s->buffer == NULL) {
21  free(s);
22  return NULL;
23  }
24  }
25  return s;
26 }
27 
28 void urcsv_free(urcsv_t **urcsv)
29 {
30  if (urcsv != NULL && *urcsv != NULL) {
31  free((*urcsv)->buffer);
32  free(*urcsv);
33  (*urcsv) = NULL;
34  }
35 }
36 
37 char *urcsv_header(urcsv_t *urcsv)
38 {
39  if (urcsv == NULL) {
40  return NULL;
41  }
42  return ur_template_string_delimiter(urcsv->tmplt, urcsv->delimiter);
43 }
44 
45 int urcsv_value(char *dst, uint32_t size, void *ptr, int type, int field_len)
46 {
47  int written = 0;
48  char *p = dst;
49 
50  // Static field - check what type is it and use appropriate format
51  switch (type) {
52  case UR_TYPE_UINT8:
53  written = snprintf(p, size, "%" PRIu8, *(uint8_t*) ptr);
54  break;
55  case UR_TYPE_UINT16:
56  written = snprintf(p, size, "%" PRIu16, *(uint16_t*) ptr);
57  break;
58  case UR_TYPE_UINT32:
59  written = snprintf(p, size, "%" PRIu32, *(uint32_t*) ptr);
60  break;
61  case UR_TYPE_UINT64:
62  written = snprintf(p, size, "%" PRIu64, *(uint64_t*) ptr);
63  break;
64  case UR_TYPE_INT8:
65  written = snprintf(p, size, "%" PRIi8, *(int8_t*) ptr);
66  break;
67  case UR_TYPE_INT16:
68  written = snprintf(p, size, "%" PRIi16, *(int16_t*) ptr);
69  break;
70  case UR_TYPE_INT32:
71  written = snprintf(p, size, "%" PRIi32, *(int32_t*) ptr);
72  break;
73  case UR_TYPE_INT64:
74  written = snprintf(p, size, "%" PRIi64, *(int64_t*) ptr);
75  break;
76  case UR_TYPE_CHAR:
77  written = snprintf(p, size, "%c", *(char*) ptr);
78  break;
79  case UR_TYPE_FLOAT:
80  written = snprintf(p, size, "%f", *(float*) ptr);
81  break;
82  case UR_TYPE_DOUBLE:
83  written = snprintf(p, size, "%f", *(double*) ptr);
84  break;
85  case UR_TYPE_IP:
86  {
87  // IP address - convert to human-readable format and print
88  char str[46];
89  ip_to_str((ip_addr_t*) ptr, str);
90  written = snprintf(p, size, "%s", str);
91  }
92  break;
93  case UR_TYPE_MAC:
94  {
95  // MAC address - convert to human-readable format and print
96  char str[MAC_STR_LEN];
97  mac_to_str((mac_addr_t *) ptr, str);
98  written = snprintf(p, size, "%s", str);
99  }
100  break;
101  case UR_TYPE_TIME:
102  {
103  // Timestamp - convert to human-readable format and print
104  time_t sec = ur_time_get_sec(*(ur_time_t*) ptr);
105  int usec = ur_time_get_usec(*(ur_time_t*) ptr);
106  char str[40];
107  strftime(str, 39, "%FT%T", gmtime(&sec));
108  written = snprintf(p, size, "%s.%06i", str, usec);
109  }
110  break;
111  default:
112  {
113  // Unknown type - print the value in hex
114  strncpy(p, "0x", size);
115  written += 2;
116  p += 2;
117  for (int i = 0; i < field_len && written < size; i++) {
118  int w = snprintf(p, size - written, "%02x", ((unsigned char *) ptr)[i]);
119  written += w;
120  p += w;
121  }
122  }
123  break;
124  } // case (field type)
125 
126  return written;
127 }
128 
129 int urcsv_field(char *dst, uint32_t size, const void *rec, ur_field_type_t id, ur_template_t *tmplt)
130 {
131  int written = 0;
132  char *p = dst;
133 
134  // Get pointer to the field (valid for static fields only)
135  void *ptr = ur_get_ptr_by_id(tmplt, rec, id);
136  int type = ur_get_type(id);
137 
138  if (type == UR_TYPE_STRING) {
139  // Printable string - print it as it is
140  int fs = ur_get_var_len(tmplt, rec, id);
141  char *data = ur_get_ptr_by_id(tmplt, rec, id);
142  *(p++) = '"';
143  written++;
144 
145  while (fs-- && (written < size)) {
146  switch (*data) {
147  case '\n': // Replace newline with space
148  /* TODO / FIXME possible bug - info lost */
149  *(p++) = ' ';
150  written++;
151  break;
152  case '"' : // Double quotes in string
153  *(p++) = '"';
154  written++;
155  *(p++) = '"';
156  written++;
157  break;
158  default: // Check if character is printable
159  if (isprint(*data)) {
160  *(p++) = *data;
161  written++;
162  }
163  }
164  data++;
165  }
166  *(p++) = '"';
167  written++;
168  } else if (type == UR_TYPE_BYTES) {
169  // Generic string of bytes - print each byte as two hex digits
170  int fs = ur_get_var_len(tmplt, rec, id);
171  unsigned char *data = ur_get_ptr_by_id(tmplt, rec, id);
172  while (fs-- && (written < size)) {
173  int w = snprintf(p, size, "%02x", *data++);
174  written += w;
175  p += w;
176  }
177  } else if (ur_is_varlen(id)) {
178  int elem_type = ur_array_get_elem_type(id);
179  int elem_size = ur_array_get_elem_size(id);
180  int elem_cnt = ur_array_get_elem_cnt(tmplt, rec, id);
181  int array_len = ur_get_len(tmplt, rec, id);
182  int i;
183 
184  if (written + 2 < size) {
185  written += 2;
186  *(p++) = '[';
187  for (i = 0; i < elem_cnt; i++) {
188  int w = urcsv_value(p, size - written, ((char *) ptr) + i * elem_size, elem_type, array_len);
189  written += w;
190  p += w;
191  if (written + 1 >= size) {
192  /* not enough space */
193  return 0;
194  }
195  if (i + 1 != elem_cnt) {
196  *(p++) = '|';
197  written++;
198  }
199  }
200  *(p++) = ']';
201  }
202  } else {
203  return urcsv_value(p, size, ptr, type, ur_get_len(tmplt, rec, id));
204  }
205 
206  return written;
207 }
208 
209 char *urcsv_record(urcsv_t *urcsv, const void *rec)
210 {
211  int delim = 0;
212  int i = 0, written = 0;
213  ur_field_id_t id = 0;
214 
215  if (urcsv == NULL || rec == NULL) {
216  return NULL;
217  }
218 
219  urcsv->curpos = urcsv->buffer;
220  urcsv->free_space = urcsv->buffer_size;
221 
222  // Iterate over all output fields
223  while ((id = ur_iter_fields_record_order(urcsv->tmplt, i++)) != UR_ITER_END) {
224  if (delim != 0) {
225  *(urcsv->curpos++) = urcsv->delimiter;
226  urcsv->free_space -= 1;
227  }
228 
229  delim = 1;
230 reallocated:
231  if (ur_is_present(urcsv->tmplt, id)) {
232  // Static field - check what type is it and use appropriate format
233  written = urcsv_field(urcsv->curpos, urcsv->free_space, rec, id, urcsv->tmplt);
234 
235  urcsv->free_space -= written;
236  urcsv->curpos += written;
237  } else {
238  continue;
239  }
240 
241  if (urcsv->free_space < 100 || (written == 0 && ur_get_var_len(urcsv->tmplt, rec, id) != 0)) {
242  urcsv->free_space += urcsv->buffer_size / 2;
243  urcsv->buffer_size += urcsv->buffer_size / 2;
244  uint32_t offset = urcsv->curpos - urcsv->buffer;
245  void *temp = realloc(urcsv->buffer, urcsv->buffer_size);
246  if (temp != NULL) {
247  urcsv->buffer = temp;
248  urcsv->curpos = urcsv->buffer + offset;
249  } else {
250  return NULL;
251  }
252  if (written == 0) {
253  goto reallocated;
254  }
255  }
256  } // loop over fields
257 
258  *urcsv->curpos = 0;
259  return strdup(urcsv->buffer);
260 }
261 
Definition of UniRec API to create CSV-like representation of UniRec data.
var-len fields (string where only printable characters are expected; &#39;\0&#39; at the end should NOT be in...
Definition: unirec.h:96
int (8b)
Definition: unirec.h:102
float (32b)
Definition: unirec.h:107
#define ur_get_type(field_id)
Get type of UniRec field Get type of any UniRec defined field.
Definition: unirec.h:388
int (64b)
Definition: unirec.h:106
char * urcsv_record(urcsv_t *urcsv, const void *rec)
Definition: unirec2csv.c:209
unsigned int (16b)
Definition: unirec.h:101
ur_template_t * tmplt
Definition: unirec2csv.h:51
*uint16_t * ur_get_ptr_by_id(tmplt2, buffer2, new_id))
MAC address (48b)
Definition: unirec.h:110
uint32_t buffer_size
Definition: unirec2csv.h:66
char * urcsv_header(urcsv_t *urcsv)
Definition: unirec2csv.c:37
INLINE void mac_to_str(const mac_addr_t *addr, char *str)
Definition: macaddr.h:129
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_time_get_sec(time)
Get number of seconds from ur_time_t.
Definition: ur_time.h:124
free(rec)
int (32b)
Definition: unirec.h:104
#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
IP address (128b)
Definition: unirec.h:109
unsigned int (64b)
Definition: unirec.h:105
void * rec
mac_addr_t
Definition: macaddr.h:75
#define ur_array_get_elem_size(field_id)
Get size of a single element of UniRec field.
Definition: unirec.h:535
char * buffer
Definition: unirec2csv.h:56
char delimiter
Definition: unirec2csv.h:76
double (64b)
Definition: unirec.h:108
#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
#define UR_ITER_END
Last value in iterating through the fields.
Definition: unirec.h:76
uint32_t free_space
Definition: unirec2csv.h:71
#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
int16_t ur_field_id_t
Type of UniRec field identifiers.
Definition: unirec.h:136
#define ur_is_varlen(field_id)
Is given field variable-length? Return true (non-zero value) if given ID refers to a field with varia...
Definition: unirec.h:646
#define ur_array_get_elem_cnt(tmplt, rec, field_id)
Get number of elements stored in an UniRec array.
Definition: unirec.h:546
var-len fields (generic string of bytes)
Definition: unirec.h:97
unsigned int (32b)
Definition: unirec.h:103
char * curpos
Definition: unirec2csv.h:61
#define MAC_STR_LEN
Definition: macaddr.h:57
ur_field_type_t
Definition: unirec.h:95
INLINE void ip_to_str(const ip_addr_t *addr, char *str)
Definition: ipaddr.h:325
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:253
urcsv_t * urcsv_init(ur_template_t *tmplt, char delimiter)
Definition: unirec2csv.c:7
time (64b)
Definition: unirec.h:111
int urcsv_value(char *dst, uint32_t size, void *ptr, int type, int field_len)
Definition: unirec2csv.c:45
char
Definition: unirec.h:98
#define ur_time_get_usec(time)
Get number of microeconds from ur_time_t.
Definition: ur_time.h:139
unsigned int (8b)
Definition: unirec.h:99
int urcsv_field(char *dst, uint32_t size, const void *rec, ur_field_type_t id, ur_template_t *tmplt)
Definition: unirec2csv.c:129
UniRec template. It contains a table mapping a field to its position in an UniRec record...
Definition: unirec.h:191
void urcsv_free(urcsv_t **urcsv)
Definition: unirec2csv.c:28
int (8b)
Definition: unirec.h:100
#define ur_array_get_elem_type(field_id)
Get type of an element stored in an UniRec array.
Definition: unirec.h:555
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:1306