aboutsummaryrefslogtreecommitdiffstats
path: root/tools/libxl/libxlu_cfg.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-03-03 17:39:22 +0000
committerKeir Fraser <keir.fraser@citrix.com>2010-03-03 17:39:22 +0000
commitb104c3762dcbe310318a14bed35f0813db48a26d (patch)
tree6ec4448b8b7c28e306348ebad1b41a4555ff83f7 /tools/libxl/libxlu_cfg.c
parent24c2f2ccee02f7bf83bf8a9ffdb204cf8d40c653 (diff)
downloadxen-b104c3762dcbe310318a14bed35f0813db48a26d.tar.gz
xen-b104c3762dcbe310318a14bed35f0813db48a26d.tar.bz2
xen-b104c3762dcbe310318a14bed35f0813db48a26d.zip
Replace config file parser for "xl"
This provides a replacement config file parser for "xl" based on bison and flex. Benefits: * proper error reporting with line numbers * parser can understand nearly all "xm" configuration files directly (doesn't understand Python code but should do everything else) * parser also understands the ;-infested "xl" style files * removes the dependency on libconfig * better checking for certain kinds of mistakes * eliminates the strange "massage file and try again" code This is intended to support all config files currently supported by "xl" and almost all files supported by "xm". (NB that whether a feature works depends on the implementation of that feature in xl/libxl of course.) This patch also introduces a new library "libxlutil" which is mainly for the benefit of "xl". Users of libxl do not need to use libxlutil, but they can do so if they want to parse "xl" files without being "xl". Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com> Acked-by: Vincent Hanquez <vincent.hanquez@eu.citrix.com>
Diffstat (limited to 'tools/libxl/libxlu_cfg.c')
-rw-r--r--tools/libxl/libxlu_cfg.c341
1 files changed, 341 insertions, 0 deletions
diff --git a/tools/libxl/libxlu_cfg.c b/tools/libxl/libxlu_cfg.c
new file mode 100644
index 0000000000..632c371cf5
--- /dev/null
+++ b/tools/libxl/libxlu_cfg.c
@@ -0,0 +1,341 @@
+
+#include "libxlu_internal.h"
+#include "libxlu_cfg_y.h"
+#include "libxlu_cfg_l.h"
+#include "libxlu_cfg_i.h"
+
+XLU_Config *xlu_cfg_init(FILE *report, const char *report_filename) {
+ XLU_Config *cfg;
+
+ cfg= malloc(sizeof(*cfg));
+ if (!cfg) return 0;
+
+ cfg->report= report;
+ cfg->filename= strdup(report_filename);
+ if (!cfg->filename) { free(cfg); return 0; }
+
+ cfg->settings= 0;
+ return cfg;
+}
+
+int xlu_cfg_readfile(XLU_Config *cfg, const char *real_filename) {
+ CfgParseContext ctx;
+ FILE *f;
+ int e, r;
+
+ ctx.cfg= cfg;
+ ctx.err= 0;
+ ctx.lexerrlineno= -1;
+
+ f= fopen(real_filename, "r");
+ if (!f) {
+ e= errno;
+ fprintf(cfg->report,"%s: unable to open configuration file: %s\n",
+ real_filename, strerror(e));
+ return e;
+ }
+
+ e= xlu__cfg_yylex_init_extra(&ctx, &ctx.scanner);
+ if (e) {
+ fprintf(cfg->report,"%s: unable to create scanner: %s\n",
+ cfg->filename, strerror(e));
+ return e;
+ }
+
+ xlu__cfg_yyrestart(f, ctx.scanner);
+
+ r= xlu__cfg_yyparse(&ctx);
+ if (r) assert(ctx.err);
+
+ xlu__cfg_yylex_destroy(ctx.scanner);
+ fclose(f);
+
+ return ctx.err;
+}
+
+void xlu__cfg_set_free(XLU_ConfigSetting *set) {
+ free(set->name);
+ free(set->values);
+ free(set);
+}
+
+void xlu_cfg_destroy(XLU_Config *cfg) {
+ XLU_ConfigSetting *set, *set_next;
+
+ for (set= cfg->settings;
+ set;
+ set= set_next) {
+ set_next= set->next;
+ xlu__cfg_set_free(set);
+ }
+ free(cfg->filename);
+ free(cfg);
+}
+
+static XLU_ConfigSetting *find(const XLU_Config *cfg, const char *n) {
+ XLU_ConfigSetting *set;
+
+ for (set= cfg->settings;
+ set;
+ set= set->next)
+ if (!strcmp(set->name, n))
+ return set;
+ return 0;
+}
+
+static int find_atom(const XLU_Config *cfg, const char *n,
+ XLU_ConfigSetting **set_r) {
+ XLU_ConfigSetting *set;
+
+ set= find(cfg,n);
+ if (!set) return ESRCH;
+
+ if (set->avalues!=1) {
+ fprintf(cfg->report,
+ "%s:%d: warning: parameter `%s' is"
+ " a list but should be a single value\n",
+ cfg->filename, set->lineno, n);
+ return EINVAL;
+ }
+ *set_r= set;
+ return 0;
+}
+
+int xlu_cfg_get_string(const XLU_Config *cfg, const char *n,
+ const char **value_r) {
+ XLU_ConfigSetting *set;
+ int e;
+
+ e= find_atom(cfg,n,&set); if (e) return e;
+ *value_r= set->values[0];
+ return 0;
+}
+
+int xlu_cfg_get_long(const XLU_Config *cfg, const char *n,
+ long *value_r) {
+ long l;
+ XLU_ConfigSetting *set;
+ int e;
+ char *ep;
+
+ e= find_atom(cfg,n,&set); if (e) return e;
+ errno= 0; l= strtol(set->values[0], &ep, 0);
+ e= errno;
+ if (errno) {
+ e= errno;
+ assert(e==EINVAL || e==ERANGE);
+ fprintf(cfg->report,
+ "%s:%d: warning: parameter `%s' could not be parsed"
+ " as a number: %s\n",
+ cfg->filename, set->lineno, n, strerror(e));
+ return e;
+ }
+ if (*ep || ep==set->values[0]) {
+ fprintf(cfg->report,
+ "%s:%d: warning: parameter `%s' is not a valid number\n",
+ cfg->filename, set->lineno, n);
+ return EINVAL;
+ }
+ *value_r= l;
+ return 0;
+}
+
+
+int xlu_cfg_get_list(const XLU_Config *cfg, const char *n,
+ XLU_ConfigList **list_r, int *entries_r) {
+ XLU_ConfigSetting *set;
+ set= find(cfg,n); if (!set) return ESRCH;
+ if (set->avalues==1) {
+ fprintf(cfg->report,
+ "%s:%d: warning: parameter `%s' is a single value"
+ " but should be a list\n",
+ cfg->filename, set->lineno, n);
+ return EINVAL;
+ }
+ if (list_r) *list_r= set;
+ if (entries_r) *entries_r= set->nvalues;
+ return 0;
+}
+
+const char *xlu_cfg_get_listitem(const XLU_ConfigList *set, int entry) {
+ if (entry < 0 || entry >= set->nvalues) return 0;
+ return set->values[entry];
+}
+
+
+XLU_ConfigSetting *xlu__cfg_set_mk(CfgParseContext *ctx,
+ int alloc, char *atom) {
+ XLU_ConfigSetting *set= 0;
+
+ if (ctx->err) goto x;
+ assert(!!alloc == !!atom);
+
+ set= malloc(sizeof(*set));
+ if (!set) goto xe;
+
+ set->name= 0; /* tbd */
+ set->avalues= alloc;
+
+ if (!alloc) {
+ set->nvalues= 0;
+ set->values= 0;
+ } else {
+ set->values= malloc(sizeof(*set->values) * alloc);
+ if (!set->values) goto xe;
+
+ set->nvalues= 1;
+ set->values[0]= atom;
+ }
+ return set;
+
+ xe:
+ ctx->err= errno;
+ x:
+ free(set);
+ free(atom);
+ return 0;
+}
+
+void xlu__cfg_set_add(CfgParseContext *ctx, XLU_ConfigSetting *set,
+ char *atom) {
+ if (ctx->err) return;
+
+ assert(atom);
+
+ if (set->nvalues >= set->avalues) {
+ int new_avalues;
+ char **new_values;
+
+ if (set->avalues > INT_MAX / 100) { ctx->err= ERANGE; return; }
+ new_avalues= set->avalues * 4;
+ new_values= realloc(set->values,
+ sizeof(*new_values) * new_avalues);
+ if (!new_values) { ctx->err= errno; free(atom); return; }
+ set->values= new_values;
+ set->avalues= new_avalues;
+ }
+ set->values[set->nvalues++]= atom;
+}
+
+void xlu__cfg_set_store(CfgParseContext *ctx, char *name,
+ XLU_ConfigSetting *set, int lineno) {
+ if (ctx->err) return;
+
+ assert(name);
+ set->name= name;
+ set->lineno= lineno;
+ set->next= ctx->cfg->settings;
+ ctx->cfg->settings= set;
+}
+
+char *xlu__cfgl_strdup(CfgParseContext *ctx, const char *src) {
+ char *result;
+
+ if (ctx->err) return 0;
+ result= strdup(src);
+ if (!result) ctx->err= errno;
+ return result;
+}
+
+char *xlu__cfgl_dequote(CfgParseContext *ctx, const char *src) {
+ char *result;
+ const char *p;
+ char *q;
+ int len, c, nc;
+
+ if (ctx->err) return 0;
+
+ len= strlen(src);
+ assert(len>=2 && src[0]==src[len-1]);
+
+ result= malloc(len-1);
+ if (!result) { ctx->err= errno; return 0; }
+
+ q= result;
+
+ for (p= src+1;
+ p < src+len-1;
+ ) {
+ c= *p++;
+ if (c=='\\') {
+ assert(p < src+len-1);
+ nc= *p++;
+ if (nc=='"' || nc=='\'' || nc=='\\') {
+ *q++= nc;
+ } else if (nc=='a') { *q++= '\007';
+ } else if (nc=='b') { *q++= '\010';
+ } else if (nc=='f') { *q++= '\014';
+ } else if (nc=='n') { *q++= '\n';
+ } else if (nc=='r') { *q++= '\r';
+ } else if (nc=='t') { *q++= '\t';
+ } else if (nc=='v') { *q++= '\013';
+ } else if (nc=='x') {
+
+#define NUMERIC_CHAR(minlen,maxlen,base,basetext) do{ \
+ char numbuf[(maxlen)+1], *ep; \
+ unsigned long val; \
+ \
+ strncpy(numbuf,p,(maxlen)); \
+ numbuf[(maxlen)]= 0; \
+ val= strtoul(numbuf, &ep, (base)); \
+ if (ep <= numbuf+(minlen)) { \
+ xlu__cfgl_lexicalerror(ctx,"invalid digit after" \
+ " backslash " basetext "numerical character escape" \
+ " in quoted string"); \
+ ctx->err= EINVAL; \
+ goto x; \
+ } \
+ p += (ep - numbuf); \
+ }while(0)
+
+ p++;
+ NUMERIC_CHAR(2,2,16,"hex");
+ } else if (nc>='0' && nc<='7') {
+ NUMERIC_CHAR(1,3,10,"octal");
+ }
+ assert(p <= src+len-1);
+ } else {
+ *q++= c;
+ }
+ }
+
+ x:
+ *q++= 0;
+ return result;
+}
+
+void xlu__cfgl_lexicalerror(CfgParseContext *ctx, char const *msg) {
+ YYLTYPE loc;
+ loc.first_line= xlu__cfg_yyget_lineno(ctx->scanner);
+ xlu__cfg_yyerror(&loc, ctx, msg);
+ ctx->lexerrlineno= loc.first_line;
+}
+
+void xlu__cfg_yyerror(YYLTYPE *loc, CfgParseContext *ctx, char const *msg) {
+ const char *text, *newline;
+ int len, lineno;
+
+ lineno= loc->first_line;
+ if (lineno <= ctx->lexerrlineno) return;
+
+ text= xlu__cfg_yyget_text(ctx->scanner);
+ len= xlu__cfg_yyget_leng(ctx->scanner);
+ newline= "";
+ if (len>0 && text[len-1]=='\n') {
+ len--;
+ lineno--;
+ if (!len) {
+ newline= "<newline>";
+ }
+ }
+ while (len>0 && (text[len-1]=='\t' || text[len-1]==' ')) {
+ len--;
+ }
+
+ fprintf(ctx->cfg->report,
+ "%s:%d: config parsing error near %s%.*s%s%s: %s\n",
+ ctx->cfg->filename, lineno,
+ len?"`":"", len, text, len?"'":"", newline,
+ msg);
+ if (!ctx->err) ctx->err= EINVAL;
+}