/*
*  gcal_rc.c:  Pool of special functions necessary for managing the fixed dates.
*
*
*  Copyright (C) 1994, 1995, 1996 Thomas Esken
*
*  This software doesn't claim completeness, correctness or usability.
*  On principle I will not be liable for ANY damages or losses (implicit
*  or explicit), which result from using or handling my software.
*  If you use this software, you agree without any exception to this
*  agreement, which binds you LEGALLY !!
*
*  This program is free software; you can redistribute it and/or modify
*  it under the terms of the `GNU General Public License' as published by
*  the `Free Software Foundation'; either version 2, or (at your option)
*  any later version.
*
*  You should have received a copy of the `GNU General Public License'
*  along with this program; if not, write to the:
*
*    Free Software Foundation, Inc.
*    59 Temple Place - Suite 330
*    Boston, MA 02111-1307,  USA
*/



/*
*  Include definition header file to see whether USE_RC is defined there.
*    Compile this module only if USE_RC is defined, otherwise skip it.
*/
#include "gcal_tai.h"



#if USE_RC
#  ifdef RCSID
static char rcsid[]="$Id: gcal_rc.c 2.01 1996/06/06 02:00:01 tom Exp $";
#  endif



/*
*  Include header files.
*/
#  if HAVE_CTYPE_H
#    include <ctype.h>
#  endif
#  include "gcal.h"



/*
*  Function prototypes.
*/
#  if __cplusplus
extern "C"
{
#  endif
/*
************************************************** Defined in `gcal_hdy.c'.
*/
IMPORT int
eval_holiday __P_((      int  day,
                   const int  month,
                   const int  year,
                   const int  wd,
                   const Bool forwards));
/*
************************************************** Defined in `gcal_tty.c'.
*/
IMPORT void
print_text __P_((FILE *fp,
                 char *text_line));
/*
************************************************** Defined in `gcal_utl.c'.
*/
IMPORT VOID_PTR
my_malloc __P_((const int   amount,
                const int   exit_status,
                const char *module_name,
                const long  module_line,
                const char *var_name,
                const int   var_contents));
IMPORT VOID_PTR
my_realloc __P_((      VOID_PTR  ptr_memblock,
                 const int       amount,
                 const int       exit_status,
                 const char     *module_name,
                 const long      module_line,
                 const char     *var_name,
                 const int       var_contents));
IMPORT void
resize_all_strings __P_((const int   amount,
                         const char *module_name,
                         const long  module_line));
IMPORT void
my_error __P_((const int   exit_status,
               const char *module_name,
               const long  module_line,
               const char *var_name,
               const int   var_contents));
IMPORT int
my_atoi __P_((const char *s));
IMPORT int
compare_d_m_name __P_((const char       *s,
                       const Cmode_enum  mode));
IMPORT const char *
month_name __P_((const int month));
IMPORT Ulint
date2num __P_((const int day,
               const int month,
               const int year));
IMPORT Bool
doy2date __P_((      int  doy,
               const int  is_leap_year,
                     int *day,
                     int *month));
IMPORT int
weekday_of_date __P_((const int day,
                      const int month,
                      const int year));
IMPORT int
day_of_year __P_((const int day,
                  const int month,
                  const int year));
IMPORT int
days_of_february __P_((const int year));
IMPORT Bool
valid_date __P_((const int day,
                 const int month,
                 const int year));
IMPORT int
weekno2doy __P_((      int week,
                 const int year));
IMPORT int
knuth_easter_formula __P_((const int year));
/*
************************************************** Defined in `gcal_rc.c'.
*/
EXPORT void
rc_clean_flags __P_((void));
EXPORT Line_struct *
rc_get_date __P_((      char        *the_line,
                        Line_struct *lineptrs,
                  const Bool         is_rc_file,
                        Bool        *is_weekday_mode,
                        int         *d,
                        int         *m,
                        int         *y,
                        int         *n,
                        int         *len,
                        char        *hc,
                        int         *hn,
                        int         *hwd,
                  const char        *filename,
                  const long         line_number,
                  const char        *line_buffer,
                  const Bool         on_error_exit));
EXPORT Bool
precomp_nth_wd __P_((      int         diff,
                     const int         wd,
                           int        *n,
                           int        *day,
                           int        *month,
                           int        *year,
                     const Cmode_enum  mode));
EXPORT Bool
precomp_date __P_((      int         diff,
                   const int         wd,
                         int        *day,
                         int        *month,
                   const int         year,
                   const Cmode_enum  mode));
EXPORT Bool
set_dvar __P_((const char      *line_buffer,
               const char      *filename,
               const long       line_number,
               const Dvar_enum  mode));
EXPORT Bool
set_tvar __P_((const char      *line_buffer,
               const Tvar_enum  mode));
EXPORT void
nth_weekday_of_month __P_((      int  *d,
                                 int  *m,
                                 int  *y,
                           const int  *n,
                                 Bool *is_weekday_mode));
EXPORT void
prev_date __P_((int *day,
                int *month,
                int *year));
EXPORT void
next_date __P_((int *day,
                int *month,
                int *year));
EXPORT void
num2date __P_((Ulint  julian_days,
               int   *day,
               int   *month,
               int   *year));
EXPORT Slint
d_between __P_((const int d1,
                const int m1,
                const int y1,
                const int d2,
                const int m2,
                const int y2));
EXPORT Slint
w_between __P_((const int d1,
                const int m1,
                const int y1,
                const int d2,
                const int m2,
                const int y2));
EXPORT Slint
m_between __P_((const int m1,
                const int y1,
                const int m2,
                const int y2));
EXPORT void
manage_leap_day __P_((      int  *day,
                            int  *month,
                            int   year,
                      const char *line_buffer,
                      const char *filename,
                      const long  line_number));
LOCAL void
dvar_warning __P_((const int   exit_status,
                   const char  dvar,
                   const char *filename,
                   const long  line_number,
                   const char *text));
#  if __cplusplus
}
#  endif



/*
*  Declare public(extern) variables.
*/
IMPORT const int    dvec[];                 /* Amount of days in months */
IMPORT const int    mvec[];                 /* Number of past days of month */
IMPORT Greg_struct *greg;                   /* Points to the used Gregorian Reformation date */
IMPORT Dvar_struct  rc_dvar[];              /* Date variables a[=`mmdd']...z[] (`yyyy'@{a|b|...|z}[[-]<n>]) */
IMPORT Tvar_struct  rc_tvar[];              /* Text variables $a[=TEXT]...$z[] */
IMPORT Line_struct *lineptrs;               /* Pointers to different parts of a (resource file) line */
IMPORT Uint         maxlen_max;             /* Actual size of all string vectors */
IMPORT int          len_year_max;           /* String length of the maximum year able to compute */
IMPORT int          warning_level;          /* --debug[=0...WARN_LVL_MAX] */
IMPORT int          start_day;              /* -s<0,1...7|day name> */
IMPORT int          day;                    /* Current day */
IMPORT int          month;                  /* Current month */
IMPORT int          year;                   /* Current year */
IMPORT int          fiscal_month;           /* Starting month of a fiscal year */
IMPORT int          is_leap_year;           /* Is current year a leap year? */
IMPORT char        *s5;                     /* General purpose text buffer */
IMPORT Bool         rc_period_flag;         /* [-c]<<<<n>>[<d|w|+|-]>|`mmdd'|`mmww[w]'<n>> */
IMPORT Bool         rc_period_list;         /* [-c]l */
IMPORT Bool         rc_tomorrow_flag;       /* [-c]t */
IMPORT Bool         rc_week_flag;           /* [-c]w */
IMPORT Bool         rc_month_flag;          /* [-c]m */
IMPORT Bool         rc_year_flag;           /* [-c]y */
IMPORT Bool         rc_week_year_flag;      /* [-c<<n>>]w */
IMPORT Bool         rc_forwards_flag;       /* [-c<<n>|w|m|y>]+ */
IMPORT Bool         rc_backwards_flag;      /* [-c<<n>|w|m|y>]- */
IMPORT Bool         rc_feb_29_to_feb_28;    /* `--leap-day=february' given */
IMPORT Bool         rc_feb_29_to_mar_01;    /* `--leap-day=march' given */
IMPORT Bool         is_3month_mode;         /* Argument is `.' or `.+' or `.-' */
IMPORT Bool         is_3month_mode2;        /* Argument is `..' -> current quarter of actual year */
IMPORT Bool         adate_set;              /* [-c]<n>w and actual date modified */



   PUBLIC void
rc_clean_flags ()
/*
   Clean all global flags (except `rc_period_list'),
     which are related to the fixed date warning period.
*/
{
   rc_tomorrow_flag=rc_week_flag=rc_month_flag=rc_year_flag
   =rc_week_year_flag=rc_forwards_flag=rc_backwards_flag=rc_period_flag = FALSE;
}



   PUBLIC Line_struct *
rc_get_date (the_line, lineptrs, is_rc_file, is_weekday_mode, d, m, y, n, len, hc, hn, hwd,
             filename, line_number, line_buffer, on_error_exit)
         char        *the_line;
         Line_struct *lineptrs;
   const Bool         is_rc_file;
         Bool        *is_weekday_mode;
         int         *d;
         int         *m;
         int         *y;
         int         *n;
         int         *len;
         char        *hc;
         int         *hn;
         int         *hwd;
   const char        *filename;
   const long         line_number;
   const char        *line_buffer;
   const Bool         on_error_exit;
/*
   Converts the textual/string `date' of a RC-file line to a numerical date
     and returns a pointer struct to the "day"-part and the "text"-part of the
     line indicating whether the "day"-part contains a list or a range of days;
     a char pointer to the "repeat"-field and to the "appears"-field if these
     exists, and/or if a @... or *... day is encoded in "date"-part and year
     is set to zero in the line, then this function returns holiday_mode_char
     (==date variable) or upper case characters 'D' or 'W' in &hc, the day
     displacement in &hn and a possible weekday name (mo...su) converted to a
     number (1...7) in &hwd for further managing of such a line.  If any invalid
     date is given in line, then this function either returns -1 in &y or leaves
     the complete program with an error message (depending on mode of operation
     resp., contents of `on_error_exit' variable).
*/
{
   register int    num_of_range_chars=0;
   register int    num_of_repeat_chars=0;
   register int    num_of_appears_chars=0;
   register int    i;
   auto     char   str8[8];   /* For "date"-parts, lenght of 7 chars+'\0' maximum! */
   auto     char  *ptr_char;
   auto     Bool   is_hdy_mode=FALSE;


   *hc = '\0';
   lineptrs->day_list=lineptrs->day_range = FALSE;
   lineptrs->repeat_part=lineptrs->appears_part = (char *)NULL;
   (*len)=(*hn)=(*hwd)=(*n)=i = 0;
   /*
      Get the year from the year field of the line.
   */
   while (   *the_line
          && !isspace(*the_line)
          && isdigit(*the_line)
          && (i < len_year_max))
     str8[i++] = *the_line++;
   str8[i] = '\0';
   *y = my_atoi (str8);
   *len = i;
   /*
      Get the month from the month field of the line.
   */
   i = 0;
   while (   *the_line
          && !isspace(*the_line)
          && (i < 2))
     str8[i++] = *the_line++;
   if (i)
     /*
        Try to get a short (3 character) textual month name.
     */
     if (   isalpha(*the_line)
         && (   isupper(str8[i-1])
#  if USE_EASC
             || str8[i-1] == *AE
             || str8[i-1] == *OE
             || str8[i-1] == *UE
             || str8[i-1] == *AAE
             || str8[i-1] == *OOE
             || str8[i-1] == *UUE
#  else /* !USE_EASC */
             || str8[i-1] == '"'
#  endif /* !USE_EASC */
             || islower(str8[i-1])))
       str8[i++] = *the_line++;
   str8[i] = '\0';
   *m = my_atoi (str8);
   if (!*m)
     /*
        Check for short (3 character) textual month name.
     */
     *m = compare_d_m_name (str8, MOnth);
   else
     if (   i == 3
         || (   (i == 2)
             && (!isdigit(str8[1]))))
      {
        /*
           Error, invalid month field.
        */
        if (on_error_exit)
          my_error (122, filename, line_number, line_buffer, *m);
        *y = -1;
      }
   /*
      Check if @... date variable statement or *... statement is given.
   */
   if (i)
    {
      *len += i;
      if (*str8 == RC_HDY_CHAR)
       {
         is_hdy_mode = TRUE;
         if (i == 2)
           *hc = (char)tolower(str8[1]);
       }
      else
        if (*str8 == RC_NWD_CHAR)
         {
           is_hdy_mode = TRUE;
           if (   (i == 2)
               && (   toupper(str8[1]) == 'D'
                   || toupper(str8[1]) == 'W'))
             *hc = (char)toupper(str8[1]);
           else
            {
              if (i == 2)
                /*
                   Error, invalid mode specifying character given.
                */
                *hc = (char)toupper(str8[1]);
              else
                /*
                   Error, no mode specifying character given.
                */
                *hc = *str8;
            }
         }
    }
   /*
      If the special value "99" for a month `m' is given,
        set the month to 12 (december).
   */
   if (*m == 99)
     *m = MONTH_MAX;
   if (   !is_hdy_mode
       && (   *m > MONTH_MAX
           || (   !*m
               && (   (   (i == 1)
                       && !isdigit(*str8))
                   || (   (i == 2)
                       && (   !isdigit(*str8)
                           || !isdigit(str8[1])))
                   || (   (i == 3)
                       && (   !isdigit(*str8)
                           || !isdigit(str8[1])
                           || !isdigit(str8[2])))))))
    {
      /*
         Error, invalid month field given.
      */
      if (on_error_exit)
        my_error (122, filename, line_number, line_buffer, *m);
      *y = -1;
    }
   /*
      Get the day (maximum 3 characters in this case, template is either `dd', `ww'  or `www')
        resp., @... date variable or *... statement (maximum 7 characters in this case,
        template is: [+|-]nnn`www').
   */
   ptr_char=lineptrs->day_part = the_line;
   i = 0;
   while (   *the_line
          && !isspace(*the_line)
          && (i < ((is_hdy_mode) ? 7 : 3)))
     str8[i++] = *the_line++;
   str8[i] = '\0';
   *d = atoi(str8);
   *len += i;
   *is_weekday_mode = FALSE;
   the_line--;
   if (   isalpha(*the_line)
       || (   (i < 3)
           && !is_hdy_mode))
     the_line++;
   /*
      Check for a list/range of days/textual day names,
        if such a list is found, let `lineptrs->day_part' point to it
        and return to caller for further managing this list/range.
   */
   while (   *ptr_char
          && !isspace(*ptr_char))
    {
      if (*ptr_char == RC_DLIST_CHAR)
        lineptrs->day_list = TRUE;
      else
        if (*ptr_char == RC_DRANGE_CHAR)
         {
           num_of_range_chars++;
           lineptrs->day_range = TRUE;
         }
        else
          if (*ptr_char == RC_REPEAT_CHAR)
           {
             num_of_repeat_chars++;
             lineptrs->repeat_part = ptr_char;
           }
          else
            if (*ptr_char == RC_APPEARS_CHAR)
             {
               num_of_appears_chars++;
               lineptrs->appears_part = ptr_char;
             }
      ptr_char++;
    }
   if (   lineptrs->day_list
       || lineptrs->day_range)
    {
      if (is_rc_file)
       {
         if (   (   num_of_range_chars > 1
                 || *ptr_char == RC_DLIST_CHAR
                 || *ptr_char == RC_DRANGE_CHAR
                 || (   lineptrs->day_list
                     && lineptrs->day_range)
                 || (   !lineptrs->day_list
                     && !lineptrs->day_range
                     && (   num_of_repeat_chars > 1
                         || num_of_appears_chars > 1)))
             && on_error_exit)
           /*
              Error, invalid list/range of days.
           */
           my_error (123, filename, line_number, line_buffer, 0);
         /*
            Check if a day variable is referenced.
         */
         if (   islower(*hc)
             && (*hc != RC_EASTER_CHAR))
          {
            /*
               Try to assign a local date variable if there is set any,
                 else try to assign a global date variable if there is set any,
                 otherwise we have to skip this part.
            */
            if (   rc_dvar[IDX(*hc)].l.month
                || rc_dvar[IDX(*hc)].g.month)
             {
               if (rc_dvar[IDX(*hc)].l.month)
                {
                  *m = (int)rc_dvar[IDX(*hc)].l.month;
                  *d = (int)rc_dvar[IDX(*hc)].l.day;
                }
               else
                {
                  *m = (int)rc_dvar[IDX(*hc)].g.month;
                  *d = (int)rc_dvar[IDX(*hc)].g.day;
                }
             }
            else
             {
               /*
                  Error, no such date variable defined.
               */
               if (   (warning_level >= 0)
                   && on_error_exit)
                 dvar_warning (113, *hc, filename, line_number, line_buffer);
               *y = -1;
             }
          }
         if (!isalpha(str8[i-1]))
           (*len)--;
         i = 0;
         while (   *the_line
                && !isspace(*the_line))
          {
            the_line++;
            i++;
          }
         *len += i;
       }
      else
       {
         /*
            Error, list/range of days is given in an expression it may not occur.
         */
         if (on_error_exit)
           my_error (123, filename, line_number, line_buffer, 0);
         *y = -1;
       }
    }
   else
    {
      if (   !is_rc_file
          && (   num_of_repeat_chars
              || num_of_appears_chars))
       {
         /*
            Error, day "repeat" or "appears" coding is given in an expression
              it may not occur.
         */
         if (on_error_exit)
           my_error (123, filename, line_number, line_buffer, 0);
         *y = -1;
       }
      else
        if (   num_of_repeat_chars > 1
            || num_of_appears_chars > 1)
         {
           /*
              Error, "repeat" or "appears" coding given twice or more.
           */
           if (on_error_exit)
             my_error (123, filename, line_number, line_buffer, 0);
           *y = -1;
         }
      lineptrs->day_part = (char *)NULL;
    }
   /*
      If no list/range of days is given, try to precompute the according date.
   */
   if (lineptrs->day_part == (char *)NULL)
    {
      if (!is_hdy_mode)
       {
         /*
            Check for simple textual day name (either two or three characters),
              template `ww' or `www'.
         */
         if (!*d)
          {
            if (*str8)
              *d = compare_d_m_name (str8, DAy);
            if (*d)
             {
               *is_weekday_mode = TRUE;
               if (isdigit(str8[i-1]))
                 (*len)--;
             }
            else
             {
               i = 0;
               while (isdigit(str8[i]))
                 i++;
               if (str8[i])
                {
                  /*
                     Error, invalid day field.
                  */
                  if (on_error_exit)
                    my_error (121, filename, line_number, line_buffer, *d);
                  *y = -1;
                }
             }
          }
         else
           if (   (i > 1)
               && !isdigit(str8[1]))
            {
              /*
                 Error, invalid day field.
              */
              if (on_error_exit)
                my_error (121, filename, line_number, line_buffer, *d);
              *y = -1;
            }
         /*
            Check whether a "n'th weekday of month" field exists.
         */
         if (   *the_line
             && !isspace(*the_line))
          {
            if (isdigit(*the_line))
             {
               *n = (*the_line - '0');
               if (*n)
                {
                  if (   (*n > 5)
                      && (*n < 9))
                   {
                     /*
                        Error, invalid "n'th weekday of month" field.
                     */
                     if (on_error_exit)
                       my_error (117, filename, line_number, line_buffer, *n);
                     *y = -1;
                   }
                }
             }
            else
              if (   (lineptrs->repeat_part == (char *)NULL)
                  && (lineptrs->appears_part == (char *)NULL))
               {
                 /*
                    Error, missing separator between "date"-part and "text"-part.
                 */
                 if (on_error_exit)
                   my_error (116, filename, line_number, line_buffer, 0);
                 *y = -1;
               }
            if (*the_line)
              the_line++;
            if (   *the_line
                && !isspace(*the_line)
                && (lineptrs->repeat_part == (char *)NULL)
                && (lineptrs->appears_part == (char *)NULL))
             {
               /*
                  Error, missing separator between "date"-part and "text"-part.
               */
               if (on_error_exit)
                 my_error (116, filename, line_number, line_buffer, 0);
               *y = -1;
             }
            if (   *n
                && (   *d < DAY_MIN
                    || *d > DAY_MAX))
             {
               /*
                  Error, "n'th weekday of month" entry set but invalid day encoded.
               */
               if (on_error_exit)
                 my_error (121, filename, line_number, line_buffer, *d);
               *y = -1;
             }
            (*len)++;
            if (   lineptrs->repeat_part != (char *)NULL
                || lineptrs->appears_part != (char *)NULL)
              while (   *the_line
                     && !isspace(*the_line))
               {
                 the_line++;
                 (*len)++;
               }
          }
       }
      else
       {
         if (isdigit(*the_line))
           the_line++;
         if (   *the_line
             && !isspace(*the_line)
             && (lineptrs->repeat_part == (char *)NULL)
             && (lineptrs->appears_part == (char *)NULL))
          {
            /*
               Error, missing separator character between "date"-part and "text"-part.
            */
            if (on_error_exit)
              my_error (116, filename, line_number, line_buffer, 0);
            *y = -1;
          }
         /*
            Compute the base date of '@' date variable "date"-part of line
              or '*' n'th weekday of year/weekday `ww[w]' of n'th week
              in case an explicit year `yyyy' is given in "date"-part.
         */
         i = atoi(str8);
         ptr_char = str8;
         if (islower(*hc))
          {
            if (   *ptr_char == *ASC_LIT
                || *ptr_char == *DES_LIT)
              ptr_char++;
            if (   *ptr_char == *ASC_LIT
                || *ptr_char == *DES_LIT
                || isalpha(*ptr_char))
             {
               /*
                  Error, simple weekday name or invalid sign given.
               */
               if (on_error_exit)
                 my_error (123, filename, line_number, line_buffer, 0);
               *hc = '\0';
               *d = 0;
               *y = -1;
             }
          }
         else
           if (   *ptr_char == *ASC_LIT
               || *ptr_char == *DES_LIT)
            {
              /*
                 Error, invalid sign given.
              */
              if (on_error_exit)
                my_error (123, filename, line_number, line_buffer, 0);
              *hc = '\0';
              *d = 0;
              *y = -1;
            }
         /*
            Now eat all digits.
         */
         while (isdigit(*ptr_char))
           ptr_char++;
         if (   *ptr_char
             && (*ptr_char != RC_REPEAT_CHAR)
             && (*ptr_char != RC_APPEARS_CHAR))
          {
            *hwd = compare_d_m_name (ptr_char, DAy);
            if (!*hwd)
             {
               /*
                  Error, invalid textual short day name given.
               */
               if (on_error_exit)
                 my_error (123, filename, line_number, line_buffer, 0);
               *hc = '\0';
               *d = 0;
               *y = -1;
             }
          }
         if (*y >= 0)
          {
            if (*hc == RC_EASTER_CHAR)
             {
               if (!precomp_date (i, *hwd, d, m, *y, EAster))
                {
                  if (!*y)
                   {
                     /*
                        No explicit year `yyyy' given in "date"-part of line.
                     */
                     *hn = i;
                     *d = 0;
                     *m = 0;
                   }
                  else
                   {
                     /*
                        Invalid relative date given.
                     */
                     *hc = '\0';
                     *d = 0;
                     *y = -1;
                   }
                }
               else
                 *hc = '\0';
             }
            else
              if (islower(*hc))
               {
                 /*
                    Try to assign a local date variable if there is set any,
                      else try to assign a global date variable if there is set any,
                      otherwise we have to skip this part.
                 */
                 if (   rc_dvar[IDX(*hc)].l.month
                     || rc_dvar[IDX(*hc)].g.month)
                  {
                    if (rc_dvar[IDX(*hc)].l.month)
                     {
                       *m = (int)rc_dvar[IDX(*hc)].l.month;
                       *d = (int)rc_dvar[IDX(*hc)].l.day;
                     }
                    else
                     {
                       *m = (int)rc_dvar[IDX(*hc)].g.month;
                       *d = (int)rc_dvar[IDX(*hc)].g.day;
                     }
                    if (!precomp_date (i, *hwd, d, m, *y, DVar))
                     {
                       if (!*y)
                         /*
                            No explicit year `yyyy' given in "date"-part of line.
                         */
                         *hn = i;
                       else
                        {
                          /*
                             Invalid relative date given.
                          */
                          *hc = '\0';
                          *d = 0;
                          *y = -1;
                        }
                     }
                    else
                      *hc = '\0';
                  }
                 else
                  {
                    /*
                       Error, no such date variable defined.
                    */
                    if (   (warning_level >= 0)
                        && on_error_exit)
                      dvar_warning (113, *hc, filename, line_number, line_buffer);
                    *hc = '\0';
                    *d = 0;
                    *y = -1;
                  }
               }
              else
                if (   *hc == 'D'
                    || *hc == 'W')
                 {
                   /*
                      Try to compute the '*' n'th weekday of year resp.,
                        weekday `ww[w]' of n'th week statement.
                   */
                   if (*y == 0)
                    {
                      /*
                         No explicit year `yyyy' given in "date"-part of line.
                      */
                      *hn = i;
                      *d = 0;
                      *m = 0;
                    }
                   else
                     if (precomp_nth_wd (i, *hwd, hn, d, m, y,
                                         (*hc == 'D') ? DAy : WEek))
                       *hc = '\0';
                 }
                else
                  /*
                     Error, either an invalid date variable character trails the holiday
                       mode character '@', or an invalid character trails the "n'th weekday
                       of year" resp., weekday `ww[w]' of "n'th week mode" character '*'.
                  */
                  if (on_error_exit)
                    my_error (123, filename, line_number, line_buffer, 0);
          }
         if (   lineptrs->repeat_part != (char *)NULL
             || lineptrs->appears_part != (char *)NULL)
           while (   *the_line
                  && !isspace(*the_line))
            {
              the_line++;
              (*len)++;
            }
         if (*the_line)
           the_line++;
       }
    }
   /*
      Now let's allocate memory for all pointers to texts of the `lineptrs' structure
        if we work on a resource/include file (except `text_part').  That's absolutely
        necessary because after a potential resizing of "all strings" elsewhere in a later
        part of the program, these pointers could get lost otherwise.  The caller has to
        free this memory!
   */
   if (is_rc_file)
    {
      /*
         ONLY IF DETECTED!
      */
      if (lineptrs->day_part != (char *)NULL)
       {
         ptr_char = lineptrs->day_part;
         i = 0;
         LOOP
          {
            if (   !*ptr_char
                || isspace(*ptr_char))
              break;
            i++;
            ptr_char++;
          }
         ptr_char = lineptrs->day_part;
         lineptrs->day_part = (char *)my_malloc (i+1,
                                                 124, __FILE__, ((long)__LINE__)-1,
                                                 "lineptrs->day_part", 0);
         strncpy(lineptrs->day_part, ptr_char, i);
         lineptrs->day_part[i] = '\0';
       }
      /*
         ONLY IF DETECTED!
      */
      if (lineptrs->repeat_part != (char *)NULL)
       {
         ptr_char = lineptrs->repeat_part;
         i = 0;
         LOOP
          {
            if (   !*ptr_char
                || isspace(*ptr_char))
              break;
            i++;
            ptr_char++;
          }
         ptr_char = lineptrs->repeat_part;
         lineptrs->repeat_part = (char *)my_malloc (i+1,
                                                    124, __FILE__, ((long)__LINE__)-1,
                                                    "lineptrs->repeat_part", 0);
         strncpy(lineptrs->repeat_part, ptr_char, i);
         lineptrs->repeat_part[i] = '\0';
       }
      /*
         ONLY IF DETECTED!
      */
      if (lineptrs->appears_part != (char *)NULL)
       {
         ptr_char = lineptrs->appears_part;
         i = 0;
         LOOP
          {
            if (   !*ptr_char
                || isspace(*ptr_char))
              break;
            i++;
            ptr_char++;
          }
         ptr_char = lineptrs->appears_part;
         lineptrs->appears_part = (char *)my_malloc (i+1,
                                                     124, __FILE__, ((long)__LINE__)-1,
                                                     "lineptrs->appears_part", 0);
         strncpy(lineptrs->appears_part, ptr_char, i);
         lineptrs->appears_part[i] = '\0';
       }
      if (   (   lineptrs->repeat_part != (char *)NULL
              || lineptrs->appears_part != (char *)NULL)
          && !is_hdy_mode
          && !*is_weekday_mode
          && !lineptrs->day_list
          && !lineptrs->day_range)
        (*len)--;
    }
   /*
      ALWAYS!
   */
   lineptrs->text_part = the_line;

   return lineptrs;
}



   PUBLIC Bool
precomp_nth_wd (diff, wd, n, day, month, year, mode)
         int         diff;
   const int         wd;
         int        *n;
         int        *day;
         int        *month;
         int        *year;
   const Cmode_enum  mode;
/*
   Precompute the date of the "n'th absolute weekday" `wd' of the year
     or the date on weekday `wd' of the "n'th absolute week" of the year,
     and return TRUE in case date exits in year, otherwise FALSE.
*/
{
   register int  j=0;
   auto     int  i=0;


   if (*year)
    {
      if (mode == DAy)
       {
         *day = DAY_MIN;
         *month = MONTH_MIN;
         if (wd)
          {
            if (   diff == WEEK_MAX+1
                || diff == 99)
             {
               i = diff;
               diff = WEEK_MAX;
             }
          }
         else
          {
            /*
               If a special value "999" for `diff' is given,
                 set it to last day of year (365|366).
            */
            if (diff == 999)
              diff = DAY_LAST + (days_of_february (*year) == 29);
            i = diff--;
          }
       }
      else
       {
         /*
            `mode' == WEek.
         */
         j = diff;
         diff=i = weekno2doy (diff, *year);
         if (diff > DAY_MIN)
           diff--;
         else
           diff = 1;
         if (doy2date (diff, (days_of_february (*year)==29), day, month))
           diff = 1;
       }
    }
   if (!precomp_date (diff, wd, day, month, *year, DVar))
    {
      if (!*year)
       {
         /*
            No explicit year `yyyy' given in "date"-part of line.
         */
         *day = 0;
         *month = 0;
         *n = diff;
       }
      else
       {
         /*
            Invalid relative date given.
         */
         *day = 0;
         *month = 0;
         *year = -1;
       }
      return FALSE;
    }
   else
    {
      if (   wd
          && (mode == DAy))
       {
         register int  year_old=*year;


         if (i)
           for (diff=DAY_MIN ; diff <= DAY_MAX ; diff++)
             next_date (day, month, year);
         if (   (   (*day <= DAY_MAX)
                 && (*year != year_old))
             || weekday_of_date (DAY_MIN, MONTH_MIN, *year) == wd)
           for (diff=DAY_MIN ; diff <= DAY_MAX ; diff++)
             prev_date (day, month, year);
         if (i == WEEK_MAX+1)
          {
            i = DAY_MIN;
            *month = MONTH_MIN;
            (void)precomp_date (WEEK_MAX, wd, &i, month, *year, DVar);
            if (   (*day == i)
                && (weekday_of_date (DAY_MIN, MONTH_MIN, *year) != wd))
             {
               /*
                  Error, no such 53rd weekday `ww[w]' of year.
               */
               *day = 0;
               *month = 0;
               *year = -1;
               return FALSE;
             }
          }
       }
      else
        /*
           `mode' == WEek.
        */
        if (   !wd
            || i < DAY_MIN
            || (   (j <= 1)
                && (*day == DAY_MAX+1)
                && (wd == DAY_MIN)))
         {
           if (*day >= DAY_MAX+i)
             *day -= DAY_MAX;
           else
             if (   !wd
                 && (   i < DAY_MIN
                     || (   (*day == DAY_MIN+1)
                         && (i == DAY_MIN))))
               (*day)--;
           if (*day < DAY_MIN)
            {
              /*
                 Error, n'th week doesn't contain such a weekday `ww[w]'.
              */
              *day = 0;
              *month = 0;
              *year = -1;
              return FALSE;
            }
         }
    }

   return TRUE;
}



   PUBLIC Bool
precomp_date (diff, wd, day, month, year, mode)
         int         diff;
   const int         wd;
         int        *day;
         int        *month;
   const int         year;
   const Cmode_enum  mode;
/*
   Precompute the date relative to Easter Sunday's date (mode==EAster) or
     relative to date variables date (mode==DVar) plus displacement `diff'
     or displacement `diff' `wd' and return TRUE in case date exits in year,
     otherwise FALSE.
*/
{
   register int  i;


   if (   (   (mode == EAster)
           && (year >= EASTER_MIN)
           && (year <= EASTER_MAX))
       || (   (mode == DVar)
           && (year >= YEAR_MIN)
           && (year <= YEAR_MAX)))
    {
      if (mode == EAster)
        i = knuth_easter_formula (year);
      else
       {
         if (!valid_date (*day, *month, year))
           /*
              Error, invalid date given (e.g. 19010229).
           */
           return FALSE;
         i = day_of_year (*day, *month, year);
       }
      if (wd)
       {
         /*
            Calculate date like:  3rd(`diff') Friday(`wd') before Easter Sunday's date.
         */
         if (   wd < DAY_MIN
             || wd > DAY_MAX)
           /*
              Error, invalid weekday specified.
           */
           return FALSE;
         else
           if (!diff)
             /*
                Error, a weekday but no difference specified.
             */
             return FALSE;
           else
             if (diff == -99)
              {
                /*
                   Detect first weekday `wd' of year.
                */
                *month = MONTH_MIN;
                *day = eval_holiday (DAY_MIN, *month, year, wd, TRUE);
                return TRUE;
              }
             else
               if (diff == 99)
                {
                  /*
                     Detect last weekday `wd' of year.
                  */
                  *month = MONTH_MAX;
                  *day = eval_holiday (dvec[MONTH_MAX-1], *month, year, wd, FALSE);
                  return TRUE;
                }
               else
                {
                  register int  act_wd;
                  auto     int  d;
                  auto     int  m;
                  auto     int  y=year;


                  doy2date (i, (days_of_february (y)==29), &d, &m);
                  act_wd = weekday_of_date (d, m, y);
                  if (act_wd != wd)
                   {
                     if (diff < 0)
                      {
                        /*
                           Try to detect first weekday `wd' before actual date.
                        */
                        while (act_wd != wd)
                         {
                           prev_date (&d, &m, &y);
                           act_wd = weekday_of_date (d, m, y);
                           i--;
                         }
                        diff++;
                      }
                     else
                      {
                        /*
                           Try to detect first weekday `wd' after actual date.
                        */
                        while (act_wd != wd)
                         {
                           next_date (&d, &m, &y);
                           act_wd = weekday_of_date (d, m, y);
                           i++;
                         }
                        diff--;
                      }
                   }
                  if (y != year)
                    /*
                       Error, we have left the year bounds.
                    */
                    return FALSE;
                  /*
                     Calculate the difference.
                  */
                  i += diff * DAY_MAX;
                }
       }
      else
       {
         /*
           Calculate the difference.
         */
         if (diff == -999)
           i = 1;
         else
           if (diff == 999)
             i = DAY_LAST + (days_of_february (year) == 29);
           else
             i += diff;
       }
      if (doy2date (i, (days_of_february (year)==29), day, month))
        return TRUE;
    }

   return FALSE;
}



   PUBLIC Bool
set_dvar (line_buffer, filename, line_number, mode)
   const char      *line_buffer;
   const char      *filename;
   const long       line_number;
   const Dvar_enum  mode;
/*
   Scans given string `line_buffer' and tries to detect a valid date variable
     references, which can be:
       1) `dvar'=           (NOTHING)  --> Undefine local `dvar' so we are able to use
                                             its global value.  If `mode' is set to "GLobal",
                                             this "empty" assignment results an error. 
       2) `dvar'=`mmdd'                --> Assignment of a constant date expression `mmdd'.
       3) `dvar'=`mmww[w]'<n>          --> Assignment of a dynamic date expression.
                                             n'th weekday `ww[w]' in month `mm'.
       4) `dvar'=*d<n>[`ww[w]']        --> Assignment of a dynamic date expression
                                             n'th weekday `ww[w]' of year.
       5) `dvar'=*w<n>[`ww[w]']        --> Assignment of a dynamic date expression
                                             weekday `ww[w]' of n'th week of year.
       6) `dvar'=`dvar'                --> Assignment of a date variable `dvar',
                                             which must be already defined.
       7) `dvar'=`dvar'[+|-]<n>        --> Assignment of a date variable `dvar', which must be already
                                             defined, advanced by plus/minus <n> days.
       8) `dvar'=`dvar'[+|-]<n>`ww[w]' --> Assignment of a date variable `dvar', which must be already
                                             defined, advanced by plus/minus <n> weekdays `ww[w]'.
       9) `dvar'++                     --> Simple incrementation.
      10) `dvar'--                     --> Simple decrementation.
      11) `dvar'+=<n>                  --> Addition of a constant numeric factor <n>.
      12) `dvar'-=<n>                  --> Subtraction of a constant numeric factor <n>.
      13) `dvar'+=<n>`ww[w]'           --> Addition of <n> weekdays `ww[w]'.
      14) `dvar'-=<n>`ww[w]'           --> Subtraction of <n> weekdays `ww[w]'.
     A date variable name is valid from a...d and f...z (total 25 variables,
     case-insensitive), because the `e' variable is always reserved for current
     Easter Sunday's date so we must skip any reference to this variable.
     No whitespace characters may occur between the date variable, operator
     and value.  Stores assignment (1)...(8) at position `date variable'
     into global date variable vector `rc_dvar[]' (either the local or the
     global ones, depending on given `mode', which can be either "GLobal"
     or "LOcal".  Assignments (1), (3)...(5), (7), (8) and operations (9)...(14)
     may be used ONLY in local date variables.  Returns FALSE if an error
     occurs, otherwise TRUE.
*/
{
   auto       int   i;
   auto       int   len;
   auto       int   d=0;
   auto       int   m=0;
   auto       int   y=year;
   auto       int   n;
   auto       char  op;
   auto       char  op2;
   auto const char *ptr_char=line_buffer;
   auto       Bool  is_error=FALSE;
   auto       Bool  is_weekday_mode;
   auto       Bool  dvar_with_displacement=FALSE;
   auto       Bool  dvar_inc_dec=FALSE;
   auto       Bool  dvar_add_sub=FALSE;
   auto       Bool  skip_dvar_assign=FALSE;


   /*
      Skip and return error if invalid date variable name is given.
   */
   if (   isalpha(*ptr_char)
       && (tolower(*ptr_char) != RC_EASTER_CHAR))
    {
      ptr_char++;
      /*
         Check if assignment (1)...(8) is given.
      */
      if (*ptr_char != *RC_DVAR_ASSIGN)
       {
         if (   (*ptr_char != *RC_DVAR_ADD)
             && (*ptr_char != *RC_DVAR_SUB))
           /*
              Error, invalid first operator character found (no '+' or '-' given).
           */
           is_error = TRUE;
         else
          {
            /*
               Check if operation (9)...(14) is given.
            */
            op = *ptr_char++;
            if (*ptr_char)
             {
               op2 = *ptr_char++;
               if (   op2 == op
                   || op2 == *RC_DVAR_ASSIGN)
                {
                  if (mode == GLobal)
                    m = (int)rc_dvar[IDX(*line_buffer)].g.month;
                  else
                    m = (int)rc_dvar[IDX(*line_buffer)].l.month;
                  if (m)
                   {
                     if (op == op2)
                      {
                        while (isspace(*ptr_char))
                          ptr_char++;
                        if (*ptr_char)
                          /*
                             Error, found invalid trailing characters.
                          */
                          is_error = TRUE;
                        else
                          /*
                             Either 'dvar++' or 'dvar--' found.
                          */
                          dvar_inc_dec = TRUE;
                      }
                     else
                       /*
                          Either 'dvar+=...' or 'dvar-=...' found.
                       */
                       dvar_add_sub = TRUE;
                     if (!is_error)
                       goto LABEL_compute_dvar;
                   }
                  else
                   {
                     /*
                        Error, date variable undefined.
                     */
                     skip_dvar_assign = TRUE;
                     if (warning_level >= 0)
                       dvar_warning (113, *line_buffer, filename, line_number, line_buffer);
                   }
                }
               else
                 /*
                    Error, invalid second operator character found
                      (no '=', '+' or '-' given resp., illegal combination of '+' and '-').
                 */
                 is_error = TRUE;
             }
            else
              /*
                 Error, incomplete operator found (no '+=', '-=', '++' or '--' given).
              */
              is_error = TRUE;
          }
       }
      else
       {
         /*
            Assignment (1)...(8) to date variable found (simple '=' given),
              scan expression part of date variable definition.  Assignments
              (1), (3)...(5), (7), (8) are ONLY allowed for local date variables.
         */
         i = 0;
         ptr_char++;
         if (!*ptr_char)
          {
            /*
               No date assigned ("empty" assignment), set the date variable slot to
                 zero so we are able to use its possibly setted global value if this
                 variable is referenced again at a later place within the sequence.
                 This kind of assignment is allowed for local date variables only;
                 for global date variables, we have to report an error instead.
            */
            if (mode == GLobal)
              /*
                 Error, empty assignment to a global date variable given.
              */
              is_error = TRUE;
          }
         else
          {
            if (   isalpha(*ptr_char)
                && !isalpha(*(ptr_char+1)))
             {
               op = *ptr_char;
               ptr_char++;
               if (   !*ptr_char
                   || isspace(*ptr_char))
                {
                  if (tolower(op) == RC_EASTER_CHAR)
                   {
                     /*
                        Error, date variable is invalid.
                     */
                     skip_dvar_assign = TRUE;
                     if (warning_level >= 0)
                       dvar_warning (112, *line_buffer, filename, line_number, line_buffer);
                   }
                  else
                   {
                     /*
                        If the character after '=' is alphabetic and is not trailed
                          by digits, assume assignment (6) is given.
                     */
                     if (mode == GLobal)
                      {
                        m = (int)rc_dvar[IDX(op)].g.month;
                        d = (int)rc_dvar[IDX(op)].g.day;
                      }
                     else
                      {
                        m = (int)rc_dvar[IDX(op)].l.month;
                        d = (int)rc_dvar[IDX(op)].l.day;
                      }
                   }
                }
               else
                {
                  /*
                     Check if assignments (7)...(8) are given.
                  */
                  if (   *ptr_char == *ASC_LIT
                      || *ptr_char == *DES_LIT
                      || isdigit(*ptr_char ))
                   {
                     ptr_char--;
                     dvar_with_displacement = TRUE;
                     goto LABEL_compute_dvar;
                   }
                  else
                    /*
                       Error, invalid date variable name given.
                    */
                    is_error = TRUE;
                }
             }
            else
             {
LABEL_compute_dvar:
               i = (int)strlen(line_buffer) + len_year_max;
               if ((Uint)i >= maxlen_max)
                 resize_all_strings (i+1, __FILE__, (long)__LINE__);
               if (dvar_with_displacement)
                 sprintf(s5, "%0*d%c%s", len_year_max, y, RC_HDY_CHAR, ptr_char);
               else
                 if (dvar_add_sub)
                   sprintf(s5, "%0*d%c%c%c%s", len_year_max, y, RC_HDY_CHAR, *line_buffer, op, ptr_char);
                 else
                   if (dvar_inc_dec)
                     sprintf(s5, "%0*d%c%c%c1", len_year_max, y, RC_HDY_CHAR, *line_buffer, op);
                   else
                     sprintf(s5, "%0*d%s", len_year_max, y, ptr_char);
               /*
                  `rc_get_date()' arguments `len' and `i' are dummys
                    only and must be given.  They are not respected!
               */
               (void)rc_get_date (s5, lineptrs, FALSE, &is_weekday_mode, &d, &m, &y, &n, &len,
                                  &op, &i, &i, filename, line_number, line_buffer, TRUE);
               if (y != -1)
                {
                  /*
                     Check if assignments (3)...(5) are given.
                  */
                  if (   (mode == GLobal)
                      && (   op
                          || is_weekday_mode))
                    is_error = TRUE;
                  else
                   {
                     /*
                        Assignments (2)...(3) are given.
                     */
                     if (   m < MONTH_MIN
                         || m > MONTH_MAX)
                       /*
                          Error, invalid month given.
                       */
                       is_error = TRUE;
                     else
                      {
                        i = dvec[m-1];
                        if (m == 2)
                          i += is_leap_year;
                        /*
                           Check for assignment (3) `dvar'=`mmww[w]'<n> (`ww'=mo...su,
                             `www'=mon...sun, n=1...5|9), e.g.:
                             x=03mo3  sets `x' to date of 3rd Monday in March
                             x=03mon3  sets `x' to date of 3rd Monday in March, too.
                        */
                        if (is_weekday_mode)
                         {
                           if (n == 9)
                             d = eval_holiday (i, m, year, d, FALSE);
                           else
                            {
                              d = eval_holiday (DAY_MIN, m, year, d, TRUE);
                              d += (DAY_MAX * (n - 1));
                              if (d > i)
                               {
                                 /*
                                    Month contains no such "n'th weekday of month",
                                      ignore the assignment but produce NO error!!
                                 */
                                 skip_dvar_assign = TRUE;
                                 if (warning_level >= 0)
                                   dvar_warning (112, *line_buffer, filename, line_number, line_buffer);
                               }
                            }
                         }
                        else
                         {
                           /*
                              Assume assignment (1) is given.
                           */
                           if (d == 99)
                             d = i;
                           /*
                              We must avoid an assigment like `dvar'=0229
                                if we are in fiscal year mode and the next
                                year is no leap year and no "--leap-day=ARG"
                                option is given!
                           */
                           if (   (fiscal_month > MONTH_MIN+1)
                               && (days_of_february (year+1) == 28)
                               && !rc_feb_29_to_feb_28
                               && !rc_feb_29_to_mar_01
                               && (m == 2)
                               && (d == 29))
                            {
                              /*
                                 Year contains no such date,
                                   ignore the assignment but produce NO error!!
                              */
                              skip_dvar_assign = TRUE;
                              if (warning_level >= 0)
                                dvar_warning (112, *line_buffer, filename, line_number, line_buffer);
                            }
                           else
                            {
                              if (d > i)
                               {
                                 manage_leap_day (&d, &m, year, line_buffer, filename, line_number);
                                 i = d;
                               }
                              if (   d < DAY_MIN
                                  || d > i)
                               {
                                 /*
                                    Error, invalid day given.
                                 */
                                 is_error = TRUE;
                               }
                            }
                         }
                      }
                   }
                }
               else
                {
                  /*
                     Year contains no such date,
                       ignore the assignment but produce NO error!!
                  */
                  skip_dvar_assign = TRUE;
                  if (warning_level >= 0)
                    dvar_warning (112, *line_buffer, filename, line_number, line_buffer);
                }
             }
          }
       }
      if (   !is_error
          && !skip_dvar_assign)
       {
         /*
            Store the assigned/calculated date.
         */
         if (mode == GLobal)
          {
            rc_dvar[IDX(*line_buffer)].g.month = (char)m;
            rc_dvar[IDX(*line_buffer)].g.day = (char)d;
          }
         else
          {
            rc_dvar[IDX(*line_buffer)].l.month = (char)m;
            rc_dvar[IDX(*line_buffer)].l.day = (char)d;
          }
       }
    }
   else
     /*
        Error, invalid date variable name given (not a...df...z).
     */
     is_error = TRUE;

   return (Bool)!is_error;
}



   PUBLIC Bool
set_tvar (line_buffer, mode)
   const char      *line_buffer;
   const Tvar_enum  mode;
/*
   Scans given string `line_buffer' and tries to detect a valid text variable
     reference, which is:
       $`tvar'=[TEXT] --> Assignment of a constant text expression TEXT to `tvar'
                          (TEXT may contain references to other `tvar's, which
                          are always expanded recursively before assignment is
                          performed)!
     A text variable name is valid from $a...$z (totally 26 variables,
     case-insensitve).  No whitespace characters may occur between the text
     variable prefix character '$' and the text variable letter itself, the
     assignment operator '=' and TEXT value.  Stores assigned TEXT at position
     `text variable' into global text variable vector `rc_tvar[]' (either the
     local or the global ones, depending on given `mode', which can be either
     "GLobal" or "LOcal".  Returns FALSE if an error occurs, otherwise TRUE.
*/
{
   register   int   len;
   auto       char  tvar;
   auto const char *ptr_char=line_buffer;
   auto       Bool  is_error=FALSE;


   if (*ptr_char == RC_TVAR_CHAR)
    {
      /*
         Skip the trailing '$' character of a text variable by default.
      */
      ptr_char++;
      /*
         Skip and return error if invalid text variable name is given.
      */
      if (isalpha(*ptr_char))
       {
         tvar = *ptr_char++;
         /*
            Check if an assignment is given.
         */
         if (*ptr_char == *RC_TVAR_ASSIGN)
          {
            register       int    i=0;
            auto     const char  *ptr_tvar;
            auto           Bool   is_quoted=FALSE;


            ptr_char++;
            /*
               Check if the assigned TEXT contains any references
                 to other `tvar' variables, if so, insert their TEXTs.
            */
            ptr_tvar = strchr(ptr_char, RC_TVAR_CHAR);
            if (ptr_tvar != (char *)NULL)
             {
               do
                {
                  len = (int)(ptr_tvar - ptr_char);
                  if (len)
                   {
                     while ((Uint)len+i >= maxlen_max)
                       resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                     strncpy(s5+i, ptr_char, len);
                     i += len;
                   }
                  s5[i] = '\0';
                  if (i)
                    if (s5[i-1] == QUOTE_CHAR)
                      is_quoted = TRUE;
                  ptr_tvar++;
                  if (   !is_quoted
                      && isalpha(*ptr_tvar))
                   {
                     register int  j=0;


                     /*
                        Try to insert the value of this `tvar' (this is its TEXT).
                     */
                     if (   (mode == GLobal)
                         && (rc_tvar[IDX(*ptr_tvar)].g.text != (char *)NULL))
                      {
                        j = (int)strlen(rc_tvar[IDX(*ptr_tvar)].g.text);
                        if (j)
                         {
                           while ((Uint)i+j >= maxlen_max)
                             resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                           strcat(s5, rc_tvar[IDX(*ptr_tvar)].g.text);
                         }
                      }
                     else
                       if (   (mode == LOcal)
                           && (rc_tvar[IDX(*ptr_tvar)].l.text != (char *)NULL))
                        {
                          j = (int)strlen(rc_tvar[IDX(*ptr_tvar)].l.text);
                          if (j)
                           {
                             while ((Uint)i+j >= maxlen_max)
                               resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                             strcat(s5, rc_tvar[IDX(*ptr_tvar)].l.text);
                           }
                        }
                     if (   (   (mode == GLobal)
                             && (rc_tvar[IDX(*ptr_tvar)].g.text != (char *)NULL))
                         || (   (mode == LOcal)
                             && (rc_tvar[IDX(*ptr_tvar)].l.text != (char *)NULL))
                         || (   (tvar == *ptr_tvar)
                             && (   (   (mode == GLobal)
                                     && (rc_tvar[IDX(*ptr_tvar)].g.text == (char *)NULL))
                                 || (   (mode == LOcal)
                                     && (rc_tvar[IDX(*ptr_tvar)].l.text == (char *)NULL)))))
                      {
                        /*
                           Skip `tvar' name.
                        */
                        len += 2;
                        if (j)
                          i += j;
                        else
                          /*
                             If `tvar' is "empty", remove a possibly obsolete whitespace.
                          */
                          if (i)
                            if (   isspace(s5[i-1])
                                && isspace(*(ptr_tvar + 1)))
                              s5[--i] = '\0';
                      }
                     else
                      {
                        /*
                           If `tvar' isn't defined, don't touch its name.
                        */
                        if ((Uint)i+2 >= maxlen_max)
                          resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                        s5[i++] = RC_TVAR_CHAR;
                        s5[i++] = *ptr_tvar;
                        s5[i] = '\0';
                        len += 2;
                      }
                   }
                  else
                   {
                     /*
                        If a quoted or an invalid `tvar' name is found, don't touch it.
                     */
                     if ((Uint)i+1 >= maxlen_max)
                       resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                     s5[i++] = RC_TVAR_CHAR;
                     s5[i] = '\0';
                     len++;
                     if (*ptr_tvar)
                      {
                        if ((Uint)i+1 >= maxlen_max)
                          resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                        s5[i++] = *ptr_tvar;
                        s5[i] = '\0';
                        len++;
                      }
                   }
                  ptr_char += len;
                  ptr_tvar = strchr(ptr_char, RC_TVAR_CHAR);
                  is_quoted = FALSE;
                } while (ptr_tvar != (char *)NULL);   /* I don't like the GNU-coding scheme for do-whiles */
               /*
                  Add possibly trailing ordinary text.
               */
               if (*ptr_char)
                {
                  i += (int)strlen(ptr_char);
                  while ((Uint)i >= maxlen_max)
                    resize_all_strings (maxlen_max<<1, __FILE__, (long)__LINE__);
                  strcat(s5, ptr_char);
                }
               i++;
               ptr_char = s5;
             }
            else
              i = (int)strlen(ptr_char) + 1;
            /*
               Store TEXT to the according `tvar' text variable.
            */
            if (mode == GLobal)
             {
               if (rc_tvar[IDX(tvar)].g.text == (char *)NULL)
                 rc_tvar[IDX(tvar)].g.text = (char *)my_malloc (i,
                                                                124, __FILE__, ((long)__LINE__)-1,
                                                                "rc_tvar[IDX(tvar)].g.text", IDX(tvar));
               else
                 rc_tvar[IDX(tvar)].g.text = (char *)my_realloc ((VOID_PTR)(rc_tvar[IDX(tvar)].g.text), i,
                                                                 124, __FILE__, ((long)__LINE__)-1,
                                                                 "rc_tvar[IDX(tvar)].g.text", IDX(tvar));
               strcpy(rc_tvar[IDX(tvar)].g.text, ptr_char);
             }
            else
             {
               if (i > 1)
                {
                  /*
                     We have to store the assigned text.
                  */ 
                  if (rc_tvar[IDX(tvar)].l.text == (char *)NULL)
                    rc_tvar[IDX(tvar)].l.text = (char *)my_malloc (i,
                                                                   124, __FILE__, ((long)__LINE__)-1,
                                                                   "rc_tvar[IDX(tvar)].l.text", IDX(tvar));
                  else
                    rc_tvar[IDX(tvar)].l.text = (char *)my_realloc ((VOID_PTR)(rc_tvar[IDX(tvar)].l.text), i,
                                                                    124, __FILE__, ((long)__LINE__)-1,
                                                                    "rc_tvar[IDX(tvar)].l.text", IDX(tvar));
                  strcpy(rc_tvar[IDX(tvar)].l.text, ptr_char);
                }
               else
                 /*
                    No text assigned ("empty" assignment), set the text variable slot to
                      NULL so we are able to use its possibly setted global value if
                      this variable is referenced again at a later place within the sequence.
                 */
                 if (rc_tvar[IDX(tvar)].l.text != (char *)NULL)
                  {
                    free(rc_tvar[IDX(tvar)].l.text);
                    rc_tvar[IDX(tvar)].l.text = (char *)NULL;
                  }
             }
          }
         else
           /*
              Error, invalid operator character found (not '=' given).
           */
           is_error = TRUE;
       }
      else
        /*
           Error, invalid text variable name given (not a...z).
        */
        is_error = TRUE;
    }
   else
     /*
        Error, no leading '$' character (text variable prefix) given.
     */
     is_error = TRUE;

   return (Bool)!is_error;
}



   PUBLIC void
nth_weekday_of_month (d, m, y, n, is_weekday_mode)
         int  *d;
         int  *m;
         int  *y;
   const int  *n;
         Bool *is_weekday_mode;
/*
   If "n'th weekday of month" field is encoded:
     Compute the according date and return it in &d, &m, &y.
     If conversion error occurs, return &y==-1 (special value).
*/
{
   register int   i;
   register int   j=0;
   auto     int   dd=0;
   auto     int   mm=0;
   auto     Bool  year_set=FALSE;
   auto     Bool  year_modified=FALSE;


   if (   *n
       && (   !rc_year_flag
           || (   *m
               && rc_year_flag))
       && (   !rc_period_list
           || (   *m
               && rc_period_list)))
    {
      if (   !*m
          && (   is_3month_mode
              || is_3month_mode2
              || fiscal_month > MONTH_MIN))
        /*
           If fiscal year resp., 3 month mode and no month encoded, skip evaluation.
        */
        ;
      else
       {
         *is_weekday_mode = FALSE;
         if (!*y)
          {
            year_set = TRUE;
            *y = year;
          }
         if (!*m)
          {
            *m = month;
            /*
               A [-c][<n>]w or [-c]t option set:
                 Lookahead whether the week ends in the month it started.
            */
            if (   rc_week_flag
                || rc_tomorrow_flag)
             {
               /*
                  <0000|`yyyy'>00`ww[w]'<n> event is in last week of last month of previous year.
               */
               if (   (*n > 3)
                   && (day < DAY_MIN))
                {
                  i = (days_of_february (year-1) == 29);
                  j = day + DAY_LAST + i;
                  (void)doy2date (j, i, &dd, &mm);
                }
               else
                 if (*n == 1)
                  {
                    /*
                       <0000|`yyyy'>00`ww[w]'<n> event is in first week of next month of actual year.
                    */
                    if (   (day+DAY_MAX-1 > 0)
                        && (day+DAY_MAX-1 < DAY_LAST+is_leap_year+1))
                      (void)doy2date (day+DAY_MAX-1, is_leap_year, &dd, &mm);
                    else
                     {
                       /*
                          <0000|`yyyy'>00`ww[w]'<n> event is in first week of first month of next year.
                       */
                       i = (days_of_february (year+1) == 29);
                       j = (day + DAY_MAX - 1) - (DAY_LAST + is_leap_year);
                       (void)doy2date (j, i, &dd, &mm);
                     }
                  }
               dd = *d;
             }
          }
         else
           if (   year_set
               && (   rc_week_flag
                   || rc_tomorrow_flag))
            {
              if (   (*n == 9)
                  && (*m == MONTH_MAX)
                  && (*y > YEAR_MIN)
                  && (day < DAY_MIN))
               {
                 year_modified = TRUE;
                 (*y)--;
               }
              else
                if (   (*n == 1)
                    && (*m == MONTH_MIN)
                    && (*y < YEAR_MAX)
                    && (day+DAY_MAX >= DAY_LAST+is_leap_year))
                 {
                   year_modified = TRUE;
                   (*y)++;
                 }
            }
         if (   year_set
             && (*y < YEAR_MAX)
             && (   (fiscal_month > MONTH_MIN)
                 && (*m < fiscal_month)))
           if (!year_modified)
             (*y)++;
         if (*m == 2)
           i = days_of_february (*y);
         else
           i = dvec[*m-1];
         if (*n == 9)
           *d = eval_holiday (i, *m, *y, *d, FALSE);
         else
          {
            *d = eval_holiday (DAY_MIN, *m, *y, *d, TRUE);
            *d += (DAY_MAX * (*n - 1));
            /*
               The "n'th weekday of month" doesn't occur in month:
                 Skip it.
            */
            if (*d > i)
              *y = -1;
          }
         /*
            A [-c][<n>]w or [-c]t option set:
              Correction for lookahead.
         */
         if (   mm
             && (   rc_week_flag
                 || rc_tomorrow_flag))
          {
            if (   (*n == 1)
                && (mm != *m))
             {
               *m = mm;
               if (   (day+DAY_MAX-1 > 0)
                   && (day+DAY_MAX-1 < DAY_LAST+is_leap_year+1))
                 /*
                    Void, don't change the year of event.
                 */
                 ;
               else
                 if (   year_set
                     && (year < YEAR_MAX))
                   *y = year + 1;
               *d = eval_holiday (DAY_MIN, *m, *y, dd, TRUE);
             }
            else
              if (   (*n > 3)
                  && (   (   adate_set
                          && (mm == *m))
                      || (   !adate_set
                          && (mm != *m))))
               {
                 if (!adate_set)
                   *m = mm;
                 if (   year_set
                     && (year > YEAR_MIN))
                   *y = year - 1;
                 if (*n == 9)
                   *d = eval_holiday (dvec[MONTH_MAX-1], *m, *y, dd, FALSE);
                 else
                  {
                    *d = eval_holiday (DAY_MIN, *m, *y, dd, TRUE);
                    *d += (DAY_MAX * (*n - 1));
                    /*
                       The "n'th weekday of month" doesn't occur in month:
                         Skip it
                    */
                    if (*d > dvec[MONTH_MAX-1])
                      *y = -1;
                  }
               }
          }
       }
    }
}



   PUBLIC void
prev_date (day, month, year)
   int *day;
   int *month;
   int *year;
/*
   Sets a delivered date back by one day (to yesterdays date)
     respecting the missing period of the Gregorian Reformation.
*/
{
   if (   (*day == greg->last_day+1)
       && (*month == greg->month)
       && (*year == greg->year))
     *day = greg->first_day - 1;
   else
    {
      (*day)--;
      if (   !*day
          || !valid_date (*day, *month, *year))
       {
         (*month)--;
         if (*month < MONTH_MIN)
          {
            *month = MONTH_MAX;
            (*year)--;
          }
         if (*month == 2)
           *day = days_of_february (*year);
         else
           *day = dvec[*month-1];
       }
    }
}



   PUBLIC void
next_date (day, month, year)
   int *day;
   int *month;
   int *year;
/*
   Sets the delivered date forwards by one day (to tomorrows date)
     respecting the missing period of the Gregorian Reformation.
*/
{
   if (   (*day == greg->first_day-1)
       && (*month == greg->month)
       && (*year == greg->year))
     *day = greg->last_day + 1;
   else
    {
      (*day)++;
      if (!valid_date (*day, *month, *year))
       {
         *day = DAY_MIN;
         if (*month == MONTH_MAX)
          {
            *month = MONTH_MIN;
            (*year)++;
          }
         else
           (*month)++;
       }
    }
}



   PUBLIC void
num2date (julian_days, day, month, year)
   Ulint  julian_days;
   int   *day;
   int   *month;
   int   *year;
/*
   Converts a delivered absolute number of days `julian_days' to a standard date
     (since 00010101(==`yyyymmdd'), returned in &day, &month and &year)
     respecting the missing period of the Gregorian Reformation.
*/
{
   auto     double  x;
   auto     Ulint   jdays=date2num (greg->first_day-1, greg->month, greg->year);
   register int     i;


   if (julian_days > jdays)
     julian_days += (Ulint)(greg->last_day - greg->first_day + 1);
   x = (double)julian_days / (DAY_LAST + 0.25);
   i = (int)x;
   if ((double)i != x)
     *year = i + 1;
   else
    {
      *year = i;
      i--;
    }
   if (julian_days > jdays)
    {
      /*
         Correction for Gregorian years.
      */
      julian_days -= (Ulint)((*year / 400) - (greg->year / 400));
      julian_days += (Ulint)((*year / 100) - (greg->year / 100));
      x = (double)julian_days / (DAY_LAST + 0.25);
      i = (int)x;
      if ((double)i != x)
        *year = i + 1;
      else
       {
         *year = i;
         i--;
       }
      if (   (*year % 400)
          && !(*year % 100))
        julian_days--;
    }
   i = (int)(julian_days - (Ulint)(i * (DAY_LAST + 0.25)));
   /*
      Correction for Gregorian centuries.
   */
   if (   (*year > greg->year)
       && (*year % 400)
       && !(*year % 100)
       && (i < ((*year/100)-(greg->year/100))-((*year/400)-(greg->year/400))))
     i++;
   (void)doy2date (i, (days_of_february (*year)==29), day, month);
}



   PUBLIC Slint
d_between (d1, m1, y1, d2, m2, y2)
   const int d1;
   const int m1;
   const int y1;
   const int d2;
   const int m2;
   const int y2;
/*
   Computes the amount of days between date1(base date) and date2
     exclusive date1 and date2, and adds 1 to result.
*/
{
   return date2num (d2, m2, y2)-date2num (d1, m1, y1);
}



   PUBLIC Slint
w_between (d1, m1, y1, d2, m2, y2)
   const int d1;
   const int m1;
   const int y1;
   const int d2;
   const int m2;
   const int y2;
/*
   Computes the amount of weeks between date1(base date) and date2
     exclusive date1 and date2, and adds 1 to result.
*/
{
   auto     Ulint  date1=date2num (d1, m1, y1);
   auto     Ulint  date2=date2num (d2, m2, y2);
   auto     Slint  diff;
   auto     Slint  result;


   diff = (Slint)date2 - (date1 - (SYEAR(weekday_of_date (d1, m1, y1), start_day)) + 1);
   result = diff / DAY_MAX;
   if (   (diff % DAY_MAX)
       && (diff < 0L))
     result--;

   return result;
}



   PUBLIC Slint
m_between (m1, y1, m2, y2)
   const int m1;
   const int y1;
   const int m2;
   const int y2;
/*
   Computes the amount of months between date1(base date) and date2
     exclusive date1 and date2, and adds 1 to result.
*/
{
   return ((y2 - y1)*MONTH_MAX)+(m2 - m1);
}



   PUBLIC void
manage_leap_day (day, month, year, line_buffer, filename, line_number)
         int  *day;
         int  *month;
         int   year;
   const char *line_buffer;
   const char *filename;
   const long  line_number;
/*
   Tries to set the leap day (29-Feb) either to "28-Feb" or "1-Mar"
     and prints a warning message in case this date modification is
     performed successfully (only if --debug[=ARG] is given).
*/
{
   register int  action=0;


   if (   (*month == 2)
       && (*day == 29)
       && (   rc_feb_29_to_feb_28
           || rc_feb_29_to_mar_01))
    {
      if (   (fiscal_month > MONTH_MIN+1)
          && (year < YEAR_MAX))
       {
         if (days_of_february (year+1) == 28)
          {
            if (rc_feb_29_to_feb_28)
              *day=action = 28;
            else
             {
               *day=action = DAY_MIN;
               (*month)++;
             }
          }
       }
      else
        if (days_of_february (year) == 28)
         {
           if (rc_feb_29_to_feb_28)
             *day=action = 28;
           else
            {
              *day=action = DAY_MIN;
              (*month)++;
            }
         }
      if (   (warning_level >= 0)
          && action)
       {
         *s5 = '\0';
         print_text (stderr, s5);
         action = (int)strlen(filename) + 100;
         if ((Uint)action >= maxlen_max)
           resize_all_strings (action+1, __FILE__, (long)__LINE__);
#  if USE_GER
         sprintf(s5, "Schalttag auf `%02d-%s' gesetzt in Datei `%s'.",
                 *day, month_name (*month), filename);
#  else /* !USE_GER */
         sprintf(s5, _("Leap-day set to `%02d-%s' in file `%s'."),
                 *day, month_name (*month), filename);
#  endif /* !USE_GER */
         print_text (stderr, s5);
#  if USE_GER
         sprintf(s5, "Zeile %ld: %s", line_number, line_buffer);
#  else /* !USE_GER */
         sprintf(s5, _("Line %ld: %s"), line_number, line_buffer);
#  endif /* !USE_GER */
         print_text (stderr, s5);
       }
    }
}



   LOCAL void
dvar_warning (exit_status, dvar, filename, line_number, text)
   const int   exit_status;
   const char  dvar;
   const char *filename;
   const long  line_number;
   const char *text;
/*
   Prints a warning message in case an operation on a date variable is invalid
     and terminates program if `warning_level' is set to "MAX" amount.
*/
{
   register int  i;


   *s5 = '\0';
   print_text (stderr, s5);
   i = (int)strlen(filename) + 100;
   if ((Uint)i >= maxlen_max)
     resize_all_strings (i+1, __FILE__, (long)__LINE__);
   switch (exit_status)
    {
      case 113:
#  if USE_GER
        sprintf(s5, "Datumvariable `%c' undefiniert in Datei `%s'.", dvar, filename);
#  else /* !USE_GER */
        sprintf(s5, _("Date variable `%c' undefined in file `%s'."), dvar, filename);
#  endif /* !USE_GER */
        break;
      case 112:
#  if USE_GER
        sprintf(s5, "Datumwert ung"UE"ltig (Variable `%c') in Datei `%s'.", dvar, filename);
#  else /* !USE_GER */
        sprintf(s5, _("Invalid date value (variable `%c') in file `%s'."), dvar, filename);
#  endif /* !USE_GER */
        break;
      default:
        /*
           This case MUST be an internal error!
        */
        abort();
    }
   print_text (stderr, s5);
   i = (int)strlen(text) + 100;
   if ((Uint)i >= maxlen_max)
     resize_all_strings (i+1, __FILE__, (long)__LINE__);
#  if USE_GER
   if (!line_number)
     sprintf(s5, "Argument `%s' in Kommandozeile ignoriert", text);
   else
     sprintf(s5, "Zeile %ld ignoriert: %s", line_number, text);
#  else /* !USE_GER */
   if (!line_number)
     sprintf(s5, _("Argument `%s' of command line ignored"), text);
   else
     sprintf(s5, _("Line %ld ignored: %s"), line_number, text);
#  endif /* !USE_GER */
   print_text (stderr, s5);
   if (warning_level >= WARN_LVL_MAX)
    {
#  if USE_GER
      strcpy(s5, "Abbruch!");
#  else /* !USE_GER */
      strcpy(s5, _("Abort!"));
#  endif /* !USE_GER */
      print_text (stderr, s5);
      exit(exit_status);
    }
}
#endif /* USE_RC */
