A trunk that builds is a productive trunk.
[asterisk/asterisk.git] / utils / ael_main.c
1 #include "asterisk/autoconfig.h"
2
3 #include <sys/types.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <stdarg.h>
7 #include <string.h>
8 #include <locale.h>
9 #include <ctype.h>
10 #if !defined(SOLARIS) && !defined(__CYGWIN__)
11 #include <err.h>
12 #endif
13 #include <errno.h>
14 #include <regex.h>
15 #include <limits.h>
16
17 #include "asterisk/ast_expr.h"
18 #include "asterisk/channel.h"
19 #include "asterisk/module.h"
20 #include "asterisk/app.h"
21 #include "asterisk/ael_structs.h"
22
23 struct namelist
24 {
25         char name[100];
26         char name2[100];
27         struct namelist *next;
28 };
29
30 struct ast_context 
31 {
32         int extension_count;
33         char name[100];
34         char registrar[100];
35         struct namelist *includes;
36         struct namelist *ignorepats;
37         struct namelist *switches;
38         struct namelist *eswitches;
39
40         struct namelist *includes_last;
41         struct namelist *ignorepats_last;
42         struct namelist *switches_last;
43         struct namelist *eswitches_last;
44
45         struct ast_context *next;
46 };
47
48 #define ADD_LAST(headptr,memptr) if(!headptr){ headptr=(memptr); (headptr##_last)=(memptr);} else {(headptr##_last)->next = (memptr); (headptr##_last) = (memptr);}
49
50 void destroy_namelist(struct namelist *x);
51 void destroy_namelist(struct namelist *x)
52 {
53         struct namelist *z,*z2;
54         for(z=x; z; z = z2)
55         {
56                 z2 = z->next;
57                 z->next = 0;
58                 free(z);
59         }
60 }
61
62 struct namelist *create_name(char *name);
63 struct namelist *create_name(char *name)
64 {
65         struct namelist *x = calloc(1, sizeof(*x));
66         if (!x)
67                 return NULL;
68         strncpy(x->name, name, sizeof(x->name) - 1);
69         return x;
70 }
71
72 struct ast_context *context_list;
73 struct ast_context *last_context;
74 struct namelist *globalvars;
75 struct namelist *globalvars_last;
76
77 int conts=0, extens=0, priors=0;
78 char last_exten[18000];
79 char ast_config_AST_CONFIG_DIR[PATH_MAX];
80 char ast_config_AST_VAR_DIR[PATH_MAX];
81
82 void ast_add_profile(void);
83 void ast_cli_register_multiple(void);
84 void ast_register_file_version(void);
85 void ast_unregister_file_version(void);
86 int ast_add_extension2(struct ast_context *con,
87                                            int replace, const char *extension, int priority, const char *label, const char *callerid,
88                                                 const char *application, void *data, void (*datad)(void *),
89                                            const char *registrar);
90 void pbx_builtin_setvar(void *chan, void *data);
91 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar);
92 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar);
93 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar);
94 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar);
95 void ast_merge_contexts_and_delete(void);
96 void ast_context_verify_includes(void);
97 struct ast_context * ast_walk_contexts(void);
98 void ast_cli_unregister_multiple(void);
99 void ast_context_destroy(void);
100 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...);
101 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with);
102 void ast_verbose(const char *fmt, ...);
103 struct ast_app *pbx_findapp(const char *app);
104 void filter_leading_space_from_exprs(char *str);
105 void filter_newlines(char *str);
106 static int quiet = 0;
107 static int no_comp = 0;
108 static int use_curr_dir = 0;
109 static int dump_extensions = 0;
110 static int FIRST_TIME = 0;
111 static FILE *dumpfile;
112
113 struct ast_app *pbx_findapp(const char *app)
114 {
115         return (struct ast_app*)1; /* so as not to trigger an error */
116 }
117
118 void ast_add_profile(void)
119 {
120         if (!no_comp)
121                 printf("Executed ast_add_profile();\n");
122 }
123
124 int ast_loader_register(int (*updater)(void))
125 {
126         return 1;
127 }
128
129 int ast_loader_unregister(int (*updater)(void))
130 {
131         return 1;
132 }
133 void ast_module_register(const struct ast_module_info *x)
134 {
135 }
136
137 void ast_module_unregister(const struct ast_module_info *x)
138 {
139 }
140
141
142 void ast_cli_register_multiple(void)
143 {
144         if(!no_comp)
145                 printf("Executed ast_cli_register_multiple();\n");
146 }
147
148 void ast_register_file_version(void)
149 {
150         /* if(!no_comp)
151                 printf("Executed ast_register_file_version();\n"); */
152         /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
153 }
154
155 void ast_unregister_file_version(void)
156 {
157         /* if(!no_comp)
158                 printf("Executed ast_unregister_file_version();\n"); */
159         /* I'm erasing this, because I don't think anyone really ever needs to see it anyway */
160
161 }
162 int ast_add_extension2(struct ast_context *con,
163                         int replace, const char *extension, int priority, const char *label, const char *callerid,
164                         const char *application, void *data, void (*datad)(void *),
165                         const char *registrar)
166 {
167         priors++;
168         con->extension_count++;
169         if (strcmp(extension,last_exten) != 0) {
170                 extens++;
171                 strcpy(last_exten, extension);
172         }
173         if (!label) {
174                 label = "(null)";
175         }
176         if (!callerid) {
177                 callerid = "(null)";
178         }
179         if (!application) {
180                 application = "(null)";
181         }
182
183         if(!no_comp)
184                 printf("Executed ast_add_extension2(context=%s, rep=%d, exten=%s, priority=%d, label=%s, callerid=%s, appl=%s, data=%s, FREE, registrar=%s);\n",
185                            con->name, replace, extension, priority, label, callerid, application, (data?(char*)data:"(null)"), registrar);
186
187         if( dump_extensions && dumpfile ) {
188                 struct namelist *n;
189
190                 if( FIRST_TIME ) {
191                         FIRST_TIME = 0;
192                         
193                         if( globalvars )
194                                 fprintf(dumpfile,"[globals]\n");
195                         
196                         for(n=globalvars;n;n=n->next) {
197                                 fprintf(dumpfile, "%s\n", n->name);
198                         }
199                 }
200                 
201                 /* print out each extension , possibly the context header also */
202                 if( con != last_context ) {
203                         fprintf(dumpfile,"\n\n[%s]\n", con->name);
204                         last_context = con;
205                         for(n=con->ignorepats;n;n=n->next) {
206                                 fprintf(dumpfile, "ignorepat => %s\n", n->name);
207                         }
208                         for(n=con->includes;n;n=n->next) {
209                                 fprintf(dumpfile, "include => %s\n", n->name);
210                         }
211                         for(n=con->switches;n;n=n->next) {
212                                 fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
213                         }
214                         for(n=con->eswitches;n;n=n->next) {
215                                 fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
216                         }
217                         
218                 }
219                 if( data ) {
220                         filter_newlines((char*)data);
221                         filter_leading_space_from_exprs((char*)data);
222
223                         if( strcmp(label,"(null)") != 0  )
224                                 fprintf(dumpfile,"exten => %s,%d(%s),%s(%s)\n", extension, priority, label, application, (char*)data);
225                         else
226                                 fprintf(dumpfile,"exten => %s,%d,%s(%s)\n", extension, priority, application, (char*)data);
227
228                 } else {
229
230                         if( strcmp(label,"(null)") != 0  )
231                                 fprintf(dumpfile,"exten => %s,%d(%s),%s\n", extension, priority, label, application);
232                         else
233                                 fprintf(dumpfile,"exten => %s,%d,%s\n", extension, priority, application);
234                 }
235         }
236         
237         /* since add_extension2 is responsible for the malloc'd data stuff */
238         if( data )
239                 free(data);
240         return 0;
241 }
242
243 void pbx_builtin_setvar(void *chan, void *data)
244 {
245         struct namelist *x = create_name((char*)data);
246         if(!no_comp)
247                 printf("Executed pbx_builtin_setvar(chan, data=%s);\n", (char*)data);
248
249         if( dump_extensions ) {
250                 x = create_name((char*)data);
251                 ADD_LAST(globalvars,x);
252         }
253 }
254         
255
256 struct ast_context * ast_context_create(void **extcontexts, const char *name, const char *registrar)
257 {
258         struct ast_context *x = calloc(1, sizeof(*x));
259         if (!x)
260                 return NULL;
261         x->next = context_list;
262         context_list = x;
263         if (!no_comp)
264                 printf("Executed ast_context_create(conts, name=%s, registrar=%s);\n", name, registrar);
265         conts++;
266         strncpy(x->name, name, sizeof(x->name) - 1);
267         strncpy(x->registrar, registrar, sizeof(x->registrar) - 1);
268         return x;
269 }
270
271 void ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
272 {
273         if(!no_comp)
274                 printf("Executed ast_context_add_ignorepat2(con, value=%s, registrar=%s);\n", value, registrar);
275         if( dump_extensions ) {
276                 struct namelist *x;
277                 x = create_name((char*)value);
278                 ADD_LAST(con->ignorepats,x);
279         }
280 }
281
282 void ast_context_add_include2(struct ast_context *con, const char *value, const char *registrar)
283 {
284         if(!no_comp)
285                 printf("Executed ast_context_add_include2(con, value=%s, registrar=%s);\n", value, registrar);
286         if( dump_extensions ) {
287                 struct namelist *x;
288                 x = create_name((char*)value);
289                 ADD_LAST(con->includes,x);
290         }
291 }
292
293 void ast_context_add_switch2(struct ast_context *con, const char *value, const char *data, int eval, const char *registrar)
294 {
295         if(!no_comp)
296                 printf("Executed ast_context_add_switch2(con, value=%s, data=%s, eval=%d, registrar=%s);\n", value, data, eval, registrar);
297         if( dump_extensions ) {
298                 struct namelist *x;
299                 x = create_name((char*)value);
300                 strncpy(x->name2,data,100);
301                 if( eval ) {
302
303                         ADD_LAST(con->switches,x);
304
305                 } else {
306
307                         ADD_LAST(con->eswitches,x);
308                 }
309         }
310 }
311
312 void ast_merge_contexts_and_delete(void)
313 {
314         if(!no_comp)
315                 printf("Executed ast_merge_contexts_and_delete();\n");
316 }
317
318 void ast_context_verify_includes(void)
319 {
320         if(!no_comp)
321                 printf("Executed ast_context_verify_includes();\n");
322 }
323
324 struct ast_context * ast_walk_contexts(void)
325 {
326         if(!no_comp)
327                 printf("Executed ast_walk_contexts();\n");
328         return 0;
329 }
330
331 void ast_cli_unregister_multiple(void)
332 {
333         if(!no_comp)
334                 printf("Executed ast_cli_unregister_multiple();\n");
335 }
336
337 void ast_context_destroy(void)
338 {
339         if( !no_comp)
340                 printf("Executed ast_context_destroy();\n");
341 }
342
343 void ast_log(int level, const char *file, int line, const char *function, const char *fmt, ...)
344 {
345         va_list vars;
346         va_start(vars,fmt);
347         if( !quiet || level > 2 ) {
348             printf("LOG: lev:%d file:%s  line:%d func: %s  ",
349                    level, file, line, function);
350             vprintf(fmt, vars);
351             fflush(stdout);
352             va_end(vars);
353         }
354 }
355
356 void ast_verbose(const char *fmt, ...)
357 {
358         va_list vars;
359         va_start(vars,fmt);
360
361         printf("VERBOSE: ");
362         vprintf(fmt, vars);
363         fflush(stdout);
364         va_end(vars);
365 }
366
367 char *ast_process_quotes_and_slashes(char *start, char find, char replace_with)
368 {
369         char *dataPut = start;
370         int inEscape = 0;
371         int inQuotes = 0;
372
373         for (; *start; start++) {
374                 if (inEscape) {
375                         *dataPut++ = *start;       /* Always goes verbatim */
376                         inEscape = 0;
377                 } else {
378                         if (*start == '\\') {
379                                 inEscape = 1;      /* Do not copy \ into the data */
380                         } else if (*start == '\'') {
381                                 inQuotes = 1-inQuotes;   /* Do not copy ' into the data */
382                         } else {
383                                 /* Replace , with |, unless in quotes */
384                                 *dataPut++ = inQuotes ? *start : ((*start==find) ? replace_with : *start);
385                         }
386                 }
387         }
388         if (start != dataPut)
389                 *dataPut = 0;
390         return dataPut;
391 }
392
393 void filter_leading_space_from_exprs(char *str)
394 {
395         /*  Mainly for aesthetics */
396         char *t, *v, *u = str;
397         
398         while ( u && *u ) {
399
400                 if( *u == '$' && *(u+1) == '[' ) {
401                         t = u+2;
402                         while( *t == '\n' || *t == '\r' || *t == '\t' || *t == ' ' ) {
403                                 v = t;
404                                 while ( *v ) {
405                                         *v = *(v+1);
406                                         v++;
407                                 }
408                         }
409                 }
410                 
411                 u++;
412         }
413 }
414
415 void filter_newlines(char *str)
416 {
417         /* remove all newlines, returns  */
418         char *t=str;
419         while( t && *t ) {
420                 if( *t == '\n' || *t == '\r' ) {
421                         *t = ' '; /* just replace newlines and returns with spaces; they act as
422                                                  token separators, and just blindly removing them could be
423                                                  harmful. */
424                 }
425                 t++;
426         }
427 }
428
429
430 extern struct module_symbols mod_data;
431 extern int ael_external_load_module(void);
432
433 int main(int argc, char **argv)
434 {
435         int i;
436         struct namelist *n;
437         struct ast_context *lp,*lp2;
438         
439         for(i=1;i<argc;i++) {
440                 if( argv[i][0] == '-' && argv[i][1] == 'n' )
441                         no_comp =1;
442                 if( argv[i][0] == '-' && argv[i][1] == 'q' ) {
443                         quiet = 1;
444                         no_comp =1;
445                 }
446                 if( argv[i][0] == '-' && argv[i][1] == 'd' )
447                         use_curr_dir =1;
448                 if( argv[i][0] == '-' && argv[i][1] == 'w' )
449                         dump_extensions =1;
450         }
451         
452         if( !quiet ) {
453                 printf("\n(If you find progress and other non-error messages irritating, you can use -q to suppress them)\n");
454                 if( !no_comp )
455                         printf("\n(You can use the -n option if you aren't interested in seeing all the instructions generated by the compiler)\n\n");
456                 if( !use_curr_dir )
457                         printf("\n(You can use the -d option if you want to use the current working directory as the CONFIG_DIR. I will look in this dir for extensions.ael* and its included files)\n\n");
458                 if( !dump_extensions )
459                         printf("\n(You can use the -w option to dump extensions.conf format to extensions.conf.aeldump)\n");
460         }
461
462         if( use_curr_dir ) {
463                 strcpy(ast_config_AST_CONFIG_DIR, ".");
464         }
465         else {
466                 strcpy(ast_config_AST_CONFIG_DIR, "/etc/asterisk");
467         }
468         strcpy(ast_config_AST_VAR_DIR, "/var/lib/asterisk");
469         
470         if( dump_extensions ) {
471                 dumpfile = fopen("extensions.conf.aeldump","w");
472                 if( !dumpfile ) {
473                         printf("\n\nSorry, cannot open extensions.conf.aeldump for writing! Correct the situation and try again!\n\n");
474                         exit(10);
475                 }
476                 
477         }
478
479         FIRST_TIME = 1;
480         
481         ael_external_load_module();
482         
483         ast_log(4, "ael2_parse", __LINE__, "main", "%d contexts, %d extensions, %d priorities\n", conts, extens, priors);
484
485         if( dump_extensions && dumpfile ) {
486         
487                 for( lp = context_list; lp; lp = lp->next ) { /* print out any contexts that didn't have any
488                                                                                                                  extensions in them */
489                         if( lp->extension_count == 0 ) {
490                                 
491                                 fprintf(dumpfile,"\n\n[%s]\n", lp->name);
492                                 
493                                 for(n=lp->ignorepats;n;n=n->next) {
494                                         fprintf(dumpfile, "ignorepat => %s\n", n->name);
495                                 }
496                                 for(n=lp->includes;n;n=n->next) {
497                                         fprintf(dumpfile, "include => %s\n", n->name);
498                                 }
499                                 for(n=lp->switches;n;n=n->next) {
500                                         fprintf(dumpfile, "switch => %s/%s\n", n->name, n->name2);
501                                 }
502                                 for(n=lp->eswitches;n;n=n->next) {
503                                         fprintf(dumpfile, "eswitch => %s/%s\n", n->name, n->name2);
504                                 }
505                         }
506                 }
507         }
508         
509         if( dump_extensions && dumpfile )
510                 fclose(dumpfile);
511         
512         for( lp = context_list; lp; lp = lp2 ) { /* free the ast_context structs */
513                 lp2 = lp->next;
514                 lp->next = 0;
515
516                 destroy_namelist(lp->includes);
517                 destroy_namelist(lp->ignorepats);
518                 destroy_namelist(lp->switches);
519                 destroy_namelist(lp->eswitches);
520
521                 free(lp);
522         }
523         
524     return 0;
525 }