Makefile: Warn users of pkgx.dev about their poor life choices
[moreutils.git] / errno.c
blobfcf3dee66324dec051eec6772b5ce7362b802673
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 pclose(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' },
136 { 0, 0, 0, 0 }
140 static void
141 usage(void)
143 printf("Usage: errno [-lsS] [--list] [--search] [--search-all-locales] "
144 "[keyword]\n");
148 int
149 main(int argc, char **argv)
151 int i;
152 int exit_code;
153 int index = 0;
154 enum {
155 lookup_mode,
156 list_mode,
157 search_mode,
158 search_all_mode
159 } mode = lookup_mode;
161 setlocale(LC_ALL, "");
163 for (;;) {
164 int c = getopt_long(argc, argv, "hlsS", options, &index);
165 if (c == -1)
166 break;
168 switch (c) {
169 case 'h':
170 usage();
171 return EXIT_SUCCESS;
173 case 'l':
174 mode = list_mode;
175 break;
177 case 's':
178 mode = search_mode;
179 break;
181 case 'S':
182 mode = search_all_mode;
183 break;
185 case '?':
186 break;
188 default:
189 fprintf(stderr, "getopt returned 0x%02x\n", c);
190 return EXIT_FAILURE;
194 exit_code = EXIT_SUCCESS;
196 switch (mode) {
197 case lookup_mode:
198 for (i = optind; i < argc; ++i) {
199 const char *arg = argv[i];
200 if (toupper(arg[0]) == 'E') {
201 if (!report_from_name(arg))
202 exit_code = EXIT_FAILURE;
203 } else if (isdigit(arg[0])) {
204 if (!report_from_code(atoi(arg)))
205 exit_code = EXIT_FAILURE;
206 } else {
207 fprintf(stderr, "ERROR: Not understood: %s\n", arg);
208 exit_code = EXIT_FAILURE;
211 break;
213 case list_mode:
214 for (i = 0; i < num_errnos; ++i)
215 report(errnos[i].name, errnos[i].code);
216 break;
218 case search_mode:
219 search(argc - optind, argv + optind);
220 break;
222 case search_all_mode:
223 search_all(argc - optind, argv + optind);
224 break;
227 return exit_code;