This isn't a library function, but a program that I needed to polish up a bit.
Fiddling and tweaking can turn it into a library function without too much
trouble.
The last file ("err-names.h") is a derived file that depends on the "mk" script
that is unabashedly bash. It is also c99. That is pretty recent, too.
/** * @file errno.c * * Time-stamp: "2011-08-02 14:04:06 bkorb" * * Print out error numbers and meanings * * Copyright (c) 2002-2011 Bruce Korb - all rights reserved * * errno is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * errno is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <errno.h> #include <regex.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
#include "err-names.h"
static char const usage_text[] =
"USAGE: errno <name-number-or-description> [...]\n"
"For each argument, the program will find the error(s) that match\n"
"the name, error number or description pattern and print a line:\n"
" nnn (ENAME. . . . . ) == Description\n"
"where 'nnn' is the numerical number, 'ENAME' is the #defined name,\n"
"and 'Description' may be plain text or a regular expression.\n";
#ifndef NUL
#define NUL '\0'
#endif
/**
* Print usage and exit. This is always a success procedure because
* all command line arguments are presumed to be an error number
* search expression. This is only called when no arguments are provided.
*/
static void
usage(void)
{
fwrite(usage_text, sizeof(usage_text) - 1, 1, stdout);
exit(EXIT_SUCCESS);
}
/**
* parse a number. If there is any problem with the number, return -1.
* The entire input string must be consumed. If it looks like a number,
* but is not a valid errno number, "print_errno()" will catch it and
* return "false" to its caller.
*
* @param arg input string
* @returns -1 or the number indicated by the string
*/
static int
parse_errno(char const * arg)
{
errno = 0;
char * end;
unsigned long val = strtoul(arg, &end, 0);
if ((errno != 0) || (*end != NUL)) return -1;
return (int)val;
}
/**
* print the error number, name and description.
* The error number must be in the error name table.
*
* @param err the error number
* @param desc the error description
* @returns false if the error number is invalid, otherwise true.
*/
static bool
print_errno(int err, char const * desc)
{
if ((unsigned)err >= ERRNO_LIMIT)
return false;
char const * name = errno_names[err];
if (name == NULL)
return false;
char buf[1024];
int len = snprintf(buf, sizeof(buf), show_fmt, err, name, desc);
char * ps = strchr(buf, '(');
char * pe = strchr(ps, ')');
if ((ps != NULL) && (pe != NULL)) {
for (;;) {
ps += 2;
if (ps >= pe) break;
if (*ps == ' ') *ps = '.';
}
}
fwrite(buf, len, 1, stdout);
return true;
}
static int
re_find_err(regex_t * re)
{
int find_ct = 0;
for (int err = 1; err < 255; err++) {
char const * errstr = strerror(err);
if (regexec(re, errstr, 0, NULL, 0) == 0) {
find_ct++;
print_errno(err, errstr);
}
}
return find_ct;
}
static int
print_by_name(char const * ename)
{
for (int idx = 1; idx < ERRNO_LIMIT; idx++) {
char const * name = errno_names[idx];
if ((name != NULL) && (strcmp(ename, name) == 0)) {
char const * txt = strerror(idx);
print_errno(idx, txt);
return EXIT_SUCCESS;
}
}
fprintf(stderr, "no error is named '%s'\n", ename);
return EXIT_FAILURE;
}
static int
find_errno(char const * arg)
{
static char const not_name_chars[] =
" \t.,;/abcdefghijklmnopqrstuvwxyz";
if ((*arg == 'E') && (strpbrk(arg, not_name_chars) == NULL))
return print_by_name(arg);
regex_t re;
int err = regcomp(&re, arg, 0);
int match_ct = 0;
printf("looking for matches to: '%s'\n", arg);
if (err == 0) {
match_ct = re_find_err(&re);
regfree(&re);
} else {
for (err = 1; err < 255; err++) {
char const * errstr = strerror(err);
if (strstr(errstr, arg) != NULL) {
match_ct++;
print_errno(err, errstr);
}
}
}
if (match_ct == 0) {
fprintf(stderr, "no error descriptions match '%s'\n\n", arg);
return EXIT_FAILURE;
}
putc('\n', stdout);
return EXIT_SUCCESS;
}
int
main(int argc, char ** argv)
{
int res = EXIT_SUCCESS;
if (argc <= 1)
usage();
while (--argc > 0) {
char * arg = *++argv;
int err = parse_errno(arg);
if (err < 0)
res |= find_errno(arg);
else if (! print_errno(err, strerror(err))) {
res |= EXIT_FAILURE;
fprintf(stderr, "error number %d is invalid\n", err);
}
}
return res;
}
/*
* Local Variables:
* mode: C
* c-file-style: "stroustrup"
* indent-tabs-mode: nil
* End:
* end of agen5/autogen.c */
# errno Makefile
#
# $Id: Makefile,v 1.2 2003/04/12 18:09:00 bkorb Exp $
EXE := errno
CC := $(shell which cc) -std=c99
SRC := $(EXE).c
HDR := err-names.h
OBJ := $(SRC:.c=.o)
CFLAGS = -O4 -g
$(EXE) : $(OBJ)
$(CC) -g -o $@ $(OBJ)
$(OBJ) : $(SRC) $(HDR)
$(CC) $(CFLAGS) -c -o $@ $(SRC)
err-names.h : mk-err-names.sh
$(SHELL) mk-err-names.sh
clean :
rm -f $(OBJ) *~ './.#'*
clobber : clean
rm -f $(EXE) $(HDR)
mk-err-names.sh
Description: application/shellscript
/* -*- buffer-read-only: t -*- vi: set ro: * * DO NOT EDIT THIS FILE * * This file has been derived by scanning system headers: * * /usr/include/asm-generic/errno-base.h * /usr/include/asm-generic/errno.h * /usr/include/asm/errno.h * /usr/include/bits/errno.h * /usr/include/errno.h * /usr/include/linux/errno.h * * @file errno.c * * Time-stamp: "2011-08-02 14:04:06 bkorb" * * Print out error numbers and meanings * * Copyright (c) 2002-2011 Bruce Korb - all rights reserved * * errno is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * errno is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see <http://www.gnu.org/licenses/>. */ #ifndef ERRNO_LIMIT #define ERRNO_LIMIT 133 static char const * const errno_names[ERRNO_LIMIT] = { [ 1] = "EPERM", [ 2] = "ENOENT", [ 3] = "ESRCH", [ 4] = "EINTR", [ 5] = "EIO", [ 6] = "ENXIO", [ 7] = "E2BIG", [ 8] = "ENOEXEC", [ 9] = "EBADF", [ 10] = "ECHILD", [ 11] = "EAGAIN", [ 12] = "ENOMEM", [ 13] = "EACCES", [ 14] = "EFAULT", [ 15] = "ENOTBLK", [ 16] = "EBUSY", [ 17] = "EEXIST", [ 18] = "EXDEV", [ 19] = "ENODEV", [ 20] = "ENOTDIR", [ 21] = "EISDIR", [ 22] = "EINVAL", [ 23] = "ENFILE", [ 24] = "EMFILE", [ 25] = "ENOTTY", [ 26] = "ETXTBSY", [ 27] = "EFBIG", [ 28] = "ENOSPC", [ 29] = "ESPIPE", [ 30] = "EROFS", [ 31] = "EMLINK", [ 32] = "EPIPE", [ 33] = "EDOM", [ 34] = "ERANGE", [ 35] = "EDEADLK", [ 36] = "ENAMETOOLONG", [ 37] = "ENOLCK", [ 38] = "ENOSYS", [ 39] = "ENOTEMPTY", [ 40] = "ELOOP", [ 42] = "ENOMSG", [ 43] = "EIDRM", [ 44] = "ECHRNG", [ 45] = "EL2NSYNC", [ 46] = "EL3HLT", [ 47] = "EL3RST", [ 48] = "ELNRNG", [ 49] = "EUNATCH", [ 50] = "ENOCSI", [ 51] = "EL2HLT", [ 52] = "EBADE", [ 53] = "EBADR", [ 54] = "EXFULL", [ 55] = "ENOANO", [ 56] = "EBADRQC", [ 57] = "EBADSLT", [ 59] = "EBFONT", [ 60] = "ENOSTR", [ 61] = "ENODATA", [ 62] = "ETIME", [ 63] = "ENOSR", [ 64] = "ENONET", [ 65] = "ENOPKG", [ 66] = "EREMOTE", [ 67] = "ENOLINK", [ 68] = "EADV", [ 69] = "ESRMNT", [ 70] = "ECOMM", [ 71] = "EPROTO", [ 72] = "EMULTIHOP", [ 73] = "EDOTDOT", [ 74] = "EBADMSG", [ 75] = "EOVERFLOW", [ 76] = "ENOTUNIQ", [ 77] = "EBADFD", [ 78] = "EREMCHG", [ 79] = "ELIBACC", [ 80] = "ELIBBAD", [ 81] = "ELIBSCN", [ 82] = "ELIBMAX", [ 83] = "ELIBEXEC", [ 84] = "EILSEQ", [ 85] = "ERESTART", [ 86] = "ESTRPIPE", [ 87] = "EUSERS", [ 88] = "ENOTSOCK", [ 89] = "EDESTADDRREQ", [ 90] = "EMSGSIZE", [ 91] = "EPROTOTYPE", [ 92] = "ENOPROTOOPT", [ 93] = "EPROTONOSUPPORT", [ 94] = "ESOCKTNOSUPPORT", [ 95] = "EOPNOTSUPP", [ 96] = "EPFNOSUPPORT", [ 97] = "EAFNOSUPPORT", [ 98] = "EADDRINUSE", [ 99] = "EADDRNOTAVAIL", [100] = "ENETDOWN", [101] = "ENETUNREACH", [102] = "ENETRESET", [103] = "ECONNABORTED", [104] = "ECONNRESET", [105] = "ENOBUFS", [106] = "EISCONN", [107] = "ENOTCONN", [108] = "ESHUTDOWN", [109] = "ETOOMANYREFS", [110] = "ETIMEDOUT", [111] = "ECONNREFUSED", [112] = "EHOSTDOWN", [113] = "EHOSTUNREACH", [114] = "EALREADY", [115] = "EINPROGRESS", [116] = "ESTALE", [117] = "EUCLEAN", [118] = "ENOTNAM", [119] = "ENAVAIL", [120] = "EISNAM", [121] = "EREMOTEIO", [122] = "EDQUOT", [123] = "ENOMEDIUM", [124] = "EMEDIUMTYPE", [125] = "ECANCELED", [126] = "ENOKEY", [127] = "EKEYEXPIRED", [128] = "EKEYREVOKED", [129] = "EKEYREJECTED", [130] = "EOWNERDEAD", [131] = "ENOTRECOVERABLE", [132] = "ERFKILL", }; static char const show_fmt[] = "%5d (%-15s) == %s\n"; #endif /* ERRNO_LIMIT */
