maint: update copyright
[gnulib.git] / lib / sig2str.c
1 /* sig2str.c -- convert between signal names and numbers
2
3    Copyright (C) 2002, 2004, 2006, 2009-2014 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     int base, delta;
329
330     if (! (rtmin <= signum && signum <= rtmax))
331       return -1;
332
333     if (signum <= rtmin + (rtmax - rtmin) / 2)
334       {
335         strcpy (signame, "RTMIN");
336         base = rtmin;
337       }
338     else
339       {
340         strcpy (signame, "RTMAX");
341         base = rtmax;
342       }
343
344     delta = signum - base;
345     if (delta != 0)
346       sprintf (signame + 5, "%+d", delta);
347     return 0;
348   }
349 }