1edc9f119502d32c079b0b570387f53a96ac7304
[gnulib.git] / lib / sig2str.c
1 /* sig2str.c -- convert between signal names and numbers
2
3    Copyright (C) 2002 Free Software Foundation, Inc.
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2, or (at your option)
8    any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 /* Written by Paul Eggert.  */
20
21 #if HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #include <limits.h>
26 #include <signal.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #if HAVE_SYS_WAIT_H
32 # include <sys/wait.h>
33 #endif
34 #ifndef WTERMSIG
35 # define WTERMSIG(s) ((s) & 0x7F)
36 #endif
37
38 #include "sig2str.h"
39
40 #ifndef SIGRTMIN
41 # define SIGRTMIN 0
42 # undef SIGRTMAX
43 #endif
44 #ifndef SIGRTMAX
45 # define SIGRTMAX (SIGRTMIN - 1)
46 #endif
47
48 #define NUMNAME(name) { SIG##name, #name }
49
50 /* Signal names and numbers.  Put the preferred name first.  */
51 static struct numname { int num; char const name[8]; } numname_table[] =
52   {
53     /* Signals required by POSIX 1003.1-2001 base, listed in
54        traditional numeric order.  */
55 #ifdef SIGHUP
56     NUMNAME (HUP),
57 #endif
58 #ifdef SIGINT
59     NUMNAME (INT),
60 #endif
61 #ifdef SIGQUIT
62     NUMNAME (QUIT),
63 #endif
64 #ifdef SIGILL
65     NUMNAME (ILL),
66 #endif
67 #ifdef SIGTRAP
68     NUMNAME (TRAP),
69 #endif
70 #ifdef SIGABRT
71     NUMNAME (ABRT),
72 #endif
73 #ifdef SIGFPE
74     NUMNAME (FPE),
75 #endif
76 #ifdef SIGKILL
77     NUMNAME (KILL),
78 #endif
79 #ifdef SIGBUS
80     NUMNAME (BUS),
81 #endif
82 #ifdef SIGSEGV
83     NUMNAME (SEGV),
84 #endif
85 #ifdef SIGPIPE
86     NUMNAME (PIPE),
87 #endif
88 #ifdef SIGALRM
89     NUMNAME (ALRM),
90 #endif
91 #ifdef SIGTERM
92     NUMNAME (TERM),
93 #endif
94 #ifdef SIGUSR1
95     NUMNAME (USR1),
96 #endif
97 #ifdef SIGUSR2
98     NUMNAME (USR2),
99 #endif
100 #ifdef SIGCHLD
101     NUMNAME (CHLD),
102 #endif
103 #ifdef SIGURG
104     NUMNAME (URG),
105 #endif
106 #ifdef SIGSTOP
107     NUMNAME (STOP),
108 #endif
109 #ifdef SIGTSTP
110     NUMNAME (TSTP),
111 #endif
112 #ifdef SIGCONT
113     NUMNAME (CONT),
114 #endif
115 #ifdef SIGTTIN
116     NUMNAME (TTIN),
117 #endif
118 #ifdef SIGTTOU
119     NUMNAME (TTOU),
120 #endif
121
122     /* Signals required by POSIX 1003.1-2001 with the XSI extension.  */
123 #ifdef SIGSYS
124     NUMNAME (SYS),
125 #endif
126 #ifdef SIGPOLL
127     NUMNAME (POLL),
128 #endif
129 #ifdef SIGVTALRM
130     NUMNAME (VTALRM),
131 #endif
132 #ifdef SIGPROF
133     NUMNAME (PROF),
134 #endif
135 #ifdef SIGXCPU
136     NUMNAME (XCPU),
137 #endif
138 #ifdef SIGXFSZ
139     NUMNAME (XFSZ),
140 #endif
141
142     /* Unix Version 7.  */
143 #ifdef SIGIOT
144     NUMNAME (IOT),      /* Older name for ABRT.  */
145 #endif
146 #ifdef SIGEMT
147     NUMNAME (EMT),
148 #endif
149
150     /* USG Unix.  */
151 #ifdef SIGPHONE
152     NUMNAME (PHONE),
153 #endif
154 #ifdef SIGWIND
155     NUMNAME (WIND),
156 #endif
157
158     /* Unix System V.  */
159 #ifdef SIGCLD
160     NUMNAME (CLD),
161 #endif
162 #ifdef SIGPWR
163     NUMNAME (PWR),
164 #endif
165
166     /* GNU/Linux 2.2 and Solaris 8.  */
167 #ifdef SIGCANCEL
168     NUMNAME (CANCEL),
169 #endif
170 #ifdef SIGLWP
171     NUMNAME (LWP),
172 #endif
173 #ifdef SIGWAITING
174     NUMNAME (WAITING),
175 #endif
176 #ifdef SIGFREEZE
177     NUMNAME (FREEZE),
178 #endif
179 #ifdef SIGTHAW
180     NUMNAME (THAW),
181 #endif
182 #ifdef SIGLOST
183     NUMNAME (LOST),
184 #endif
185 #ifdef SIGWINCH
186     NUMNAME (WINCH),
187 #endif
188
189     /* GNU/Linux 2.2.  */
190 #ifdef SIGINFO
191     NUMNAME (INFO),
192 #endif
193 #ifdef SIGIO
194     NUMNAME (IO),
195 #endif
196 #ifdef SIGSTKFLT
197     NUMNAME (STKFLT),
198 #endif
199
200     /* AIX 5L.  */
201 #ifdef SIGDANGER
202     NUMNAME (DANGER),
203 #endif
204 #ifdef SIGGRANT
205     NUMNAME (GRANT),
206 #endif
207 #ifdef SIGMIGRATE
208     NUMNAME (MIGRATE),
209 #endif
210 #ifdef SIGMSG
211     NUMNAME (MSG),
212 #endif
213 #ifdef SIGPRE
214     NUMNAME (PRE),
215 #endif
216 #ifdef SIGRETRACT
217     NUMNAME (RETRACT),
218 #endif
219 #ifdef SIGSAK
220     NUMNAME (SAK),
221 #endif
222 #ifdef SIGSOUND
223     NUMNAME (SOUND),
224 #endif
225
226     /* Older AIX versions.  */
227 #ifdef SIGALRM1 
228     NUMNAME (ALRM1),    /* unknown; taken from Bash 2.05 */
229 #endif
230 #ifdef SIGKAP
231     NUMNAME (KAP),      /* Older name for SIGGRANT.  */
232 #endif
233 #ifdef SIGVIRT
234     NUMNAME (VIRT),     /* unknown; taken from Bash 2.05 */
235 #endif
236 #ifdef SIGWINDOW
237     NUMNAME (WINDOW),   /* Older name for SIGWINCH.  */
238 #endif
239
240     /* BeOS */
241 #ifdef SIGKILLTHR
242     NUMNAME (KILLTHR),
243 #endif
244
245     /* Older HP-UX versions.  */
246 #ifdef SIGDIL
247     NUMNAME (DIL),
248 #endif
249
250     /* Korn shell and Bash, of uncertain vintage.  */
251     { 0, "EXIT" }
252   };
253
254 #define NUMNAME_ENTRIES (sizeof numname_table / sizeof numname_table[0])
255
256 /* ISDIGIT differs from isdigit, as follows:
257    - Its arg may be any int or unsigned int; it need not be an unsigned char.
258    - It's guaranteed to evaluate its argument exactly once.
259    - It's typically faster.
260    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
261    ISDIGIT_LOCALE unless it's important to use the locale's definition
262    of `digit' even when the host does not conform to POSIX.  */
263 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
264
265 /* Convert the signal name SIGNAME to a signal number.  Return the
266    signal number if successful, -1 otherwise.  */
267
268 static int
269 str2signum (char const *signame)
270 {
271   if (ISDIGIT (*signame))
272     {
273       char *endp;
274       long int n = strtol (signame, &endp, 10);
275       if (! *endp && n <= SIGNUM_BOUND)
276         return n;
277     }
278   else
279     {
280       int i;
281       for (i = 0; i < NUMNAME_ENTRIES; i++)
282         if (strcmp (numname_table[i].name, signame) == 0)
283           return numname_table[i].num;
284
285       {
286         char *endp;
287         int rtmin = SIGRTMIN;
288         int rtmax = SIGRTMAX;
289
290         if (0 < rtmin && strncmp (signame, "RTMIN", 5) == 0)
291           {
292             long int n = strtol (signame + 5, &endp, 10);
293             if (! *endp && 0 <= n && n <= rtmax - rtmin)
294               return rtmin + n;
295           }
296         else if (0 < rtmax && strncmp (signame, "RTMAX", 5) == 0)
297           {
298             long int n = strtol (signame + 5, &endp, 10);
299             if (! *endp && rtmin - rtmax <= n && n <= 0)
300               return rtmax + n;
301           }
302       }
303     }
304
305   return -1;
306 }
307
308 /* Convert the signal name SIGNAME to the signal number *SIGNUM.
309    Return 0 if successful, -1 otherwise.  */
310
311 int
312 str2sig (char const *signame, int *signum)
313 {
314   *signum = str2signum (signame);
315   return *signum < 0 ? -1 : 0;
316 }
317
318 /* Convert SIGNUM to a signal name in SIGNAME.  SIGNAME must point to
319    a buffer of at least SIG2STR_MAX bytes.  Return 0 if successful, -1
320    otherwise.  */
321
322 int
323 sig2str (int signum, char *signame)
324 {
325   int i;
326   for (i = 0; i < NUMNAME_ENTRIES; i++)
327     if (numname_table[i].num == signum)
328       {
329         strcpy (signame, numname_table[i].name);
330         return 0;
331       }
332
333   {
334     int rtmin = SIGRTMIN;
335     int rtmax = SIGRTMAX;
336
337     if (! (rtmin <= signum && signum <= rtmax))
338       return -1;
339
340     if (signum <= rtmin + (rtmax - rtmin) / 2)
341       {
342         int delta = signum - rtmin;
343         sprintf (signame, delta ? "RTMIN+%d" : "RTMIN", delta);
344       }
345     else
346       {
347         int delta = rtmax - signum;
348         sprintf (signame, delta ? "RTMAX-%d" : "RTMAX", delta);
349       }
350
351     return 0;
352   }
353 }