libexplain  1.4.D001
libexplain/fprintf_or_die.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2010, 2012, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify it
00006  * under the terms of the GNU Lesser General Public License as published by
00007  * the Free Software Foundation; either version 3 of the License, or (at
00008  * your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful, but
00011  * WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
00013  * General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00017  */
00018 
00019 #include <libexplain/ac/errno.h>
00020 #include <libexplain/ac/stdarg.h>
00021 #include <libexplain/ac/stdio.h>
00022 
00023 #include <libexplain/buffer/errno/fprintf.h>
00024 #include <libexplain/common_message_buffer.h>
00025 #include <libexplain/fprintf.h>
00026 #include <libexplain/output.h>
00027 #include <libexplain/string_buffer.h>
00028 
00029 
00030 int
00031 explain_fprintf_or_die(FILE *fp, const char *format, ...)
00032 {
00033     int             hold_errno;
00034     va_list         ap;
00035     va_list         ap2;
00036     int             result;
00037 
00038     va_start(ap, format);
00039 
00040     /*
00041      * We may need a second copy, just in case the call fails.  We can't
00042      * call va_start again, that isn't the way this works.  And we can't
00043      * do a simple assignment, because there are some funky compilers
00044      * out there, and va_list could be some serious coding.
00045      *
00046      * <rant>
00047      * The va_copy functionality was introduced in ANSI C in 1999.  If
00048      * your compiler doesn't have it, raise a bug with your vendor.  You
00049      * should also SERIOUSLY consider upgrading to gcc, which has been
00050      * ANSI C 1999 compliant since 1999.
00051      * </rant>
00052      */
00053     va_copy(ap2, ap);
00054 
00055     hold_errno = errno;
00056     errno = EINVAL;
00057     result = vfprintf(fp, format, ap);
00058     if (result < 0)
00059     {
00060         explain_string_buffer_t sb;
00061 
00062         hold_errno = errno;
00063         explain_string_buffer_init
00064         (
00065             &sb,
00066             explain_common_message_buffer,
00067             explain_common_message_buffer_size
00068         );
00069         /* can't re-use "ap" here, this is why we prepped "ap2" earlier */
00070         explain_buffer_errno_fprintf(&sb, hold_errno, fp, format, ap2);
00071         explain_output_error("%s", explain_common_message_buffer);
00072         explain_output_exit_failure();
00073     }
00074     va_end(ap2); /* yes, both of them */
00075     va_end(ap);
00076     errno = hold_errno;
00077     return result;
00078 }
00079 
00080 
00081 int
00082 explain_fprintf_on_error(FILE *fp, const char *format, ...)
00083 {
00084     int             hold_errno;
00085     int             result;
00086     va_list         ap;
00087     va_list         ap2;
00088 
00089     va_start(ap, format);
00090     va_copy(ap2, ap); /* see comments in explain_fprintf_or_die */
00091 
00092     hold_errno = errno;
00093     errno = EINVAL;
00094     result = vfprintf(fp, format, ap);
00095     if (result < 0)
00096     {
00097         explain_string_buffer_t sb;
00098 
00099         hold_errno = errno;
00100         explain_string_buffer_init
00101         (
00102             &sb,
00103             explain_common_message_buffer,
00104             explain_common_message_buffer_size
00105         );
00106         explain_buffer_errno_fprintf(&sb, hold_errno, fp, format, ap2);
00107         explain_output_error("%s", explain_common_message_buffer);
00108     }
00109     va_end(ap2); /* yes, both of them */
00110     va_end(ap);
00111     errno = hold_errno;
00112     return result;
00113 }
00114 
00115 
00116 /* vim: set ts=8 sw=4 et : */