Back to index

cell-binutils  2.17cvs20070401
strerror.c
Go to the documentation of this file.
00001 /* Extended support for using errno values.
00002    Written by Fred Fish.  fnf@cygnus.com
00003    This file is in the public domain.  --Per Bothner.  */
00004 
00005 #include "config.h"
00006 
00007 #ifdef HAVE_SYS_ERRLIST
00008 /* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least)
00009    might declare sys_errlist in a way that the compiler might consider
00010    incompatible with our later declaration, perhaps by using const
00011    attributes.  So we hide the declaration in errno.h (if any) using a
00012    macro. */
00013 #define sys_nerr sys_nerr__
00014 #define sys_errlist sys_errlist__
00015 #endif
00016 
00017 #include "ansidecl.h"
00018 #include "libiberty.h"
00019 
00020 #include <stdio.h>
00021 #include <errno.h>
00022 
00023 #ifdef HAVE_SYS_ERRLIST
00024 #undef sys_nerr
00025 #undef sys_errlist
00026 #endif
00027 
00028 /*  Routines imported from standard C runtime libraries. */
00029 
00030 #ifdef HAVE_STDLIB_H
00031 #include <stdlib.h>
00032 #else
00033 extern PTR malloc ();
00034 #endif
00035 
00036 #ifdef HAVE_STRING_H
00037 #include <string.h>
00038 #else
00039 extern PTR memset ();
00040 #endif
00041 
00042 #ifndef MAX
00043 #  define MAX(a,b) ((a) > (b) ? (a) : (b))
00044 #endif
00045 
00046 static void init_error_tables (void);
00047 
00048 /* Translation table for errno values.  See intro(2) in most UNIX systems
00049    Programmers Reference Manuals.
00050 
00051    Note that this table is generally only accessed when it is used at runtime
00052    to initialize errno name and message tables that are indexed by errno
00053    value.
00054 
00055    Not all of these errnos will exist on all systems.  This table is the only
00056    thing that should have to be updated as new error numbers are introduced.
00057    It's sort of ugly, but at least its portable. */
00058 
00059 struct error_info
00060 {
00061   const int value;          /* The numeric value from <errno.h> */
00062   const char *const name;   /* The equivalent symbolic value */
00063 #ifndef HAVE_SYS_ERRLIST
00064   const char *const msg;    /* Short message about this value */
00065 #endif
00066 };
00067 
00068 #ifndef HAVE_SYS_ERRLIST
00069 #   define ENTRY(value, name, msg) {value, name, msg}
00070 #else
00071 #   define ENTRY(value, name, msg) {value, name}
00072 #endif
00073 
00074 static const struct error_info error_table[] =
00075 {
00076 #if defined (EPERM)
00077   ENTRY(EPERM, "EPERM", "Not owner"),
00078 #endif
00079 #if defined (ENOENT)
00080   ENTRY(ENOENT, "ENOENT", "No such file or directory"),
00081 #endif
00082 #if defined (ESRCH)
00083   ENTRY(ESRCH, "ESRCH", "No such process"),
00084 #endif
00085 #if defined (EINTR)
00086   ENTRY(EINTR, "EINTR", "Interrupted system call"),
00087 #endif
00088 #if defined (EIO)
00089   ENTRY(EIO, "EIO", "I/O error"),
00090 #endif
00091 #if defined (ENXIO)
00092   ENTRY(ENXIO, "ENXIO", "No such device or address"),
00093 #endif
00094 #if defined (E2BIG)
00095   ENTRY(E2BIG, "E2BIG", "Arg list too long"),
00096 #endif
00097 #if defined (ENOEXEC)
00098   ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"),
00099 #endif
00100 #if defined (EBADF)
00101   ENTRY(EBADF, "EBADF", "Bad file number"),
00102 #endif
00103 #if defined (ECHILD)
00104   ENTRY(ECHILD, "ECHILD", "No child processes"),
00105 #endif
00106 #if defined (EWOULDBLOCK)   /* Put before EAGAIN, sometimes aliased */
00107   ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"),
00108 #endif
00109 #if defined (EAGAIN)
00110   ENTRY(EAGAIN, "EAGAIN", "No more processes"),
00111 #endif
00112 #if defined (ENOMEM)
00113   ENTRY(ENOMEM, "ENOMEM", "Not enough space"),
00114 #endif
00115 #if defined (EACCES)
00116   ENTRY(EACCES, "EACCES", "Permission denied"),
00117 #endif
00118 #if defined (EFAULT)
00119   ENTRY(EFAULT, "EFAULT", "Bad address"),
00120 #endif
00121 #if defined (ENOTBLK)
00122   ENTRY(ENOTBLK, "ENOTBLK", "Block device required"),
00123 #endif
00124 #if defined (EBUSY)
00125   ENTRY(EBUSY, "EBUSY", "Device busy"),
00126 #endif
00127 #if defined (EEXIST)
00128   ENTRY(EEXIST, "EEXIST", "File exists"),
00129 #endif
00130 #if defined (EXDEV)
00131   ENTRY(EXDEV, "EXDEV", "Cross-device link"),
00132 #endif
00133 #if defined (ENODEV)
00134   ENTRY(ENODEV, "ENODEV", "No such device"),
00135 #endif
00136 #if defined (ENOTDIR)
00137   ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"),
00138 #endif
00139 #if defined (EISDIR)
00140   ENTRY(EISDIR, "EISDIR", "Is a directory"),
00141 #endif
00142 #if defined (EINVAL)
00143   ENTRY(EINVAL, "EINVAL", "Invalid argument"),
00144 #endif
00145 #if defined (ENFILE)
00146   ENTRY(ENFILE, "ENFILE", "File table overflow"),
00147 #endif
00148 #if defined (EMFILE)
00149   ENTRY(EMFILE, "EMFILE", "Too many open files"),
00150 #endif
00151 #if defined (ENOTTY)
00152   ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"),
00153 #endif
00154 #if defined (ETXTBSY)
00155   ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"),
00156 #endif
00157 #if defined (EFBIG)
00158   ENTRY(EFBIG, "EFBIG", "File too large"),
00159 #endif
00160 #if defined (ENOSPC)
00161   ENTRY(ENOSPC, "ENOSPC", "No space left on device"),
00162 #endif
00163 #if defined (ESPIPE)
00164   ENTRY(ESPIPE, "ESPIPE", "Illegal seek"),
00165 #endif
00166 #if defined (EROFS)
00167   ENTRY(EROFS, "EROFS", "Read-only file system"),
00168 #endif
00169 #if defined (EMLINK)
00170   ENTRY(EMLINK, "EMLINK", "Too many links"),
00171 #endif
00172 #if defined (EPIPE)
00173   ENTRY(EPIPE, "EPIPE", "Broken pipe"),
00174 #endif
00175 #if defined (EDOM)
00176   ENTRY(EDOM, "EDOM", "Math argument out of domain of func"),
00177 #endif
00178 #if defined (ERANGE)
00179   ENTRY(ERANGE, "ERANGE", "Math result not representable"),
00180 #endif
00181 #if defined (ENOMSG)
00182   ENTRY(ENOMSG, "ENOMSG", "No message of desired type"),
00183 #endif
00184 #if defined (EIDRM)
00185   ENTRY(EIDRM, "EIDRM", "Identifier removed"),
00186 #endif
00187 #if defined (ECHRNG)
00188   ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"),
00189 #endif
00190 #if defined (EL2NSYNC)
00191   ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"),
00192 #endif
00193 #if defined (EL3HLT)
00194   ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"),
00195 #endif
00196 #if defined (EL3RST)
00197   ENTRY(EL3RST, "EL3RST", "Level 3 reset"),
00198 #endif
00199 #if defined (ELNRNG)
00200   ENTRY(ELNRNG, "ELNRNG", "Link number out of range"),
00201 #endif
00202 #if defined (EUNATCH)
00203   ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"),
00204 #endif
00205 #if defined (ENOCSI)
00206   ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"),
00207 #endif
00208 #if defined (EL2HLT)
00209   ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"),
00210 #endif
00211 #if defined (EDEADLK)
00212   ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"),
00213 #endif
00214 #if defined (ENOLCK)
00215   ENTRY(ENOLCK, "ENOLCK", "No record locks available"),
00216 #endif
00217 #if defined (EBADE)
00218   ENTRY(EBADE, "EBADE", "Invalid exchange"),
00219 #endif
00220 #if defined (EBADR)
00221   ENTRY(EBADR, "EBADR", "Invalid request descriptor"),
00222 #endif
00223 #if defined (EXFULL)
00224   ENTRY(EXFULL, "EXFULL", "Exchange full"),
00225 #endif
00226 #if defined (ENOANO)
00227   ENTRY(ENOANO, "ENOANO", "No anode"),
00228 #endif
00229 #if defined (EBADRQC)
00230   ENTRY(EBADRQC, "EBADRQC", "Invalid request code"),
00231 #endif
00232 #if defined (EBADSLT)
00233   ENTRY(EBADSLT, "EBADSLT", "Invalid slot"),
00234 #endif
00235 #if defined (EDEADLOCK)
00236   ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"),
00237 #endif
00238 #if defined (EBFONT)
00239   ENTRY(EBFONT, "EBFONT", "Bad font file format"),
00240 #endif
00241 #if defined (ENOSTR)
00242   ENTRY(ENOSTR, "ENOSTR", "Device not a stream"),
00243 #endif
00244 #if defined (ENODATA)
00245   ENTRY(ENODATA, "ENODATA", "No data available"),
00246 #endif
00247 #if defined (ETIME)
00248   ENTRY(ETIME, "ETIME", "Timer expired"),
00249 #endif
00250 #if defined (ENOSR)
00251   ENTRY(ENOSR, "ENOSR", "Out of streams resources"),
00252 #endif
00253 #if defined (ENONET)
00254   ENTRY(ENONET, "ENONET", "Machine is not on the network"),
00255 #endif
00256 #if defined (ENOPKG)
00257   ENTRY(ENOPKG, "ENOPKG", "Package not installed"),
00258 #endif
00259 #if defined (EREMOTE)
00260   ENTRY(EREMOTE, "EREMOTE", "Object is remote"),
00261 #endif
00262 #if defined (ENOLINK)
00263   ENTRY(ENOLINK, "ENOLINK", "Link has been severed"),
00264 #endif
00265 #if defined (EADV)
00266   ENTRY(EADV, "EADV", "Advertise error"),
00267 #endif
00268 #if defined (ESRMNT)
00269   ENTRY(ESRMNT, "ESRMNT", "Srmount error"),
00270 #endif
00271 #if defined (ECOMM)
00272   ENTRY(ECOMM, "ECOMM", "Communication error on send"),
00273 #endif
00274 #if defined (EPROTO)
00275   ENTRY(EPROTO, "EPROTO", "Protocol error"),
00276 #endif
00277 #if defined (EMULTIHOP)
00278   ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"),
00279 #endif
00280 #if defined (EDOTDOT)
00281   ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"),
00282 #endif
00283 #if defined (EBADMSG)
00284   ENTRY(EBADMSG, "EBADMSG", "Not a data message"),
00285 #endif
00286 #if defined (ENAMETOOLONG)
00287   ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"),
00288 #endif
00289 #if defined (EOVERFLOW)
00290   ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"),
00291 #endif
00292 #if defined (ENOTUNIQ)
00293   ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"),
00294 #endif
00295 #if defined (EBADFD)
00296   ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"),
00297 #endif
00298 #if defined (EREMCHG)
00299   ENTRY(EREMCHG, "EREMCHG", "Remote address changed"),
00300 #endif
00301 #if defined (ELIBACC)
00302   ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"),
00303 #endif
00304 #if defined (ELIBBAD)
00305   ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"),
00306 #endif
00307 #if defined (ELIBSCN)
00308   ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"),
00309 #endif
00310 #if defined (ELIBMAX)
00311   ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"),
00312 #endif
00313 #if defined (ELIBEXEC)
00314   ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"),
00315 #endif
00316 #if defined (EILSEQ)
00317   ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"),
00318 #endif
00319 #if defined (ENOSYS)
00320   ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"),
00321 #endif
00322 #if defined (ELOOP)
00323   ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"),
00324 #endif
00325 #if defined (ERESTART)
00326   ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"),
00327 #endif
00328 #if defined (ESTRPIPE)
00329   ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"),
00330 #endif
00331 #if defined (ENOTEMPTY)
00332   ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"),
00333 #endif
00334 #if defined (EUSERS)
00335   ENTRY(EUSERS, "EUSERS", "Too many users"),
00336 #endif
00337 #if defined (ENOTSOCK)
00338   ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"),
00339 #endif
00340 #if defined (EDESTADDRREQ)
00341   ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"),
00342 #endif
00343 #if defined (EMSGSIZE)
00344   ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"),
00345 #endif
00346 #if defined (EPROTOTYPE)
00347   ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"),
00348 #endif
00349 #if defined (ENOPROTOOPT)
00350   ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"),
00351 #endif
00352 #if defined (EPROTONOSUPPORT)
00353   ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"),
00354 #endif
00355 #if defined (ESOCKTNOSUPPORT)
00356   ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"),
00357 #endif
00358 #if defined (EOPNOTSUPP)
00359   ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"),
00360 #endif
00361 #if defined (EPFNOSUPPORT)
00362   ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"),
00363 #endif
00364 #if defined (EAFNOSUPPORT)
00365   ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"),
00366 #endif
00367 #if defined (EADDRINUSE)
00368   ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"),
00369 #endif
00370 #if defined (EADDRNOTAVAIL)
00371   ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"),
00372 #endif
00373 #if defined (ENETDOWN)
00374   ENTRY(ENETDOWN, "ENETDOWN", "Network is down"),
00375 #endif
00376 #if defined (ENETUNREACH)
00377   ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"),
00378 #endif
00379 #if defined (ENETRESET)
00380   ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"),
00381 #endif
00382 #if defined (ECONNABORTED)
00383   ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"),
00384 #endif
00385 #if defined (ECONNRESET)
00386   ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"),
00387 #endif
00388 #if defined (ENOBUFS)
00389   ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"),
00390 #endif
00391 #if defined (EISCONN)
00392   ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"),
00393 #endif
00394 #if defined (ENOTCONN)
00395   ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"),
00396 #endif
00397 #if defined (ESHUTDOWN)
00398   ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"),
00399 #endif
00400 #if defined (ETOOMANYREFS)
00401   ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"),
00402 #endif
00403 #if defined (ETIMEDOUT)
00404   ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"),
00405 #endif
00406 #if defined (ECONNREFUSED)
00407   ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"),
00408 #endif
00409 #if defined (EHOSTDOWN)
00410   ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"),
00411 #endif
00412 #if defined (EHOSTUNREACH)
00413   ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"),
00414 #endif
00415 #if defined (EALREADY)
00416   ENTRY(EALREADY, "EALREADY", "Operation already in progress"),
00417 #endif
00418 #if defined (EINPROGRESS)
00419   ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"),
00420 #endif
00421 #if defined (ESTALE)
00422   ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"),
00423 #endif
00424 #if defined (EUCLEAN)
00425   ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"),
00426 #endif
00427 #if defined (ENOTNAM)
00428   ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"),
00429 #endif
00430 #if defined (ENAVAIL)
00431   ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"),
00432 #endif
00433 #if defined (EISNAM)
00434   ENTRY(EISNAM, "EISNAM", "Is a named type file"),
00435 #endif
00436 #if defined (EREMOTEIO)
00437   ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"),
00438 #endif
00439   ENTRY(0, NULL, NULL)
00440 };
00441 
00442 #ifdef EVMSERR
00443 /* This is not in the table, because the numeric value of EVMSERR (32767)
00444    lies outside the range of sys_errlist[].  */
00445 static struct { int value; const char *name, *msg; }
00446   evmserr = { EVMSERR, "EVMSERR", "VMS-specific error" };
00447 #endif
00448 
00449 /* Translation table allocated and initialized at runtime.  Indexed by the
00450    errno value to find the equivalent symbolic value. */
00451 
00452 static const char **error_names;
00453 static int num_error_names = 0;
00454 
00455 /* Translation table allocated and initialized at runtime, if it does not
00456    already exist in the host environment.  Indexed by the errno value to find
00457    the descriptive string.
00458 
00459    We don't export it for use in other modules because even though it has the
00460    same name, it differs from other implementations in that it is dynamically
00461    initialized rather than statically initialized. */
00462 
00463 #ifndef HAVE_SYS_ERRLIST
00464 
00465 #define sys_nerr sys_nerr__
00466 #define sys_errlist sys_errlist__
00467 static int sys_nerr;
00468 static const char **sys_errlist;
00469 
00470 #else
00471 
00472 extern int sys_nerr;
00473 extern char *sys_errlist[];
00474 
00475 #endif
00476 
00477 /*
00478 
00479 NAME
00480 
00481        init_error_tables -- initialize the name and message tables
00482 
00483 SYNOPSIS
00484 
00485        static void init_error_tables ();
00486 
00487 DESCRIPTION
00488 
00489        Using the error_table, which is initialized at compile time, generate
00490        the error_names and the sys_errlist (if needed) tables, which are
00491        indexed at runtime by a specific errno value.
00492 
00493 BUGS
00494 
00495        The initialization of the tables may fail under low memory conditions,
00496        in which case we don't do anything particularly useful, but we don't
00497        bomb either.  Who knows, it might succeed at a later point if we free
00498        some memory in the meantime.  In any case, the other routines know
00499        how to deal with lack of a table after trying to initialize it.  This
00500        may or may not be considered to be a bug, that we don't specifically
00501        warn about this particular failure mode.
00502 
00503 */
00504 
00505 static void
00506 init_error_tables (void)
00507 {
00508   const struct error_info *eip;
00509   int nbytes;
00510 
00511   /* If we haven't already scanned the error_table once to find the maximum
00512      errno value, then go find it now. */
00513 
00514   if (num_error_names == 0)
00515     {
00516       for (eip = error_table; eip -> name != NULL; eip++)
00517        {
00518          if (eip -> value >= num_error_names)
00519            {
00520              num_error_names = eip -> value + 1;
00521            }
00522        }
00523     }
00524 
00525   /* Now attempt to allocate the error_names table, zero it out, and then
00526      initialize it from the statically initialized error_table. */
00527 
00528   if (error_names == NULL)
00529     {
00530       nbytes = num_error_names * sizeof (char *);
00531       if ((error_names = (const char **) malloc (nbytes)) != NULL)
00532        {
00533          memset (error_names, 0, nbytes);
00534          for (eip = error_table; eip -> name != NULL; eip++)
00535            {
00536              error_names[eip -> value] = eip -> name;
00537            }
00538        }
00539     }
00540 
00541 #ifndef HAVE_SYS_ERRLIST
00542 
00543   /* Now attempt to allocate the sys_errlist table, zero it out, and then
00544      initialize it from the statically initialized error_table. */
00545 
00546   if (sys_errlist == NULL)
00547     {
00548       nbytes = num_error_names * sizeof (char *);
00549       if ((sys_errlist = (const char **) malloc (nbytes)) != NULL)
00550        {
00551          memset (sys_errlist, 0, nbytes);
00552          sys_nerr = num_error_names;
00553          for (eip = error_table; eip -> name != NULL; eip++)
00554            {
00555              sys_errlist[eip -> value] = eip -> msg;
00556            }
00557        }
00558     }
00559 
00560 #endif
00561 
00562 }
00563 
00564 /*
00565 
00566 
00567 @deftypefn Extension int errno_max (void)
00568 
00569 Returns the maximum @code{errno} value for which a corresponding
00570 symbolic name or message is available.  Note that in the case where we
00571 use the @code{sys_errlist} supplied by the system, it is possible for
00572 there to be more symbolic names than messages, or vice versa.  In
00573 fact, the manual page for @code{perror(3C)} explicitly warns that one
00574 should check the size of the table (@code{sys_nerr}) before indexing
00575 it, since new error codes may be added to the system before they are
00576 added to the table.  Thus @code{sys_nerr} might be smaller than value
00577 implied by the largest @code{errno} value defined in @code{<errno.h>}.
00578 
00579 We return the maximum value that can be used to obtain a meaningful
00580 symbolic name or message.
00581 
00582 @end deftypefn
00583 
00584 */
00585 
00586 int
00587 errno_max (void)
00588 {
00589   int maxsize;
00590 
00591   if (error_names == NULL)
00592     {
00593       init_error_tables ();
00594     }
00595   maxsize = MAX (sys_nerr, num_error_names);
00596   return (maxsize - 1);
00597 }
00598 
00599 #ifndef HAVE_STRERROR
00600 
00601 /*
00602 
00603 @deftypefn Supplemental char* strerror (int @var{errnoval})
00604 
00605 Maps an @code{errno} number to an error message string, the contents
00606 of which are implementation defined.  On systems which have the
00607 external variables @code{sys_nerr} and @code{sys_errlist}, these
00608 strings will be the same as the ones used by @code{perror}.
00609 
00610 If the supplied error number is within the valid range of indices for
00611 the @code{sys_errlist}, but no message is available for the particular
00612 error number, then returns the string @samp{Error @var{num}}, where
00613 @var{num} is the error number.
00614 
00615 If the supplied error number is not a valid index into
00616 @code{sys_errlist}, returns @code{NULL}.
00617 
00618 The returned string is only guaranteed to be valid only until the
00619 next call to @code{strerror}.
00620 
00621 @end deftypefn
00622 
00623 */
00624 
00625 char *
00626 strerror (int errnoval)
00627 {
00628   const char *msg;
00629   static char buf[32];
00630 
00631 #ifndef HAVE_SYS_ERRLIST
00632 
00633   if (error_names == NULL)
00634     {
00635       init_error_tables ();
00636     }
00637 
00638 #endif
00639 
00640   if ((errnoval < 0) || (errnoval >= sys_nerr))
00641     {
00642 #ifdef EVMSERR
00643       if (errnoval == evmserr.value)
00644        msg = evmserr.msg;
00645       else
00646 #endif
00647       /* Out of range, just return NULL */
00648       msg = NULL;
00649     }
00650   else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL))
00651     {
00652       /* In range, but no sys_errlist or no entry at this index. */
00653       sprintf (buf, "Error %d", errnoval);
00654       msg = buf;
00655     }
00656   else
00657     {
00658       /* In range, and a valid message.  Just return the message. */
00659       msg = (char *) sys_errlist[errnoval];
00660     }
00661   
00662   return (msg);
00663 }
00664 
00665 #endif /* ! HAVE_STRERROR */
00666 
00667 
00668 /*
00669 
00670 @deftypefn Replacement {const char*} strerrno (int @var{errnum})
00671 
00672 Given an error number returned from a system call (typically returned
00673 in @code{errno}), returns a pointer to a string containing the
00674 symbolic name of that error number, as found in @code{<errno.h>}.
00675 
00676 If the supplied error number is within the valid range of indices for
00677 symbolic names, but no name is available for the particular error
00678 number, then returns the string @samp{Error @var{num}}, where @var{num}
00679 is the error number.
00680 
00681 If the supplied error number is not within the range of valid
00682 indices, then returns @code{NULL}.
00683 
00684 The contents of the location pointed to are only guaranteed to be
00685 valid until the next call to @code{strerrno}.
00686 
00687 @end deftypefn
00688 
00689 */
00690 
00691 const char *
00692 strerrno (int errnoval)
00693 {
00694   const char *name;
00695   static char buf[32];
00696 
00697   if (error_names == NULL)
00698     {
00699       init_error_tables ();
00700     }
00701 
00702   if ((errnoval < 0) || (errnoval >= num_error_names))
00703     {
00704 #ifdef EVMSERR
00705       if (errnoval == evmserr.value)
00706        name = evmserr.name;
00707       else
00708 #endif
00709       /* Out of range, just return NULL */
00710       name = NULL;
00711     }
00712   else if ((error_names == NULL) || (error_names[errnoval] == NULL))
00713     {
00714       /* In range, but no error_names or no entry at this index. */
00715       sprintf (buf, "Error %d", errnoval);
00716       name = (const char *) buf;
00717     }
00718   else
00719     {
00720       /* In range, and a valid name.  Just return the name. */
00721       name = error_names[errnoval];
00722     }
00723 
00724   return (name);
00725 }
00726 
00727 /*
00728 
00729 @deftypefn Extension int strtoerrno (const char *@var{name})
00730 
00731 Given the symbolic name of a error number (e.g., @code{EACCES}), map it
00732 to an errno value.  If no translation is found, returns 0.
00733 
00734 @end deftypefn
00735 
00736 */
00737 
00738 int
00739 strtoerrno (const char *name)
00740 {
00741   int errnoval = 0;
00742 
00743   if (name != NULL)
00744     {
00745       if (error_names == NULL)
00746        {
00747          init_error_tables ();
00748        }
00749       for (errnoval = 0; errnoval < num_error_names; errnoval++)
00750        {
00751          if ((error_names[errnoval] != NULL) &&
00752              (strcmp (name, error_names[errnoval]) == 0))
00753            {
00754              break;
00755            }
00756        }
00757       if (errnoval == num_error_names)
00758        {
00759 #ifdef EVMSERR
00760          if (strcmp (name, evmserr.name) == 0)
00761            errnoval = evmserr.value;
00762          else
00763 #endif
00764          errnoval = 0;
00765        }
00766     }
00767   return (errnoval);
00768 }
00769 
00770 
00771 /* A simple little main that does nothing but print all the errno translations
00772    if MAIN is defined and this file is compiled and linked. */
00773 
00774 #ifdef MAIN
00775 
00776 #include <stdio.h>
00777 
00778 int
00779 main (void)
00780 {
00781   int errn;
00782   int errnmax;
00783   const char *name;
00784   const char *msg;
00785   char *strerror ();
00786 
00787   errnmax = errno_max ();
00788   printf ("%d entries in names table.\n", num_error_names);
00789   printf ("%d entries in messages table.\n", sys_nerr);
00790   printf ("%d is max useful index.\n", errnmax);
00791 
00792   /* Keep printing values until we get to the end of *both* tables, not
00793      *either* table.  Note that knowing the maximum useful index does *not*
00794      relieve us of the responsibility of testing the return pointer for
00795      NULL. */
00796 
00797   for (errn = 0; errn <= errnmax; errn++)
00798     {
00799       name = strerrno (errn);
00800       name = (name == NULL) ? "<NULL>" : name;
00801       msg = strerror (errn);
00802       msg = (msg == NULL) ? "<NULL>" : msg;
00803       printf ("%-4d%-18s%s\n", errn, name, msg);
00804     }
00805 
00806   return 0;
00807 }
00808 
00809 #endif