bash 符号 errno 到字符串
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2217723/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Symbolic errno to String
提问by Flame
Is there a command-line tool that will take a symbolic errno such as EINVALand print the corresponding string, Invalid argument?
是否有命令行工具可以使用符号 errnoEINVAL并打印相应的字符串,Invalid argument?
I would like to avoid having to find that EINVAL is value 22 on my system and then using$ perror 22.
我想避免在我的系统上发现 EINVAL 的值为 22,然后使用$ perror 22.
Ideally I could write something like
理想情况下,我可以写一些类似的东西
$ errorcommand EINVAL
Invalid argument
$
$ errorcommand EINVAL
无效参数
$
采纳答案by Jonathan Leffler
AFAIK, there isn't a standard tool that does the job. At one level, it wouldn't be particularly hard to write one - the messiest parts are finding the correct file to parse (is is often, but by no means always, /usr/include/sys/errno.h) and then taking the data from that to do the mapping of names to numbers. I have not found a system that uses enum values rather than #define values, but it is probably only a matter of time. It is also a moot point whether to generate a triple consisting of token number (EINTR, etc), token name ("EINTR", etc) and error message ("Interrupted system call", etc), or whether to use just the number and name and leave it to 'strerror()' to supply the message.
AFAIK,没有完成这项工作的标准工具。在一个层面上,写一个并不是特别困难 - 最混乱的部分是找到正确的文件来解析(通常,但绝不总是,/usr/include/sys/errno.h)然后采取从中提取的数据进行名称到数字的映射。我还没有找到使用枚举值而不是 #define 值的系统,但这可能只是时间问题。是否生成由令牌编号(EINTR 等)、令牌名称(“EINTR”等)和错误消息(“中断的系统调用”等)组成的三元组,或者是否仅使用数字,这也是一个有争议的问题并命名并将其留给 'strerror()' 以提供消息。
As I said, it isn't particularly hard. I already had a program called 'errno' that accepted pure numeric values and printed the corresponding error messages:
正如我所说,这并不是特别难。我已经有一个名为“errno”的程序,它接受纯数值并打印相应的错误消息:
$ errno 1:10 20
1: Operation not permitted
2: No such file or directory
3: No such process
4: Interrupted system call
5: Input/output error
6: Device not configured
7: Argument list too long
8: Exec format error
9: Bad file descriptor
10: No child processes
20: Not a directory
$
I've written a Perl script and hacked the program to handle symbolic error numbers too:
我已经编写了一个 Perl 脚本并破解了程序来处理符号错误号:
$ errno 1:4 EINTR ENOTDIR
1 (EPERM): Operation not permitted
2 (ENOENT): No such file or directory
3 (ESRCH): No such process
4 (EINTR): Interrupted system call
EINTR (4): Interrupted system call
ENOTDIR (20): Not a directory
$
It does not handle ranges of symbolic error numbers (exercise for the reader).
它不处理符号错误号的范围(读者练习)。
generrno.pl
通用文件
#!/usr/bin/perl -w
#
# @(#)$Id: generrno.pl,v 1.1 2010/02/07 18:39:18 jleffler Exp jleffler $
#
# Generate table of error number constants from given file(s)
use strict;
my %symlist;
my $maxsymlen = 0;
my $maxmsglen = 0;
while (<>)
{
next unless m%^\s*#\s*define\s+(E[A-Z0-9a-z]+)\s+(\d+)\s*/\*\s*([A-Za-z].*\S)\s*\*/%;
$symlist{} = { number => , message => };
$maxsymlen = length() if length() > $maxsymlen;
$maxmsglen = length() if length() > $maxmsglen;
}
my $format = sprintf " { %%-%ds %%-%ds %%-5s %%-%ds },\n", $maxsymlen + 3, $maxsymlen + 1, $maxmsglen + 2;
foreach my $key (sort keys %symlist)
{
my $name = qq{"$key",};
my $symbol = qq{$key,};
my $number = qq{$symlist{$key}->{number},};
my $message = qq{"$symlist{$key}->{message}"};
printf $format, $name, $symbol, $number, $message;
}
errno.c
错误号
/*
@(#)File: $RCSfile: errno.c,v $
@(#)Version: $Revision: 2.2 $
@(#)Last changed: $Date: 2010/02/07 19:22:37 $
@(#)Purpose: Print messages corresponding to errno values or name
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 2003,2005,2008,2010
*/
/*TABSTOP=4*/
#define MAIN_PROGRAM
/* Need O/S specific messages as well as POSIX messages */
//#if __STDC_VERSION__ >= 199901L
//#define _XOPEN_SOURCE 600
//#else
//#define _XOPEN_SOURCE 500
//#endif /* __STDC_VERSION__ */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* getopt() on MacOS X 10.2 */
#include "stderr.h"
#include "range.h"
typedef struct err_info
{
const char *errsym; /* Error symbol - "EINTR" */
int errnum; /* Error number - EINTR */
int errdef; /* Error define - 4 */
const char *errmsg; /* Error message - Interrupted system call */
} err_info;
/*
** Generate generrno.h using:
** perl generrno.pl /usr/include/sys/errno.h > generrno.h
** NB: list must be sorted alphabetically on symbol name
*/
static const err_info err_msgs[] =
{
#include "generrno.h"
};
static const char usestr[] = "[-qV] [--] lo[:hi] ...";
#define DIM(x) (sizeof(x)/sizeof(*(x)))
static const err_info *err_nums[DIM(err_msgs)];
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_errno_c[] = "@(#)$Id: errno.c,v 2.2 2010/02/07 19:22:37 jleffler Exp $";
#endif /* lint */
static int cmp_err_number(const void *v1, const void *v2)
{
int e1 = (*((const err_info * const *)v1))->errnum;
int e2 = (*((const err_info * const *)v2))->errnum;
return(e1 - e2);
}
static void map_numbers(void)
{
int i;
for (i = 0; i < DIM(err_msgs); i++)
err_nums[i] = &err_msgs[i];
qsort(err_nums, DIM(err_nums), sizeof(*err_nums), cmp_err_number);
}
static const char *err_symbol(int num)
{
const char *sym = "<UNKNOWN>";
err_info lookfor = { 0, num, 0, 0 };
err_info *lookptr = &lookfor;
const err_info **found = bsearch(&lookptr, err_nums, DIM(err_nums), sizeof(*err_nums), cmp_err_number);
if (found != 0)
sym = (*found)->errsym;
return(sym);
}
static int cmp_err_symbol(const void *v1, const void *v2)
{
const char *s1 = ((const err_info *)v1)->errsym;
const char *s2 = ((const err_info *)v2)->errsym;
return(strcmp(s1, s2));
}
static int pr_string_errno(const char *arg, int qflag)
{
int estat = EXIT_SUCCESS;
err_info lookfor = { arg, 0, 0, 0 };
const err_info *found = bsearch(&lookfor, err_msgs, DIM(err_msgs), sizeof(*err_msgs), cmp_err_symbol);
if (found == 0)
{
err_remark("unrecognized symbol %s\n", arg);
estat = EXIT_FAILURE;
}
else if (qflag == 0)
printf("%s (%d): %s\n", arg, found->errnum, found->errmsg);
return(estat);
}
static int pr_number_errno(const char *arg, int qflag)
{
int estat = EXIT_SUCCESS;
long lo;
long hi;
const char *endp;
long msg;
endp = numeric_range(arg, &lo, &hi);
if (endp == arg)
err_remark("Invalid range specified (%s) - should be lo[:hi]\n", arg);
else if (*endp != '/*
@(#)File: $RCSfile: stderr.h,v $
@(#)Version: $Revision: 9.2 $
@(#)Last changed: $Date: 2009/03/06 06:52:26 $
@(#)Purpose: Header file for standard error functions
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 1989-93,1996-99,2003,2005-09
@(#)Product: :PRODUCT:
*/
#ifndef STDERR_H
#define STDERR_H
#ifdef MAIN_PROGRAM
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_stderr_h[] = "@(#)$Id: stderr.h,v 9.2 2009/03/06 06:52:26 jleffler Exp $";
#endif /* lint */
#endif
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <stdio.h>
#include <stdarg.h>
#ifdef __GNUC__
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#define NORETURN() __attribute__((noreturn))
#else
#define PRINTFLIKE(n,m) /* If only */
#define NORETURN() /* If only */
#endif /* __GNUC__ */
/* -- Definitions for error handling */
enum { ERR_STAT = 1 }; /* Default exit status */
enum { ERR_DEFAULT = 0x0000 }; /* Default flag */
enum { ERR_NOFLUSH = 0x0001 }; /* Do not flush open files */
enum { ERR_EXIT = 0x0004 }; /* Exit -- do not return */
enum { ERR_ABORT = 0x0008 }; /* Abort -- do not return */
enum { ERR_STAMP = 0x0020 }; /* Timestamp messages */
enum { ERR_NOARG0 = 0x0040 }; /* Do not print arg0 prefix */
enum { ERR_PID = 0x0080 }; /* Include pid=nnnnn info */
enum { ERR_ERRNO = 0x0100 }; /* Include system error */
#ifdef USE_STDERR_SYSLOG
/* Definitions related to using syslog */
enum { ERR_LOG_EMERG = 0x01000 }; /* system is unusable */
enum { ERR_LOG_ALERT = 0x02000 }; /* action must be taken immediately */
enum { ERR_LOG_CRIT = 0x04000 }; /* critical conditions */
enum { ERR_LOG_ERR = 0x08000 }; /* error conditions */
enum { ERR_LOG_WARNING = 0x10000 }; /* warning conditions */
enum { ERR_LOG_NOTICE = 0x20000 }; /* normal but signification condition */
enum { ERR_LOG_INFO = 0x40000 }; /* informational */
enum { ERR_LOG_DEBUG = 0x80000 }; /* debug-level messages */
enum { ERR_LOG_LEVEL_HI = ERR_LOG_EMERG|ERR_LOG_ALERT|ERR_LOG_CRIT|ERR_LOG_ERR };
enum { ERR_LOG_LEVEL_LO = ERR_LOG_WARNING|ERR_LOG_NOTICE|ERR_LOG_INFO|ERR_LOG_DEBUG };
enum { ERR_LOG_LEVEL = ERR_LOG_LEVEL_HI|ERR_LOG_LEVEL_LO };
#endif /* USE_STDERR_SYSLOG */
/* -- Standard combinations of flags */
enum { ERR_REM = ERR_DEFAULT };
enum { ERR_ERR = ERR_EXIT };
enum { ERR_ABT = ERR_ABORT };
enum { ERR_LOG = ERR_STAMP|ERR_PID };
enum { ERR_SYSREM = ERR_REM|ERR_ERRNO };
enum { ERR_SYSERR = ERR_ERR|ERR_ERRNO };
/* -- Maximum recorded length of argv[0]; extra is truncated */
enum { ERR_MAXLEN_ARGV0 = 63 };
/* -- Global definitions */
extern const char err_format1[]; /* "%s\n" - for one string argument */
extern const char err_format2[]; /* "%s %s\n" - for two string arguments */
extern const char *err_getarg0(void);
extern void err_setarg0(const char *argv0);
extern FILE *err_stderr(FILE *fp);
extern const char *err_rcs_string(const char *s, char *buffer, size_t buflen);
extern void err_abort(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_error(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_error1(const char *s1) NORETURN();
extern void err_error2(const char *s1, const char *s2) NORETURN();
extern void err_help(const char *use_str, const char *hlp_str) NORETURN();
extern void err_helplist(const char *use_str, const char * const *help_list) NORETURN();
extern void err_internal(const char *function, const char *msg) NORETURN();
extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5);
extern void err_print(int flags, int estat, const char *format, va_list args);
extern void err_printversion(const char *program, const char *verinfo);
extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);
extern void err_remark1(const char *s1);
extern void err_remark2(const char *s1, const char *s2);
extern void err_report(int flags, int estat, const char *format, ...) PRINTFLIKE(3,4);
extern void err_syserr(const char *format, ...) PRINTFLIKE(1,2) NORETURN();
extern void err_syserr1(const char *s1) NORETURN();
extern void err_syserr2(const char *s1, const char *s2) NORETURN();
extern void err_sysrem(const char *format, ...) PRINTFLIKE(1,2);
extern void err_sysrem1(const char *s1);
extern void err_sysrem2(const char *s1, const char *s2);
extern void err_usage(const char *usestr) NORETURN();
extern void err_version(const char *program, const char *verinfo) NORETURN();
extern int err_getlogopts(void); /* Get default log options */
extern int err_setlogopts(int new_opts); /* Set default log options */
#ifdef USE_STDERR_FILEDESC
extern int err_use_fd(int fd); /* Use file descriptor */
#endif /* USE_STDERR_FILEDESC */
#ifdef USE_STDERR_SYSLOG
/* In case of doubt, use zero for both logopts and facility */
extern int err_use_syslog(int logopts, int facility); /* Configure/use syslog() */
#endif /* USE_STDERR_SYSLOG */
/*
** JL 2003-07-31: Security Note.
** Question: given that err_remark("abc\n") and err_remark1("abc")
** produce the same output, when should you use err_remark1()
** instead of err_remark()?
** Answer 1: trivia - when you can't put the newline in the string.
** Answer 2: security - when the argument contains user input and could,
** therefore, contain conversion specifiers, etc. The code in
** err_remark() does not (and cannot) verify that you have
** passed correct arguments for the conversion specifiers in
** the format string.
** Answer 3: inertia - when migrating code that uses remark().
**
** Generalizing: when you use a function that has 'const char *format'
** in the prototype above, make sure your code is fully in charge of the
** format string to avoid security lapses. Do not allow the user to
** provide that string unless you stringently check it beforehand.
*/
#endif /* STDERR_H */
')
err_remark("Non-numeric character (%c) after range '%s'\n",
(isprint((unsigned char)*endp) ? *endp : '?'), arg);
else
{
for (msg = lo; msg <= hi; msg++)
{
char *msgtxt = strerror(msg);
if (msgtxt == 0)
{
err_remark("no message for errno = %ld\n", msg);
estat = EXIT_FAILURE;
}
else if (qflag == 0)
printf("%ld (%s): %s\n", msg, err_symbol(msg), msgtxt);
}
}
return(estat);
}
static int pr_errno(char *arg, int qflag)
{
int estat;
if (isalpha(*arg))
estat = pr_string_errno(arg, qflag);
else
estat = pr_number_errno(arg, qflag);
return(estat);
}
int main(int argc, char **argv)
{
int i;
int opt;
int nstat;
int estat = EXIT_SUCCESS;
int qflag = 0;
int nflag = 0;
err_setarg0(argv[0]);
map_numbers();
while ((opt = getopt(argc, argv, "qV0:1:2:3:4:5:6:7:8:9:")) != EOF)
{
switch (opt)
{
case 'q':
qflag = 1;
break;
case 'V':
err_version("ERRNO", "$Revision: 2.2 $ ($Date: 2010/02/07 19:22:37 $)");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* GETOPT() is probably not the right tool for this job! */
nstat = pr_errno(optarg-2, qflag);
if (estat == EXIT_SUCCESS)
estat = nstat;
nflag = 1;
break;
default:
err_usage(usestr);
break;
}
}
if (optind >= argc && nflag == 0)
err_usage(usestr);
for (i = optind; i < argc; i++)
{
nstat = pr_errno(argv[i], qflag);
if (estat == EXIT_SUCCESS)
estat = nstat;
}
return(estat);
}
The code needs some supporting files - stderr.h, range.h, range2.c and stderrmin.c (a simpler version of the stderr.c I normally use, which has extra bells and whistles for handling syslog and writing to file descriptors instead of file pointers.).
代码需要一些支持文件 - stderr.h、range.h、range2.c 和 stderrmin.c(我通常使用的更简单的 stderr.c 版本,它有额外的花里胡哨来处理系统日志和写入文件描述符文件指针。)。
stderr.h
标准错误文件
/*
@(#)File: $RCSfile: range.h,v $
@(#)Version: $Revision: 1.8 $
@(#)Last changed: $Date: 2008/02/11 07:39:36 $
@(#)Purpose: Declaration of range parsing functions
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 1997,2005,2007-08
@(#)Product: :PRODUCT:
*/
/*TABSTOP=4*/
#ifndef RANGE_H
#define RANGE_H
#ifdef MAIN_PROGRAM
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_range_h[] = "@(#)$Id: range.h,v 1.8 2008/02/11 07:39:36 jleffler Exp $";
#endif /* lint */
#endif /* MAIN_PROGRAM */
/*
** parse_range(): parse range of non-negative numbers.
**
** Given a string, parse_range() returns the lo and hi values corresponding
** to the range specified by the string. For example:
** Input: Low High
** 23 23 23
** 23-25 23 25
** 23- 23 0
** -23 0 23
** Any delimiter other than '-' before or after a number terminates the
** scan, but commas are skipped. Returns pointer to character after
** last character parsed (which may or may not be '/*
@(#)File: $RCSfile: range2.c,v $
@(#)Version: $Revision: 1.8 $
@(#)Last changed: $Date: 2008/02/11 08:44:50 $
@(#)Purpose: Decode string into range of integers.
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 1997,2002,2005,2007-08
@(#)Product: :PRODUCT:
*/
/*TABSTOP=4*/
/*
** Parse number ranges, dealing with positive and negative values,
** and ranges separated by either colon or double-dot.
**
** Input: Low High
** 23 23 23
** -23 -23 -23
** 23:25 23 25
** 23..25 23 25
** -23..-25 -25 -23
** -23..25 -23 25
** 23..-25 -25 23
** -23..+25 -23 25
** Any other delimiter after number (or before number) terminates
** input. NB: a leading colon (or dot) is not a valid range. If
** there is a format error, the returned pointer points to the
** start of the string (and lo and hi are unchanged). If there is
** no error, then the returned pointer points to the ASCII NUL at
** the end of the string.
*/
#include "range.h"
#include <stdlib.h>
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_range2_c[] = "@(#)$Id: range2.c,v 1.8 2008/02/11 08:44:50 jleffler Exp $";
#endif /* lint */
/*
** Parse numeric range.
** Return pointer to trailing '/*
@(#)File: $RCSfile: stderrmin.c,v $
@(#)Version: $Revision: 9.6 $
@(#)Last changed: $Date: 2009/03/02 20:27:38 $
@(#)Purpose: Minimal implementation of error reporting routines
@(#)Author: J Leffler
@(#)Copyright: (C) JLSS 1988-91,1996-99,2001,2003,2005-09
@(#)Product: :PRODUCT:
*/
/*TABSTOP=4*/
#undef STDERR_EXTENDED
#include "stderr.h"
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#else
extern int getpid(void);
#endif /* HAVE_UNISTD_H */
enum { MAX_MSGLEN = 2048 };
/* Global format strings */
const char err_format1[] = "%s\n";
const char err_format2[] = "%s %s\n";
static const char def_format[] = "%Y-%m-%d %H:%M:%S";
static const char *tm_format = def_format;
static char arg0[ERR_MAXLEN_ARGV0+1] = "**undefined**";
/* Permitted default error flags */
enum { ERR_LOGOPTS = ERR_NOFLUSH | ERR_EXIT | ERR_ABORT | ERR_STAMP |
ERR_NOARG0 | ERR_PID | ERR_ERRNO };
static int err_flags = 0; /* Default error flags (ERR_STAMP, ERR_PID, etc) */
static FILE *errout = 0;
/*
** err_???_print() functions are named systematically, and are all static.
**
** err_[ev][crx][fn]_print():
** -- e takes ellipsis argument
** -- v takes va_list argument
** -- c conditionally exits
** -- r returns (no exit)
** -- x exits (no return)
** -- f takes file pointer
** -- n no file pointer (use errout)
**
** NB: no-return and printf-like can only be attached to declarations, not definitions.
*/
static void err_vxf_print(FILE *fp, int flags, int estat, const char *format, va_list args)
NORETURN();
static void err_vxn_print(int flags, int estat, const char *format, va_list args)
NORETURN();
static void err_exn_print(int flags, int estat, const char *format, ...)
NORETURN() PRINTFLIKE(3,4);
static void err_terminate(int flags, int estat) NORETURN();
#ifndef lint
/* Prevent over-aggressive optimizers from eliminating ID string */
const char jlss_id_stderrmin_c[] = "@(#)$Id: stderrmin.c,v 9.6 2009/03/02 20:27:38 jleffler Exp $";
#endif /* lint */
/*
** Set default log options, returning old value.
** Setting ERR_EXIT and ERR_ABORT is permitted but not recommended.
*/
int err_setlogopts(int new_opts)
{
int old_opts = err_flags;
err_flags = new_opts & ERR_LOGOPTS;
return(old_opts);
}
/* Return default log options */
int err_getlogopts(void)
{
return(err_flags);
}
/* Change the definition of 'stderr', reporting on the old one too */
/* NB: using err_stderr((FILE *)0) simply reports the current 'stderr' */
FILE *(err_stderr)(FILE *newerr)
{
FILE *old;
if (errout == 0)
errout = stderr;
old = errout;
if (newerr != 0)
errout = newerr;
return(old);
}
/* Return stored basename of command */
const char *(err_getarg0)(void)
{
return(arg0);
}
/* Store basename of command, excluding trailing slashes */
void (err_setarg0)(const char *argv0)
{
/* Ignore three pathological program names -- NULL, "/" and "" */
if (argv0 != 0 && *argv0 != '$ errno 98
EADDRINUSE 98 Address already in use
$ errno EINVAL
EINVAL 22 Invalid argument
' && (*argv0 != '/' || *(argv0 + 1) != 'user@host:~$ grep EINVAL /usr/include/asm-generic/errno*.h
/usr/include/asm-generic/errno-base.h:#define EINVAL 22 /* Invalid argument */
'))
{
const char *cp;
size_t nbytes = sizeof(arg0) - 1;
if ((cp = strrchr(argv0, '/')) == 0)
{
/* Basename of file only */
cp = argv0;
}
else if (*(cp + 1) != 'import errno
from os import strerror
from sys import argv
print strerror(errno.__dict__[argv[1]]
')
{
/* Regular pathname containing slashes but not trailing slashes */
cp++;
}
else
{
/* Skip backwards over trailing slashes */
const char *ep = cp;
while (ep > argv0 && *ep == '/')
ep--;
/* Skip backwards over non-slashes */
cp = ep;
while (cp > argv0 && *cp != '/')
cp--;
assert(ep >= cp);
cp++;
nbytes = (size_t)(ep - cp) + 1;
if (nbytes > sizeof(arg0) - 1)
nbytes = sizeof(arg0) - 1;
}
strncpy(arg0, cp, nbytes);
arg0[nbytes] = 'strerror()
';
}
}
const char *(err_rcs_string)(const char *s2, char *buffer, size_t buflen)
{
const char *src = s2;
char *dst = buffer;
char *end = buffer + buflen - 1;
/*
** Bother RCS! We've probably been given something like:
** "$Revision: 9.6 $ ($Date: 2009/03/02 20:27:38 $)"
** We only want to emit "7.5 (2001/08/11 06:25:48)".
** Skip the components between '$' and ': ', copy up to ' $',
** repeating as necessary. And we have to test for overflow!
** Also work with the unexpanded forms of keywords ($Keyword$).
** Never needed this with SCCS!
*/
while (*src != 'grep EINVAL /usr/include/sys/errno.h
' && dst < end)
{
while (*src != '
#! /bin/bash -f
errorDir="/usr/include/asm-generic"
strError=""
numericVal=awk -v pat="$strError" 'function errorcommand
{
grep "" /usr/include/errno.h /usr/include/*/errno.h
}
~ pat{print }' $errorDir/errno-base.h $errorDir/errno.h
perror $numericVal
' && *src != '$')
{
*dst++ = *src++;
if (dst >= end)
break;
}
if (*src == '$')
src++;
while (*src != 'function errorcommand
{
grep "" /usr/include/errno.h /usr/include/*/errno.h
}
' && *src != ':' && *src != '$')
src++;
if (*src == '$ errorcommand EINV
/usr/include/sys/errno.h:#define EINVAL 22 /* Invalid argument */
$
')
break;
if (*src == '$')
{
/* Unexpanded keyword '$Keyword$' notation */
src++;
continue;
}
if (*src == ':')
src++;
if (*src == ' ')
src++;
while (*src != '
#!/bin/bash -f
file="/tmp/prog$$.c"
out="/tmp/prog$$"
if [ $# -ne 1 ]
then
echo "Usage: find /usr/include/ -name errno*.h -exec grep ERRNO {} +
ERROR-NO"
exit 1
fi
echo "#include <stdio.h>" >> $file
echo "#include <errno.h>" >> $file
echo "int main(){" >> $file
echo "printf(\":%s\n\",strerror());" >> $file
echo "}" >> $file
gcc $file -o $out &> /dev/null
if [ $? == "0" ]
then
$out
rm -f $out
else
echo "Syntax Error: Unknown"
fi
# cleanup the file
rm -f $file
' && *src != '$')
{
/* Map / in 2009/02/15 to dash */
/* Heuristic - maps slashes surrounded by digits to dashes */
char c = *src++;
if (c == '/' && isdigit(*src) && isdigit(*(src-2)))
c = '-';
*dst++ = c;
if (dst >= end)
break;
}
if (*src == '$')
{
if (*(dst-1) == ' ')
dst--;
src++;
}
}
*dst = '[x@localhost]$ find /usr/include/ -name errno*.h -exec grep EINVAL {} +
/usr/include/asm-generic/errno-base.h:#define EINVAL 22 /* Invalid argument */
[x@localhost]$ find /usr/include/ -name errno*.h -exec grep 111 {} +
/usr/include/asm-generic/errno.h:#define ECONNREFUSED 111 /* Connection refused */
';
return(buffer);
}
/* Format a time string for now (using ISO8601 format) */
/* Allow for future settable time format with tm_format */
static char *err_time(char *buffer, size_t buflen)
{
time_t now;
struct tm *tp;
now = time((time_t *)0);
tp = localtime(&now);
strftime(buffer, buflen, tm_format, tp);
return(buffer);
}
/* Most fundamental (and flexible) error message printing routine - always returns */
static
' if OK, else pointer to input string
*/
const char *numeric_range(const char *str, long *lo, long *hi)
{
const char *s = str;
char *t;
long l;
long h;
l = strtol(s, &t, 10);
if (*t == '##代码##')
{
/* Just one number */
*lo = *hi = l;
return(t);
}
if (*t == ':')
t += 1;
else if (t[0] == '.' && t[1] == '.')
t += 2;
else
{
/* Format error */
return(str);
}
h = strtol(t, &t, 10);
if (*t != '##代码##')
{
/* Format error */
return(str);
}
if (h < l)
{
long x = h;
h = l;
l = x;
}
*lo = l;
*hi = h;
return(t);
}
#ifdef TEST
#include <stdio.h>
#include "stderr.h"
int main(int argc, char **argv)
{
int i;
long lo;
long hi;
const char *t;
const char *s;
err_setarg0(argv[0]);
if (argc <= 1)
err_usage("range [...]");
for (i = 1; i < argc; i++)
{
t = argv[i];
if (t != 0 && *t != '##代码##')
{
printf("Parse: %15s (addr = 0x%08lX) ", t, (unsigned long)t);
fflush(stdout);
s = numeric_range(t, &lo, &hi);
printf("Range: %2ld -> %2ld (addr = 0x%08lX; trailer = <<%s>>)\n", lo, hi, (unsigned long)s, s);
fflush(stdout);
}
}
return(0);
}
#endif /* TEST */
') if successful.
** Otherwise, returns null.
**
** Idiomatic use:
**
** const char *ptr = source_string;
** const char *nxt;
** while ((nxt = parse_range(ptr, &lo, &hi)) != 0)
** {
** if (nxt == ptr)
** err_error("invalid range string (%s)\n", source_string);
** use_range(lo, hi);
** ptr = nxt;
** }
*/
extern const char *parse_range(const char *str, long *lo, long *hi);
/*
** numeric_range(): parse range of numbers, positive or negative.
**
** Input: Low High
** 23 23 23
** -23 -23 -23
** 23:25 23 25
** 23..25 23 25
** -23..-25 -25 -23
** -23..25 -23 25
** 23..-25 -25 23
** Returns pointer to '##代码##' at end of string if OK, sets *lo and *hi,
** and guarantees *lo <= *hi.
** Otherwise, returns pointer to start of string and does not set *lo or *hi.
**
** Idiomatic use:
**
** const char *ptr = source_string;
** const char *nxt;
** while ((nxt = numeric_range(ptr, &lo, &hi)) != 0)
** {
** if (nxt == ptr)
** err_error("invalid range string (%s)\n", source_string);
** use_range(lo, hi);
** ptr = nxt;
** }
*/
extern const char *numeric_range(const char *str, long *lo, long *hi);
#endif /* RANGE_H */
range.h
范围.h
##代码##range2.c
范围2.c
##代码##stderrmin.c
标准错误
This is about 400 lines, instead of about 700 lines. Yes, it is overkill for this program; I don't use it only in this program.
这是大约 400 行,而不是大约 700 行。是的,这个程序有点矫枉过正;我不只在这个程序中使用它。
##代码##回答by jdzions
At least for Ubuntu (12.04 and later, to my certain knowledge), there's an errnoutility you can easily install via apt-get install errno.
至少对于 Ubuntu(12.04 及更高版本,据我所知),有一个errno实用程序可以通过apt-get install errno.
回答by Joao da Silva
This works on Ubuntu 9.04:
这适用于 Ubuntu 9.04:
##代码##You can also try a Python script:
您还可以尝试使用 Python 脚本:
##代码##回答by John Weldon
回答by Rob Wells
Tried
试过
##代码##and seen what comes back?
看到什么回来了?
回答by sud03r
Caution: As this script uses the location of ERROR MACROS,this might not be portable although it works on my system.
注意:由于此脚本使用了 ERROR MACROS 的位置,因此尽管它可以在我的系统上运行,但它可能无法移植。
回答by vy32
Rob Wells is partially correct. Unfortunately /usr/include/asm/errno.his nonstandard. You really need to grep /usr/include/errno.hand /usr/include/*/errno.h.
Rob Wells 是部分正确的。不幸的/usr/include/asm/errno.h是是非标准的。你真的需要 grep/usr/include/errno.h和/usr/include/*/errno.h.
To make this errorcommand, try adding this to your .bashrc file:
要生成此错误命令,请尝试将其添加到您的 .bashrc 文件中:
##代码##Which works like this:
它的工作原理是这样的:
Rob Wells is partially correct. Unfortunately /usr/include/asm/errno.his nonstandard. You really need to grep /usr/include/errno.hand /usr/include/*/errno.h.
Rob Wells 是部分正确的。不幸的/usr/include/asm/errno.h是是非标准的。你真的需要 grep/usr/include/errno.h和/usr/include/*/errno.h.
To make this errorcommand, try adding this to your .bashrc file:
要生成此错误命令,请尝试将其添加到您的 .bashrc 文件中:
##代码##Which works like this:
它的工作原理是这样的:
##代码##回答by sud03r
A compact bash script that exactly does what you want:
一个紧凑的 bash 脚本,完全可以满足您的需求:
##代码##回答by Steve Emmerson
There's no standard utility to do this. I believe your best bet is to write such a utility yourself. Use strerror() to print the associated error message.
没有标准实用程序可以执行此操作。我相信最好的办法是自己编写这样的实用程序。使用 strerror() 打印相关的错误消息。
回答by Jem Tucker
For people that want a quick, on-liner:
对于想要快速在线的人:
##代码##e.g.
例如
##代码##
