1 /*!
2 *  \file rc-check.c
3 *  \brief Checks if a line (of a resource file)
4 *               must be inserted into `rc_elems_table[]'.
5 */
6 /*
7 *  Copyright (c) 1994, 95, 96, 1997, 2000 Thomas Esken
8 *  Copyright (c) 2010, 2011, 2013 Free Software Foundation, Inc.
9 *
10 *  This software doesn't claim completeness, correctness or usability.
11 *  On principle I will not be liable for ANY damages or losses (implicit
12 *  or explicit), which result from using or handling my software.
13 *  If you use this software, you agree without any exception to this
14 *  agreement, which binds you LEGALLY !!
15 *
16 *  This program is free software; you can redistribute it and/or modify
17 *  it under the terms of the `GNU General Public License' as published by
18 *  the `Free Software Foundation'; either version 3, or (at your option)
19 *  any later version.
20 *
21 *  You should have received a copy of the `GNU General Public License'
22 *  along with this program; if not, write to the:
23 *
24 */
25 
26 
27 
28 /*
29 *  Include definition header file to see whether USE_RC is defined there.
30 *    Compile this module only if USE_RC is defined, otherwise skip it.
31 */
32 #include "tailor.h"
33 
34 
35 
36 #if USE_RC
37 
38 
39 /*
40 *  Include header files.
41 */
42 # if HAVE_CTYPE_H
43 #  include <ctype.h>
44 # endif
45 # include "common.h"
46 # include "rc-defs.h"
47 # include "globals.h"
48 # include "rc-insert.h"
49 # include "rc-utils.h"
50 # include "utils.h"
51 # include "rc-check.h"
52 
53 
54 
55 /*
56 *  static functions prototypes.
57 */
58 __BEGIN_DECLARATIONS
59 /*
60 ************************************************** Defined in `rc-check.c'.
61 */
62 static Bool
63   date_matches_period __P_ ((int *print_twice,
64 			     int day, int ed, const int wd));
65 static int get_number __P_ ((char **string));
66 __END_DECLARATIONS
67 /*
68 *  static variables definitions.
69 */
70 /*! Textual weekday name is found and must be respected. */
71 static Bool is_weekday_mode = FALSE;
72 
73 /*! No explicit month command is given in the command line. */
74 static Bool changed_month = FALSE;
75 
76 
77 
78 /*
79 *  Function implementations.
80 */
81 void
rc_check(line_buffer,filename,line_number,line_length,rc_elems,day,ed,wd)82 rc_check (line_buffer, filename, line_number, line_length, rc_elems, day, ed,
83 	  wd)
84      char *line_buffer;
85      const char *filename;
86      const long line_number;
87      const int line_length;
88      int *rc_elems;
89      const int day;
90      const int ed;
91      const int wd;
92 /*!
93    Checks whether a single line of a resource file resp.,
94      eternal holiday must be displayed.
95 */
96 {
97   register int i;
98   register int j;
99   register int buf_d = 0;
100   register int buf_m;
101   register int buf_y;
102   register int dvar_base_day = 0;
103   register int dvar_base_month = 0;
104   register int repeat = 0;
105   register int appears = 0;
106   register int productions = 2;
107   register int tmp_month = month;
108   auto int print_twice;
109   auto int len_date;
110   auto int n;
111   auto int tmp_d;
112   auto int tmp_m;
113   auto int tmp_y;
114   auto int tmp_n;
115   auto int tmp_hn;
116   auto int tmp_hwd = 0;
117   auto Bool is_valid_date;
118   auto Bool is_day_given;
119   auto Bool is_month_given;
120   auto Bool is_coded_month;
121   auto Bool is_first = TRUE;
122   auto Bool is_range = FALSE;
123   auto Bool date_unset = FALSE;
124   auto Bool must_ignore_feb_29 = FALSE;
125 
126 
127   /*
128      Decode a delivered line:
129      This means all necessary information is stored in the according
130      variables, which are set by decoding the "date"-part of the line.
131    */
132   lineptrs =
133     rc_get_date (line_buffer, lineptrs, TRUE, &is_weekday_mode, &d, &m, &y,
134 		 &n, &len_date, &hc, &hn, &hwd, filename, line_number,
135 		 line_buffer, TRUE);
136   if (len_date < 1)
137     /*
138        Error, invalid date field given.
139      */
140     my_error (ERR_INVALID_DATE_FIELD, filename, line_number, line_buffer, 0);
141   if ((len_date < line_length) && !*lineptrs->text_part)
142     /*
143        Error, missing whitespace character between "date"-part and "text"-part.
144      */
145     my_error (ERR_NO_SEPARATOR_CHAR, filename, line_number, line_buffer, 0);
146   if (!month)
147     {
148       month = act_month;
149       changed_month = TRUE;
150     }
151   else
152     changed_month = FALSE;
153   buf_m = m;
154   buf_y = y;
155   /*
156      We work with a buffer of the returned (allocated and filled)
157      char pointers of the `lineptrs' struct.
158    */
159   lptrs->day_part = lineptrs->day_part;
160   lptrs->repeat_part = lineptrs->repeat_part;
161   lptrs->appears_part = lineptrs->appears_part;
162   do
163     {
164       /*
165          Look if a list/range of days/weekday names is given,
166          if so then let's create 1xN productions of such a line.
167        */
168       if (!is_range && (lptrs->day_part != (char *) NULL))
169 	{
170 	  auto char *ptr2_char;
171 	  auto char ch;
172 
173 
174 	  repeat = appears = hwd = tmp_hn = hn = tmp_n = n = i = 0;
175 	  is_range = is_coded_month = is_month_given = is_day_given =
176 	    is_weekday_mode = FALSE;
177 	  /*
178 	     Store the base date if a date variable is given.
179 	   */
180 	  if (is_first && islower (hc))
181 	    {
182 	      if (y == SPECIAL_VALUE)
183 		/*
184 		   Error, date variable is undefined.
185 		 */
186 		break;
187 	      dvar_base_day = d;
188 	      dvar_base_month = m;
189 	    }
190 	  if (lineptrs->day_list)
191 	    /*
192 	       Manage a list of days/weekday names.
193 	     */
194 	    {
195 	      /*
196 	         If a list of days/weekday names is given, we have to set the
197 	         number of productions to any value greater 1, because we
198 	         terminate the production creating loop by a `break' statement
199 	         after all elements of the list are evaluated.
200 	       */
201 	      productions = 2;
202 	      /*
203 	         Copy an element of the list into `s6'.
204 	       */
205 	      while (*lptrs->day_part
206 		     && !isspace (*lptrs->day_part)
207 		     && (*lptrs->day_part != RC_DLIST_CHAR
208 			 && (*lptrs->day_part != RC_REPEAT_CHAR)
209 			 && (*lptrs->day_part != RC_APPEARS_CHAR)))
210 		s6[i++] = *(lptrs->day_part++);
211 	      s6[i] = '\0';
212 	      if (!i && (!is_first || !islower (hc)))
213 		/*
214 		   Error, an empty list element given (e.g.:  DD,,DD or WW[W],,WW[W]N).
215 		   The only place where an empty list element may occur is the
216 		   trailing character after a @e|t|DVAR text, e.g.:  @e,+10,-3fr ...,
217 		   which means -> first evaluate  @e  and then  @e+10  and then  @e-3fr.
218 		 */
219 		my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
220 			  line_buffer, 0);
221 	      is_first = FALSE;
222 	      ptr2_char = s6;
223 	      if (hc && *ptr2_char)
224 		{
225 		  hn = atoi (s6);
226 		  if (islower (hc))
227 		    {
228 		      if (*ptr2_char == *ASC_LIT || *ptr2_char == *DES_LIT)
229 			ptr2_char++;
230 		      if (*ptr2_char == *ASC_LIT
231 			  || *ptr2_char == *DES_LIT || isalpha (*ptr2_char))
232 			/*
233 			   Error, simple weekday name or invalid sign given.
234 			 */
235 			my_error (ERR_INVALID_DATE_FIELD, filename,
236 				  line_number, line_buffer, 0);
237 		    }
238 		  else if (*ptr2_char == *ASC_LIT || *ptr2_char == *DES_LIT)
239 		    /*
240 		       Error, invalid sign given.
241 		     */
242 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
243 			      line_buffer, 0);
244 		  /*
245 		     Now eat all digits.
246 		   */
247 		  while (isdigit (*ptr2_char))
248 		    ptr2_char++;
249 		}
250 	      if (!hc || *ptr2_char)
251 		{
252 		  if (!hc && i)
253 		    {
254 		      if (i > 2)
255 			{
256 			  if (!isdigit (*ptr2_char))
257 			    {
258 			      ch = s6[TXTLEN_MONTH];
259 			      s6[TXTLEN_MONTH] = '\0';
260 			      m = compare_d_m_name (ptr2_char, MOnth);
261 			      s6[TXTLEN_MONTH] = ch;
262 			      if (!m)
263 				{
264 				  if (compare_d_m_name (ptr2_char, DAy))
265 				    goto LABEL_list_day_name_given;
266 				  /*
267 				     Error, invalid textual month name given.
268 				   */
269 				  my_error (ERR_INVALID_DATE_FIELD, filename,
270 					    line_number, line_buffer, 0);
271 				}
272 			      ptr2_char++;
273 			    }
274 			  else
275 			    {
276 			      ch = s6[2];
277 			      s6[2] = '\0';
278 			      m = atoi (ptr2_char);
279 			      if (m == 99)
280 				m = MONTH_MAX;
281 			      if (m > MONTH_MAX)
282 				/*
283 				   Error, invalid month number (mm) given.
284 				 */
285 				my_error (ERR_INVALID_DATE_FIELD, filename,
286 					  line_number, line_buffer, 0);
287 			      s6[2] = ch;
288 			    }
289 			  ptr2_char += 2;
290 			  if (m)
291 			    is_month_given = TRUE;
292 			  else
293 			    is_coded_month = TRUE;
294 			}
295 		    LABEL_list_day_name_given:
296 		      d = atoi (ptr2_char);
297 		      if (d)
298 			is_day_given = TRUE;
299 		      else if (isdigit (*ptr2_char))
300 			/*
301 			   Error, invalid day number (DD) given.
302 			 */
303 			my_error (ERR_INVALID_DATE_FIELD, filename,
304 				  line_number, line_buffer, 0);
305 		    }
306 		  if (!isdigit (*ptr2_char))
307 		    {
308 		      d = compare_d_m_name (ptr2_char, DAy);
309 		      if (!d)
310 			/*
311 			   Error, invalid textual day name (WW[W]) given.
312 			 */
313 			my_error (ERR_INVALID_DATE_FIELD, filename,
314 				  line_number, line_buffer, 0);
315 		    }
316 		}
317 	      if (!is_month_given && !is_coded_month)
318 		m = buf_m;
319 	      y = buf_y;
320 	      if (!is_day_given)
321 		{
322 		  if (!hc)
323 		    {
324 		      if (isdigit (s6[i - 1]))
325 			{
326 			  if (isdigit (s6[i - 2]))
327 			    /*
328 			       Error, "N'th weekday of month" field contains more than one digit.
329 			     */
330 			    my_error (ERR_INVALID_DATE_FIELD, filename,
331 				      line_number, line_buffer, 0);
332 			  n = CHR2DIG (s6[i - 1]);
333 			  /*
334 			     Error, invalid "N'th weekday of month" number given.
335 			   */
336 			  if ((n > 5) && (n < 9))
337 			    my_error (ERR_INVALID_NWD_FIELD, filename,
338 				      line_number, line_buffer, n);
339 			}
340 		      if (!n)
341 			is_weekday_mode = TRUE;
342 		    }
343 		  else
344 		    {
345 		      if (*ptr2_char)
346 			hwd = d;
347 		      if (!islower (hc))
348 			d = 0;
349 		    }
350 		}
351 	      if (islower (hc))
352 		{
353 		  d = dvar_base_day;
354 		  m = dvar_base_month;
355 		}
356 	      if (hc && y)
357 		{
358 		  if (islower (hc))
359 		    {
360 		      if (!precomp_date (hn, hwd, &d, &m, y,
361 					 (hc == RC_EASTER_CHAR) ? EAster :
362 					 ((hc ==
363 					   RC_TODAY_CHAR) ? TOday : DVar)))
364 			/*
365 			   If the date is not computable, skip this list entry.
366 			 */
367 			y = SPECIAL_VALUE;
368 		    }
369 		  else
370 		    if (!precomp_nth_wd (hn, hwd, &hn, &d, &m, &y,
371 					 (hc == 'D') ? DAy : WEek))
372 		    /*
373 		       If the date is not computable, skip this list entry.
374 		     */
375 		    y = SPECIAL_VALUE;
376 		}
377 	      if (!y && !is_coded_month)
378 		manage_leap_day (&d, &m, year, line_buffer, filename,
379 				 line_number);
380 	      /*
381 	         Check if a "repeat for N days since..." field or a
382 	         "for each N'th day since..." field is given in this list element.
383 	       */
384 	      if (*lptrs->day_part == RC_REPEAT_CHAR
385 		  || *lptrs->day_part == RC_APPEARS_CHAR)
386 		{
387 		  if (is_weekday_mode)
388 		    /*
389 		       Error, it's invalid to specify a simple weekday name WWW
390 		       with a "repeat" or "appears" coding (e.g.: WWW:10,WWW.3,WWW:10.3 ...).
391 		     */
392 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
393 			      line_buffer, 0);
394 		  else
395 		    {
396 		      register int num_repeat = 0;
397 		      register int num_appears = 0;
398 
399 
400 		      do
401 			{
402 			  if (*lptrs->day_part == RC_REPEAT_CHAR)
403 			    {
404 			      repeat = get_number (&lptrs->day_part);
405 			      num_repeat++;
406 			    }
407 			  if (*lptrs->day_part == RC_APPEARS_CHAR)
408 			    {
409 			      appears = get_number (&lptrs->day_part);
410 			      num_appears++;
411 			    }
412 			}
413 		      while (--productions);
414 		      if (num_repeat > 1
415 			  || num_appears > 1 || (!repeat && !appears))
416 			/*
417 			   Error, either "repeat" or "appears" coding given twice
418 			   or invalid by other reasons (a number > 999 given).
419 			 */
420 			my_error (ERR_INVALID_DATE_FIELD, filename,
421 				  line_number, line_buffer, 0);
422 		      if (appears)
423 			appears--;
424 		      /*
425 		         Well, we have to use an unoptimized number of productions now.
426 		       */
427 		      productions = repeat;
428 		    }
429 		}
430 	      /*
431 	         Skip the ONE separating character of the list of days.
432 	       */
433 	      if (*lptrs->day_part == RC_DLIST_CHAR)
434 		lptrs->day_part++;
435 	      else if (!*lptrs->day_part || isspace (*lptrs->day_part))
436 		{
437 		  free (lineptrs->day_part);
438 		  lptrs->day_part = lineptrs->day_part = (char *) NULL;
439 		}
440 	      else
441 		/*
442 		   Error, invalid "repeat" or "appears" coding given
443 		   (one of the fields contains invalid characters).
444 		 */
445 		my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
446 			  line_buffer, 0);
447 	    }
448 	  else
449 	    /*
450 	       Manage a range of days/weekday names.
451 	     */
452 	    {
453 	      if (lptrs->repeat_part != (char *) NULL)
454 		/*
455 		   Error, a "repeat" coding makes no sense in ranges of days.
456 		 */
457 		my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
458 			  line_buffer, 0);
459 	      /*
460 	         Copy the starting element of the range into `s6'.
461 	       */
462 	      while (*lptrs->day_part != RC_DRANGE_CHAR)
463 		s6[i++] = *(lptrs->day_part++);
464 	      s6[i] = '\0';
465 	      if (strchr (s6, RC_APPEARS_CHAR) != (char *) NULL)
466 		/*
467 		   Error, a "appears" coding may only be given last to a range of days.
468 		 */
469 		my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
470 			  line_buffer, 0);
471 	      ptr2_char = s6;
472 	      /*
473 	         Skip THE separating character of the range of days.
474 	       */
475 	      lptrs->day_part++;
476 	      if (hc && *ptr2_char)
477 		{
478 		  hn = atoi (s6);
479 		  if (islower (hc))
480 		    {
481 		      if (*ptr2_char == *ASC_LIT || *ptr2_char == *DES_LIT)
482 			ptr2_char++;
483 		      if (*ptr2_char == *ASC_LIT
484 			  || *ptr2_char == *DES_LIT || isalpha (*ptr2_char))
485 			/*
486 			   Error, simple weekday name WWW or invalid sign given.
487 			 */
488 			my_error (ERR_INVALID_DATE_FIELD, filename,
489 				  line_number, line_buffer, 0);
490 		    }
491 		  else if (*ptr2_char == *ASC_LIT || *ptr2_char == *DES_LIT)
492 		    /*
493 		       Error, invalid sign given.
494 		     */
495 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
496 			      line_buffer, 0);
497 		  /*
498 		     Now eat all digits.
499 		   */
500 		  while (isdigit (*ptr2_char))
501 		    ptr2_char++;
502 		}
503 	      if (!hc || *ptr2_char)
504 		{
505 		  if (!hc)
506 		    {
507 		      d = atoi (ptr2_char);
508 		      if (d)
509 			is_day_given = TRUE;
510 		      else if (isdigit (*ptr2_char))
511 			/*
512 			   Error, invalid day number (==0) given.
513 			 */
514 			my_error (ERR_INVALID_DATE_FIELD, filename,
515 				  line_number, line_buffer, 0);
516 		    }
517 		  if (!isdigit (*ptr2_char))
518 		    {
519 		      buf_d = d = compare_d_m_name (ptr2_char, DAy);
520 		      if (!d)
521 			/*
522 			   Error, invalid weekday name (WW[W]) given.
523 			 */
524 			my_error (ERR_INVALID_DATE_FIELD, filename,
525 				  line_number, line_buffer, 0);
526 		    }
527 		  if (!is_day_given)
528 		    {
529 		      if (!hc && isdigit (s6[i - 1]))
530 			{
531 			  if (isdigit (s6[i - 2]))
532 			    /*
533 			       Error, "N'th weekday of month" field contains more than one digit.
534 			     */
535 			    my_error (ERR_INVALID_DATE_FIELD, filename,
536 				      line_number, line_buffer, 0);
537 			  n = CHR2DIG (s6[i - 1]);
538 			  /*
539 			     Error, invalid "N'th weekday of month" number given.
540 			   */
541 			  if ((n > 5) && (n < 9))
542 			    my_error (ERR_INVALID_NWD_FIELD, filename,
543 				      line_number, line_buffer, n);
544 			  if (n)
545 			    {
546 			      is_range = TRUE;
547 			      nth_weekday_of_month (&d, &m, &y, &n,
548 						    &is_weekday_mode);
549 			      if (!m || y == SPECIAL_VALUE)
550 				/*
551 				   If the date is not computable, exit the loop.
552 				 */
553 				break;
554 			    }
555 			  else
556 			    is_weekday_mode = TRUE;
557 			}
558 		      else
559 			{
560 			  if (!hc)
561 			    is_weekday_mode = TRUE;
562 			  else
563 			    {
564 			      is_range = TRUE;
565 			      hwd = d;
566 			    }
567 			}
568 		    }
569 		  else
570 		    {
571 		      if (!m
572 			  && (rc_year_flag
573 			      || rc_period_list
574 			      || is_3month_mode
575 			      || is_3month_mode2 || fiscal_month > MONTH_MIN))
576 			/*
577 			   If no month `m' is given and we are in one of these modes,
578 			   exit the loop.
579 			 */
580 			break;
581 		      is_range = TRUE;
582 		      if (!y)
583 			y = year;
584 		      if (!m)
585 			m = month;
586 		    }
587 		}
588 	      else
589 		{
590 		  is_range = TRUE;
591 		  hwd = 0;
592 		}
593 	      if (hc)
594 		{
595 		  if (!y)
596 		    y = year;
597 		  if (islower (hc))
598 		    {
599 		      d = dvar_base_day;
600 		      m = dvar_base_month;
601 		      if (!precomp_date (hn, hwd, &d, &m, y,
602 					 (hc == RC_EASTER_CHAR) ? EAster :
603 					 ((hc ==
604 					   RC_TODAY_CHAR) ? TOday : DVar)))
605 			date_unset = TRUE;
606 		    }
607 		  else
608 		    if (!precomp_nth_wd (hn, hwd, &hn, &d, &m, &y,
609 					 (hc == 'D') ? DAy : WEek))
610 		    date_unset = TRUE;
611 		  if (date_unset)
612 		    {
613 		      /*
614 		         If the date is not computable, set `d' and `m'
615 		         to 1-JAN if `hn' is less zero, otherwise to 31-DEC
616 		         if `hn' is greater than +1.
617 		       */
618 		      if (!hn || hwd)
619 			/*
620 			   If the date isn't computable at all, exit the loop.
621 			 */
622 			break;
623 		      date_unset = FALSE;
624 		      if (hn < 0)
625 			{
626 			  m = MONTH_MIN;
627 			  d = DAY_MIN;
628 			}
629 		      else
630 			{
631 			  m = MONTH_MAX;
632 			  d = dvec[m - 1];
633 			}
634 		    }
635 		}
636 	      /*
637 	         Copy the final element of the range into `s6'.
638 	       */
639 	      is_day_given = FALSE;
640 	      i = 0;
641 	      while (*lptrs->day_part
642 		     && !isspace (*lptrs->day_part)
643 		     && (*lptrs->day_part != RC_APPEARS_CHAR))
644 		s6[i++] = *(lptrs->day_part++);
645 	      s6[i] = '\0';
646 	      ptr2_char = s6;
647 	      free (lineptrs->day_part);
648 	      lptrs->day_part = lineptrs->day_part = (char *) NULL;
649 	      if (hc && *ptr2_char)
650 		{
651 		  tmp_hn = atoi (s6);
652 		  if (islower (hc))
653 		    {
654 		      if (*ptr2_char == *ASC_LIT || *ptr2_char == *DES_LIT)
655 			ptr2_char++;
656 		      if (*ptr2_char == *ASC_LIT
657 			  || *ptr2_char == *DES_LIT || isalpha (*ptr2_char))
658 			/*
659 			   Error, simple weekday name or invalid sign given.
660 			 */
661 			my_error (ERR_INVALID_DATE_FIELD, filename,
662 				  line_number, line_buffer, 0);
663 		    }
664 		  else if (*ptr2_char == *ASC_LIT || *ptr2_char == *DES_LIT)
665 		    /*
666 		       Error, invalid sign given.
667 		     */
668 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
669 			      line_buffer, 0);
670 		  /*
671 		     Now eat all digits.
672 		   */
673 		  while (isdigit (*ptr2_char))
674 		    ptr2_char++;
675 		  /*
676 		     Now eat an "appears" field (if given).
677 		   */
678 		  if (*ptr2_char == RC_APPEARS_CHAR)
679 		    {
680 		      ptr2_char++;
681 		      while (isdigit (*ptr2_char))
682 			ptr2_char++;
683 		    }
684 		}
685 	      if (!hc || *ptr2_char)
686 		{
687 		  if (!hc && i)
688 		    {
689 		      if (i > 2)
690 			{
691 			  if (!isdigit (*ptr2_char))
692 			    {
693 			      ch = s6[TXTLEN_MONTH];
694 			      s6[TXTLEN_MONTH] = '\0';
695 			      tmp_m = compare_d_m_name (ptr2_char, MOnth);
696 			      s6[TXTLEN_MONTH] = ch;
697 			      if (!tmp_m)
698 				{
699 				  if (compare_d_m_name (ptr2_char, DAy))
700 				    goto LABEL_range_day_name_given;
701 				  /*
702 				     Error, invalid textual month name given.
703 				   */
704 				  my_error (ERR_INVALID_DATE_FIELD, filename,
705 					    line_number, line_buffer, 0);
706 				}
707 			      s6[3] = ch;
708 			      ptr2_char++;
709 			    }
710 			  else
711 			    {
712 			      ch = s6[2];
713 			      s6[2] = '\0';
714 			      tmp_m = atoi (ptr2_char);
715 			      if (tmp_m == 99)
716 				tmp_m = MONTH_MAX;
717 			      if (tmp_m > MONTH_MAX)
718 				/*
719 				   Error, invalid month number (MM) given.
720 				 */
721 				my_error (ERR_INVALID_DATE_FIELD, filename,
722 					  line_number, line_buffer, 0);
723 			      s6[2] = ch;
724 			    }
725 			  ptr2_char += 2;
726 			  if (tmp_m)
727 			    is_month_given = TRUE;
728 			  else
729 			    is_coded_month = TRUE;
730 			}
731 		    LABEL_range_day_name_given:
732 		      tmp_d = atoi (ptr2_char);
733 		      if (tmp_d)
734 			is_day_given = TRUE;
735 		    }
736 		  if (!isdigit (*ptr2_char))
737 		    {
738 		      buf_d = tmp_d = compare_d_m_name (ptr2_char, DAy);
739 		      if (!tmp_d)
740 			/*
741 			   Error, invalid textual day name (WW[W]) given.
742 			 */
743 			my_error (ERR_INVALID_DATE_FIELD, filename,
744 				  line_number, line_buffer, 0);
745 		    }
746 		  if (!is_day_given)
747 		    {
748 		      if (isdigit (s6[i - 1]))
749 			{
750 			  if (isdigit (s6[i - 2]))
751 			    /*
752 			       Error, "N'th weekday of month" field contains more than one digit.
753 			     */
754 			    my_error (ERR_INVALID_DATE_FIELD, filename,
755 				      line_number, line_buffer, 0);
756 			  tmp_n = CHR2DIG (s6[i - 1]);
757 			}
758 		      if (!hc && tmp_n && is_range)
759 			{
760 			  /*
761 			     Error, invalid "N'th weekday of month" number given.
762 			   */
763 			  if ((tmp_n > 5) && (tmp_n < 9))
764 			    my_error (ERR_INVALID_NWD_FIELD, filename,
765 				      line_number, line_buffer, tmp_n);
766 			  if (!is_month_given)
767 			    tmp_m = buf_m;
768 			  tmp_y = buf_y;
769 			  nth_weekday_of_month (&tmp_d, &tmp_m, &tmp_y,
770 						&tmp_n, &is_weekday_mode);
771 			  if (!tmp_m || tmp_y == SPECIAL_VALUE)
772 			    /*
773 			       If the date is not computable, exit the loop.
774 			     */
775 			    break;
776 			  if (y != tmp_y)
777 			    /*
778 			       If the dates are in different years, exit the loop.
779 			     */
780 			    break;
781 			}
782 		      else
783 			{
784 			  if (!hc && (tmp_n || is_range))
785 			    /*
786 			       Error, mixed range of days given (DD#WW[W], WW[W]#WW[W]N or WW[W]N#WW[w]).
787 			     */
788 			    my_error (ERR_INVALID_DATE_FIELD, filename,
789 				      line_number, line_buffer, 0);
790 			  else if (!tmp_hn && is_range)
791 			    /*
792 			       Error, invalid range of days given (NWW[W]#WW[W]).
793 			     */
794 			    my_error (ERR_INVALID_DATE_FIELD, filename,
795 				      line_number, line_buffer, 0);
796 			  else
797 			    tmp_hwd = tmp_d;
798 			}
799 		    }
800 		  else
801 		    {
802 		      if (is_day_given && !is_range)
803 			/*
804 			   Error, invalid range of days given (WW[W]#DD).
805 			 */
806 			my_error (ERR_INVALID_DATE_FIELD, filename,
807 				  line_number, line_buffer, 0);
808 		      if (!tmp_m && is_coded_month
809 			  && (rc_year_flag || rc_period_list || is_3month_mode
810 			      || is_3month_mode2 || fiscal_month > MONTH_MIN))
811 			/*
812 			   If the month of a final day is coded like: ...#MMDD
813 			   or ...#MMWW[W]N, but MM is explicitly set to zero (==00 coded)
814 			   and we are in one of these modes, exit the loop.
815 			 */
816 			break;
817 		      if (!is_month_given)
818 			tmp_m = m;
819 		      tmp_y = y;
820 		    }
821 		}
822 	      else
823 		tmp_hwd = 0;
824 	      /*
825 	         We have to avoid constructions like: YYYY00DD|WW[W]N#MMDD|WW[W]N
826 	         which means, no starting month but a final month is given and
827 	         if both months differ after pre-evaluating the starting month
828 	         (which is set to the current month), exit the loop.
829 	       */
830 	      if (!buf_m && is_month_given && (m != tmp_m))
831 		break;
832 	      if (hc)
833 		{
834 		  tmp_y = y;
835 		  if (islower (hc))
836 		    {
837 		      tmp_d = dvar_base_day;
838 		      tmp_m = dvar_base_month;
839 		      if (!precomp_date
840 			  (tmp_hn, tmp_hwd, &tmp_d, &tmp_m, tmp_y,
841 			   (hc ==
842 			    RC_EASTER_CHAR) ? EAster : ((hc ==
843 							 RC_TODAY_CHAR) ?
844 							TOday : DVar)))
845 			date_unset = TRUE;
846 		    }
847 		  else
848 		    if (!precomp_nth_wd
849 			(tmp_hn, tmp_hwd, &tmp_hn, &tmp_d, &tmp_m, &tmp_y,
850 			 (hc == 'D') ? DAy : WEek))
851 		    date_unset = TRUE;
852 		  if (date_unset)
853 		    {
854 		      /*
855 		         If the date is not computable, set `tmp_d' and `tmp_m'
856 		         to 1-JAN if `tmp_hn' is less zero, otherwise to 31-DEC
857 		         if `tmp_hn' is greater than +1.
858 		       */
859 		      if (!tmp_hn || tmp_hwd)
860 			/*
861 			   If the date isn't computable at all, exit the loop.
862 			 */
863 			break;
864 		      if (tmp_hn < 0)
865 			{
866 			  tmp_m = MONTH_MIN;
867 			  tmp_d = DAY_MIN;
868 			}
869 		      else
870 			{
871 			  tmp_m = MONTH_MAX;
872 			  tmp_d = dvec[tmp_m - 1];
873 			}
874 		    }
875 		  hc = '\0';
876 		}
877 	      n = 0;
878 	      /*
879 	         Let's decode the "for each N'th day since..." field of a line.
880 	       */
881 	      if (lptrs->appears_part != (char *) NULL)
882 		{
883 		  appears = get_number (&lptrs->appears_part);
884 		  if (!appears
885 		      || (*lptrs->appears_part
886 			  && !isspace (*lptrs->appears_part)))
887 		    /*
888 		       Error, invalid "appears" field given.
889 		     */
890 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
891 			      line_buffer, 0);
892 		  appears--;
893 		}
894 	      /*
895 	         Compute the number of 1xN productions.
896 	       */
897 	      if (is_range)
898 		{
899 		  /*
900 		     If the special value "99" for a day is given,
901 		     set the day to the last day of the month.
902 		   */
903 		  if (d == 99)
904 		    {
905 		      if (m == 2)
906 			d = days_of_february (y);
907 		      else
908 			d = dvec[m - 1];
909 		    }
910 		  if (tmp_d == 99)
911 		    {
912 		      if (tmp_m == 2)
913 			tmp_d = days_of_february (tmp_y);
914 		      else
915 			tmp_d = dvec[tmp_m - 1];
916 		    }
917 		  if (d > MONTH_LAST || tmp_d > MONTH_LAST)
918 		    /*
919 		       Error, invalid day number (>MONTH_LAST) is given.
920 		     */
921 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
922 			      line_buffer, 0);
923 		  if (!buf_y)
924 		    {
925 		      if (buf_m)
926 			manage_leap_day (&d, &m, y, line_buffer, filename,
927 					 line_number);
928 		      if (is_month_given || (buf_m && !is_month_given))
929 			manage_leap_day (&tmp_d, &tmp_m, tmp_y, line_buffer,
930 					 filename, line_number);
931 		      /*
932 		         Check if a range of days starting or ending at
933 		         00000229 must be ignored in non-leap years.
934 		       */
935 		      if ((days_of_february (y) == 28)
936 			  && (((d == 29)
937 			       && (m == 2)
938 			       && (m == buf_m))
939 			      || ((tmp_d == 29)
940 				  && (tmp_m == 2)
941 				  && (tmp_m == buf_m || is_month_given))))
942 			must_ignore_feb_29 = TRUE;
943 		    }
944 		  /*
945 		     If invalid dates are given, try to correct them.
946 		   */
947 		  while (!valid_date (d, m, y))
948 		    {
949 		      if (!buf_m || must_ignore_feb_29)
950 			d--;
951 		      else
952 			/*
953 			   Error, invalid date given (e.g.: YYYY0230 or YYYY0931).
954 			 */
955 			my_error (ERR_INVALID_DATE_FIELD, filename,
956 				  line_number, line_buffer, 0);
957 		    }
958 		  while (!valid_date (tmp_d, tmp_m, tmp_y))
959 		    {
960 		      if ((!buf_m && !is_month_given) || must_ignore_feb_29)
961 			tmp_d--;
962 		      else
963 			/*
964 			   Error, invalid date given (e.g.: YYYY0230 or YYYY0931).
965 			 */
966 			my_error (ERR_INVALID_DATE_FIELD, filename,
967 				  line_number, line_buffer, 0);
968 		    }
969 		  /*
970 		     Compute the raw number of 1xN productions.
971 		   */
972 		  i = day_of_year (d, m, y);
973 		  j = day_of_year (tmp_d, tmp_m, tmp_y);
974 		  if (i > j)
975 		    {
976 		      /*
977 		         Swap the starting date of the event.
978 		       */
979 		      int tmp = i;
980 		      i = j;
981 		      j = tmp;
982 
983 		      d = tmp_d;
984 		      m = tmp_m;
985 		      y = tmp_y;
986 		    }
987 		  productions = j - i;
988 		  if (productions)
989 		    {
990 		      /*
991 		         Optimize the number of 1xN productions.
992 		       */
993 		      if (i < day)
994 			{
995 			  if (appears)
996 			    {
997 			      register int k;
998 
999 
1000 			      /*
1001 			         Advance to the first date in period if an "appears" coding is given.
1002 			       */
1003 			      do
1004 				{
1005 				  k = i;
1006 				  (void) doy2date (i + appears + 1,
1007 						   (days_of_february (y) ==
1008 						    29), &d, &m);
1009 				  i = day_of_year (d, m, y);
1010 				  if (i == k)
1011 				    /*
1012 				       The date can't be advanced by an "appears" factor
1013 				       because the computed date would be leaving the year bounds!
1014 				     */
1015 				    i = day;
1016 				}
1017 			      while (i < day);
1018 			    }
1019 			  else
1020 			    i = day;
1021 			}
1022 		      /*
1023 		         Set a new starting date of the event.
1024 		       */
1025 		      (void) doy2date (i, (days_of_february (y) == 29), &d,
1026 				       &m);
1027 		      if (j > ed - 1)
1028 			j = ed - 1;
1029 		      productions = j - i;
1030 		      if (productions < 0)
1031 			/*
1032 			   Date doesn't match the period, exit the loop.
1033 			 */
1034 			break;
1035 		    }
1036 		}
1037 	      else
1038 		{
1039 		  if (is_month_given)
1040 		    /*
1041 		       Error, simple textual weekday ranges (WW[W]#WW[W]) may
1042 		       not have a specified final month like: WW[W]#MMWW[W].
1043 		     */
1044 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
1045 			      line_buffer, 0);
1046 		  /*
1047 		     Compute the number of 1xN productions for simple weekdays!
1048 		   */
1049 		  if (d > tmp_d)
1050 		    productions = DAY_MAX - d + tmp_d;
1051 		  else
1052 		    productions = tmp_d - d;
1053 		  buf_d = d;
1054 		}
1055 	      productions++;
1056 	      is_first = FALSE;
1057 	    }
1058 	}
1059       else if (is_first)
1060 	{
1061 	  /*
1062 	     Single date given (means no list of days AND no range of days).
1063 	   */
1064 	  if (!y)
1065 	    manage_leap_day (&d, &m, year, line_buffer, filename,
1066 			     line_number);
1067 	  /*
1068 	     Let's decode the "repeat for N days since..." field of a line
1069 	     and/or the "for each N'th day since..." field of a line.
1070 	   */
1071 	  if (lptrs->repeat_part != (char *) NULL
1072 	      || lptrs->appears_part != (char *) NULL)
1073 	    {
1074 	      if (is_weekday_mode && !n)
1075 		/*
1076 		   Error, "repeat" or "appears" coding given to a
1077 		   simple weekday name (e.g.: YYYYMMWW[W]:10.3 ...).
1078 		 */
1079 		my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
1080 			  line_buffer, 0);
1081 	      if (lptrs->repeat_part != (char *) NULL)
1082 		{
1083 		  repeat = get_number (&lptrs->repeat_part);
1084 		  if (!repeat
1085 		      || (*lptrs->repeat_part
1086 			  && !isspace (*lptrs->repeat_part)
1087 			  && (*lptrs->repeat_part != RC_APPEARS_CHAR)))
1088 		    /*
1089 		       Error, invalid "repeat" field given.
1090 		     */
1091 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
1092 			      line_buffer, 0);
1093 		}
1094 	      if (lptrs->appears_part != (char *) NULL)
1095 		{
1096 		  appears = get_number (&lptrs->appears_part);
1097 		  if (!appears
1098 		      || (*lptrs->appears_part
1099 			  && !isspace (*lptrs->appears_part)
1100 			  && (*lptrs->appears_part != RC_REPEAT_CHAR)))
1101 		    /*
1102 		       Error, invalid "appears" field given.
1103 		     */
1104 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
1105 			      line_buffer, 0);
1106 		}
1107 	    }
1108 	  if (!repeat)
1109 	    /*
1110 	       Let's create either 1x1 or 1x2 productions of such a line by default.
1111 	     */
1112 	    productions = 1;
1113 	  else
1114 	    {
1115 	      /*
1116 	         Now we have the number of productions of this date!
1117 	       */
1118 	      is_first = FALSE;
1119 	      if (appears)
1120 		appears--;
1121 	      /*
1122 	         Well, we have to use an unoptimized number of productions
1123 	         in this case.
1124 	       */
1125 	      productions = repeat;
1126 	    }
1127 	}
1128       /*
1129          If the "date"-part of the current line is valid,
1130          try to respect the current line.
1131        */
1132       if (y >= 0)
1133 	{
1134 	  /*
1135 	     Necessary pre-initializations of module local variables.
1136 	   */
1137 	  is_valid_date = TRUE;
1138 	  is_2dvar = is_2easter = FALSE;
1139 	  incr_year = decr_year = d_buf = m_buf = 0;
1140 	  /*
1141 	     Default is a 1x1 production of a line
1142 	     (except some cases the `-c[]t' "tomorrow" flag is given).
1143 	   */
1144 	  print_twice = 1;
1145 	  if (!is_range)
1146 	    {
1147 	      if (d)
1148 		{
1149 		  /*
1150 		     If the special value "99" for a day is given,
1151 		     set the day to the last day of the month.
1152 		   */
1153 		  if (d == 99)
1154 		    {
1155 		      if (m)
1156 			{
1157 			  if (m == 2)
1158 			    d = days_of_february ((y) ? y : year);
1159 			  else
1160 			    d = dvec[m - 1];
1161 			}
1162 		      else
1163 			{
1164 			  if (month == 2)
1165 			    d = days_of_february ((y) ? y : year);
1166 			  else
1167 			    d = dvec[month - 1];
1168 			}
1169 		    }
1170 		  is_valid_date =
1171 		    valid_date (d, (m) ? m : month, (y) ? y : year);
1172 		}
1173 	      if (!is_valid_date)
1174 		{
1175 		  if ((!y
1176 		       && (((m == 2
1177 			     || (!m
1178 				 && (month == 2)))
1179 			    && (d == 29))
1180 			   || (!m
1181 			       && (d <= MONTH_LAST))))
1182 		      || (y && !m && (d <= MONTH_LAST)))
1183 		    /*
1184 		       If no month/year entry given, ignore that date.
1185 		     */
1186 		    ;
1187 		  else
1188 		    /*
1189 		       Invalid date field given.
1190 		     */
1191 		    my_error (ERR_INVALID_DATE_FIELD, filename, line_number,
1192 			      line_buffer, 0);
1193 		}
1194 	      /*
1195 	         If a "N'th weekday of month" field is given, compute the according date.
1196 	       */
1197 	      if (n)
1198 		{
1199 		  nth_weekday_of_month (&d, &m, &y, &n, &is_weekday_mode);
1200 		  if (!m)
1201 		    /*
1202 		       If the date is not computable (`m' is still 0), exit the loop.
1203 		     */
1204 		    break;
1205 		}
1206 	      else if (!y)
1207 		{
1208 		  if (hwd
1209 		      && ((fiscal_month > MONTH_MIN)
1210 			  || ((hc == RC_EASTER_CHAR)
1211 			      && (day < DAY_MIN
1212 				  || ed > DAY_LAST + is_leap_year + 1))))
1213 		    /*
1214 		       FIXME!
1215 		       Actually it's not possible to evaluate events, which
1216 		       occur in every year and are set to a "N'th weekday"
1217 		       displacement, and the mode of operation is generally
1218 		       for fiscal years or for weeks, which have left the
1219 		       bounds of the actual year and are related to the Easter
1220 		       Sundays date, because Easter Sunday is on one date in
1221 		       the current year and on another date in the other year!!
1222 		       Grrr... seems I've to rework this for future releases
1223 		       ...or will it be a feature???
1224 		     */
1225 		    y = SPECIAL_VALUE;
1226 		  else
1227 		    {
1228 		      /*
1229 		         If @e... Easter holiday "date"-part is given, compute the according date.
1230 		       */
1231 		      if (hc == RC_EASTER_CHAR)
1232 			{
1233 			  register int epy = knuth_easter_formula (year - 1);	/* Easter Sunday in previous year */
1234 			  register int eay = knuth_easter_formula (year);	/* Easter Sunday in current year */
1235 			  register int eny = knuth_easter_formula (year + 1);	/* Easter Sunday in next year */
1236 
1237 
1238 			  if (fiscal_month > MONTH_MIN)
1239 			    {
1240 			      /*
1241 			         Precalculate the number of days in last month of fiscal year.
1242 			       */
1243 			      if (fiscal_month - 1 == 2)
1244 				i = days_of_february (year + 1);
1245 			      else
1246 				i = dvec[fiscal_month - 2];
1247 			      /*
1248 			         Manage fiscal year request.
1249 			       */
1250 			      if (year == EASTER_MIN - 1)
1251 				{
1252 				  j =
1253 				    day_of_year (i, fiscal_month - 1,
1254 						 year + 1);
1255 				  if (hn + eny <= j)
1256 				    {
1257 				      if (!precomp_date
1258 					  (hn, hwd, &d, &m, year + 1, EAster))
1259 					y = SPECIAL_VALUE;
1260 				    }
1261 				  else
1262 				    y = SPECIAL_VALUE;
1263 				}
1264 			      else
1265 				{
1266 				  j =
1267 				    day_of_year (DAY_MIN, fiscal_month, year);
1268 				  if (hn + eay >= j)
1269 				    {
1270 				      if (!precomp_date
1271 					  (hn, hwd, &d, &m, year, EAster))
1272 					y = SPECIAL_VALUE;
1273 				      else
1274 					{
1275 					  /*
1276 					     Check whether this single event also occurs in the next year.
1277 					   */
1278 					  j =
1279 					    day_of_year (i, fiscal_month - 1,
1280 							 year + 1);
1281 					  if (!is_3month_mode
1282 					      && !is_3month_mode2
1283 					      && (hn + eny <= j))
1284 					    {
1285 					      /*
1286 					         We need a 1x2 production of the line.
1287 					       */
1288 					      print_twice++;
1289 					      is_2easter = TRUE;
1290 					    }
1291 					}
1292 				    }
1293 				  else
1294 				    {
1295 				      if (is_3month_mode || is_3month_mode2)
1296 					{
1297 					  if (fiscal_month >= MONTH_MAX - 1)
1298 					    {
1299 					      j = dvec[MONTH_MIN - 1];
1300 					      if (fiscal_month == MONTH_MAX)
1301 						j +=
1302 						  days_of_february (year +
1303 								    1) +
1304 						  is_leap_year;
1305 					      if (hn + eny <= j)
1306 						{
1307 						  if (!precomp_date
1308 						      (hn, hwd, &d, &m,
1309 						       year + 1, EAster))
1310 						    y = SPECIAL_VALUE;
1311 						}
1312 					      else
1313 						y = SPECIAL_VALUE;
1314 					    }
1315 					  else
1316 					    y = SPECIAL_VALUE;
1317 					}
1318 				      else
1319 					{
1320 					  j =
1321 					    day_of_year (i, fiscal_month - 1,
1322 							 year + 1);
1323 					  if (hn + eny <= j)
1324 					    {
1325 					      if (!precomp_date
1326 						  (hn, hwd, &d, &m, year + 1,
1327 						   EAster))
1328 						y = SPECIAL_VALUE;
1329 					    }
1330 					  else
1331 					    y = SPECIAL_VALUE;
1332 					}
1333 				    }
1334 				}
1335 			    }
1336 			  else
1337 			    /*
1338 			       Manage `-c0w' request resp.,
1339 			       `-cw' in case date is in first days of January.
1340 			     */
1341 			  if (day < DAY_MIN)
1342 			    {
1343 			      j =
1344 				DAY_LAST + (days_of_february (year - 1) ==
1345 					    29);
1346 			      if ((hn + epy >= j + day) && (hn + epy <= j))
1347 				{
1348 				  if (!precomp_date
1349 				      (hn, hwd, &d, &m, year - 1, EAster))
1350 				    y = SPECIAL_VALUE;
1351 				}
1352 			      else
1353 				{
1354 				  if (hn + eay < ed)
1355 				    {
1356 				      if (!precomp_date
1357 					  (hn, hwd, &d, &m, year, EAster))
1358 					y = SPECIAL_VALUE;
1359 				    }
1360 				  else
1361 				    y = SPECIAL_VALUE;
1362 				}
1363 			    }
1364 			  else
1365 			    /*
1366 			       Manage `-c99w' (`-c52w' | `-c53w') request resp.,
1367 			       `-ct' or `-cw' in case date is in last days of December.
1368 			     */
1369 			  if (ed > DAY_LAST + is_leap_year + 1)
1370 			    {
1371 			      j = DAY_LAST + is_leap_year;
1372 			      if ((hn + eay >= day) && (hn + eay <= j))
1373 				{
1374 				  if (!precomp_date
1375 				      (hn, hwd, &d, &m, year, EAster))
1376 				    y = SPECIAL_VALUE;
1377 				}
1378 			      else
1379 				{
1380 				  if (hn + eny < ed - j)
1381 				    {
1382 				      if (!precomp_date
1383 					  (hn, hwd, &d, &m, year + 1, EAster))
1384 					y = SPECIAL_VALUE;
1385 				    }
1386 				  else
1387 				    y = SPECIAL_VALUE;
1388 				}
1389 			    }
1390 			  else
1391 			    /*
1392 			       All other "ordinary" requests...
1393 			     */
1394 			  if (!precomp_date (hn, hwd, &d, &m, year, EAster))
1395 			    y = SPECIAL_VALUE;
1396 			}
1397 		      else
1398 			/*
1399 			   If @t|DVAR... "date"-part is given, compute the according date.
1400 			 */
1401 		      if (islower (hc))
1402 			{
1403 			  if (fiscal_month > MONTH_MIN)
1404 			    {
1405 			      register int date_dvar =
1406 				day_of_year (d, m, year);
1407 
1408 
1409 			      /*
1410 			         Precalculate number of days in the last month of fiscal year.
1411 			       */
1412 			      if (fiscal_month - 1 == 2)
1413 				i = days_of_february (year + 1);
1414 			      else
1415 				i = dvec[fiscal_month - 2];
1416 			      /*
1417 			         Manage fiscal year request.
1418 			       */
1419 			      j = day_of_year (DAY_MIN, fiscal_month, year);
1420 			      /*
1421 			         Buffer day and month.
1422 			       */
1423 			      d_buf = d;
1424 			      m_buf = m;
1425 			      if (hn + date_dvar >= j)
1426 				{
1427 				  if (!precomp_date (hn, hwd, &d, &m, year,
1428 						     (hc ==
1429 						      RC_TODAY_CHAR) ? TOday :
1430 						     DVar))
1431 				    y = SPECIAL_VALUE;
1432 				  else
1433 				    {
1434 				      /*
1435 				         Check whether this single event also occurs in next year.
1436 				       */
1437 				      j =
1438 					day_of_year (i, fiscal_month - 1,
1439 						     year + 1);
1440 				      if (!is_3month_mode && !is_3month_mode2
1441 					  && (hn + date_dvar <= j))
1442 					{
1443 					  /*
1444 					     We need a 1x2 production of the line.
1445 					   */
1446 					  print_twice++;
1447 					  is_2dvar = TRUE;
1448 					}
1449 				    }
1450 				}
1451 			      else
1452 				{
1453 				  if (is_3month_mode || is_3month_mode2)
1454 				    {
1455 				      if (fiscal_month >= MONTH_MAX - 1)
1456 					{
1457 					  j = dvec[MONTH_MIN - 1];
1458 					  if (fiscal_month == MONTH_MAX)
1459 					    j +=
1460 					      days_of_february (year + 1) +
1461 					      is_leap_year;
1462 					  if (hn + date_dvar <= j)
1463 					    {
1464 					      if (!precomp_date
1465 						  (hn, hwd, &d, &m, year + 1,
1466 						   (hc ==
1467 						    RC_TODAY_CHAR) ? TOday :
1468 						   DVar))
1469 						y = SPECIAL_VALUE;
1470 					    }
1471 					  else
1472 					    y = SPECIAL_VALUE;
1473 					}
1474 				      else
1475 					y = SPECIAL_VALUE;
1476 				    }
1477 				  else
1478 				    {
1479 				      j =
1480 					day_of_year (i, fiscal_month - 1,
1481 						     year + 1);
1482 				      if (hn + date_dvar <= j)
1483 					{
1484 					  if (!precomp_date
1485 					      (hn, hwd, &d, &m, year + 1,
1486 					       (hc ==
1487 						RC_TODAY_CHAR) ? TOday :
1488 					       DVar))
1489 					    y = SPECIAL_VALUE;
1490 					}
1491 				      else
1492 					y = SPECIAL_VALUE;
1493 				    }
1494 				}
1495 			    }
1496 			  else
1497 			    /*
1498 			       All other "ordinary" requests...
1499 			     */
1500 			  if (!precomp_date (hn, hwd, &d, &m, year,
1501 					       (hc ==
1502 						  RC_TODAY_CHAR) ? TOday :
1503 					       DVar))
1504 			    y = SPECIAL_VALUE;
1505 			}
1506 		      else
1507 			/*
1508 			   If a 0*d|wN[WW[W]] "date"-part is given, compute the according date.
1509 			 */
1510 		      if (hc == 'D' || hc == 'W')
1511 			{
1512 			  y = year;
1513 			  if (precomp_nth_wd (hn, hwd, &hn, &d, &m, &y,
1514 					      (hc == 'D') ? DAy : WEek))
1515 			    {
1516 			      register int date_dvar = day_of_year (d, m, y);
1517 
1518 
1519 			      if (fiscal_month > MONTH_MIN)
1520 				{
1521 				  /*
1522 				     Precalculate the number of days of the last month of fiscal year.
1523 				   */
1524 				  if (fiscal_month - 1 == 2)
1525 				    i = days_of_february (year + 1);
1526 				  else
1527 				    i = dvec[fiscal_month - 2];
1528 				  /*
1529 				     Manage fiscal year request.
1530 				   */
1531 				  j =
1532 				    day_of_year (DAY_MIN, fiscal_month, year);
1533 				  if (date_dvar >= j)
1534 				    {
1535 				      /*
1536 				         Check whether this single event also occurs in the next year
1537 				       */
1538 				      j =
1539 					day_of_year (i, fiscal_month - 1,
1540 						     year + 1);
1541 				      if (!is_3month_mode && !is_3month_mode2
1542 					  && (date_dvar <= j))
1543 					{
1544 					  /*
1545 					     Buffer day and month.
1546 					   */
1547 					  d_buf = d;
1548 					  m_buf = m;
1549 					  /*
1550 					     We need a 1x2 production of the line.
1551 					   */
1552 					  print_twice++;
1553 					  is_2dvar = TRUE;
1554 					}
1555 				    }
1556 				  else
1557 				    {
1558 				      if (is_3month_mode || is_3month_mode2)
1559 					{
1560 					  if (fiscal_month >= MONTH_MAX - 1)
1561 					    {
1562 					      j = dvec[MONTH_MIN - 1];
1563 					      if (fiscal_month == MONTH_MAX)
1564 						j +=
1565 						  days_of_february (year +
1566 								    1) +
1567 						  is_leap_year;
1568 					      if (date_dvar <= j)
1569 						{
1570 						  y++;
1571 						  (void) precomp_nth_wd (hn,
1572 									 hwd,
1573 									 &hn,
1574 									 &d,
1575 									 &m,
1576 									 &y,
1577 									 (hc
1578 									  ==
1579 									  'D')
1580 									 ? DAy
1581 									 :
1582 									 WEek);
1583 						}
1584 					      else
1585 						y = SPECIAL_VALUE;
1586 					    }
1587 					  else
1588 					    y = SPECIAL_VALUE;
1589 					}
1590 				      else
1591 					{
1592 					  j =
1593 					    day_of_year (i, fiscal_month - 1,
1594 							 year + 1);
1595 					  if (date_dvar <= j)
1596 					    {
1597 					      y++;
1598 					      (void) precomp_nth_wd (hn, hwd,
1599 								     &hn, &d,
1600 								     &m, &y,
1601 								     (hc ==
1602 								      'D') ?
1603 								     DAy :
1604 								     WEek);
1605 					    }
1606 					  else
1607 					    y = SPECIAL_VALUE;
1608 					}
1609 				    }
1610 				}
1611 			    }
1612 			}
1613 		    }
1614 		}
1615 	    }
1616 	  /*
1617 	     Check whether this current line must be displayed.
1618 	   */
1619 	  if (y >= 0)
1620 	    {
1621 	      if (!is_range && (repeat > 1))
1622 		is_range = TRUE;
1623 	      if (date_matches_period (&print_twice, day, ed, wd))
1624 		/*
1625 		   Now insert this current line into `rc_elems_table[]'
1626 		   (lines with no "text"-part are valid and are displayed).
1627 		 */
1628 		insert_line_into_table (line_buffer, filename, line_number,
1629 					rc_elems, len_date, print_twice);
1630 	    }
1631 	}
1632       /*
1633          We have to restore some elements of the date and
1634          to precompute the next date if a range of days is given!
1635        */
1636       if (lineptrs->day_range || repeat)
1637 	{
1638 	  if (is_range)
1639 	    {
1640 	      if (m)
1641 		{
1642 		  if (y <= 0)
1643 		    y = year;
1644 		  if (appears)
1645 		    {
1646 		      /*
1647 		         Advance to the next date in period if an "appears" coding is given.
1648 		       */
1649 		      i = day_of_year (d, m, y);
1650 		      (void) doy2date (i + appears + 1,
1651 				       (days_of_february (y) == 29), &d, &m);
1652 		      productions -= appears;
1653 		    }
1654 		  else
1655 		    (void) next_date (&d, &m, &y);
1656 		  /*
1657 		     If we evaluate a list of days and found "repeat" or "appears" fields
1658 		     in it and made all necessary productions, we must manage this
1659 		     explicitly by setting `is_range' to FALSE and `productions'
1660 		     to any value greater 1, otherwise the next element of the
1661 		     list would not be managed!
1662 		   */
1663 		  if (lineptrs->day_list
1664 		      && (productions <= 1)
1665 		      && (lptrs->day_part != (char *) NULL))
1666 		    {
1667 		      productions = 2;
1668 		      is_range = FALSE;
1669 		    }
1670 		}
1671 	      else
1672 		/*
1673 		   Such a date is not computable.
1674 		 */
1675 	      if (lineptrs->day_list)
1676 		{
1677 		  /*
1678 		     The list of days still contains elements.
1679 		   */
1680 		  if (lptrs->day_part != (char *) NULL)
1681 		    {
1682 		      productions = 2;
1683 		      is_range = FALSE;
1684 		    }
1685 		  else
1686 		    /*
1687 		       We are at the end of a list of days.
1688 		     */
1689 		    break;
1690 		}
1691 	    }
1692 	  else
1693 	    {
1694 	      if (appears)
1695 		{
1696 		  /*
1697 		     Advance to the next date in period if an "appears" coding is given.
1698 		   */
1699 		  productions -= appears;
1700 		  if (productions > 0)
1701 		    for (i = 0; i <= appears; i++)
1702 		      if (++buf_d > DAY_MAX)
1703 			buf_d = DAY_MIN;
1704 		}
1705 	      else if (++buf_d > DAY_MAX)
1706 		buf_d = DAY_MIN;
1707 	      d = buf_d;
1708 	      m = buf_m;
1709 	      y = buf_y;
1710 	    }
1711 	}
1712       else if (lineptrs->day_list && (lptrs->day_part == (char *) NULL))
1713 	/*
1714 	   We have already managed the last element of a list of days.
1715 	 */
1716 	break;
1717     }
1718   while (--productions > 0);
1719   month = tmp_month;
1720   if (lineptrs->repeat_part != (char *) NULL)
1721     free (lineptrs->repeat_part);
1722   if (lineptrs->appears_part != (char *) NULL)
1723     free (lineptrs->appears_part);
1724 }
1725 
1726 
1727 
1728 static Bool
date_matches_period(print_twice,day,ed,wd)1729 date_matches_period (print_twice, day, ed, wd)
1730      int *print_twice;
1731      int day;
1732      int ed;
1733      const int wd;
1734 /*!
1735    Checks if a given date (module global variables `d' for the day, `m' for
1736      the month and `y' for the year) matches a given period, which starts at
1737      absolute day of year `day' and ends at absolute day of year `ed' (the
1738      actual weekday is given in `wd').  If the given date matches the
1739      specified period, return TRUE, otherwise FALSE.
1740 */
1741 {
1742   register int i;
1743   register int j;
1744   auto int dd;
1745   auto int mm;
1746   auto int yy;
1747   auto Bool print_line = FALSE;
1748   auto Bool is_valid_date = TRUE;
1749 
1750 
1751   if (is_date_given
1752       || ((year != act_year)
1753 	  && (day > 0))
1754       || ((month && (month != act_month)) && (year == act_year)))
1755     {
1756       /*
1757          NOT in simple month-/year mode (an explicit date is given in command line):
1758          Manage `-c[]' arguments.
1759        */
1760       if (d && !is_weekday_mode)
1761 	{
1762 	  incr_year = ((fiscal_month > MONTH_MIN)
1763 		       && (m < fiscal_month) && (!y || y == year + 1));
1764 	  if (is_date_given && month && !changed_month && !m)
1765 	    {
1766 	      m = month;
1767 	      is_valid_date = valid_date (d, m, (y) ? y : year);
1768 	    }
1769 	  if (is_valid_date && (!y || y - incr_year == year) && m && d)
1770 	    {
1771 	      if (month && !changed_month)
1772 		{
1773 		  if (m == month)
1774 		    {
1775 		      if (!is_leap_year && (m == 2) && (d == 29))
1776 			;	/* If the year is no leap year, ignore that date */
1777 		      else
1778 			print_line = TRUE;
1779 		    }
1780 		}
1781 	      else
1782 		{
1783 		  if (fiscal_month > MONTH_MIN)
1784 		    {
1785 		      /*
1786 		         Respect fiscal years!
1787 		       */
1788 		      if ((incr_year
1789 			   && (year < YEAR_MAX))
1790 			  || ((m >= fiscal_month) && (!y || y == year)))
1791 			{
1792 			  if ((days_of_february (year + incr_year) == 28)
1793 			      && (m == 2) && (d == 29))
1794 			    ;	/* If the year is no leap year, ignore that date */
1795 			  else
1796 			    print_line = TRUE;
1797 			}
1798 		    }
1799 		  else
1800 		    /*
1801 		       Respect non fiscal years!
1802 		     */
1803 		  if (!is_leap_year && (m == 2) && (d == 29))
1804 		    ;		/* If the year is no leap year, ignore that date */
1805 		  else
1806 		    print_line = TRUE;
1807 		}
1808 	    }
1809 	}
1810     }
1811   else
1812     {
1813       /*
1814          Simple month-/year mode (NO explicit date is given in command line):
1815          Manage `-c[]w|m|y[+|-]' arguments.
1816        */
1817       if ((rc_period_flag
1818 	   || rc_week_flag
1819 	   || rc_month_flag
1820 	   || rc_year_flag)
1821 	  && !is_date_given
1822 	  && (!y
1823 	      || y == year
1824 	      || (rc_week_flag
1825 		  && (((year + 1 <= YEAR_MAX)
1826 		       && (ed > DAY_LAST + is_leap_year + 1))
1827 		      || ((year - 1 >= YEAR_MIN) && (day < DAY_MIN))))))
1828 	{
1829 	  register int td;
1830 
1831 
1832 	  if (m && d)
1833 	    {
1834 	      if (rc_week_flag && !y && (m != month))
1835 		{
1836 		  if ((ed > DAY_LAST + is_leap_year + 1)
1837 		      && !adate_set
1838 		      && (rc_forwards_flag
1839 			  || (!rc_forwards_flag && !rc_backwards_flag)))
1840 		    y = year + 1;
1841 		  else
1842 		    if ((day < DAY_MIN)
1843 			&& !adate_set
1844 			&& (rc_backwards_flag
1845 			    || (!rc_forwards_flag && !rc_backwards_flag)))
1846 		    y = year - 1;
1847 		}
1848 	      if (y < YEAR_MIN || y > YEAR_MAX)
1849 		{
1850 		  if (adate_set)
1851 		    {
1852 		      if (m == month)
1853 			{
1854 			  if (day < DAY_MIN)
1855 			    y = year - 1;
1856 			}
1857 		      else
1858 			{
1859 			  if (ed > DAY_LAST + is_leap_year + 1)
1860 			    y = year + 1;
1861 			}
1862 		      if (y < YEAR_MIN || y > YEAR_MAX)
1863 			y = year;
1864 		    }
1865 		  else
1866 		    y = year;
1867 		}
1868 	    }
1869 	  if ((rc_week_flag
1870 	       && is_weekday_mode) || (!is_weekday_mode && (y || m || d)))
1871 	    {
1872 	      /*
1873 	         Respect short day name entry YYYYMMWW[W] ... (WW[W]==short dayname).
1874 	       */
1875 	      if (rc_week_flag && is_weekday_mode)
1876 		{
1877 		  static struct
1878 		  {
1879 		    char day[DAY_MAX];
1880 		    char dst[DAY_MAX];
1881 		  } wday_list;
1882 		  static Bool fill_wday_list = FALSE;
1883 
1884 
1885 		  j = 0;
1886 		  if (!fill_wday_list)
1887 		    {
1888 		      if (rc_forwards_flag
1889 			  || (!rc_forwards_flag && !rc_backwards_flag))
1890 			{
1891 			  i = wd;
1892 			  LOOP
1893 			  {
1894 			    wday_list.day[i - 1] = (char) i;
1895 			    wday_list.dst[i - 1] = (char) j++;
1896 			    i++;
1897 			    if (i > DAY_MAX)
1898 			      i = DAY_MIN;
1899 			    if (i == start_day)
1900 			      break;
1901 			  }
1902 			}
1903 		      j = 0;
1904 		      if (rc_backwards_flag
1905 			  || (!rc_forwards_flag && !rc_backwards_flag))
1906 			{
1907 			  i = wd;
1908 			  LOOP
1909 			  {
1910 			    if (i < DAY_MIN)
1911 			      i = DAY_MAX;
1912 			    wday_list.day[i - 1] = (char) i;
1913 			    wday_list.dst[i - 1] = (char) ++j;
1914 			    if (i == start_day)
1915 			      break;
1916 			    i--;
1917 			  }
1918 			}
1919 		      fill_wday_list = TRUE;
1920 		    }
1921 		  if (wday_list.day[d - 1])
1922 		    {
1923 		      yy = year;
1924 		      if (rc_week_year_flag)
1925 			{
1926 			  j = day;
1927 			  if (day < 1)
1928 			    {
1929 			      yy = year - 1;
1930 			      j += (DAY_LAST + (days_of_february (yy) == 29));
1931 			    }
1932 			  (void) doy2date (j, (days_of_february (yy) == 29),
1933 					   &dd, &mm);
1934 			}
1935 		      else
1936 			{
1937 			  dd = act_day;
1938 			  mm = month;
1939 			}
1940 		      if (rc_forwards_flag)
1941 			for (i = 0; i < wday_list.dst[d - 1]; i++)
1942 			  (void) next_date (&dd, &mm, &yy);
1943 		      else if (rc_backwards_flag)
1944 			for (i = 1; i < wday_list.dst[d - 1]; i++)
1945 			  (void) prev_date (&dd, &mm, &yy);
1946 		      else
1947 			{
1948 			  i = SYEAR (d, start_day);
1949 			  j = SYEAR (wd, start_day);
1950 			  if (i - j <= 0)
1951 			    for (i = 1; i < wday_list.dst[d - 1]; i++)
1952 			      (void) prev_date (&dd, &mm, &yy);
1953 			  else
1954 			    for (i = 0; i < wday_list.dst[d - 1]; i++)
1955 			      (void) next_date (&dd, &mm, &yy);
1956 			}
1957 		      if ((!m || m == mm) && (!y || y == yy))
1958 			{
1959 			  d = dd;
1960 			  m = mm;
1961 			  y = yy;
1962 			}
1963 		      else
1964 			y = SPECIAL_VALUE;
1965 		    }
1966 		  else
1967 		    y = SPECIAL_VALUE;
1968 		}
1969 	      if (rc_week_flag
1970 		  && (y >= 0)
1971 		  && (day < DAY_MIN || ed > DAY_LAST + is_leap_year + 1))
1972 		{
1973 		  if ((rc_backwards_flag
1974 		       || (!rc_forwards_flag
1975 			   && !rc_backwards_flag))
1976 		      && (y == year - 1) && m && d)
1977 		    {
1978 		      ed = DAY_LAST + (days_of_february (y) == 29);
1979 		      day = ed + day;
1980 		      td = day_of_year (d, m, y);
1981 		      if ((td <= ed) && (td >= day))
1982 			{
1983 			  decr_year = 1;
1984 			  print_line = TRUE;
1985 			}
1986 		    }
1987 		  else
1988 		    if ((rc_forwards_flag
1989 			 || (!rc_forwards_flag
1990 			     && !rc_backwards_flag))
1991 			&& (y == year + 1) && m && d)
1992 		    {
1993 		      td = day_of_year (d, m, y) + DAY_LAST + is_leap_year;
1994 		      if ((td < ed) && (td >= day))
1995 			{
1996 			  incr_year = 1;
1997 			  print_line = TRUE;
1998 			}
1999 		    }
2000 		  else
2001 		    {
2002 		      if ((y == year
2003 			   || ((y == year - 1)
2004 			       && !rc_forwards_flag)
2005 			   || ((y == year + 1)
2006 			       && !rc_backwards_flag)) && m && d)
2007 			{
2008 			  td = day_of_year (d, m, y);
2009 			  if ((td < ed) && (td >= day))
2010 			    print_line = TRUE;
2011 			}
2012 		      else if (d)
2013 			{
2014 			  td = 0;
2015 			  m = month;
2016 			  if (day < DAY_MIN)
2017 			    {
2018 			      if (!y || y == year || y == year - 1)
2019 				{
2020 				  if (adate_set)
2021 				    i = dvec[MONTH_MAX - 1] + day - 1;
2022 				  else
2023 				    i =
2024 				      dvec[MONTH_MAX - 1] + act_day -
2025 				      (SYEAR (wd, start_day));
2026 				  if (d > i)
2027 				    {
2028 				      m = MONTH_MAX;
2029 				      if (!y)
2030 					y = year - 1;
2031 				      if (y == year)
2032 					td = day_of_year (d, m, year);
2033 				      else
2034 					{
2035 					  ed =
2036 					    DAY_LAST +
2037 					    (days_of_february (y) == 29);
2038 					  day = ed + day;
2039 					  td = day_of_year (d, m, y);
2040 					  decr_year = 1;
2041 					}
2042 				    }
2043 				  else if (!y || y == year)
2044 				    {
2045 				      if (adate_set)
2046 					{
2047 					  m = MONTH_MIN;
2048 					  td = day_of_year (d, m, year) + 1;
2049 					}
2050 				      else
2051 					td = day_of_year (d, m, year) + 1;
2052 				    }
2053 				  else
2054 				    td = ed + 1;
2055 				  if ((td <= ed) && (td >= day))
2056 				    print_line = TRUE;
2057 				}
2058 			    }
2059 			  else if (!y || y == year || y == year + 1)
2060 			    {
2061 			      i = act_day - (SYEAR (wd, start_day));
2062 			      if (d < i)
2063 				{
2064 				  m = MONTH_MIN;
2065 				  if (!y)
2066 				    y = year + 1;
2067 				  if (y == year + 1)
2068 				    {
2069 				      td =
2070 					day_of_year (d, m,
2071 						     y) + DAY_LAST +
2072 					is_leap_year;
2073 				      incr_year = 1;
2074 				    }
2075 				}
2076 			      else if (!y || y == year)
2077 				td = day_of_year (d, m, year);
2078 			      if ((td < ed) && (td >= day))
2079 				print_line = TRUE;
2080 			    }
2081 			}
2082 		    }
2083 		}
2084 	      else if (y >= 0 || y == year)
2085 		{
2086 		  if (((rc_month_flag
2087 			|| rc_week_flag
2088 			|| rc_period_flag)
2089 		       && m
2090 		       && !d)
2091 		      || ((rc_month_flag
2092 			   || rc_week_flag)
2093 			  && !m
2094 			  && !d)
2095 		      || ((rc_year_flag || rc_period_list) && (!m || !d)))
2096 		    ;		/* Void, ignore such entries! */
2097 		  else
2098 		    {
2099 		      register int mmm = m;
2100 
2101 
2102 		      if (!y)
2103 			y = year;
2104 		      if (!m)
2105 			{
2106 			  mmm = m = month;
2107 			  (void) doy2date (day, is_leap_year, &dd, &mm);
2108 			  if ((dd > d) && (mm == m))
2109 			    m++;
2110 			  else if ((dd < d) && (mm < m))
2111 			    m--;
2112 			}
2113 		      /*
2114 		         If a valid date is given, respect it.
2115 		       */
2116 		      if (valid_date (d, m, y))
2117 			{
2118 			  td = day_of_year (d, m, y);
2119 			  if ((td >= day) && (td < ed))
2120 			    print_line = TRUE;
2121 			  else
2122 			    m = mmm;
2123 			}
2124 		      else
2125 			m = mmm;
2126 		    }
2127 		}
2128 	    }
2129 	}
2130       else
2131 	if (!rc_period_flag
2132 	    && !rc_week_flag && !rc_month_flag && !rc_year_flag)
2133 	{
2134 	  /*
2135 	     Simple month-/year month mode (NO explicit date is given in command line):
2136 	     Manage `-c[]' or `-c[]t' arguments.
2137 	   */
2138 	  dd = act_day;
2139 	  mm = month;
2140 	  yy = year;
2141 	  if (rc_tomorrow_flag)
2142 	    (void) next_date (&dd, &mm, &yy);
2143 	  if ((!y
2144 	       || y == year
2145 	       || (rc_tomorrow_flag
2146 		   && (ed > DAY_LAST + is_leap_year + 1)
2147 		   && (y == year + 1)
2148 		   && (!m
2149 		       || m == mm)))
2150 	      && (!m
2151 		  || m == month
2152 		  || (rc_tomorrow_flag
2153 		      && (m == mm)
2154 		      && (!y
2155 			  || ((ed > DAY_LAST + is_leap_year + 1)
2156 			      && (y == year + 1))
2157 			  || ((ed <= DAY_LAST + is_leap_year + 1)
2158 			      && (y == year))))))
2159 	    {
2160 	      if (is_weekday_mode)
2161 		{
2162 		  /*
2163 		     Respect short day name entry YYYYMMWW[W] ... (WW[W]==short dayname).
2164 		   */
2165 		  i = weekday_of_date (act_day, month, year);
2166 		  j = 0;
2167 		  if (rc_tomorrow_flag)
2168 		    j = (d == weekday_of_date (dd, mm, yy));
2169 		  if (((d == i)
2170 		       && (ed <= DAY_LAST + is_leap_year + 1)
2171 		       && (!m
2172 			   || m == month))
2173 		      || ((d == i)
2174 			  && ((ed > DAY_LAST + is_leap_year + 1)
2175 			      && ((!y
2176 				   && (!m
2177 				       || m == month))
2178 				  || y == year)))
2179 		      || (j
2180 			  && (!m
2181 			      || m == month + 1
2182 			      || m == mm)
2183 			  && (!y
2184 			      || ((ed > DAY_LAST + is_leap_year + 1)
2185 				  && (y == year + 1))
2186 			      || ((ed <= DAY_LAST + is_leap_year + 1)
2187 				  && (y == year)))))
2188 		    {
2189 		      if (j)
2190 			{
2191 			  m = mm;
2192 			  d = dd;
2193 			  if (rc_tomorrow_flag && (yy != year))
2194 			    incr_year = 1;
2195 			}
2196 		      else
2197 			{
2198 			  m = month;
2199 			  d = act_day;
2200 			}
2201 		      if (rc_tomorrow_flag
2202 			  && !rc_have_today_in_list && (d != dd))
2203 			;	/* Void, ignore such entries! */
2204 		      else
2205 			print_line = TRUE;
2206 		    }
2207 		}
2208 	      else
2209 		if (!d
2210 		    || ((d == act_day)
2211 			&& (!m
2212 			    || m == month)
2213 			&& (!y
2214 			    || y == year))
2215 		    || ((d == dd)
2216 			&& (mm == month
2217 			    || (rc_tomorrow_flag
2218 				&& ((!m
2219 				     && (ed <= DAY_LAST + is_leap_year + 1)
2220 				     && (!y
2221 					 || y == year))
2222 				    || m == month + 1 || m == mm)))))
2223 		{
2224 		  if (rc_tomorrow_flag)
2225 		    {
2226 		      if (!d
2227 			  && (!m
2228 			      || (mm == month || m == month + 1 || m == mm)))
2229 			{
2230 			  if ((yy > year) && (d || m || y))
2231 			    {
2232 			      if (!y || y == yy)
2233 				{
2234 				  m = mm;
2235 				  d = dd;
2236 				  incr_year = 1;
2237 				}
2238 			    }
2239 			  else
2240 			    if (m
2241 				|| y != year
2242 				|| ed <= DAY_LAST + is_leap_year + 1)
2243 			    {
2244 			      if (!d
2245 				  && m && (mm != month) && (!y || y == year))
2246 				{
2247 				  m = mm;
2248 				  d = dd;
2249 				}
2250 			      else
2251 				{
2252 				  if (rc_have_today_in_list)
2253 				    /*
2254 				       We need a 1x2 production of the line.
2255 				     */
2256 				    (*print_twice)++;
2257 				  else
2258 				    {
2259 				      m = mm;
2260 				      d = dd;
2261 				      if (yy != year)
2262 					incr_year = 1;
2263 				    }
2264 				}
2265 			    }
2266 			}
2267 		      else
2268 			{
2269 			  if ((d == dd) && (!m || m == mm))
2270 			    {
2271 			      m = mm;
2272 			      if (ed > DAY_LAST + is_leap_year + 1)
2273 				incr_year = 1;
2274 			    }
2275 			}
2276 		    }
2277 		  if (!m)
2278 		    m = month;
2279 		  if (!d)
2280 		    d = act_day;
2281 		  if (rc_tomorrow_flag && !rc_have_today_in_list && (d != dd))
2282 		    ;		/* Void, ignore such entries! */
2283 		  else
2284 		    print_line = TRUE;
2285 		}
2286 	    }
2287 	}
2288     }
2289   /*
2290      Avoid an incorrect assignment in case fixed date mentioned occurred
2291      during the missing period in month of Gregorian Reformation.
2292    */
2293   if (print_line
2294       && (year + incr_year - decr_year == greg->year)
2295       && (m == greg->month)
2296       && ((d >= greg->first_day) && (d <= greg->last_day)))
2297     print_line = FALSE;
2298   /*
2299      If 3-month mode is wanted, insert only those fixed dates
2300      which occur in that period.
2301    */
2302   if (print_line && (is_3month_mode || is_3month_mode2))
2303     {
2304       register int m2 = fiscal_month + 1;
2305       register int m3 = fiscal_month + 2;
2306 
2307 
2308       if (fiscal_month >= MONTH_MAX - 1)
2309 	{
2310 	  m3 = MONTH_MIN;
2311 	  if (fiscal_month == MONTH_MAX)
2312 	    {
2313 	      m2 = MONTH_MIN;
2314 	      m3++;
2315 	    }
2316 	}
2317       if ((m != fiscal_month) && (m != m2) && (m != m3))
2318 	print_line = FALSE;
2319     }
2320 
2321   return (print_line);
2322 }
2323 
2324 
2325 
2326 static int
get_number(string)2327 get_number (string)
2328      char **string;
2329 /*!
2330    Returns the absolute value of a "repeat for N days since..." field or
2331      "for each N'th day since..." field using the global `s6' text buffer.
2332 */
2333 {
2334   register int i = 0;
2335 
2336 
2337   if (*string != (char *) NULL)
2338     {
2339       (*string)++;
2340       while (isdigit (**string))
2341 	s6[i++] = *((*string)++);
2342       s6[i] = '\0';
2343       /*
2344          Make sure we return values in range 1...366
2345          or 0 if an error has occurred.
2346        */
2347       if (i > 3)
2348 	return (0);
2349       i = atoi (s6);
2350       if (i > DAY_LAST + 1)
2351 	i = DAY_LAST + 1;
2352     }
2353 
2354   return (i);
2355 }
2356 #endif /* USE_RC */
2357