xref: /openbsd/gnu/usr.bin/cvs/lib/strerror.c (revision 771fbea0)
1 /* Extended support for using errno values.
2    Copyright (C) 1992 Free Software Foundation, Inc.
3    Written by Fred Fish.  fnf@cygnus.com
4 
5 This file is part of the libiberty library.
6 Libiberty is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10 
11 Libiberty is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library 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>
38 extern void *malloc (size_t size);				/* 4.10.3.3 */
39 extern void *memset (void *s, int c, size_t n);			/* 4.11.6.1 */
40 #else	/* !__STDC__ */
41 extern char *malloc ();		/* Standard memory allocater */
42 extern 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 
60 struct 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 
75 static 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 
446 static char **error_names;
447 static 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 
459 static int sys_nerr;
460 static char **sys_errlist;
461 
462 #else
463 
464 extern int sys_nerr;
465 extern char *sys_errlist[];
466 
467 #endif
468 
469 
470 /*
471 
472 NAME
473 
474 	init_error_tables -- initialize the name and message tables
475 
476 SYNOPSIS
477 
478 	static void init_error_tables ();
479 
480 DESCRIPTION
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 
486 BUGS
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 
498 static void
499 init_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 
559 NAME
560 
561 	errno_max -- return the max errno value
562 
563 SYNOPSIS
564 
565 	int errno_max ();
566 
567 DESCRIPTION
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 
584 int
585 errno_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 
599 NAME
600 
601 	strerror -- map an error number to an error message string
602 
603 SYNOPSIS
604 
605 	char *strerror (int errnoval)
606 
607 DESCRIPTION
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 
627 char *
628 strerror (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 
667 NAME
668 
669 	strerrno -- map an error number to a symbolic name string
670 
671 SYNOPSIS
672 
673 	char *strerrno (int errnoval)
674 
675 DESCRIPTION
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 
689 BUGS
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 
696 char *
697 strerrno (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 
730 NAME
731 
732 	strtoerrno -- map a symbolic errno name to a numeric value
733 
734 SYNOPSIS
735 
736 	int strtoerrno (char *name)
737 
738 DESCRIPTION
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 
745 int
746 strtoerrno (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 
779 main ()
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