Subversion Repositories Kolibri OS

Rev

Rev 5191 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  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 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.