Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:47 2009

## 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: 211526 $")
    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 application 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 application 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, "%30f", &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, "%30d-%30d", &num1, &num2) == 2) {
    00210                /* range with both start and end */
    00211             } else if (sscanf(nextgroup, "-%30d", &num2) == 1) {
    00212                /* range with end */
    00213                num1 = 0;
    00214             } else if ((sscanf(nextgroup, "%30d%1c", &num1, &trashchar) == 2) && (trashchar == '-')) {
    00215                /* range with start */
    00216                num2 = MAXRESULT;
    00217             } else if (sscanf(nextgroup, "%30d", &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 }