Index: pbx.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx.c,v retrieving revision 1.281 diff -u -r1.281 pbx.c --- pbx.c 26 Sep 2005 19:51:58 -0000 1.281 +++ pbx.c 28 Sep 2005 17:22:42 -0000 @@ -908,60 +908,102 @@ 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 +1448,7 @@ { 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 +1539,8 @@ 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 +1549,8 @@ 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;