chiark / gitweb /
Moved xmalloc etc. into both.c
[userv.git] / parser.c
index 898bbfac2c3f2f0d9e1d8ac6e3d2ba1cfd0092fa..0d1054ff29ae454f92474e6711e711549a4ab0e6 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -6,7 +6,7 @@
  * about m4 quoting &c., but we have to #include it so that the C
  * objects from the lexer are available.
  *
- * Copyright (C)1996-1997 Ian Jackson
+ * Copyright (C)1996-1999 Ian Jackson
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
@@ -139,7 +139,7 @@ static void freecharparray(char **array) {
 static int dequote(char *inplace) {
   char *p, *q, buf[4], *bep;
   int v;
-  
+
   p=q=inplace;
   assert(*p++ = '"');
   while (*p && *p != '"') {
@@ -149,30 +149,42 @@ static int dequote(char *inplace) {
     case 'r': *q++= '\r'; continue;
     case 't': *q++= '\t'; continue;
     case 'x':
-      assert(buf[0]= *++p); assert(buf[1]= *++p); buf[2]= 0;
-      v= strtoul(buf,&bep,16); assert(bep == buf+2);
-      assert(!(v & ~0xff)); *q++= v; p++; continue;
+      p++;
+      if (!((buf[0]= *p++) && (buf[1]= *p++))) {
+       parseerrprint("quoted string ends inside \\x<hex> sequence");
+       return tokv_error;
+      }
+      buf[2]= 0;
+      v= strtoul(buf,&bep,16);
+      if (bep != buf+2) {
+       parseerrprint("invalid \\<hex> sequence \\x%s in quoted string",buf);
+       return tokv_error;
+      }
+      assert(!(v & ~0xff));
+      *q++= v;
+      continue;
     default:
       if (isalpha(*p)) {
         parseerrprint("unknown \\<letter> sequence \\%c in quoted string",*p);
         return tokv_error;
       } else if (isdigit(*p)) {
-        assert(buf[0]= *++p); assert(buf[1]= *++p); assert(buf[2]= *++p);
+        if (!((buf[0]= *p++) && (buf[1]= *p++) && (buf[2]= *p++))) abort();
         buf[3]= 0; v= strtoul(buf,&bep,8);
-        if (bep != buf+3 || (v & ~0xff)); {
+        if (bep != buf+3 || (v & ~0xff)) {
           parseerrprint("invalid \\<octal> sequence \\%s in quoted string",buf);
           return tokv_error;
         }
-        *q++= v; p++; continue;
+        *q++= v; continue;
       } else if (ispunct(*p)) {
         *q++= *p++; continue;
       } else {
        while (*p==' ' || *p=='\t') p++;
-       assert(*p=='\n');
+       v= *p++; assert(v=='\n');
       }
     }
   }
   assert(*p); assert(!*++p);
+  *q++= 0;
   return tokv_quotedstring;
 }
 
@@ -358,6 +370,7 @@ static int paa_message(const char **message_r) {
   /* Returned value is invalidated by repeated calls. */
   static char *buildbuf;
   static int buildbuflen;
+  const char *usetext;
 
   int r, tl;
 
@@ -372,9 +385,10 @@ static int paa_message(const char **message_r) {
       return tokv_error;
     }
     if (r == tokv_newline) break;
-    tl+= strlen(yytext);
+    usetext= r == tokv_lwsp ? " " : yytext;
+    tl+= strlen(usetext);
     if (makeroom(&buildbuf,&buildbuflen,tl)) return stringoverflow("message");
-    strcat(buildbuf,yytext);
+    strcat(buildbuf,usetext);
   }
   *message_r= buildbuf;
   return 0;
@@ -487,7 +501,7 @@ static int pf_service(int ptoken, char ***rvalues) {
 }
 
 static int pf_callinguser(int ptoken, char ***rvalues) {
-  return parm_usernameuid(rvalues,logname,request_mbuf.callinguid);
+  return parm_usernameuid(rvalues,loginname,request_mbuf.callinguid);
 }
 
 static int pf_serviceuser(int ptoken, char ***rvalues) {
@@ -838,8 +852,7 @@ int df_reset(int dtoken) {
 
   r= pa_mnl(); if (r) return r;
   r= parse_string(RESET_CONFIGURATION,"<builtin reset configuration>",1);
-  assert(!r);
-  return 0;  
+  return r;
 }
 
 int dfg_fdwant(int dtoken) {
@@ -986,14 +999,16 @@ int df_includedirectory(int dtoken) {
   int r, cpl, tel, c, found;
   DIR *d;
   struct dirent *de;
-  const char *p, *cp;
+  const char *p, *cpget;
+  char *cp;
   
-  r= paa_1path(&cp); if (r) return r;
-  d= opendir(cp);
+  r= paa_1path(&cpget); if (r) return r;
+  d= opendir(cpget);
   if (!d) {
-    parseerrprint("unable to open directory `%s': %s",cp,strerror(errno));
+    parseerrprint("unable to open directory `%s': %s",cpget,strerror(errno));
     return tokv_error;
   }
+  cp= xstrsave(cpget);
   cpl= strlen(cp);
   while ((de= readdir(d))) {
     tel= strlen(de->d_name);
@@ -1002,60 +1017,72 @@ int df_includedirectory(int dtoken) {
     if (!*p || !isalnum(*p)) continue;
     while ((c= *++p)) if (!(isalnum(c) || c=='-')) break;
     if (c) continue;
-    if (makeroom(&buildbuf,&buildbuflen,cpl+1+tel+1))
-      return stringoverflow("pathname in directory");
+    if (makeroom(&buildbuf,&buildbuflen,cpl+1+tel+1)) {
+      stringoverflow("pathname in directory");
+      r= tokv_error; goto x_err;
+    }
     snyprintf(buildbuf,buildbuflen,"%s/%s",cp,de->d_name);
-    r= parse_file(buildbuf,&found); if (r) { closedir(d); return r; }
+    r= parse_file(buildbuf,&found); if (r) goto x_err;
     if (!found) {
       parseerrprint("unable to open file `%s' in included directory `%s': %s",
                    de->d_name,cp,strerror(errno));
-      closedir(d);
-      return tokv_error;
+      r= tokv_error; goto x_err;
     }
   }
   if (closedir(d)) {
     parseerrprint("error closing directory `%s': %s",cp,strerror(errno));
+    free(cp);
     return tokv_error;
   }
+  free(cp);
   return 0;
+
+x_err:
+  closedir(d);
+  free(cp);
+  return r;
 }
 
 int df_includelookup(int dtoken) {
   static char *buildbuf=0;
   int buildbuflen=0;
   
-  char **parmvalues, **pp, *p, *q;
-  const char *cp;
+  char **parmvalues, **pp, *p, *q, *cp;
+  const char *cpget;
   struct stat stab;
   int r, done, thisdone, cpl, c;
 
   r= pa_mwsp(); if (r) return r;
   r= pa_parameter(&parmvalues,0); if (r) return r;
-  r= paa_1path(&cp); if (r) { freecharparray(parmvalues); return r; }
-  if (stat(cp,&stab)) {
-    parseerrprint("unable to access directory `%s': %s",cp,strerror(errno));
+  r= paa_1path(&cpget); if (r) { freecharparray(parmvalues); return r; }
+  if (stat(cpget,&stab)) {
+    parseerrprint("unable to access directory `%s': %s",cpget,strerror(errno));
     freecharparray(parmvalues); return tokv_error;
   }
   if (!S_ISDIR(stab.st_mode)) {
-    parseerrprint("object `%s' is not a directory or link to one",cp);
+    parseerrprint("object `%s' is not a directory or link to one",cpget);
     freecharparray(parmvalues); return tokv_error;
   }
   done= 0;
+  cp= xstrsave(cpget);
   cpl= strlen(cp);
   if (!parmvalues[0]) {
-    if (makeroom(&buildbuf,&buildbuflen,cpl+1+sizeof(NONEINCLUDELOOKUP)))
-      return stringoverflow("pathname in directory for lookup of undefined parameter");
+    if (makeroom(&buildbuf,&buildbuflen,cpl+1+sizeof(NONEINCLUDELOOKUP))) {
+      stringoverflow("pathname in directory for lookup of undefined parameter");
+      r= tokv_error; goto x_err;
+    }
     snyprintf(buildbuf,buildbuflen,"%s/" NONEINCLUDELOOKUP,cp);
-    r= parse_file(buildbuf,&thisdone);
-    if (r) { freecharparray(parmvalues); return r; }
+    r= parse_file(buildbuf,&thisdone); if (r) goto x_err;
     if (thisdone) done= 1;
   } else {
     for (pp=parmvalues;
         *pp && (!done || dtoken == tokv_word_includelookupall);
         pp++) {
       if (makeroom(&buildbuf,&buildbuflen,
-                  cpl+1+strlen(*pp)*2+3+sizeof(EMPTYINCLUDELOOKUP)+1))
-       return stringoverflow("pathname in directory for lookup");
+                  cpl+1+strlen(*pp)*2+3+sizeof(EMPTYINCLUDELOOKUP)+1)) {
+       stringoverflow("pathname in directory for lookup");
+       r= tokv_error; goto x_err;
+      }
       strcpy(buildbuf,cp);
       p= *pp; q= buildbuf+cpl;
       *q++= '/';
@@ -1064,26 +1091,38 @@ int df_includelookup(int dtoken) {
       } else {
        if (*p=='.') *q++= ':';
        while ((c= *p++)) {
-         if (c=='/') { *q++= ':'; c='-'; }
-         else if (c==':') { *q++= ':'; }
+         if (c=='/') {
+           *q++= ':';
+           c= '-';
+         } else if (!((c >= '0' && c <= '9') ||
+                      (c >= 'a' && c <= 'z') ||
+                      c == '-' || c == '_')) {
+           *q++= ':';
+         }
          *q++= c;
        }
        *q++= 0;
       }
       r= parse_file(buildbuf,&thisdone);
-      if (r) { freecharparray(parmvalues); return r; }
+      if (r) goto x_err;
       if (thisdone) done= 1;
     }
   }
-  freecharparray(parmvalues);
   if (!done) {
     if (makeroom(&buildbuf,&buildbuflen,
-                cpl+1+sizeof(DEFAULTINCLUDELOOKUP)))
-      return stringoverflow("pathname in directory for lookup of default");
+                cpl+1+sizeof(DEFAULTINCLUDELOOKUP))) {
+      stringoverflow("pathname in directory for lookup of default");
+      r= tokv_error; goto x_err;
+    }
     snyprintf(buildbuf,buildbuflen,"%s/" DEFAULTINCLUDELOOKUP,cp);
-    r= parse_file(buildbuf,0); if (r) return r;
+    r= parse_file(buildbuf,0); if (r) goto x_err;
   }
-  return 0;
+  r= 0;
+  
+x_err:
+  freecharparray(parmvalues);
+  free(cp);
+  return r;
 }
 
 /* Control constructs */
@@ -1235,8 +1274,10 @@ static void parser_pop(void) {
 }
 
 int parse_string(const char *string, const char *descrip, int isinternal) {
-  /* Returns the same things as parser, except that tokv_eof
-   * is turned into 0.
+  /* Returns the same things as parser, except that tokv_eof is turned
+   * into 0.  *string must be statically allocated or copied, so that
+   * it is not overwritten while the parsing takes place (unlike with
+   * parse_file).
    */
   static const struct stat blankstab;
   
@@ -1256,9 +1297,10 @@ int parse_string(const char *string, const char *descrip, int isinternal) {
 }
 
 static int parse_file(const char *string, int *didexist) {
-  /* Returns the same things as parser, except that tokv_eof
-   * is turned into 0.  If *didexist is 0 then errno will
-   * have been set.
+  /* Returns the same things as parser, except that tokv_eof is turned
+   * into 0.  If *didexist is 0 then errno will have been set.
+   * *string will be copied by parse_file so it may be be overwritten
+   * during the parsing (so, for example, yytext need not be copied).
    */
   static int fileparselevel= 0;
   
@@ -1266,6 +1308,7 @@ static int parse_file(const char *string, int *didexist) {
   YY_BUFFER_STATE ybuf;
   int r;
   FILE *file;
+  char *filename;
   struct stat newstab;
 
   if (fileparselevel >= MAX_INCLUDE_NEST) {
@@ -1296,7 +1339,8 @@ static int parse_file(const char *string, int *didexist) {
 
   ybuf= yy_create_buffer(file,YY_BUF_SIZE);
   if (!ybuf) syscallerror("unable to create flex buffer for file");
-  parser_push(&usestate,string,&newstab,ybuf,0);
+  filename= xstrsave(string);
+  parser_push(&usestate,filename,&newstab,ybuf,0);
   fileparselevel++;
   
   r= parser(0);
@@ -1304,9 +1348,10 @@ static int parse_file(const char *string, int *didexist) {
     parseerrprint("error reading configuration file `%s'",string);
     r= tokv_error;
   }
-  
+
   fileparselevel--;
   parser_pop();
+  free(filename);
   fclose(file);
   if (r == tokv_eof) r= 0;
   return r;