Wed Apr 6 11:29:45 2011

Asterisk developer's documentation


func_cut.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (c) 2003-2006 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  * 
00020  * \brief CUT function
00021  *
00022  * \author Tilghman Lesher <app_cut__v003@the-tilghman.com>
00023  *
00024  * \ingroup functions
00025  */
00026 
00027 #include "asterisk.h"
00028 
00029 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211539 $")
00030 
00031 #include "asterisk/file.h"
00032 #include "asterisk/channel.h"
00033 #include "asterisk/pbx.h"
00034 #include "asterisk/module.h"
00035 #include "asterisk/app.h"
00036 
00037 /*** DOCUMENTATION
00038    <function name="SORT" language="en_US">
00039       <synopsis>
00040          Sorts a list of key/vals into a list of keys, based upon the vals.   
00041       </synopsis>
00042       <syntax>
00043          <parameter name="keyval" required="true" argsep=":">
00044             <argument name="key1" required="true" />
00045             <argument name="val1" required="true" />
00046          </parameter>
00047          <parameter name="keyvaln" multiple="true" argsep=":">
00048             <argument name="key2" required="true" />
00049             <argument name="val2" required="true" />
00050          </parameter>
00051       </syntax>
00052       <description>
00053          <para>Takes a comma-separated list of keys and values, each separated by a colon, and returns a
00054          comma-separated list of the keys, sorted by their values.  Values will be evaluated as
00055          floating-point numbers.</para>
00056       </description>
00057    </function>
00058    <function name="CUT" language="en_US">
00059       <synopsis>
00060          Slices and dices strings, based upon a named delimiter.     
00061       </synopsis>
00062       <syntax>
00063          <parameter name="varname" required="true">
00064             <para>Variable you want cut</para>
00065          </parameter>
00066          <parameter name="char-delim" required="true">
00067             <para>Delimiter, defaults to <literal>-</literal></para>
00068          </parameter>
00069          <parameter name="range-spec" required="true">
00070             <para>Number of the field you want (1-based offset), may also be specified as a range (with <literal>-</literal>)
00071             or group of ranges and fields (with <literal>&amp;</literal>)</para>
00072          </parameter>
00073       </syntax>
00074       <description>
00075          <para>Cut out information from a string (<replaceable>varname</replaceable>), based upon a named delimiter.</para>
00076       </description> 
00077    </function>
00078  ***/
00079 
00080 struct sortable_keys {
00081    char *key;
00082    float value;
00083 };
00084 
00085 static int sort_subroutine(const void *arg1, const void *arg2)
00086 {
00087    const struct sortable_keys *one=arg1, *two=arg2;
00088    if (one->value < two->value)
00089       return -1;
00090    else if (one->value == two->value)
00091       return 0;
00092    else
00093       return 1;
00094 }
00095 
00096 #define ERROR_NOARG  (-1)
00097 #define ERROR_NOMEM  (-2)
00098 #define ERROR_USAGE  (-3)
00099 
00100 static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen)
00101 {
00102    char *strings, *ptrkey, *ptrvalue;
00103    int count=1, count2, element_count=0;
00104    struct sortable_keys *sortable_keys;
00105 
00106    *buffer = '\0';
00107 
00108    if (!data)
00109       return ERROR_NOARG;
00110 
00111    strings = ast_strdupa(data);
00112 
00113    for (ptrkey = strings; *ptrkey; ptrkey++) {
00114       if (*ptrkey == ',')
00115          count++;
00116    }
00117 
00118    sortable_keys = alloca(count * sizeof(struct sortable_keys));
00119 
00120    memset(sortable_keys, 0, count * sizeof(struct sortable_keys));
00121 
00122    /* Parse each into a struct */
00123    count2 = 0;
00124    while ((ptrkey = strsep(&strings, ","))) {
00125       ptrvalue = strchr(ptrkey, ':');
00126       if (!ptrvalue) {
00127          count--;
00128          continue;
00129       }
00130       *ptrvalue++ = '\0';
00131       sortable_keys[count2].key = ptrkey;
00132       sscanf(ptrvalue, "%30f", &sortable_keys[count2].value);
00133       count2++;
00134    }
00135 
00136    /* Sort the structs */
00137    qsort(sortable_keys, count, sizeof(struct sortable_keys), sort_subroutine);
00138 
00139    for (count2 = 0; count2 < count; count2++) {
00140       int blen = strlen(buffer);
00141       if (element_count++) {
00142          strncat(buffer + blen, ",", buflen - blen - 1);
00143          blen++;
00144       }
00145       strncat(buffer + blen, sortable_keys[count2].key, buflen - blen - 1);
00146    }
00147 
00148    return 0;
00149 }
00150 
00151 static int cut_internal(struct ast_channel *chan, char *data, struct ast_str **buf, ssize_t buflen)
00152 {
00153    char *parse, ds[2], *var_expr;
00154    size_t delim_consumed;
00155    struct ast_str *var_value;
00156    AST_DECLARE_APP_ARGS(args,
00157       AST_APP_ARG(varname);
00158       AST_APP_ARG(delimiter);
00159       AST_APP_ARG(field);
00160    );
00161 
00162    parse = ast_strdupa(data);
00163 
00164    AST_STANDARD_APP_ARGS(args, parse);
00165 
00166    /* Check arguments */
00167    if (args.argc < 3) {
00168       return ERROR_NOARG;
00169    } else if (!(var_expr = alloca(strlen(args.varname) + 4))) {
00170       return ERROR_NOMEM;
00171    }
00172 
00173    /* Get the value of the variable named in the 1st argument */
00174    snprintf(var_expr, strlen(args.varname) + 4, "${%s}", args.varname);
00175    var_value = ast_str_create(16);
00176    ast_str_substitute_variables(&var_value, 0, chan, var_expr);
00177 
00178    /* Copy delimiter from 2nd argument to ds[] possibly decoding backslash escapes */
00179    if (ast_get_encoded_char(args.delimiter, ds, &delim_consumed)) {
00180       ast_copy_string(ds, "-", sizeof(ds));
00181    }
00182    ds[1] = '\0';
00183 
00184    if (ast_str_strlen(var_value)) {
00185       int curfieldnum = 1;
00186       char *curfieldptr = ast_str_buffer(var_value);
00187       int out_field_count = 0;
00188 
00189       while (curfieldptr != NULL && args.field != NULL) {
00190          char *next_range = strsep(&(args.field), "&");
00191          int start_field, stop_field;
00192          char trashchar;
00193 
00194          if (sscanf(next_range, "%30d-%30d", &start_field, &stop_field) == 2) {
00195             /* range with both start and end */
00196          } else if (sscanf(next_range, "-%30d", &stop_field) == 1) {
00197             /* range with end only */
00198             start_field = 1;
00199          } else if ((sscanf(next_range, "%30d%1c", &start_field, &trashchar) == 2) && (trashchar == '-')) {
00200             /* range with start only */
00201             stop_field = INT_MAX;
00202          } else if (sscanf(next_range, "%30d", &start_field) == 1) {
00203             /* single number */
00204             stop_field = start_field;
00205          } else {
00206             /* invalid field spec */
00207             ast_free(var_value);
00208             return ERROR_USAGE;
00209          }
00210 
00211          /* Get to start, if not there already */
00212          while (curfieldptr != NULL && curfieldnum < start_field) {
00213             strsep(&curfieldptr, ds);
00214             curfieldnum++;
00215          }
00216 
00217          /* Most frequent problem is the expectation of reordering fields */
00218          if (curfieldnum > start_field) {
00219             ast_log(LOG_WARNING, "We're already past the field you wanted?\n");
00220          }
00221 
00222          /* Output fields until we either run out of fields or stop_field is reached */
00223          while (curfieldptr != NULL && curfieldnum <= stop_field) {
00224             char *field_value = strsep(&curfieldptr, ds);
00225             ast_str_append(buf, buflen, "%s%s", out_field_count++ ? ds : "", field_value);
00226             curfieldnum++;
00227          }
00228       }
00229    }
00230    ast_free(var_value);
00231    return 0;
00232 }
00233 
00234 static int acf_sort_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00235 {
00236    int ret = -1;
00237 
00238    switch (sort_internal(chan, data, buf, len)) {
00239    case ERROR_NOARG:
00240       ast_log(LOG_ERROR, "SORT() requires an argument\n");
00241       break;
00242    case ERROR_NOMEM:
00243       ast_log(LOG_ERROR, "Out of memory\n");
00244       break;
00245    case 0:
00246       ret = 0;
00247       break;
00248    default:
00249       ast_log(LOG_ERROR, "Unknown internal error\n");
00250    }
00251 
00252    return ret;
00253 }
00254 
00255 static int acf_cut_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00256 {
00257    int ret = -1;
00258    struct ast_str *str = ast_str_create(16);
00259 
00260    switch (cut_internal(chan, data, &str, len)) {
00261    case ERROR_NOARG:
00262       ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
00263       break;
00264    case ERROR_NOMEM:
00265       ast_log(LOG_ERROR, "Out of memory\n");
00266       break;
00267    case ERROR_USAGE:
00268       ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n");
00269       break;
00270    case 0:
00271       ret = 0;
00272       ast_copy_string(buf, ast_str_buffer(str), len);
00273       break;
00274    default:
00275       ast_log(LOG_ERROR, "Unknown internal error\n");
00276    }
00277    ast_free(str);
00278    return ret;
00279 }
00280 
00281 static int acf_cut_exec2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00282 {
00283    int ret = -1;
00284 
00285    switch (cut_internal(chan, data, buf, len)) {
00286    case ERROR_NOARG:
00287       ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n");
00288       break;
00289    case ERROR_NOMEM:
00290       ast_log(LOG_ERROR, "Out of memory\n");
00291       break;
00292    case ERROR_USAGE:
00293       ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n");
00294       break;
00295    case 0:
00296       ret = 0;
00297       break;
00298    default:
00299       ast_log(LOG_ERROR, "Unknown internal error\n");
00300    }
00301 
00302    return ret;
00303 }
00304 
00305 static struct ast_custom_function acf_sort = {
00306    .name = "SORT",
00307    .read = acf_sort_exec,
00308 };
00309 
00310 static struct ast_custom_function acf_cut = {
00311    .name = "CUT",
00312    .read = acf_cut_exec,
00313    .read2 = acf_cut_exec2,
00314 };
00315 
00316 static int unload_module(void)
00317 {
00318    int res = 0;
00319 
00320    res |= ast_custom_function_unregister(&acf_cut);
00321    res |= ast_custom_function_unregister(&acf_sort);
00322 
00323    return res;
00324 }
00325 
00326 static int load_module(void)
00327 {
00328    int res = 0;
00329 
00330    res |= ast_custom_function_register(&acf_cut);
00331    res |= ast_custom_function_register(&acf_sort);
00332 
00333    return res;
00334 }
00335 
00336 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Cut out information from a string");

Generated on Wed Apr 6 11:29:45 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7