Browse code

core: support for include file in cfg

- syntax:
include path/to/file
- example:
include checks.cfg
- path can be absolute or relative
- if path is relative:
- first attempt is to open the file relative to current directory
- second attempt is to open the file relative to the directory
of the file including it
- if include file fails, then print error and exit
- cfg syntax error messages print file name
- there is no restriction where 'include' can be used, can have
global parameters, module configs or entire/parts of route blocks

Daniel-Constantin Mierla authored on 25/08/2009 16:27:01
Showing 3 changed files
... ...
@@ -122,6 +122,7 @@
122 122
 	int column=1;
123 123
 	int startcolumn=1;
124 124
 	int startline=1;
125
+	char *finame = 0;
125 126
 	static int ign_lines=0;
126 127
 	static int ign_columns=0;
127 128
 	char* yy_number_str=0; /* str correspondent for the current NUMBER token */
... ...
@@ -132,12 +133,30 @@
132 132
 	static void count_more();
133 133
 	static void count_ignore();
134 134
 
135
+	#define MAX_INCLUDE_DEPTH 10
136
+	static struct sr_yy_state {
137
+		YY_BUFFER_STATE state;
138
+		int line;
139
+		int column;
140
+		int startcolumn;
141
+		int startline;
142
+		char *finame;
143
+	} include_stack[MAX_INCLUDE_DEPTH];
144
+	static int include_stack_ptr = 0;
145
+
146
+	static int sr_push_yy_state(char *fin);
147
+	static int sr_pop_yy_state();
148
+
149
+	static struct sr_yy_fname {
150
+		char *fname;
151
+		struct sr_yy_fname *next;
152
+	} *sr_yy_fname_list = 0;
135 153
 
136 154
 %}
137 155
 
138 156
 /* start conditions */
139 157
 %x STRING1 STRING2 STR_BETWEEN COMMENT COMMENT_LN ATTR SELECT AVP_PVAR PVAR_P 
140
-%x PVARID
158
+%x PVARID INCL
141 159
 
142 160
 /* config script types : #!SER  or #!KAMAILIO or #!MAX_COMPAT */
143 161
 SER_CFG			SER
... ...
@@ -201,6 +220,8 @@ CASE			"case"
201 201
 DEFAULT			"default"
202 202
 WHILE			"while"
203 203
 
204
+INCLUDE         "include"
205
+
204 206
 /*ACTION LVALUES*/
205 207
 URIHOST			"uri:host"
206 208
 URIPORT			"uri:port"
... ...
@@ -556,6 +577,8 @@ EAT_ABLE	[\ \t\b\r]
556 556
 <INITIAL>{DEFAULT}	{ count(); yylval.strval=yytext; return DEFAULT; }
557 557
 <INITIAL>{WHILE}	{ count(); yylval.strval=yytext; return WHILE; }
558 558
 
559
+<INITIAL>{INCLUDE}  { BEGIN(INCL); }
560
+
559 561
 <INITIAL>{URIHOST}	{ count(); yylval.strval=yytext; return URIHOST; }
560 562
 <INITIAL>{URIPORT}	{ count(); yylval.strval=yytext; return URIPORT; }
561 563
 
... ...
@@ -1097,6 +1120,13 @@ EAT_ABLE	[\ \t\b\r]
1097 1097
 
1098 1098
 <SELECT>.               { unput(yytext[0]); state = INITIAL_S; BEGIN(INITIAL); } /* Rescan the token in INITIAL state */
1099 1099
 
1100
+<INCL>[ \t]*      /* eat the whitespace */
1101
+<INCL>[^ \t\n]+   { /* get the include file name */
1102
+				if(sr_push_yy_state(yytext)<0)
1103
+					exit(-1);
1104
+				BEGIN(INITIAL);
1105
+}
1106
+
1100 1107
 
1101 1108
 <<EOF>>							{
1102 1109
 									switch(state){
... ...
@@ -1141,7 +1171,8 @@ EAT_ABLE	[\ \t\b\r]
1141 1141
 													" while parsing"
1142 1142
 													" avp or pvar name\n");
1143 1143
 									}
1144
-									return 0;
1144
+									if(sr_pop_yy_state()<0)
1145
+										return 0;
1145 1146
 								}
1146 1147
 
1147 1148
 %%
... ...
@@ -1253,3 +1284,127 @@ int yywrap()
1253 1253
 {
1254 1254
 	return 1;
1255 1255
 }
1256
+
1257
+static int sr_push_yy_state(char *fin)
1258
+{
1259
+	struct sr_yy_fname *fn = NULL;
1260
+	char *x = NULL;
1261
+	char *newf = NULL;
1262
+
1263
+	if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
1264
+	{
1265
+		LOG(L_CRIT, "too many includes\n");
1266
+		return -1;
1267
+	}
1268
+
1269
+	include_stack[include_stack_ptr].state = YY_CURRENT_BUFFER;
1270
+	include_stack[include_stack_ptr].line = line;
1271
+	include_stack[include_stack_ptr].column = column;
1272
+	include_stack[include_stack_ptr].startline = startline;
1273
+	include_stack[include_stack_ptr].startcolumn = startcolumn;
1274
+	include_stack[include_stack_ptr].finame = finame;
1275
+	include_stack_ptr++;
1276
+
1277
+	line=1;
1278
+	column=1;
1279
+	startline=1;
1280
+	startcolumn=1;
1281
+
1282
+	yyin = fopen(fin, "r" );
1283
+
1284
+	if ( ! yyin )
1285
+	{
1286
+		finame = (finame==0)?cfg_file:finame;
1287
+		if(finame==0 || fin[0]=='/')
1288
+		{
1289
+			LOG(L_CRIT, "cannot open included file: %s\n", fin);
1290
+			return -1;
1291
+		}
1292
+		x = strrchr(finame, '/');
1293
+		if(x)
1294
+		{
1295
+			newf = (char*)pkg_malloc(x-finame+strlen(fin)+2);
1296
+			if(newf==0)
1297
+			{
1298
+				LOG(L_CRIT, "no more pkg\n");
1299
+				return -1;
1300
+			}
1301
+			newf[0] = '\0';
1302
+			strncat(newf, finame, x-finame);
1303
+			strcat(newf, "/");
1304
+			strcat(newf, fin);
1305
+		}
1306
+		yyin = fopen(newf, "r" );
1307
+		if ( ! yyin )
1308
+		{
1309
+			LOG(L_CRIT, "cannot open included file: %s (%s)\n", fin, newf);
1310
+			return -1;
1311
+		}
1312
+		LOG(L_DBG, "including file: %s (%s)\n", fin, newf);
1313
+	} else {
1314
+		newf = fin;
1315
+	}
1316
+
1317
+	fn = sr_yy_fname_list;
1318
+	while(fn!=0)
1319
+	{
1320
+		if(strcmp(fn->fname, newf)==0)
1321
+		{
1322
+			if(newf!=fin)
1323
+				pkg_free(newf);
1324
+			newf = fin;
1325
+			break;
1326
+		}
1327
+		fn = fn->next;
1328
+	}
1329
+	if(fn==0)
1330
+	{
1331
+		fn = (struct sr_yy_fname*)pkg_malloc(sizeof(struct sr_yy_fname));
1332
+		if(fn==0)
1333
+		{
1334
+			if(newf!=fin)
1335
+				pkg_free(newf);
1336
+			LOG(L_CRIT, "no more pkg\n");
1337
+			return -1;
1338
+		}
1339
+		if(newf==fin)
1340
+		{
1341
+			fn->fname = (char*)pkg_malloc(strlen(fin)+1);
1342
+			if(fn->fname==0)
1343
+			{
1344
+				pkg_free(fn);
1345
+				LOG(L_CRIT, "no more pkg!\n");
1346
+				return -1;
1347
+			}
1348
+			strcpy(fn->fname, fin);
1349
+		} else {
1350
+			fn->fname = newf;
1351
+		}
1352
+		fn->next = sr_yy_fname_list;
1353
+		sr_yy_fname_list = fn;
1354
+	}
1355
+
1356
+	finame = fn->fname;
1357
+
1358
+	yy_switch_to_buffer( yy_create_buffer(yyin, YY_BUF_SIZE ) );
1359
+
1360
+	return 0;
1361
+
1362
+}
1363
+
1364
+static int sr_pop_yy_state()
1365
+{
1366
+	include_stack_ptr--;
1367
+	if (include_stack_ptr<0 )
1368
+		return -1;
1369
+
1370
+	yy_delete_buffer( YY_CURRENT_BUFFER );
1371
+	yy_switch_to_buffer(include_stack[include_stack_ptr].state);
1372
+	line=include_stack[include_stack_ptr].line;
1373
+	column=include_stack[include_stack_ptr].column;
1374
+	startline=include_stack[include_stack_ptr].startline;
1375
+	startcolumn=include_stack[include_stack_ptr].startcolumn;
1376
+	finame = include_stack[include_stack_ptr].finame;
1377
+	return 0;
1378
+}
1379
+
... ...
@@ -3070,7 +3070,7 @@ extern int line;
3070 3070
 extern int column;
3071 3071
 extern int startcolumn;
3072 3072
 extern int startline;
3073
-
3073
+extern char *finame;
3074 3074
 
3075 3075
 static void get_cpos(struct cfg_pos* pos)
3076 3076
 {
... ...
@@ -3078,6 +3078,9 @@ static void get_cpos(struct cfg_pos* pos)
3078 3078
 	pos->e_line=line;
3079 3079
 	pos->s_col=startcolumn;
3080 3080
 	pos->e_col=column-1;
3081
+	if(finame==0)
3082
+		finame = (cfg_file!=0)?cfg_file:"default";
3083
+	pos->fname=finame;
3081 3084
 }
3082 3085
 
3083 3086
 
... ...
@@ -3090,15 +3093,15 @@ static void warn_at(struct cfg_pos* p, char* format, ...)
3090 3090
 	vsnprintf(s, sizeof(s), format, ap);
3091 3091
 	va_end(ap);
3092 3092
 	if (p->e_line!=p->s_line)
3093
-		LOG(L_WARN, "warning in config file, from line %d, column %d to"
3093
+		LOG(L_WARN, "warning in config file %s, from line %d, column %d to"
3094 3094
 					" line %d, column %d: %s\n",
3095
-					p->s_line, p->s_col, p->e_line, p->e_col, s);
3095
+					p->fname, p->s_line, p->s_col, p->e_line, p->e_col, s);
3096 3096
 	else if (p->s_col!=p->e_col)
3097
-		LOG(L_WARN, "warning in config file, line %d, column %d-%d: %s\n",
3098
-					p->s_line, p->s_col, p->e_col, s);
3097
+		LOG(L_WARN, "warning in config file %s, line %d, column %d-%d: %s\n",
3098
+					p->fname, p->s_line, p->s_col, p->e_col, s);
3099 3099
 	else
3100
-		LOG(L_WARN, "warning in config file, line %d, column %d: %s\n",
3101
-				p->s_line, p->s_col, s);
3100
+		LOG(L_WARN, "warning in config file %s, line %d, column %d: %s\n",
3101
+				p->fname, p->s_line, p->s_col, s);
3102 3102
 	cfg_warnings++;
3103 3103
 }
3104 3104
 
... ...
@@ -3113,15 +3116,15 @@ static void yyerror_at(struct cfg_pos* p, char* format, ...)
3113 3113
 	vsnprintf(s, sizeof(s), format, ap);
3114 3114
 	va_end(ap);
3115 3115
 	if (p->e_line!=p->s_line)
3116
-		LOG(L_CRIT, "parse error in config file, from line %d, column %d"
3116
+		LOG(L_CRIT, "parse error in config file %s, from line %d, column %d"
3117 3117
 					" to line %d, column %d: %s\n",
3118
-					p->s_line, p->s_col, p->e_line, p->e_col, s);
3118
+					p->fname, p->s_line, p->s_col, p->e_line, p->e_col, s);
3119 3119
 	else if (p->s_col!=p->e_col)
3120
-		LOG(L_CRIT, "parse error in config file, line %d, column %d-%d: %s\n",
3121
-					p->s_line, p->s_col, p->e_col, s);
3120
+		LOG(L_CRIT,"parse error in config file %s, line %d, column %d-%d: %s\n",
3121
+					p->fname, p->s_line, p->s_col, p->e_col, s);
3122 3122
 	else
3123
-		LOG(L_CRIT, "parse error in config file, line %d, column %d: %s\n",
3124
-					p->s_line, p->s_col, s);
3123
+		LOG(L_CRIT, "parse error in config file %s, line %d, column %d: %s\n",
3124
+					p->fname, p->s_line, p->s_col, s);
3125 3125
 	cfg_errors++;
3126 3126
 }
3127 3127
 
... ...
@@ -136,6 +136,7 @@ struct cfg_pos{
136 136
 	int e_line;
137 137
 	unsigned short s_col;
138 138
 	unsigned short e_col;
139
+	char *fname;
139 140
 };
140 141
 
141 142