chiark / gitweb /
Upgrade licence to GPLv3+.
[userv.git] / parser.c
index ecfe32239aac292c8c4e313997c5f8320db397fc..e65ff7986598dce3e0b043d72ca0c1b3bedca8a9 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -6,11 +6,14 @@
  * 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
+ * userv is
+ * Copyright 1996-2017 Ian Jackson <ian@davenant.greenend.org.uk>.
+ * Copyright 2000      Ben Harris <bjh21@cam.ac.uk>
+ * Copyright 2016-2017 Peter Benie <pjb1008@cam.ac.uk>
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful, but
@@ -19,8 +22,7 @@
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with userv; if not, write to the Free Software
- * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * along with userv; if not, see <http://www.gnu.org/licenses/>.
  */
 
 static int parse_file(const char *string, int *didexist);
@@ -98,7 +100,7 @@ static void errwhere(struct parser_state *tstate, char *bufput, int bufputlen) {
            tstate->filename,tstate->reportlineno);
 }
 
-void parseerrprint(const char *fmt, ...) {
+int parseerrprint(const char *fmt, ...) {
   va_list al;
   char errmsg[MAX_ERRMSG_LEN];
 
@@ -107,6 +109,8 @@ void parseerrprint(const char *fmt, ...) {
   vsnytprintfcat(errmsg,sizeof(errmsg),fmt,al);
   senderrmsg(errmsg,eh.handling);
   va_end(al);
+
+  return tokv_error;
 }
 
 static int unexpected(int found, int wanted, const char *wantedstr) {
@@ -115,13 +119,11 @@ static int unexpected(int found, int wanted, const char *wantedstr) {
    */
   if (found == wanted) return 0;
   if (found == tokv_error) return found;
-  parseerrprint("found %s, expected %s",printtoken(found),wantedstr);
-  return tokv_error;
+  return parseerrprint("found %s, expected %s",printtoken(found),wantedstr);
 }
 
 static int stringoverflow(const char *where) {
-  parseerrprint("string buffer became far too large building %s",where);
-  return tokv_error;
+  return parseerrprint("string buffer became far too large building %s",where);
 }
 
 /*
@@ -136,43 +138,55 @@ static void freecharparray(char **array) {
   free(array);
 }
 
+static void countnewlines(void) {
+  char *p;
+  for (p=yytext; *p; p++)
+    if (*p == '\n')
+      cstate->lineno++;
+}
+
 static int dequote(char *inplace) {
   char *p, *q, buf[4], *bep;
   int v;
-  
+
   p=q=inplace;
-  assert(*p++ = '"');
+  assert(*p=='"');  p++;
   while (*p && *p != '"') {
     if (*p != '\\') { *q++= *p++; continue; }
     switch (*++p) {
-    case 'n': *q++= '\n'; continue;
-    case 'r': *q++= '\r'; continue;
-    case 't': *q++= '\t'; continue;
+    case 'n': *q++= '\n'; p++; continue;
+    case 'r': *q++= '\r'; p++; continue;
+    case 't': *q++= '\t'; p++; 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++)))
+       return parseerrprint("quoted string ends inside \\x<hex> sequence");
+      buf[2]= 0;
+      v= strtoul(buf,&bep,16);
+      if (bep != buf+2)
+       return parseerrprint("invalid \\<hex> sequence \\x%s in quoted string",buf);
+      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 (ISCHAR(isalpha,*p))
+        return parseerrprint("unknown \\<letter> sequence \\%c in quoted string",*p);
+      if (ISCHAR(isdigit,*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)); {
-          parseerrprint("invalid \\<octal> sequence \\%s in quoted string",buf);
-          return tokv_error;
-        }
-        *q++= v; p++; continue;
-      } else if (ispunct(*p)) {
+        if (bep != buf+3 || (v & ~0xff))
+          return parseerrprint("invalid \\<octal> sequence \\%s in quoted string",buf);
+        *q++= v; continue;
+      } else if (ISCHAR(ispunct,*p)) {
         *q++= *p++; continue;
       } else {
        while (*p==' ' || *p=='\t') p++;
-       assert(*p=='\n');
+       v= *p++; assert(v=='\n');
       }
     }
   }
-  assert(*p); assert(!*++p);
+  assert(*p); p++; assert(!*p);
+  *q++= 0;
   return tokv_quotedstring;
 }
 
@@ -193,6 +207,8 @@ const char *printtoken(int token) {
     return buf;
   } else if (token & tokt_number) {
     snyprintf(buf,sizeof(buf),"number %d",lr_min); return buf;
+  } else if (token & tokt_fdrange && token & tokr_word) {
+    snyprintf(buf,sizeof(buf),"fd %s",buf); return buf;
   } else if (token & tokt_fdrange && lr_max==-1) {
     snyprintf(buf,sizeof(buf),"fdrange %d-",lr_min); return buf;
   } else if (token & tokt_fdrange) {
@@ -211,8 +227,8 @@ const char *printtoken(int token) {
     l= strlen(buf); i= sizeof(buf)-l-2; p= yytext; q= buf+l;
     while ((c= *p++)) {
       if (i-- <= 0) { q--; strcpy(q-3,"..."); break; }
-      if (isspace(c)) c= ' ';
-      else if (!isprint(c) || iscntrl(c)) c= '?';
+      if (ISCHAR(isspace,c)) c= ' ';
+      else if (!ISCHAR(isprint,c) || ISCHAR(iscntrl,c)) c= '?';
       else *q++= c;
     }
     strcpy(q,"'");
@@ -336,8 +352,8 @@ static int paa_pathargs(const char **path_r, char ***newargs_r) {
     }
     if (used>=size) {
       if (used >= MAX_ARGSDEFVAR) {
-       parseerrprint("far too many arguments to service program");
-       r= tokv_error; goto error;
+       r= parseerrprint("far too many arguments to service program");
+       goto error;
       }
       size= (used+5)<<1;
       newargs= xrealloc(newargs,sizeof(char*)*(size+1));
@@ -358,6 +374,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;
 
@@ -367,14 +384,13 @@ static int paa_message(const char **message_r) {
   buildbuf[0]= 0;
   for (;;) {
     r= yylex(); if (r == tokv_error) return r;
-    if (r == tokv_eof) {
-      parseerrprint("unexpected end of file in message text");
-      return tokv_error;
-    }
+    if (r == tokv_eof)
+      return parseerrprint("unexpected end of file in message text");
     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;
@@ -396,8 +412,7 @@ static int skiptoeol(void) {
   if (token == tokv_newline) return 0;
   if (token == tokv_error) return token;
   assert(token == tokv_eof);
-  parseerrprint("unexpected end of file while looking for end of line");
-  return tokv_error;
+  return parseerrprint("unexpected end of file while looking for end of line");
 }
 
 static int skip(int allowce) {
@@ -411,7 +426,7 @@ static int skip(int allowce) {
 
   for (;;) { /* loop over lines */
     cstate->reportlineno= cstate->lineno;
-    do { token= yylex(); } while (token == tokv_lwsp);
+    do { token= yylex(); } while (token == tokv_lwsp || token == tokv_newline);
     if (token & tokt_exception) {
       return token;
     } else if (token & tokt_controlend) {
@@ -425,9 +440,8 @@ static int skip(int allowce) {
         r= skip(token); if (r & tokt_exception) return r;
       }
     } else if (!(token & tokt_directive) && !(token & tokt_condop)) {
-      parseerrprint("not a directive (or conditional operator) "
-                   "while looking for control structure end");
-      return tokv_error;
+      return parseerrprint("not a directive (or conditional operator) "
+                          "while looking for control structure end");
     }
     r= skiptoeol(); if (r) return r;
   }
@@ -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) {
@@ -579,9 +593,7 @@ int pcf_range(int ctoken, char *const *pv, int *rtrue) {
   char *ep;
   unsigned long v;
 
-  r= pa_mwsp(); if (r) return r;
   mintoken= pa_numberdollar(&min); if (mintoken == tokv_error) return mintoken;
-  r= pa_mwsp(); if (r) return r;
   maxtoken= pa_numberdollar(&max); if (maxtoken == tokv_error) return maxtoken;
   r= pa_mnl(); if (r) return r;
   for (pp= pv; *pp; pp++) {
@@ -602,20 +614,18 @@ int pcf_grep(int ctoken, char *const *pv, int *rtrue) {
   
   r= paa_1path(&cp); if (r) return r;
   file= fopen(cp,"r");
-  if (!file) {
-    parseerrprint("unable to open file `%s' for grep: %s",cp,strerror(errno));
-    return tokv_error;
-  }
+  if (!file)
+    return parseerrprint("unable to open file `%s' for grep: %s",cp,strerror(errno));
   maxlen= 0;
   for (pp= pv; *pp; pp++) { l= strlen(*pp); if (l > maxlen) maxlen= l; }
   buf= xmalloc(maxlen+2); actrue= 0; c= 0;
   while (!actrue && c!=EOF) {
     c= getc(file); if (c==EOF) break;
-    if (isspace(c)) continue;
+    if (ISCHAR(isspace,c)) continue;
     l= maxlen+1; p= buf;
     while (l>0 && c!='\n' && c!=EOF) { *p++= c; l--; c= getc(file); } 
-    if (c=='\n' || c==EOF || isspace(c)) {
-      while (p>buf && isspace(p[-1])) --p;
+    if (c=='\n' || c==EOF || ISCHAR(isspace,c)) {
+      while (p>buf && ISCHAR(isspace,p[-1])) --p;
       *p= 0; posstrue= 0;
       for (pp= pv; !posstrue && *pp; pp++)
        if (!strcmp(*pp,buf)) posstrue= 1;
@@ -626,7 +636,7 @@ int pcf_grep(int ctoken, char *const *pv, int *rtrue) {
       for (;;) {
         c= getc(file);
         if (c==EOF || c=='\n') break;
-        if (!isspace(c)) posstrue= 0;
+        if (!ISCHAR(isspace,c)) posstrue= 0;
       }
     }
     if (posstrue) actrue= 1;
@@ -743,7 +753,7 @@ int df_executefromdirectory(int dtoken) {
 
   r= paa_pathargs(&rv,&newargs); if (r) return r;
   p= strrchr(service,'/'); if (p) p++; else p= service;
-  if (!*p || !isalnum(*p)) {
+  if (!*p || !ISCHAR(isalnum,*p)) {
     parseerrprint("execute-from-directory requires initial char of service "
                  "portion to be alphanumeric (service portion was `%s')",
                  p);
@@ -751,7 +761,7 @@ int df_executefromdirectory(int dtoken) {
     return tokv_error;
   }
   for (q=p+1; *q; q++) {
-    if (!isalnum(*q) && *q != '-') {
+    if (!ISCHAR(isalnum,*q) && *q != '-') {
       parseerrprint("execute-from-directory requires service portion to "
                    "contain only alphanumerics and hyphens (was `%s')",
                    p);
@@ -838,8 +848,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) {
@@ -851,21 +860,16 @@ int dfg_fdwant(int dtoken) {
   if (!(r & tokt_fdrange)) return unexpected(r,-1,"file descriptor range");
   fdmin= lr_min; fdmax= lr_max;
   if (fdmin<0 || fdmin>MAX_ALLOW_FD ||
-      (fdmax != -1 && fdmax<0) || fdmax>MAX_ALLOW_FD) {
-    parseerrprint("file descriptor in range is negative or far too large");
-    return tokv_error;
-  }
+      (fdmax != -1 && fdmax<0) || fdmax>MAX_ALLOW_FD)
+    return parseerrprint("file descriptor in range is negative or far too large");
   r= yylex(); if (r == tokv_error) return r;
   if (r == tokv_newline) {
-    if (needreadwrite > 0) {
-      parseerrprint("read or write is required");
-      return tokv_error;
-    }
+    if (needreadwrite > 0)
+      return parseerrprint("read or write is required");
     havereadwrite= 0;
   } else if (r == tokv_lwsp) {
-    if (needreadwrite < 0) {
-      parseerrprint("read or write not allowed"); return tokv_error;
-    }
+    if (needreadwrite < 0)
+      return parseerrprint("read or write not allowed");
     r= yylex(); if (r == tokv_error) return r;
     if (!(r & tokt_readwrite))
       return unexpected(r,-1,"read or write (or perhaps newline)");
@@ -877,7 +881,8 @@ int dfg_fdwant(int dtoken) {
   ensurefdarray(fdmin);
   if (fdmax == -1) {
     if (!(dtoken == tokv_word_rejectfd || dtoken == tokv_word_ignorefd))
-      parseerrprint("unspecified maximum only allowed with reject-fd and ignore-fd");
+      return parseerrprint("unspecified maximum only allowed"
+                          " with reject-fd and ignore-fd");
     fdmax= fdarrayused-1;
     restfdwantstate= dtoken;
     restfdwantrw= havereadwrite;
@@ -934,10 +939,8 @@ int df_errorstofile(int dtoken) {
   
   r= paa_1path(&cp); if (r) return r;
   file= fopen(cp,"a");
-  if (!file) {
-    parseerrprint("unable to open error log file `%s': %s",cp,strerror(errno));
-    return tokv_error;
-  }
+  if (!file)
+    return parseerrprint("unable to open error log file `%s': %s",cp,strerror(errno));
   if (setvbuf(file,0,_IOLBF,MAX_ERRMSG_LEN)) {
     parseerrprint("unable to set line buffering on errors file: %s",strerror(errno));
     fclose(file); return tokv_error;
@@ -972,11 +975,10 @@ int df_include(int dtoken) {
   r= paa_1path(&cp); if (r) return r;
   r= parse_file(cp,&found); if (r) return r;
   if (found || dtoken == tokv_word_includeifexist) return 0;
-  parseerrprint(dtoken == tokv_word_includesysconfig ?
-               "system configuration file `%s' does not exist" :
-               "included file `%s' does not exist",
-               cp);
-  return tokv_error;
+  return parseerrprint(dtoken == tokv_word_includesysconfig ?
+                      "system configuration file `%s' does not exist" :
+                      "included file `%s' does not exist",
+                      cp);
 }
 
 int df_includedirectory(int dtoken) {
@@ -986,76 +988,103 @@ 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);
-  if (!d) {
-    parseerrprint("unable to open directory `%s': %s",cp,strerror(errno));
-    return tokv_error;
-  }
+  r= paa_1path(&cpget); if (r) return r;
+  d= opendir(cpget);
+  if (!d)
+    return parseerrprint("unable to open directory `%s': %s",cpget,strerror(errno));
+  cp= xstrsave(cpget);
   cpl= strlen(cp);
-  while ((de= readdir(d))) {
+  while ((errno=0, de= readdir(d))) {
     tel= strlen(de->d_name);
     if (!tel) continue;
     p= de->d_name;
-    if (!*p || !isalnum(*p)) continue;
-    while ((c= *++p)) if (!(isalnum(c) || c=='-')) break;
+    if (!*p || !ISCHAR(isalnum,*p)) continue;
+    while ((c= *++p)) if (!(ISCHAR(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= parseerrprint("unable to open file `%s' in included directory `%s': %s",
+                      de->d_name,cp,strerror(errno));
+      goto x_err;
     }
   }
+  if (errno) {
+    parseerrprint("error reading directory `%s': %s",cp,strerror(errno));
+    closedir(d);
+    free(cp);
+    return tokv_error;
+  }
   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;
+}
+
+static int oldquote = 0;
+
+int dfg_lookupquotemode(int dtoken) {
+  int r;
+  r= pa_mnl(); if (r) return r;
+  oldquote = dtoken == tokv_word_includelookupquoteold;
+  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 +1093,40 @@ 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 (oldquote ?
+                    !((c >= '0' && c <= '9') ||
+                      (c >= 'a' && c <= 'z') ||
+                      c == '-' || 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 */
@@ -1158,8 +1201,7 @@ int df_cd(int dtoken) {
 
   r= paa_1path(&cp); if (r) return r;
   if (!chdir(cp)) return 0;
-  parseerrprint("unable to change directory to `%s': %s",cp,strerror(errno));
-  return tokv_error;
+  return parseerrprint("unable to change directory to `%s': %s",cp,strerror(errno));
 }
 
 int df_userrcfile(int dtoken) {
@@ -1185,8 +1227,7 @@ int df_error(int dtoken) {
   int r;
 
   r= paa_message(&mp); if (r) return r;
-  parseerrprint("`error' directive: %s",mp);
-  return tokv_error;
+  return parseerrprint("`error' directive: %s",mp);
 }
 
 int df_eof(int dtoken) {
@@ -1272,43 +1313,37 @@ static int parse_file(const char *string, int *didexist) {
   char *filename;
   struct stat newstab;
 
-  if (fileparselevel >= MAX_INCLUDE_NEST) {
-    parseerrprint("too many nested levels of included files");
-    return tokv_error;
-  }
+  if (fileparselevel >= MAX_INCLUDE_NEST)
+    return parseerrprint("too many nested levels of included files");
   file= fopen(string,"r");
   if (!file) {
     if (errno == ENOENT) {
       if (didexist) *didexist= 0;
       return 0;
     }
-    parseerrprint("unable to open config file `%s': %s",string,strerror(errno));
-    return tokv_error;
+    return parseerrprint("unable to open config file `%s': %s",string,strerror(errno));
   }
   r= fstat(fileno(file),&newstab); if (r) syscallerror("unable to fstat new file");
   for (checkrecurse= cstate; checkrecurse; checkrecurse= checkrecurse->upstate) {
     if (!checkrecurse->filestab.st_mode) continue;
     if (newstab.st_dev==checkrecurse->filestab.st_dev &&
        newstab.st_ino==checkrecurse->filestab.st_ino) {
-      parseerrprint("recursion detected - config file `%s' calls itself",string);
       fclose(file);
-      return tokv_error;
+      return parseerrprint("recursion detected - config file `%s' calls itself",string);
     }
   }
   
   if (didexist) *didexist= 1;
 
-  filename= xstrsave(file);
   ybuf= yy_create_buffer(file,YY_BUF_SIZE);
   if (!ybuf) syscallerror("unable to create flex buffer for file");
+  filename= xstrsave(string);
   parser_push(&usestate,filename,&newstab,ybuf,0);
   fileparselevel++;
   
   r= parser(0);
-  if (ferror(file)) {
-    parseerrprint("error reading configuration file `%s'",string);
-    r= tokv_error;
-  }
+  if (ferror(file))
+    r= parseerrprint("error reading configuration file `%s'",string);
 
   fileparselevel--;
   parser_pop();