Author: bapt
Date: Wed Jul  8 21:06:19 2015
New Revision: 285291
URL: https://svnweb.freebsd.org/changeset/base/285291

Log:
  MFC: r279597 (and 259152,259219 as dependency)
  
  Make calendar(1) usable again. rework the calendar parser so that it is
  compatible with documented format:
  
  Support includes surrounded by '"' or '<' '>'
  Print warnings about bad syntax
  Correctly navigate through include directories to find calendar files
  Correctly support multiple includes
  
  While here:
  
  MFC: 262011 (by eadler)
  
  calendar(1): don't segfault in invalid input
  
  When the user supplies an invalid number of days provide a useful error 
message
  instead of segfaulting.
  
  Approved by:  re (gjb)

Deleted:
  stable/10/usr.bin/calendar/calcpp.c
Modified:
  stable/10/usr.bin/calendar/Makefile
  stable/10/usr.bin/calendar/calendar.c
  stable/10/usr.bin/calendar/calendar.h
  stable/10/usr.bin/calendar/io.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/usr.bin/calendar/Makefile
==============================================================================
--- stable/10/usr.bin/calendar/Makefile Wed Jul  8 19:26:36 2015        
(r285290)
+++ stable/10/usr.bin/calendar/Makefile Wed Jul  8 21:06:19 2015        
(r285291)
@@ -5,7 +5,7 @@
 
 PROG=  calendar
 SRCS=  calendar.c locale.c events.c dates.c parsedata.c io.c day.c \
-       ostern.c paskha.c pom.c sunpos.c calcpp.c
+       ostern.c paskha.c pom.c sunpos.c
 DPADD= ${LIBM}
 LDADD= -lm
 INTER=          de_AT.ISO_8859-15 de_DE.ISO8859-1 fr_FR.ISO8859-1 \

Modified: stable/10/usr.bin/calendar/calendar.c
==============================================================================
--- stable/10/usr.bin/calendar/calendar.c       Wed Jul  8 19:26:36 2015        
(r285290)
+++ stable/10/usr.bin/calendar/calendar.c       Wed Jul  8 21:06:19 2015        
(r285291)
@@ -96,10 +96,14 @@ main(int argc, char *argv[])
 
                case 'A': /* days after current date */
                        f_dayAfter = atoi(optarg);
+                       if (f_dayAfter < 0)
+                               errx(1, "number of days must be positive");
                        break;
 
                case 'B': /* days before current date */
                        f_dayBefore = atoi(optarg);
+                       if (f_dayBefore < 0)
+                               errx(1, "number of days must be positive");
                        break;
 
                case 'D': /* debug output of sun and moon info */

Modified: stable/10/usr.bin/calendar/calendar.h
==============================================================================
--- stable/10/usr.bin/calendar/calendar.h       Wed Jul  8 19:26:36 2015        
(r285290)
+++ stable/10/usr.bin/calendar/calendar.h       Wed Jul  8 21:06:19 2015        
(r285291)
@@ -168,10 +168,6 @@ void       closecal(FILE *);
 FILE   *opencalin(void);
 FILE   *opencalout(void);
 
-/* calcpp.c */
-void   initcpp(void);
-FILE   *fincludegets(char *buf, int size, FILE *fp);
-
 /* ostern.c / paskha.c */
 int    paskha(int);
 int    easter(int);

Modified: stable/10/usr.bin/calendar/io.c
==============================================================================
--- stable/10/usr.bin/calendar/io.c     Wed Jul  8 19:26:36 2015        
(r285290)
+++ stable/10/usr.bin/calendar/io.c     Wed Jul  8 21:06:19 2015        
(r285291)
@@ -51,14 +51,23 @@ __FBSDID("$FreeBSD$");
 #include <langinfo.h>
 #include <locale.h>
 #include <pwd.h>
+#include <stdbool.h>
+#define _WITH_GETLINE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stringlist.h>
 #include <unistd.h>
 
 #include "pathnames.h"
 #include "calendar.h"
 
+enum {
+       T_OK = 0,
+       T_ERR,
+       T_PROCESS,
+};
+
 const char *calendarFile = "calendar"; /* default calendar file */
 static const char *calendarHomes[] = {".calendar", _PATH_INCLUDE}; /* HOME */
 static const char *calendarNoMail = "nomail";/* don't sent mail if file exist 
*/
@@ -68,6 +77,147 @@ static char path[MAXPATHLEN];
 struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon;
 struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice;
 
+static int cal_parse(FILE *in, FILE *out);
+
+static StringList *definitions = NULL;
+static struct event *events[MAXCOUNT];
+static char *extradata[MAXCOUNT];
+
+static void
+trimlr(char **buf)
+{
+       char *walk = *buf;
+
+       while (isspace(*walk))
+               walk++;
+       while (isspace(walk[strlen(walk) -1]))
+               walk[strlen(walk) -1] = '\0';
+
+       *buf = walk;
+}
+
+static FILE *
+cal_fopen(const char *file)
+{
+       FILE *fp;
+       char *home = getenv("HOME");
+       unsigned int i;
+
+       if (home == NULL || *home == '\0') {
+               warnx("Cannot get home directory");
+               return (NULL);
+       }
+
+       if (chdir(home) != 0) {
+               warnx("Cannot enter home directory");
+               return (NULL);
+       }
+
+       for (i = 0; i < sizeof(calendarHomes)/sizeof(calendarHomes[0]) ; i++) {
+               if (chdir(calendarHomes[i]) != 0)
+                       continue;
+
+               if ((fp = fopen(file, "r")) != NULL)
+                       return (fp);
+       }
+
+       warnx("can't open calendar file \"%s\"", file);
+
+       return (NULL);
+}
+
+static int
+token(char *line, FILE *out, bool *skip)
+{
+       char *walk, c, a;
+
+       if (strncmp(line, "endif", 5) == 0) {
+               *skip = false;
+               return (T_OK);
+       }
+
+       if (*skip)
+               return (T_OK);
+
+       if (strncmp(line, "include", 7) == 0) {
+               walk = line + 7;
+
+               trimlr(&walk);
+
+               if (*walk == '\0') {
+                       warnx("Expecting arguments after #include");
+                       return (T_ERR);
+               }
+
+               if (*walk != '<' && *walk != '\"') {
+                       warnx("Excecting '<' or '\"' after #include");
+                       return (T_ERR);
+               }
+
+               a = *walk;
+               walk++;
+               c = walk[strlen(walk) - 1];
+
+               switch(c) {
+               case '>':
+                       if (a != '<') {
+                               warnx("Unterminated include expecting '\"'");
+                               return (T_ERR);
+                       }
+                       break;
+               case '\"':
+                       if (a != '\"') {
+                               warnx("Unterminated include expecting '>'");
+                               return (T_ERR);
+                       }
+                       break;
+               default:
+                       warnx("Unterminated include expecting '%c'",
+                           a == '<' ? '>' : '\"' );
+                       return (T_ERR);
+               }
+               walk[strlen(walk) - 1] = '\0';
+
+               if (cal_parse(cal_fopen(walk), out))
+                       return (T_ERR);
+
+               return (T_OK);
+       }
+
+       if (strncmp(line, "define", 6) == 0) {
+               if (definitions == NULL)
+                       definitions = sl_init();
+               walk = line + 6;
+               trimlr(&walk);
+
+               if (*walk == '\0') {
+                       warnx("Expecting arguments after #define");
+                       return (T_ERR);
+               }
+
+               sl_add(definitions, strdup(walk));
+               return (T_OK);
+       }
+
+       if (strncmp(line, "ifndef", 6) == 0) {
+               walk = line + 6;
+               trimlr(&walk);
+
+               if (*walk == '\0') {
+                       warnx("Expecting arguments after #ifndef");
+                       return (T_ERR);
+               }
+
+               if (definitions != NULL && sl_find(definitions, walk) != NULL)
+                       *skip = true;
+
+               return (T_OK);
+       }
+
+       return (T_PROCESS);
+
+}
+
 #define        REPLACE(string, slen, struct_) \
                if (strncasecmp(buf, (string), (slen)) == 0 && buf[(slen)]) { \
                        if (struct_.name != NULL)                             \
@@ -77,30 +227,25 @@ struct fixs nmarequinox, nsepequinox, nj
                        struct_.len = strlen(buf + (slen));                   \
                        continue;                                             \
                }
-void
-cal(void)
+static int
+cal_parse(FILE *in, FILE *out)
 {
-       char *pp, p;
-       FILE *fpin;
-       FILE *fpout;
-       int l;
-       int count, i;
+       char *line = NULL;
+       char *buf;
+       size_t linecap = 0;
+       ssize_t linelen;
+       ssize_t l;
+       static int d_first = -1;
+       static int count = 0;
+       int i;
        int month[MAXCOUNT];
        int day[MAXCOUNT];
        int year[MAXCOUNT];
-       char **extradata;       /* strings of 20 length */
-       int flags;
-       static int d_first = -1;
-       char buf[2048 + 1];
-       struct event *events[MAXCOUNT];
-       struct tm tm;
+       bool skip = false;
        char dbuf[80];
-
-       initcpp();
-       extradata = (char **)calloc(MAXCOUNT, sizeof(char *));
-       for (i = 0; i < MAXCOUNT; i++) {
-               extradata[i] = (char *)calloc(1, 20);
-       }
+       char *pp, p;
+       struct tm tm;
+       int flags;
 
        /* Unused */
        tm.tm_sec = 0;
@@ -108,20 +253,32 @@ cal(void)
        tm.tm_hour = 0;
        tm.tm_wday = 0;
 
-       count = 0;
-       if ((fpin = opencalin()) == NULL) {
-               free(extradata);
-               return;
-       }
-       if ((fpout = opencalout()) == NULL) {
-               fclose(fpin);
-               free(extradata);
-               return;
-       }
-       while ((fpin = fincludegets(buf, sizeof(buf), fpin)) != NULL) {
-               if (*buf == '\0')
+       if (in == NULL)
+               return (1);
+
+       while ((linelen = getline(&line, &linecap, in)) > 0) {
+               if (linelen == 0)
+                       continue;
+
+               if (*line == '#') {
+                       switch (token(line+1, out, &skip)) {
+                       case T_ERR:
+                               free(line);
+                               return (1);
+                       case T_OK:
+                               continue;
+                       case T_PROCESS:
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
+               if (skip)
                        continue;
-               for (l = strlen(buf);
+
+               buf = line;
+               for (l = linelen;
                     l > 0 && isspace((unsigned char)buf[l - 1]);
                     l--)
                        ;
@@ -208,16 +365,41 @@ cal(void)
                }
        }
 
+       free(line);
+       fclose(in);
+
+       return (0);
+}
+
+void
+cal(void)
+{
+       FILE *fpin;
+       FILE *fpout;
+       int i;
+
+       for (i = 0; i < MAXCOUNT; i++)
+               extradata[i] = (char *)calloc(1, 20);
+
+
+       if ((fpin = opencalin()) == NULL)
+               return;
+
+       if ((fpout = opencalout()) == NULL) {
+               fclose(fpin);
+               return;
+       }
+
+       if (cal_parse(fpin, fpout))
+               return;
+
        event_print_all(fpout);
        closecal(fpout);
-       free(extradata);
 }
 
 FILE *
 opencalin(void)
 {
-       size_t i;
-       int found;
        struct stat sbuf;
        FILE *fpin;
 
@@ -231,22 +413,7 @@ opencalin(void)
                        if ((fpin = fopen(calendarFile, "r")) == NULL)
                                return (NULL);
                } else {
-                       char *home = getenv("HOME");
-                       if (home == NULL || *home == '\0')
-                               errx(1, "cannot get home directory");
-                       if (chdir(home) != 0)
-                               errx(1, "cannot enter home directory");
-                       for (found = i = 0; i < sizeof(calendarHomes) /
-                           sizeof(calendarHomes[0]); i++)
-                               if (chdir(calendarHomes[i]) == 0 &&
-                                   (fpin = fopen(calendarFile, "r")) != NULL) {
-                                       found = 1;
-                                       break;
-                               }
-                       if (!found)
-                               errx(1,
-                                   "can't open calendar file \"%s\": %s (%d)",
-                                   calendarFile, strerror(errno), errno);
+                       fpin = cal_fopen(calendarFile);
                }
        }
        return (fpin);
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to