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