1 /* $XConsortium: reparser.y /main/2 1996/11/11 11:52:15 drk $ */
4 * (c) Copyright 1993, 1994 Hewlett-Packard Company
5 * (c) Copyright 1993, 1994 International Business Machines Corp.
6 * (c) Copyright 1993, 1994 Novell, Inc.
7 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
10 #include <EUSCompat.h>
17 /* The parsed rule is stored in this structure */
18 RepeatEvent *_DtCm_repeat_info;
21 extern void yyerror(char*);
23 static int CompareNums(const void *, const void *);
24 static int CompareDayTime(const void *, const void *);
25 static int CompareWeekDayTime(const void *, const void *);
26 static unsigned int *ConvertNumList(NumberList *, unsigned int * /* Return */);
27 static WeekDayTime *ConvertWeekDayTime(WeekDayTimeList *, unsigned int *);
28 static NumberList *AllocNumber(unsigned int);
29 static WeekDayTimeList *AllocWeekDayTimeList(NumberList*, NumberList *,
31 static RepeatEvent *HandleEndDate(RepeatEvent *, time_t);
32 static RepeatEvent *DeriveMinuteEvent(unsigned int, unsigned int);
33 static RepeatEvent *DeriveDailyEvent(unsigned int, NumberList *,
34 unsigned int, RepeatEvent *);
35 static RepeatEvent *DeriveWeeklyEvent(unsigned int, DayTimeList *,
36 unsigned int, RepeatEvent *);
37 static RepeatEvent *DeriveMonthlyEvent(RepeatType, unsigned int, void *,
38 unsigned int, RepeatEvent *);
39 static RepeatEvent *DeriveYearlyEvent(RepeatType, unsigned int, NumberList *,
40 unsigned int, RepeatEvent *);
44 %token ERROR ENDMARKER DURATION NUMBER FIRSTWEEK SECONDWEEK THIRDWEEK
45 %token FOURTHWEEK FIFTHWEEK LASTWEEK SECONDLAST THIRDLAST FOURTHLAST
46 %token FIFTHLAST MINUTECOMMAND DAILYCOMMAND WEEKLYCOMMAND MONTHPOSCOMMAND
47 %token MONTHDAYCOMMAND YEARDAYCOMMAND YEARMONTHCOMMAND LASTDAY SUNDAY
48 %token MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY DATE
58 WeekDayTimeList *wdtl;
63 %type <re> start begin minuteEvent dailyEvent weeklyEvent monthlyPosEvent
64 monthlyDayEvent yearlyByMonth yearlyByDay
65 %type <nl> time0List timeList dayOfMonthList monthOfYearList
66 dayOfYearList occurrenceList genericNumberList
67 generic0NumberList weekdayList
68 %type <weekday> SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY
70 %type <number> duration NUMBER occurrence endMarker time
71 %type <dtl> weekdayTimeList
72 %type <wdtl> weekDayTime
73 %type <dt> weekdayTimePair
75 %type <enddate> endDate
77 %% /* Beginning of rules section */
81 _DtCm_repeat_info = $$;
86 * XXX: Memory leak: We need to free up any portion
87 * of the re struct that has be allocated before the
88 * error was encountered.
90 _DtCm_repeat_info = NULL;
94 begin : minuteEvent endDate
96 $$ = HandleEndDate($1, $2);
100 $$ = HandleEndDate($1, $2);
102 | weeklyEvent endDate
104 $$ = HandleEndDate($1, $2);
106 | monthlyPosEvent endDate
108 $$ = HandleEndDate($1, $2);
110 | monthlyDayEvent endDate
112 $$ = HandleEndDate($1, $2);
114 | yearlyByMonth endDate
116 $$ = HandleEndDate($1, $2);
118 | yearlyByDay endDate
120 $$ = HandleEndDate($1, $2);
124 minuteEvent : /* empty */
128 | MINUTECOMMAND NUMBER duration
131 $$ = DeriveMinuteEvent($2, $3);
139 : DAILYCOMMAND NUMBER time0List duration minuteEvent
141 $$ = DeriveDailyEvent($2, $3, $4, $5);
147 : WEEKLYCOMMAND NUMBER weekdayTimeList duration minuteEvent
149 $$ = DeriveWeeklyEvent($2, $3, $4, $5);
152 | WEEKLYCOMMAND NUMBER duration minuteEvent
154 $$ = DeriveWeeklyEvent($2, NULL, $3, $4);
160 : MONTHPOSCOMMAND NUMBER weekDayTime duration minuteEvent
162 $$ = DeriveMonthlyEvent(RT_MONTHLY_POSITION,
166 | MONTHPOSCOMMAND NUMBER weekDayTime duration dailyEvent
168 $$ = DeriveMonthlyEvent(RT_MONTHLY_POSITION,
172 | MONTHPOSCOMMAND NUMBER weekDayTime duration weeklyEvent
174 $$ = DeriveMonthlyEvent(RT_MONTHLY_POSITION,
180 monthlyDayEvent : MONTHDAYCOMMAND NUMBER dayOfMonthList duration minuteEvent
182 $$ = DeriveMonthlyEvent(RT_MONTHLY_DAY, $2, $3, $4, $5);
185 | MONTHDAYCOMMAND NUMBER dayOfMonthList duration dailyEvent
187 $$ = DeriveMonthlyEvent(RT_MONTHLY_DAY, $2, $3, $4, $5);
190 | MONTHDAYCOMMAND NUMBER dayOfMonthList duration weeklyEvent
192 $$ = DeriveMonthlyEvent(RT_MONTHLY_DAY, $2, $3, $4, $5);
197 yearlyByMonth : YEARMONTHCOMMAND NUMBER monthOfYearList duration minuteEvent
199 $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
202 | YEARMONTHCOMMAND NUMBER monthOfYearList duration dailyEvent
204 $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
207 | YEARMONTHCOMMAND NUMBER monthOfYearList duration weeklyEvent
209 $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
212 | YEARMONTHCOMMAND NUMBER monthOfYearList duration
215 $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
218 | YEARMONTHCOMMAND NUMBER monthOfYearList duration
221 $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
226 yearlyByDay : YEARDAYCOMMAND NUMBER dayOfYearList duration minuteEvent
228 $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
231 | YEARDAYCOMMAND NUMBER dayOfYearList duration dailyEvent
233 $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
236 | YEARDAYCOMMAND NUMBER dayOfYearList duration weeklyEvent
238 $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
241 | YEARDAYCOMMAND NUMBER dayOfYearList duration monthlyPosEvent
243 $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
246 | YEARDAYCOMMAND NUMBER dayOfYearList duration monthlyDayEvent
248 $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
253 /* e.g. 1W MO TU 1300 1400 */
254 weekDayTime : /* empty */
258 | weekDayTime occurrenceList weekdayList
260 WeekDayTimeList *wdtl;
262 wdtl = AllocWeekDayTimeList($2, $3, NULL);
267 wdtl->wdtl_next = $$->wdtl_next;
268 $$->wdtl_next = wdtl;
271 | weekDayTime occurrenceList weekdayList timeList
273 WeekDayTimeList *wdtl;
275 wdtl = AllocWeekDayTimeList($2, $3, $4);
280 wdtl->wdtl_next = $$->wdtl_next;
281 $$->wdtl_next = wdtl;
286 /* e.g. MO TU WE TH */
287 weekdayList : weekday
289 $$ = AllocNumber($1);
291 | weekdayList weekday
295 nl = AllocNumber($2);
300 nl->nl_next = $$->nl_next;
306 /* e.g. 1W 3W 2L LW */
307 occurrenceList : occurrence
309 $$ = AllocNumber($1);
311 | occurrenceList occurrence
315 nl = AllocNumber($2);
320 nl->nl_next = $$->nl_next;
326 /* e.g. MO 1300 1500 2000 */
327 weekdayTimePair : weekday time0List
331 dt = (DayTime *)calloc(1, sizeof(DayTime));
334 /* Convert from list to array, sort */
337 (Time *)ConvertNumList($2, &(dt->dt_ntime));
342 /* e.g. MO 1300 1500 2000 TU 1200 1400 */
343 weekdayTimeList : weekdayTimePair
347 dtl = (DayTimeList *)calloc(1, sizeof(DayTimeList));
349 dtl->dtl_daytime = $1;
350 dtl->dtl_next = NULL;
355 | weekdayTimeList weekdayTimePair
360 dtl = (DayTimeList *)calloc(1, sizeof(DayTimeList));
362 dtl->dtl_daytime = $2;
363 dtl->dtl_next = NULL;
368 /* Insert the new entry at the end. This is
369 * so that MO TU 200 300 TH will maintain the
370 * same order in the list since MO uses the
371 * times next to TU and TH is dependent on the
375 while (dtl_end->dtl_next)
376 dtl_end = dtl_end->dtl_next;
378 dtl_end->dtl_next = dtl;
383 /* e.g. 1+ 2+ 3- 1- */
384 occurrence : FIRSTWEEK endMarker
387 if ($2) RE_SET_FLAG($$);
389 | SECONDWEEK endMarker
392 if ($2) RE_SET_FLAG($$);
394 | THIRDWEEK endMarker
397 if ($2) RE_SET_FLAG($$);
399 | FOURTHWEEK endMarker
402 if ($2) RE_SET_FLAG($$);
404 | FIFTHWEEK endMarker
407 if ($2) RE_SET_FLAG($$);
412 if ($2) RE_SET_FLAG($$);
414 | SECONDLAST endMarker
417 if ($2) RE_SET_FLAG($$);
419 | THIRDLAST endMarker
422 if ($2) RE_SET_FLAG($$);
424 | FOURTHLAST endMarker
427 if ($2) RE_SET_FLAG($$);
429 | FIFTHLAST endMarker
432 if ($2) RE_SET_FLAG($$);
436 endDate : /* empty */
442 if (_csa_iso8601_to_tick($1, &$$) == -1)
448 weekday : SUNDAY endMarker
451 if ($2) RE_SET_FLAG($$);
456 if ($2) RE_SET_FLAG($$);
461 if ($2) RE_SET_FLAG($$);
463 | WEDNESDAY endMarker
466 if ($2) RE_SET_FLAG($$);
471 if ($2) RE_SET_FLAG($$);
476 if ($2) RE_SET_FLAG($$);
481 if ($2) RE_SET_FLAG($$);
485 /* e.g. 0100 1200 1300 or NULL */
486 time0List : /* empty */
494 nl = AllocNumber($2);
499 nl->nl_next = $$->nl_next;
506 time : NUMBER endMarker
516 endMarker : /* empty */
527 duration : /* empty */
529 /* If no duration then default to 2 - set later if
536 /* If duration == 0 then repeat forever */
544 timeList : genericNumberList
545 dayOfMonthList : generic0NumberList
546 monthOfYearList : generic0NumberList
547 dayOfYearList : generic0NumberList
549 generic0NumberList: /* empty */
564 $$ = AllocNumber($1);
568 int number = RE_LASTDAY;
573 $$ = AllocNumber(number);
575 | genericNumberList NUMBER endMarker
582 nl = AllocNumber($2);
587 nl->nl_next = $$->nl_next;
591 | genericNumberList LASTDAY endMarker
594 int number = RE_LASTDAY;
599 nl = AllocNumber(number);
604 nl->nl_next = $$->nl_next;
613 * Convert the NumberList (linked list) to an array, sort the array.
615 static unsigned int *
620 NumberList *nl_head = nl;
624 if (!nl) return (unsigned int *)NULL;
631 array = (unsigned int *) calloc(i, sizeof(unsigned int));
633 /* Convert the list into an array */
638 array[i] = nl->nl_number;
650 qsort((void *)array, i, sizeof(unsigned int), CompareNums);
656 * Convert the DayTimeList to an array, sort the array.
663 DayTimeList *dtl_head = dtl;
664 DayTime *daytime_array;
668 if (!dtl) return (DayTime *)NULL;
675 daytime_array = (DayTime *) calloc(i, sizeof(DayTime));
677 /* Convert the list into an array */
680 DayTimeList *dtl_prev;
682 daytime_array[i].dt_day = dtl->dtl_daytime->dt_day;
683 daytime_array[i].dt_ntime = dtl->dtl_daytime->dt_ntime;
684 daytime_array[i].dt_time = dtl->dtl_daytime->dt_time;
689 /* alloc'ed in <weekdayTimeList> */
695 for (i = 0; i < *count; i++) {
696 if (daytime_array[i].dt_time == NULL) {
703 for (j = no_time; j < i; j++) {
704 daytime_array[j].dt_ntime =
705 daytime_array[i].dt_ntime;
706 daytime_array[j].dt_time =
708 daytime_array[j].dt_ntime,
710 memcpy(daytime_array[j].dt_time,
711 daytime_array[i].dt_time,
712 daytime_array[j].dt_ntime *
721 qsort((void *)daytime_array, *count, sizeof(DayTime), CompareDayTime);
723 return daytime_array;
734 const unsigned int *i = (const unsigned int *)data1;
735 const unsigned int *j = (const unsigned int *)data2;
737 if ((unsigned )RE_MASK_STOP(*i) > (unsigned )RE_MASK_STOP(*j))
739 if ((unsigned )RE_MASK_STOP(*i) < (unsigned )RE_MASK_STOP(*j))
752 const DayTime *i = (const DayTime *)data1;
753 const DayTime *j = (const DayTime *)data2;
755 if ((unsigned )RE_MASK_STOP(i->dt_day) >
756 (unsigned )RE_MASK_STOP(j->dt_day))
758 if ((unsigned )RE_MASK_STOP(i->dt_day) <
759 (unsigned )RE_MASK_STOP(j->dt_day))
772 const WeekDayTime *i = (const WeekDayTime *)data1;
773 const WeekDayTime *j = (const WeekDayTime *)data2;
775 if ((unsigned )RE_MASK_STOP(i->wdt_week[0]) >
776 (unsigned )RE_MASK_STOP(j->wdt_week[0]))
778 if ((unsigned )RE_MASK_STOP(i->wdt_week[0]) <
779 (unsigned )RE_MASK_STOP(j->wdt_week[0]))
790 nl = (NumberList *)calloc(1, sizeof(NumberList));
799 * Given three NumberLists convert them into arrays and return a WeekDayTime.
801 static WeekDayTimeList *
802 AllocWeekDayTimeList(
803 NumberList *week_list,
804 NumberList *day_list,
805 NumberList *time_list)
808 WeekDayTimeList *wdtl;
810 wdt = (WeekDayTime *)calloc(1, sizeof(WeekDayTime));
811 wdtl = (WeekDayTimeList *)calloc(1, sizeof(WeekDayTimeList));
814 (WeekNumber *)ConvertNumList(week_list, &(wdt->wdt_nweek));
816 (WeekDay *)ConvertNumList(day_list, &(wdt->wdt_nday));
818 (Time *)ConvertNumList(time_list, &(wdt->wdt_ntime));
819 wdtl->wdtl_weektime = wdt;
825 * Convert the DayTimeList to an array, sort the array.
829 WeekDayTimeList *wdtl,
832 WeekDayTimeList *wdtl_head = wdtl;
836 if (!wdtl) return (WeekDayTime *)NULL;
840 wdtl = wdtl->wdtl_next;
843 array = (WeekDayTime *) calloc(i, sizeof(WeekDayTime));
845 /* Convert the list into an array */
848 WeekDayTimeList *wdtl_prev;
850 array[i].wdt_day = wdtl->wdtl_weektime->wdt_day;
851 array[i].wdt_nday = wdtl->wdtl_weektime->wdt_nday;
852 array[i].wdt_time = wdtl->wdtl_weektime->wdt_time;
853 array[i].wdt_ntime = wdtl->wdtl_weektime->wdt_ntime;
854 array[i].wdt_week = wdtl->wdtl_weektime->wdt_week;
855 array[i].wdt_nweek = wdtl->wdtl_weektime->wdt_nweek;
859 wdtl = wdtl->wdtl_next;
867 qsort((void *)array, i, sizeof(WeekDayTime), CompareWeekDayTime);
879 re->re_end_date = enddate;
880 } else if (re->re_duration == RE_NOTSET) {
888 * Create a RepeatEvent for the minute portion of a rule.
892 unsigned int interval,
893 unsigned int duration)
900 re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
902 re->re_interval = interval;
903 re->re_duration = duration;
904 re->re_type = RT_MINUTE;
910 * Create a RepeatEvent for the daily portion of a rule.
914 unsigned int interval,
915 NumberList *time_list,
916 unsigned int duration,
917 RepeatEvent *other_event)
924 dd = (DailyData *)calloc(1, sizeof(DailyData));
926 /* Convert from list to array, sort */
927 dd->dd_time = (Time *)ConvertNumList(time_list, &(dd->dd_ntime));
932 re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
934 re->re_interval = interval;
935 re->re_duration = duration;
936 re->re_type = RT_DAILY;
937 re->re_data.re_daily = dd;
939 /* If there is a minuteEvent, tack it on */
941 re->re_next = other_event;
942 other_event->re_prev = re;
949 * Create a RepeatEvent for the weekly portion of a rule.
953 unsigned int interval,
955 unsigned int duration,
956 RepeatEvent *other_event)
961 wd = (WeeklyData *)calloc(1, sizeof(WeeklyData));
963 /* Convert from list to array, sort */
964 wd->wd_daytime = ConvertDayTime(dtl, &(wd->wd_ndaytime));
969 re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
971 re->re_interval = interval;
972 re->re_duration = duration;
973 re->re_type = RT_WEEKLY;
974 re->re_data.re_weekly = wd;
977 re->re_next = other_event;
978 other_event->re_prev = re;
985 * Create a RepeatEvent for the monthly portion of a rule.
990 unsigned int interval,
992 unsigned int duration,
993 RepeatEvent *other_event)
998 md = (MonthlyData *)calloc(1, sizeof(MonthlyData));
1000 /* Convert from list to array, sort */
1001 if (type == RT_MONTHLY_POSITION) {
1002 md->md_weektime = ConvertWeekDayTime(
1003 (WeekDayTimeList *)data_list, &(md->md_nitems));
1005 md->md_days = ConvertNumList(
1006 (NumberList *)data_list, &(md->md_nitems));
1012 re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
1014 re->re_interval = interval;
1015 re->re_duration = duration;
1017 re->re_data.re_monthly = md;
1019 /* If there is an another event, tack it on */
1021 re->re_next = other_event;
1022 other_event->re_prev = re;
1029 * Create a RepeatEvent for the yearly portion of a rule.
1031 static RepeatEvent *
1034 unsigned int interval,
1036 unsigned int duration,
1037 RepeatEvent *other_event)
1042 yd = (YearlyData *)calloc(1, sizeof(YearlyData));
1044 /* Convert from list to array, sort */
1045 yd->yd_items = ConvertNumList(nl, &(yd->yd_nitems));
1050 re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
1052 re->re_interval = interval;
1053 re->re_duration = duration;
1055 re->re_data.re_yearly = yd;
1057 /* If there is an another event, tack it on */
1059 re->re_next = other_event;
1060 other_event->re_prev = re;
1070 /* Don't do anything */