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