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