Asterisk - The Open Source Telephony Project GIT-master-80b953f
Loading...
Searching...
No Matches
formatters.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2026, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \author George Joseph <gjoseph@sangoma.com>
22 *
23 * \brief Formatters
24 *
25 */
26
27#include "cdrel.h"
28#include "asterisk/json.h"
29#include "asterisk/cdr.h"
30#include "asterisk/cel.h"
31
32static char *quote_escaper(const char *value, char quote, char quote_escape, char *qvalue)
33{
34 char *ptr = qvalue;
35 const char *dataptr = value;
36
37 if (!qvalue) {
38 return NULL;
39 }
40
41 while(*dataptr != '\0') {
42 if (*dataptr == quote) {
43 *ptr++ = quote_escape;
44 }
45 *ptr++ = *dataptr++;
46 }
47 *ptr='\0';
48 return qvalue;
49}
50
52 struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
53{
54 int quotes_count = 0;
55 int needs_quoting = ast_test_flag(&field->flags, cdrel_flag_quote);
56 int ix = 0;
57 int input_len = strlen(input_value->values.string ?: "");
58 int res = 0;
59 char *qvalue = NULL;
60 char *evalue = (char *)input_value->values.string;
61
62 output_value->data_type = cdrel_type_string;
63 output_value->field_name = input_value->field_name;
64
65 if (input_len == 0) {
66 output_value->values.string = ast_strdup(needs_quoting ? "\"\"" : "");
67 return 0;
68 }
69
70 for (ix = 0; ix < input_len; ix++) {
71 char c = input_value->values.string[ix];
72 if (c == config->quote[0]) {
73 quotes_count++;
74 needs_quoting = 1;
75 } else if (c == config->separator[0] || c == '\r' || c == '\n') {
76 needs_quoting = 1;
77 }
78 }
79
80 ast_debug(5, "%s: %s=%s %s", cdrel_basename(config->output_filename), input_value->field_name,
81 input_value->values.string, ast_str_tmp(128, cdrel_get_field_flags(&field->flags, &STR_TMP)));
82
83 if (!needs_quoting) {
84 output_value->values.string = ast_strdup(input_value->values.string);
85 return output_value->values.string == NULL ? -1 : 0;
86 }
87
88 /* For every quote_count, we need an extra byte for the quote escape character. */
89 qvalue = ast_alloca(input_len + quotes_count + 1);
90 if (quotes_count) {
91 evalue = quote_escaper(input_value->values.string, config->quote[0], config->quote_escape[0], qvalue);
92 }
93 res = ast_asprintf(&output_value->values.string, "%s%s%s", config->quote, evalue, config->quote);
94 return res < 0 ? -1 : 0;
95}
96
97#define DEFINE_FORMATTER(_name, _field, _type, _fmt) \
98 static int format_ ## _name (struct cdrel_config *config, \
99 struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value) \
100 { \
101 int res = 0; \
102 char *quote = ""; \
103 if (input_value->data_type != output_value->data_type) { \
104 /* Forward to other formatter */ \
105 return cdrel_field_formatters[output_value->data_type](config, field, input_value, output_value); \
106 } \
107 output_value->field_name = input_value->field_name; \
108 if ((config->quoting_method == cdrel_quoting_method_all || ast_test_flag(&field->flags, cdrel_flag_quote)) \
109 && !ast_test_flag(&field->flags, cdrel_flag_noquote)) { \
110 quote = config->quote; \
111 } \
112 res = ast_asprintf(&output_value->values.string, "%s" _fmt "%s", quote, input_value->values._field, quote); \
113 output_value->data_type = cdrel_type_string; \
114 return res < 0 ? -1 : 0; \
115 }
116
117DEFINE_FORMATTER(uint32, uint32, uint32_t, "%u")
118DEFINE_FORMATTER(int32, int32, int32_t, "%d")
119DEFINE_FORMATTER(uint64, uint64, uint64_t, "%lu")
120DEFINE_FORMATTER(int64, int64, int64_t, "%ld")
121DEFINE_FORMATTER(double, doubler, double, "%.6f")
122
124 struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
125{
126 struct ast_tm tm;
127 char tempbuf[64] = { 0, };
128 int res = 0;
129 const char *format = "%Y-%m-%d %T";
130
131 output_value->field_name = input_value->field_name;
132
133 if (field->output_data_type == cdrel_type_int64) {
134 output_value->data_type = cdrel_type_int64;
135 output_value->values.int64 = input_value->values.tv.tv_sec;
136 return format_int64(config, field, output_value, output_value);
137 } else if (field->output_data_type == cdrel_type_double) {
138 output_value->data_type = cdrel_type_double;
139 output_value->values.doubler = ((double)input_value->values.tv.tv_sec) + ((double)input_value->values.tv.tv_usec) / 1000000.0;
140 return format_double(config, field, output_value, output_value);
141 } else if (field->output_data_type == cdrel_type_cel_timefmt) {
142 res = ast_cel_format_eventtime(input_value->values.tv, tempbuf, 64);
143 if (res != 0) {
144 return res;
145 }
146 input_value->values.string = tempbuf;
147 input_value->data_type = cdrel_type_string;
148 output_value->data_type = cdrel_type_string;
149 return format_string(config, field, input_value, output_value);
150 } else if (!ast_strlen_zero(field->data)) {
151 format = field->data;
152 }
153
154 if (input_value->values.tv.tv_sec > 0) {
155 ast_localtime(&input_value->values.tv, &tm, NULL);
156 ast_strftime(tempbuf, sizeof(tempbuf), format, &tm);
157 }
158 input_value->values.string = tempbuf;
159 input_value->data_type = cdrel_type_string;
160 output_value->data_type = cdrel_type_string;
161 res = format_string(config, field, input_value, output_value);
162 return res;
163}
164
166 struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
167{
168 int res = 0;
169
170 input_value->values.string = (char *)ast_channel_amaflags2string(input_value->values.int64);
171 input_value->data_type = cdrel_type_string;
172 output_value->data_type = cdrel_type_string;
173 res = format_string(config, field, input_value, output_value);
174 return res;
175}
176
178 struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
179{
180 int res = 0;
181
182 input_value->values.string = (char *)ast_cdr_disp2str(input_value->values.int64);
183 input_value->data_type = cdrel_type_string;
184 output_value->data_type = cdrel_type_string;
185 res = format_string(config, field, input_value, output_value);
186 return res;
187}
188
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
Call Detail Record API.
const char * ast_cdr_disp2str(int disposition)
Disposition to a string.
Definition cdr.c:3576
Private header for res_cdrel_custom.
const char * cdrel_basename(const char *path)
@ cdrel_type_cel_timefmt
Definition cdrel.h:81
@ cdrel_type_amaflags
Definition cdrel.h:76
@ cdrel_type_disposition
Definition cdrel.h:77
@ cdrel_type_uint64
Definition cdrel.h:86
@ cdrel_type_double
Definition cdrel.h:87
@ cdrel_type_int64
Definition cdrel.h:85
@ cdrel_type_int32
Definition cdrel.h:83
@ cdrel_type_string
Definition cdrel.h:73
@ cdrel_type_timeval
Definition cdrel.h:74
@ cdrel_type_uint32
Definition cdrel.h:84
cdrel_field_formatter cdrel_field_formatters[cdrel_data_type_end]
@ cdrel_flag_quote
Definition cdrel.h:104
const char * cdrel_get_field_flags(struct ast_flags *flags, struct ast_str **str)
Call Event Logging API.
int ast_cel_format_eventtime(struct timeval eventtime, char *timebuf, size_t len)
Format an event timeval using dateformat from cel.conf.
Definition cel.c:694
static const char config[]
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition channel.c:4407
#define DEFINE_FORMATTER(_name, _field, _type, _fmt)
Definition formatters.c:97
static char * quote_escaper(const char *value, char quote, char quote_escape, char *qvalue)
Definition formatters.c:32
int load_formatters(void)
Definition formatters.c:189
static int format_string(struct cdrel_config *config, struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
Definition formatters.c:51
static int format_amaflags(struct cdrel_config *config, struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
Definition formatters.c:165
static int format_disposition(struct cdrel_config *config, struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
Definition formatters.c:177
static int format_timeval(struct cdrel_config *config, struct cdrel_field *field, struct cdrel_value *input_value, struct cdrel_value *output_value)
Definition formatters.c:123
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define ast_debug(level,...)
Log a DEBUG message.
Asterisk JSON abstraction layer.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition localtime.c:1739
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition localtime.c:2524
#define NULL
Definition resample.c:96
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_tmp(init_len, __expr)
Provides a temporary ast_str and returns a copy of its buffer.
Definition strings.h:1189
struct ast_flags flags
Definition cdrel.h:276
union cdrel_value::@454 values
int64_t int64
Definition cdrel.h:181
enum cdrel_data_type data_type
Definition cdrel.h:175
char * field_name
Definition cdrel.h:174
char * string
Definition cdrel.h:178
int value
Definition syslog.c:37
static struct test_val d
static struct test_val c
#define ast_test_flag(p, flag)
Definition utils.h:64