libamxc  1.10.3
C Generic Data Containers
amxc_variant_dump.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <stdlib.h>
56 #include <stdio.h>
57 #include <unistd.h>
58 #include <string.h>
59 #include <syslog.h>
60 
61 #include <amxc/amxc_string.h>
62 #include <amxc/amxc_variant_type.h>
63 #include <amxc/amxc_rbuffer.h>
64 #include <amxc/amxc_string_split.h>
65 #include <amxc_variant_priv.h>
66 #include <amxc/amxc_macros.h>
67 
68 typedef struct _amxc_log_var {
69  int fd;
70  FILE* stream;
73 
74 typedef int (* amxc_var_dump_fn_t) (const amxc_var_t* const var,
75  int indent,
76  amxc_log_var_t* log);
77 
78 static void amxc_var_log_init(amxc_log_var_t* log, int fd, FILE* stream, size_t msg_length) {
79  log->fd = fd;
80  log->stream = stream;
81  amxc_string_init(&log->message, msg_length);
82 }
83 
85  const char* line,
86  size_t length) {
87  int retval = 0;
88  if(log->fd != -1) {
89  retval = write(log->fd, line, length);
90  } else if(log->stream != NULL) {
91  retval = fwrite(line, 1, length, log->stream); // size is 1 to return the number of bytes like write()
92  } else {
93  retval = amxc_string_append(&log->message, line, length);
94  if(amxc_string_search(&log->message, "\n", 0) >= 0) {
95  syslog(LOG_DAEMON | LOG_DEBUG,
96  "%s", amxc_string_get(&log->message, 0));
98  }
99  }
100  return retval;
101 }
102 
103 static int amxc_var_dump_internal(const amxc_var_t* const var,
104  int indent,
105  amxc_log_var_t* log);
106 
107 static void write_indentation(int indent, amxc_log_var_t* log) {
108  for(int i = 0; i < indent; i++) {
109  when_true(amxc_var_write(log, " ", 1) == -1, exit);
110  }
111 
112 exit:
113  return;
114 }
115 
116 static int variant_dump_type(const amxc_var_t* const var,
117  int indent,
118  amxc_log_var_t* log) {
119  amxc_string_t txt;
120  char addr[64] = "";
121  const char* type_name = amxc_var_type_name_of(var);
122 
123  write_indentation(indent, log);
124  amxc_string_init(&txt, 64);
125  amxc_string_append(&txt, "<", 1);
126  if(type_name != NULL) {
127  amxc_string_append(&txt, type_name, strlen(type_name));
128  } else {
129  amxc_string_append(&txt, "UNKNOWN", 7);
130  }
131  amxc_string_append(&txt, ">:", 2);
133  snprintf(addr, 63, "%p:", var->data.data);
134  amxc_string_append(&txt, addr, strlen(addr));
135  }
137  amxc_string_get(&txt, 0),
138  amxc_string_text_length(&txt)) == -1,
139  exit);
140 
141 exit:
142  amxc_string_clean(&txt);
143  return 0;
144 }
145 
146 static int variant_dump_null(UNUSED const amxc_var_t* const var,
147  int indent,
148  amxc_log_var_t* log) {
149  write_indentation(indent, log);
150  when_true(amxc_var_write(log, "<NULL>", 6) == -1, exit);
151 
152 exit:
153  return 0;
154 }
155 
156 static int variant_dump_char(const amxc_var_t* const var,
157  int indent,
158  amxc_log_var_t* log) {
159  const char* txt = amxc_var_constcast(cstring_t, var);
160  write_indentation(indent, log);
161  when_true(amxc_var_write(log, "\"", 1) == -1, exit);
162  if(txt != NULL) {
163  when_true(amxc_var_write(log, txt, strlen(txt)) == -1, exit);
164  }
165  when_true(amxc_var_write(log, "\"", 1) == -1, exit);
166 
167 exit:
168  return 0;
169 }
170 
171 static int variant_dump_default(const amxc_var_t* const var,
172  int indent,
173  amxc_log_var_t* log) {
174  int retval = -1;
175  char* text = amxc_var_dyncast(cstring_t, var);
176 
177  write_indentation(indent, log);
178 
179  if(text != NULL) {
180  when_true(amxc_var_write(log, text, strlen(text)) == -1, exit);
181  retval = 0;
182  } else {
183  retval = variant_dump_type(var, indent, log);
184  }
185 
186 exit:
187  free(text);
188  return retval;
189 }
190 
191 static int variant_dump_list(const amxc_var_t* const var,
192  int indent,
193  amxc_log_var_t* log) {
194 
196 
197  when_true(amxc_var_write(log, "[\n", 2) == -1, exit);
198  indent += 4;
199  amxc_llist_for_each(it, list) {
201  if((amxc_var_type_of(lvar) == AMXC_VAR_ID_HTABLE) ||
202  ( amxc_var_type_of(lvar) == AMXC_VAR_ID_LIST)) {
203  write_indentation(indent, log);
204  }
205  amxc_var_dump_internal(lvar, indent, log);
206  if(amxc_llist_it_get_next(it) != NULL) {
207  when_true(amxc_var_write(log, ",\n", 2) == -1, exit);
208  } else {
209  when_true(amxc_var_write(log, "\n", 1) == -1, exit);
210  }
211  }
212  indent -= 4;
213  write_indentation(indent, log);
214  when_true(amxc_var_write(log, "]", 1) == -1, exit);
215 
216 exit:
217  return 0;
218 }
219 
220 static int variant_dump_htable(const amxc_var_t* const var,
221  int indent,
222  amxc_log_var_t* log) {
225  const char* prev_key = NULL;
226  amxc_htable_it_t* it = NULL;
227 
228  when_true(amxc_var_write(log, "{\n", 2) == -1, exit);
229  indent += 4;
230  for(uint32_t i = 0; i < amxc_array_capacity(keys); i++) {
231  amxc_var_t* hvar = NULL;
232  const char* key
233  = (const char*) amxc_array_it_get_data(amxc_array_get_at(keys, i));
234  if((prev_key != NULL) && (key != NULL) && (strcmp(key, prev_key) == 0)) {
236  } else {
237  it = amxc_htable_get(htable, key);
238  }
239  prev_key = key;
240  hvar = amxc_var_from_htable_it(it);
241  write_indentation(indent, log);
242  if(key != NULL) {
243  when_true(amxc_var_write(log, key, strlen(key)) == -1, exit);
244  } else {
245  when_true(amxc_var_write(log, "UNKNOWN", 7) == -1, exit);
246  }
247  when_true(amxc_var_write(log, " = ", 3) == -1, exit);
248  if((amxc_var_type_of(hvar) == AMXC_VAR_ID_HTABLE) ||
249  ( amxc_var_type_of(hvar) == AMXC_VAR_ID_LIST)) {
250  amxc_var_dump_internal(hvar, indent, log);
251  } else {
252  amxc_var_dump_internal(hvar, 0, log);
253  }
254  if(i + 1 < amxc_array_capacity(keys)) {
255  when_true(amxc_var_write(log, ",\n", 2) == -1, exit);
256  } else {
257  when_true(amxc_var_write(log, "\n", 1) == -1, exit);
258  }
259  }
260  indent -= 4;
261  write_indentation(indent, log);
262  when_true(amxc_var_write(log, "}", 1) == -1, exit);
263 
264 exit:
265  amxc_array_delete(&keys, NULL);
266  return 0;
267 }
268 
269 static int variant_dump_fd(const amxc_var_t* const var,
270  int indent,
271  amxc_log_var_t* log) {
272  variant_dump_type(var, indent, log);
273  return variant_dump_default(var, indent, log);
274 }
275 
276 static int variant_dump_ts(const amxc_var_t* const var,
277  int indent,
278  amxc_log_var_t* log) {
279  variant_dump_type(var, indent, log);
280  return variant_dump_default(var, indent, log);
281 }
282 
283 static int amxc_var_dump_internal(const amxc_var_t* const var,
284  int indent,
285  amxc_log_var_t* log) {
286  int retval = -1;
307  NULL,
308  };
309 
311  retval = variant_dump_default(var, indent, log);
312  } else {
313  if(dumpfn[var->type_id] != NULL) {
314  retval = dumpfn[var->type_id](var, indent, log);
315  }
316  }
317 
318  return retval;
319 }
320 
321 static int amxc_var_dump_impl(const amxc_var_t* const var, int fd, FILE* stream) {
322  int retval = 0;
323  amxc_log_var_t log;
324 
325  amxc_var_log_init(&log, fd, stream, 0);
326 
327  if(var == NULL) {
328  amxc_var_write(&log, "NULL\n", 5);
329  goto exit;
330  }
331 
332  retval = amxc_var_dump_internal(var, 0, &log);
333  when_true(amxc_var_write(&log, "\n", 1) == -1, exit);
334 
335 exit:
337  return retval;
338 }
339 
340 int amxc_var_dump(const amxc_var_t* const var, int fd) {
341  return amxc_var_dump_impl(var, fd, NULL);
342 }
343 
344 int amxc_var_dump_stream(const amxc_var_t* const var, FILE* stream) {
345  return amxc_var_dump_impl(var, -1, stream);
346 }
347 
348 int amxc_var_log(const amxc_var_t* const var) {
349  amxc_log_var_t log;
350  int retval = 0;
351 
352  amxc_var_log_init(&log, -1, NULL, 1024);
353 
354  if(var == NULL) {
355  syslog(LOG_DAEMON | LOG_DEBUG, "NULL");
356  goto exit;
357  }
358 
359  retval = amxc_var_dump_internal(var, 0, &log);
360  if(!amxc_string_is_empty(&log.message)) {
361  syslog(LOG_DAEMON | LOG_DEBUG, "%s", amxc_string_get(&log.message, 0));
362  }
363 
364 exit:
366  return retval;
367 }
#define when_true(x, l)
Definition: amxc_macros.h:134
#define UNUSED
Definition: amxc_macros.h:70
Ambiorix ring buffer API header file.
Ambiorix string API header file.
#define cstring_t
Convenience macro.
Definition: amxc_variant.h:584
#define amxc_var_from_htable_it(ht_it)
Get the variant pointer from an amxc htable iterator.
Definition: amxc_variant.h:790
#define amxc_var_from_llist_it(ll_it)
Get the variant pointer from an amxc linked list iterator.
Definition: amxc_variant.h:799
static int variant_dump_ts(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int amxc_var_dump_impl(const amxc_var_t *const var, int fd, FILE *stream)
static void amxc_var_log_init(amxc_log_var_t *log, int fd, FILE *stream, size_t msg_length)
static int variant_dump_type(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int variant_dump_null(UNUSED const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int variant_dump_default(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int variant_dump_list(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int variant_dump_htable(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int amxc_var_dump_internal(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static int variant_dump_fd(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
int(* amxc_var_dump_fn_t)(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
static void write_indentation(int indent, amxc_log_var_t *log)
static int amxc_var_write(amxc_log_var_t *log, const char *line, size_t length)
struct _amxc_log_var amxc_log_var_t
static int variant_dump_char(const amxc_var_t *const var, int indent, amxc_log_var_t *log)
Ambiorix ring buffer API header file.
AMXC_INLINE void * amxc_array_it_get_data(const amxc_array_it_t *const it)
Gets the data pointer of array iterator.
Definition: amxc_array.h:729
AMXC_INLINE size_t amxc_array_capacity(const amxc_array_t *const array)
Gets the capacity of the array.
Definition: amxc_array.h:694
amxc_array_it_t * amxc_array_get_at(const amxc_array_t *const array, const unsigned int index)
Gets the item iterator for the given index.
Definition: amxc_array.c:504
void amxc_array_delete(amxc_array_t **array, const amxc_array_it_delete_t func)
Frees the previously allocated array.
Definition: amxc_array.c:213
amxc_htable_it_t * amxc_htable_it_get_next_key(const amxc_htable_it_t *const reference)
Gets the next iterator in the hash table with the same key.
amxc_array_t * amxc_htable_get_sorted_keys(const amxc_htable_t *const htable)
Creates an array containing all keys of the hash table.
Definition: amxc_htable.c:339
amxc_htable_it_t * amxc_htable_get(const amxc_htable_t *const htable, const char *const key)
Gets a hash table iterator from the hash table.
Definition: amxc_htable.c:278
AMXC_INLINE amxc_llist_it_t * amxc_llist_it_get_next(const amxc_llist_it_t *const reference)
Gets the next iterator in the list.
Definition: amxc_llist.h:824
#define amxc_llist_for_each(it, list)
Loops over the list from head to tail.
Definition: amxc_llist.h:253
const char * amxc_string_get(const amxc_string_t *const string, const size_t offset)
Gets the content of the string buffer.
Definition: amxc_string.c:339
AMXC_INLINE int amxc_string_append(amxc_string_t *const string, const char *const text, const size_t length)
Appends text to the end of the current content of the string buffer.
Definition: amxc_string.h:920
void amxc_string_reset(amxc_string_t *const string)
Resets the buffer, reset the content to all 0.
Definition: amxc_string.c:203
AMXC_INLINE size_t amxc_string_text_length(const amxc_string_t *const string)
Gets the current size of the used string buffer.
Definition: amxc_string.h:997
int amxc_string_search(const amxc_string_t *const string, const char *needle, uint32_t start_pos)
Searches a sub-string in a string.
Definition: amxc_string.c:765
int amxc_string_init(amxc_string_t *const string, const size_t length)
Initializes a string.
Definition: amxc_string.c:163
AMXC_INLINE bool amxc_string_is_empty(const amxc_string_t *const string)
Checks if the string is empty.
Definition: amxc_string.h:1015
void amxc_string_clean(amxc_string_t *const string)
Frees the string buffer and reset length attributes.
Definition: amxc_string.c:189
#define AMXC_VAR_ID_CUSTOM_BASE
Base variant id for custom variants.
Definition: amxc_variant.h:257
#define AMXC_VAR_ID_ANY
Special variant id, typically used in cast or conversion functions.
Definition: amxc_variant.h:247
#define AMXC_VAR_ID_LIST
Ambiorix Linked List variant id.
Definition: amxc_variant.h:206
#define AMXC_VAR_ID_HTABLE
Ambiorix Hash Table variant id.
Definition: amxc_variant.h:212
int amxc_var_dump(const amxc_var_t *const var, int fd)
Dumps the content of the variant in a human readable manner.
int amxc_var_log(const amxc_var_t *const var)
Logs the content of the variant in a human readable manner to syslog.
int amxc_var_dump_stream(const amxc_var_t *const var, FILE *stream)
Dumps the content of the variant in a human readable manner.
uint32_t amxc_var_type_of(const amxc_var_t *const var)
Gets the variant type id of a variant.
Definition: amxc_variant.c:668
#define amxc_var_dyncast(type, var)
Dynamic cast a variant to a certain type.
Definition: amxc_variant.h:678
#define amxc_var_constcast(type, var)
Takes the content from a variant.
Definition: amxc_variant.h:722
const char * amxc_var_type_name_of(const amxc_var_t *const var)
Gets the variant type name of a variant.
Definition: amxc_variant.c:672
The array structure.
Definition: amxc_array.h:162
The hash table iterator structure.
Definition: amxc_htable.h:138
The hash table structure.
Definition: amxc_htable.h:175
The linked list structure.
Definition: amxc_llist.h:228
amxc_string_t message
The string structure.
Definition: amxc_string.h:103
The variant struct definition.
Definition: amxc_variant.h:861
void * data
Definition: amxc_variant.h:883
uint32_t type_id
Definition: amxc_variant.h:864
static amxc_htable_it_t it[2000]
static amxc_htable_t * htable
static amxc_var_t * var
Definition: test_issue_58.c:77