Sat Mar 24 22:55:11 2007

Asterisk developer's documentation


app_cut.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (c) 2003 Tilghman Lesher.  All rights reserved.
00005  *
00006  * Tilghman Lesher <app_cut__v003@the-tilghman.com>
00007  *
00008  * This code is released by the author with no restrictions on usage.
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  */
00017 
00018 /*! \file
00019  * \brief Cut application
00020  *
00021  * \ingroup applications
00022  */
00023 
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <string.h>
00028 
00029 #include "asterisk.h"
00030 
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 7497 $")
00032 
00033 #include "asterisk/file.h"
00034 #include "asterisk/logger.h"
00035 #include "asterisk/options.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/app.h"
00040 
00041 /* Maximum length of any variable */
00042 #define MAXRESULT 1024
00043 
00044 static char *tdesc = "Cut out information from a string";
00045 
00046 static char *app_cut = "Cut";
00047 
00048 static char *cut_synopsis = "Splits a variable's contents using the specified delimiter";
00049 
00050 static char *cut_descrip =
00051 "  Cut(newvar=varname,delimiter,fieldspec): This applicaiton will split the\n"
00052 "contents of a variable based on the given delimeter and store the result in\n"
00053 "a new variable.\n"
00054 "Parameters:\n"
00055 "  newvar    - new variable created from result string\n"
00056 "  varname   - variable you want cut\n"
00057 "  delimiter - defaults to '-'\n"
00058 "  fieldspec - number of the field you want (1-based offset)\n"
00059 "              may also be specified as a range (with -)\n"
00060 "              or group of ranges and fields (with &)\n"
00061 "This application has been deprecated in favor of the CUT function.\n";
00062 
00063 static char *app_sort = "Sort";
00064 static char *app_sort_synopsis = "Sorts a list of keywords and values";
00065 static char *app_sort_descrip =
00066 "  Sort(newvar=key1:val1[,key2:val2[[...],keyN:valN]]): This application will\n"
00067 "sort the list provided in ascending order. The result will be stored in the\n"
00068 "specified variable name.\n"
00069 "  This applicaiton has been deprecated in favor of the SORT function.\n";
00070 
00071 STANDARD_LOCAL_USER;
00072 
00073 LOCAL_USER_DECL;
00074 
00075 struct sortable_keys {
00076    char *key;
00077    float value;
00078 };
00079 
00080 static int sort_subroutine(const void *arg1, const void *arg2)
00081 {
00082    const struct sortable_keys *one=arg1, *two=arg2;
00083    if (one->value < two->value) {
00084       return -1;
00085    } else if (one->value == two->value) {
00086       return 0;
00087    } else {
00088       return 1;
00089    }
00090 }
00091 
00092 #define ERROR_NOARG  (-1)
00093 #define ERROR_NOMEM  (-2)
00094 #define ERROR_USAGE  (-3)
00095 
00096 static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
00097 {
00098    char *strings, *ptrkey, *ptrvalue;
00099    int count=1, count2, element_count=0;
00100    struct sortable_keys *sortable_keys;
00101 
00102    memset(buffer, 0, buflen);
00103 
00104    if (!data) {
00105       return ERROR_NOARG;
00106    }
00107 
00108    strings = ast_strdupa((char *)data);
00109    if (!strings) {
00110       return ERROR_NOMEM;
00111    }
00112 
00113    for (ptrkey = strings; *ptrkey; ptrkey++) {
00114       if (*ptrkey == '|') {
00115          count++;
00116       }
00117    }
00118 
00119    sortable_keys = alloca(count * sizeof(struct sortable_keys));
00120    if (!sortable_keys) {
00121       return ERROR_NOMEM;
00122    }
00123 
00124    memset(sortable_keys, 0, count * sizeof(struct sortable_keys));
00125 
00126    /* Parse each into a struct */
00127    count2 = 0;
00128    while ((ptrkey = strsep(&strings, "|"))) {
00129       ptrvalue = index(ptrkey, ':');
00130       if (!ptrvalue) {
00131          count--;
00132          continue;
00133       }
00134       *ptrvalue = '\0';
00135       ptrvalue++;
00136       sortable_keys[count2].key = ptrkey;
00137       sscanf(ptrvalue, "%f", &sortable_keys[count2].value);
00138       count2++;
00139    }
00140 
00141    /* Sort the structs */
00142    qsort(sortable_keys, count, sizeof(struct sortable_keys), sort_subroutine);
00143 
00144    for (count2 = 0; count2 < count; count2++) {
00145       int blen = strlen(buffer);
00146       if (element_count++) {
00147          strncat(buffer + blen, ",", buflen - blen - 1);
00148          blen++;
00149       }
00150       strncat(buffer + blen, sortable_keys[count2].key, buflen - blen - 1);
00151    }
00152 
00153    return 0;
00154 }
00155 
00156 static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
00157 {
00158    char *s, *args[3], *varname=NULL, *delimiter=NULL, *field=NULL;
00159    int args_okay = 0;
00160 
00161    memset(buffer, 0, buflen);
00162 
00163    /* Check and parse arguments */
00164    if (data) {
00165       s = ast_strdupa((char *)data);
00166       if (s) {
00167          ast_app_separate_args(s, '|', args, 3);
00168          varname = args[0];
00169          delimiter = args[1];
00170          field = args[2];
00171 
00172          if (field) {
00173             args_okay = 1;
00174          }
00175       } else {
00176          return ERROR_NOMEM;
00177       }
00178    }
00179 
00180    if (args_okay) {
00181       char d, ds[2];
00182       char *tmp = alloca(strlen(varname) + 4);
00183       char varvalue[MAXRESULT], *tmp2=varvalue;
00184 
00185       if (tmp) {
00186          snprintf(tmp, strlen(varname) + 4, "${%s}", varname);
00187          memset(varvalue, 0, sizeof(varvalue));
00188       } else {
00189          return ERROR_NOMEM;
00190       }
00191 
00192       if (delimiter[0])
00193          d = delimiter[0];
00194       else
00195          d = '-';
00196 
00197       /* String form of the delimiter, for use with strsep(3) */
00198       snprintf(ds, sizeof(ds), "%c", d);
00199 
00200       pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1);
00201 
00202       if (tmp2) {
00203          int curfieldnum = 1;
00204          while ((tmp2 != NULL) && (field != NULL)) {
00205             char *nextgroup = strsep(&field, "&");
00206             int num1 = 0, num2 = MAXRESULT;
00207             char trashchar;
00208 
00209             if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) {
00210                /* range with both start and end */
00211             } else if (sscanf(nextgroup, "-%d", &num2) == 1) {
00212                /* range with end */
00213                num1 = 0;
00214             } else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) {
00215                /* range with start */
00216                num2 = MAXRESULT;
00217             } else if (sscanf(nextgroup, "%d", &num1) == 1) {
00218                /* single number */
00219                num2 = num1;
00220             } else {
00221                return ERROR_USAGE;
00222             }
00223 
00224             /* Get to start, if any */
00225             if (num1 > 0) {
00226                while ((tmp2 != (char *)NULL + 1) && (curfieldnum < num1)) {
00227                   tmp2 = index(tmp2, d) + 1;
00228                   curfieldnum++;
00229                }
00230             }
00231 
00232             /* Most frequent problem is the expectation of reordering fields */
00233             if ((num1 > 0) && (curfieldnum > num1)) {
00234                ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
00235             }
00236 
00237             /* Re-null tmp2 if we added 1 to NULL */
00238             if (tmp2 == (char *)NULL + 1)
00239                tmp2 = NULL;
00240 
00241             /* Output fields until we either run out of fields or num2 is reached */
00242             while ((tmp2 != NULL) && (curfieldnum <= num2)) {
00243                char *tmp3 = strsep(&tmp2, ds);
00244                int curlen = strlen(buffer);
00245 
00246                if (curlen) {
00247                   snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3);
00248                } else {
00249                   snprintf(buffer, buflen, "%s", tmp3);
00250                }
00251 
00252                curfieldnum++;
00253             }
00254          }
00255       }
00256    } else {
00257       return ERROR_NOARG;
00258    }
00259    return 0;
00260 }
00261 
00262 static int sort_exec(struct ast_channel *chan, void *data)
00263 {
00264    int res=0;
00265    struct localuser *u;
00266    char *varname, *strings, result[512] = "";
00267    static int dep_warning=0;
00268 
00269    if (!dep_warning) {
00270       ast_log(LOG_WARNING, "The application Sort is deprecated.  Please use the SORT() function instead.\n");
00271       dep_warning=1;
00272    }
00273 
00274    if (!data) {
00275       ast_log(LOG_ERROR, "Sort() requires an argument\n");
00276       return 0;
00277    }
00278 
00279    LOCAL_USER_ADD(u);
00280 
00281    strings = ast_strdupa((char *)data);
00282    if (!strings) {
00283       ast_log(LOG_ERROR, "Out of memory\n");
00284       LOCAL_USER_REMOVE(u);
00285       return 0;
00286    }
00287 
00288    varname = strsep(&strings, "=");
00289    switch (sort_internal(chan, strings, result, sizeof(result))) {
00290    case ERROR_NOARG:
00291       ast_log(LOG_ERROR, "Sort() requires an argument\n");
00292       res = 0;
00293       break;
00294    case ERROR_NOMEM:
00295       ast_log(LOG_ERROR, "Out of memory\n");
00296       res = -1;
00297       break;
00298    case 0:
00299       pbx_builtin_setvar_helper(chan, varname, result);
00300       res = 0;
00301       break;
00302    default:
00303       ast_log(LOG_ERROR, "Unknown internal error\n");
00304       res = -1;
00305    }
00306    LOCAL_USER_REMOVE(u);
00307    return res;
00308 }
00309 
00310 static int cut_exec(struct ast_channel *chan, void *data)
00311 {
00312    int res=0;
00313    struct localuser *u;
00314    char *s, *newvar=NULL, result[512];
00315    static int dep_warning = 0;
00316 
00317    LOCAL_USER_ADD(u);
00318 
00319    if (!dep_warning) {
00320       ast_log(LOG_WARNING, "The application Cut is deprecated.  Please use the CUT() function instead.\n");
00321       dep_warning=1;
00322    }
00323 
00324    /* Check and parse arguments */
00325    if (data) {
00326       s = ast_strdupa((char *)data);
00327       if (s) {
00328          newvar = strsep(&s, "=");
00329       } else {
00330          ast_log(LOG_ERROR, "Out of memory\n");
00331          LOCAL_USER_REMOVE(u);
00332          return -1;
00333       }
00334    }
00335 
00336    switch (cut_internal(chan, s, result, sizeof(result))) {
00337    case ERROR_NOARG:
00338       ast_log(LOG_ERROR, "Cut() requires an argument\n");
00339       res = 0;
00340       break;
00341    case ERROR_NOMEM:
00342       ast_log(LOG_ERROR, "Out of memory\n");
00343       res = -1;
00344       break;
00345    case ERROR_USAGE:
00346       ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
00347       res = 0;
00348       break;
00349    case 0:
00350       pbx_builtin_setvar_helper(chan, newvar, result);
00351       res = 0;
00352       break;
00353    default:
00354       ast_log(LOG_ERROR, "Unknown internal error\n");
00355       res = -1;
00356    }
00357    LOCAL_USER_REMOVE(u);
00358    return res;
00359 }
00360 
00361 static char *acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
00362 {
00363    struct localuser *u;
00364 
00365    LOCAL_USER_ACF_ADD(u);
00366 
00367    switch (sort_internal(chan, data, buf, len)) {
00368    case ERROR_NOARG:
00369       ast_log(LOG_ERROR, "SORT() requires an argument\n");
00370       break;
00371    case ERROR_NOMEM:
00372       ast_log(LOG_ERROR, "Out of memory\n");
00373       break;
00374    case 0:
00375       break;
00376    default:
00377       ast_log(LOG_ERROR, "Unknown internal error\n");
00378    }
00379    LOCAL_USER_REMOVE(u);
00380    return buf;
00381 }
00382 
00383 static char *acf_cut_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
00384 {
00385    struct localuser *u;
00386 
00387    LOCAL_USER_ACF_ADD(u);
00388 
00389    switch (cut_internal(chan, data, buf, len)) {
00390    case ERROR_NOARG:
00391       ast_log(LOG_ERROR, "CUT() requires an argument\n");
00392       break;
00393    case ERROR_NOMEM:
00394       ast_log(LOG_ERROR, "Out of memory\n");
00395       break;
00396    case ERROR_USAGE:
00397       ast_log(LOG_ERROR, "Usage: %s\n", cut_synopsis);
00398       break;
00399    case 0:
00400       break;
00401    default:
00402       ast_log(LOG_ERROR, "Unknown internal error\n");
00403    }
00404    LOCAL_USER_REMOVE(u);
00405    return buf;
00406 }
00407 
00408 struct ast_custom_function acf_sort = {
00409    .name = "SORT",
00410    .synopsis = "Sorts a list of key/vals into a list of keys, based upon the vals",
00411    .syntax = "SORT(key1:val1[...][,keyN:valN])",
00412    .desc =
00413 "Takes a comma-separated list of keys and values, each separated by a colon, and returns a\n"
00414 "comma-separated list of the keys, sorted by their values.  Values will be evaluated as\n"
00415 "floating-point numbers.\n",
00416    .read = acf_sort_exec,
00417 };
00418 
00419 struct ast_custom_function acf_cut = {
00420    .name = "CUT",
00421    .synopsis = "Slices and dices strings, based upon a named delimiter.",
00422    .syntax = "CUT(<varname>,<char-delim>,<range-spec>)",
00423    .desc =
00424 "  varname    - variable you want cut\n"
00425 "  char-delim - defaults to '-'\n"
00426 "  range-spec - number of the field you want (1-based offset)\n"
00427 "             may also be specified as a range (with -)\n"
00428 "             or group of ranges and fields (with &)\n",
00429    .read = acf_cut_exec,
00430 };
00431 
00432 int unload_module(void)
00433 {
00434    int res;
00435 
00436    res = ast_custom_function_unregister(&acf_cut);
00437    res |= ast_custom_function_unregister(&acf_sort);
00438    res |= ast_unregister_application(app_sort);
00439    res |= ast_unregister_application(app_cut);
00440 
00441    STANDARD_HANGUP_LOCALUSERS;
00442 
00443    return res;
00444 }
00445 
00446 int load_module(void)
00447 {
00448    int res;
00449 
00450    res = ast_custom_function_register(&acf_cut);
00451    res |= ast_custom_function_register(&acf_sort);
00452    res |= ast_register_application(app_sort, sort_exec, app_sort_synopsis, app_sort_descrip);
00453    res |= ast_register_application(app_cut, cut_exec, cut_synopsis, cut_descrip);
00454 
00455    return res;
00456 }
00457 
00458 char *description(void)
00459 {
00460    return tdesc;
00461 }
00462 
00463 int usecount(void)
00464 {
00465    int res;
00466    STANDARD_USECOUNT(res);
00467    return res;
00468 }
00469 
00470 char *key()
00471 {
00472    return ASTERISK_GPL_KEY;
00473 }

Generated on Sat Mar 24 22:55:11 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7