std.c: usage(): Use `myerror()` instead of `fprintf()`
[sunny256-utils.git] / Lib / std / c / src / std.c
blob191d8e5fd2a42227bacc7f0d5d61a9c2d7b3a964
1 /*
2 * STDfilenameDTS
3 * File ID: STDuuidDTS
5 * (C)opyleft STDyearDTS- Øyvind A. Holm <sunny@sunbase.org>
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "STDexecDTS.h"
24 * Global variables
27 const char *progname;
28 struct Options opt;
31 * msg() - Print a message prefixed with "[progname]: " to stderr if the
32 * current verbose level is equal or higher than the first argument. The rest
33 * of the arguments are delivered to vfprintf().
34 * Returns the number of characters written.
37 int msg(const VerboseLevel verbose, const char *format, ...)
39 int retval = 0;
41 assert(format);
42 assert(strlen(format));
44 if (opt.verbose >= verbose) {
45 va_list ap;
47 va_start(ap, format);
48 retval = fprintf(stderr, "%s: ", progname);
49 retval += vfprintf(stderr, format, ap);
50 retval += fprintf(stderr, "\n");
51 va_end(ap);
54 return retval;
58 * std_strerror() - Replacement for `strerror()` that returns a predictable
59 * error message on every platform so the tests work everywhere.
62 static const char *std_strerror(const int errnum)
64 switch (errnum) {
65 case EACCES:
66 return "Permission denied";
67 default:
69 * Should never happen. If this line is executed, an `errno`
70 * value is missing from `std_strerror()`, and tests may fail
71 * on other platforms.
73 return strerror(errnum);
78 * myerror() - Print an error message to stderr using this format:
80 * a: b: c
82 * where `a` is the name of the program (the value of `progname`), `b` is the
83 * output from the printf-like string and optional arguments, and `c` is the
84 * error message from `errno`. If `errno` indicates no error, the ": c" part is
85 * not printed. Returns the number of characters written.
88 int myerror(const char *format, ...)
90 va_list ap;
91 int retval = 0;
92 const int orig_errno = errno;
94 assert(format);
95 assert(strlen(format));
97 retval = fprintf(stderr, "%s: ", progname);
98 va_start(ap, format);
99 retval += vfprintf(stderr, format, ap);
100 va_end(ap);
101 if (orig_errno)
102 retval += fprintf(stderr, ": %s", std_strerror(orig_errno));
103 retval += fprintf(stderr, "\n");
105 return retval;
109 * print_license() - Display the program license. Returns `EXIT_SUCCESS`.
112 static int print_license(void)
114 puts("(C)opyleft STDyearDTS- Øyvind A. Holm <sunny@sunbase.org>");
115 puts("");
116 puts("This program is free software; you can redistribute it"
117 " and/or modify it \n"
118 "under the terms of the GNU General Public License as"
119 " published by the \n"
120 "Free Software Foundation; either version 2 of the License,"
121 " or (at your \n"
122 "option) any later version.");
123 puts("");
124 puts("This program is distributed in the hope that it will be"
125 " useful, but \n"
126 "WITHOUT ANY WARRANTY; without even the implied warranty of \n"
127 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
128 puts("See the GNU General Public License for more details.");
129 puts("");
130 puts("You should have received a copy of"
131 " the GNU General Public License along \n"
132 "with this program. If not, see <http://www.gnu.org/licenses/>.");
134 return EXIT_SUCCESS;
138 * print_version() - Print version information on stdout. If `-q` is used, only
139 * the version number is printed. Returns `EXIT_SUCCESS`.
142 static int print_version(void)
144 if (opt.verbose <= VERBOSE_QUIET) {
145 puts(EXEC_VERSION);
146 return EXIT_SUCCESS;
148 printf("%s %s (%s)\n", progname, EXEC_VERSION, EXEC_DATE);
149 #ifdef GCOV
150 printf("has GCOV\n");
151 #endif
152 #ifdef NDEBUG
153 printf("has NDEBUG\n");
154 #endif
155 #ifdef PROF
156 printf("has PROF\n");
157 #endif
158 #ifdef UNUSED
159 printf("has UNUSED\n");
160 #endif
162 return EXIT_SUCCESS;
166 * usage() - Prints a help screen. Returns `retval`.
169 static int usage(const int retval)
171 if (retval != EXIT_SUCCESS) {
172 myerror("Type \"%s --help\" for help screen."
173 " Returning with value %d.", progname, retval);
174 return retval;
176 puts("");
177 if (opt.verbose >= 1) {
178 print_version();
179 puts("");
181 printf("Usage: %s [options]\n", progname);
182 printf("\n");
183 printf("Options:\n");
184 printf("\n");
185 printf(" -h, --help\n"
186 " Show this help.\n");
187 printf(" --license\n"
188 " Print the software license.\n");
189 printf(" -q, --quiet\n"
190 " Be more quiet. Can be repeated to increase silence.\n");
191 printf(" -v, --verbose\n"
192 " Increase level of verbosity. Can be repeated.\n");
193 printf(" --selftest\n"
194 " Run the built-in test suite.\n");
195 printf(" --version\n"
196 " Print version information.\n");
197 printf("\n");
199 return retval;
203 * choose_opt_action() - Decide what to do when option `c` is found. Read
204 * definitions for long options from `opts`.
205 * Returns 0 if ok, or 1 if `c` is unknown or anything fails.
208 static int choose_opt_action(const int c, const struct option *opts)
210 int retval = 0;
212 assert(opts);
214 switch (c) {
215 case 0:
216 if (!strcmp(opts->name, "license"))
217 opt.license = true;
218 else if (!strcmp(opts->name, "selftest"))
219 opt.selftest = true;
220 else if (!strcmp(opts->name, "version"))
221 opt.version = true;
222 break;
223 case 'h':
224 opt.help = true;
225 break;
226 case 'q':
227 opt.verbose--;
228 break;
229 case 'v':
230 opt.verbose++;
231 break;
232 default:
233 msg(VERBOSE_DEBUG,
234 "%s(): getopt_long() returned character code %d",
235 __func__, c);
236 retval = 1;
237 break;
240 return retval;
244 * parse_options() - Parse command line options.
245 * Returns 0 if succesful, or 1 if an error occurs.
248 static int parse_options(const int argc, char * const argv[])
250 int retval = 0;
252 assert(argv);
254 opt.help = false;
255 opt.license = false;
256 opt.selftest = false;
257 opt.verbose = 0;
258 opt.version = false;
260 while (!retval) {
261 int c;
262 int option_index = 0;
263 static const struct option long_options[] = {
264 {"help", no_argument, NULL, 'h'},
265 {"license", no_argument, NULL, 0},
266 {"quiet", no_argument, NULL, 'q'},
267 {"selftest", no_argument, NULL, 0},
268 {"verbose", no_argument, NULL, 'v'},
269 {"version", no_argument, NULL, 0},
270 {0, 0, 0, 0}
273 c = getopt_long(argc, argv,
274 "h" /* --help */
275 "q" /* --quiet */
276 "v" /* --verbose */
277 , long_options, &option_index);
278 if (c == -1)
279 break;
280 retval = choose_opt_action(c, &long_options[option_index]);
283 return retval;
287 * main()
290 int main(int argc, char *argv[])
292 int retval = EXIT_SUCCESS;
294 progname = argv[0];
295 errno = 0;
297 if (parse_options(argc, argv)) {
298 myerror("Option error");
299 return usage(EXIT_FAILURE);
302 msg(VERBOSE_DEBUG, "%s(): Using verbose level %d",
303 __func__, opt.verbose);
304 msg(VERBOSE_DEBUG, "%s(): argc = %d, optind = %d",
305 __func__, argc, optind);
307 if (opt.help)
308 return usage(EXIT_SUCCESS);
309 if (opt.selftest)
310 return selftest();
311 if (opt.version)
312 return print_version();
313 if (opt.license)
314 return print_license();
316 if (optind < argc) {
317 int t;
319 for (t = optind; t < argc; t++) {
320 msg(VERBOSE_DEBUG, "%s(): Non-option arg %d: %s",
321 __func__, t, argv[t]);
325 msg(VERBOSE_DEBUG, "Returning from %s() with value %d",
326 __func__, retval);
327 return retval;
330 /* vim: set ts=8 sw=8 sts=8 noet fo+=w tw=79 fenc=UTF-8 : */