[BACK]Return to day.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / calendar

Diff for /src/usr.bin/calendar/day.c between version 1.6 and 1.7

version 1.6, 1998/11/08 04:31:13 version 1.7, 1998/12/13 07:31:07
Line 62 
Line 62 
 #include "pathnames.h"  #include "pathnames.h"
 #include "calendar.h"  #include "calendar.h"
   
   #define WEEKLY 1
   #define MONTHLY 2
   #define YEARLY 3
   
 struct tm *tp;  struct tm *tp;
 int *cumdays, offset, yrdays;  int *cumdays, offset;
 char dayname[10];  char dayname[10];
   
   
Line 140 
Line 144 
                         errx(1, "cannot allocate memory");                          errx(1, "cannot allocate memory");
                 fnmonths[i].len = strlen(buf);                  fnmonths[i].len = strlen(buf);
         }          }
           /* Hardwired special events */
           spev[0].name = strdup(EASTER);
           spev[0].nlen = EASTERNAMELEN;
           spev[0].getev = easter;
           spev[1].name = strdup(PASKHA);
           spev[1].nlen = PASKHALEN;
           spev[1].getev = paskha;
           for (i = 0; i < NUMEV; i++) {
                   if (spev[i].name == NULL)
                           errx(1, "cannot allocate memory");
                   spev[i].uname = NULL;
           }
 }  }
   
 void  void
 settime(now)  settime(now)
         time_t now;          time_t *now;
 {  {
         tp = localtime(&now);          tp = localtime(now);
         if (isleap(tp->tm_year + TM_YEAR_BASE)) {          tp->tm_sec = 0;
                 yrdays = DAYSPERLYEAR;          tp->tm_min = 0;
           /* Avoid getting caught by a timezone shift; set time to noon */
           tp->tm_isdst = 0;
           tp->tm_hour = 12;
           *now = mktime(tp);
           if (isleap(tp->tm_year + TM_YEAR_BASE))
                 cumdays = daytab[1];                  cumdays = daytab[1];
         } else {          else
                 yrdays = DAYSPERNYEAR;  
                 cumdays = daytab[0];                  cumdays = daytab[0];
         }  
         /* Friday displays Monday's events */          /* Friday displays Monday's events */
         offset = tp->tm_wday == 5 ? 3 : 1;          offset = tp->tm_wday == 5 ? 3 : 1;
           if (f_dayAfter)
                   offset = 0;     /* Except not when range is set explicitly */
         header[5].iov_base = dayname;          header[5].iov_base = dayname;
   
         (void) setlocale(LC_TIME, "C");          (void) setlocale(LC_TIME, "C");
Line 202 
Line 223 
   
     /* Year */      /* Year */
     if (len >= 6) {      if (len >= 6) {
         *(date + len - 4) = '\0';                  *(date + len - 4) = '\0';
         tm.tm_year = atoi(date);                  tm.tm_year = atoi(date);
   
         /* tm_year up TM_YEAR_BASE ... */          /* tm_year up TM_YEAR_BASE ... */
         if (tm.tm_year < 69)            /* Y2K */          if (tm.tm_year < 69)            /* Y2K */
Line 235 
Line 256 
 isnow(endp)  isnow(endp)
         char    *endp;          char    *endp;
 {  {
         int day, flags = 0, month = 0, v1, v2;          int day = 0, flags = 0, month = 0, v1, v2, i;
         int monthp, dayp, varp;          int monthp, dayp, varp = 0;
         struct match *matches;          struct match *matches = NULL, *tmp, *tmp2;
           int interval = YEARLY;  /* how frequently the event repeats. */
           int vwd = 0;    /* Variable weekday */
           time_t tdiff, ttmp;
           struct tm tmtmp;
   
         /*          /*
          * CONVENTION           * CONVENTION
Line 255 
Line 280 
                 return (NULL);                  return (NULL);
   
         /* Easter or Easter depending days */          /* Easter or Easter depending days */
         if (flags & F_EASTER)          if (flags & F_SPECIAL)
             day = v1 - 1; /* days since January 1 [0-365] */                  vwd = v1;
   
          /*           /*
           * 1. {Weekday,Day} XYZ ...            * 1. {Weekday,Day} XYZ ...
Line 265 
Line 290 
           */            */
         else if (flags & F_ISDAY || v1 > 12) {          else if (flags & F_ISDAY || v1 > 12) {
   
                 /* found a day; day: 1-31 or weekday: 1-7 */                  /* found a day; day: 13-31 or weekday: 1-7 */
                 day = v1;                  day = v1;
   
                 /* {Day,Weekday} {Month,Monthname} ... */                  /* {Day,Weekday} {Month,Monthname} ... */
                 /* if no recognizable month, assume just a day alone                  /* if no recognizable month, assume just a day alone -- this is
                  * in other words, find month or use current month */                   * very unlikely and can only happen after the first 12 days.
                 if (!(month = getfield(endp, &endp, &flags)))                   * --find month or use current month */
                   if (!(month = getfield(endp, &endp, &flags))) {
                         month = tp->tm_mon + 1;                          month = tp->tm_mon + 1;
                           /* F_ISDAY is set only if a weekday was spelled out */
                           /* F_ISDAY must be set if 0 < day < 8 */
                           if ((day <= 7) && (day >= 1))
                                   interval = WEEKLY;
                           else
                                   interval = MONTHLY;
                   } else if ((day <= 7) && (day >= 1))
                           day += 10;
                           /* it's a weekday; make it the first one of the month */
                   if (month == -1) {
                           month = tp->tm_mon + 1;
                           interval = MONTHLY;
                   }
                   if ((month > 12) || (month < 1))
                           return (NULL);
         }          }
   
         /* 2. {Monthname} XYZ ... */          /* 2. {Monthname} XYZ ... */
         else if (flags & F_ISMONTH) {          else if (flags & F_ISMONTH) {
                 month = v1;                  month = v1;
                   if (month == -1) {
                           month = tp->tm_mon + 1;
                           interval = MONTHLY;
                   }
                 /* Monthname {day,weekday} */                  /* Monthname {day,weekday} */
                 /* if no recognizable day, assume the first day in month */                  /* if no recognizable day, assume the first day in month */
                 if (!(day = getfield(endp, &endp, &flags)))                  if (!(day = getfield(endp, &endp, &flags)))
                         day = 1;                          day = 1;
                   /* If a weekday was spelled out without an ordering,
                    * assume the first of that day in the month */
                   if ((flags & F_ISDAY) && (day >= 1) && (day <=7))
                           day += 10;
         }          }
   
         /* Hm ... */          /* Hm ... */
Line 296 
Line 344 
                 if (flags & F_ISMONTH) {                  if (flags & F_ISMONTH) {
                         day = v1;                          day = v1;
                         month = v2;                          month = v2;
                         varp = 0;                          if (month == -1) {
                                   month = tp->tm_mon + 1;
                                   interval = MONTHLY;
                           }
                 }                  }
   
                 /* {Month} {Weekday,Day} ...  */                  /* {Month} {Weekday,Day} ...  */
Line 305 
Line 356 
                         month = v1;                          month = v1;
                         /* if no recognizable day, assume the first */                          /* if no recognizable day, assume the first */
                         day = v2 ? v2 : 1;                          day = v2 ? v2 : 1;
                         varp = 0;                          if ((flags & F_ISDAY) && (day >= 1) && (day <= 7))
                                   day += 10;
                 }                  }
         }          }
   
Line 315 
Line 367 
          */           */
         if (flags & F_ISDAY) {          if (flags & F_ISDAY) {
 #if DEBUG  #if DEBUG
             fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);                  fprintf(stderr, "\nday: %d %s month %d\n", day, endp, month);
 #endif  #endif
   
             varp = 1;                  varp = 1;
             /* variable weekday, SundayLast, MondayFirst ... */                  /* variable weekday, SundayLast, MondayFirst ... */
             if (day < 0 || day >= 10) {                  if (day < 0 || day >= 10)
                           vwd = day;
                 /* negative offset; last, -4 .. -1 */                  else {
                 if (day < 0) {                          day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);
                     v1 = day/10 - 1;          /* offset -4 ... -1 */                          interval = WEEKLY;
                     day = 10 + (day % 10);    /* day 1 ... 7 */  
   
                     /* which weekday the end of the month is (1-7) */  
                     v2 = (cumdays[month + 1] - tp->tm_yday +  
                         tp->tm_wday + 371) % 7 + 1;  
   
                     /* and subtract enough days */  
                     day = cumdays[month + 1] - cumdays[month] +  
                         (v1 + 1) * 7 - (v2 - day + 7) % 7;  
 #if DEBUG  
                     fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2);  
 #endif  
                 }                  }
           } else
           /* Check for silliness.  Note we still catch Feb 29 */
                   if (!(flags & F_SPECIAL) &&
                       (day > (cumdays[month + 1] - cumdays[month]) || day < 1)) {
                           if (!((month == 2 && day == 29) ||
                               (interval == MONTHLY && day <= 31)))
                                   return (NULL);
                   }
   
                 /* first, second ... +1 ... +5 */          if (!(flags & F_SPECIAL)) {
                 else {                  monthp = month;
                     v1 = day/10;        /* offset */                  dayp = day;
                     day = day % 10;                  day = cumdays[month] + day;
   
                     /* which weekday the first of the month is */  
                     v2 = (cumdays[month] - tp->tm_yday +  
                         tp->tm_wday + 372) % 7 + 1;  
   
                     /* and add enough days */  
                     day = 1 + (v1 - 1) * 7 + (day - v2 + 7) % 7;  
 #if DEBUG  #if DEBUG
                     fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2);                  fprintf(stderr, "day2: day %d(%d) yday %d\n", dayp, day, tp->tm_yday);
 #endif  #endif
             }          /* Speed up processing for the most common situation:  yearly events
             }           * when the interval being checked is less than a month or so (this
             else           * could be less than a year, but then we have to start worrying about
                     day = tp->tm_mday + (((day - 1) - tp->tm_wday + 7) % 7);           * leap years).  Only one event can match, and it's easy to find.
            * Note we can't check special events, because they can wander widely.
            */
                   if (((v1 = offset + f_dayAfter) < 50) && (interval == YEARLY)) {
                           memcpy(&tmtmp, tp, sizeof(struct tm));
                           tmtmp.tm_mday = dayp;
                           tmtmp.tm_mon = monthp - 1;
                           v2 = day - tp->tm_yday;
                           if ((v2 > v1) || (v2 < 0)) {
                                   if ((v2 += isleap(tp->tm_year + TM_YEAR_BASE) ? 366 : 365)
                                       <= v1)
                                           tmtmp.tm_year++;
                                   else
                                           return(NULL);
                           }
                           if ((tmp = malloc(sizeof(struct match))) == NULL)
                                   errx(1, "cannot allocate memory");
                           tmp->when = f_time + v2 * SECSPERDAY;
                           (void)mktime(&tmtmp);
                           if (strftime(tmp->print_date,
                               sizeof(tmp->print_date),
                           /*    "%a %b %d", &tm);  Skip weekdays */
                               "%b %d", &tmtmp) == 0)
                                   tmp->print_date[sizeof(tmp->print_date) - 1] = '\0';
                           tmp->var   = varp;
                           tmp->next  = NULL;
                           return(tmp);
                   }
         }          }
   
         if (!(flags & F_EASTER)) {  
             monthp = month;  
             dayp = day;  
             day = cumdays[month] + day;  
         }  
         else {          else {
             for (v1 = 0; day > cumdays[v1]; v1++)                  varp = 1;
                 ;                  /* Set up v1 to the event number and ... */
             monthp = v1 - 1;                  v1 = vwd % (NUMEV + 1) - 1;
             dayp = day - cumdays[v1 - 1];                  vwd /= (NUMEV + 1);
             varp = 1;                  if (v1 < 0) {
                           v1 += NUMEV + 1;
                           vwd--;
                   }
                   dayp = monthp = 1;      /* Why not */
         }          }
   
 #if DEBUG          /* Compare to past and coming instances of the event.  The i == 0 part
         fprintf(stderr, "day2: day %d(%d) yday %d\n", dayp, day, tp->tm_yday);           * of the loop corresponds to this specific instance.  Note that we
 #endif           * can leave things sort of higgledy-piggledy since a mktime() happens
         /* if today or today + offset days */           * on this before anything gets printed.  Also note that even though
         if ((day >= tp->tm_yday - f_dayBefore &&           * we've effectively gotten rid of f_dayBefore, we still have to check
             day <= tp->tm_yday + offset + f_dayAfter) ||           * the one prior event for situations like "the 31st of every month"
            * and "yearly" events which could happen twice in one year but not in
         /* if number of days left in this year + days to event in next year */           * the next */
            (yrdays - tp->tm_yday + day <= offset + f_dayAfter ||          tmp2 = matches;
             /* a year backward, eg. 6 Jan and 10 days before -> 27. Dec */          for (i = -1; i < 2; i++) {
             tp->tm_yday + day - f_dayBefore < 0                  memcpy(&tmtmp, tp, sizeof(struct tm));
             )) {                  tmtmp.tm_mday = dayp;
                 if ((matches = malloc(sizeof(struct match))) == NULL)                  tmtmp.tm_mon = month = monthp - 1;
                         errx(1,"cannot allocate memory");                  do {
                 matches->month = monthp;                          v2 = 0;
                 matches->day   = dayp;                          switch (interval) {
                 matches->var   = varp;                          case WEEKLY:
                 matches->year  = tp->tm_year;   /* XXX */                                  tmtmp.tm_mday += 7 * i;
                 matches->next  = NULL;                                  break;
                 return (matches);                          case MONTHLY:
                                   month += i;
                                   tmtmp.tm_mon = month;
                                   switch(tmtmp.tm_mon) {
                                   case -1:
                                           tmtmp.tm_mon = month = 11;
                                           tmtmp.tm_year--;
                                           break;
                                   case 12:
                                           tmtmp.tm_mon = month = 0;
                                           tmtmp.tm_year++;
                                           break;
                                   }
                                   if (vwd) {
                                           v1 = vwd;
                                           variable_weekday(&v1, tmtmp.tm_mon + 1,
                                               tmtmp.tm_year + TM_YEAR_BASE);
                                           tmtmp.tm_mday = v1;
                                   } else
                                           tmtmp.tm_mday = dayp;
                                   break;
                           case YEARLY:
                           default:
                                   tmtmp.tm_year += i;
                                   if (flags & F_SPECIAL) {
                                           tmtmp.tm_mon = 0;       /* Gee, mktime() is nice */
                                           tmtmp.tm_mday = spev[v1].getev(tmtmp.tm_year +
                                               vwd + TM_YEAR_BASE);
                                   } else if (vwd) {
                                           v1 = vwd;
                                           variable_weekday(&v1, tmtmp.tm_mon + 1,
                                               tmtmp.tm_year + TM_YEAR_BASE);
                                           tmtmp.tm_mday = v1;
                                   } else {
                                   /* Need the following to keep Feb 29 from
                                    * becoming Mar 1 */
                                   tmtmp.tm_mday = dayp;
                                   tmtmp.tm_mon = monthp - 1;
                                   }
                                   break;
                           }
                           /* How many days apart are we */
                           if ((ttmp = mktime(&tmtmp)) == -1)
                                   warnx("time out of range: %s", endp);
                           else {
                                   tdiff = difftime(ttmp, f_time)/ SECSPERDAY;
                                   if (tdiff <= offset + f_dayAfter) {
                                           if (tdiff >=  0) {
                                           if ((tmp = malloc(sizeof(struct match))) == NULL)
                                                   errx(1, "cannot allocate memory");
                                           tmp->when = ttmp;
                                           if (strftime(tmp->print_date,
                                               sizeof(tmp->print_date),
                                           /*    "%a %b %d", &tm);  Skip weekdays */
                                               "%b %d", &tmtmp) == 0)
                                                   tmp->print_date[sizeof(tmp->print_date) - 1] = '\0';
                                           tmp->var   = varp;
                                           tmp->next  = NULL;
                                           if (tmp2)
                                                   tmp2->next = tmp;
                                           else
                                                   matches = tmp;
                                           tmp2 = tmp;
                                           v2 = (i == 1) ? 1 : 0;
                                           }
                                   } else
                                           i = 2; /* No point checking in the future */
                           }
                   } while (v2 != 0);
         }          }
         return (NULL);          return (matches);
 }  }
   
   
Line 450 
Line 584 
   
         offset = strlen(s);          offset = strlen(s);
   
   
         /* Sun+1 or Wednesday-2          /* Sun+1 or Wednesday-2
          *    ^              ^   */           *    ^              ^   */
   
         /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */          /* printf ("x: %s %s %d\n", s, s + offset - 2, offset); */
         switch(*(s + offset - 2)) {          switch(*(s + offset - 2)) {
         case '-':          case '-':
             return(-(atoi(s + offset - 1)));  
             break;  
         case '+':          case '+':
             return(atoi(s + offset - 1));              return(atoi(s + offset - 2));
             break;              break;
         }          }
   
   
         /*          /*
          * some aliases: last, first, second, third, fourth           * some aliases: last, first, second, third, fourth
          */           */
Line 481 
Line 611 
         else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))          else if (offset > 6 && !strcasecmp(s + offset - 6, "fourth"))
             return(+4);              return(+4);
   
   
         /* no offset detected */          /* no offset detected */
         return(0);          return(0);
   }
   
   
   int
   foy(year)
           int year;
   {
           /* 0-6; what weekday Jan 1 is */
           year--;
           return ((1 - year/100 + year/400 + (int)(365.25 * year)) % 7);
   }
   
   
   
   void
   variable_weekday(day, month, year)
           int *day, month, year;
   {
           int v1, v2;
           int *cumdays;
           int day1;
   
           if (isleap(year))
                   cumdays = daytab[1];
           else
                   cumdays = daytab[0];
           day1 = foy(year);
           /* negative offset; last, -4 .. -1 */
           if (*day < 0) {
                   v1 = *day/10 - 1;          /* offset -4 ... -1 */
                   *day = 10 + (*day % 10);    /* day 1 ... 7 */
   
                   /* which weekday the end of the month is (1-7) */
                   v2 = (cumdays[month + 1] + day1) % 7 + 1;
   
                   /* and subtract enough days */
                   *day = cumdays[month + 1] - cumdays[month] +
                       (v1 + 1) * 7 - (v2 - *day + 7) % 7;
   #if DEBUG
                   fprintf(stderr, "\nMonth %d ends on weekday %d\n", month, v2);
   #endif
           }
   
           /* first, second ... +1 ... +5 */
           else {
                   v1 = *day/10;        /* offset */
                   *day = *day % 10;
   
                   /* which weekday the first of the month is (1-7) */
                   v2 = (cumdays[month] + 1 + day1) % 7 + 1;
   
                   /* and add enough days */
                   *day = 1 + (v1 - 1) * 7 + (*day - v2 + 7) % 7;
   #if DEBUG
                   fprintf(stderr, "\nMonth %d starts on weekday %d\n", month, v2);
   #endif
           }
 }  }

Legend:
Removed from v.1.6  
changed lines
  Added in v.1.7