]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/lib/strerror.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / lib / strerror.c
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 #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>
40 extern void *malloc (size_t size);                              /* 4.10.3.3 */
41 extern void *memset (void *s, int c, size_t n);                 /* 4.11.6.1 */
42 #else   /* !__STDC__ */
43 extern char *malloc ();         /* Standard memory allocater */
44 extern 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
62 struct 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
77 static 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
448 static char **error_names;
449 static 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
461 static int sys_nerr;
462 static char **sys_errlist;
463
464 #else
465
466 extern int sys_nerr;
467 extern char *sys_errlist[];
468
469 #endif
470
471
472 /*
473
474 NAME
475
476         init_error_tables -- initialize the name and message tables
477
478 SYNOPSIS
479
480         static void init_error_tables ();
481
482 DESCRIPTION
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
488 BUGS
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
500 static void
501 init_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
561 NAME
562
563         errno_max -- return the max errno value
564
565 SYNOPSIS
566
567         int errno_max ();
568
569 DESCRIPTION
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
586 int
587 errno_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
601 NAME
602
603         strerror -- map an error number to an error message string
604
605 SYNOPSIS
606
607         char *strerror (int errnoval)
608
609 DESCRIPTION
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
629 char *
630 strerror (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
669 NAME
670
671         strerrno -- map an error number to a symbolic name string
672
673 SYNOPSIS
674
675         char *strerrno (int errnoval)
676
677 DESCRIPTION
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
691 BUGS
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
698 char *
699 strerrno (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
732 NAME
733
734         strtoerrno -- map a symbolic errno name to a numeric value
735
736 SYNOPSIS
737
738         int strtoerrno (char *name)
739
740 DESCRIPTION
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
747 int
748 strtoerrno (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
781 main ()
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