Thu Apr 28 2011 17:15:22

Asterisk developer's documentation


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 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211580 $")
00031 
00032 #include <ctype.h>
00033 
00034 #include "asterisk/module.h"
00035 #include "asterisk/channel.h"
00036 #include "asterisk/pbx.h"
00037 #include "asterisk/utils.h"
00038 #include "asterisk/app.h"
00039 
00040 AST_THREADSTORAGE(result_buf);
00041 
00042 /*** DOCUMENTATION
00043    <function name="SPRINTF" language="en_US">
00044       <synopsis>
00045          Format a variable according to a format string.
00046       </synopsis>
00047       <syntax>
00048          <parameter name="format" required="true" />
00049          <parameter name="arg1" required="true" />
00050          <parameter name="arg2" multiple="true" />
00051          <parameter name="argN" />
00052       </syntax>
00053       <description>
00054          <para>Parses the format string specified and returns a string matching 
00055          that format. Supports most options found in <emphasis>sprintf(3)</emphasis>.
00056          Returns a shortened string if a format specifier is not recognized.</para>
00057       </description>
00058       <see-also>
00059          <ref type="manpage">sprintf(3)</ref>
00060       </see-also>
00061    </function>
00062  ***/
00063 static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00064 {
00065 #define SPRINTF_FLAG 0
00066 #define SPRINTF_WIDTH   1
00067 #define SPRINTF_PRECISION  2
00068 #define SPRINTF_LENGTH  3
00069 #define SPRINTF_CONVERSION 4
00070    int i, state = -1, argcount = 0;
00071    char *formatstart = NULL, *bufptr = buf;
00072    char formatbuf[256] = "";
00073    int tmpi;
00074    double tmpd;
00075    AST_DECLARE_APP_ARGS(arg,
00076             AST_APP_ARG(format);
00077             AST_APP_ARG(var)[100];
00078    );
00079 
00080    AST_STANDARD_APP_ARGS(arg, data);
00081 
00082    /* Scan the format, converting each argument into the requisite format type. */
00083    for (i = 0; arg.format[i]; i++) {
00084       switch (state) {
00085       case SPRINTF_FLAG:
00086          if (strchr("#0- +'I", arg.format[i]))
00087             break;
00088          state = SPRINTF_WIDTH;
00089       case SPRINTF_WIDTH:
00090          if (arg.format[i] >= '0' && arg.format[i] <= '9')
00091             break;
00092 
00093          /* Next character must be a period to go into a precision */
00094          if (arg.format[i] == '.') {
00095             state = SPRINTF_PRECISION;
00096          } else {
00097             state = SPRINTF_LENGTH;
00098             i--;
00099          }
00100          break;
00101       case SPRINTF_PRECISION:
00102          if (arg.format[i] >= '0' && arg.format[i] <= '9')
00103             break;
00104          state = SPRINTF_LENGTH;
00105       case SPRINTF_LENGTH:
00106          if (strchr("hl", arg.format[i])) {
00107             if (arg.format[i + 1] == arg.format[i])
00108                i++;
00109             state = SPRINTF_CONVERSION;
00110             break;
00111          } else if (strchr("Lqjzt", arg.format[i])) {
00112             state = SPRINTF_CONVERSION;
00113             break;
00114          }
00115          state = SPRINTF_CONVERSION;
00116       case SPRINTF_CONVERSION:
00117          if (strchr("diouxXc", arg.format[i])) {
00118             /* Integer */
00119 
00120             /* Isolate this format alone */
00121             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00122             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00123 
00124             /* Convert the argument into the required type */
00125             if (arg.var[argcount]) {
00126                if (sscanf(arg.var[argcount++], "%30d", &tmpi) != 1) {
00127                   ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf);
00128                   goto sprintf_fail;
00129                }
00130             } else {
00131                ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
00132                goto sprintf_fail;
00133             }
00134 
00135             /* Format the argument */
00136             snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
00137 
00138             /* Update the position of the next parameter to print */
00139             bufptr = strchr(buf, '\0');
00140          } else if (strchr("eEfFgGaA", arg.format[i])) {
00141             /* Double */
00142 
00143             /* Isolate this format alone */
00144             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00145             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00146 
00147             /* Convert the argument into the required type */
00148             if (arg.var[argcount]) {
00149                if (sscanf(arg.var[argcount++], "%30lf", &tmpd) != 1) {
00150                   ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf);
00151                   goto sprintf_fail;
00152                }
00153             } else {
00154                ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
00155                goto sprintf_fail;
00156             }
00157 
00158             /* Format the argument */
00159             snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
00160 
00161             /* Update the position of the next parameter to print */
00162             bufptr = strchr(buf, '\0');
00163          } else if (arg.format[i] == 's') {
00164             /* String */
00165 
00166             /* Isolate this format alone */
00167             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00168             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00169 
00170             /* Format the argument */
00171             snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
00172 
00173             /* Update the position of the next parameter to print */
00174             bufptr = strchr(buf, '\0');
00175          } else if (arg.format[i] == '%') {
00176             /* Literal data to copy */
00177             *bufptr++ = arg.format[i];
00178          } else {
00179             /* Not supported */
00180 
00181             /* Isolate this format alone */
00182             ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00183             formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00184 
00185             ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]);
00186             goto sprintf_fail;
00187          }
00188          state = -1;
00189          break;
00190       default:
00191          if (arg.format[i] == '%') {
00192             state = SPRINTF_FLAG;
00193             formatstart = &arg.format[i];
00194             break;
00195          } else {
00196             /* Literal data to copy */
00197             *bufptr++ = arg.format[i];
00198          }
00199       }
00200    }
00201    *bufptr = '\0';
00202    return 0;
00203 sprintf_fail:
00204    return -1;
00205 }
00206 
00207 static struct ast_custom_function sprintf_function = {
00208    .name = "SPRINTF",
00209    .read = acf_sprintf,
00210 };
00211 
00212 static int unload_module(void)
00213 {
00214    int res = 0;
00215 
00216    res |= ast_custom_function_unregister(&sprintf_function);
00217 
00218    return res;
00219 }
00220 
00221 static int load_module(void)
00222 {
00223    int res = 0;
00224 
00225    res |= ast_custom_function_register(&sprintf_function);
00226 
00227    return res;
00228 }
00229 
00230 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SPRINTF dialplan function");