Home | History | Annotate | Download | only in libiberty
      1 /* Extended support for using errno values.
      2    Written by Fred Fish.  fnf (at) cygnus.com
      3    This file is in the public domain.  --Per Bothner.  */
      4 
      5 #include "config.h"
      6 
      7 #ifdef HAVE_SYS_ERRLIST
      8 /* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least)
      9    might declare sys_errlist in a way that the compiler might consider
     10    incompatible with our later declaration, perhaps by using const
     11    attributes.  So we hide the declaration in errno.h (if any) using a
     12    macro. */
     13 #define sys_nerr sys_nerr__
     14 #define sys_errlist sys_errlist__
     15 #endif
     16 
     17 #include "ansidecl.h"
     18 #include "libiberty.h"
     19 
     20 #include <stdio.h>
     21 #include <errno.h>
     22 
     23 #ifdef HAVE_SYS_ERRLIST
     24 #undef sys_nerr
     25 #undef sys_errlist
     26 #endif
     27 
     28 /*  Routines imported from standard C runtime libraries. */
     29 
     30 #ifdef HAVE_STDLIB_H
     31 #include <stdlib.h>
     32 #else
     33 extern PTR malloc ();
     34 #endif
     35 
     36 #ifdef HAVE_STRING_H
     37 #include <string.h>
     38 #else
     39 extern PTR memset ();
     40 #endif
     41 
     42 #ifndef MAX
     43 #  define MAX(a,b) ((a) > (b) ? (a) : (b))
     44 #endif
     45 
     46 static void init_error_tables (void);
     47 
     48 /* Translation table for errno values.  See intro(2) in most UNIX systems
     49    Programmers Reference Manuals.
     50 
     51    Note that this table is generally only accessed when it is used at runtime
     52    to initialize errno name and message tables that are indexed by errno
     53    value.
     54 
     55    Not all of these errnos will exist on all systems.  This table is the only
     56    thing that should have to be updated as new error numbers are introduced.
     57    It's sort of ugly, but at least its portable. */
     58 
     59 struct error_info
     60 {
     61   const int value;		/* The numeric value from <errno.h> */
     62   const char *const name;	/* The equivalent symbolic value */
     63 #ifndef HAVE_SYS_ERRLIST
     64   const char *const msg;	/* Short message about this value */
     65 #endif
     66 };
     67 
     68 #ifndef HAVE_SYS_ERRLIST
     69 #   define ENTRY(value, name, msg)	{value, name, msg}
     70 #else
     71 #   define ENTRY(value, name, msg)	{value, name}
     72 #endif
     73 
     74 static const struct error_info error_table[] =
     75 {
     76 #if defined (EPERM)
     77   ENTRY(EPERM, "EPERM", "Not owner"),
     78 #endif
     79 #if defined (ENOENT)
     80   ENTRY(ENOENT, "ENOENT", "No such file or directory"),
     81 #endif
     82 #if defined (ESRCH)
     83   ENTRY(ESRCH, "ESRCH", "No such process"),
     84 #endif
     85 #if defined (EINTR)
     86   ENTRY(EINTR, "EINTR", "Interrupted system call"),
     87 #endif
     88 #if defined (EIO)
     89   ENTRY(EIO, "EIO", "I/O error"),
     90 #endif
     91 #if defined (ENXIO)
     92   ENTRY(ENXIO, "ENXIO", "No such device or address"),
     93 #endif
     94 #if defined (E2BIG)
     95   ENTRY(E2BIG, "E2BIG", "Arg list too long"),
     96 #endif
     97 #if defined (ENOEXEC)
     98   ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"),
     99 #endif
    100 #if defined (EBADF)
    101   ENTRY(EBADF, "EBADF", "Bad file number"),
    102 #endif
    103 #if defined (ECHILD)
    104   ENTRY(ECHILD, "ECHILD", "No child processes"),
    105 #endif
    106 #if defined (EWOULDBLOCK)	/* Put before EAGAIN, sometimes aliased */
    107   ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"),
    108 #endif
    109 #if defined (EAGAIN)
    110   ENTRY(EAGAIN, "EAGAIN", "No more processes"),
    111 #endif
    112 #if defined (ENOMEM)
    113   ENTRY(ENOMEM, "ENOMEM", "Not enough space"),
    114 #endif
    115 #if defined (EACCES)
    116   ENTRY(EACCES, "EACCES", "Permission denied"),
    117 #endif
    118 #if defined (EFAULT)
    119   ENTRY(EFAULT, "EFAULT", "Bad address"),
    120 #endif
    121 #if defined (ENOTBLK)
    122   ENTRY(ENOTBLK, "ENOTBLK", "Block device required"),
    123 #endif
    124 #if defined (EBUSY)
    125   ENTRY(EBUSY, "EBUSY", "Device busy"),
    126 #endif
    127 #if defined (EEXIST)
    128   ENTRY(EEXIST, "EEXIST", "File exists"),
    129 #endif
    130 #if defined (EXDEV)
    131   ENTRY(EXDEV, "EXDEV", "Cross-device link"),
    132 #endif
    133 #if defined (ENODEV)
    134   ENTRY(ENODEV, "ENODEV", "No such device"),
    135 #endif
    136 #if defined (ENOTDIR)
    137   ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"),
    138 #endif
    139 #if defined (EISDIR)
    140   ENTRY(EISDIR, "EISDIR", "Is a directory"),
    141 #endif
    142 #if defined (EINVAL)
    143   ENTRY(EINVAL, "EINVAL", "Invalid argument"),
    144 #endif
    145 #if defined (ENFILE)
    146   ENTRY(ENFILE, "ENFILE", "File table overflow"),
    147 #endif
    148 #if defined (EMFILE)
    149   ENTRY(EMFILE, "EMFILE", "Too many open files"),
    150 #endif
    151 #if defined (ENOTTY)
    152   ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"),
    153 #endif
    154 #if defined (ETXTBSY)
    155   ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"),
    156 #endif
    157 #if defined (EFBIG)
    158   ENTRY(EFBIG, "EFBIG", "File too large"),
    159 #endif
    160 #if defined (ENOSPC)
    161   ENTRY(ENOSPC, "ENOSPC", "No space left on device"),
    162 #endif
    163 #if defined (ESPIPE)
    164   ENTRY(ESPIPE, "ESPIPE", "Illegal seek"),
    165 #endif
    166 #if defined (EROFS)
    167   ENTRY(EROFS, "EROFS", "Read-only file system"),
    168 #endif
    169 #if defined (EMLINK)
    170   ENTRY(EMLINK, "EMLINK", "Too many links"),
    171 #endif
    172 #if defined (EPIPE)
    173   ENTRY(EPIPE, "EPIPE", "Broken pipe"),
    174 #endif
    175 #if defined (EDOM)
    176   ENTRY(EDOM, "EDOM", "Math argument out of domain of func"),
    177 #endif
    178 #if defined (ERANGE)
    179   ENTRY(ERANGE, "ERANGE", "Math result not representable"),
    180 #endif
    181 #if defined (ENOMSG)
    182   ENTRY(ENOMSG, "ENOMSG", "No message of desired type"),
    183 #endif
    184 #if defined (EIDRM)
    185   ENTRY(EIDRM, "EIDRM", "Identifier removed"),
    186 #endif
    187 #if defined (ECHRNG)
    188   ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"),
    189 #endif
    190 #if defined (EL2NSYNC)
    191   ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"),
    192 #endif
    193 #if defined (EL3HLT)
    194   ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"),
    195 #endif
    196 #if defined (EL3RST)
    197   ENTRY(EL3RST, "EL3RST", "Level 3 reset"),
    198 #endif
    199 #if defined (ELNRNG)
    200   ENTRY(ELNRNG, "ELNRNG", "Link number out of range"),
    201 #endif
    202 #if defined (EUNATCH)
    203   ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"),
    204 #endif
    205 #if defined (ENOCSI)
    206   ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"),
    207 #endif
    208 #if defined (EL2HLT)
    209   ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"),
    210 #endif
    211 #if defined (EDEADLK)
    212   ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"),
    213 #endif
    214 #if defined (ENOLCK)
    215   ENTRY(ENOLCK, "ENOLCK", "No record locks available"),
    216 #endif
    217 #if defined (EBADE)
    218   ENTRY(EBADE, "EBADE", "Invalid exchange"),
    219 #endif
    220 #if defined (EBADR)
    221   ENTRY(EBADR, "EBADR", "Invalid request descriptor"),
    222 #endif
    223 #if defined (EXFULL)
    224   ENTRY(EXFULL, "EXFULL", "Exchange full"),
    225 #endif
    226 #if defined (ENOANO)
    227   ENTRY(ENOANO, "ENOANO", "No anode"),
    228 #endif
    229 #if defined (EBADRQC)
    230   ENTRY(EBADRQC, "EBADRQC", "Invalid request code"),
    231 #endif
    232 #if defined (EBADSLT)
    233   ENTRY(EBADSLT, "EBADSLT", "Invalid slot"),
    234 #endif
    235 #if defined (EDEADLOCK)
    236   ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"),
    237 #endif
    238 #if defined (EBFONT)
    239   ENTRY(EBFONT, "EBFONT", "Bad font file format"),
    240 #endif
    241 #if defined (ENOSTR)
    242   ENTRY(ENOSTR, "ENOSTR", "Device not a stream"),
    243 #endif
    244 #if defined (ENODATA)
    245   ENTRY(ENODATA, "ENODATA", "No data available"),
    246 #endif
    247 #if defined (ETIME)
    248   ENTRY(ETIME, "ETIME", "Timer expired"),
    249 #endif
    250 #if defined (ENOSR)
    251   ENTRY(ENOSR, "ENOSR", "Out of streams resources"),
    252 #endif
    253 #if defined (ENONET)
    254   ENTRY(ENONET, "ENONET", "Machine is not on the network"),
    255 #endif
    256 #if defined (ENOPKG)
    257   ENTRY(ENOPKG, "ENOPKG", "Package not installed"),
    258 #endif
    259 #if defined (EREMOTE)
    260   ENTRY(EREMOTE, "EREMOTE", "Object is remote"),
    261 #endif
    262 #if defined (ENOLINK)
    263   ENTRY(ENOLINK, "ENOLINK", "Link has been severed"),
    264 #endif
    265 #if defined (EADV)
    266   ENTRY(EADV, "EADV", "Advertise error"),
    267 #endif
    268 #if defined (ESRMNT)
    269   ENTRY(ESRMNT, "ESRMNT", "Srmount error"),
    270 #endif
    271 #if defined (ECOMM)
    272   ENTRY(ECOMM, "ECOMM", "Communication error on send"),
    273 #endif
    274 #if defined (EPROTO)
    275   ENTRY(EPROTO, "EPROTO", "Protocol error"),
    276 #endif
    277 #if defined (EMULTIHOP)
    278   ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"),
    279 #endif
    280 #if defined (EDOTDOT)
    281   ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"),
    282 #endif
    283 #if defined (EBADMSG)
    284   ENTRY(EBADMSG, "EBADMSG", "Not a data message"),
    285 #endif
    286 #if defined (ENAMETOOLONG)
    287   ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"),
    288 #endif
    289 #if defined (EOVERFLOW)
    290   ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"),
    291 #endif
    292 #if defined (ENOTUNIQ)
    293   ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"),
    294 #endif
    295 #if defined (EBADFD)
    296   ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"),
    297 #endif
    298 #if defined (EREMCHG)
    299   ENTRY(EREMCHG, "EREMCHG", "Remote address changed"),
    300 #endif
    301 #if defined (ELIBACC)
    302   ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"),
    303 #endif
    304 #if defined (ELIBBAD)
    305   ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"),
    306 #endif
    307 #if defined (ELIBSCN)
    308   ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"),
    309 #endif
    310 #if defined (ELIBMAX)
    311   ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"),
    312 #endif
    313 #if defined (ELIBEXEC)
    314   ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"),
    315 #endif
    316 #if defined (EILSEQ)
    317   ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"),
    318 #endif
    319 #if defined (ENOSYS)
    320   ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"),
    321 #endif
    322 #if defined (ELOOP)
    323   ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"),
    324 #endif
    325 #if defined (ERESTART)
    326   ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"),
    327 #endif
    328 #if defined (ESTRPIPE)
    329   ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"),
    330 #endif
    331 #if defined (ENOTEMPTY)
    332   ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"),
    333 #endif
    334 #if defined (EUSERS)
    335   ENTRY(EUSERS, "EUSERS", "Too many users"),
    336 #endif
    337 #if defined (ENOTSOCK)
    338   ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"),
    339 #endif
    340 #if defined (EDESTADDRREQ)
    341   ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"),
    342 #endif
    343 #if defined (EMSGSIZE)
    344   ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"),
    345 #endif
    346 #if defined (EPROTOTYPE)
    347   ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"),
    348 #endif
    349 #if defined (ENOPROTOOPT)
    350   ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"),
    351 #endif
    352 #if defined (EPROTONOSUPPORT)
    353   ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"),
    354 #endif
    355 #if defined (ESOCKTNOSUPPORT)
    356   ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"),
    357 #endif
    358 #if defined (EOPNOTSUPP)
    359   ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"),
    360 #endif
    361 #if defined (EPFNOSUPPORT)
    362   ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"),
    363 #endif
    364 #if defined (EAFNOSUPPORT)
    365   ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"),
    366 #endif
    367 #if defined (EADDRINUSE)
    368   ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"),
    369 #endif
    370 #if defined (EADDRNOTAVAIL)
    371   ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"),
    372 #endif
    373 #if defined (ENETDOWN)
    374   ENTRY(ENETDOWN, "ENETDOWN", "Network is down"),
    375 #endif
    376 #if defined (ENETUNREACH)
    377   ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"),
    378 #endif
    379 #if defined (ENETRESET)
    380   ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"),
    381 #endif
    382 #if defined (ECONNABORTED)
    383   ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"),
    384 #endif
    385 #if defined (ECONNRESET)
    386   ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"),
    387 #endif
    388 #if defined (ENOBUFS)
    389   ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"),
    390 #endif
    391 #if defined (EISCONN)
    392   ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"),
    393 #endif
    394 #if defined (ENOTCONN)
    395   ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"),
    396 #endif
    397 #if defined (ESHUTDOWN)
    398   ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"),
    399 #endif
    400 #if defined (ETOOMANYREFS)
    401   ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"),
    402 #endif
    403 #if defined (ETIMEDOUT)
    404   ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"),
    405 #endif
    406 #if defined (ECONNREFUSED)
    407   ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"),
    408 #endif
    409 #if defined (EHOSTDOWN)
    410   ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"),
    411 #endif
    412 #if defined (EHOSTUNREACH)
    413   ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"),
    414 #endif
    415 #if defined (EALREADY)
    416   ENTRY(EALREADY, "EALREADY", "Operation already in progress"),
    417 #endif
    418 #if defined (EINPROGRESS)
    419   ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"),
    420 #endif
    421 #if defined (ESTALE)
    422   ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"),
    423 #endif
    424 #if defined (EUCLEAN)
    425   ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"),
    426 #endif
    427 #if defined (ENOTNAM)
    428   ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"),
    429 #endif
    430 #if defined (ENAVAIL)
    431   ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"),
    432 #endif
    433 #if defined (EISNAM)
    434   ENTRY(EISNAM, "EISNAM", "Is a named type file"),
    435 #endif
    436 #if defined (EREMOTEIO)
    437   ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"),
    438 #endif
    439   ENTRY(0, NULL, NULL)
    440 };
    441 
    442 #ifdef EVMSERR
    443 /* This is not in the table, because the numeric value of EVMSERR (32767)
    444    lies outside the range of sys_errlist[].  */
    445 static struct { int value; const char *name, *msg; }
    446   evmserr = { EVMSERR, "EVMSERR", "VMS-specific error" };
    447 #endif
    448 
    449 /* Translation table allocated and initialized at runtime.  Indexed by the
    450    errno value to find the equivalent symbolic value. */
    451 
    452 static const char **error_names;
    453 static int num_error_names = 0;
    454 
    455 /* Translation table allocated and initialized at runtime, if it does not
    456    already exist in the host environment.  Indexed by the errno value to find
    457    the descriptive string.
    458 
    459    We don't export it for use in other modules because even though it has the
    460    same name, it differs from other implementations in that it is dynamically
    461    initialized rather than statically initialized. */
    462 
    463 #ifndef HAVE_SYS_ERRLIST
    464 
    465 #define sys_nerr sys_nerr__
    466 #define sys_errlist sys_errlist__
    467 static int sys_nerr;
    468 static const char **sys_errlist;
    469 
    470 #else
    471 
    472 
    473 #ifndef sys_nerr
    474 extern int sys_nerr;
    475 #endif
    476 #ifndef sys_errlist
    477 extern char *sys_errlist[];
    478 #endif
    479 
    480 #endif
    481 
    482 /*
    483 
    484 NAME
    485 
    486 	init_error_tables -- initialize the name and message tables
    487 
    488 SYNOPSIS
    489 
    490 	static void init_error_tables ();
    491 
    492 DESCRIPTION
    493 
    494 	Using the error_table, which is initialized at compile time, generate
    495 	the error_names and the sys_errlist (if needed) tables, which are
    496 	indexed at runtime by a specific errno value.
    497 
    498 BUGS
    499 
    500 	The initialization of the tables may fail under low memory conditions,
    501 	in which case we don't do anything particularly useful, but we don't
    502 	bomb either.  Who knows, it might succeed at a later point if we free
    503 	some memory in the meantime.  In any case, the other routines know
    504 	how to deal with lack of a table after trying to initialize it.  This
    505 	may or may not be considered to be a bug, that we don't specifically
    506 	warn about this particular failure mode.
    507 
    508 */
    509 
    510 static void
    511 init_error_tables (void)
    512 {
    513   const struct error_info *eip;
    514   int nbytes;
    515 
    516   /* If we haven't already scanned the error_table once to find the maximum
    517      errno value, then go find it now. */
    518 
    519   if (num_error_names == 0)
    520     {
    521       for (eip = error_table; eip -> name != NULL; eip++)
    522 	{
    523 	  if (eip -> value >= num_error_names)
    524 	    {
    525 	      num_error_names = eip -> value + 1;
    526 	    }
    527 	}
    528     }
    529 
    530   /* Now attempt to allocate the error_names table, zero it out, and then
    531      initialize it from the statically initialized error_table. */
    532 
    533   if (error_names == NULL)
    534     {
    535       nbytes = num_error_names * sizeof (char *);
    536       if ((error_names = (const char **) malloc (nbytes)) != NULL)
    537 	{
    538 	  memset (error_names, 0, nbytes);
    539 	  for (eip = error_table; eip -> name != NULL; eip++)
    540 	    {
    541 	      error_names[eip -> value] = eip -> name;
    542 	    }
    543 	}
    544     }
    545 
    546 #ifndef HAVE_SYS_ERRLIST
    547 
    548   /* Now attempt to allocate the sys_errlist table, zero it out, and then
    549      initialize it from the statically initialized error_table. */
    550 
    551   if (sys_errlist == NULL)
    552     {
    553       nbytes = num_error_names * sizeof (char *);
    554       if ((sys_errlist = (const char **) malloc (nbytes)) != NULL)
    555 	{
    556 	  memset (sys_errlist, 0, nbytes);
    557 	  sys_nerr = num_error_names;
    558 	  for (eip = error_table; eip -> name != NULL; eip++)
    559 	    {
    560 	      sys_errlist[eip -> value] = eip -> msg;
    561 	    }
    562 	}
    563     }
    564 
    565 #endif
    566 
    567 }
    568 
    569 /*
    570 
    571 
    572 @deftypefn Extension int errno_max (void)
    573 
    574 Returns the maximum @code{errno} value for which a corresponding
    575 symbolic name or message is available.  Note that in the case where we
    576 use the @code{sys_errlist} supplied by the system, it is possible for
    577 there to be more symbolic names than messages, or vice versa.  In
    578 fact, the manual page for @code{perror(3C)} explicitly warns that one
    579 should check the size of the table (@code{sys_nerr}) before indexing
    580 it, since new error codes may be added to the system before they are
    581 added to the table.  Thus @code{sys_nerr} might be smaller than value
    582 implied by the largest @code{errno} value defined in @code{<errno.h>}.
    583 
    584 We return the maximum value that can be used to obtain a meaningful
    585 symbolic name or message.
    586 
    587 @end deftypefn
    588 
    589 */
    590 
    591 int
    592 errno_max (void)
    593 {
    594   int maxsize;
    595 
    596   if (error_names == NULL)
    597     {
    598       init_error_tables ();
    599     }
    600   maxsize = MAX (sys_nerr, num_error_names);
    601   return (maxsize - 1);
    602 }
    603 
    604 #ifndef HAVE_STRERROR
    605 
    606 /*
    607 
    608 @deftypefn Supplemental char* strerror (int @var{errnoval})
    609 
    610 Maps an @code{errno} number to an error message string, the contents
    611 of which are implementation defined.  On systems which have the
    612 external variables @code{sys_nerr} and @code{sys_errlist}, these
    613 strings will be the same as the ones used by @code{perror}.
    614 
    615 If the supplied error number is within the valid range of indices for
    616 the @code{sys_errlist}, but no message is available for the particular
    617 error number, then returns the string @samp{Error @var{num}}, where
    618 @var{num} is the error number.
    619 
    620 If the supplied error number is not a valid index into
    621 @code{sys_errlist}, returns @code{NULL}.
    622 
    623 The returned string is only guaranteed to be valid only until the
    624 next call to @code{strerror}.
    625 
    626 @end deftypefn
    627 
    628 */
    629 
    630 char *
    631 strerror (int errnoval)
    632 {
    633   const char *msg;
    634   static char buf[32];
    635 
    636 #ifndef HAVE_SYS_ERRLIST
    637 
    638   if (error_names == NULL)
    639     {
    640       init_error_tables ();
    641     }
    642 
    643 #endif
    644 
    645   if ((errnoval < 0) || (errnoval >= sys_nerr))
    646     {
    647 #ifdef EVMSERR
    648       if (errnoval == evmserr.value)
    649 	msg = evmserr.msg;
    650       else
    651 #endif
    652       /* Out of range, just return NULL */
    653       msg = NULL;
    654     }
    655   else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
    656     {
    657       /* In range, but no sys_errlist or no entry at this index. */
    658       sprintf (buf, "Error %d", errnoval);
    659       msg = buf;
    660     }
    661   else
    662     {
    663       /* In range, and a valid message.  Just return the message. */
    664       msg = (char *) sys_errlist[errnoval];
    665     }
    666 
    667   return (msg);
    668 }
    669 
    670 #endif	/* ! HAVE_STRERROR */
    671 
    672 
    673 /*
    674 
    675 @deftypefn Replacement {const char*} strerrno (int @var{errnum})
    676 
    677 Given an error number returned from a system call (typically returned
    678 in @code{errno}), returns a pointer to a string containing the
    679 symbolic name of that error number, as found in @code{<errno.h>}.
    680 
    681 If the supplied error number is within the valid range of indices for
    682 symbolic names, but no name is available for the particular error
    683 number, then returns the string @samp{Error @var{num}}, where @var{num}
    684 is the error number.
    685 
    686 If the supplied error number is not within the range of valid
    687 indices, then returns @code{NULL}.
    688 
    689 The contents of the location pointed to are only guaranteed to be
    690 valid until the next call to @code{strerrno}.
    691 
    692 @end deftypefn
    693 
    694 */
    695 
    696 const char *
    697 strerrno (int errnoval)
    698 {
    699   const char *name;
    700   static char buf[32];
    701 
    702   if (error_names == NULL)
    703     {
    704       init_error_tables ();
    705     }
    706 
    707   if ((errnoval < 0) || (errnoval >= num_error_names))
    708     {
    709 #ifdef EVMSERR
    710       if (errnoval == evmserr.value)
    711 	name = evmserr.name;
    712       else
    713 #endif
    714       /* Out of range, just return NULL */
    715       name = NULL;
    716     }
    717   else if ((error_names == NULL) || (error_names[errnoval] == NULL))
    718     {
    719       /* In range, but no error_names or no entry at this index. */
    720       sprintf (buf, "Error %d", errnoval);
    721       name = (const char *) buf;
    722     }
    723   else
    724     {
    725       /* In range, and a valid name.  Just return the name. */
    726       name = error_names[errnoval];
    727     }
    728 
    729   return (name);
    730 }
    731 
    732 /*
    733 
    734 @deftypefn Extension int strtoerrno (const char *@var{name})
    735 
    736 Given the symbolic name of a error number (e.g., @code{EACCES}), map it
    737 to an errno value.  If no translation is found, returns 0.
    738 
    739 @end deftypefn
    740 
    741 */
    742 
    743 int
    744 strtoerrno (const char *name)
    745 {
    746   int errnoval = 0;
    747 
    748   if (name != NULL)
    749     {
    750       if (error_names == NULL)
    751 	{
    752 	  init_error_tables ();
    753 	}
    754       for (errnoval = 0; errnoval < num_error_names; errnoval++)
    755 	{
    756 	  if ((error_names[errnoval] != NULL) &&
    757 	      (strcmp (name, error_names[errnoval]) == 0))
    758 	    {
    759 	      break;
    760 	    }
    761 	}
    762       if (errnoval == num_error_names)
    763 	{
    764 #ifdef EVMSERR
    765 	  if (strcmp (name, evmserr.name) == 0)
    766 	    errnoval = evmserr.value;
    767 	  else
    768 #endif
    769 	  errnoval = 0;
    770 	}
    771     }
    772   return (errnoval);
    773 }
    774 
    775 
    776 /* A simple little main that does nothing but print all the errno translations
    777    if MAIN is defined and this file is compiled and linked. */
    778 
    779 #ifdef MAIN
    780 
    781 #include <stdio.h>
    782 
    783 int
    784 main (void)
    785 {
    786   int errn;
    787   int errnmax;
    788   const char *name;
    789   const char *msg;
    790   char *strerror ();
    791 
    792   errnmax = errno_max ();
    793   printf ("%d entries in names table.\n", num_error_names);
    794   printf ("%d entries in messages table.\n", sys_nerr);
    795   printf ("%d is max useful index.\n", errnmax);
    796 
    797   /* Keep printing values until we get to the end of *both* tables, not
    798      *either* table.  Note that knowing the maximum useful index does *not*
    799      relieve us of the responsibility of testing the return pointer for
    800      NULL. */
    801 
    802   for (errn = 0; errn <= errnmax; errn++)
    803     {
    804       name = strerrno (errn);
    805       name = (name == NULL) ? "<NULL>" : name;
    806       msg = strerror (errn);
    807       msg = (msg == NULL) ? "<NULL>" : msg;
    808       printf ("%-4d%-18s%s\n", errn, name, msg);
    809     }
    810 
    811   return 0;
    812 }
    813 
    814 #endif
    815