libexplain  1.4.D001
libexplain/buffer/einval/format_string.c
Go to the documentation of this file.
00001 /*
00002  * libexplain - Explain errno values returned by libc functions
00003  * Copyright (C) 2010, 2013 Peter Miller
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU Lesser General Public License as
00007  * published by the Free Software Foundation; either version 3 of the
00008  * License, or (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013  * Lesser 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/assert.h>
00020 #include <libexplain/ac/stdio.h>
00021 #include <libexplain/ac/string.h>
00022 
00023 #include <libexplain/buffer/einval.h>
00024 
00025 
00026 void
00027 explain_buffer_einval_format_string(explain_string_buffer_t *sb,
00028     const char *caption, const char *value, size_t errpos)
00029 {
00030     const char      *end;
00031     const char      *percent;
00032     size_t          nbytes;
00033     explain_string_buffer_t yuck_sb;
00034     char            yuck[1000];
00035     const char      *internal;
00036 
00037     /*
00038      * The sequences "...%l%..." and "...%l%" are errors, but we don't
00039      * want the last %, we want the first.  Thus we move back one.
00040      * But must also be wary of "...%" or "...%l" i.e. unterminated
00041      * specifications.
00042      *
00043      * The unterminated cases that start with '%' are hard to detect, so
00044      * intially we ignore them.
00045      *
00046      * The last character is the offending character, or the actual
00047      * specifier (which is not in the "internal" set), step over it (it
00048      * could also be a percent).
00049      */
00050     assert(errpos > 0);
00051     end = value + errpos;
00052     percent = end - 1;
00053 
00054     /*
00055      * The errpos indicates the *end* of the broken format,
00056      * hunt backwards for the starting '%'.
00057      */
00058     internal = " #$'+-.0123456789ILZhjlqtz";
00059     while (percent > value)
00060     {
00061         unsigned char c;
00062         --percent;
00063         c = *percent;
00064         if (c == '%')
00065             break;
00066         if (!strchr(internal, c))
00067         {
00068             /*
00069              * Oh dear, the error is uglier than we thought.
00070              * Probably an unterminated specifier (like "...%").
00071              */
00072             percent = end - 1;
00073             break;
00074         }
00075     }
00076 
00077     /*
00078      * Build ourselves a quoted string.
00079      */
00080     explain_string_buffer_init(&yuck_sb, yuck, sizeof(yuck));
00081     nbytes = end - percent;
00082     explain_string_buffer_puts_quoted_n(&yuck_sb, percent, nbytes);
00083 
00084     /*
00085      * Explain why it is broken.
00086      */
00087     explain_string_buffer_printf_gettext
00088     (
00089         sb,
00090         /*
00091          * xgettext: This error message is issued when a system call
00092          * reports a problem with a printf(3)-style format string,
00093          * in the case where a format specifier is malformed.
00094          *
00095          * %1$s =>  the name of the offending system-call argument.
00096          * %2$s =>  the offending format specification (already quoted)
00097          * %3$ld => the byte position of the invalid format specifier within
00098          *          the format string
00099          */
00100         i18n("within the %s argument the conversion specification %s, "
00101             "starting at position %ld, is not valid"),
00102         caption,
00103         yuck,
00104         (long)(percent - value)
00105     );
00106 }
00107 
00108 
00109 void
00110 explain_buffer_einval_format_string_hole(explain_string_buffer_t *sb,
00111     const char *caption, int hole_index)
00112 {
00113     char            buf[30];
00114 
00115     snprintf(buf, sizeof(buf), "\"%%%d$\"", hole_index);
00116     explain_string_buffer_printf_gettext
00117     (
00118         sb,
00119         /*
00120          * xgettext: This error message is issued when a system call
00121          * reports a problem with a printf(3)-style format string,
00122          * in the case where a %n$ specifier has not been used.
00123          *
00124          * %1$s => the name of the offending system-call argument.
00125          * %2$s => the argument position of the missing format specifier,
00126          *         already quoted (including percent and dollar sign).
00127          */
00128         i18n("the %s argument does not contain a %s specification"),
00129         caption,
00130         buf
00131     );
00132 }
00133 
00134 
00135 /* vim: set ts=8 sw=4 et : */