VirtualBox

source: kBuild/trunk/src/gmake/misc.c@ 930

Last change on this file since 930 was 549, checked in by bird, 18 years ago

Regenerated config.h.os2 and make adjustments to make it all build quietly on OS/2.

  • Property svn:eol-style set to native
File size: 21.2 KB
Line 
1/* Miscellaneous generic support functions for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
31998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
4Foundation, Inc.
5This file is part of GNU Make.
6
7GNU Make is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 2, or (at your option) any later version.
10
11GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16GNU Make; see the file COPYING. If not, write to the Free Software
17Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
18
19#include "make.h"
20#include "dep.h"
21#include "debug.h"
22
23/* All bcopy calls in this file can be replaced by memcpy and save a tick or two. */
24#ifdef CONFIG_WITH_OPTIMIZATION_HACKS
25# undef bcopy
26# if defined(__GNUC__) && defined(CONFIG_WITH_OPTIMIZATION_HACKS)
27# define bcopy(src, dst, size) __builtin_memcpy ((dst), (src), (size))
28# else
29# define bcopy(src, dst, size) memcpy ((dst), (src), (size))
30# endif
31#endif
32
33/* Variadic functions. We go through contortions to allow proper function
34 prototypes for both ANSI and pre-ANSI C compilers, and also for those
35 which support stdarg.h vs. varargs.h, and finally those which have
36 vfprintf(), etc. and those who have _doprnt... or nothing.
37
38 This fancy stuff all came from GNU fileutils, except for the VA_PRINTF and
39 VA_END macros used here since we have multiple print functions. */
40
41#if USE_VARIADIC
42# if HAVE_STDARG_H
43# include <stdarg.h>
44# define VA_START(args, lastarg) va_start(args, lastarg)
45# else
46# include <varargs.h>
47# define VA_START(args, lastarg) va_start(args)
48# endif
49# if HAVE_VPRINTF
50# define VA_PRINTF(fp, lastarg, args) vfprintf((fp), (lastarg), (args))
51# else
52# define VA_PRINTF(fp, lastarg, args) _doprnt((lastarg), (args), (fp))
53# endif
54# define VA_END(args) va_end(args)
55#else
56/* We can't use any variadic interface! */
57# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
58# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
59# define VA_START(args, lastarg)
60# define VA_PRINTF(fp, lastarg, args) fprintf((fp), (lastarg), va_alist)
61# define VA_END(args)
62#endif
63
64
65/* Compare strings *S1 and *S2.
66 Return negative if the first is less, positive if it is greater,
67 zero if they are equal. */
68
69int
70alpha_compare (const void *v1, const void *v2)
71{
72 const char *s1 = *((char **)v1);
73 const char *s2 = *((char **)v2);
74
75 if (*s1 != *s2)
76 return *s1 - *s2;
77 return strcmp (s1, s2);
78}
79
80
81/* Discard each backslash-newline combination from LINE.
82 Backslash-backslash-newline combinations become backslash-newlines.
83 This is done by copying the text at LINE into itself. */
84
85void
86collapse_continuations (char *line)
87{
88 register char *in, *out, *p;
89 register int backslash;
90 register unsigned int bs_write;
91
92 in = strchr (line, '\n');
93 if (in == 0)
94 return;
95
96 out = in;
97 while (out > line && out[-1] == '\\')
98 --out;
99
100 while (*in != '\0')
101 {
102 /* BS_WRITE gets the number of quoted backslashes at
103 the end just before IN, and BACKSLASH gets nonzero
104 if the next character is quoted. */
105 backslash = 0;
106 bs_write = 0;
107 for (p = in - 1; p >= line && *p == '\\'; --p)
108 {
109 if (backslash)
110 ++bs_write;
111 backslash = !backslash;
112
113 /* It should be impossible to go back this far without exiting,
114 but if we do, we can't get the right answer. */
115 if (in == out - 1)
116 abort ();
117 }
118
119 /* Output the appropriate number of backslashes. */
120 while (bs_write-- > 0)
121 *out++ = '\\';
122
123 /* Skip the newline. */
124 ++in;
125
126 /* If the newline is quoted, discard following whitespace
127 and any preceding whitespace; leave just one space. */
128 if (backslash)
129 {
130 in = next_token (in);
131 while (out > line && isblank ((unsigned char)out[-1]))
132 --out;
133 *out++ = ' ';
134 }
135 else
136 /* If the newline isn't quoted, put it in the output. */
137 *out++ = '\n';
138
139 /* Now copy the following line to the output.
140 Stop when we find backslashes followed by a newline. */
141 while (*in != '\0')
142 if (*in == '\\')
143 {
144 p = in + 1;
145 while (*p == '\\')
146 ++p;
147 if (*p == '\n')
148 {
149 in = p;
150 break;
151 }
152 while (in < p)
153 *out++ = *in++;
154 }
155 else
156 *out++ = *in++;
157 }
158
159 *out = '\0';
160}
161
162
163/* Print N spaces (used in debug for target-depth). */
164
165void
166print_spaces (unsigned int n)
167{
168 while (n-- > 0)
169 putchar (' ');
170}
171
172
173
174/* Return a newly-allocated string whose contents
175 concatenate those of s1, s2, s3. */
176
177char *
178concat (const char *s1, const char *s2, const char *s3)
179{
180 unsigned int len1, len2, len3;
181 char *result;
182
183 len1 = *s1 != '\0' ? strlen (s1) : 0;
184 len2 = *s2 != '\0' ? strlen (s2) : 0;
185 len3 = *s3 != '\0' ? strlen (s3) : 0;
186
187 result = (char *) xmalloc (len1 + len2 + len3 + 1);
188
189 if (*s1 != '\0')
190 bcopy (s1, result, len1);
191 if (*s2 != '\0')
192 bcopy (s2, result + len1, len2);
193 if (*s3 != '\0')
194 bcopy (s3, result + len1 + len2, len3);
195 *(result + len1 + len2 + len3) = '\0';
196
197 return result;
198}
199
200
201/* Print a message on stdout. */
202
203void
204#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
205message (int prefix, const char *fmt, ...)
206#else
207message (prefix, fmt, va_alist)
208 int prefix;
209 const char *fmt;
210 va_dcl
211#endif
212{
213#if USE_VARIADIC
214 va_list args;
215#endif
216
217 log_working_directory (1);
218
219 if (fmt != 0)
220 {
221 if (prefix)
222 {
223 if (makelevel == 0)
224 printf ("%s: ", program);
225 else
226 printf ("%s[%u]: ", program, makelevel);
227 }
228 VA_START (args, fmt);
229 VA_PRINTF (stdout, fmt, args);
230 VA_END (args);
231 putchar ('\n');
232 }
233
234 fflush (stdout);
235}
236
237/* Print an error message. */
238
239void
240#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
241error (const struct floc *flocp, const char *fmt, ...)
242#else
243error (flocp, fmt, va_alist)
244 const struct floc *flocp;
245 const char *fmt;
246 va_dcl
247#endif
248{
249#if USE_VARIADIC
250 va_list args;
251#endif
252
253 log_working_directory (1);
254
255 if (flocp && flocp->filenm)
256 fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
257 else if (makelevel == 0)
258 fprintf (stderr, "%s: ", program);
259 else
260 fprintf (stderr, "%s[%u]: ", program, makelevel);
261
262 VA_START(args, fmt);
263 VA_PRINTF (stderr, fmt, args);
264 VA_END (args);
265
266 putc ('\n', stderr);
267 fflush (stderr);
268}
269
270/* Print an error message and exit. */
271
272void
273#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
274fatal (const struct floc *flocp, const char *fmt, ...)
275#else
276fatal (flocp, fmt, va_alist)
277 const struct floc *flocp;
278 const char *fmt;
279 va_dcl
280#endif
281{
282#if USE_VARIADIC
283 va_list args;
284#endif
285
286 log_working_directory (1);
287
288 if (flocp && flocp->filenm)
289 fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno);
290 else if (makelevel == 0)
291 fprintf (stderr, "%s: *** ", program);
292 else
293 fprintf (stderr, "%s[%u]: *** ", program, makelevel);
294
295 VA_START(args, fmt);
296 VA_PRINTF (stderr, fmt, args);
297 VA_END (args);
298
299 fputs (_(". Stop.\n"), stderr);
300
301 die (2);
302}
303
304#ifndef HAVE_STRERROR
305
306#undef strerror
307
308char *
309strerror (int errnum)
310{
311 extern int errno, sys_nerr;
312#ifndef __DECC
313 extern char *sys_errlist[];
314#endif
315 static char buf[] = "Unknown error 12345678901234567890";
316
317 if (errno < sys_nerr)
318 return sys_errlist[errnum];
319
320 sprintf (buf, _("Unknown error %d"), errnum);
321 return buf;
322}
323#endif
324
325/* Print an error message from errno. */
326
327void
328perror_with_name (const char *str, const char *name)
329{
330 error (NILF, _("%s%s: %s"), str, name, strerror (errno));
331}
332
333/* Print an error message from errno and exit. */
334
335void
336pfatal_with_name (const char *name)
337{
338 fatal (NILF, _("%s: %s"), name, strerror (errno));
339
340 /* NOTREACHED */
341}
342
343
344/* Like malloc but get fatal error if memory is exhausted. */
345/* Don't bother if we're using dmalloc; it provides these for us. */
346
347#ifndef HAVE_DMALLOC_H
348
349#undef xmalloc
350#undef xrealloc
351#undef xstrdup
352
353char *
354xmalloc (unsigned int size)
355{
356 /* Make sure we don't allocate 0, for pre-ANSI libraries. */
357 char *result = (char *) malloc (size ? size : 1);
358 if (result == 0)
359 fatal (NILF, _("virtual memory exhausted"));
360 return result;
361}
362
363
364char *
365xrealloc (char *ptr, unsigned int size)
366{
367 char *result;
368
369 /* Some older implementations of realloc() don't conform to ANSI. */
370 if (! size)
371 size = 1;
372 result = ptr ? realloc (ptr, size) : malloc (size);
373 if (result == 0)
374 fatal (NILF, _("virtual memory exhausted"));
375 return result;
376}
377
378
379char *
380xstrdup (const char *ptr)
381{
382 char *result;
383
384#ifdef HAVE_STRDUP
385 result = strdup (ptr);
386#else
387 result = (char *) malloc (strlen (ptr) + 1);
388#endif
389
390 if (result == 0)
391 fatal (NILF, _("virtual memory exhausted"));
392
393#ifdef HAVE_STRDUP
394 return result;
395#else
396 return strcpy(result, ptr);
397#endif
398}
399
400#endif /* HAVE_DMALLOC_H */
401
402char *
403savestring (const char *str, unsigned int length)
404{
405 register char *out = (char *) xmalloc (length + 1);
406 if (length > 0)
407 bcopy (str, out, length);
408 out[length] = '\0';
409 return out;
410}
411
412
413
414#ifndef CONFIG_WITH_OPTIMIZATION_HACKS /* This is really a reimplemntation of
415 memchr, only slower. It's been replaced by a macro in the header file. */
416
417/* Limited INDEX:
418 Search through the string STRING, which ends at LIMIT, for the character C.
419 Returns a pointer to the first occurrence, or nil if none is found.
420 Like INDEX except that the string searched ends where specified
421 instead of at the first null. */
422
423char *
424lindex (const char *s, const char *limit, int c)
425{
426 while (s < limit)
427 if (*s++ == c)
428 return (char *)(s - 1);
429
430 return 0;
431}
432#endif /* CONFIG_WITH_OPTIMIZATION_HACKS */
433
434
435/* Return the address of the first whitespace or null in the string S. */
436
437char *
438end_of_token (const char *s)
439{
440 while (*s != '\0' && !isblank ((unsigned char)*s))
441 ++s;
442 return (char *)s;
443}
444
445#ifdef WINDOWS32
446/*
447 * Same as end_of_token, but take into account a stop character
448 */
449char *
450end_of_token_w32 (char *s, char stopchar)
451{
452 register char *p = s;
453 register int backslash = 0;
454
455 while (*p != '\0' && *p != stopchar
456 && (backslash || !isblank ((unsigned char)*p)))
457 {
458 if (*p++ == '\\')
459 {
460 backslash = !backslash;
461 while (*p == '\\')
462 {
463 backslash = !backslash;
464 ++p;
465 }
466 }
467 else
468 backslash = 0;
469 }
470
471 return p;
472}
473#endif
474
475/* Return the address of the first nonwhitespace or null in the string S. */
476
477char *
478next_token (const char *s)
479{
480 while (isblank ((unsigned char)*s))
481 ++s;
482 return (char *)s;
483}
484
485/* Find the next token in PTR; return the address of it, and store the
486 length of the token into *LENGTHPTR if LENGTHPTR is not nil. */
487
488char *
489find_next_token (char **ptr, unsigned int *lengthptr)
490{
491 char *p = next_token (*ptr);
492 char *end;
493
494 if (*p == '\0')
495 return 0;
496
497 *ptr = end = end_of_token (p);
498 if (lengthptr != 0)
499 *lengthptr = end - p;
500 return p;
501}
502
503
504
505/* Allocate a new `struct dep' with all fields initialized to 0. */
506
507struct dep *
508alloc_dep ()
509{
510 struct dep *d = (struct dep *) xmalloc (sizeof (struct dep));
511 bzero ((char *) d, sizeof (struct dep));
512 return d;
513}
514
515
516/* Free `struct dep' along with `name' and `stem'. */
517
518void
519free_dep (struct dep *d)
520{
521 if (d->name != 0)
522 free (d->name);
523
524 if (d->stem != 0)
525 free (d->stem);
526
527 free ((char *)d);
528}
529
530/* Copy a chain of `struct dep', making a new chain
531 with the same contents as the old one. */
532
533struct dep *
534copy_dep_chain (const struct dep *d)
535{
536 register struct dep *c;
537 struct dep *firstnew = 0;
538 struct dep *lastnew = 0;
539
540 while (d != 0)
541 {
542 c = (struct dep *) xmalloc (sizeof (struct dep));
543 bcopy ((char *) d, (char *) c, sizeof (struct dep));
544
545 if (c->name != 0)
546 c->name = xstrdup (c->name);
547 if (c->stem != 0)
548 c->stem = xstrdup (c->stem);
549
550 c->next = 0;
551 if (firstnew == 0)
552 firstnew = lastnew = c;
553 else
554 lastnew = lastnew->next = c;
555
556 d = d->next;
557 }
558
559 return firstnew;
560}
561
562/* Free a chain of 'struct dep'. */
563
564void
565free_dep_chain (struct dep *d)
566{
567 while (d != 0)
568 {
569 struct dep *df = d;
570 d = d->next;
571 free_dep (df);
572 }
573}
574
575
576/* Free a chain of `struct nameseq'. Each nameseq->name is freed
577 as well. For `struct dep' chains use free_dep_chain. */
578
579void
580free_ns_chain (struct nameseq *n)
581{
582 register struct nameseq *tmp;
583
584 while (n != 0)
585 {
586 if (n->name != 0)
587 free (n->name);
588
589 tmp = n;
590
591 n = n->next;
592
593 free (tmp);
594 }
595
596}
597
598#ifdef iAPX286
599/* The losing compiler on this machine can't handle this macro. */
600
601char *
602dep_name (struct dep *dep)
603{
604 return dep->name == 0 ? dep->file->name : dep->name;
605}
606#endif
607
608
609#ifdef GETLOADAVG_PRIVILEGED
610
611#ifdef POSIX
612
613/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
614 functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
615 for example) which claim to be POSIX.1 also have the BSD setreuid and
616 setregid functions, but they don't work as in BSD and only the POSIX.1
617 way works. */
618
619#undef HAVE_SETREUID
620#undef HAVE_SETREGID
621
622#else /* Not POSIX. */
623
624/* Some POSIX.1 systems have the seteuid and setegid functions. In a
625 POSIX-like system, they are the best thing to use. However, some
626 non-POSIX systems have them too but they do not work in the POSIX style
627 and we must use setreuid and setregid instead. */
628
629#undef HAVE_SETEUID
630#undef HAVE_SETEGID
631
632#endif /* POSIX. */
633
634#ifndef HAVE_UNISTD_H
635extern int getuid (), getgid (), geteuid (), getegid ();
636extern int setuid (), setgid ();
637#ifdef HAVE_SETEUID
638extern int seteuid ();
639#else
640#ifdef HAVE_SETREUID
641extern int setreuid ();
642#endif /* Have setreuid. */
643#endif /* Have seteuid. */
644#ifdef HAVE_SETEGID
645extern int setegid ();
646#else
647#ifdef HAVE_SETREGID
648extern int setregid ();
649#endif /* Have setregid. */
650#endif /* Have setegid. */
651#endif /* No <unistd.h>. */
652
653/* Keep track of the user and group IDs for user- and make- access. */
654static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
655#define access_inited (user_uid != -1)
656static enum { make, user } current_access;
657
658
659/* Under -d, write a message describing the current IDs. */
660
661static void
662log_access (const char *flavor)
663{
664 if (! ISDB (DB_JOBS))
665 return;
666
667 /* All the other debugging messages go to stdout,
668 but we write this one to stderr because it might be
669 run in a child fork whose stdout is piped. */
670
671 fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
672 flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
673 (unsigned long) getegid (), (unsigned long) getgid ());
674 fflush (stderr);
675}
676
677
678static void
679init_access (void)
680{
681#ifndef VMS
682 user_uid = getuid ();
683 user_gid = getgid ();
684
685 make_uid = geteuid ();
686 make_gid = getegid ();
687
688 /* Do these ever fail? */
689 if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
690 pfatal_with_name ("get{e}[gu]id");
691
692 log_access (_("Initialized access"));
693
694 current_access = make;
695#endif
696}
697
698#endif /* GETLOADAVG_PRIVILEGED */
699
700/* Give the process appropriate permissions for access to
701 user data (i.e., to stat files, or to spawn a child process). */
702void
703user_access (void)
704{
705#ifdef GETLOADAVG_PRIVILEGED
706
707 if (!access_inited)
708 init_access ();
709
710 if (current_access == user)
711 return;
712
713 /* We are in "make access" mode. This means that the effective user and
714 group IDs are those of make (if it was installed setuid or setgid).
715 We now want to set the effective user and group IDs to the real IDs,
716 which are the IDs of the process that exec'd make. */
717
718#ifdef HAVE_SETEUID
719
720 /* Modern systems have the seteuid/setegid calls which set only the
721 effective IDs, which is ideal. */
722
723 if (seteuid (user_uid) < 0)
724 pfatal_with_name ("user_access: seteuid");
725
726#else /* Not HAVE_SETEUID. */
727
728#ifndef HAVE_SETREUID
729
730 /* System V has only the setuid/setgid calls to set user/group IDs.
731 There is an effective ID, which can be set by setuid/setgid.
732 It can be set (unless you are root) only to either what it already is
733 (returned by geteuid/getegid, now in make_uid/make_gid),
734 the real ID (return by getuid/getgid, now in user_uid/user_gid),
735 or the saved set ID (what the effective ID was before this set-ID
736 executable (make) was exec'd). */
737
738 if (setuid (user_uid) < 0)
739 pfatal_with_name ("user_access: setuid");
740
741#else /* HAVE_SETREUID. */
742
743 /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
744 They may be set to themselves or each other. So you have two alternatives
745 at any one time. If you use setuid/setgid, the effective will be set to
746 the real, leaving only one alternative. Using setreuid/setregid, however,
747 you can toggle between your two alternatives by swapping the values in a
748 single setreuid or setregid call. */
749
750 if (setreuid (make_uid, user_uid) < 0)
751 pfatal_with_name ("user_access: setreuid");
752
753#endif /* Not HAVE_SETREUID. */
754#endif /* HAVE_SETEUID. */
755
756#ifdef HAVE_SETEGID
757 if (setegid (user_gid) < 0)
758 pfatal_with_name ("user_access: setegid");
759#else
760#ifndef HAVE_SETREGID
761 if (setgid (user_gid) < 0)
762 pfatal_with_name ("user_access: setgid");
763#else
764 if (setregid (make_gid, user_gid) < 0)
765 pfatal_with_name ("user_access: setregid");
766#endif
767#endif
768
769 current_access = user;
770
771 log_access (_("User access"));
772
773#endif /* GETLOADAVG_PRIVILEGED */
774}
775
776/* Give the process appropriate permissions for access to
777 make data (i.e., the load average). */
778void
779make_access (void)
780{
781#ifdef GETLOADAVG_PRIVILEGED
782
783 if (!access_inited)
784 init_access ();
785
786 if (current_access == make)
787 return;
788
789 /* See comments in user_access, above. */
790
791#ifdef HAVE_SETEUID
792 if (seteuid (make_uid) < 0)
793 pfatal_with_name ("make_access: seteuid");
794#else
795#ifndef HAVE_SETREUID
796 if (setuid (make_uid) < 0)
797 pfatal_with_name ("make_access: setuid");
798#else
799 if (setreuid (user_uid, make_uid) < 0)
800 pfatal_with_name ("make_access: setreuid");
801#endif
802#endif
803
804#ifdef HAVE_SETEGID
805 if (setegid (make_gid) < 0)
806 pfatal_with_name ("make_access: setegid");
807#else
808#ifndef HAVE_SETREGID
809 if (setgid (make_gid) < 0)
810 pfatal_with_name ("make_access: setgid");
811#else
812 if (setregid (user_gid, make_gid) < 0)
813 pfatal_with_name ("make_access: setregid");
814#endif
815#endif
816
817 current_access = make;
818
819 log_access (_("Make access"));
820
821#endif /* GETLOADAVG_PRIVILEGED */
822}
823
824/* Give the process appropriate permissions for a child process.
825 This is like user_access, but you can't get back to make_access. */
826void
827child_access (void)
828{
829#ifdef GETLOADAVG_PRIVILEGED
830
831 if (!access_inited)
832 abort ();
833
834 /* Set both the real and effective UID and GID to the user's.
835 They cannot be changed back to make's. */
836
837#ifndef HAVE_SETREUID
838 if (setuid (user_uid) < 0)
839 pfatal_with_name ("child_access: setuid");
840#else
841 if (setreuid (user_uid, user_uid) < 0)
842 pfatal_with_name ("child_access: setreuid");
843#endif
844
845#ifndef HAVE_SETREGID
846 if (setgid (user_gid) < 0)
847 pfatal_with_name ("child_access: setgid");
848#else
849 if (setregid (user_gid, user_gid) < 0)
850 pfatal_with_name ("child_access: setregid");
851#endif
852
853 log_access (_("Child access"));
854
855#endif /* GETLOADAVG_PRIVILEGED */
856}
857
858
859#ifdef NEED_GET_PATH_MAX
860unsigned int
861get_path_max (void)
862{
863 static unsigned int value;
864
865 if (value == 0)
866 {
867 long int x = pathconf ("/", _PC_PATH_MAX);
868 if (x > 0)
869 value = x;
870 else
871 return MAXPATHLEN;
872 }
873
874 return value;
875}
876#endif
877
878
879
880/* This code is stolen from gnulib.
881 If/when we abandon the requirement to work with K&R compilers, we can
882 remove this (and perhaps other parts of GNU make!) and migrate to using
883 gnulib directly.
884
885 This is called only through atexit(), which means die() has already been
886 invoked. So, call exit() here directly. Apparently that works...?
887*/
888
889/* Close standard output, exiting with status 'exit_failure' on failure.
890 If a program writes *anything* to stdout, that program should close
891 stdout and make sure that it succeeds before exiting. Otherwise,
892 suppose that you go to the extreme of checking the return status
893 of every function that does an explicit write to stdout. The last
894 printf can succeed in writing to the internal stream buffer, and yet
895 the fclose(stdout) could still fail (due e.g., to a disk full error)
896 when it tries to write out that buffered data. Thus, you would be
897 left with an incomplete output file and the offending program would
898 exit successfully. Even calling fflush is not always sufficient,
899 since some file systems (NFS and CODA) buffer written/flushed data
900 until an actual close call.
901
902 Besides, it's wasteful to check the return value from every call
903 that writes to stdout -- just let the internal stream state record
904 the failure. That's what the ferror test is checking below.
905
906 It's important to detect such failures and exit nonzero because many
907 tools (most notably `make' and other build-management systems) depend
908 on being able to detect failure in other tools via their exit status. */
909
910void
911close_stdout (void)
912{
913 int prev_fail = ferror (stdout);
914 int fclose_fail = fclose (stdout);
915
916 if (prev_fail || fclose_fail)
917 {
918 if (fclose_fail)
919 error (NILF, _("write error: %s"), strerror (errno));
920 else
921 error (NILF, _("write error"));
922 exit (EXIT_FAILURE);
923 }
924}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette