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 extern int sys_nerr;
    473 extern char *sys_errlist[];
    474 
    475 #endif
    476 
    477 /*
    478 
    479 NAME
    480 
    481 	init_error_tables -- initialize the name and message tables
    482 
    483 SYNOPSIS
    484 
    485 	static void init_error_tables ();
    486 
    487 DESCRIPTION
    488 
    489 	Using the error_table, which is initialized at compile time, generate
    490 	the error_names and the sys_errlist (if needed) tables, which are
    491 	indexed at runtime by a specific errno value.
    492 
    493 BUGS
    494 
    495 	The initialization of the tables may fail under low memory conditions,
    496 	in which case we don't do anything particularly useful, but we don't
    497 	bomb either.  Who knows, it might succeed at a later point if we free
    498 	some memory in the meantime.  In any case, the other routines know
    499 	how to deal with lack of a table after trying to initialize it.  This
    500 	may or may not be considered to be a bug, that we don't specifically
    501 	warn about this particular failure mode.
    502 
    503 */
    504 
    505 static void
    506 init_error_tables (void)
    507 {
    508   const struct error_info *eip;
    509   int nbytes;
    510 
    511   /* If we haven't already scanned the error_table once to find the maximum
    512      errno value, then go find it now. */
    513 
    514   if (num_error_names == 0)
    515     {
    516       for (eip = error_table; eip -> name != NULL; eip++)
    517 	{
    518 	  if (eip -> value >= num_error_names)
    519 	    {
    520 	      num_error_names = eip -> value + 1;
    521 	    }
    522 	}
    523     }
    524 
    525   /* Now attempt to allocate the error_names table, zero it out, and then
    526      initialize it from the statically initialized error_table. */
    527 
    528   if (error_names == NULL)
    529     {
    530       nbytes = num_error_names * sizeof (char *);
    531       if ((error_names = (const char **) malloc (nbytes)) != NULL)
    532 	{
    533 	  memset (error_names, 0, nbytes);
    534 	  for (eip = error_table; eip -> name != NULL; eip++)
    535 	    {
    536 	      error_names[eip -> value] = eip -> name;
    537 	    }
    538 	}
    539     }
    540 
    541 #ifndef HAVE_SYS_ERRLIST
    542 
    543   /* Now attempt to allocate the sys_errlist table, zero it out, and then
    544      initialize it from the statically initialized error_table. */
    545 
    546   if (sys_errlist == NULL)
    547     {
    548       nbytes = num_error_names * sizeof (char *);
    549       if ((sys_errlist = (const char **) malloc (nbytes)) != NULL)
    550 	{
    551 	  memset (sys_errlist, 0, nbytes);
    552 	  sys_nerr = num_error_names;
    553 	  for (eip = error_table; eip -> name != NULL; eip++)
    554 	    {
    555 	      sys_errlist[eip -> value] = eip -> msg;
    556 	    }
    557 	}
    558     }
    559 
    560 #endif
    561 
    562 }
    563 
    564 /*
    565 
    566 
    567 @deftypefn Extension int errno_max (void)
    568 
    569 Returns the maximum @code{errno} value for which a corresponding
    570 symbolic name or message is available.  Note that in the case where we
    571 use the @code{sys_errlist} supplied by the system, it is possible for
    572 there to be more symbolic names than messages, or vice versa.  In
    573 fact, the manual page for @code{perror(3C)} explicitly warns that one
    574 should check the size of the table (@code{sys_nerr}) before indexing
    575 it, since new error codes may be added to the system before they are
    576 added to the table.  Thus @code{sys_nerr} might be smaller than value
    577 implied by the largest @code{errno} value defined in @code{<errno.h>}.
    578 
    579 We return the maximum value that can be used to obtain a meaningful
    580 symbolic name or message.
    581 
    582 @end deftypefn
    583 
    584 */
    585 
    586 int
    587 errno_max (void)
    588 {
    589   int maxsize;
    590 
    591   if (error_names == NULL)
    592     {
    593       init_error_tables ();
    594     }
    595   maxsize = MAX (sys_nerr, num_error_names);
    596   return (maxsize - 1);
    597 }
    598 
    599 #ifndef HAVE_STRERROR
    600 
    601 /*
    602 
    603 @deftypefn Supplemental char* strerror (int @var{errnoval})
    604 
    605 Maps an @code{errno} number to an error message string, the contents
    606 of which are implementation defined.  On systems which have the
    607 external variables @code{sys_nerr} and @code{sys_errlist}, these
    608 strings will be the same as the ones used by @code{perror}.
    609 
    610 If the supplied error number is within the valid range of indices for
    611 the @code{sys_errlist}, but no message is available for the particular
    612 error number, then returns the string @samp{Error @var{num}}, where
    613 @var{num} is the error number.
    614 
    615 If the supplied error number is not a valid index into
    616 @code{sys_errlist}, returns @code{NULL}.
    617 
    618 The returned string is only guaranteed to be valid only until the
    619 next call to @code{strerror}.
    620 
    621 @end deftypefn
    622 
    623 */
    624 
    625 char *
    626 strerror (int errnoval)
    627 {
    628   const char *msg;
    629   static char buf[32];
    630 
    631 #ifndef HAVE_SYS_ERRLIST
    632 
    633   if (error_names == NULL)
    634     {
    635       init_error_tables ();
    636     }
    637 
    638 #endif
    639 
    640   if ((errnoval < 0) || (errnoval >= sys_nerr))
    641     {
    642 #ifdef EVMSERR
    643       if (errnoval == evmserr.value)
    644 	msg = evmserr.msg;
    645       else
    646 #endif
    647       /* Out of range, just return NULL */
    648       msg = NULL;
    649     }
    650   else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
    651     {
    652       /* In range, but no sys_errlist or no entry at this index. */
    653       sprintf (buf, "Error %d", errnoval);
    654       msg = buf;
    655     }
    656   else
    657     {
    658       /* In range, and a valid message.  Just return the message. */
    659       msg = (char *) sys_errlist[errnoval];
    660     }
    661 
    662   return (msg);
    663 }
    664 
    665 #endif	/* ! HAVE_STRERROR */
    666 
    667 
    668 /*
    669 
    670 @deftypefn Replacement {const char*} strerrno (int @var{errnum})
    671 
    672 Given an error number returned from a system call (typically returned
    673 in @code{errno}), returns a pointer to a string containing the
    674 symbolic name of that error number, as found in @code{<errno.h>}.
    675 
    676 If the supplied error number is within the valid range of indices for
    677 symbolic names, but no name is available for the particular error
    678 number, then returns the string @samp{Error @var{num}}, where @var{num}
    679 is the error number.
    680 
    681 If the supplied error number is not within the range of valid
    682 indices, then returns @code{NULL}.
    683 
    684 The contents of the location pointed to are only guaranteed to be
    685 valid until the next call to @code{strerrno}.
    686 
    687 @end deftypefn
    688 
    689 */
    690 
    691 const char *
    692 strerrno (int errnoval)
    693 {
    694   const char *name;
    695   static char buf[32];
    696 
    697   if (error_names == NULL)
    698     {
    699       init_error_tables ();
    700     }
    701 
    702   if ((errnoval < 0) || (errnoval >= num_error_names))
    703     {
    704 #ifdef EVMSERR
    705       if (errnoval == evmserr.value)
    706 	name = evmserr.name;
    707       else
    708 #endif
    709       /* Out of range, just return NULL */
    710       name = NULL;
    711     }
    712   else if ((error_names == NULL) || (error_names[errnoval] == NULL))
    713     {
    714       /* In range, but no error_names or no entry at this index. */
    715       sprintf (buf, "Error %d", errnoval);
    716       name = (const char *) buf;
    717     }
    718   else
    719     {
    720       /* In range, and a valid name.  Just return the name. */
    721       name = error_names[errnoval];
    722     }
    723 
    724   return (name);
    725 }
    726 
    727 /*
    728 
    729 @deftypefn Extension int strtoerrno (const char *@var{name})
    730 
    731 Given the symbolic name of a error number (e.g., @code{EACCES}), map it
    732 to an errno value.  If no translation is found, returns 0.
    733 
    734 @end deftypefn
    735 
    736 */
    737 
    738 int
    739 strtoerrno (const char *name)
    740 {
    741   int errnoval = 0;
    742 
    743   if (name != NULL)
    744     {
    745       if (error_names == NULL)
    746 	{
    747 	  init_error_tables ();
    748 	}
    749       for (errnoval = 0; errnoval < num_error_names; errnoval++)
    750 	{
    751 	  if ((error_names[errnoval] != NULL) &&
    752 	      (strcmp (name, error_names[errnoval]) == 0))
    753 	    {
    754 	      break;
    755 	    }
    756 	}
    757       if (errnoval == num_error_names)
    758 	{
    759 #ifdef EVMSERR
    760 	  if (strcmp (name, evmserr.name) == 0)
    761 	    errnoval = evmserr.value;
    762 	  else
    763 #endif
    764 	  errnoval = 0;
    765 	}
    766     }
    767   return (errnoval);
    768 }
    769 
    770 
    771 /* A simple little main that does nothing but print all the errno translations
    772    if MAIN is defined and this file is compiled and linked. */
    773 
    774 #ifdef MAIN
    775 
    776 #include <stdio.h>
    777 
    778 int
    779 main (void)
    780 {
    781   int errn;
    782   int errnmax;
    783   const char *name;
    784   const char *msg;
    785   char *strerror ();
    786 
    787   errnmax = errno_max ();
    788   printf ("%d entries in names table.\n", num_error_names);
    789   printf ("%d entries in messages table.\n", sys_nerr);
    790   printf ("%d is max useful index.\n", errnmax);
    791 
    792   /* Keep printing values until we get to the end of *both* tables, not
    793      *either* table.  Note that knowing the maximum useful index does *not*
    794      relieve us of the responsibility of testing the return pointer for
    795      NULL. */
    796 
    797   for (errn = 0; errn <= errnmax; errn++)
    798     {
    799       name = strerrno (errn);
    800       name = (name == NULL) ? "<NULL>" : name;
    801       msg = strerror (errn);
    802       msg = (msg == NULL) ? "<NULL>" : msg;
    803       printf ("%-4d%-18s%s\n", errn, name, msg);
    804     }
    805 
    806   return 0;
    807 }
    808 
    809 #endif
    810