1 /*!
2 *  \file txt2gcal.c
3 *  \brief Creates a verbatim Gcal resource file from a text file.
4 */
5 /*
6 *  Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 *  2009, 2010, 2011, 2013, 2014 Free Software Foundation, Inc.
8 *  Copyright (c) 1996, 1997, 2000 Thomas Esken
9 *
10 *  This software doesn't claim completeness, correctness or usability.
11 *  On principle I will not be liable for ANY damages or losses (implicit
12 *  or explicit), which result from using or handling my software.
13 *  If you use this software, you agree without any exception to this
14 *  agreement, which binds you LEGALLY !!
15 *
16 *  This program is free software; you can redistribute it and/or modify
17 *  it under the terms of the `GNU General Public License' as published by
18 *  the `Free Software Foundation'; either version 3, or (at your option)
19 *  any later version.
20 *
21 *  You should have received a copy of the `GNU General Public License'
22 *  along with this program; if not, write to the:
23 *
24 */
25 
26 
27 #include "tailor.h"
28 #if HAVE_ASSERT_H
29 # include <assert.h>
30 #endif
31 #if HAVE_CTYPE_H
32 # include <ctype.h>
33 #endif
34 #if HAVE_ERRNO_H
35 # include <errno.h>
36 #endif
37 #if (!HAVE_SIGNAL_H || !HAVE_SIGNAL) && HAVE_SYS_TYPES_H
38 /* Otherwise "gcal.h" includes <sys/types.h>. */
39 # include <sys/types.h>
40 #endif
41 #if HAVE_SYS_STAT_H
42 # include <sys/stat.h>
43 #endif
44 #ifndef USE_RC
45 # define USE_RC  1
46 #else
47 # if !USE_RC
48 #  undef  USE_RC
49 #  define USE_RC  1
50 # endif
51 #endif
52 #include "common.h"
53 #include "rc-defs.h"
54 #include "txt2gcal.h"
55 
56 
57 
58 /*
59 *  static functions prototypes.
60 */
61 __BEGIN_DECLARATIONS
62   static void
63   usage_msg __P_ ((FILE * fp, const char *prgr_name, int exit_status));
64 static void
65   version_msg __P_ ((FILE * fp, const char *prgr_name, int exit_status));
66 static VOID_PTR
67   my_malloc __P_ ((const int amount,
68 		   const int exit_status,
69 		   const char *module_name,
70 		   const long module_line,
71 		   const char *var_name, const int var_contents));
72 static VOID_PTR
73   my_realloc __P_ ((VOID_PTR ptr_memblock,
74 		    const int amount,
75 		    const int exit_status,
76 		    const char *module_name,
77 		    const long module_line,
78 		    const char *var_name, const int var_contents));
79 static void
80   my_error __P_ ((const int exit_status,
81 		  const char *module_name,
82 		  const long module_line,
83 		  const char *var_name, const int var_contents));
84 #if HAVE_SIGNAL && (defined(SIGINT) || defined(SIGTERM) || defined(SIGHUP))
85 static RETSIGTYPE handle_signal __P_ ((int the_signal));
86 #endif
87 #if !HAVE_STRNCASECMP
88 static int my_strncasecmp __P_ ((const char *s1, const char *s2, int len));
89 #endif /* !HAVE_STRNCASECMP */
90 static char *decode_format __P_ ((FILE * fp,
91 				  Bool * is_eof,
92 				  int *flen, int *fwidth, int *ch));
93 __END_DECLARATIONS
94 /*
95 *  static variables definitions.
96 */
97 #ifdef DJG
98 /*! Set to SHRT_MAX for checking the maximum table range. */
99 static Usint testval = (Usint) 0;
100 #else
101 /*! Set to INT_MAX for checking the maximum table range. */
102 static Uint testval = (Uint) 0;
103 #endif
104 
105 /*! Actual length of all strings. */
106 static Uint maxlen_max = MAXLEN_MAX;
107 
108 /*! The name of this executable. */
109 static char *prgr_name = (char *) NULL;
110 
111 /*! Text of `--help' option name. */
112 static char *help_option_name = "help";
113 
114 /*! Text of `--version' option name. */
115 static char *version_option_name = "version";
116 
117 
118 
119 /*
120 *  Function implementations.
121 */
122 static void
usage_msg(fp,prgr_name,exit_status)123 usage_msg (fp, prgr_name, exit_status)
124      FILE *fp;
125      const char *prgr_name;
126      int exit_status;
127 /*!
128    Writes the program "usage" text to file `fp' and
129      terminates the program with `exit_status'.
130 */
131 {
132   fprintf (fp, _("Usage:  %s  [--%s | --%s] | [TEXT-FILE | -] [DATE-PART]\n"),
133 	   prgr_name, help_option_name, version_option_name);
134   if (exit_status == EXIT_SUCCESS)
135     {
136       S_NEWLINE (fp);
137       fprintf (fp, _("Email bug reports to <%s>"), BUG_REPORT_ADR1);
138       S_NEWLINE (fp);
139     }
140   exit (exit_status);
141 }
142 
143 
144 
145 static void
version_msg(fp,prgr_name,exit_status)146 version_msg (fp, prgr_name, exit_status)
147      FILE *fp;
148      const char *prgr_name;
149      int exit_status;
150 /*!
151    Writes the program "version" text to file `fp' and
152      terminates the program with `exit_status'.
153 */
154 {
155   fprintf (fp, "%s (GNU cal %s)\n", prgr_name, PACKAGE_VERSION);
156   fprintf (fp, "%s\n", COPYRIGHT_TXT);
157   fprintf (fp,
158 	   _
159 	   ("This is free software; see the source for copying conditions."));
160   S_NEWLINE (fp);
161   fprintf (fp,
162 	   _("There is NO warranty, without even the implied warranty of"));
163   S_NEWLINE (fp);
164   fprintf (fp, _("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."));
165   S_NEWLINE (fp);
166   exit (exit_status);
167 }
168 
169 
170 
171 static VOID_PTR
my_malloc(amount,exit_status,module_name,module_line,var_name,var_contents)172 my_malloc (amount, exit_status, module_name, module_line, var_name,
173 	   var_contents)
174      const int amount;
175      const int exit_status;
176      const char *module_name;
177      const long module_line;
178      const char *var_name;
179      const int var_contents;
180 /*!
181    Allocate AMOUNT bytes of memory dynamically, with error checking.
182      Calls `my_error()' and terminates the program if any errors occur.
183      AMOUNT is limited to `int' range instead of `size_t' range;
184      this is wanted!
185 */
186 {
187   auto VOID_PTR ptr_memblock;
188 
189 
190   if ((Uint) amount > testval)
191     /*
192        Error, table size overflow!
193      */
194     my_error (ERR_INTERNAL_TABLE_CRASH, module_name, module_line, var_name,
195 	      (int) testval);
196   ptr_memblock = (VOID_PTR) malloc ((int) amount);
197   if (ptr_memblock == (VOID_PTR) NULL)
198     /*
199        Error, `malloc()' failed.
200      */
201     my_error (exit_status, module_name, module_line, var_name, var_contents);
202 
203   return (ptr_memblock);
204 }
205 
206 
207 
208 static VOID_PTR
my_realloc(ptr_memblock,amount,exit_status,module_name,module_line,var_name,var_contents)209 my_realloc (ptr_memblock, amount, exit_status, module_name, module_line,
210 	    var_name, var_contents)
211      VOID_PTR ptr_memblock;
212      const int amount;
213      const int exit_status;
214      const char *module_name;
215      const long module_line;
216      const char *var_name;
217      const int var_contents;
218 /*!
219    Change the size of an allocated block of memory PTR_MEMBLOCK to AMOUNT
220      bytes, with error checking.  Calls `my_error()' and terminates the program
221      if any errors occur.  AMOUNT is limited to `int' range instead of `size_t'
222      range; this is wanted!  If PTR_MEMBLOCK is NULL, `my_malloc()' is called
223      instead.
224 */
225 {
226   if ((Uint) amount > testval)
227     /*
228        Error, table size overflow!
229      */
230     my_error (ERR_INTERNAL_TABLE_CRASH, module_name, module_line, var_name,
231 	      (int) testval);
232   if (ptr_memblock == (VOID_PTR) NULL)
233     return (my_malloc
234 	    (amount, exit_status, module_name, module_line, var_name,
235 	     var_contents));
236   ptr_memblock = (VOID_PTR) realloc (ptr_memblock, (int) amount);
237   if (ptr_memblock == (VOID_PTR) NULL)
238     /*
239        Error, `realloc()' failed.
240      */
241     my_error (exit_status, module_name, module_line, var_name, var_contents);
242 
243   return (ptr_memblock);
244 }
245 
246 
247 
248 static void
my_error(exit_status,module_name,module_line,var_name,var_contents)249 my_error (exit_status, module_name, module_line, var_name, var_contents)
250      const int exit_status;
251      const char *module_name;
252      const long module_line;
253      const char *var_name;
254      const int var_contents;
255 /*!
256    Displays a specific error message on STDERR channel
257      and terminates the program with status `exit_status'.
258 */
259 {
260   fprintf (stderr, _("\n%s: abort, "), prgr_name);
261   switch (exit_status)
262     {
263     case ERR_NO_MEMORY_AVAILABLE:
264       fprintf (stderr, _("`%s' line %ld: virtual memory exhausted (%s=%d)"),
265 	       module_name, module_line, var_name, var_contents);
266       break;
267     case ERR_INTERNAL_TABLE_CRASH:
268       fprintf (stderr,
269 	       _
270 	       ("`%s' line %ld: (`%s') invalid value for table size `sizeof %s>%d'"),
271 	       module_name, module_line, _("internal"), var_name,
272 	       var_contents);
273       break;
274     default:
275       fprintf (stderr, _("`%s' line %ld: (`%s') unmanaged error (%d)"),
276 	       module_name, module_line, _("internal"), exit_status);
277     }
278   S_NEWLINE (stderr);
279   exit (exit_status);
280 }
281 
282 
283 
284 #if HAVE_SIGNAL && (defined(SIGINT) || defined(SIGTERM) || defined(SIGHUP))
285 static RETSIGTYPE
handle_signal(the_signal)286 handle_signal (the_signal)
287      int the_signal;
288 /*!
289    Signal handler function which displays the numeric ID of the
290      received signal on STDERR channel and terminates the program
291      with ERR_TERMINATION_BY_SIGNAL exit status.
292 */
293 {
294   fflush (stdout);
295   fprintf (stderr, _("\n%s: program aborted by signal %d\n"), prgr_name,
296 	   the_signal);
297   exit (ERR_TERMINATION_BY_SIGNAL);
298 }
299 #endif /* HAVE_SIGNAL && (SIGINT || SIGTERM || SIGHUP) */
300 
301 
302 
303 #if !HAVE_STRNCASECMP
304 static int
my_strncasecmp(s1,s2,len)305 my_strncasecmp (s1, s2, len)
306      const char *s1;
307      const char *s2;
308      int len;
309 /*!
310    Same as the ANSI C `strncmp()' function, but case insensitive.
311 */
312 {
313   auto const Uchar *p1 = (const Uchar *) s1;
314   auto const Uchar *p2 = (const Uchar *) s2;
315   auto Uchar c1;
316   auto Uchar c2;
317 
318 
319   if (!len || p1 == p2)
320     return (0);
321   if (len < 0)
322     len = -len;
323   do
324     {
325       c1 = tolower (*p1++);
326       c2 = tolower (*p2++);
327       if (!c1 || c1 != c2)
328 	return (c1 - c2);
329     }
330   while (--len);
331 
332   return (c1 - c2);
333 }
334 #endif /* !HAVE_STRNCASECMP */
335 
336 
337 
338 static char *
decode_format(fp,is_eof,flen,fwidth,ch)339 decode_format (fp, is_eof, flen, fwidth, ch)
340      FILE *fp;
341      Bool *is_eof;
342      int *flen;
343      int *fwidth;
344      int *ch;
345 /*!
346    Simplified check for an optional format instruction taken from `fp' stream
347      which can either be used in case a TVAR or a `%...' special text is
348      referenced. The template of such a format is:
349      [ ALIGNMENT [SIGN] [LZERO] WIDTH [STYLE] [SUFFIX] FORMAT ],
350      e.g., $[<|:|>[+][0]N[u|U|l|L|w|W][&]*|#]TVAR, resp.,
351      %[<|:|>[+][0]N[u|U|l|L|w|W][&]*|#]?, like `$:+010u&#a' or `%>20l&*Y'.
352      ALIGNMENT: '<' == adjusts field contents at the left margin using width WIDTH.
353                 ':' == adjusts field contents in centered manner using width WIDTH.
354                 '>' == ajdusts field contents at the right margin using width WIDTH.
355      SIGN     : '+' == leads a numerical value always by its sign.
356      LZERO    : '0' == fills a numerical value up to WIDTH leading zeroes
357                        inclusivly a possibly leading explicit SIGN or
358                        an implicitly leading negative sign.
359      WIDTH    : FWIDTH_MIN...FWIDTH_MAX == is the width of the field.
360      STYLE    : 'u' == converts field contents to upper-case letters.
361                 'l' == converts field contents to lower-case letters.
362                 'w' == converts field contents to capitalized words.
363      SUFFIX   : '&' == provides a numerical value with an ordinal number suffix.
364      FORMAT   : '*' == does not cut the field contents after
365                        position WIDTH if it is longer than WIDTH.
366                 '#' == cuts the field contents after
367                        position WIDTH if it is longer than WIDTH.
368    This function returns the scanned format instruction inclusive the TVAR
369      resp., %... special text character, its length in `&flen' , and on
370      success, a value not equal SPECIAL_VALUE in `&fwidth'.  `&fwidth' is set
371      to SPECIAL_VALUE in case an error occurs during the scan of the format
372      instruction.  `&is_eof' is set to TRUE if END_OF_FILE is detected during
373      the scan, otherwise it is set to FALSE.  `&ch' contains the
374      last character scanned.
375 */
376 {
377   static int the_len = 0;
378   static char *format_txt;
379   auto char *ptr_char;
380   static Bool is_allocated = FALSE;
381 
382 
383   *is_eof = FALSE;
384   *flen = 0;
385   *fwidth = SPECIAL_VALUE;
386   /*
387      Allocate the memory area of the returned `format_txt' string.
388    */
389   if (!is_allocated)
390     {
391       is_allocated = TRUE;
392       /*
393          Detect the number of digits of FWIDTH_MAX.
394        */
395       *ch = FWIDTH_MAX;
396       while (*ch)
397 	{
398 	  the_len++;
399 	  *ch /= 10;
400 	}
401       /*
402          Initial memory allocation for the `format_txt' string, which is:
403          ALIGNMENT + [SIGN] + [LZERO] + WIDTH   + [STYLE] + [SUFFIX] + FORMAT + CHAR + TERMINATOR
404          1 + [1+]     [1+]    + the_len + [1+]    + [1+]       1      + 1    + 1
405          ==> 7 + 1('\0' terminator) + the_len(FWIDTH_MAX==up to 3 digits)
406          ==> 11 characters maximum.
407        */
408       format_txt = (char *) my_malloc (the_len + 8, ERR_NO_MEMORY_AVAILABLE,
409 				       __FILE__, ((long) __LINE__) - 1L,
410 				       "format_txt", 0);
411     }
412   ptr_char = format_txt;
413   /*
414      Start scanning the format instruction.
415    */
416   *ch = fgetc (fp);
417   *ptr_char++ = (char) *ch;
418   (*flen)++;
419   switch (*ch)
420     {
421     case FLEFT_CHAR:
422     case FCENTER_CHAR:
423     case FRIGHT_CHAR:
424       if ((*ch = fgetc (fp)) == EOF)
425 	{
426 	  *is_eof = TRUE;
427 	  *ptr_char = '\0';
428 	  return (format_txt);
429 	}
430       break;
431     default:
432       *ptr_char = '\0';
433       return (format_txt);
434     }
435   if (*ch == FSIGN_CHAR)
436     {
437       *ptr_char++ = (char) *ch;
438       (*flen)++;
439       if ((*ch = fgetc (fp)) == EOF)
440 	{
441 	  *is_eof = TRUE;
442 	  *ptr_char = '\0';
443 	  return (format_txt);
444 	}
445     }
446   if (*ch == FLZERO_CHAR)
447     {
448       *ptr_char++ = (char) *ch;
449       (*flen)++;
450       if ((*ch = fgetc (fp)) == EOF)
451 	{
452 	  *is_eof = TRUE;
453 	  *ptr_char = '\0';
454 	  return (format_txt);
455 	}
456     }
457   if (isdigit (*ch))
458     {
459       if (*ch != FLZERO_CHAR)
460 	{
461 	  register int len = the_len;
462 
463 
464 	  LOOP
465 	  {
466 	    if (isdigit (*ch))
467 	      {
468 		*ptr_char++ = (char) *ch;
469 		(*flen)++;
470 		if (!--len)
471 		  {
472 		    if ((*ch = fgetc (fp)) == EOF)
473 		      {
474 			*is_eof = TRUE;
475 			*ptr_char = '\0';
476 			return (format_txt);
477 		      }
478 		    break;
479 		  }
480 	      }
481 	    else
482 	      break;
483 	    if ((*ch = fgetc (fp)) == EOF)
484 	      {
485 		*is_eof = TRUE;
486 		*ptr_char = '\0';
487 		return (format_txt);
488 	      }
489 	  }
490 	  *fwidth = 0;
491 	  if (toupper (*ch) == toupper (FUPPER_CHAR)
492 	      || toupper (*ch) == toupper (FLOWER_CHAR)
493 	      || toupper (*ch) == toupper (FWORD_CHAR))
494 	    {
495 	      *ptr_char++ = (char) *ch;
496 	      (*flen)++;
497 	      if ((*ch = fgetc (fp)) == EOF)
498 		{
499 		  *is_eof = TRUE;
500 		  *fwidth = SPECIAL_VALUE;
501 		  *ptr_char = '\0';
502 		  return (format_txt);
503 		}
504 	    }
505 	  if (*ch == FSUFFIX_CHAR)
506 	    {
507 	      *ptr_char++ = (char) *ch;
508 	      (*flen)++;
509 	      if ((*ch = fgetc (fp)) == EOF)
510 		{
511 		  *is_eof = TRUE;
512 		  *fwidth = SPECIAL_VALUE;
513 		  *ptr_char = '\0';
514 		  return (format_txt);
515 		}
516 	    }
517 	  switch (*ch)
518 	    {
519 	    case FFIX_CHAR:
520 	    case FVAR_CHAR:
521 	      *ptr_char++ = (char) *ch;
522 	      (*flen)++;
523 	      if ((*ch = fgetc (fp)) == EOF)
524 		{
525 		  *is_eof = TRUE;
526 		  *fwidth = SPECIAL_VALUE;
527 		}
528 	      *ptr_char++ = (char) *ch;
529 	      (*flen)++;
530 	      break;
531 	    default:
532 	      *ptr_char++ = (char) *ch;
533 	      (*flen)++;
534 	      *fwidth = SPECIAL_VALUE;
535 	    }
536 	}
537       else
538 	{
539 	  *ptr_char++ = (char) *ch;
540 	  (*flen)++;
541 	}
542     }
543   *ptr_char = '\0';
544 
545   return (format_txt);
546 }
547 
548 
549 
550 int
main(argc,argv)551 main (argc, argv)
552      int argc;
553      char *argv[];
554 /*!
555    Creates a verbatim Gcal resource file from a given text file
556      (optional argument 1) with a given date-part (optional argument 2) and
557      displays the results on the STDOUT channel.  If no text file name
558      or only a dash '-' is given, read input from STDIN channel.
559 */
560 {
561   auto FILE *fp = (FILE *) NULL;
562   register int i;
563   register int ch;
564   register int ch2;
565   register int ch3 = '\0';
566   auto int flen;
567   auto int fwidth;
568   auto int last_char = '\0';
569   auto char *s1;
570   auto char *ptr_char;
571   auto Bool is_eof = FALSE;
572   auto Bool is_regular_file = TRUE;
573   auto Bool avoid_quote_char = FALSE;
574   auto Bool is_trailing_whitespace = FALSE;
575 
576 
577 #ifdef GCAL_NLS
578   /*
579      Now initialize the NLS functions.
580    */
581 # if HAVE_SETLOCALE
582   setlocale (LC_ALL, "");
583 # endif
584 # ifndef LOCALEDIR
585 #  define LOCALEDIR  NULL
586 # endif
587   bindtextdomain (PACKAGE, LOCALEDIR);
588   textdomain (PACKAGE);
589 #endif
590   /*
591      Let's set `testval' to SHRT_MAX/INT_MAX if SHRT_MAX/INT_MAX itself isn't
592      defined.  This solution only works on machines with internal arithmethics
593      based on "two complements".
594    */
595 #ifdef DJG
596 # ifdef SHRT_MAX
597   testval = SHRT_MAX;
598 # else /* !SHRT_MAX */
599   testval = ~0;
600   testval >>= 1;
601 # endif	/* !SHRT_MAX */
602 #else /* !DJG */
603 # ifdef INT_MAX
604   testval = INT_MAX;
605 # else /* !INT_MAX */
606   testval = ~0;
607   testval >>= 1;
608 # endif	/* !INT_MAX */
609 #endif /* !DJG */
610 #if HAVE_ASSERT_H
611   /*
612      To ensure safe program operations,
613      MAXLEN_MAX must be 1024 minimum and `testval' maximum!
614    */
615   assert (MAXLEN_MAX >= 1024);
616   assert ((Uint) MAXLEN_MAX <= testval);
617   assert (strlen (PACKAGE_VERSION) > 0);
618 #endif /* HAVE_ASSERT_H */
619   /*
620      Initial memory allocation for the `s1' string.
621    */
622   s1 = (char *) my_malloc (MAXLEN_MAX, ERR_NO_MEMORY_AVAILABLE,
623 			   __FILE__, ((long) __LINE__) - 1L, "s1", 0);
624   /*
625      Detect the own program name.
626    */
627   i = (int) strlen (*argv);
628   if ((Uint) i >= maxlen_max)
629     s1 = my_realloc ((VOID_PTR) s1,
630 		     i + 1, ERR_NO_MEMORY_AVAILABLE,
631 		     __FILE__, ((long) __LINE__) - 2L, "s1", i + 1);
632   strcpy (s1, *argv);
633 #ifdef SUFFIX_SEP
634   /*
635      Eliminate version suffix under VMS.
636    */
637   ptr_char = strrchr (s1, *SUFFIX_SEP);
638   if (ptr_char != (char *) NULL)
639     *ptr_char = '\0';
640 #endif
641   i = (int) strlen (s1);
642 #ifdef DJG
643   ptr_char = strrchr (s1, *DIR2_SEP);
644 #else /* !DJG */
645   ptr_char = strrchr (s1, *DIR_SEP);
646 #endif /* !DJG */
647   if (ptr_char != (char *) NULL)
648     {
649       ptr_char++;
650       i = (int) strlen (ptr_char);
651     }
652   else
653     ptr_char = s1;
654   if (tolower ('A') == 'a')
655     {
656       auto char *buf_ptr_char = ptr_char;
657 
658 
659       for (; *ptr_char; ptr_char++)
660 	*ptr_char = (char) tolower (*ptr_char);
661       ptr_char = buf_ptr_char;
662     }
663   /*
664      Suppress ".exe" suffix for MSDOS, OS/2 and VMS.
665    */
666   if ((i > 4) && !strcmp (ptr_char + i - 4, ".exe"))
667     {
668       i -= 4;
669       *(ptr_char + i) = '\0';
670     }
671   prgr_name = (char *) my_malloc (i + 1, ERR_NO_MEMORY_AVAILABLE,
672 				  __FILE__, ((long) __LINE__) - 1L,
673 				  "prgr_name", 0);
674   strcpy (prgr_name, ptr_char);
675 #if HAVE_SIGNAL
676   /*
677      Now let's modify the signal handling a bit to make sure that
678      temporary files are always deleted if such signals are raised.
679    */
680 # ifdef SIGINT
681   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
682     (void) signal (SIGINT, (Sig_type) handle_signal);
683 # endif
684 # ifdef SIGTERM
685   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
686     (void) signal (SIGTERM, (Sig_type) handle_signal);
687 # endif
688 # ifdef SIGHUP
689   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
690     (void) signal (SIGHUP, (Sig_type) handle_signal);
691 # endif
692 #endif /* HAVE_SIGNAL */
693   if (argc > 1)
694     {
695       if ((strlen (argv[1]) == 1) && (*argv[1] == *SWITCH))
696 	/*
697 	   STDIN channel explicitly wanted!
698 	 */
699 	fp = stdin;
700       else
701 	{
702 	  /*
703 	     Check if `--help' or `--version' long-style option is given.
704 	   */
705 	  if ((strlen (argv[1]) > 2)
706 	      && (*argv[1] == *SWITCH) && (*(argv[1] + 1) == *SWITCH))
707 	    {
708 	      if (!strncasecmp
709 		  (argv[1] + 2, help_option_name, strlen (argv[1] + 2)))
710 		usage_msg (stdout, prgr_name, EXIT_SUCCESS);
711 	      if (!strncasecmp
712 		  (argv[1] + 2, version_option_name, strlen (argv[1] + 2)))
713 		version_msg (stdout, prgr_name, EXIT_SUCCESS);
714 	      /*
715 	         Error, unknown long-style option given.
716 	       */
717 	      fprintf (stderr, _("%s: unrecognized option `%s'"), prgr_name,
718 		       argv[1]);
719 	      S_NEWLINE (stderr);
720 	      usage_msg (stderr, prgr_name, ERR_INVALID_OPTION);
721 	    }
722 	  else
723 	    {
724 #if HAVE_SYS_STAT_H && defined(S_IFMT) && defined(S_IFREG)
725 	      auto struct stat statbuf;
726 
727 
728 	      /*
729 	         Test if the file is a regular file, if not, this is an error!
730 	       */
731 	      if (!stat (argv[1], &statbuf))
732 		{
733 		  if ((statbuf.st_mode & S_IFMT) == S_IFREG)
734 		    fp = fopen (argv[1], "r");
735 		  else
736 		    is_regular_file = FALSE;
737 		}
738 #else /* !HAVE_SYS_STAT_H || !S_IFMT || !S_IFREG */
739 	      fp = fopen (argv[1], "r");
740 #endif /* !HAVE_SYS_STAT_H || !S_IFMT || !S_IFREG */
741 	    }
742 	}
743     }
744   else
745     fp = stdin;
746   if (fp == (FILE *) NULL)
747     {
748       i = (int) strlen (prgr_name) + strlen (argv[1]) + 5;
749       if ((Uint) i >= maxlen_max)
750 	s1 = (char *) my_realloc ((VOID_PTR) s1, i + 1,
751 				  ERR_NO_MEMORY_AVAILABLE,
752 				  __FILE__, ((long) __LINE__) - 2, "s1", 0);
753       sprintf (s1, "%s: `%s' ", prgr_name, argv[1]);
754 #if HAVE_ERRNO_H
755       if (!is_regular_file)
756 	fprintf (stderr, _("%s: no regular file\n"), s1);
757       else
758 	perror (s1);
759       exit (EXIT_FAILURE);
760 #else /* !HAVE_ERRNO_H */
761       fprintf (stderr, _("%s: file not found\n"), s1);
762       exit (ERR_FILE_NOT_FOUND);
763 #endif /* !HAVE_ERRNO_H */
764     }
765   /*
766      Write "date"-part of resource file line.
767    */
768   if (argc > 2)
769     fprintf (stdout, "%s ", argv[2]);
770   else
771     fputs ("0 ", stdout);
772   while ((ch = ch2 = fgetc (fp)) != EOF)
773     {
774       switch (ch)
775 	{
776 	case QUOTE_CHAR:
777 	  ch2 = fgetc (fp);
778 	  if (ch2 != EOF)
779 	    switch (ch2)
780 	      {
781 	      case '\n':
782 		fprintf (stdout, "%c %c%c%c", ch, RC_NL_CHAR, ch, ch2);
783 		break;
784 	      case RC_NL_CHAR:
785 	      case RC_NL2_CHAR:
786 	      case RC_TVAR_CHAR:
787 	      case RC_SPECIAL_TEXT_CHAR:
788 		fprintf (stdout, "%c%c%c", ch, ch, ch2);
789 		break;
790 	      default:
791 		fprintf (stdout, "%c%c", ch, ch2);
792 	      }
793 	  else
794 	    fputc (ch, stdout);
795 	  break;
796 	case RC_TVAR_CHAR:
797 	  ptr_char = decode_format (fp, &is_eof, &flen, &fwidth, &last_char);
798 	  if (!is_eof)
799 	    {
800 	      ch2 = *(ptr_char + flen - 1);
801 	      if ((isalpha (ch2)
802 		   && (fwidth != SPECIAL_VALUE
803 		       || *ptr_char == ch2)) || ch3 == QUOTE_CHAR)
804 		fputc (QUOTE_CHAR, stdout);
805 	      *(ptr_char + flen - 1) = '\0';
806 	      switch (ch2)
807 		{
808 		case RC_NL_CHAR:
809 		case RC_NL2_CHAR:
810 		  fprintf (stdout, "%c%c%c", ch, QUOTE_CHAR, ch2);
811 		  break;
812 		case RC_SPECIAL_TEXT_CHAR:
813 		case RC_TVAR_CHAR:
814 		  if (*ptr_char)
815 		    fprintf (stdout, "%c%s", ch, ptr_char);
816 		  else
817 		    fputc (ch, stdout);
818 		  ungetc (ch2, fp);
819 		  break;
820 		case '\n':
821 		  if (*ptr_char)
822 		    fprintf (stdout, "%c%s%c%c%c", ch, ptr_char, RC_NL_CHAR,
823 			     QUOTE_CHAR, ch2);
824 		  else
825 		    fprintf (stdout, "%c%c%c%c", ch, RC_NL_CHAR, QUOTE_CHAR,
826 			     ch2);
827 		  if (!ch3)
828 		    avoid_quote_char = TRUE;
829 		  break;
830 		default:
831 		  if (*ptr_char)
832 		    fprintf (stdout, "%c%s%c", ch, ptr_char, ch2);
833 		  else
834 		    fprintf (stdout, "%c%c", ch, ch2);
835 		  if (!ch3)
836 		    avoid_quote_char = TRUE;
837 		  if (ch2 != last_char)
838 		    ungetc (last_char, fp);
839 		}
840 	    }
841 	  else
842 	    fputc (ch, stdout);
843 	  break;
844 	case RC_SPECIAL_TEXT_CHAR:
845 	  ptr_char = decode_format (fp, &is_eof, &flen, &fwidth, &last_char);
846 	  if (!is_eof)
847 	    {
848 	      ch2 = *(ptr_char + flen - 1);
849 	      switch (ch2)
850 		{
851 		case RC_SHELL_ESC_CHAR:
852 		case RC_ENV_VAR_CHAR:
853 		case RC_EX_LHDY_CHAR:
854 		case RC_EX_NLHDY_CHAR:
855 		case RC_EX_AHDY_CHAR:
856 		case RC_EX_NAHDY_CHAR:
857 		case RC_EX_MON_CHAR:
858 		case RC_EX_NMON_CHAR:
859 		case RC_EX_TUE_CHAR:
860 		case RC_EX_NTUE_CHAR:
861 		case RC_EX_WED_CHAR:
862 		case RC_EX_NWED_CHAR:
863 		case RC_EX_THU_CHAR:
864 		case RC_EX_NTHU_CHAR:
865 		case RC_EX_FRI_CHAR:
866 		case RC_EX_NFRI_CHAR:
867 		case RC_EX_SAT_CHAR:
868 		case RC_EX_NSAT_CHAR:
869 		case RC_EX_SUN_CHAR:
870 		case RC_EX_NSUN_CHAR:
871 		case RC_EX_MON_2_THU_CHAR:
872 		case RC_EX_NMON_2_THU_CHAR:
873 		case RC_EX_MON_2_FRI_CHAR:
874 		case RC_EX_NMON_2_FRI_CHAR:
875 		case RC_IDATE_CHAR:
876 		case RC_EDATE_CHAR:
877 		case RC_WDNAME_CHAR:
878 		case RC_WDNR_M1_2_S7_CHAR:
879 		case RC_WDNR_M0_2_S6_CHAR:
880 		case RC_WDNR_S1_2_S7_CHAR:
881 		case RC_WDNR_S0_2_S6_CHAR:
882 		case RC_WDNR_X1_2_X7_CHAR:
883 		case RC_WDNR_X0_2_X6_CHAR:
884 		case RC_DOYNR_CHAR:
885 		case RC_DAYNR_CHAR:
886 		case RC_MONTHNAME_CHAR:
887 		case RC_MONTHNR_CHAR:
888 		case RC_YEARNR_CHAR:
889 		case RC_WEEKNR_CHAR:
890 		case RC_BYEAR_CHAR:
891 		case RC_MOON_CHAR:
892 		case RC_MOON_IMAGE_CHAR:
893 		case RC_BIO_CHAR:
894 		case RC_BIO_BAR_CHAR:
895 		case RC_TDATE_CHAR:
896 		case RC_JDAYS_CHAR:
897 		case RC_TIME_CHAR:
898 		case RC_TIME_TMI_CHAR:
899 		case RC_TIME_HR_CHAR:
900 		case RC_TIME_MI_CHAR:
901 		case RC_TIME_AMPM_CHAR:
902 		case RC_GMTIME_CHAR:
903 		case RC_GMTIME_TMI_CHAR:
904 		case RC_GMTIME_HR_CHAR:
905 		case RC_GMTIME_MI_CHAR:
906 		case RC_GMTIME_AMPM_CHAR:
907 		case RC_LT_ZONE_OFFS_CHAR:
908 		case RC_UT_ZONE_OFFS_CHAR:
909 		case RC_DISTANCE_CHAR:
910 		case RC_SUN_RISE_CHAR:
911 		case RC_SUN_SET_CHAR:
912 		case RC_SUN_DAY_CHAR:
913 		case RC_SUN_NIGHT_CHAR:
914 		case RC_MOON_RISE_CHAR:
915 		case RC_MOON_SET_CHAR:
916 		case RC_MOON_DAY_CHAR:
917 		case RC_MOON_NIGHT_CHAR:
918 		case RC_DAY_DIFF_CHAR:
919 		case RC_WEEK_DIFF_CHAR:
920 		case RC_MONTH_DIFF_CHAR:
921 		case RC_YEAR_DIFF_CHAR:
922 		case RC_HLS1S_CHAR:
923 		case RC_HLS1E_CHAR:
924 		case RC_HLS2S_CHAR:
925 		case RC_HLS2E_CHAR:
926 		case RC_HLS3S_CHAR:
927 		case RC_HLS3E_CHAR:
928 		case RC_HLS4S_CHAR:
929 		case RC_HLS4E_CHAR:
930 		case RC_HLS5S_CHAR:
931 		case RC_HLS5E_CHAR:
932 		  if (fwidth != SPECIAL_VALUE || *ptr_char == ch2)
933 		    fputc (QUOTE_CHAR, stdout);
934 		  ch3 = '\0';
935 		  /* Fallthrough. */
936 		default:
937 		  if (ch3 == QUOTE_CHAR)
938 		    fputc (QUOTE_CHAR, stdout);
939 		  *(ptr_char + flen - 1) = '\0';
940 		  switch (ch2)
941 		    {
942 		    case RC_NL_CHAR:
943 		    case RC_NL2_CHAR:
944 		      fprintf (stdout, "%c%c%c", ch, QUOTE_CHAR, ch2);
945 		      break;
946 		    case RC_SPECIAL_TEXT_CHAR:
947 		    case RC_TVAR_CHAR:
948 		      if (*ptr_char)
949 			fprintf (stdout, "%c%s", ch, ptr_char);
950 		      else
951 			fputc (ch, stdout);
952 		      ungetc (ch2, fp);
953 		      break;
954 		    case '\n':
955 		      if (*ptr_char)
956 			fprintf (stdout, "%c%s%c%c%c", ch, ptr_char,
957 				 RC_NL_CHAR, QUOTE_CHAR, ch2);
958 		      else
959 			fprintf (stdout, "%c%c%c%c", ch, RC_NL_CHAR,
960 				 QUOTE_CHAR, ch2);
961 		      if (!ch3)
962 			avoid_quote_char = TRUE;
963 		      break;
964 		    default:
965 		      if (*ptr_char)
966 			fprintf (stdout, "%c%s%c", ch, ptr_char, ch2);
967 		      else
968 			fprintf (stdout, "%c%c", ch, ch2);
969 		      if (!ch3)
970 			avoid_quote_char = TRUE;
971 		      if (ch2 != last_char)
972 			ungetc (last_char, fp);
973 		    }
974 		}
975 	    }
976 	  else
977 	    fputc (ch, stdout);
978 	  break;
979 	case RC_NL_CHAR:
980 	case RC_NL2_CHAR:
981 	  fputc (QUOTE_CHAR, stdout);
982 	  /* Fallthrough. */
983 	default:
984 	  switch (ch)
985 	    {
986 	    case '\n':
987 	      ch2 = fgetc (fp);
988 	      if (ch2 != EOF)
989 		{
990 		  switch (ch3)
991 		    {
992 		    case QUOTE_CHAR:
993 		      fprintf (stdout, " %c%c%c", RC_NL_CHAR, ch3, ch);
994 		      break;
995 		    default:
996 		      fprintf (stdout, "%c%c%c", RC_NL_CHAR, QUOTE_CHAR, ch);
997 		      if (!ch3)
998 			avoid_quote_char = TRUE;
999 		    }
1000 		  ungetc (ch2, fp);
1001 		}
1002 	      break;
1003 	    default:
1004 	      if (isspace (ch)
1005 		  && !avoid_quote_char && !is_trailing_whitespace)
1006 		fputc (QUOTE_CHAR, stdout);
1007 	      is_trailing_whitespace = TRUE;
1008 	      fputc (ch, stdout);
1009 	    }
1010 	}
1011       if (is_eof)
1012 	break;
1013       ch3 = ch2;
1014     }
1015   (void) fclose (fp);
1016 
1017   exit (EXIT_SUCCESS);
1018 }
1019