Thu Oct 11 06:33:47 2012

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

Generated on Thu Oct 11 06:33:47 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6