00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00035
00036 #include <ctype.h>
00037
00038 #include "asterisk/module.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/app.h"
00043
00044 AST_THREADSTORAGE(result_buf);
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067 static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00068 {
00069 #define SPRINTF_FLAG 0
00070 #define SPRINTF_WIDTH 1
00071 #define SPRINTF_PRECISION 2
00072 #define SPRINTF_LENGTH 3
00073 #define SPRINTF_CONVERSION 4
00074 int i, state = -1, argcount = 0;
00075 char *formatstart = NULL, *bufptr = buf;
00076 char formatbuf[256] = "";
00077 int tmpi;
00078 double tmpd;
00079 AST_DECLARE_APP_ARGS(arg,
00080 AST_APP_ARG(format);
00081 AST_APP_ARG(var)[100];
00082 );
00083
00084 AST_STANDARD_APP_ARGS(arg, data);
00085
00086
00087 for (i = 0; arg.format[i]; i++) {
00088 switch (state) {
00089 case SPRINTF_FLAG:
00090 if (strchr("#0- +'I", arg.format[i]))
00091 break;
00092 state = SPRINTF_WIDTH;
00093 case SPRINTF_WIDTH:
00094 if (arg.format[i] >= '0' && arg.format[i] <= '9')
00095 break;
00096
00097
00098 if (arg.format[i] == '.') {
00099 state = SPRINTF_PRECISION;
00100 } else {
00101 state = SPRINTF_LENGTH;
00102 i--;
00103 }
00104 break;
00105 case SPRINTF_PRECISION:
00106 if (arg.format[i] >= '0' && arg.format[i] <= '9')
00107 break;
00108 state = SPRINTF_LENGTH;
00109 case SPRINTF_LENGTH:
00110 if (strchr("hl", arg.format[i])) {
00111 if (arg.format[i + 1] == arg.format[i])
00112 i++;
00113 state = SPRINTF_CONVERSION;
00114 break;
00115 } else if (strchr("Lqjzt", arg.format[i])) {
00116 state = SPRINTF_CONVERSION;
00117 break;
00118 }
00119 state = SPRINTF_CONVERSION;
00120 case SPRINTF_CONVERSION:
00121 if (strchr("diouxXc", arg.format[i])) {
00122
00123
00124
00125 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00126 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00127
00128
00129 if (arg.var[argcount]) {
00130 if (sscanf(arg.var[argcount++], "%30d", &tmpi) != 1) {
00131 ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf);
00132 goto sprintf_fail;
00133 }
00134 } else {
00135 ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
00136 goto sprintf_fail;
00137 }
00138
00139
00140 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
00141
00142
00143 bufptr = strchr(buf, '\0');
00144 } else if (strchr("eEfFgGaA", arg.format[i])) {
00145
00146
00147
00148 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00149 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00150
00151
00152 if (arg.var[argcount]) {
00153 if (sscanf(arg.var[argcount++], "%30lf", &tmpd) != 1) {
00154 ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf);
00155 goto sprintf_fail;
00156 }
00157 } else {
00158 ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
00159 goto sprintf_fail;
00160 }
00161
00162
00163 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
00164
00165
00166 bufptr = strchr(buf, '\0');
00167 } else if (arg.format[i] == 's') {
00168
00169
00170
00171 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00172 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00173
00174
00175 snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
00176
00177
00178 bufptr = strchr(buf, '\0');
00179 } else if (arg.format[i] == '%') {
00180
00181 *bufptr++ = arg.format[i];
00182 } else {
00183
00184
00185
00186 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00187 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00188
00189 ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]);
00190 goto sprintf_fail;
00191 }
00192 state = -1;
00193 break;
00194 default:
00195 if (arg.format[i] == '%') {
00196 state = SPRINTF_FLAG;
00197 formatstart = &arg.format[i];
00198 break;
00199 } else {
00200
00201 *bufptr++ = arg.format[i];
00202 }
00203 }
00204 }
00205 *bufptr = '\0';
00206 return 0;
00207 sprintf_fail:
00208 return -1;
00209 }
00210
00211 static struct ast_custom_function sprintf_function = {
00212 .name = "SPRINTF",
00213 .read = acf_sprintf,
00214 };
00215
00216 static int unload_module(void)
00217 {
00218 int res = 0;
00219
00220 res |= ast_custom_function_unregister(&sprintf_function);
00221
00222 return res;
00223 }
00224
00225 static int load_module(void)
00226 {
00227 int res = 0;
00228
00229 res |= ast_custom_function_register(&sprintf_function);
00230
00231 return res;
00232 }
00233
00234 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SPRINTF dialplan function");