1 /*!
2 *  \file tcal.c
3 *  \brief Start `gcal' with date set ONE day ahead
4 *
5 *  (default mode, like the `--shift=1' long-style option is passed to it).
6 *  Useful if you call this program in `~/.profile' and you want to see all
7 *  fixed dates related to tomorrow + 1 day (advanced  -ct respectively
8 *  --period-of-fixed-dates=t  option).  Works *only* for Gregorian years!
9 */
10 /*
11 *  Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
12 *  2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
13 *  Copyright (c) 1995, 96, 1997, 2000 Thomas Esken
14 *
15 *  This software doesn't claim completeness, correctness or usability.
16 *  On principle I will not be liable for ANY damages or losses (implicit
17 *  or explicit), which result from using or handling my software.
18 *  If you use this software, you agree without any exception to this
19 *  agreement, which binds you LEGALLY !!
20 *
21 *  This program is free software; you can redistribute it and/or modify
22 *  it under the terms of the `GNU General Public License' as published by
23 *  the `Free Software Foundation'; either version 3, or (at your option)
24 *  any later version.
25 *
26 *  You should have received a copy of the `GNU General Public License'
27 *  along with this program; if not, write to the:
28 *
29 */
30 
31 
32 /*
33 *  Include header files.
34 */
35 #include "tailor.h"
36 #if HAVE_ASSERT_H
37 # include <assert.h>
38 #endif
39 #if HAVE_CTYPE_H
40 # include <ctype.h>
41 #endif
42 #if HAVE_UNISTD_H
43 # include <unistd.h>
44 #endif
45 #if HAVE_LIMITS_H
46 # include <limits.h>
47 #endif
48 #if HAVE_ERRNO_H
49 # include <errno.h>
50 #endif
51 #if (!HAVE_SIGNAL_H || !HAVE_SIGNAL) && HAVE_SYS_TYPES_H
52 /* Otherwise "gcal.h" includes <sys/types.h>. */
53 # include <sys/types.h>
54 #endif
55 #if HAVE_SYS_STAT_H
56 # include <sys/stat.h>
57 #endif
58 #if TIME_WITH_SYS_TIME
59 # include <sys/time.h>
60 # include <time.h>
61 #else /* !TIME_WITH_SYS_TIME */
62 # if HAVE_SYS_TIME_H
63 #  include <sys/time.h>
64 # else /* !HAVE_SYS_TIME_H */
65 #  include <time.h>
66 # endif	/* !HAVE_SYS_TIME_H */
67 #endif /* !TIME_WITH_SYS_TIME */
68 #ifdef MSDOS
69 # include <process.h>
70 #endif
71 #ifndef USE_RC
72 # define USE_RC  1
73 #else
74 # if !USE_RC
75 #  undef  USE_RC
76 #  define USE_RC  1
77 # endif
78 #endif
79 #include "common.h"
80 #include "rc-defs.h"
81 #include "tcal.h"
82 
83 
84 
85 /*
86 *  static functions prototypes.
87 */
88 __BEGIN_DECLARATIONS
89   static void
90   usage_msg __P_ ((FILE * fp, const char *prgr_name, int exit_status));
91 static void
92   version_msg __P_ ((FILE * fp, const char *prgr_name, int exit_status));
93 static VOID_PTR
94   my_malloc __P_ ((const int amount,
95 		   const int exit_status,
96 		   const char *module_name,
97 		   const long module_line,
98 		   const char *var_name, const int var_contents));
99 static VOID_PTR
100   my_realloc __P_ ((VOID_PTR ptr_memblock,
101 		    const int amount,
102 		    const int exit_status,
103 		    const char *module_name,
104 		    const long module_line,
105 		    const char *var_name, const int var_contents));
106 static void
107   my_error __P_ ((const int exit_status,
108 		  const char *module_name,
109 		  const long module_line,
110 		  const char *var_name, const int var_contents));
111 #if HAVE_SIGNAL && (defined(SIGINT) || defined(SIGTERM) || defined(SIGHUP))
112 static RETSIGTYPE handle_signal __P_ ((int the_signal));
113 #endif
114 #if !HAVE_STRNCASECMP
115 static int my_strncasecmp __P_ ((const char *s1, const char *s2, int len));
116 #endif /* !HAVE_STRNCASECMP */
117 static int days_of_february __P_ ((const int year));
118 static Bool
119   doy2date __P_ ((int doy, const int is_leap_year, int *day, int *month));
120 static Ulint date2num __P_ ((const int day, const int month, const int year));
121 static void num2date __P_ ((Ulint mjd, int *day, int *month, int *year));
122 static void get_actual_date __P_ ((int *day, int *month, int *year));
123 __END_DECLARATIONS
124 /*
125 *  static variables definitions.
126 */
127 /*!
128    Number of days in months.
129 */
130 static const int dvec[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
131 
132 /*!
133    Number of past days of month.
134 */
135 static const int mvec[] =
136   { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
137 
138 /*!
139    The Gregorian Reformation dates table is an unterminated vector
140      of `Greg_struct'.
141 */
142 static Greg_struct greg_reform_date[] = {
143 /*
144   { int year, int month, int f_day, int l_day },
145 */
146   {1582, 10, 5, 14},
147   {1752, 9, 3, 13}
148 };
149 
150 /*! Points to the used Gregorian Reformation date. */
151 static Greg_struct *greg = greg_reform_date;
152 
153 #ifdef DJG
154 /*! Set to SHRT_MAX for checking the maximum table range. */
155 static Usint testval = (Usint) 0;
156 #else
157 /*! Set to INT_MAX for checking the maximum table range. */
158 static Uint testval = (Uint) 0;
159 #endif
160 
161 /*! Actual length of all strings. */
162 static Uint maxlen_max = MAXLEN_MAX;
163 
164 /*! The name of this executable. */
165 static char *prgr_name = (char *) NULL;
166 
167 /*! Text of `--help' option name. */
168 static char *help_option_name = "help";
169 
170 /*! Text of `--version' option name. */
171 static char *version_option_name = "version";
172 
173 /*! Text of `--shift' option name. */
174 static char *shift_option_name = "shift";
175 
176 
177 
178 /*
179 *  Function implementations.
180 */
181 static void
usage_msg(fp,prgr_name,exit_status)182 usage_msg (fp, prgr_name, exit_status)
183      FILE *fp;
184      const char *prgr_name;
185      int exit_status;
186 /*!
187    Writes the program "usage" text to file `fp' and
188      terminates the program with `exit_status'.
189 */
190 {
191   fprintf (fp,
192 	   _
193 	   ("Usage:  %s  [--%s | --%s] | [--%s=[+|-]NUMBER] [ARGUMENT...]\n"),
194 	   prgr_name, help_option_name, version_option_name,
195 	   shift_option_name);
196   if (exit_status == EXIT_SUCCESS)
197     {
198       S_NEWLINE (fp);
199       fprintf (fp, _("Email bug reports to <%s>"), BUG_REPORT_ADR1);
200       S_NEWLINE (fp);
201     }
202   exit (exit_status);
203 }
204 
205 
206 
207 static void
version_msg(fp,prgr_name,exit_status)208 version_msg (fp, prgr_name, exit_status)
209      FILE *fp;
210      const char *prgr_name;
211      int exit_status;
212 /*!
213    Writes the program "version" text to file `fp' and
214      terminates the program with `exit_status'.
215 */
216 {
217   fprintf (fp, "%s (GNU cal %s)\n", prgr_name, PACKAGE_VERSION);
218   fprintf (fp, "%s\n", COPYRIGHT_TXT);
219   fprintf (fp,
220 	   _
221 	   ("This is free software; see the source for copying conditions."));
222   S_NEWLINE (fp);
223   fprintf (fp,
224 	   _("There is NO warranty, without even the implied warranty of"));
225   S_NEWLINE (fp);
226   fprintf (fp, _("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."));
227   S_NEWLINE (fp);
228   exit (exit_status);
229 }
230 
231 
232 
233 static VOID_PTR
my_malloc(amount,exit_status,module_name,module_line,var_name,var_contents)234 my_malloc (amount, exit_status, module_name, module_line, var_name,
235 	   var_contents)
236      const int amount;
237      const int exit_status;
238      const char *module_name;
239      const long module_line;
240      const char *var_name;
241      const int var_contents;
242 /*!
243    Allocate AMOUNT bytes of memory dynamically, with error checking.
244      Calls `my_error()' and terminates the program if any errors occur.
245      AMOUNT is limited to `int' range instead of `size_t' range;
246      this is wanted!
247 */
248 {
249   auto VOID_PTR ptr_memblock;
250 
251 
252   if ((Uint) amount > testval)
253     /*
254        Error, table size overflow!
255      */
256     my_error (ERR_INTERNAL_TABLE_CRASH, module_name, module_line, var_name,
257 	      (int) testval);
258   ptr_memblock = (VOID_PTR) malloc ((int) amount);
259   if (ptr_memblock == (VOID_PTR) NULL)
260     /*
261        Error, `malloc()' function failed.
262      */
263     my_error (exit_status, module_name, module_line, var_name, var_contents);
264 
265   return (ptr_memblock);
266 }
267 
268 
269 
270 static VOID_PTR
my_realloc(ptr_memblock,amount,exit_status,module_name,module_line,var_name,var_contents)271 my_realloc (ptr_memblock, amount, exit_status, module_name, module_line,
272 	    var_name, var_contents)
273      VOID_PTR ptr_memblock;
274      const int amount;
275      const int exit_status;
276      const char *module_name;
277      const long module_line;
278      const char *var_name;
279      const int var_contents;
280 /*!
281    Change the size of an allocated block of memory PTR_MEMBLOCK to AMOUNT
282      bytes, with error checking.  Calls `my_error()' and terminates the program
283      if any errors occur.  AMOUNT is limited to `int' range instead of `size_t'
284      range; this is wanted!  If PTR_MEMBLOCK is NULL, `my_malloc()' is called
285      instead.
286 */
287 {
288   if ((Uint) amount > testval)
289     /*
290        Error, table size overflow!
291      */
292     my_error (ERR_INTERNAL_TABLE_CRASH, module_name, module_line, var_name,
293 	      (int) testval);
294   if (ptr_memblock == (VOID_PTR) NULL)
295     return (my_malloc
296 	    (amount, exit_status, module_name, module_line, var_name,
297 	     var_contents));
298   ptr_memblock = (VOID_PTR) realloc (ptr_memblock, (int) amount);
299   if (ptr_memblock == (VOID_PTR) NULL)
300     /*
301        Error, `realloc()' function failed.
302      */
303     my_error (exit_status, module_name, module_line, var_name, var_contents);
304 
305   return (ptr_memblock);
306 }
307 
308 
309 
310 static void
my_error(exit_status,module_name,module_line,var_name,var_contents)311 my_error (exit_status, module_name, module_line, var_name, var_contents)
312      const int exit_status;
313      const char *module_name;
314      const long module_line;
315      const char *var_name;
316      const int var_contents;
317 /*!
318    Displays a specific error message on STDERR channel
319      and terminates the program with status `exit_status'.
320 */
321 {
322   fprintf (stderr, _("\n%s: abort, "), prgr_name);
323   switch (exit_status)
324     {
325     case ERR_NO_MEMORY_AVAILABLE:
326       fprintf (stderr, _("`%s' line %ld: virtual memory exhausted (%s=%d)"),
327 	       module_name, module_line, var_name, var_contents);
328       break;
329     case ERR_INTERNAL_TABLE_CRASH:
330       fprintf (stderr,
331 	       _
332 	       ("`%s' line %ld: (`%s') invalid value for table size `sizeof %s>%d'"),
333 	       module_name, module_line, _("internal"), var_name,
334 	       var_contents);
335       break;
336     case EXIT_FATAL:
337       fprintf (stderr, _("shift value `%s' is invalid"), var_name);
338       break;
339     default:
340       fprintf (stderr, _("`%s' line %ld: (`%s') unmanaged error (%d)"),
341 	       module_name, module_line, _("internal"), exit_status);
342     }
343   S_NEWLINE (stderr);
344   exit (exit_status);
345 }
346 
347 
348 
349 #if HAVE_SIGNAL && (defined(SIGINT) || defined(SIGTERM) || defined(SIGHUP))
350 static RETSIGTYPE
handle_signal(the_signal)351 handle_signal (the_signal)
352      int the_signal;
353 /*!
354    Signal handler function which displays the numeric ID of the
355      received signal on STDERR channel and terminates the program
356      with ERR_TERMINATION_BY_SIGNAL exit status.
357 */
358 {
359   fflush (stdout);
360   fprintf (stderr, _("\n%s: program aborted by signal %d\n"), prgr_name,
361 	   the_signal);
362   exit (ERR_TERMINATION_BY_SIGNAL);
363 }
364 #endif /* HAVE_SIGNAL && (SIGINT || SIGTERM || SIGHUP) */
365 
366 
367 
368 #if !HAVE_STRNCASECMP
369 static int
my_strncasecmp(s1,s2,len)370 my_strncasecmp (s1, s2, len)
371      const char *s1;
372      const char *s2;
373      int len;
374 /*!
375    Same as the ANSI C `strncmp()' function, but case insensitive.
376 */
377 {
378   auto const Uchar *p1 = (const Uchar *) s1;
379   auto const Uchar *p2 = (const Uchar *) s2;
380   auto Uchar c1;
381   auto Uchar c2;
382 
383 
384   if (!len || p1 == p2)
385     return (0);
386   if (len < 0)
387     len = -len;
388   do
389     {
390       c1 = tolower (*p1++);
391       c2 = tolower (*p2++);
392       if (!c1 || c1 != c2)
393 	return (c1 - c2);
394     }
395   while (--len);
396 
397   return (c1 - c2);
398 }
399 #endif /* !HAVE_STRNCASECMP */
400 
401 
402 
403 static int
days_of_february(year)404 days_of_february (year)
405      const int year;
406 /*!
407    Computes the number of days in February --- respecting
408      the Gregorian Reformation period --- and returns them.
409 */
410 {
411   register int day;
412 
413 
414   if ((year > greg->year)
415       || ((year == greg->year)
416 	  && (greg->month == 1
417 	      || ((greg->month == 2) && (greg->last_day >= 28)))))
418     day = (year & 3) ? 28 : ((!(year % 100) && (year % 400)) ? 28 : 29);
419   else
420     day = (year & 3) ? 28 : 29;
421   /*
422      Exception, the year 4 AD was historically NO leap year!
423    */
424   if (year == 4)
425     day--;
426 
427   return (day);
428 }
429 
430 
431 
432 static Bool
doy2date(doy,is_leap_year,day,month)433 doy2date (doy, is_leap_year, day, month)
434      int doy;
435      const int is_leap_year;
436      int *day;
437      int *month;
438 /*!
439    Converts a given number of days of a year to a standard date
440      (returned in &day and &month) and returns:
441        TRUE in case the `day_of_year' number is valid;
442        FALSE otherwise.
443 */
444 {
445   register int i;
446   auto Bool decrement_date;
447 
448 
449   if (doy > DAY_LAST + is_leap_year || doy < DAY_MIN)
450     return (FALSE);
451   decrement_date = (Bool) (is_leap_year && (doy > mvec[2]));
452   if (decrement_date)
453     doy--;
454   for (i = MONTH_MIN; i < MONTH_MAX; i++)
455     {
456       doy -= dvec[i - 1];
457       if (doy <= 0)
458 	{
459 	  doy += dvec[i - 1];
460 	  break;
461 	}
462     }
463   *month = i;
464   *day = doy;
465   if (decrement_date && (*month == 2) && (*day == 28))
466     (*day)++;
467 
468   return (TRUE);
469 }
470 
471 
472 
473 static Ulint
date2num(day,month,year)474 date2num (day, month, year)
475      const int day;
476      const int month;
477      const int year;
478 /*!
479    Computes the absolute number of days of the given date since
480      00010101(==YYYYMMDD) respecting the missing period of the
481      Gregorian Reformation.
482 */
483 {
484   auto Ulint mjd =
485     (Ulint) ((year - 1) * (Ulint) (DAY_LAST) + ((year - 1) >> 2));
486 
487 
488   if (year > greg->year
489       || ((year == greg->year)
490 	  && (month > greg->month
491 	      || ((month == greg->month) && (day > greg->last_day)))))
492     mjd -= (Ulint) (greg->last_day - greg->first_day + 1);
493   if (year > greg->year)
494     {
495       mjd += (((year - 1) / 400) - (greg->year / 400));
496       mjd -= (((year - 1) / 100) - (greg->year / 100));
497       if (!(greg->year % 100) && (greg->year % 400))
498 	mjd--;
499     }
500   mjd += (Ulint) mvec[month - 1];
501   mjd += day;
502   if ((days_of_february (year) == 29) && (month > 2))
503     mjd++;
504 
505   return (mjd);
506 }
507 
508 
509 
510 static void
num2date(mjd,day,month,year)511 num2date (mjd, day, month, year)
512      Ulint mjd;
513      int *day;
514      int *month;
515      int *year;
516 /*!
517    Converts a delivered absolute number of days `mjd' to a standard
518      date (since 00010101(==YYYYMMDD), returned in &day, &month and &year)
519      respecting the missing period of the Gregorian Reformation.
520 */
521 {
522   auto double x;
523   auto Ulint jdays = date2num (greg->first_day - 1, greg->month, greg->year);
524   register int i;
525 
526 
527   if (mjd > jdays)
528     mjd += (Ulint) (greg->last_day - greg->first_day + 1);
529   x = (double) mjd / (DAY_LAST + 0.25);
530   i = (int) x;
531   if ((double) i != x)
532     *year = i + 1;
533   else
534     {
535       *year = i;
536       i--;
537     }
538   if (mjd > jdays)
539     {
540       /*
541          Correction for Gregorian years.
542        */
543       mjd -= (Ulint) ((*year / 400) - (greg->year / 400));
544       mjd += (Ulint) ((*year / 100) - (greg->year / 100));
545       x = (double) mjd / (DAY_LAST + 0.25);
546       i = (int) x;
547       if ((double) i != x)
548 	*year = i + 1;
549       else
550 	{
551 	  *year = i;
552 	  i--;
553 	}
554       if ((*year % 400) && !(*year % 100))
555 	mjd--;
556     }
557   i = (int) (mjd - (Ulint) (i * (DAY_LAST + 0.25)));
558   /*
559      Correction for Gregorian centuries.
560    */
561   if ((*year > greg->year)
562       && (*year % 400)
563       && !(*year % 100)
564       && (i <
565 	  ((*year / 100) - (greg->year / 100)) - ((*year / 400) -
566 						  (greg->year / 400))))
567     i++;
568   (void) doy2date (i, (days_of_february (*year) == 29), day, month);
569 }
570 
571 
572 
573 static void
get_actual_date(day,month,year)574 get_actual_date (day, month, year)
575      int *day;
576      int *month;
577      int *year;
578 /*!
579    Gets the actual date from the system.
580 */
581 {
582   auto struct tm *sys_date;
583   auto MY_TIME_T sys_time;
584 
585 
586   sys_time = time ((MY_TIME_T *) NULL);
587   sys_date = localtime (&sys_time);
588   *day = sys_date->tm_mday;
589   *month = sys_date->tm_mon + 1;
590   *year = sys_date->tm_year;
591   if (*year < CENTURY)
592     *year += CENTURY;
593 }
594 
595 
596 
597 int
main(argc,argv)598 main (argc, argv)
599      int argc;
600      char *argv[];
601 /*!
602    Starts Gcal with date set one day ahead (default mode, like the `--shift=1'
603      long-style option is passed to it) and all other arguments which are given
604      in the command line.  The program first tries to use the `gcal' executable
605      which is specified in the environment variable $GCALPROG if it is set,
606      otherwise it will be searched using the $PATH environment variable.
607 */
608 {
609   auto Ulint the_date;
610   auto Slint shift_value = (Slint) CHR2DIG (*SHIFT_VALUE_DEFAULT);
611   register Uint my_argc_max = MY_ARGC_MAX;
612   register int my_argc = 0;
613   register int len_year_max;
614   register int i;
615   register int arg_len;
616   register int status;
617   auto int day;
618   auto int month;
619   auto int year;
620   auto char **my_argv = (char **) NULL;
621   auto char *s1;
622   auto char *gcal_prgr;
623   auto char *ptr_char;
624   auto char *buf_ptr_char;
625   auto Bool shift_value_set = FALSE;
626 #if defined(GCAL_NLS)
627   auto Bool is_en = FALSE;
628 #endif
629 
630 
631   /*
632      Let's set `testval' to SHRT_MAX/INT_MAX if SHRT_MAX/INT_MAX itself
633      isn't defined.  This solution only works on machines with internal
634      arithmethics based on "two complements".
635    */
636 #ifdef DJG
637 # ifdef SHRT_MAX
638   testval = SHRT_MAX;
639 # else /* !SHRT_MAX */
640   testval = ~0;
641   testval >>= 1;
642 # endif	/* !SHRT_MAX */
643 #else /* !DJG */
644 # ifdef INT_MAX
645   testval = INT_MAX;
646 # else /* !INT_MAX */
647   testval = ~0;
648   testval >>= 1;
649 # endif	/* !INT_MAX */
650 #endif /* !DJG */
651 #if HAVE_ASSERT_H
652   /*
653      To ensure safe program operations,
654      MAXLEN_MAX must be 1024 minimum and `testval' maximum!
655    */
656   assert (MAXLEN_MAX >= 1024);
657   assert ((Uint) MAXLEN_MAX <= testval);
658 #endif
659   /*
660      Initial memory allocation for the `s1' string.
661    */
662   s1 = (char *) my_malloc (MAXLEN_MAX, ERR_NO_MEMORY_AVAILABLE,
663 			   __FILE__, ((long) __LINE__) - 1L, "s1", 0);
664   /*
665      Compute the string length of the maximum year able to compute.
666    */
667   sprintf (s1, "%d", YEAR_MAX);
668   len_year_max = (int) strlen (s1);
669   /*
670      Perform some more assertations for safe program operation.
671    */
672 #if HAVE_ASSERT_H
673   /*
674      Check if value for maximum number of table entries
675      fits to the positive range of a signed int (SHRT_MAX/INT_MAX)!
676    */
677   assert (len_year_max < 11);
678   assert (len_year_max > 0);
679   assert (YEAR_MAX >= YEAR_MIN);
680   assert (MONTH_MAX == 12);
681   assert (CENTURY == 1900);
682   assert (strlen (PACKAGE_NAME) > 0);
683   assert (strlen (PACKAGE_VERSION) > 0);
684   assert (MY_ARGC_MAX > 1);
685   assert ((Uint) MY_ARGC_MAX <= testval);
686 #endif /* HAVE_ASSERT_H */
687 #ifdef GCAL_NLS
688   /*
689      Now initialize the NLS functions.
690    */
691 #if HAVE_SETLOCALE
692   setlocale (LC_ALL, "");
693 # endif
694 # ifndef LOCALEDIR
695 #  define LOCALEDIR  NULL
696 # endif
697   bindtextdomain (PACKAGE, LOCALEDIR);
698   textdomain (PACKAGE);
699   /*
700      Now check whether we have to use the Gregorian Reformation date of 1752
701      (table index 1 !!) by default!
702    */
703 # if !defined(AMIGA) || defined(__GNUC__)
704   /*
705      Detect whether the $LANGUAGE environment variable (GNU specific) is set.
706    */
707   ptr_char = getenv (ENV_VAR_LANGUAGE);
708   if (ptr_char != (char *) NULL)
709     if (!*ptr_char)
710       ptr_char = (char *) NULL;
711   if (ptr_char == (char *) NULL)
712     {
713       /*
714          Detect whether the $LC_ALL environment variable is set.
715        */
716       ptr_char = getenv (ENV_VAR_LC_ALL);
717       if (ptr_char != (char *) NULL)
718 	if (!*ptr_char)
719 	  ptr_char = (char *) NULL;
720     }
721 #  if HAVE_LC_MESSAGES
722   if (ptr_char == (char *) NULL)
723     {
724       /*
725          Detect whether the $LC_MESSAGES environment variable is set.
726        */
727       ptr_char = getenv (ENV_VAR_LC_MESSAGES);
728       if (ptr_char != (char *) NULL)
729 	if (!*ptr_char)
730 	  ptr_char = (char *) NULL;
731     }
732 #  endif
733   if (ptr_char == (char *) NULL)
734     {
735       /*
736          Detect whether the $LANG environment variable is set.
737        */
738       ptr_char = getenv (ENV_VAR_LANG);
739       if (ptr_char != (char *) NULL)
740 	if (!*ptr_char)
741 	  ptr_char = (char *) NULL;
742     }
743   /*
744      Now check the kind of territory specifics we have to use!
745    */
746   if (ptr_char != (char *) NULL)
747     {
748       if (*ptr_char)
749 	{
750 	  strncpy (s1, ptr_char, 6);
751 	  s1[5] = '\0';
752 	  if (!strncasecmp (s1, "en", 2))
753 	    /*
754 	       We have to use the Gregorian Reformation date of 1752 (table index 1 !!).
755 	     */
756 	    is_en = TRUE;
757 	  else
758 	    /*
759 	       Hmm... We have to check whether the special settings "C" or
760 	       "POSIX" are given, if so, we have to use the Gregorian
761 	       Reformation date of 1752 (table index 1 !!).
762 	     */
763 	  if (!strncasecmp (s1, "posix", 5) || !strcasecmp (s1, "c"))
764 	    is_en = TRUE;
765 	}
766       else
767 	/*
768 	   Environment variable defined but not set, hmm...
769 	   Let's use the Gregorian Reformation date of 1752 (table index 1 !!).
770 	 */
771 	is_en = TRUE;
772     }
773   else
774     /*
775        No environment variable defined.
776      */
777 # endif /* !AMIGA || __GNUC__ */
778     /*
779        Let's use the Gregorian Reformation date of 1752 (table index 1 !!).
780      */
781     is_en = TRUE;
782   if (is_en)
783     /*
784        Set the date of Gregorian Reformation to 1752 (table index 1 !!)
785      */
786     greg++;
787 #else /* !GCAL_NLS */
788   /*
789      Set the date of Gregorian Reformation to 1752 (table index 1 !!)
790    */
791   greg++;
792 #endif	/* !GCAL_NLS */
793   /*
794      Detect the own program name.
795    */
796   i = (int) strlen (*argv);
797   if ((Uint) i >= maxlen_max)
798     s1 = my_realloc ((VOID_PTR) s1,
799 		     i + 1, ERR_NO_MEMORY_AVAILABLE,
800 		     __FILE__, ((long) __LINE__) - 2L, "s1", i + 1);
801   strcpy (s1, *argv);
802 #ifdef SUFFIX_SEP
803   /*
804      Eliminate version suffix under VMS.
805    */
806   ptr_char = strrchr (s1, *SUFFIX_SEP);
807   if (ptr_char != (char *) NULL)
808     *ptr_char = '\0';
809 #endif
810   i = (int) strlen (s1);
811 #ifdef DJG
812   ptr_char = strrchr (s1, *DIR2_SEP);
813 #else /* !DJG */
814   ptr_char = strrchr (s1, *DIR_SEP);
815 #endif /* !DJG */
816   if (ptr_char != (char *) NULL)
817     {
818       ptr_char++;
819       i = (int) strlen (ptr_char);
820     }
821   else
822     ptr_char = s1;
823   if (tolower ('A') == 'a')
824     {
825       buf_ptr_char = ptr_char;
826       for (; *ptr_char; ptr_char++)
827 	*ptr_char = (char) tolower (*ptr_char);
828       ptr_char = buf_ptr_char;
829     }
830   /*
831      Suppress ".exe" suffix for MSDOS, OS/2 and VMS.
832    */
833   if ((i > 4) && !strcmp (ptr_char + i - 4, ".exe"))
834     {
835       i -= 4;
836       *(ptr_char + i) = '\0';
837     }
838   prgr_name = (char *) my_malloc (i + 1, ERR_NO_MEMORY_AVAILABLE,
839 				  __FILE__, ((long) __LINE__) - 1L,
840 				  "prgr_name", 0);
841   strcpy (prgr_name, ptr_char);
842 #if HAVE_SIGNAL
843   /*
844      Now let's modify the signal handling a bit to make sure that
845      temporary files are always deleted if such signals are raised.
846    */
847 # ifdef SIGINT
848   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
849     (void) signal (SIGINT, (Sig_type) handle_signal);
850 # endif
851 # ifdef SIGTERM
852   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
853     (void) signal (SIGTERM, (Sig_type) handle_signal);
854 # endif
855 # ifdef SIGHUP
856   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
857     (void) signal (SIGHUP, (Sig_type) handle_signal);
858 # endif
859 #endif /* HAVE_SIGNAL */
860   buf_ptr_char = SHIFT_VALUE_DEFAULT;
861   if (argc > 1)
862     {
863       /*
864          Check if `--help', `--version' or `--shift=[+|-]NUMBER'
865          long-style option is given.
866        */
867       arg_len = (int) strlen (argv[1]) - 2;
868       if ((arg_len > 0)
869 	  && (*argv[1] == *SWITCH) && (*(argv[1] + 1) == *SWITCH))
870 	{
871 	  auto Bool is_number = TRUE;
872 
873 
874 	  if (!strncasecmp (argv[1] + 2, help_option_name, arg_len))
875 	    usage_msg (stdout, prgr_name, EXIT_SUCCESS);
876 	  if (!strncasecmp (argv[1] + 2, version_option_name, arg_len))
877 	    version_msg (stdout, prgr_name, EXIT_SUCCESS);
878 	  if (!strncasecmp (argv[1] + 2, shift_option_name, 3))
879 	    {
880 	      ptr_char = strchr (argv[1] + 2, *LARG_SEP);
881 	      if (ptr_char != (char *) NULL)
882 		i = (int) (ptr_char - (argv[1] + 2));
883 	      else
884 		i = arg_len;
885 	      switch (i)
886 		{
887 		case 3:
888 		case 4:
889 		case 5:
890 		  if (!strncasecmp (argv[1] + 2, shift_option_name, i))
891 		    break;
892 		  /* Fallthrough. */
893 		default:
894 		  /*
895 		     Error, unrecognized option.
896 		   */
897 		  fprintf (stderr, _("%s: unrecognized option `%s'"),
898 			   prgr_name, argv[1]);
899 		  S_NEWLINE (stderr);
900 		  usage_msg (stderr, prgr_name, ERR_INVALID_OPTION);
901 		}
902 	      if (ptr_char == (char *) NULL
903 		  || ((ptr_char != (char *) NULL) && !*(ptr_char + 1)))
904 		{
905 		  /*
906 		     Error, option requires an argument.
907 		   */
908 		  fprintf (stderr,
909 			   _("%s: option `--%s' requires an argument"),
910 			   prgr_name, shift_option_name);
911 		  S_NEWLINE (stderr);
912 		  usage_msg (stderr, prgr_name, ERR_INVALID_OPTION);
913 		}
914 	      else
915 		{
916 		  /*
917 		     Let's get the argument of the `--shift=[+|-]NUMBER'
918 		     long-style option.
919 		   */
920 		  ptr_char++;
921 		  shift_value = atol (ptr_char);
922 		  /*
923 		     Check if the argument is a NUMBER.
924 		   */
925 		  buf_ptr_char = ptr_char;
926 		  if (*ptr_char == '+' || *ptr_char == '-')
927 		    ptr_char++;
928 		  if (!*ptr_char)
929 		    is_number = FALSE;
930 		  else
931 		    {
932 		      while (isdigit (*ptr_char))
933 			ptr_char++;
934 		      if (*ptr_char)
935 			is_number = FALSE;
936 		    }
937 		  if (!is_number)
938 		    {
939 		      /*
940 		         Error, invalid argument.
941 		       */
942 		      fprintf (stderr,
943 			       _("%s: option with invalid argument -- %s"),
944 			       prgr_name, argv[1]);
945 		      S_NEWLINE (stderr);
946 		      usage_msg (stderr, prgr_name, ERR_INVALID_OPTION);
947 		    }
948 		  shift_value_set = TRUE;
949 		}
950 	    }
951 	}
952     }
953   /*
954      Detect the name of the Gcal executable.
955    */
956 #if !defined(AMIGA) || defined(__GNUC__)
957   gcal_prgr = getenv (ENV_VAR_GCALPROG);
958   if (gcal_prgr != (char *) NULL)
959     {
960       if (!*gcal_prgr)
961 	gcal_prgr = PACKAGE_NAME;
962     }
963   else
964 #endif /* !AMIGA || __GNUC__ */
965     gcal_prgr = PACKAGE_NAME;
966   /*
967      Get the actual date.
968    */
969   get_actual_date (&day, &month, &year);
970   /*
971      Compute the Julian Day number of the actual date.
972    */
973   the_date = date2num (day, month, year);
974   /*
975      Check if the shifted date is in the right range.
976    */
977   if ((Slint) the_date + shift_value <= 0L
978       || (Slint) the_date + shift_value >
979       (Slint) date2num (dvec[MONTH_MAX - 1], MONTH_MAX, YEAR_MAX))
980     my_error (EXIT_FATAL, "", 0L, buf_ptr_char, 0);
981   /*
982      Now calculate the shifted date (default mode is tomorrow [+1]).
983    */
984   num2date ((Ulint) the_date + shift_value, &day, &month, &year);
985   /*
986      Initial memory allocation for the `my_argv[]' table.
987    */
988   my_argv = (char **) my_malloc (MY_ARGC_MAX * sizeof (char *),
989 				 ERR_NO_MEMORY_AVAILABLE,
990 				 __FILE__, ((long) __LINE__) - 2L,
991 				 "my_argv[MY_ARGC_MAX]", MY_ARGC_MAX);
992   /*
993      Now copy the name of the Gcal executable into `my_argv[]'
994      table at position 0.
995    */
996   my_argv[my_argc] = (char *) my_malloc (strlen (gcal_prgr) + 1,
997 					 ERR_NO_MEMORY_AVAILABLE,
998 					 __FILE__, ((long) __LINE__) - 2L,
999 					 "my_argv[my_argc]", my_argc);
1000   strcpy (my_argv[my_argc++], gcal_prgr);
1001   /*
1002      Now construct and copy the actual date modifier %DATE into `my_argv[]'
1003      table at position 1.
1004    */
1005   sprintf (s1, "%c%0*d%02d%02d", RC_ADATE_CHAR, len_year_max, year, month,
1006 	   day);
1007   my_argv[my_argc] =
1008     (char *) my_malloc (strlen (s1) + 1, ERR_NO_MEMORY_AVAILABLE, __FILE__,
1009 			((long) __LINE__) - 1L, "my_argv[my_argc]", my_argc);
1010   strcpy (my_argv[my_argc++], s1);
1011   /*
1012      Skip the locally respected `--shift=[+|-]NUMBER' long-style option
1013      if given in the command line.
1014    */
1015   if (shift_value_set)
1016     {
1017       argc--;
1018       argv++;
1019     }
1020   /*
1021      Now copy all other command line arguments which are delivered to
1022      the Gcal executable into `my_argv[]' table at position `my_argc'.
1023    */
1024   while (argc > 1)
1025     {
1026       argv++;
1027       if ((Uint) my_argc >= my_argc_max)
1028 	{
1029 	  /*
1030 	     Resize the `my_argv[]' table.
1031 	   */
1032 	  my_argc_max <<= 1;
1033 	  if (my_argc_max * sizeof (char *) > testval)
1034 	    my_argc_max--;
1035 	  my_argv = (char **) my_realloc ((VOID_PTR) my_argv,
1036 					  my_argc_max * sizeof (char *),
1037 					  ERR_NO_MEMORY_AVAILABLE,
1038 					  __FILE__, ((long) __LINE__) - 3L,
1039 					  "my_argv[my_argc_max]",
1040 					  my_argc_max);
1041 	}
1042       my_argv[my_argc] = (char *) my_malloc (strlen (*argv) + 1,
1043 					     ERR_NO_MEMORY_AVAILABLE,
1044 					     __FILE__, ((long) __LINE__) - 2L,
1045 					     "my_argv[my_argc]", my_argc);
1046       strcpy (my_argv[my_argc++], *argv);
1047       argc--;
1048     }
1049   /*
1050      And terminate the `my_argv[]' table by a final NULL element.
1051    */
1052   if ((Uint) my_argc >= my_argc_max)
1053     {
1054       /*
1055          Resize the `my_argv[]' table.
1056        */
1057       my_argc_max <<= 1;
1058       if (my_argc_max * sizeof (char *) > testval)
1059 	my_argc_max--;
1060       my_argv = (char **) my_realloc ((VOID_PTR) my_argv,
1061 				      my_argc_max * sizeof (char *),
1062 				      ERR_NO_MEMORY_AVAILABLE,
1063 				      __FILE__, ((long) __LINE__) - 3L,
1064 				      "my_argv[my_argc_max]", my_argc_max);
1065     }
1066   my_argv[my_argc] = (char *) NULL;
1067   /*
1068      Run the Gcal executable alltogether with the collected arguments.
1069    */
1070   status = execvp (gcal_prgr, my_argv);
1071   if (status == -1)
1072     {
1073       fprintf (stderr, _("%s: error during program execution of `%s'\n"),
1074 	       prgr_name, gcal_prgr);
1075 #if HAVE_ERRNO_H
1076       perror (gcal_prgr);
1077 #endif
1078       exit (ERR_EXTERNAL_CMD_FAILURE);
1079     }
1080 
1081   exit (status);
1082 }
1083