Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


func_cut.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (c) 2003-2006 Tilghman Lesher. All rights reserved.
5  *
6  * Tilghman Lesher <app_cut__v003@the-tilghman.com>
7  *
8  * This code is released by the author with no restrictions on usage.
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  */
17 
18 /*! \file
19  *
20  * \brief CUT function
21  *
22  * \author Tilghman Lesher <app_cut__v003@the-tilghman.com>
23  *
24  * \ingroup functions
25  */
26 
27 /*** MODULEINFO
28  <support_level>core</support_level>
29  ***/
30 
31 #include "asterisk.h"
32 
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 370642 $")
34 
35 #include "asterisk/file.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/module.h"
39 #include "asterisk/app.h"
40 
41 /*** DOCUMENTATION
42  <function name="SORT" language="en_US">
43  <synopsis>
44  Sorts a list of key/vals into a list of keys, based upon the vals.
45  </synopsis>
46  <syntax>
47  <parameter name="keyval" required="true" argsep=":">
48  <argument name="key1" required="true" />
49  <argument name="val1" required="true" />
50  </parameter>
51  <parameter name="keyvaln" multiple="true" argsep=":">
52  <argument name="key2" required="true" />
53  <argument name="val2" required="true" />
54  </parameter>
55  </syntax>
56  <description>
57  <para>Takes a comma-separated list of keys and values, each separated by a colon, and returns a
58  comma-separated list of the keys, sorted by their values. Values will be evaluated as
59  floating-point numbers.</para>
60  </description>
61  </function>
62  <function name="CUT" language="en_US">
63  <synopsis>
64  Slices and dices strings, based upon a named delimiter.
65  </synopsis>
66  <syntax>
67  <parameter name="varname" required="true">
68  <para>Variable you want cut</para>
69  </parameter>
70  <parameter name="char-delim" required="true">
71  <para>Delimiter, defaults to <literal>-</literal></para>
72  </parameter>
73  <parameter name="range-spec" required="true">
74  <para>Number of the field you want (1-based offset), may also be specified as a range (with <literal>-</literal>)
75  or group of ranges and fields (with <literal>&amp;</literal>)</para>
76  </parameter>
77  </syntax>
78  <description>
79  <para>Cut out information from a string (<replaceable>varname</replaceable>), based upon a named delimiter.</para>
80  </description>
81  </function>
82  ***/
83 
84 struct sortable_keys {
85  char *key;
86  float value;
87 };
88 
89 static int sort_subroutine(const void *arg1, const void *arg2)
90 {
91  const struct sortable_keys *one=arg1, *two=arg2;
92  if (one->value < two->value)
93  return -1;
94  else if (one->value == two->value)
95  return 0;
96  else
97  return 1;
98 }
99 
100 #define ERROR_NOARG (-1)
101 #define ERROR_NOMEM (-2)
102 #define ERROR_USAGE (-3)
103 
104 static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
105 {
106  char *strings, *ptrkey, *ptrvalue;
107  int count=1, count2, element_count=0;
109 
110  *buffer = '\0';
111 
112  if (!data)
113  return ERROR_NOARG;
114 
115  strings = ast_strdupa(data);
116 
117  for (ptrkey = strings; *ptrkey; ptrkey++) {
118  if (*ptrkey == ',')
119  count++;
120  }
121 
122  sortable_keys = ast_alloca(count * sizeof(struct sortable_keys));
123 
124  memset(sortable_keys, 0, count * sizeof(struct sortable_keys));
125 
126  /* Parse each into a struct */
127  count2 = 0;
128  while ((ptrkey = strsep(&strings, ","))) {
129  ptrvalue = strchr(ptrkey, ':');
130  if (!ptrvalue) {
131  count--;
132  continue;
133  }
134  *ptrvalue++ = '\0';
135  sortable_keys[count2].key = ptrkey;
136  sscanf(ptrvalue, "%30f", &sortable_keys[count2].value);
137  count2++;
138  }
139 
140  /* Sort the structs */
141  qsort(sortable_keys, count, sizeof(struct sortable_keys), sort_subroutine);
142 
143  for (count2 = 0; count2 < count; count2++) {
144  int blen = strlen(buffer);
145  if (element_count++) {
146  strncat(buffer + blen, ",", buflen - blen - 1);
147  blen++;
148  }
149  strncat(buffer + blen, sortable_keys[count2].key, buflen - blen - 1);
150  }
151 
152  return 0;
153 }
154 
155 static int cut_internal(struct ast_channel *chan, char *data, struct ast_str **buf, ssize_t buflen)
156 {
157  char *parse, ds[2], *var_expr;
158  size_t delim_consumed;
159  struct ast_str *var_value;
161  AST_APP_ARG(varname);
162  AST_APP_ARG(delimiter);
163  AST_APP_ARG(field);
164  );
165 
166  parse = ast_strdupa(data);
167 
168  AST_STANDARD_APP_ARGS(args, parse);
169 
170  /* Check arguments */
171  if (args.argc < 3) {
172  return ERROR_NOARG;
173  }
174  var_expr = ast_alloca(strlen(args.varname) + 4);
175 
176  /* Get the value of the variable named in the 1st argument */
177  snprintf(var_expr, strlen(args.varname) + 4, "${%s}", args.varname);
178  var_value = ast_str_create(16);
179  ast_str_substitute_variables(&var_value, 0, chan, var_expr);
180 
181  /* Copy delimiter from 2nd argument to ds[] possibly decoding backslash escapes */
182  if (ast_get_encoded_char(args.delimiter, ds, &delim_consumed)) {
183  ast_copy_string(ds, "-", sizeof(ds));
184  }
185  ds[1] = '\0';
186 
187  if (ast_str_strlen(var_value)) {
188  int curfieldnum = 1;
189  char *curfieldptr = ast_str_buffer(var_value);
190  int out_field_count = 0;
191 
192  while (curfieldptr != NULL && args.field != NULL) {
193  char *next_range = strsep(&(args.field), "&");
194  int start_field, stop_field;
195  char trashchar;
196 
197  if (sscanf(next_range, "%30d-%30d", &start_field, &stop_field) == 2) {
198  /* range with both start and end */
199  } else if (sscanf(next_range, "-%30d", &stop_field) == 1) {
200  /* range with end only */
201  start_field = 1;
202  } else if ((sscanf(next_range, "%30d%1c", &start_field, &trashchar) == 2) && (trashchar == '-')) {
203  /* range with start only */
204  stop_field = INT_MAX;
205  } else if (sscanf(next_range, "%30d", &start_field) == 1) {
206  /* single number */
207  stop_field = start_field;
208  } else {
209  /* invalid field spec */
210  ast_free(var_value);
211  return ERROR_USAGE;
212  }
213 
214  /* Get to start, if not there already */
215  while (curfieldptr != NULL && curfieldnum < start_field) {
216  strsep(&curfieldptr, ds);
217  curfieldnum++;
218  }
219 
220  /* Most frequent problem is the expectation of reordering fields */
221  if (curfieldnum > start_field) {
222  ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
223  }
224 
225  /* Output fields until we either run out of fields or stop_field is reached */
226  while (curfieldptr != NULL && curfieldnum <= stop_field) {
227  char *field_value = strsep(&curfieldptr, ds);
228  ast_str_append(buf, buflen, "%s%s", out_field_count++ ? ds : "", field_value);
229  curfieldnum++;
230  }
231  }
232  }
233  ast_free(var_value);
234  return 0;
235 }
236 
237 static int acf_sort_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
238 {
239  int ret = -1;
240 
241  switch (sort_internal(chan, data, buf, len)) {
242  case ERROR_NOARG:
243  ast_log(LOG_ERROR, "SORT() requires an argument\n");
244  break;
245  case ERROR_NOMEM:
246  ast_log(LOG_ERROR, "Out of memory\n");
247  break;
248  case 0:
249  ret = 0;
250  break;
251  default:
252  ast_log(LOG_ERROR, "Unknown internal error\n");
253  }
254 
255  return ret;
256 }
257 
258 static int acf_cut_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
259 {
260  int ret = -1;
261  struct ast_str *str = ast_str_create(16);
262 
263  switch (cut_internal(chan, data, &str, len)) {
264  case ERROR_NOARG:
265  ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
266  break;
267  case ERROR_NOMEM:
268  ast_log(LOG_ERROR, "Out of memory\n");
269  break;
270  case ERROR_USAGE:
271  ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n");
272  break;
273  case 0:
274  ret = 0;
275  ast_copy_string(buf, ast_str_buffer(str), len);
276  break;
277  default:
278  ast_log(LOG_ERROR, "Unknown internal error\n");
279  }
280  ast_free(str);
281  return ret;
282 }
283 
284 static int acf_cut_exec2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
285 {
286  int ret = -1;
287 
288  switch (cut_internal(chan, data, buf, len)) {
289  case ERROR_NOARG:
290  ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
291  break;
292  case ERROR_NOMEM:
293  ast_log(LOG_ERROR, "Out of memory\n");
294  break;
295  case ERROR_USAGE:
296  ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n");
297  break;
298  case 0:
299  ret = 0;
300  break;
301  default:
302  ast_log(LOG_ERROR, "Unknown internal error\n");
303  }
304 
305  return ret;
306 }
307 
308 static struct ast_custom_function acf_sort = {
309  .name = "SORT",
310  .read = acf_sort_exec,
311 };
312 
313 static struct ast_custom_function acf_cut = {
314  .name = "CUT",
315  .read = acf_cut_exec,
316  .read2 = acf_cut_exec2,
317 };
318 
319 static int unload_module(void)
320 {
321  int res = 0;
322 
323  res |= ast_custom_function_unregister(&acf_cut);
324  res |= ast_custom_function_unregister(&acf_sort);
325 
326  return res;
327 }
328 
329 static int load_module(void)
330 {
331  int res = 0;
332 
333  res |= ast_custom_function_register(&acf_cut);
334  res |= ast_custom_function_register(&acf_sort);
335 
336  return res;
337 }
338 
339 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Cut out information from a string");
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
Asterisk main include file. File version handling, generic pbx functions.
static int acf_cut_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_cut.c:258
char * strsep(char **str, const char *delims)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: utils.h:653
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:900
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
static struct ast_custom_function acf_sort
Definition: func_cut.c:308
const char * str
Definition: app_jack.c:144
int value
Definition: syslog.c:39
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
#define ERROR_NOARG
Definition: func_cut.c:100
#define ERROR_NOMEM
Definition: func_cut.c:101
General Asterisk PBX channel definitions.
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
Core PBX routines and definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static int cut_internal(struct ast_channel *chan, char *data, struct ast_str **buf, ssize_t buflen)
Definition: func_cut.c:155
#define LOG_ERROR
Definition: logger.h:155
int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
Decode an encoded control or extended ASCII character.
Definition: app.c:2122
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
static struct @350 args
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
float value
Definition: func_cut.c:86
static int load_module(void)
Definition: func_cut.c:329
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
#define ast_free(a)
Definition: astmm.h:97
static int acf_sort_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_cut.c:237
#define ERROR_USAGE
Definition: func_cut.c:102
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:471
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
char * key
Definition: func_cut.c:85
static struct ast_custom_function acf_cut
Definition: func_cut.c:313
const char * name
Definition: pbx.h:96
static int unload_module(void)
Definition: func_cut.c:319
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
Asterisk module definitions.
static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
Definition: func_cut.c:104
static int acf_cut_exec2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_cut.c:284
static int sort_subroutine(const void *arg1, const void *arg2)
Definition: func_cut.c:89
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180