Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:55 2009

## Asterisk developer's documentation

# pbx_ael.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2005, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  */
    00018
    00019 /*! \file
    00020  *
    00021  * \brief Compile symbolic Asterisk Extension Logic into Asterisk extensions
    00022  *
    00023  */
    00024
    00025 #include <sys/types.h>
    00026 #include <stdlib.h>
    00027 #include <stdio.h>
    00028 #include <string.h>
    00029 #include <ctype.h>
    00030 #include <errno.h>
    00031
    00032 #include "asterisk.h"
    00033
    00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 45134 $")
    00035
    00036 #include "asterisk/pbx.h"
    00037 #include "asterisk/config.h"
    00038 #include "asterisk/module.h"
    00039 #include "asterisk/logger.h"
    00040 #include "asterisk/cli.h"
    00041 #include "asterisk/callerid.h"
    00042
    00043 struct stringlink {
    00044    struct stringlink *next;
    00045    char data[0];
    00046 };
    00047
    00048 #define FILLIN_BREAK    1
    00049 #define FILLIN_CONTINUE    2
    00050
    00051 struct fillin {
    00052    struct fillin *next;
    00053    char exten[AST_MAX_EXTENSION];
    00054    int priority;
    00055    int type;
    00056 };
    00057
    00058 #ifdef __AST_DEBUG_MALLOC
    00059 static void FREE(void *ptr)
    00060 {
    00061    free(ptr);
    00062 }
    00063 #else
    00064 #define FREE free
    00065 #endif
    00066
    00067 #define DEBUG_READ   (1 << 0)
    00068 #define DEBUG_TOKENS (1 << 1)
    00069 #define DEBUG_MACROS (1 << 2)
    00070 #define DEBUG_CONTEXTS (1 << 3)
    00071
    00072 static int aeldebug = 0;
    00073
    00074 static char *dtext = "Asterisk Extension Language Compiler";
    00075 static char *config = "extensions.ael";
    00076 static char *registrar = "pbx_ael";
    00077
    00078 static char *__grab_token(char *src, const char *filename, int lineno, int link)
    00079 {
    00080    char *c;
    00081    char *b;
    00082    char *a;
    00083    int level = 0;
    00084    char *ret;
    00085 #if 0
    00086    if (aeldebug || DEBUG_TOKENS)
    00087       ast_verbose("Searching for token in '%s'!\n", src);
    00088 #endif
    00089    c = src;
    00090    while(*c) {
    00091       if ((*c == '\\')) {
    00092          c++;
    00093          if (!*c)
    00094             c--;
    00095       } else {
    00096          if ((*c == '{') || (*c == '(')) {
    00097             level++;
    00098          } else if ((*c == '}') || (*c == ')')) {
    00099             if (level)
    00100                level--;
    00101             else
    00102                ast_log(LOG_WARNING, "Syntax error at line %d of '%s', too many closing braces!\n", lineno, filename);
    00103          } else if ((*c == ';') && !level) {
    00104             /* Got a token! */
    00105             *c = '\0';
    00106             b = c;
    00107             b--;
    00108             c++;
    00109             while((b > src) && (*b < 33)) {
    00110                *b = '\0';
    00111                b--;
    00112             }
    00113             a = ast_skip_blanks(src);
    00114             if (link) {
    00115                ret = malloc(strlen(a) + sizeof(struct stringlink) + 1);
    00116                if (ret)
    00117                   strcpy(ret + sizeof(struct stringlink), a);
    00118             } else
    00119                ret = strdup(a);
    00120             /* Save remainder */
    00121             memmove(src, c, strlen(c) + 1);
    00122             return ret;
    00123          }
    00124       }
    00125       c++;
    00126    }
    00127    return NULL;
    00128 }
    00129
    00130 static char *grab_token(char *src, const char *filename, int lineno)
    00131 {
    00132    return __grab_token(src, filename, lineno, 0);
    00133 }
    00134
    00135 static struct stringlink *arg_parse(char *args, const char *filename, int lineno)
    00136 {
    00137    struct stringlink *cur, *prev=NULL, *root=NULL;
    00138    if (args) {
    00139       if (aeldebug & DEBUG_TOKENS)
    00140          ast_verbose("Parsing args '%s'!\n", args);
    00141       if (args[0] == '{') {
    00142          /* Strip mandatory '}' from end */
    00143          args[strlen(args) - 1] = '\0';
    00144          while ((cur = (struct stringlink *)__grab_token(args + 1, filename, lineno, 1))) {
    00145             cur->next = NULL;
    00146             if (prev)
    00147                prev->next = cur;
    00148             else
    00149                root = cur;
    00150             prev = cur;
    00151          }
    00152       } else if (*args) {
    00153          root = malloc(sizeof(struct stringlink) + strlen(args) + 1);
    00154          if (root) {
    00155             strcpy(root->data, args);
    00156             root->next = NULL;
    00157          }
    00158       }
    00159    }
    00160    return root;
    00161 }
    00162
    00163 static char *grab_else(char *args, const char *filename, int lineno)
    00164 {
    00165    char *ret = NULL;
    00166    int level=0;
    00167    char *c;
    00168    if (args) {
    00169       if (args[0] == '{') {
    00170          c = args;
    00171          while(*c) {
    00172             if (*c == '{')
    00173                level++;
    00174             else if (*c == '}') {
    00175                level--;
    00176                if (!level) {
    00177                   c++;
    00178                   while(*c && (*c < 33)) { *c = '\0'; c++; };
    00179                   if (!strncasecmp(c, "else", 4) &&
    00180                      ((c[4] == '{') || (c[4] < 33))) {
    00181                         /* Ladies and gentlemen, we have an else clause */
    00182                      *c = '\0';
    00183                      c += 4;
    00184                      c = ast_skip_blanks(c);
    00185                      ret = c;
    00186                      if (aeldebug & DEBUG_TOKENS)
    00187                         ast_verbose("Returning else clause '%s'\n", c);
    00188                   }
    00189                   break;
    00190                }
    00191             }
    00192             c++;
    00193          }
    00194       }
    00195    }
    00196    return ret;
    00197 }
    00198
    00199 static struct stringlink *param_parse(char *parms, const char *macro, const char *filename, int lineno)
    00200 {
    00201    char *s, *e;
    00202    struct stringlink *root = NULL, *prev=NULL, *cur;
    00203    if (!parms || !*parms)
    00204       return NULL;
    00205    if (*parms != '(') {
    00206       ast_log(LOG_NOTICE, "Syntax error in parameter list for macro '%s' at about line %d of %s: Expecting '(' but got '%c'\n", macro, lineno, filename, *parms);
    00207       return NULL;
    00208    }
    00209    s = parms + 1;
    00210    while(*s) {
    00211       s = ast_skip_blanks(s);
    00212       e = s;
    00213       while(*e &&  (*e != ')') && (*e != ',')) {
    00214          if (*e < 33)
    00215             *e = '\0';
    00216          e++;
    00217       }
    00218       if (*e) {
    00219          /* Strip token */
    00220          *e = '\0';
    00221          e++;
    00222          /* Skip over whitespace */
    00223          e = ast_skip_blanks(e);
    00224          /* Link */
    00225          cur = malloc(strlen(s) + sizeof(struct stringlink) + 1);
    00226          if (cur) {
    00227             cur->next = NULL;
    00228             strcpy(cur->data, s);
    00229             if (prev)
    00230                prev->next = cur;
    00231             else
    00232                root = cur;
    00233             prev = cur;
    00234          }
    00235          s = e;
    00236       }
    00237    }
    00238    return root;
    00239 }
    00240
    00241 static void arg_free(struct stringlink *cur)
    00242 {
    00243    struct stringlink *last;
    00244    while(cur) {
    00245       last = cur;
    00246       cur = cur->next;
    00247       free(last);
    00248    }
    00249 }
    00250
    00251 static void handle_globals(struct stringlink *vars)
    00252 {
    00253    while(vars) {
    00254       pbx_builtin_setvar(NULL, vars->data);
    00255       vars = vars->next;
    00256    }
    00257 }
    00258
    00259 static struct stringlink *split_token(char *token, const char *filename, int lineno)
    00260 {
    00261    char *args, *p;
    00262    struct stringlink *argv;
    00263    args = token;
    00264    while (*args && (*args > 32) && (*args != '{') && (*args != '(')) args++;
    00265    if (*args) {
    00266       p = args;
    00267       args = ast_skip_blanks(args);
    00268       if (*args != '(') {
    00269          *p = '\0';
    00270       } else {
    00271          while (*args && (*args != ')')) args++;
    00272          if (*args == ')') {
    00273             args++;
    00274             args = ast_skip_blanks(args);
    00275          }
    00276       }
    00277       if (!*args)
    00278          args = NULL;
    00279    } else args = NULL;
    00280    argv = arg_parse(args, filename, lineno);
    00281    if (args)
    00282       *args = '\0';
    00283    return argv;
    00284 }
    00285
    00286 static int matches_keyword(const char *data, const char *keyword)
    00287 {
    00288    char c;
    00289    if (!strncasecmp(data, keyword, strlen(keyword))) {
    00290       c = data[strlen(keyword)];
    00291       if ((c < 33) || (c == '(') || (c == '{'))
    00292          return 1;
    00293    }
    00294    return 0;
    00295 }
    00296
    00297 static struct stringlink *split_params(char *token, const char *filename, int lineno)
    00298 {
    00299    char *params;
    00300    struct stringlink *paramv;
    00301    params = token;
    00302    while(*params && (*params > 32) && (*params != '(')) params++;
    00303    if (*params) {
    00304       if (*params != '(') {
    00305          *params = '\0';
    00306          params++;
    00307          params = ast_skip_blanks(params);
    00308       }
    00309       if (!*params)
    00310          params = NULL;
    00311    } else params = NULL;
    00312    paramv = param_parse(params, token, filename, lineno);
    00313    if (params)
    00314       *params = '\0';
    00315    return paramv;
    00316 }
    00317
    00318 static const char *get_case(char *s, char **restout, int *pattern)
    00319 {
    00320    char *newcase=NULL;
    00321    char *rest=NULL;
    00322    if (!strncasecmp(s, "case", 4) && s[4] && ((s[4] < 33) || (s[4] == ':'))) {
    00323       newcase = s + 4;
    00324       newcase = ast_skip_blanks(newcase);
    00325       rest = newcase;
    00326       *pattern = 0;
    00327    } else if (!strncasecmp(s, "pattern", 7) && s[7] && ((s[7] < 33) || (s[7] == ':'))) {
    00328       newcase = s + 8;
    00329       newcase = ast_skip_blanks(newcase);
    00330       rest = newcase;
    00331       *pattern = 1;
    00332    } else if (!strncasecmp(s, "default", 7) && ((s[7] < 33) || (s[7] == ':'))) {
    00333       newcase = ".";
    00334       rest = s + 7;
    00335       rest = ast_skip_blanks(rest);
    00336       *pattern = 1;
    00337    }
    00338
    00339    if (rest) {
    00340       while (*rest && (*rest > 32) && (*rest != ':')) rest++;
    00341       if (*rest) {
    00342          *rest = 0;
    00343          rest++;
    00344          while (*rest && ((*rest == ':') || (*rest < 33))) rest++;
    00345          *restout = rest;
    00346       } else {
    00347          *restout = "";
    00348       }
    00349    } else
    00350       *restout = s;
    00351    if (aeldebug & DEBUG_TOKENS)
    00352       ast_verbose("GETCASE: newcase is '%s', rest = '%s'\n", newcase, *restout);
    00353    return newcase;
    00354 }
    00355
    00356 static void fillin_free(struct fillin *fillin)
    00357 {
    00358    struct fillin *cur, *next;
    00359    cur =  fillin;
    00360    while(cur) {
    00361       next = cur->next;
    00362       free(cur);
    00363       cur = next;
    00364    }
    00365 }
    00366
    00367 static void fillin_process(struct ast_context *con, struct fillin *fillin, const char *filename, int lineno, const char *breakexten, int breakprio, const char *contexten, int contprio)
    00368 {
    00369    struct fillin *cur;
    00370    char *app;
    00371    char mdata[AST_MAX_EXTENSION + 20];
    00372    cur = fillin;
    00373    while(cur) {
    00374       if (cur->type == FILLIN_BREAK) {
    00375          if (breakexten && breakprio) {
    00376             app = "Goto";
    00377             snprintf(mdata, sizeof(mdata), "%s|%d", breakexten, breakprio);
    00378          } else {
    00379             app = "NoOp";
    00380             snprintf(mdata, sizeof(mdata), "Invalid break");
    00381             ast_log(LOG_NOTICE, "Ignoring inappropriate break around line %d of %s\n", lineno, filename);
    00382          }
    00383          if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar))
    00384             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of break '%s'\n", cur->priority, cur->exten);
    00385       } else if (cur->type == FILLIN_CONTINUE) {
    00386          if (contexten && contprio) {
    00387             app = "Goto";
    00388             snprintf(mdata, sizeof(mdata), "%s|%d", contexten, contprio);
    00389          } else {
    00390             app = "NoOp";
    00391             snprintf(mdata, sizeof(mdata), "Invalid continue");
    00392             ast_log(LOG_NOTICE, "Ignoring inappropriate continue around line %d of %s\n", lineno, filename);
    00393          }
    00394          if (ast_add_extension2(con, 0, cur->exten, cur->priority, NULL, NULL, app, strdup(mdata), FREE, registrar))
    00395             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of continue '%s'\n", cur->priority, cur->exten);
    00396       } else {
    00397          ast_log(LOG_WARNING, "Whoa, unknown fillin type '%d'\n", cur->type);
    00398       }
    00399       cur = cur->next;
    00400    }
    00401 }
    00402
    00403 static int match_assignment(char *variable, char **value)
    00404 {
    00405    char *c;
    00406    char *ws;
    00407    int inpar = 0;
    00408    c = variable;
    00409
    00410    while (*c) {
    00411       if(*c == ')' && (inpar > 0)) {
    00412          inpar--;
    00413       } else if(*c == '(' && (inpar >= 0)) {
    00414          inpar++;
    00415       } else if(*c == '=' && (inpar == 0)) {
    00416          break;
    00417       }
    00418       c++;
    00419    }
    00420    ws = c;
    00421    c = ast_skip_blanks(c);
    00422    if (*c == '=') {
    00423       *ws = '\0';
    00424       *c = '\0';
    00425       c++;
    00426       c = ast_skip_blanks(c);
    00427       *value = c;
    00428       return 1;
    00429    }
    00430    return 0;
    00431 }
    00432
    00433 static int matches_label(char *data, char **rest)
    00434 {
    00435    char last = 0;
    00436    char *start = data;
    00437    while (*data > 32) {
    00438       last = *data;
    00439       data++;
    00440    }
    00441    if (last != ':') {
    00442       data = ast_skip_blanks(data);
    00443       last = *data;
    00444       data++;
    00445    }
    00446    if (last == ':') {
    00447       *rest = data;
    00448       /* Go back and trim up the label */
    00449       while(*start && ((*start > 32) && (*start != ':'))) start++;
    00450       *start = '\0';
    00451       return 1;
    00452    }
    00453    return 0;
    00454 }
    00455
    00456 static char *argument_end(char *str)
    00457 {
    00458    int level=0;
    00459    while(*++str) {
    00460       switch(*str) {
    00461       case '(':
    00462          level++;
    00463          break;
    00464       case ')':
    00465          if(level)
    00466             level--;
    00467          else
    00468             return str;
    00469          break;
    00470       default:
    00471          break;
    00472       }
    00473    }
    00474    return NULL;
    00475 }
    00476
    00477 static void gen_match_to_pattern(const char *pattern, char *result)
    00478 {
    00479        /* the result will be a string that will be matched by pattern */
    00480        char *p=(char *)pattern, *t=result;
    00481        while (*p) {
    00482                if (*p == 'x' || *p == 'n' || *p == 'z' || *p == 'X' || *p == 'N' || *p == 'Z')
    00483                        *t++ = '9';
    00484                else if (*p == '[') {
    00485                        char *z = p+1;
    00486                        while (*z != ']')
    00487                                z++;
    00488                        if (*(z+1)== ']')
    00489                                z++;
    00490                        *t++=*(p+1); /* use the first char in the set */
    00491                        p = z;
    00492                } else {
    00493                        *t++ = *p;
    00494                }
    00495                p++;
    00496        }
    00497        *t++ = 0; /* cap it off */
    00498 }
    00499
    00500 static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label);
    00501 static int __build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label)
    00502 {
    00503    char *app;
    00504    char *args;
    00505    char *c;
    00506    char *margs=NULL;
    00507    char *oargs;
    00508    char *rest;
    00509    const char *curcase, *newcase;
    00510    struct stringlink *swargs, *cur;
    00511    int cpos;
    00512    int mlen;
    00513    int pattern = 0;
    00514    struct fillin *fillin;
    00515
    00516    data = ast_skip_blanks(data);
    00517    if (matches_label(data, &c)) {
    00518       *label = data;
    00519       data = c;
    00520       data = ast_skip_blanks(data);
    00521    }
    00522    if (ast_strlen_zero(data))
    00523       return 0;
    00524    if (matches_keyword(data, "switch")) {
    00525       fillin = NULL;
    00526       /* Switch */
    00527       args = data + strlen("switch");
    00528       while ((*args < 33) && (*args != '(')) args++;
    00529       if ((*args == '(') && (c = argument_end(args))) {
    00530          args++;
    00531          *c = '\0';
    00532          c++;
    00533          if (aeldebug & DEBUG_TOKENS)
    00534             ast_verbose("--SWITCH on : %s\n", args);
    00535          mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
    00536          margs = alloca(mlen);
    00537          app = "Goto";
    00538          sprintf(margs, "sw-%d-%s|1", *pos, args);
    00539          ast_process_quotes_and_slashes(margs, ',', '|');
    00540          oargs = args;
    00541          args = margs;
    00542          if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
    00543             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00544          else {
    00545             *label = NULL;
    00546             (*pos)++;
    00547          }
    00548          app = "NoOp";
    00549          sprintf(margs, "Finish switch-%d", *pos - 1);
    00550          if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
    00551             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00552          else {
    00553             *label = NULL;
    00554             (*pos)++;
    00555          }
    00556          c = ast_skip_blanks(c);
    00557          if (aeldebug & DEBUG_TOKENS)
    00558             ast_verbose("ARG Parsing '%s'\n", c);
    00559          swargs = arg_parse(c, filename, lineno);
    00560          cur = swargs;
    00561          curcase = NULL;
    00562          while(cur) {
    00563             if ((newcase = get_case(cur->data, &rest, &pattern))) {
    00564                if (aeldebug & DEBUG_TOKENS)
    00565                   ast_verbose("--NEWCASE: '%s'!\n", newcase);
    00566                if (curcase) {
    00567                   char zbuf[256];
    00568
    00569                   /* Handle fall through */
    00570                   char tmp[strlen(newcase) + strlen(name) + 40];
    00571                   gen_match_to_pattern(newcase,zbuf);
    00572                   sprintf(tmp, "sw-%d-%s|%d", *pos - 2, zbuf, 1);
    00573                   ast_add_extension2(con, 0, margs, cpos, NULL, NULL, "Goto", strdup(tmp), FREE, registrar);
    00574                }
    00575                curcase = newcase;
    00576                cpos = 1;
    00577                if (pattern)
    00578                   snprintf(margs, mlen, "_sw-%d-%s", *pos - 2, curcase);
    00579                else
    00580                   snprintf(margs, mlen, "sw-%d-%s", *pos - 2, curcase);
    00581                if (!strcasecmp(rest, "break")) {
    00582                   char tmp[strlen(exten) + 10];
    00583                   sprintf(tmp, "%s|%d", exten, *pos - 1);
    00584                   ast_add_extension2(con, 0, exten, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
    00585                   curcase = NULL;
    00586                   *label = NULL;
    00587                } else
    00588                   build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
    00589             } else if (curcase) {
    00590                if (aeldebug & DEBUG_TOKENS)
    00591                   ast_verbose("Building statement from '%s'\n", rest);
    00592                if (!strcasecmp(rest, "break")) {
    00593                   char tmp[strlen(exten) + 10];
    00594                   sprintf(tmp, "%s|%d", exten, *pos - 1);
    00595                   ast_add_extension2(con, 0, margs, cpos, *label, NULL, "Goto", strdup(tmp), FREE, registrar);
    00596                   curcase = NULL;
    00597                   *label = NULL;
    00598                } else
    00599                   build_step("switch", margs, filename, lineno, con, margs, &cpos, rest, &fillin, label);
    00600             } else
    00601                ast_log(LOG_WARNING, "Unreachable code in switch at about line %d of %s\n", lineno, filename);
    00602             if (aeldebug & DEBUG_TOKENS)
    00603                ast_verbose("--SWARG: %s\n", cur->data);
    00604             cur = cur->next;
    00605          }
    00606          /* Can't do anything with these */
    00607          fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
    00608          fillin_free(fillin);
    00609          arg_free(swargs);
    00610       } else
    00611          ast_log(LOG_WARNING, "Syntax error in switch declaration in %s around line %d!\n", filename, lineno);
    00612
    00613    } else if (matches_keyword(data, "if")) {
    00614       /* If... */
    00615       args = data + strlen("if");
    00616       while ((*args < 33) && (*args != '(')) args++;
    00617       if ((*args == '(') && (c = argument_end(args))) {
    00618          int ifblock;
    00619          int ifstart;
    00620          int elsestart;
    00621          int ifend;
    00622          int ifskip;
    00623          char *elses;
    00624          char *iflabel;
    00625          args++;
    00626          *c = '\0';
    00627          c++;
    00628          c = ast_skip_blanks(c);
    00629          if (aeldebug & DEBUG_TOKENS)
    00630             ast_verbose("--IF on : '%s' : '%s'\n", args, c);
    00631          mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
    00632          margs = alloca(mlen);
    00633          /* Remember where the ifblock starts, and skip over */
    00634          ifblock = (*pos)++;
    00635          iflabel = *label;
    00636          *label = NULL;
    00637          /* Remember where the start of the ifblock is */
    00638          ifstart = *pos;
    00639          snprintf(margs, mlen, "if-%s-%d", name, ifblock);
    00640          /* Now process the block of the if */
    00641          if (aeldebug & DEBUG_TOKENS)
    00642             ast_verbose("Searching for elses in '%s'\n", c);
    00643          elses = grab_else(c, filename, lineno);
    00644          build_step("if", margs, filename, lineno, con, exten, pos, c, fillout, label);
    00645          if (elses) {
    00646             /* Reserve a goto to exit the if */
    00647             ifskip = *pos;
    00648             (*pos)++;
    00649             elsestart = *pos;
    00650             build_step("else", margs, filename, lineno, con, exten, pos, elses, fillout, label);
    00651          } else {
    00652             elsestart = *pos;
    00653             ifskip = 0;
    00654          }
    00655          ifend = *pos;
    00656          (*pos)++;
    00657          app = "NoOp";
    00658          snprintf(margs, mlen, "Finish if-%s-%d", name, ifblock);
    00659          if (ast_add_extension2(con, 0, exten, ifend, *label, NULL, app, strdup(margs), FREE, registrar))
    00660             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00661          *label = NULL;
    00662          app = "GotoIf";
    00663          snprintf(margs, mlen, "$[ %s ]?%d:%d", args, ifstart, elsestart);
    00664          if (ast_add_extension2(con, 0, exten, ifblock, iflabel, NULL, app, strdup(margs), FREE, registrar))
    00665             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00666          if (ifskip) {
    00667             /* Skip as appropriate around else clause */
    00668             snprintf(margs, mlen, "%d", ifend);
    00669             if (ast_add_extension2(con, 0, exten, ifskip, NULL, NULL, "Goto", strdup(margs), FREE, registrar))
    00670                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00671          }
    00672       } else
    00673          ast_log(LOG_WARNING, "Syntax error in if declaration in %s around line %d!\n", filename, lineno);
    00674    } else if (matches_keyword(data, "while")) {
    00675       /* While... */
    00676       fillin = NULL;
    00677       args = data + strlen("while");
    00678       while ((*args < 33) && (*args != '(')) args++;
    00679       if ((*args == '(') && (c = argument_end(args))) {
    00680          int whileblock;
    00681          int whilestart;
    00682          int whileend;
    00683          char *whilelabel;
    00684          args++;
    00685          *c = '\0';
    00686          c++;
    00687          c = ast_skip_blanks(c);
    00688          if (aeldebug & DEBUG_TOKENS)
    00689             ast_verbose("--WHILE on : '%s' : '%s'\n", args, c);
    00690          mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
    00691          margs = alloca(mlen);
    00692          /* Remember where to put the conditional, and keep its position */
    00693          whilestart = (*pos);
    00694          whilelabel = *label;
    00695          *label = NULL;
    00696          (*pos)++;
    00697          /* Remember where the whileblock starts */
    00698          whileblock = (*pos);
    00699          snprintf(margs, mlen, "while-%s-%d", name, whilestart);
    00700          build_step("while", margs, filename, lineno, con, exten, pos, c, &fillin, label);
    00701          /* Close the loop */
    00702          app = "Goto";
    00703          snprintf(margs, mlen, "%d", whilestart);
    00704          if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
    00705             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00706          *label = NULL;
    00707          whileend = (*pos);
    00708          /* Place trailer */
    00709          app = "NoOp";
    00710          snprintf(margs, mlen, "Finish while-%s-%d", name, whilestart);
    00711          if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
    00712             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00713          *label = NULL;
    00714          app = "GotoIf";
    00715          snprintf(margs, mlen, "$[ %s ]?%d:%d", args, whileblock, whileend);
    00716          if (ast_add_extension2(con, 0, exten, whilestart, whilelabel, NULL, app, strdup(margs), FREE, registrar))
    00717             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00718          fillin_process(con, fillin, filename, lineno, exten, whileend, exten, whilestart);
    00719          fillin_free(fillin);
    00720       } else
    00721          ast_log(LOG_WARNING, "Syntax error in while declaration in %s around line %d!\n", filename, lineno);
    00722    } else if (matches_keyword(data, "jump")) {
    00723       char *p;
    00724       /* Jump... */
    00725       fillin = NULL;
    00726       args = data + strlen("jump");
    00727       args = ast_skip_blanks(args);
    00728       if (aeldebug & DEBUG_TOKENS)
    00729          ast_verbose("--JUMP to : '%s'\n", args);
    00730       p = strchr(args, ',');
    00731       if (p) {
    00732          *p = '\0';
    00733          p++;
    00734       } else
    00735          p = "1";
    00736       c = strchr(args, '@');
    00737       if (c) {
    00738          *c = '\0';
    00739          c++;
    00740       }
    00741       mlen = strlen(exten) + 128 + strlen(args) + strlen(name) + (c ? strlen(c) : 0);
    00742       margs = alloca(mlen);
    00743       if (c)
    00744          snprintf(margs, mlen, "%s|%s|%s", c,args, p);
    00745       else
    00746          snprintf(margs, mlen, "%s|%s", args, p);
    00747       app = "Goto";
    00748       if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
    00749          ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00750       *label = NULL;
    00751    } else if (matches_keyword(data, "goto")) {
    00752       /* Jump... */
    00753       fillin = NULL;
    00754       args = data + strlen("goto");
    00755       args = ast_skip_blanks(args);
    00756       if (aeldebug & DEBUG_TOKENS)
    00757          ast_verbose("--GOTO to : '%s'\n", args);
    00758       app = "Goto";
    00759       if (args[0] == '(' && args[strlen(args) - 1] == ')') {
    00760          args[0] = '\0';
    00761          args++;
    00762          args[strlen(args) - 1] = '\0';
    00763       }
    00764       if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(args), FREE, registrar))
    00765          ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00766       *label = NULL;
    00767    } else if (matches_keyword(data, "for")) {
    00768       /* While... */
    00769       fillin = NULL;
    00770       args = data + strlen("for");
    00771       while ((*args < 33) && (*args != '(')) args++;
    00772       if ((*args == '(') && (c = argument_end(args))) {
    00773          int forblock;
    00774          int forprep;
    00775          int forstart;
    00776          int forend;
    00777          struct stringlink *fields;
    00778          char *tmp;
    00779          char *forlabel = NULL;
    00780          args++;
    00781          *c = '\0';
    00782          c++;
    00783          c = ast_skip_blanks(c);
    00784          /* Parse arguments first */
    00785          tmp = alloca(strlen(args) + 10);
    00786          if (tmp) {
    00787             snprintf(tmp, strlen(args) + 10, "{%s;}", args);
    00788             fields = arg_parse(tmp, filename, lineno);
    00789          } else
    00790             fields = NULL;
    00791          if (fields && fields->next && fields->next->next) {
    00792             if (aeldebug & DEBUG_TOKENS)
    00793                ast_verbose("--FOR ('%s' ; '%s' ; '%s') : '%s'\n", fields->data, fields->next->data, fields->next->next->data, c);
    00794             mlen = strlen(exten) + 128 + strlen(args) + strlen(name);
    00795             margs = alloca(mlen);
    00796             forprep = *pos;
    00797             snprintf(margs, mlen, "for-%s-%d", name, forprep);
    00798             fillin = NULL;
    00799             build_step("while", margs, filename, lineno, con, exten, pos, fields->data, &fillin, label);
    00800             /* Remember where to put the conditional, and keep its position */
    00801             forstart = (*pos);
    00802             forlabel = *label;
    00803             (*pos)++;
    00804             *label = NULL;
    00805             /* Remember where the whileblock starts */
    00806             forblock = (*pos);
    00807             build_step("for", margs, filename, lineno, con, exten, pos, c, &fillin, label);
    00808             build_step("for", margs, filename, lineno, con, exten, pos, fields->next->next->data, &fillin, label);
    00809             /* Close the loop */
    00810             app = "Goto";
    00811             snprintf(margs, mlen, "%d", forstart);
    00812             if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
    00813                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00814             *label = NULL;
    00815             forend = (*pos);
    00816             /* Place trailer */
    00817             app = "NoOp";
    00818             snprintf(margs, mlen, "Finish for-%s-%d", name, forprep);
    00819             if (ast_add_extension2(con, 0, exten, (*pos)++, *label, NULL, app, strdup(margs), FREE, registrar))
    00820                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00821             *label = NULL;
    00822             app = "GotoIf";
    00823             snprintf(margs, mlen, "$[ %s ]?%d:%d", fields->next->data, forblock, forend);
    00824             if (ast_add_extension2(con, 0, exten, forstart, forlabel, NULL, app, strdup(margs), FREE, registrar))
    00825                ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", forstart, what, name);
    00826             fillin_process(con, fillin, filename, lineno, exten, forend, exten, forstart);
    00827             fillin_free(fillin);
    00828          } else
    00829             ast_log(LOG_NOTICE, "Improper for declaration in %s around line %d!\n", filename, lineno);
    00830          arg_free(fields);
    00831       } else
    00832          ast_log(LOG_WARNING, "Syntax error in for declaration in %s around line %d!\n", filename, lineno);
    00833
    00834    } else if (!strcasecmp(data, "break") || !strcasecmp(data, "continue")) {
    00835       struct fillin *fi;
    00836       fi = malloc(sizeof(struct fillin));
    00837       if (fi) {
    00838          memset(fi, 0, sizeof(struct fillin));
    00839          if (!strcasecmp(data, "break"))
    00840             fi->type = FILLIN_BREAK;
    00841          else
    00842             fi->type = FILLIN_CONTINUE;
    00843          ast_copy_string(fi->exten, exten, sizeof(fi->exten));
    00844          fi->priority = (*pos)++;
    00845          fi->next = *fillout;
    00846          *fillout = fi;
    00847       }
    00848    } else if (match_assignment(data, &rest)) {
    00849       if (aeldebug & DEBUG_TOKENS)
    00850          ast_verbose("ASSIGN  '%s' = '%s'\n", data, rest);
    00851       mlen = strlen(rest) + strlen(data) + 20;
    00852       margs = alloca(mlen);
    00853       snprintf(margs, mlen, "%s=$[ %s ]", data, rest);
    00854       app = "Set";
    00855       if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(margs), FREE, registrar))
    00856          ast_log(LOG_WARNING, "Unable to add assignment at priority '%d' of %s '%s'\n", *pos, what, name);
    00857       else {
    00858          *label = NULL;
    00859          (*pos)++;
    00860       }
    00861    } else {
    00862       app = data;
    00863       args = app;
    00864       while (*args && (*args > 32) && (*args != '(')) args++;
    00865          if (*args != '(') {
    00866          while(*args && (*args != '(')) { *args = '\0'; args++; };
    00867       }
    00868       if (*args == '(') {
    00869          *args = '\0';
    00870          args++;
    00871          /* Got arguments, trim trailing ')' */
    00872          c = args + strlen(args) - 1;
    00873          while((c >= args) && (*c < 33) && (*c != ')')) { *c = '\0'; c--; };
    00874          if ((c >= args) && (*c == ')')) *c = '\0';
    00875       } else
    00876          args = "";
    00877       ast_process_quotes_and_slashes(args, ',', '|');
    00878       if (app[0] == '&') {
    00879          app++;
    00880          margs = alloca(strlen(args) + strlen(app) + 10);
    00881          sprintf(margs, "%s|%s", app, args);
    00882          args = margs;
    00883          app = "Macro";
    00884       }
    00885       if (aeldebug & DEBUG_TOKENS)
    00886          ast_verbose("-- APP: '%s', ARGS: '%s'\n", app, args);
    00887       if (ast_add_extension2(con, 0, exten, *pos, *label, NULL, app, strdup(args), FREE, registrar))
    00888          ast_log(LOG_WARNING, "Unable to add step at priority '%d' of %s '%s'\n", *pos, what, name);
    00889       else {
    00890          (*pos)++;
    00891          *label = NULL;
    00892       }
    00893    }
    00894    return 0;
    00895 }
    00896
    00897 static int build_step(const char *what, const char *name, const char *filename, int lineno, struct ast_context *con, char *exten, int *pos, char *data, struct fillin **fillout, char **label)
    00898 {
    00899    struct stringlink *args, *cur;
    00900    int res=0;
    00901    struct fillin *fillin=NULL;
    00902    int dropfill = 0;
    00903    char *labelin = NULL;
    00904    if (!fillout) {
    00905       fillout = &fillin;
    00906       dropfill = 1;
    00907    }
    00908    if (!label) {
    00909       label = &labelin;
    00910    };
    00911    args = arg_parse(data, filename, lineno);
    00912    cur = args;
    00913    while(cur) {
    00914       res |= __build_step(what, name, filename, lineno, con, exten, pos, cur->data, fillout, label);
    00915       cur = cur->next;
    00916    }
    00917    arg_free(args);
    00918    if (dropfill) {
    00919       fillin_process(con, fillin, filename, lineno, NULL, 0, NULL, 0);
    00920       fillin_free(fillin);
    00921    }
    00922    return res;
    00923 }
    00924
    00925 static int parse_catch(char *data, char **catch, char **rest)
    00926 {
    00927    /* Skip the word 'catch' */
    00928    data += 5;
    00929    data = ast_skip_blanks(data);
    00930    /* Here's the extension */
    00931    *catch = data;
    00932    if (!*data)
    00933       return 0;
    00934    while (*data && (*data > 32)) data++;
    00935    if (!*data)
    00936       return 0;
    00937    /* Trim any trailing spaces */
    00938    *data = '\0';
    00939    data++;
    00940    data = ast_skip_blanks(data);
    00941    if (!*data)
    00942       return 0;
    00943    *rest = data;
    00944    return 1;
    00945 }
    00946
    00947 static void handle_macro(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
    00948 {
    00949    struct stringlink *argv;
    00950    struct stringlink *paramv;
    00951    struct stringlink *cur;
    00952    struct ast_context *con;
    00953    struct fillin *fillin;
    00954    char *catch, *rest;
    00955    char name[256];
    00956    int pos;
    00957    int cpos;
    00958
    00959    if (aeldebug & DEBUG_MACROS)
    00960       ast_verbose("Root macro def is '%s'\n", vars->data);
    00961    argv = split_token(vars->data, filename, lineno);
    00962    paramv = split_params(vars->data, filename, lineno);
    00963    if (aeldebug & DEBUG_MACROS)
    00964       ast_verbose("Found macro '%s'\n", vars->data);
    00965    snprintf(name, sizeof(name), "macro-%s", vars->data);
    00966    con = ast_context_create(local_contexts, name, registrar);
    00967    if (con) {
    00968       pos = 1;
    00969       cur = paramv;
    00970       while(cur) {
    00971          if (aeldebug & DEBUG_MACROS)
    00972             ast_verbose("  PARAM => '%s'\n", cur->data);
    00973          snprintf(name, sizeof(name), "%s=${ARG%d}", cur->data, pos);
    00974          if (ast_add_extension2(con, 0, "s", pos, NULL, NULL, "Set", strdup(name), FREE, registrar))
    00975             ast_log(LOG_WARNING, "Unable to add step at priority '%d' of macro '%s'\n", pos, vars->data);
    00976          else
    00977             pos++;
    00978          cur = cur->next;
    00979       }
    00980       cur = argv;
    00981       while(cur) {
    00982          if (aeldebug & DEBUG_MACROS)
    00983             ast_verbose("  STEP => '%s'\n", cur->data);
    00984          if (matches_keyword(cur->data, "catch")) {
    00985             if (aeldebug & DEBUG_MACROS)
    00986                ast_verbose("--CATCH: '%s'\n", cur->data);
    00987             if (parse_catch(cur->data, &catch, &rest)) {
    00988                cpos = 1;
    00989                build_step("catch", catch, filename, lineno, con, catch, &cpos, rest, NULL, NULL);
    00990             } else
    00991                ast_log(LOG_NOTICE, "Parse error for catch at about line %d of %s\n", lineno, filename);
    00992          } else {
    00993             fillin = NULL;
    00994             build_step("macro", vars->data, filename, lineno, con, "s", &pos, cur->data, NULL, NULL);
    00995          }
    00996          cur = cur->next;
    00997       }
    00998    } else
    00999       ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
    01000    arg_free(paramv);
    01001    arg_free(argv);
    01002    if (vars->next)
    01003       ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
    01004 }
    01005
    01006 static int matches_extension(char *exten, char **extout)
    01007 {
    01008    char *c;
    01009    *extout = NULL;
    01010    c = exten;
    01011    while(*c && (*c > 32)) c++;
    01012    if (*c) {
    01013       *c = '\0';
    01014       c++;
    01015       c = ast_skip_blanks(c);
    01016       if (*c) {
    01017          if (*c == '=') {
    01018             *c = '\0';
    01019             c++;
    01020             if (*c == '>')
    01021                c++;
    01022             c = ast_skip_blanks(c);
    01023             *extout = c;
    01024             return 1;
    01025          }
    01026       }
    01027    }
    01028    return 0;
    01029 }
    01030
    01031 static void parse_keyword(char *s, char **o)
    01032 {
    01033    char *c;
    01034    c = s;
    01035    while((*c) && (*c > 32)) c++;
    01036    if (*c) {
    01037       *c = '\0';
    01038       c++;
    01039       c = ast_skip_blanks(c);
    01040       *o = c;
    01041    } else
    01042       *o = NULL;
    01043 }
    01044
    01045 static void handle_context(struct ast_context **local_contexts, struct stringlink *vars, const char *filename, int lineno)
    01046 {
    01047    struct stringlink *argv;
    01048    struct stringlink *cur2;
    01049    struct stringlink *argv2;
    01050    struct stringlink *cur;
    01051    struct ast_context *con;
    01052    char *rest;
    01053    char *c;
    01054    char name[256];
    01055    int pos;
    01056
    01057    if (aeldebug & DEBUG_CONTEXTS)
    01058       ast_verbose("Root context def is '%s'\n", vars->data);
    01059    argv = split_token(vars->data, filename, lineno);
    01060    if (aeldebug & DEBUG_CONTEXTS)
    01061       ast_verbose("Found context '%s'\n", vars->data);
    01062    snprintf(name, sizeof(name), "%s", vars->data);
    01063    con = ast_context_create(local_contexts, name, registrar);
    01064    if (con) {
    01065       cur = argv;
    01066       while(cur) {
    01067          if (matches_keyword(cur->data, "includes")) {
    01068             if (aeldebug & DEBUG_CONTEXTS)
    01069                ast_verbose("--INCLUDES: '%s'\n", cur->data);
    01070             parse_keyword(cur->data, &rest);
    01071             if (rest) {
    01072                argv2 = arg_parse(rest, filename, lineno);
    01073                cur2 = argv2;
    01074                while(cur2) {
    01075                   ast_context_add_include2(con, cur2->data, registrar);
    01076                   cur2 = cur2->next;
    01077                }
    01078                arg_free(argv2);
    01079             }
    01080          } else if (matches_keyword(cur->data, "ignorepat")) {
    01081             if (aeldebug & DEBUG_CONTEXTS)
    01082                ast_verbose("--IGNOREPAT: '%s'\n", cur->data);
    01083             parse_keyword(cur->data, &rest);
    01084             if (rest) {
    01085                argv2 = arg_parse(rest, filename, lineno);
    01086                cur2 = argv2;
    01087                while(cur2) {
    01088                   ast_context_add_ignorepat2(con, cur2->data, registrar);
    01089                   cur2 = cur2->next;
    01090                }
    01091                arg_free(argv2);
    01092             }
    01093          } else if (matches_keyword(cur->data, "switches") || matches_keyword(cur->data, "eswitches")) {
    01094             if (aeldebug & DEBUG_CONTEXTS)
    01095                ast_verbose("--[E]SWITCH: '%s'\n", cur->data);
    01096             parse_keyword(cur->data, &rest);
    01097             if (rest) {
    01098                argv2 = arg_parse(rest, filename, lineno);
    01099                cur2 = argv2;
    01100                while(cur2) {
    01101                   c = strchr(cur2->data, '/');
    01102                   if (c) {
    01103                      *c = '\0';
    01104                      c++;
    01105                   } else
    01106                      c = "";
    01107                   ast_context_add_switch2(con, cur2->data, c, (cur->data[0] == 'e'), registrar);
    01108                   cur2 = cur2->next;
    01109                }
    01110                arg_free(argv2);
    01111             }
    01112          } else if (matches_extension(cur->data, &rest)) {
    01113             if (aeldebug & DEBUG_CONTEXTS)
    01114                ast_verbose("Extension: '%s' => '%s'\n", cur->data, rest);
    01115             pos = 1;
    01116             build_step("extension", cur->data, filename, lineno, con, cur->data, &pos, rest, NULL, NULL);
    01117          }
    01118          cur = cur->next;
    01119       }
    01120    } else
    01121          ast_log(LOG_WARNING, "Unable to create context '%s'\n", name);
    01122    arg_free(argv);
    01123    if (vars->next)
    01124       ast_log(LOG_NOTICE, "Ignoring excess tokens in macro definition around line %d of %s!\n", lineno, filename);
    01125 }
    01126
    01127 static int handle_root_token(struct ast_context **local_contexts, char *token, int level, const char *filename, int lineno)
    01128 {
    01129    struct stringlink *argv, *cur;
    01130    argv = split_token(token, filename, lineno);
    01131    if (aeldebug & DEBUG_TOKENS) {
    01132       ast_verbose("Found root token '%s' at level %d (%s:%d)!\n", token, level, filename, lineno);
    01133       cur = argv;
    01134       while(cur) {
    01135          ast_verbose("   ARG => '%s'\n", cur->data);
    01136          cur = cur->next;
    01137       }
    01138    }
    01139    if (!strcasecmp(token, "globals")) {
    01140       handle_globals(argv);
    01141    } else if (!strcasecmp(token, "macro")) {
    01142       handle_macro(local_contexts, argv, filename, lineno);
    01143    } else if (!strcasecmp(token, "context")) {
    01144       handle_context(local_contexts, argv, filename, lineno);
    01145    } else {
    01146       ast_log(LOG_NOTICE, "Unknown root token '%s'\n", token);
    01147    }
    01148    arg_free(argv);
    01149    return 0;
    01150 }
    01151
    01152
    01153 static int ast_ael_compile(struct ast_context **local_contexts, const char *filename)
    01154 {
    01155    char *rfilename;
    01156    char *buf, *tbuf;
    01157    int bufsiz;
    01158    FILE *f;
    01159    char *c;
    01160    char *token;
    01161    int lineno=0;
    01162
    01163    if (filename[0] == '/')
    01164       rfilename = (char *)filename;
    01165    else {
    01166       rfilename = alloca(strlen(filename) + strlen(ast_config_AST_CONFIG_DIR) + 2);
    01167       sprintf(rfilename, "%s/%s", ast_config_AST_CONFIG_DIR, filename);
    01168    }
    01169
    01170    f = fopen(rfilename, "r");
    01171    if (!f) {
    01172       ast_log(LOG_WARNING, "Unable to open '%s': %s\n", rfilename, strerror(errno));
    01173       return -1;
    01174    }
    01175    buf = malloc(4096);
    01176    if (!buf) {
    01177       ast_log(LOG_WARNING, "Out of memory!\n");
    01178       fclose(f);
    01179       return -1;
    01180    }
    01181    buf[0] = 0;
    01182    bufsiz = 4096;
    01183    while(!feof(f)) {
    01184       if (bufsiz - strlen(buf) < 2048) {
    01185          bufsiz += 4096;
    01186          tbuf = realloc(buf, bufsiz);
    01187          if (tbuf) {
    01188             buf = tbuf;
    01189          } else {
    01190             free(buf);
    01191             ast_log(LOG_WARNING, "Out of memory!\n");
    01192             fclose(f);
    01193          }
    01194       }
    01195       if (fgets(buf + strlen(buf), bufsiz - strlen(buf), f)) {
    01196          lineno++;
    01197          while(*buf && buf[strlen(buf) - 1] < 33)
    01198             buf[strlen(buf) - 1] = '\0';
    01199          c = strstr(buf, "//");
    01200          if (c)
    01201             *c = '\0';
    01202          if (*buf) {
    01203             if (aeldebug & DEBUG_READ)
    01204                ast_verbose("Newly composed line '%s'\n", buf);
    01205             while((token = grab_token(buf, filename, lineno))) {
    01206                handle_root_token(local_contexts, token, 0, filename, lineno);
    01207                free(token);
    01208             }
    01209          }
    01210       }
    01211    };
    01212    free(buf);
    01213    fclose(f);
    01214    return 0;
    01215 }
    01216
    01217 static int pbx_load_module(void)
    01218 {
    01219    struct ast_context *local_contexts=NULL, *con;
    01220    ast_ael_compile(&local_contexts, config);
    01221    ast_merge_contexts_and_delete(&local_contexts, registrar);
    01222    for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
    01223       ast_context_verify_includes(con);
    01224
    01225    return 0;
    01226 }
    01227
    01228 /* CLI interface */
    01229 static int ael_debug_read(int fd, int argc, char *argv[])
    01230 {
    01231    aeldebug |= DEBUG_READ;
    01232    return 0;
    01233 }
    01234
    01235 static int ael_debug_tokens(int fd, int argc, char *argv[])
    01236 {
    01237    aeldebug |= DEBUG_TOKENS;
    01238    return 0;
    01239 }
    01240
    01241 static int ael_debug_macros(int fd, int argc, char *argv[])
    01242 {
    01243    aeldebug |= DEBUG_MACROS;
    01244    return 0;
    01245 }
    01246
    01247 static int ael_debug_contexts(int fd, int argc, char *argv[])
    01248 {
    01249    aeldebug |= DEBUG_CONTEXTS;
    01250    return 0;
    01251 }
    01252
    01253 static int ael_no_debug(int fd, int argc, char *argv[])
    01254 {
    01255    aeldebug = 0;
    01256    return 0;
    01257 }
    01258
    01259 static int ael_reload(int fd, int argc, char *argv[])
    01260 {
    01261    ast_context_destroy(NULL, registrar);
    01262    return (pbx_load_module());
    01263 }
    01264
    01265 static struct ast_cli_entry  ael_cli[] = {
    01266    { { "ael", "reload", NULL }, ael_reload, "Reload AEL configuration"},
    01267    { { "ael", "debug", "read", NULL }, ael_debug_read, "Enable AEL read debug"},
    01268    { { "ael", "debug", "tokens", NULL }, ael_debug_tokens, "Enable AEL tokens debug"},
    01269    { { "ael", "debug", "macros", NULL }, ael_debug_macros, "Enable AEL macros debug"},
    01270    { { "ael", "debug", "contexts", NULL }, ael_debug_contexts, "Enable AEL contexts debug"},
    01271    { { "ael", "no", "debug", NULL }, ael_no_debug, "Disable AEL debug messages"},
    01272 };
    01273
    01274 /*
    01275  * Standard module functions ...
    01276  */
    01277 int unload_module(void)
    01278 {
    01279    ast_context_destroy(NULL, registrar);
    01280    ast_cli_unregister_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0]));
    01281    return 0;
    01282 }
    01283
    01284
    01285 int load_module(void)
    01286 {
    01287    ast_cli_register_multiple(ael_cli, sizeof(ael_cli)/ sizeof(ael_cli[0]));
    01288    return (pbx_load_module());
    01289 }
    01290
    01291 int reload(void)
    01292 {
    01293    ast_context_destroy(NULL, registrar);
    01294    return pbx_load_module();
    01295 }
    01296
    01297 int usecount(void)
    01298 {
    01299    return 0;
    01300 }
    01301
    01302 char *description(void)
    01303 {
    01304    return dtext;
    01305 }
    01306
    01307 char *key(void)
    01308 {
    01309    return ASTERISK_GPL_KEY;
    01310 }