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