(root)/
gcc-13.2.0/
libiberty/
strerror.c
       1  /* Extended support for using errno values.
       2     Written by Fred Fish.  fnf@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 void *malloc ();
      34  #endif
      35  
      36  #ifdef HAVE_STRING_H
      37  #include <string.h>
      38  #else
      39  extern void *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", "Cannot 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