libexplain
1.4.D001
|
00001 /* 00002 * libexplain - Explain errno values returned by libc functions 00003 * Copyright (C) 2008-2013 Peter Miller 00004 * Written by Peter Miller <pmiller@opensource.org.au> 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as 00008 * published by the Free Software Foundation; either version 3 of the 00009 * License, or (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 */ 00019 00020 #include <libexplain/ac/errno.h> 00021 #include <libexplain/ac/ctype.h> 00022 #include <libexplain/ac/stdlib.h> 00023 #include <libexplain/ac/string.h> 00024 00025 #include <libexplain/fstrcmp.h> 00026 #include <libexplain/option.h> 00027 #include <libexplain/output.h> 00028 #include <libexplain/parse_bits.h> 00029 #include <libexplain/program_name.h> 00030 #include <libexplain/sizeof.h> 00031 #include <libexplain/string_buffer.h> 00032 #include <libexplain/wrap_and_print.h> 00033 00034 00035 typedef enum option_level_t option_level_t; 00036 enum option_level_t 00037 { 00038 option_level_default, 00039 option_level_something_or_die, 00040 option_level_environment_variable, 00041 option_level_client, 00042 }; 00043 00044 typedef int option_value_t; 00045 00046 typedef enum option_type_t option_type_t; 00047 enum option_type_t 00048 { 00049 option_type_bool, 00050 option_type_int 00051 }; 00052 00053 typedef struct option_t option_t; 00054 struct option_t 00055 { 00056 option_level_t level; 00057 option_value_t value; 00058 option_type_t type; 00059 }; 00060 00061 typedef char value_t; 00062 00063 static int initialised; 00064 static option_t debug = 00065 { option_level_default, 0, option_type_bool }; 00066 static option_t numeric_errno = 00067 { option_level_default, 1, option_type_bool }; 00068 static option_t dialect_specific = 00069 { option_level_default, 1, option_type_bool }; 00070 static option_t assemble_program_name = 00071 { option_level_default, 1, option_type_bool }; 00072 static option_t symbolic_mode_bits = 00073 { option_level_default, 0, option_type_bool }; 00074 static option_t internal_strerror = 00075 { option_level_default, 0, option_type_bool }; 00076 static option_t hanging_indent = 00077 { option_level_default, 0, option_type_int }; 00078 static option_t extra_device_info = 00079 { option_level_default, 1, option_type_bool }; 00080 00081 typedef struct table_t table_t; 00082 struct table_t 00083 { 00084 const char *name; 00085 option_t *location; 00086 }; 00087 00088 static const table_t table[] = 00089 { 00090 { "assemble-program-name", &assemble_program_name }, 00091 { "debug", &debug }, 00092 { "dialect-specific", &dialect_specific }, 00093 { "hanging-indent", &hanging_indent }, 00094 { "internal-strerror", &internal_strerror }, 00095 { "numeric-errno", &numeric_errno }, 00096 { "program-name", &assemble_program_name }, 00097 { "symbolic-mode-bits", &symbolic_mode_bits }, 00098 { "extra-device-info", &extra_device_info }, 00099 }; 00100 00101 00102 static const explain_parse_bits_table_t bool_table[] = 00103 { 00104 { "yes", 1 }, 00105 { "no", 0 }, 00106 { "true", 1 }, 00107 { "false", 0 }, 00108 }; 00109 00110 00111 static void 00112 process(char *name, option_level_t level) 00113 { 00114 const table_t *tp; 00115 value_t value; 00116 char *eq; 00117 int invert; 00118 00119 if (!*name) 00120 return; 00121 invert = 0; 00122 value = 1; 00123 if (name[0] == 'n' && name[1] == 'o' && name[2] == '-') 00124 { 00125 invert = 1; 00126 name += 3; 00127 } 00128 eq = strchr(name, '='); 00129 if (eq) 00130 { 00131 int n = 0; 00132 explain_parse_bits(eq + 1, bool_table, SIZEOF(bool_table), &n); 00133 value = n; 00134 while (eq > name && isspace((unsigned char)eq[-1])) 00135 --eq; 00136 *eq = '\0'; 00137 } 00138 if (invert) 00139 value = !value; 00140 for (tp = table; tp < ENDOF(table); ++tp) 00141 { 00142 if (0 == strcmp(tp->name, name)) 00143 { 00144 if (level >= tp->location->level) 00145 { 00146 tp->location->level = level; 00147 tp->location->value = value; 00148 } 00149 return; 00150 } 00151 } 00152 if (debug.value) 00153 { 00154 const table_t *best_tp; 00155 double best_weight; 00156 explain_string_buffer_t buf; 00157 char message[200]; 00158 00159 best_tp = 0; 00160 best_weight = 0.6; 00161 for (tp = table; tp < ENDOF(table); ++tp) 00162 { 00163 double weight; 00164 00165 weight = explain_fstrcmp(tp->name, name); 00166 if (best_weight < weight) 00167 { 00168 best_tp = tp; 00169 best_weight = weight; 00170 } 00171 } 00172 00173 explain_string_buffer_init(&buf, message, sizeof(message)); 00174 explain_string_buffer_puts(&buf, "libexplain: Warning: option "); 00175 explain_string_buffer_puts_quoted(&buf, name); 00176 explain_string_buffer_puts(&buf, " unknown"); 00177 if (best_tp) 00178 { 00179 if (level >= best_tp->location->level) 00180 { 00181 best_tp->location->level = level; 00182 best_tp->location->value = value; 00183 } 00184 00185 explain_string_buffer_puts(&buf, ", assuming you meant "); 00186 explain_string_buffer_puts_quoted(&buf, best_tp->name); 00187 explain_string_buffer_puts(&buf, " instead"); 00188 } 00189 explain_wrap_and_print(stderr, message); 00190 } 00191 } 00192 00193 00194 static void 00195 initialise(void) 00196 { 00197 const char *cp; 00198 int err; 00199 00200 err = errno; 00201 initialised = 1; 00202 cp = getenv("EXPLAIN_OPTIONS"); 00203 if (!cp) 00204 { 00205 /* for historical compatibility */ 00206 cp = getenv("LIBEXPLAIN_OPTIONS"); 00207 } 00208 if (!cp) 00209 cp = ""; 00210 for (;;) 00211 { 00212 char name[100]; 00213 char *np; 00214 unsigned char c; 00215 00216 c = *cp++; 00217 if (!c) 00218 break; 00219 if (isspace(c)) 00220 continue; 00221 np = name; 00222 for (;;) 00223 { 00224 if (np < ENDOF(name) -1) 00225 { 00226 if (isupper(c)) 00227 c = tolower(c); 00228 *np++ = c; 00229 } 00230 c = *cp; 00231 if (!c) 00232 break; 00233 ++cp; 00234 if (c == ',') 00235 break; 00236 } 00237 /* remove trailing white space */ 00238 while (np > name && isspace((unsigned char)np[-1])) 00239 --np; 00240 *np = '\0'; 00241 00242 process(name, option_level_environment_variable); 00243 } 00244 errno = err; 00245 } 00246 00247 00248 int 00249 explain_option_debug(void) 00250 { 00251 if (!initialised) 00252 initialise(); 00253 return debug.value; 00254 } 00255 00256 00257 int 00258 explain_option_numeric_errno(void) 00259 { 00260 if (!initialised) 00261 initialise(); 00262 return numeric_errno.value; 00263 } 00264 00265 00266 int 00267 explain_option_dialect_specific(void) 00268 { 00269 if (!initialised) 00270 initialise(); 00271 return dialect_specific.value; 00272 } 00273 00274 00275 int 00276 explain_option_assemble_program_name(void) 00277 { 00278 if (!initialised) 00279 initialise(); 00280 return assemble_program_name.value; 00281 } 00282 00283 00284 void 00285 explain_program_name_assemble(int yesno) 00286 { 00287 /* 00288 * This is the public interface, it has highest 00289 * precedence. For the internal interface, see the 00290 * #explain_program_name_assemble_internal function. 00291 */ 00292 if (!initialised) 00293 initialise(); 00294 if (assemble_program_name.level <= option_level_client) 00295 { 00296 assemble_program_name.level = option_level_client; 00297 assemble_program_name.value = !!yesno; 00298 } 00299 } 00300 00301 00302 #if 0 00303 void 00304 explain_program_name_assemble_internal(int yesno) 00305 { 00306 /* 00307 * This is the private interface. 00308 */ 00309 if (!initialised) 00310 initialise(); 00311 if (assemble_program_name.level <= option_level_something_or_die) 00312 { 00313 assemble_program_name.level = option_level_something_or_die; 00314 assemble_program_name.value = !!yesno; 00315 } 00316 } 00317 #endif 00318 00319 00320 int 00321 explain_option_symbolic_mode_bits(void) 00322 { 00323 if (!initialised) 00324 initialise(); 00325 return symbolic_mode_bits.value; 00326 } 00327 00328 00329 int 00330 explain_option_internal_strerror(void) 00331 { 00332 if (!initialised) 00333 initialise(); 00334 return internal_strerror.value; 00335 } 00336 00337 00338 int 00339 explain_option_hanging_indent(int width) 00340 { 00341 int max; 00342 int n; 00343 00344 if (!initialised) 00345 initialise(); 00346 if (width <= 0 || width >= 65536) 00347 width = 80; 00348 max = (width + 5) / 10; 00349 n = hanging_indent.value; 00350 if (n <= 0) 00351 return 0; 00352 if (n > max) 00353 return max; 00354 return n; 00355 } 00356 00357 00358 void 00359 explain_option_hanging_indent_set(int columns) 00360 { 00361 if (!initialised) 00362 initialise(); 00363 if (hanging_indent.level <= option_level_client) 00364 { 00365 if (columns < 0) 00366 columns = 0; 00367 hanging_indent.value = columns; 00368 hanging_indent.level = option_level_client; 00369 } 00370 } 00371 00372 00373 int 00374 explain_option_extra_device_info(void) 00375 { 00376 if (!initialised) 00377 initialise(); 00378 return extra_device_info.value; 00379 } 00380 00381 00382 /* vim: set ts=8 sw=4 et : */