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