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