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