libcsa: Warning prevention
[oweals/cde.git] / cde / lib / csa / reparser.y
1 /* $XConsortium: reparser.y /main/2 1996/11/11 11:52:15 drk $ */
2 %{
3 /*
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.
8  */
9
10 #include <EUSCompat.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <ctype.h>
15 #include <time.h>
16 #include "rerule.h"
17 #include "iso8601.h"
18
19 /* The parsed rule is stored in this structure */
20 RepeatEvent     *_DtCm_repeat_info;
21
22 extern int               yylex();
23 extern void              yyerror(char*);
24
25 static int CompareNums(const void *, const void *);
26 static int CompareDayTime(const void *, const void *);
27 static int CompareWeekDayTime(const void *, const void *);
28 static unsigned int *ConvertNumList(NumberList *, unsigned int * /* Return */);
29 static WeekDayTime *ConvertWeekDayTime(WeekDayTimeList *, unsigned int *);
30 static NumberList *AllocNumber(unsigned int);
31 static WeekDayTimeList *AllocWeekDayTimeList(NumberList*, NumberList *,
32                         NumberList *);
33 static RepeatEvent *HandleEndDate(RepeatEvent *, time_t);
34 static RepeatEvent *DeriveMinuteEvent(unsigned int, unsigned int);
35 static RepeatEvent *DeriveDailyEvent(unsigned int, NumberList *,
36                         unsigned int, RepeatEvent *);
37 static RepeatEvent *DeriveWeeklyEvent(unsigned int, DayTimeList *,
38                         unsigned int, RepeatEvent *);
39 static RepeatEvent *DeriveMonthlyEvent(RepeatType, unsigned int, void *,
40                         unsigned int, RepeatEvent *);
41 static RepeatEvent *DeriveYearlyEvent(RepeatType, unsigned int, NumberList *,
42                         unsigned int, RepeatEvent *);
43
44 %}
45
46 %token ERROR ENDMARKER DURATION NUMBER FIRSTWEEK SECONDWEEK THIRDWEEK
47 %token FOURTHWEEK FIFTHWEEK LASTWEEK SECONDLAST THIRDLAST FOURTHLAST            
48 %token FIFTHLAST MINUTECOMMAND DAILYCOMMAND WEEKLYCOMMAND MONTHPOSCOMMAND       
49 %token MONTHDAYCOMMAND YEARDAYCOMMAND YEARMONTHCOMMAND LASTDAY SUNDAY
50 %token MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY DATE 
51
52 %union  {
53                 int              number;
54                 RepeatEvent     *re;
55                 NumberList      *nl;
56                 WeekDay          weekday;
57                 WeekNumber       weeknum;
58                 DayTime         *dt;
59                 DayTimeList     *dtl;
60                 WeekDayTimeList *wdtl;
61                 time_t           enddate;
62                 char             date[64];
63         }
64
65 %type <re>      start begin minuteEvent dailyEvent weeklyEvent monthlyPosEvent
66                 monthlyDayEvent yearlyByMonth yearlyByDay
67 %type <nl>      time0List timeList dayOfMonthList monthOfYearList
68                 dayOfYearList occurrenceList genericNumberList 
69                 generic0NumberList weekdayList
70 %type <weekday> SUNDAY MONDAY TUESDAY WEDNESDAY THURSDAY FRIDAY SATURDAY
71                 weekday
72 %type <number>  duration NUMBER occurrence endMarker time
73 %type <dtl>     weekdayTimeList
74 %type <wdtl>    weekDayTime
75 %type <dt>      weekdayTimePair
76 %type <date>    DATE
77 %type <enddate> endDate
78
79 %% /* Beginning of rules section */
80
81 start           : begin 
82                     {
83                         _DtCm_repeat_info = $$;
84                     }
85                 | error
86                     {
87                         /*
88                          * XXX: Memory leak: We need to free up any portion
89                          * of the re struct that has be allocated before the
90                          * error was encountered.
91                          */
92                         _DtCm_repeat_info = NULL;
93                     }
94                 ;
95
96 begin           : minuteEvent endDate
97                     {
98                         $$ = HandleEndDate($1, $2);
99                     }
100                 | dailyEvent endDate
101                     {
102                         $$ = HandleEndDate($1, $2);
103                     }
104                 | weeklyEvent endDate
105                     {
106                         $$ = HandleEndDate($1, $2);
107                     }
108                 | monthlyPosEvent endDate
109                     {
110                         $$ = HandleEndDate($1, $2);
111                     }
112                 | monthlyDayEvent endDate
113                     {
114                         $$ = HandleEndDate($1, $2);
115                     }
116                 | yearlyByMonth endDate
117                     {
118                         $$ = HandleEndDate($1, $2);
119                     }
120                 | yearlyByDay endDate
121                     {
122                         $$ = HandleEndDate($1, $2);
123                     }
124                 ;
125
126 minuteEvent     : /* empty */
127                     {
128                         $$ = NULL;
129                     }
130                 | MINUTECOMMAND NUMBER duration
131                     {
132 #ifdef MINUTE
133                         $$ = DeriveMinuteEvent($2, $3);
134 #else
135                         $$ = NULL;
136 #endif /* MINUTE */
137                     }
138                 ;
139
140 dailyEvent
141                 : DAILYCOMMAND NUMBER time0List duration minuteEvent
142                     {
143                         $$ = DeriveDailyEvent($2, $3, $4, $5);
144                         if ($5) $$ = NULL;
145                     }
146                 ;
147
148 weeklyEvent
149                 : WEEKLYCOMMAND NUMBER weekdayTimeList duration minuteEvent
150                     {
151                         $$ = DeriveWeeklyEvent($2, $3, $4, $5);
152                         if ($5) $$ = NULL;
153                     }
154                 | WEEKLYCOMMAND NUMBER duration minuteEvent 
155                     {
156                         $$ = DeriveWeeklyEvent($2, NULL, $3, $4);
157                         if ($4) $$ = NULL;
158                     }
159                 ;
160
161 monthlyPosEvent
162                 : MONTHPOSCOMMAND NUMBER weekDayTime duration minuteEvent
163                     {
164                         $$ = DeriveMonthlyEvent(RT_MONTHLY_POSITION,
165                                                 $2, $3, $4, $5);
166                         if ($5) $$ = NULL;
167                     }
168                 | MONTHPOSCOMMAND NUMBER weekDayTime duration dailyEvent 
169                     {
170                         $$ = DeriveMonthlyEvent(RT_MONTHLY_POSITION,
171                                                 $2, $3, $4, $5);
172                         if ($5) $$ = NULL;
173                     }
174                 | MONTHPOSCOMMAND NUMBER weekDayTime duration weeklyEvent
175                     {
176                         $$ = DeriveMonthlyEvent(RT_MONTHLY_POSITION,
177                                                 $2, $3, $4, $5);
178                         if ($5) $$ = NULL;
179                     }
180                 ;
181
182 monthlyDayEvent : MONTHDAYCOMMAND NUMBER dayOfMonthList duration minuteEvent
183                     {
184                         $$ = DeriveMonthlyEvent(RT_MONTHLY_DAY, $2, $3, $4, $5);
185                         if ($5) $$ = NULL;
186                     }
187                 | MONTHDAYCOMMAND NUMBER dayOfMonthList duration dailyEvent
188                     {
189                         $$ = DeriveMonthlyEvent(RT_MONTHLY_DAY, $2, $3, $4, $5);
190                         if ($5) $$ = NULL;
191                     }
192                 | MONTHDAYCOMMAND NUMBER dayOfMonthList duration weeklyEvent
193                     {
194                         $$ = DeriveMonthlyEvent(RT_MONTHLY_DAY, $2, $3, $4, $5);
195                         if ($5) $$ = NULL;
196                     }
197                 ;
198
199 yearlyByMonth   : YEARMONTHCOMMAND NUMBER monthOfYearList duration minuteEvent 
200                     {
201                         $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
202                         if ($5) $$ = NULL;
203                     }
204                 | YEARMONTHCOMMAND NUMBER monthOfYearList duration dailyEvent 
205                     {
206                         $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
207                         if ($5) $$ = NULL;
208                     }
209                 | YEARMONTHCOMMAND NUMBER monthOfYearList duration weeklyEvent 
210                     {
211                         $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
212                         if ($5) $$ = NULL;
213                     }
214                 | YEARMONTHCOMMAND NUMBER monthOfYearList duration
215                                                                 monthlyPosEvent 
216                     {
217                         $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
218                         if ($5) $$ = NULL;
219                     }
220                 | YEARMONTHCOMMAND NUMBER monthOfYearList duration
221                                                                 monthlyDayEvent 
222                     {
223                         $$ = DeriveYearlyEvent(RT_YEARLY_MONTH, $2, $3, $4, $5);
224                         if ($5) $$ = NULL;
225                     }
226                 ;
227
228 yearlyByDay     : YEARDAYCOMMAND NUMBER dayOfYearList duration minuteEvent 
229                     {
230                         $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
231                         if ($5) $$ = NULL;
232                     }
233                 | YEARDAYCOMMAND NUMBER dayOfYearList duration dailyEvent 
234                     {
235                         $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
236                         if ($5) $$ = NULL;
237                     }
238                 | YEARDAYCOMMAND NUMBER dayOfYearList duration weeklyEvent 
239                     {
240                         $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
241                         if ($5) $$ = NULL;
242                     }
243                 | YEARDAYCOMMAND NUMBER dayOfYearList duration monthlyPosEvent 
244                     {
245                         $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
246                         if ($5) $$ = NULL;
247                     }
248                 | YEARDAYCOMMAND NUMBER dayOfYearList duration monthlyDayEvent 
249                     {
250                         $$ = DeriveYearlyEvent(RT_YEARLY_DAY, $2, $3, $4, $5);
251                         if ($5) $$ = NULL;
252                     }
253                 ;
254
255                 /* e.g. 1W MO TU 1300 1400 */
256 weekDayTime     : /* empty */
257                     {
258                         $$ = NULL;
259                     }
260                 | weekDayTime occurrenceList weekdayList
261                     {
262                         WeekDayTimeList *wdtl;
263
264                         wdtl = AllocWeekDayTimeList($2, $3, NULL);
265
266                         if ($1 == NULL) {
267                                 $$ = wdtl;
268                         } else {
269                                 wdtl->wdtl_next = $$->wdtl_next;
270                                 $$->wdtl_next = wdtl;
271                         }
272                     }
273                 | weekDayTime occurrenceList weekdayList timeList
274                     {
275                         WeekDayTimeList *wdtl;
276
277                         wdtl = AllocWeekDayTimeList($2, $3, $4);
278
279                         if ($1 == NULL) {
280                                 $$ = wdtl;
281                         } else {
282                                 wdtl->wdtl_next = $$->wdtl_next;
283                                 $$->wdtl_next = wdtl;
284                         }
285                     }
286                 ;
287
288                 /* e.g. MO TU WE TH */
289 weekdayList     : weekday
290                     {
291                         $$ = AllocNumber($1);
292                     }
293                 | weekdayList weekday
294                     {
295                         NumberList      *nl;
296
297                         nl = AllocNumber($2);
298
299                         if ($1 == NULL) {
300                                 $$ = nl;
301                         } else {
302                                 nl->nl_next = $$->nl_next;
303                                 $$->nl_next = nl;
304                         }
305                     }
306                 ;
307
308                 /* e.g. 1W 3W 2L LW */
309 occurrenceList  : occurrence
310                     {
311                         $$ = AllocNumber($1);
312                     }
313                 | occurrenceList occurrence
314                     {
315                         NumberList      *nl;
316
317                         nl = AllocNumber($2);
318
319                         if ($1 == NULL) {
320                                 $$ = nl;
321                         } else {
322                                 nl->nl_next = $$->nl_next;
323                                 $$->nl_next = nl;
324                         }
325                    }
326                 ;
327
328                 /* e.g. MO 1300 1500 2000 */
329 weekdayTimePair : weekday time0List
330                     {
331                         DayTime         *dt;
332
333                         dt = (DayTime *)calloc(1, sizeof(DayTime));
334
335                         dt->dt_day = $1;
336                                 /* Convert from list to array, sort */
337
338                         dt->dt_time =
339                                 (Time *)ConvertNumList($2, &(dt->dt_ntime));
340                         $$ = dt;
341                     }
342                 ;
343
344                 /* e.g. MO 1300 1500 2000 TU 1200 1400 */
345 weekdayTimeList : weekdayTimePair  
346                     {
347                         DayTimeList     *dtl;
348
349                         dtl = (DayTimeList *)calloc(1, sizeof(DayTimeList));
350
351                         dtl->dtl_daytime = $1;
352                         dtl->dtl_next = NULL;
353
354                         $$ = dtl;
355
356                     }
357                 | weekdayTimeList weekdayTimePair
358                     {
359                         DayTimeList     *dtl,
360                                         *dtl_end;
361
362                         dtl = (DayTimeList *)calloc(1, sizeof(DayTimeList));
363
364                         dtl->dtl_daytime = $2;
365                         dtl->dtl_next = NULL;
366
367                         if ($1 == NULL) {
368                                 $$ = dtl;
369                         } else {
370                                 /* Insert the new entry at the end.  This is
371                                  * so that MO TU 200 300 TH will maintain the
372                                  * same order in the list since MO uses the
373                                  * times next to TU and TH is dependent on the
374                                  * appt time.
375                                  */
376                                 dtl_end = $$;
377                                 while (dtl_end->dtl_next)
378                                         dtl_end = dtl_end->dtl_next;
379                                 
380                                 dtl_end->dtl_next = dtl;
381                         }
382                    }
383                 ;
384
385                 /* e.g. 1+ 2+ 3- 1- */
386 occurrence      : FIRSTWEEK endMarker
387                     {
388                         $$ = WK_F1;
389                         if ($2) RE_SET_FLAG($$);
390                     }
391                 | SECONDWEEK endMarker
392                     {
393                         $$ = WK_F2;
394                         if ($2) RE_SET_FLAG($$);
395                     }
396                 | THIRDWEEK endMarker
397                     {
398                         $$ = WK_F3;
399                         if ($2) RE_SET_FLAG($$);
400                     }
401                 | FOURTHWEEK endMarker
402                     {
403                         $$ = WK_F4;
404                         if ($2) RE_SET_FLAG($$);
405                     }
406                 | FIFTHWEEK endMarker
407                     {
408                         $$ = WK_F5;
409                         if ($2) RE_SET_FLAG($$);
410                     }
411                 | LASTWEEK endMarker
412                     {
413                         $$ = WK_L1;
414                         if ($2) RE_SET_FLAG($$);
415                     }
416                 | SECONDLAST endMarker
417                     {
418                         $$ = WK_L2;
419                         if ($2) RE_SET_FLAG($$);
420                     }
421                 | THIRDLAST endMarker
422                     {
423                         $$ = WK_L3;
424                         if ($2) RE_SET_FLAG($$);
425                     }
426                 | FOURTHLAST endMarker
427                     {
428                         $$ = WK_L4;
429                         if ($2) RE_SET_FLAG($$);
430                     }
431                 | FIFTHLAST endMarker
432                     {
433                         $$ = WK_L5;
434                         if ($2) RE_SET_FLAG($$);
435                     }
436                 ;
437
438 endDate : /* empty */
439                     {
440                         $$ = '\0';
441                     }
442         | DATE
443                     {
444                         if (_csa_iso8601_to_tick($1, &$$) == -1)
445                                 $$ = '\0';
446                     }
447                 ;
448
449                 /* e.g. MO TU WE */
450 weekday         : SUNDAY endMarker
451                     {
452                         $$ = WD_SUN;
453                         if ($2) RE_SET_FLAG($$);
454                     }
455                 | MONDAY endMarker
456                     {
457                         $$ = WD_MON;
458                         if ($2) RE_SET_FLAG($$);
459                     }
460                 | TUESDAY endMarker
461                     {
462                         $$ = WD_TUE;
463                         if ($2) RE_SET_FLAG($$);
464                     }
465                 | WEDNESDAY endMarker
466                     {
467                         $$ = WD_WED;
468                         if ($2) RE_SET_FLAG($$);
469                     }
470                 | THURSDAY endMarker
471                     {
472                         $$ = WD_THU;
473                         if ($2) RE_SET_FLAG($$);
474                     }
475                 | FRIDAY endMarker
476                     {
477                         $$ = WD_FRI;
478                         if ($2) RE_SET_FLAG($$);
479                     }
480                 | SATURDAY endMarker
481                     {
482                         $$ = WD_SAT;
483                         if ($2) RE_SET_FLAG($$);
484                     }
485                 ;
486
487                 /* e.g. 0100 1200 1300 or NULL */
488 time0List       : /* empty */
489                    {
490                         $$ = NULL;
491                    }
492                 | time0List time
493                    {
494                         NumberList      *nl;
495
496                         nl = AllocNumber($2);
497
498                         if ($1 == NULL) {
499                                 $$ = nl;
500                         } else {
501                                 nl->nl_next = $$->nl_next;
502                                 $$->nl_next = nl;
503                         }
504                    }
505                 ;
506
507                 /* e.g. 1000 */
508 time            : NUMBER endMarker
509                     {
510                         if ($2)
511                                 RE_SET_FLAG($1);
512                         $$ = $1;
513                     }
514
515                 ;
516
517                 /* e.g. $ */
518 endMarker       : /* empty */
519                     {
520                         $$ = FALSE;
521                     }
522                 | ENDMARKER
523                     {
524                         $$ = TRUE;
525                     }
526                 ;
527
528                 /* e.g. #10 */
529 duration        : /* empty */
530                     {
531                         /* If no duration then default to 2 - set later if 
532                          * end date not used.
533                          */
534                         $$ = RE_NOTSET;
535                     }
536                 | DURATION NUMBER
537                     {
538                         /* If duration == 0 then repeat forever */
539                         if ($2 == 0)
540                                 $$ = RE_INFINITY; 
541                         else
542                                 $$ = $2;
543                     }
544                 ;
545
546 timeList        : genericNumberList
547 dayOfMonthList  : generic0NumberList
548 monthOfYearList : generic0NumberList
549 dayOfYearList   : generic0NumberList
550
551 generic0NumberList: /* empty */
552                     {
553                         $$ = NULL;
554                     }
555                 | genericNumberList
556                     {
557                         $$ = $1;
558                     }
559
560 genericNumberList
561                 : NUMBER endMarker
562                     {
563                         if ($2)
564                                 RE_SET_FLAG($1);
565
566                         $$ = AllocNumber($1);
567                     }
568                 | LASTDAY endMarker
569                     {
570                         int     number = RE_LASTDAY;
571
572                         if ($2)
573                                 RE_SET_FLAG(number);
574
575                         $$ = AllocNumber(number);
576                     }
577                 | genericNumberList NUMBER endMarker
578                     {
579                         NumberList      *nl;
580
581                         if ($3)
582                                 RE_SET_FLAG($2);
583
584                         nl = AllocNumber($2);
585
586                         if ($1 == NULL) {
587                                 $$ = nl;
588                         } else {
589                                 nl->nl_next = $$->nl_next;
590                                 $$->nl_next = nl;
591                         }
592                     }
593                 | genericNumberList LASTDAY endMarker
594                     {
595                         NumberList      *nl;
596                         int              number = RE_LASTDAY;
597
598                         if ($3)
599                                 RE_SET_FLAG(number);
600
601                         nl = AllocNumber(number);
602
603                         if ($1 == NULL) {
604                                 $$ = nl;
605                         } else {
606                                 nl->nl_next = $$->nl_next;
607                                 $$->nl_next = nl;
608                         }
609                     }
610                 ;
611
612 %%
613
614 /*
615  * Convert the NumberList (linked list) to an array, sort the array.
616  */
617 static unsigned int *
618 ConvertNumList(
619         NumberList      *nl,
620         unsigned int    *count)
621 {
622         NumberList      *nl_head = nl;
623         unsigned int    *array;
624         int              i = 0;
625
626         if (!nl) return (unsigned int *)NULL;
627
628         while (nl) {
629                 i++;
630                 nl = nl->nl_next;
631         }
632
633         array = (unsigned int *) calloc(i, sizeof(unsigned int));
634         i = 0;
635                         /* Convert the list into an array */
636         nl = nl_head;
637         while (nl) {
638                 NumberList      *nl_prev;
639
640                 array[i] = nl->nl_number;
641                 i++;
642
643                 nl_prev = nl;
644                 nl = nl->nl_next;
645
646                 free(nl_prev);
647         }
648
649         *count = i;
650
651                         /* Sort the array */
652         qsort((void *)array, i, sizeof(unsigned int), CompareNums);
653
654         return array;
655 }
656
657 /*
658  * Convert the DayTimeList to an array, sort the array.
659  */
660 static DayTime *
661 ConvertDayTime(
662         DayTimeList     *dtl,
663         unsigned int    *count)
664 {
665         DayTimeList     *dtl_head = dtl;
666         DayTime         *daytime_array;
667         int              i = 0,
668                          no_time = -1;
669
670         if (!dtl) return (DayTime *)NULL;
671
672         while (dtl) {
673                 i++;
674                 dtl = dtl->dtl_next;
675         }
676
677         daytime_array = (DayTime *) calloc(i, sizeof(DayTime));
678         i = 0;
679                         /* Convert the list into an array */
680         dtl = dtl_head;
681         while (dtl) {
682                 DayTimeList     *dtl_prev;
683
684                 daytime_array[i].dt_day = dtl->dtl_daytime->dt_day;
685                 daytime_array[i].dt_ntime = dtl->dtl_daytime->dt_ntime;
686                 daytime_array[i].dt_time = dtl->dtl_daytime->dt_time;
687                 i++;
688
689                 dtl_prev = dtl;
690                 dtl = dtl->dtl_next;
691                         /* alloc'ed in <weekdayTimeList> */
692                 free(dtl_prev);
693         }
694
695         *count = i;
696
697         for (i = 0; i < *count; i++) {
698                 if (daytime_array[i].dt_time == NULL) {
699                         if (no_time == -1)
700                                 no_time = i;
701                 } else {
702                         if (no_time != -1) {
703                                 int j;
704
705                                 for (j = no_time; j < i; j++) {
706                                         daytime_array[j].dt_ntime = 
707                                                 daytime_array[i].dt_ntime;
708                                         daytime_array[j].dt_time = 
709                                                 (Time *)calloc(
710                                                      daytime_array[j].dt_ntime,
711                                                      sizeof(Time));
712                                         memcpy(daytime_array[j].dt_time,
713                                                daytime_array[i].dt_time,
714                                                daytime_array[j].dt_ntime *
715                                                                 sizeof(Time));
716                                 }
717                                 no_time = -1;
718                         }
719                 }
720         }
721
722                         /* Sort the array */
723         qsort((void *)daytime_array, *count, sizeof(DayTime), CompareDayTime);
724
725         return daytime_array;
726 }
727
728 /*
729  * Used by qsort()
730  */
731 static int
732 CompareNums(
733         const void      *data1,
734         const void      *data2)
735 {
736         const unsigned int      *i = (const unsigned int *)data1;
737         const unsigned int      *j = (const unsigned int *)data2;
738
739         if ((unsigned )RE_MASK_STOP(*i) > (unsigned )RE_MASK_STOP(*j))
740                 return(1);
741         if ((unsigned )RE_MASK_STOP(*i) < (unsigned )RE_MASK_STOP(*j))
742                 return(-1);
743         return (0);
744 }
745
746 /*
747  * Used by qsort()
748  */
749 static int
750 CompareDayTime(
751         const void      *data1,
752         const void      *data2)
753 {
754         const DayTime   *i = (const DayTime *)data1;
755         const DayTime   *j = (const DayTime *)data2;
756
757         if ((unsigned )RE_MASK_STOP(i->dt_day) >
758                                         (unsigned )RE_MASK_STOP(j->dt_day))
759                 return(1);
760         if ((unsigned )RE_MASK_STOP(i->dt_day) <
761                                         (unsigned )RE_MASK_STOP(j->dt_day))
762                 return(-1);
763         return (0);
764 }
765
766 /*
767  * Used by qsort()
768  */
769 static int
770 CompareWeekDayTime(
771         const void      *data1,
772         const void      *data2)
773 {
774         const WeekDayTime       *i = (const WeekDayTime *)data1;
775         const WeekDayTime       *j = (const WeekDayTime *)data2;
776
777         if ((unsigned )RE_MASK_STOP(i->wdt_week[0]) >
778                                         (unsigned )RE_MASK_STOP(j->wdt_week[0]))
779                 return(1);
780         if ((unsigned )RE_MASK_STOP(i->wdt_week[0]) <
781                                         (unsigned )RE_MASK_STOP(j->wdt_week[0]))
782                 return(-1);
783         return (0);
784 }
785
786 static NumberList *
787 AllocNumber(
788         unsigned int num)
789 {
790         NumberList      *nl;
791
792         nl = (NumberList *)calloc(1, sizeof(NumberList));
793
794         nl->nl_number = num;
795         nl->nl_next = NULL;
796
797         return nl;
798 }
799
800 /*
801  * Given three NumberLists convert them into arrays and return a WeekDayTime.
802  */
803 static WeekDayTimeList *
804 AllocWeekDayTimeList(
805         NumberList      *week_list,
806         NumberList      *day_list,
807         NumberList      *time_list)
808 {
809         WeekDayTime     *wdt;
810         WeekDayTimeList *wdtl;
811
812         wdt = (WeekDayTime *)calloc(1, sizeof(WeekDayTime));
813         wdtl = (WeekDayTimeList *)calloc(1, sizeof(WeekDayTimeList));
814
815         wdt->wdt_week =
816                 (WeekNumber *)ConvertNumList(week_list, &(wdt->wdt_nweek));
817         wdt->wdt_day =
818                 (WeekDay *)ConvertNumList(day_list, &(wdt->wdt_nday));
819         wdt->wdt_time =
820                 (Time *)ConvertNumList(time_list, &(wdt->wdt_ntime));
821         wdtl->wdtl_weektime = wdt;
822
823         return wdtl;
824 }
825
826 /*
827  * Convert the DayTimeList to an array, sort the array.
828  */
829 static WeekDayTime *
830 ConvertWeekDayTime(
831         WeekDayTimeList *wdtl,
832         unsigned int    *count)
833 {
834         WeekDayTimeList *wdtl_head = wdtl;
835         WeekDayTime     *array;
836         int              i = 0;
837
838         if (!wdtl) return (WeekDayTime *)NULL;
839
840         while (wdtl) {
841                 i++;
842                 wdtl = wdtl->wdtl_next;
843         }
844
845         array = (WeekDayTime *) calloc(i, sizeof(WeekDayTime));
846         i = 0;
847                         /* Convert the list into an array */
848         wdtl = wdtl_head;
849         while (wdtl) {
850                 WeekDayTimeList *wdtl_prev;
851
852                 array[i].wdt_day = wdtl->wdtl_weektime->wdt_day;
853                 array[i].wdt_nday = wdtl->wdtl_weektime->wdt_nday;
854                 array[i].wdt_time = wdtl->wdtl_weektime->wdt_time;
855                 array[i].wdt_ntime = wdtl->wdtl_weektime->wdt_ntime;
856                 array[i].wdt_week = wdtl->wdtl_weektime->wdt_week;
857                 array[i].wdt_nweek = wdtl->wdtl_weektime->wdt_nweek;
858                 i++;
859
860                 wdtl_prev = wdtl;
861                 wdtl = wdtl->wdtl_next;
862
863                 free(wdtl_prev);
864         }
865
866         *count = i;
867
868                         /* Sort the array */
869         qsort((void *)array, i, sizeof(WeekDayTime), CompareWeekDayTime);
870
871         return array;
872 }
873
874 static RepeatEvent *
875 HandleEndDate(
876         RepeatEvent *re,
877         time_t       enddate)
878 {
879         if (re) {
880                 if (enddate) {
881                         re->re_end_date = enddate;
882                 } else if (re->re_duration == RE_NOTSET) {
883                         re->re_duration = 2;
884                 }
885         }
886         return re;
887 }
888
889 /*
890  * Create a RepeatEvent for the minute portion of a rule.
891  */
892 static RepeatEvent *
893 DeriveMinuteEvent(
894         unsigned int     interval,
895         unsigned int     duration)
896 {
897         RepeatEvent     *re;
898
899         if (interval < 1)
900                 return NULL;
901
902         re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
903                                 
904         re->re_interval = interval;
905         re->re_duration = duration;
906         re->re_type = RT_MINUTE;
907
908         return re;
909 }
910
911 /*
912  * Create a RepeatEvent for the daily portion of a rule.
913  */
914 static RepeatEvent *
915 DeriveDailyEvent(
916         unsigned int     interval,
917         NumberList      *time_list,
918         unsigned int     duration,
919         RepeatEvent     *other_event)
920 {
921         RepeatEvent     *re;
922         DailyData       *dd;
923         NumberList      *nl;
924         int              i = 0;
925
926         dd = (DailyData *)calloc(1, sizeof(DailyData));
927
928                 /* Convert from list to array, sort */
929         dd->dd_time = (Time *)ConvertNumList(time_list, &(dd->dd_ntime));
930
931         if (interval < 1)
932                 return NULL;
933
934         re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
935                                 
936         re->re_interval = interval;
937         re->re_duration = duration;
938         re->re_type = RT_DAILY;
939         re->re_data.re_daily = dd;
940
941                 /* If there is a minuteEvent, tack it on */
942         if (other_event) {
943                 re->re_next = other_event;
944                 other_event->re_prev = re;
945         }
946
947         return re;
948 }
949
950 /*
951  * Create a RepeatEvent for the weekly portion of a rule.
952  */
953 static RepeatEvent *
954 DeriveWeeklyEvent(
955         unsigned int     interval,
956         DayTimeList     *dtl,
957         unsigned int     duration,
958         RepeatEvent     *other_event)
959 {
960         RepeatEvent     *re;
961         WeeklyData      *wd;
962
963         wd = (WeeklyData *)calloc(1, sizeof(WeeklyData));
964
965                 /* Convert from list to array, sort */
966         wd->wd_daytime = ConvertDayTime(dtl, &(wd->wd_ndaytime));
967
968         if (interval < 1)
969                 return NULL;
970
971         re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
972                                 
973         re->re_interval = interval;
974         re->re_duration = duration;
975         re->re_type = RT_WEEKLY;
976         re->re_data.re_weekly = wd;
977
978         if (other_event) {
979                 re->re_next = other_event;
980                 other_event->re_prev = re;
981         }
982
983         return re;
984 }
985
986 /*
987  * Create a RepeatEvent for the monthly portion of a rule.
988  */
989 static RepeatEvent *
990 DeriveMonthlyEvent(
991         RepeatType       type,
992         unsigned int     interval,
993         void            *data_list,
994         unsigned int     duration,
995         RepeatEvent     *other_event)
996 {
997         RepeatEvent     *re;
998         MonthlyData     *md;
999
1000         md = (MonthlyData *)calloc(1, sizeof(MonthlyData));
1001
1002                         /* Convert from list to array, sort */
1003         if (type == RT_MONTHLY_POSITION) {
1004                 md->md_weektime = ConvertWeekDayTime(
1005                         (WeekDayTimeList *)data_list, &(md->md_nitems));
1006         } else {
1007                 md->md_days = ConvertNumList(
1008                         (NumberList *)data_list, &(md->md_nitems));
1009         }
1010
1011         if (interval < 1)
1012                 return NULL;
1013
1014         re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
1015                                 
1016         re->re_interval = interval;
1017         re->re_duration = duration;
1018         re->re_type = type;
1019         re->re_data.re_monthly = md;
1020
1021                 /* If there is an another event, tack it on */
1022         if (other_event) {
1023                 re->re_next = other_event;
1024                 other_event->re_prev = re;
1025         }
1026
1027         return re;
1028 }
1029
1030 /*
1031  * Create a RepeatEvent for the yearly portion of a rule.
1032  */
1033 static RepeatEvent *
1034 DeriveYearlyEvent(
1035         RepeatType       type,
1036         unsigned int     interval,
1037         NumberList      *nl,
1038         unsigned int     duration,
1039         RepeatEvent     *other_event)
1040 {
1041         RepeatEvent     *re;
1042         YearlyData      *yd;
1043
1044         yd = (YearlyData *)calloc(1, sizeof(YearlyData));
1045
1046                         /* Convert from list to array, sort */
1047         yd->yd_items = ConvertNumList(nl, &(yd->yd_nitems));
1048
1049         if (interval < 1)
1050                 return NULL;
1051
1052         re = (RepeatEvent *)calloc(1, sizeof(RepeatEvent));
1053                                 
1054         re->re_interval = interval;
1055         re->re_duration = duration;
1056         re->re_type = type;
1057         re->re_data.re_yearly = yd;
1058
1059                 /* If there is an another event, tack it on */
1060         if (other_event) {
1061                 re->re_next = other_event;
1062                 other_event->re_prev = re;
1063         }
1064
1065         return re;
1066 }
1067
1068 void
1069 yyerror(
1070         char    *str)
1071 {
1072         /* Don't do anything */
1073 }