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