re-factor variable/function name parsing, and add substring support to function resul...
authorKevin P. Fleming <kpfleming@digium.com>
Thu, 29 Sep 2005 04:39:14 +0000 (04:39 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Thu, 29 Sep 2005 04:39:14 +0000 (04:39 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6695 65c4cc65-6c06-0410-ace0-fbb531ad65f3

pbx.c

diff --git a/pbx.c b/pbx.c
index bdc9e67..2b81d35 100755 (executable)
--- a/pbx.c
+++ b/pbx.c
@@ -908,60 +908,102 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan, struct ast
        return NULL;
 }
 
+/* Note that it's negative -- that's important later. */
+#define DONT_HAVE_LENGTH       0x80000000
+
+static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
+{
+       char *varchar, *offsetchar = NULL;
+       int parens=0;
+
+       *offset = 0;
+       *length = DONT_HAVE_LENGTH;
+       *isfunc = 0;
+       for (varchar=var; *varchar; varchar++) {
+               switch (*varchar) {
+               case '(':
+                       (*isfunc)++;
+                       parens++;
+                       break;
+               case ')':
+                       parens--;
+                       break;
+               case ':':
+                       if (parens == 0) {
+                               offsetchar = varchar + 1;
+                               *varchar = '\0';
+                               goto pvn_endfor;
+                       }
+               }
+       }
+pvn_endfor:
+       if (offsetchar) {
+               sscanf(offsetchar, "%d:%d", offset, length);
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+static char *substring(char *value, int offset, int length, char *workspace, size_t workspace_len)
+{
+       char *ret = workspace;
+
+       /* No need to do anything */
+       if (offset == 0 && length==-1) {
+               return value;
+       }
+
+       ast_copy_string(workspace, value, workspace_len);
+
+       if (abs(offset) > strlen(ret)) {        /* Offset beyond string */
+               if (offset >= 0) 
+                       offset = strlen(ret);
+               else 
+                       offset =- strlen(ret);  
+       }
+
+       /* Detect too-long length */
+       if ((offset < 0 && length > -offset) || (offset >= 0 && offset+length > strlen(ret))) {
+               if (offset >= 0) 
+                       length = strlen(ret)-offset;
+               else 
+                       length = strlen(ret)+offset;
+       }
+
+       /* Bounce up to the right offset */
+       if (offset >= 0)
+               ret += offset;
+       else
+               ret += strlen(ret)+offset;
+
+       /* Chop off at the requisite length */
+       if (length >= 0)
+               ret[length] = '\0';
+
+       return ret;
+}
+
 /*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
       functions in the dialplan
   ---*/
 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
 {
-       char *first,*second;
        char tmpvar[80];
        time_t thistime;
        struct tm brokentime;
-       int offset,offset2;
+       int offset, offset2, isfunc;
        struct ast_var_t *variables;
 
        if (c) 
                headp=&c->varshead;
        *ret=NULL;
-       if ((first=strchr(var,':'))) {  /* : Remove characters counting from end or start of string */
-               ast_copy_string(tmpvar, var, sizeof(tmpvar));
-               first = strchr(tmpvar, ':');
-               if (!first)
-                       first = tmpvar + strlen(tmpvar);
-               *first='\0';
-               pbx_retrieve_variable(c,tmpvar,ret,workspace,workspacelen - 1, headp);
+       ast_copy_string(tmpvar, var, sizeof(tmpvar));
+       if (parse_variable_name(tmpvar, &offset, &offset2, &isfunc)) {
+               pbx_retrieve_variable(c, tmpvar, ret, workspace, workspacelen, headp);
                if (!(*ret)) 
                        return;
-               offset=atoi(first+1);   /* The number of characters, 
-                                          positive: remove # of chars from start
-                                          negative: keep # of chars from end */
-                                               
-               if ((second=strchr(first+1,':'))) {     
-                       *second='\0';
-                       offset2 = atoi(second+1);               /* Number of chars to copy */
-               } else if (offset >= 0) {
-                       offset2 = strlen(*ret)-offset;  /* Rest of string */
-               } else {
-                       offset2 = abs(offset);
-               }
-
-               if (abs(offset) > strlen(*ret)) {       /* Offset beyond string */
-                       if (offset >= 0) 
-                               offset = strlen(*ret);
-                       else 
-                               offset =- strlen(*ret); 
-               }
-               if ((offset < 0 && offset2 > -offset) || (offset >= 0 && offset+offset2 > strlen(*ret))) {
-                       if (offset >= 0) 
-                               offset2 = strlen(*ret)-offset;
-                       else 
-                               offset2 = strlen(*ret)+offset;
-               }
-               if (offset >= 0)
-                       *ret += offset;
-               else
-                       *ret += strlen(*ret)+offset;
-               (*ret)[offset2] = '\0';         /* Cut at offset2 position */
+               *ret = substring(*ret, offset, offset2, workspace, workspacelen);
        } else if (c && !strncmp(var, "CALL", 4)) {
                if (!strncmp(var + 4, "ER", 2)) {
                        if (!strncmp(var + 6, "ID", 2)) {
@@ -1386,7 +1428,7 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
 {
        char *cp4;
        const char *tmp, *whereweare;
-       int length;
+       int length, offset, offset2, isfunction;
        char *workspace = NULL;
        char *ltmp = NULL, *var = NULL;
        char *nextvar, *nextexp, *nextthing;
@@ -1477,7 +1519,8 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
 
                        workspace[0] = '\0';
 
-                       if (var[len - 1] == ')') {
+                       parse_variable_name(var, &offset, &offset2, &isfunction);
+                       if (isfunction) {
                                /* Evaluate function */
                                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE);
 
@@ -1487,6 +1530,8 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                                pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
                        }
                        if (cp4) {
+                               cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
+
                                length = strlen(cp4);
                                if (length > count)
                                        length = count;