func_sprintf.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005-2006, Digium, Inc.
00005  * Portions Copyright (C) 2005, Tilghman Lesher.  All rights reserved.
00006  * Portions Copyright (C) 2005, Anthony Minessale II
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief String manipulation dialplan functions
00022  *
00023  * \author Tilghman Lesher
00024  * \author Anothony Minessale II 
00025  * \ingroup functions
00026  */
00027 
00028 /*** MODULEINFO
00029    <support_level>core</support_level>
00030  ***/
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328259 $")
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 /*** DOCUMENTATION
00047    <function name="SPRINTF" language="en_US">
00048       <synopsis>
00049          Format a variable according to a format string.
00050       </synopsis>
00051       <syntax>
00052          <parameter name="format" required="true" />
00053          <parameter name="arg1" required="true" />
00054          <parameter name="arg2" multiple="true" />
00055          <parameter name="argN" />
00056       </syntax>
00057       <description>
00058          <para>Parses the format string specified and returns a string matching 
00059          that format. Supports most options found in <emphasis>sprintf(3)</emphasis>.
00060          Returns a shortened string if a format specifier is not recognized.</para>
00061       </description>
00062       <see-also>
00063          <ref type="manpage">sprintf(3)</ref>
00064       </see-also>
00065    </function>
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    /* Scan the format, converting each argument into the requisite format type. */
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          /* Next character must be a period to go into a precision */
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             /* Integer */
00123 
00124             /* Isolate this format alone */
00125             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00126             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00127 
00128             /* Convert the argument into the required type */
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             /* Format the argument */
00140             snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
00141 
00142             /* Update the position of the next parameter to print */
00143             bufptr = strchr(buf, '\0');
00144          } else if (strchr("eEfFgGaA", arg.format[i])) {
00145             /* Double */
00146 
00147             /* Isolate this format alone */
00148             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00149             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00150 
00151             /* Convert the argument into the required type */
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             /* Format the argument */
00163             snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
00164 
00165             /* Update the position of the next parameter to print */
00166             bufptr = strchr(buf, '\0');
00167          } else if (arg.format[i] == 's') {
00168             /* String */
00169 
00170             /* Isolate this format alone */
00171             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00172             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00173 
00174             /* Format the argument */
00175             snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
00176 
00177             /* Update the position of the next parameter to print */
00178             bufptr = strchr(buf, '\0');
00179          } else if (arg.format[i] == '%') {
00180             /* Literal data to copy */
00181             *bufptr++ = arg.format[i];
00182          } else {
00183             /* Not supported */
00184 
00185             /* Isolate this format alone */
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             /* Literal data to copy */
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");

Generated on Thu Apr 16 06:27:36 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6