Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


func_sprintf.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005-2006, Digium, Inc.
5  * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved.
6  * Portions Copyright (C) 2005, Anthony Minessale II
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 /*! \file
20  *
21  * \brief String manipulation dialplan functions
22  *
23  * \author Tilghman Lesher
24  * \author Anothony Minessale II
25  * \ingroup functions
26  */
27 
28 /*** MODULEINFO
29  <support_level>core</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
35 
36 #include <ctype.h>
37 
38 #include "asterisk/module.h"
39 #include "asterisk/channel.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/utils.h"
42 #include "asterisk/app.h"
43 
45 
46 /*** DOCUMENTATION
47  <function name="SPRINTF" language="en_US">
48  <synopsis>
49  Format a variable according to a format string.
50  </synopsis>
51  <syntax>
52  <parameter name="format" required="true" />
53  <parameter name="arg1" required="true" />
54  <parameter name="arg2" multiple="true" />
55  <parameter name="argN" />
56  </syntax>
57  <description>
58  <para>Parses the format string specified and returns a string matching
59  that format. Supports most options found in <emphasis>sprintf(3)</emphasis>.
60  Returns a shortened string if a format specifier is not recognized.</para>
61  </description>
62  <see-also>
63  <ref type="manpage">sprintf(3)</ref>
64  </see-also>
65  </function>
66  ***/
67 static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
68 {
69 #define SPRINTF_FLAG 0
70 #define SPRINTF_WIDTH 1
71 #define SPRINTF_PRECISION 2
72 #define SPRINTF_LENGTH 3
73 #define SPRINTF_CONVERSION 4
74  int i, state = -1, argcount = 0;
75  char *formatstart = NULL, *bufptr = buf;
76  char formatbuf[256] = "";
77  int tmpi;
78  double tmpd;
81  AST_APP_ARG(var)[100];
82  );
83 
84  AST_STANDARD_APP_ARGS(arg, data);
85 
86  /* Scan the format, converting each argument into the requisite format type. */
87  for (i = 0; arg.format[i]; i++) {
88  switch (state) {
89  case SPRINTF_FLAG:
90  if (strchr("#0- +'I", arg.format[i]))
91  break;
92  state = SPRINTF_WIDTH;
93  case SPRINTF_WIDTH:
94  if (arg.format[i] >= '0' && arg.format[i] <= '9')
95  break;
96 
97  /* Next character must be a period to go into a precision */
98  if (arg.format[i] == '.') {
99  state = SPRINTF_PRECISION;
100  } else {
101  state = SPRINTF_LENGTH;
102  i--;
103  }
104  break;
105  case SPRINTF_PRECISION:
106  if (arg.format[i] >= '0' && arg.format[i] <= '9')
107  break;
108  state = SPRINTF_LENGTH;
109  case SPRINTF_LENGTH:
110  if (strchr("hl", arg.format[i])) {
111  if (arg.format[i + 1] == arg.format[i])
112  i++;
113  state = SPRINTF_CONVERSION;
114  break;
115  } else if (strchr("Lqjzt", arg.format[i])) {
116  state = SPRINTF_CONVERSION;
117  break;
118  }
119  state = SPRINTF_CONVERSION;
120  case SPRINTF_CONVERSION:
121  if (strchr("diouxXc", arg.format[i])) {
122  /* Integer */
123 
124  /* Isolate this format alone */
125  ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
126  formatbuf[&arg.format[i] - formatstart + 1] = '\0';
127 
128  /* Convert the argument into the required type */
129  if (arg.var[argcount]) {
130  if (sscanf(arg.var[argcount++], "%30d", &tmpi) != 1) {
131  ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf);
132  goto sprintf_fail;
133  }
134  } else {
135  ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
136  goto sprintf_fail;
137  }
138 
139  /* Format the argument */
140  snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
141 
142  /* Update the position of the next parameter to print */
143  bufptr = strchr(buf, '\0');
144  } else if (strchr("eEfFgGaA", arg.format[i])) {
145  /* Double */
146 
147  /* Isolate this format alone */
148  ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
149  formatbuf[&arg.format[i] - formatstart + 1] = '\0';
150 
151  /* Convert the argument into the required type */
152  if (arg.var[argcount]) {
153  if (sscanf(arg.var[argcount++], "%30lf", &tmpd) != 1) {
154  ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf);
155  goto sprintf_fail;
156  }
157  } else {
158  ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
159  goto sprintf_fail;
160  }
161 
162  /* Format the argument */
163  snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
164 
165  /* Update the position of the next parameter to print */
166  bufptr = strchr(buf, '\0');
167  } else if (arg.format[i] == 's') {
168  /* String */
169 
170  /* Isolate this format alone */
171  ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
172  formatbuf[&arg.format[i] - formatstart + 1] = '\0';
173 
174  /* Format the argument */
175  snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
176 
177  /* Update the position of the next parameter to print */
178  bufptr = strchr(buf, '\0');
179  } else if (arg.format[i] == '%') {
180  /* Literal data to copy */
181  *bufptr++ = arg.format[i];
182  } else {
183  /* Not supported */
184 
185  /* Isolate this format alone */
186  ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
187  formatbuf[&arg.format[i] - formatstart + 1] = '\0';
188 
189  ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]);
190  goto sprintf_fail;
191  }
192  state = -1;
193  break;
194  default:
195  if (arg.format[i] == '%') {
196  state = SPRINTF_FLAG;
197  formatstart = &arg.format[i];
198  break;
199  } else {
200  /* Literal data to copy */
201  *bufptr++ = arg.format[i];
202  }
203  }
204  }
205  *bufptr = '\0';
206  return 0;
207 sprintf_fail:
208  return -1;
209 }
210 
212  .name = "SPRINTF",
213  .read = acf_sprintf,
214 };
215 
216 static int unload_module(void)
217 {
218  int res = 0;
219 
220  res |= ast_custom_function_unregister(&sprintf_function);
221 
222  return res;
223 }
224 
225 static int load_module(void)
226 {
227  int res = 0;
228 
229  res |= ast_custom_function_register(&sprintf_function);
230 
231  return res;
232 }
233 
234 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SPRINTF dialplan function");
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:81
Main Channel structure associated with a channel.
Definition: channel.h:742
#define SPRINTF_WIDTH
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
Asterisk main include file. File version handling, generic pbx functions.
static int load_module(void)
Definition: func_sprintf.c:225
#define SPRINTF_PRECISION
#define SPRINTF_CONVERSION
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define var
Definition: ast_expr2f.c:606
#define SPRINTF_LENGTH
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
Definition: pbx.c:3814
Utility functions.
#define SPRINTF_FLAG
General Asterisk PBX channel definitions.
static struct ast_custom_function sprintf_function
Definition: func_sprintf.c:211
Data structure associated with a custom dialplan function.
Definition: pbx.h:95
Core PBX routines and definitions.
#define LOG_ERROR
Definition: logger.h:155
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
static int unload_module(void)
Definition: func_sprintf.c:216
static struct ast_threadstorage result_buf
Definition: func_sprintf.c:44
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...
const char * name
Definition: pbx.h:96
#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 snd_pcm_format_t format
Definition: chan_alsa.c:93
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1164
static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: func_sprintf.c:67
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180