aboutsummaryrefslogtreecommitdiffstats
path: root/pbx.c
diff options
context:
space:
mode:
authorkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-09-29 04:39:14 +0000
committerkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2005-09-29 04:39:14 +0000
commit27aa525896fbc6cbb581621ea21eb5fc7088e225 (patch)
treef6fe9f3919725008c3aba76c1115525cba676c7c /pbx.c
parent7fa03f76b2f572f27887c4b56b7e4ab1111b16d4 (diff)
re-factor variable/function name parsing, and add substring support to function results (issue #5284)
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@6695 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'pbx.c')
-rwxr-xr-xpbx.c127
1 files changed, 86 insertions, 41 deletions
diff --git a/pbx.c b/pbx.c
index bdc9e6742..2b81d352d 100755
--- 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;