chiark / gitweb /
finalise changelog prep. for cvs-buildpackage
[userv.git] / parser.c
index b00baac..3f40ffb 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-1999 Ian Jackson
+ * Copyright (C)1996-1999,2001 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
@@ -98,7 +98,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 +107,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 +117,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,6 +136,13 @@ 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;
@@ -145,37 +152,30 @@ static int dequote(char *inplace) {
   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':
       p++;
-      if (!((buf[0]= *p++) && (buf[1]= *p++))) {
-       parseerrprint("quoted string ends inside \\x<hex> sequence");
-       return tokv_error;
-      }
+      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) {
-       parseerrprint("invalid \\<hex> sequence \\x%s in quoted string",buf);
-       return tokv_error;
-      }
+      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)) {
+      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;
-        }
+        if (bep != buf+3 || (v & ~0xff))
+          return parseerrprint("invalid \\<octal> sequence \\%s in quoted string",buf);
         *q++= v; continue;
-      } else if (ispunct(*p)) {
+      } else if (ISCHAR(ispunct,*p)) {
         *q++= *p++; continue;
       } else {
        while (*p==' ' || *p=='\t') p++;
@@ -223,8 +223,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,"'");
@@ -348,8 +348,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));
@@ -370,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;
 
@@ -379,14 +380,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;
@@ -408,8 +408,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) {
@@ -437,9 +436,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;
   }
@@ -499,7 +497,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) {
@@ -614,20 +612,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;
@@ -638,7 +634,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;
@@ -755,7 +751,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);
@@ -763,7 +759,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);
@@ -862,21 +858,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)");
@@ -888,7 +879,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;
@@ -945,10 +937,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;
@@ -983,11 +973,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) {
@@ -1002,18 +991,16 @@ int df_includedirectory(int dtoken) {
   
   r= paa_1path(&cpget); if (r) return r;
   d= opendir(cpget);
-  if (!d) {
-    parseerrprint("unable to open directory `%s': %s",cpget,strerror(errno));
-    return tokv_error;
-  }
+  if (!d)
+    return parseerrprint("unable to open directory `%s': %s",cpget,strerror(errno));
   cp= xstrsave(cpget);
   cpl= strlen(cp);
   while ((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)) {
       stringoverflow("pathname in directory");
@@ -1022,9 +1009,9 @@ int df_includedirectory(int dtoken) {
     snyprintf(buildbuf,buildbuflen,"%s/%s",cp,de->d_name);
     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));
-      r= tokv_error; goto x_err;
+      r= parseerrprint("unable to open file `%s' in included directory `%s': %s",
+                      de->d_name,cp,strerror(errno));
+      goto x_err;
     }
   }
   if (closedir(d)) {
@@ -1089,8 +1076,14 @@ 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;
@@ -1189,8 +1182,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) {
@@ -1216,8 +1208,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) {
@@ -1303,27 +1294,23 @@ 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);
     }
   }
   
@@ -1336,10 +1323,8 @@ static int parse_file(const char *string, int *didexist) {
   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();