sponge: Check fclose to detect certian short reads. Closes: #704453
[moreutils.git] / errno.c
blobfd130c1b9dab4c8f6ed5c8929af912ea0934ef2f
1 /*
2 * errno.c -- look up errno names and descriptions
3 * Copyright 2012 Lars Wirzenius (liw@iki.fi)
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 * Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #define _GNU_SOURCE
22 #include <ctype.h>
23 #include <errno.h>
24 #include <locale.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <getopt.h>
33 static struct {
34 const char *name;
35 int code;
36 } errnos[] = {
37 #include "errnos.h"
39 static const int num_errnos = sizeof(errnos) / sizeof(errnos[0]);
42 static void
43 report(const char *name, int code)
45 printf("%s %d %s\n", name, code, strerror(code));
49 static bool
50 report_from_name(const char *name)
52 int i;
53 for (i = 0; i < num_errnos; ++i) {
54 if (strcasecmp(errnos[i].name, name) == 0) {
55 report(errnos[i].name, errnos[i].code);
56 return true;
59 return false;
63 static bool
64 report_from_code(int code)
66 int i;
67 for (i = 0; i < num_errnos; ++i) {
68 if (errnos[i].code == code) {
69 report(errnos[i].name, code);
70 return true;
73 return false;
77 static bool
78 matches(int code, int num_words, char **words)
80 const char *text = strerror(code);
81 int i;
83 for (i = 0; i < num_words; ++i) {
84 if (strcasestr(text, words[i]) == NULL)
85 return false;
87 return true;
91 static void
92 search(int num_words, char **words)
94 int i;
96 for (i = 0; i < num_errnos; ++i) {
97 if (matches(errnos[i].code, num_words, words))
98 report(errnos[i].name, errnos[i].code);
103 static void
104 search_all(int num_words, char **words)
106 FILE *f;
108 /* Static buffers are ugly, but they're simple. If anyone has a
109 locale name longer than a kilobyte, they will suffer, and they
110 will complain, and then I will fix this. */
111 char line[1024];
113 f = popen("locale -a", "r");
114 if (f == NULL) {
115 fprintf(stderr, "ERROR: Can't execute locale -a: %d: %s\n",
116 errno, strerror(errno));
117 exit(EXIT_FAILURE);
120 while (fgets(line, sizeof line, f) != NULL) {
121 line[strcspn(line, "\n")] = '\0';
122 setlocale(LC_ALL, line);
123 search(num_words, words);
126 fclose(f);
130 static struct option
131 options[] = {
132 { "help", 0, NULL, 'h' },
133 { "list", 0, NULL, 'l' },
134 { "search", 0, NULL, 's' },
135 { "search-all-locales", 0, NULL, 'S' },
139 static void
140 usage(void)
142 printf("Usage: errno [-lsS] [--list] [--search] [--search-all-locales] "
143 "[keyword]\n");
147 int
148 main(int argc, char **argv)
150 int i;
151 int exit_code;
152 int index = 0;
153 enum {
154 lookup_mode,
155 list_mode,
156 search_mode,
157 search_all_mode
158 } mode = lookup_mode;
160 setlocale(LC_ALL, "");
162 for (;;) {
163 int c = getopt_long(argc, argv, "hlsS", options, &index);
164 if (c == -1)
165 break;
167 switch (c) {
168 case 'h':
169 usage();
170 return EXIT_SUCCESS;
172 case 'l':
173 mode = list_mode;
174 break;
176 case 's':
177 mode = search_mode;
178 break;
180 case 'S':
181 mode = search_all_mode;
182 break;
184 case '?':
185 break;
187 default:
188 fprintf(stderr, "getopt returned 0x%02x\n", c);
189 return EXIT_FAILURE;
193 exit_code = EXIT_SUCCESS;
195 switch (mode) {
196 case lookup_mode:
197 for (i = optind; i < argc; ++i) {
198 const char *arg = argv[i];
199 if (toupper(arg[0]) == 'E') {
200 if (!report_from_name(arg))
201 exit_code = EXIT_FAILURE;
202 } else if (isdigit(arg[0])) {
203 if (!report_from_code(atoi(arg)))
204 exit_code = EXIT_FAILURE;
205 } else {
206 fprintf(stderr, "ERROR: Not understood: %s\n", arg);
207 exit_code = EXIT_FAILURE;
210 break;
212 case list_mode:
213 for (i = 0; i < num_errnos; ++i)
214 report(errnos[i].name, errnos[i].code);
215 break;
217 case search_mode:
218 search(argc - optind, argv + optind);
219 break;
221 case search_all_mode:
222 search_all(argc - optind, argv + optind);
223 break;
226 return exit_code;