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