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