diff options
Diffstat (limited to 'lib/sig2str.c')
-rw-r--r-- | lib/sig2str.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/lib/sig2str.c b/lib/sig2str.c new file mode 100644 index 0000000..905daea --- /dev/null +++ b/lib/sig2str.c @@ -0,0 +1,349 @@ +/* sig2str.c -- convert between signal names and numbers + + Copyright (C) 2002, 2004, 2006, 2009-2020 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. */ + +/* Written by Paul Eggert. */ + +#include <config.h> + +#include <limits.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "sig2str.h" + +#ifndef SIGRTMIN +# define SIGRTMIN 0 +# undef SIGRTMAX +#endif +#ifndef SIGRTMAX +# define SIGRTMAX (SIGRTMIN - 1) +#endif + +#define NUMNAME(name) { SIG##name, #name } + +/* Signal names and numbers. Put the preferred name first. */ +static struct numname { int num; char const name[8]; } numname_table[] = + { + /* Signals required by POSIX 1003.1-2001 base, listed in + traditional numeric order where possible. */ +#ifdef SIGHUP + NUMNAME (HUP), +#endif +#ifdef SIGINT + NUMNAME (INT), +#endif +#ifdef SIGQUIT + NUMNAME (QUIT), +#endif +#ifdef SIGILL + NUMNAME (ILL), +#endif +#ifdef SIGTRAP + NUMNAME (TRAP), +#endif +#ifdef SIGABRT + NUMNAME (ABRT), +#endif +#ifdef SIGFPE + NUMNAME (FPE), +#endif +#ifdef SIGKILL + NUMNAME (KILL), +#endif +#ifdef SIGSEGV + NUMNAME (SEGV), +#endif + /* On Haiku, SIGSEGV == SIGBUS, but we prefer SIGSEGV to match + strsignal.c output, so SIGBUS must be listed second. */ +#ifdef SIGBUS + NUMNAME (BUS), +#endif +#ifdef SIGPIPE + NUMNAME (PIPE), +#endif +#ifdef SIGALRM + NUMNAME (ALRM), +#endif +#ifdef SIGTERM + NUMNAME (TERM), +#endif +#ifdef SIGUSR1 + NUMNAME (USR1), +#endif +#ifdef SIGUSR2 + NUMNAME (USR2), +#endif +#ifdef SIGCHLD + NUMNAME (CHLD), +#endif +#ifdef SIGURG + NUMNAME (URG), +#endif +#ifdef SIGSTOP + NUMNAME (STOP), +#endif +#ifdef SIGTSTP + NUMNAME (TSTP), +#endif +#ifdef SIGCONT + NUMNAME (CONT), +#endif +#ifdef SIGTTIN + NUMNAME (TTIN), +#endif +#ifdef SIGTTOU + NUMNAME (TTOU), +#endif + + /* Signals required by POSIX 1003.1-2001 with the XSI extension. */ +#ifdef SIGSYS + NUMNAME (SYS), +#endif +#ifdef SIGPOLL + NUMNAME (POLL), +#endif +#ifdef SIGVTALRM + NUMNAME (VTALRM), +#endif +#ifdef SIGPROF + NUMNAME (PROF), +#endif +#ifdef SIGXCPU + NUMNAME (XCPU), +#endif +#ifdef SIGXFSZ + NUMNAME (XFSZ), +#endif + + /* Unix Version 7. */ +#ifdef SIGIOT + NUMNAME (IOT), /* Older name for ABRT. */ +#endif +#ifdef SIGEMT + NUMNAME (EMT), +#endif + + /* USG Unix. */ +#ifdef SIGPHONE + NUMNAME (PHONE), +#endif +#ifdef SIGWIND + NUMNAME (WIND), +#endif + + /* Unix System V. */ +#ifdef SIGCLD + NUMNAME (CLD), +#endif +#ifdef SIGPWR + NUMNAME (PWR), +#endif + + /* GNU/Linux 2.2 and Solaris 8. */ +#ifdef SIGCANCEL + NUMNAME (CANCEL), +#endif +#ifdef SIGLWP + NUMNAME (LWP), +#endif +#ifdef SIGWAITING + NUMNAME (WAITING), +#endif +#ifdef SIGFREEZE + NUMNAME (FREEZE), +#endif +#ifdef SIGTHAW + NUMNAME (THAW), +#endif +#ifdef SIGLOST + NUMNAME (LOST), +#endif +#ifdef SIGWINCH + NUMNAME (WINCH), +#endif + + /* GNU/Linux 2.2. */ +#ifdef SIGINFO + NUMNAME (INFO), +#endif +#ifdef SIGIO + NUMNAME (IO), +#endif +#ifdef SIGSTKFLT + NUMNAME (STKFLT), +#endif + + /* AIX 5L. */ +#ifdef SIGDANGER + NUMNAME (DANGER), +#endif +#ifdef SIGGRANT + NUMNAME (GRANT), +#endif +#ifdef SIGMIGRATE + NUMNAME (MIGRATE), +#endif +#ifdef SIGMSG + NUMNAME (MSG), +#endif +#ifdef SIGPRE + NUMNAME (PRE), +#endif +#ifdef SIGRETRACT + NUMNAME (RETRACT), +#endif +#ifdef SIGSAK + NUMNAME (SAK), +#endif +#ifdef SIGSOUND + NUMNAME (SOUND), +#endif + + /* Older AIX versions. */ +#ifdef SIGALRM1 + NUMNAME (ALRM1), /* unknown; taken from Bash 2.05 */ +#endif +#ifdef SIGKAP + NUMNAME (KAP), /* Older name for SIGGRANT. */ +#endif +#ifdef SIGVIRT + NUMNAME (VIRT), /* unknown; taken from Bash 2.05 */ +#endif +#ifdef SIGWINDOW + NUMNAME (WINDOW), /* Older name for SIGWINCH. */ +#endif + + /* BeOS */ +#ifdef SIGKILLTHR + NUMNAME (KILLTHR), +#endif + + /* Older HP-UX versions. */ +#ifdef SIGDIL + NUMNAME (DIL), +#endif + + /* Korn shell and Bash, of uncertain vintage. */ + { 0, "EXIT" } + }; + +#define NUMNAME_ENTRIES (sizeof numname_table / sizeof numname_table[0]) + +/* ISDIGIT differs from isdigit, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char + or EOF. + - It's typically faster. + POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to + isdigit unless it's important to use the locale's definition + of "digit" even when the host does not conform to POSIX. */ +#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) + +/* Convert the signal name SIGNAME to a signal number. Return the + signal number if successful, -1 otherwise. */ + +static int +str2signum (char const *signame) +{ + if (ISDIGIT (*signame)) + { + char *endp; + long int n = strtol (signame, &endp, 10); + if (! *endp && n <= SIGNUM_BOUND) + return n; + } + else + { + unsigned int i; + for (i = 0; i < NUMNAME_ENTRIES; i++) + if (strcmp (numname_table[i].name, signame) == 0) + return numname_table[i].num; + + { + char *endp; + int rtmin = SIGRTMIN; + int rtmax = SIGRTMAX; + + if (0 < rtmin && strncmp (signame, "RTMIN", 5) == 0) + { + long int n = strtol (signame + 5, &endp, 10); + if (! *endp && 0 <= n && n <= rtmax - rtmin) + return rtmin + n; + } + else if (0 < rtmax && strncmp (signame, "RTMAX", 5) == 0) + { + long int n = strtol (signame + 5, &endp, 10); + if (! *endp && rtmin - rtmax <= n && n <= 0) + return rtmax + n; + } + } + } + + return -1; +} + +/* Convert the signal name SIGNAME to the signal number *SIGNUM. + Return 0 if successful, -1 otherwise. */ + +int +str2sig (char const *signame, int *signum) +{ + *signum = str2signum (signame); + return *signum < 0 ? -1 : 0; +} + +/* Convert SIGNUM to a signal name in SIGNAME. SIGNAME must point to + a buffer of at least SIG2STR_MAX bytes. Return 0 if successful, -1 + otherwise. */ + +int +sig2str (int signum, char *signame) +{ + unsigned int i; + for (i = 0; i < NUMNAME_ENTRIES; i++) + if (numname_table[i].num == signum) + { + strcpy (signame, numname_table[i].name); + return 0; + } + + { + int rtmin = SIGRTMIN; + int rtmax = SIGRTMAX; + int base, delta; + + if (! (rtmin <= signum && signum <= rtmax)) + return -1; + + if (signum <= rtmin + (rtmax - rtmin) / 2) + { + strcpy (signame, "RTMIN"); + base = rtmin; + } + else + { + strcpy (signame, "RTMAX"); + base = rtmax; + } + + delta = signum - base; + if (delta != 0) + sprintf (signame + 5, "%+d", delta); + return 0; + } +} |