[1/1] libc: Added implementation for sig2str/str2sig.

Message ID 20210731132205.536278-2-mfjoyce2004@gmail.com
State Superseded
Headers show
Series
  • V3: Implementation of sig2str/str2sig
Related show

Commit Message

Matt Joyce July 31, 2021, 1:22 p.m.
Added implementations for sig2str() and str2sig() in libc/signal
in order to improve POSIX compliance. Added fucntion prototypes
in libc/include/sys/signal.h.
---
 newlib/libc/include/sys/signal.h |  17 ++
 newlib/libc/signal/Makefile.am   |   4 +-
 newlib/libc/signal/sig2str.c     | 298 +++++++++++++++++++++++++++++++
 3 files changed, 317 insertions(+), 2 deletions(-)
 create mode 100644 newlib/libc/signal/sig2str.c

-- 
2.31.1

Comments

Joel Sherrill Aug. 1, 2021, 5:03 p.m. | #1
I think this is OK. There was a lot of discussion to incorporate so
others need to concur.

On Sat, Jul 31, 2021 at 8:22 AM Matt Joyce <mfjoyce2004@gmail.com> wrote:
>

> Added implementations for sig2str() and str2sig() in libc/signal

> in order to improve POSIX compliance. Added fucntion prototypes

> in libc/include/sys/signal.h.

> ---

>  newlib/libc/include/sys/signal.h |  17 ++

>  newlib/libc/signal/Makefile.am   |   4 +-

>  newlib/libc/signal/sig2str.c     | 298 +++++++++++++++++++++++++++++++

>  3 files changed, 317 insertions(+), 2 deletions(-)

>  create mode 100644 newlib/libc/signal/sig2str.c

>

> diff --git a/newlib/libc/include/sys/signal.h b/newlib/libc/include/sys/signal.h

> index 45cc0366c..9c1c0e3c2 100644

> --- a/newlib/libc/include/sys/signal.h

> +++ b/newlib/libc/include/sys/signal.h

> @@ -12,6 +12,7 @@ extern "C" {

>  #include <sys/types.h>

>  #include <sys/_sigset.h>

>  #include <sys/_timespec.h>

> +#include <stdint.h>

>

>  #if !defined(_SIGSET_T_DECLARED)

>  #define        _SIGSET_T_DECLARED

> @@ -238,6 +239,22 @@ int sigqueue (pid_t, int, const union sigval);

>

>  #endif /* __POSIX_VISIBLE >= 199309 */

>

> +/* Using __MISC_VISIBLE until POSIX Issue 8 is officially released */

> +#if __MISC_VISIBLE

> +

> +/* POSIX Issue 8 adds sig2str() and str2sig() */

> +

> +#if __STDINT_EXP(INT_MAX) > 0x7fff

> +#define SIG2STR_MAX (sizeof("RTMAX+") + sizeof("4294967295") - 1)

> +#else

> +#define SIG2STR_MAX (sizeof("RTMAX+") + sizeof("65535") - 1)

> +#endif

> +

> +int sig2str(int, char *);

> +int str2sig(const char *__restrict, int *__restrict);

> +

> +#endif /* __MISC_VISIBLE */

> +

>  #if defined(___AM29K__)

>  /* These all need to be defined for ANSI C, but I don't think they are

>     meaningful.  */

> diff --git a/newlib/libc/signal/Makefile.am b/newlib/libc/signal/Makefile.am

> index a93dba7a9..89db26113 100644

> --- a/newlib/libc/signal/Makefile.am

> +++ b/newlib/libc/signal/Makefile.am

> @@ -4,7 +4,7 @@ AUTOMAKE_OPTIONS = cygnus

>

>  INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)

>

> -LIB_SOURCES = psignal.c raise.c signal.c

> +LIB_SOURCES = psignal.c raise.c signal.c sig2str.c

>

>  libsignal_la_LDFLAGS = -Xcompiler -nostdlib

>

> @@ -21,6 +21,6 @@ endif # USE_LIBTOOL

>

>  include $(srcdir)/../../Makefile.shared

>

> -CHEWOUT_FILES = psignal.def raise.def signal.def

> +CHEWOUT_FILES = psignal.def raise.def signal.def sig2str.def

>

>  CHAPTERS = signal.tex

> diff --git a/newlib/libc/signal/sig2str.c b/newlib/libc/signal/sig2str.c

> new file mode 100644

> index 000000000..c02fcacbd

> --- /dev/null

> +++ b/newlib/libc/signal/sig2str.c

> @@ -0,0 +1,298 @@

> +/* SPDX-License-Identifier: BSD-2-Clause */

> +/*

> + * Copyright (C) 2021 Matthew Joyce

> + *

> + * Redistribution and use in source and binary forms, with or without

> + * modification, are permitted provided that the following conditions

> + * are met:

> + * 1. Redistributions of source code must retain the above copyright

> + *    notice, this list of conditions and the following disclaimer.

> + * 2. Redistributions in binary form must reproduce the above copyright

> + *    notice, this list of conditions and the following disclaimer in the

> + *    documentation and/or other materials provided with the distribution.

> + *

> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

> + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

> + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE

> + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

> + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

> + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

> + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

> + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE

> + * POSSIBILITY OF SUCH DAMAGE.

> + */

> +

> +/*

> +FUNCTION

> +<<sig2str>>---translate between signal number and name

> +<<str2sig>>---translate between signal name and number

> +

> +INDEX

> +          sig2str

> +INDEX

> +          str2sig

> +

> +SYNOPSIS

> +          #include <signal.h>

> +          int sig2str(int <[signum]>, char *<[str]>);

> +

> +          int str2sig(const char *restrict <[str]>, int *restrict <[pnum]>);

> +

> +DESCRIPTION

> +The <<sig2str>> function translates the signal number specified by <[signum]> to

> +a signal name and stores this string in the location specified by <[str}>. The

> +application must ensure that <[str]> points to a location that can store the

> +string including the terminating null byte. The symbolic constant

> +<[SIG2STR_MAX]> defined in `<<signal.h>>' gives the maximum number of bytes

> +required.

> +

> +The <<str2sig>> function translates the signal name in the string pointed to by

> +<[str]> to a signal number and stores this value in the location specified by

> +<[pnum]>.

> +

> +RETURNS

> +<<sig2str>> returns <<0>> if <[signum]>> is a valid, supported signal number.

> +Otherwise, it returns <<-1>>.

> +

> +<<str2sig>> returns <<0>> if it stores a value in the location pointed to by

> +<[pnum]>. Otherwise it returns <<-1>>.

> +*/

> +

> +#include <signal.h>

> +#include <string.h>

> +#include <stdio.h>

> +#include <stdlib.h>

> +

> +#define SPACES_TO_N 6 /* Allows indexing to RT Signal number in str2sig */

> +#define NUM_OF_SIGS (sizeof(sig_array) / sizeof(sig_name_and_num))

> +

> +typedef struct sig_name_and_num {

> +  const char *sig_name;

> +  const int  sig_num;

> +} sig_name_and_num;

> +

> +static const sig_name_and_num sig_array[] = {

> +      { "EXIT", 0 },

> +    #ifdef SIGHUP

> +      { "HUP", SIGHUP },

> +    #endif

> +    #ifdef SIGINT

> +      { "INT", SIGINT },

> +    #endif

> +    #ifdef SIGQUIT

> +      { "QUIT", SIGQUIT },

> +    #endif

> +    #ifdef SIGILL

> +      { "ILL", SIGILL },

> +    #endif

> +    #ifdef SIGTRAP

> +      { "TRAP", SIGTRAP },

> +    #endif

> +    #ifdef SIGABRT

> +      { "ABRT", SIGABRT },

> +    #endif

> +    #ifdef SIGIOT

> +      { "IOT", SIGIOT},

> +    #endif

> +    #ifdef SIGEMT

> +      { "EMT", SIGEMT },

> +    #endif

> +    #ifdef SIGFPE

> +      { "FPE", SIGFPE },

> +    #endif

> +    #ifdef SIGKILL

> +      { "KILL", SIGKILL },

> +    #endif

> +    #ifdef SIGBUS

> +      { "BUS", SIGBUS },

> +    #endif

> +    #ifdef SIGSEGV

> +      { "SEGV", SIGSEGV },

> +    #endif

> +    #ifdef SIGSYS

> +      { "SYS", SIGSYS },

> +    #endif

> +    #ifdef SIGPIPE

> +      { "PIPE", SIGPIPE },

> +    #endif

> +    #ifdef SIGALRM

> +      { "ALRM", SIGALRM },

> +    #endif

> +    #ifdef SIGTERM

> +      { "TERM", SIGTERM },

> +    #endif

> +    #ifdef SIGURG

> +      { "URG", SIGURG },

> +    #endif

> +    #ifdef SIGSTOP

> +      { "STOP", SIGSTOP },

> +    #endif

> +    #ifdef SIGTSTP

> +      { "TSTP", SIGTSTP },

> +    #endif

> +    #ifdef SIGCONT

> +      { "CONT", SIGCONT },

> +    #endif

> +    #ifdef SIGCHLD

> +      { "CHLD", SIGCHLD },

> +    #endif

> +    #ifdef SIGCLD

> +      { "CLD", SIGCLD },

> +    #endif

> +    #ifdef SIGTTIN

> +      { "TTIN", SIGTTIN },

> +    #endif

> +    #ifdef SIGTTOU

> +      { "TTOU", SIGTTOU },

> +    #endif

> +    #ifdef SIGIO

> +      { "IO", SIGIO },

> +    #endif

> +    #ifdef SIGPOLL

> +      { "POLL", SIGPOLL },

> +    #endif

> +    #ifdef SIGWINCH

> +      { "WINCH", SIGWINCH },

> +    #endif

> +    #ifdef SIGUSR1

> +      { "USR1", SIGUSR1 },

> +    #endif

> +    #ifdef SIGUSR2

> +      { "USR2", SIGUSR2 },

> +    #endif

> +    #ifdef SIGPWR

> +      { "PWR", SIGPWR },

> +    #endif

> +    #ifdef SIGXCPU

> +      { "XCPU", SIGXCPU },

> +    #endif

> +    #ifdef SIGXFSZ

> +      { "XFSZ", SIGXFSZ },

> +    #endif

> +    #ifdef SIGVTALRM

> +      { "VTALRM", SIGVTALRM },

> +    #endif

> +    #ifdef SIGPROF

> +      { "PROF", SIGPROF },

> +    #endif

> +    #ifdef SIGLOST

> +      { "LOST", SIGLOST },

> +    #endif

> +    /* The Issue 8 standard requires that SIGRTMIN and SIGRTMAX be included

> +     * as valid results to be saved from calls to sig2str/str2sig.  */

> +    #ifdef SIGRTMIN

> +      { "RTMIN", SIGRTMIN },

> +    #endif

> +    #ifdef SIGRTMAX

> +      { "RTMAX", SIGRTMAX }

> +    #endif

> +};

> +

> +int

> +sig2str(int signum, char *str)

> +{

> +  const sig_name_and_num *sptr;

> +

> +  /* If signum falls in lower half of the real time signals range, define

> +   * the saved str value as "RTMIN+n" according to the Issue 8 standard */

> +  if ((SIGRTMIN + 1) <= signum &&

> +      signum <= (SIGRTMIN + SIGRTMAX) / 2) {

> +    sprintf(str, "RTMIN+%d", (signum-SIGRTMIN));

> +    return 0;

> +  }

> +

> +  /* If signum falls in upper half of the real time signals range, define

> +   * the saved str value as "RTMAX-m" according to the Issue 8 standard */

> +  if ((((SIGRTMIN + SIGRTMAX) / 2) + 1) <= signum &&

> +         signum <= (SIGRTMAX - 1)) {

> +    sprintf(str, "RTMAX-%d", (SIGRTMAX - signum));

> +    return 0;

> +  }

> +

> +  /* Otherwise, search for signal matching signum in sig_array. If found,

> +   * save its string value in str. */

> +  for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {

> +    if (sptr->sig_num == signum) {

> +      strcpy(str, sptr->sig_name);

> +      return 0;

> +    }

> +  }

> +

> +  /* If signum is not a recognized signal number, return -1 */

> +  return -1;

> +}

> +

> +int

> +str2sig(const char *restrict str, int *restrict pnum)

> +{

> +  unsigned long j = 0;

> +  char *endp;

> +  const sig_name_and_num *sptr;

> +  unsigned long is_valid_decimal;

> +

> +  /* i686 Cygwin only supports one RT signal. For this case, skip checks

> +   * for "RTMIN+n" and "RTMAX-m". */

> +  if (SIGRTMIN != SIGRTMAX) {

> +

> +    /* If str is in RT signal range, get number of of RT signal, save it as an

> +    * integer. */

> +    if (strncmp(str, "RTMIN+", SPACES_TO_N) == 0) {

> +      j = strtoul(&str[SPACES_TO_N], &endp, 10);

> +

> +      /* If number is valid, save it in pnum. */

> +      if (*endp == '\0') {

> +        if (1 <= j &&

> +            j <= ((SIGRTMAX - SIGRTMIN)-1)) {

> +          *pnum = (SIGRTMIN + j);

> +          return 0;

> +        }

> +        return -1;

> +      }

> +      return -1;

> +    }

> +

> +    /* If str is in RT signal range, get number of of RT signal, save it as an

> +    * integer. */

> +    if (strncmp(str, "RTMAX-", SPACES_TO_N) == 0) {

> +      j = strtoul(&str[SPACES_TO_N], &endp, 10); // and endptr null check

> +

> +      /* If number is valid, save it in pnum. */

> +      if (*endp == '\0') {

> +        if (1 <= j &&

> +            j <= ((SIGRTMAX - SIGRTMIN)-1)) {

> +          *pnum = (SIGRTMAX - j);

> +          return 0;

> +        }

> +        return -1;

> +      }

> +      return -1;

> +    }

> +  }

> +

> +  /*If str is a valid signal name, save its corresponding number in pnum. */

> +  for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {

> +    if (strcmp(sptr->sig_name, str) == 0) {

> +      *pnum = sptr->sig_num;

> +      return 0;

> +    }

> +  }

> +

> +  /* str was not found in sig_array. Check whether str is a string

> +   * representation of a valid integer. */

> +  is_valid_decimal = strtoul(str, &endp, 10);

> +

> +  if (*endp != '\0') {

> +    return -1;

> +  }

> +

> +  /* If str is a representation of a decimal value, save its integer value

> +   * in pnum. */

> +  if (1 <= is_valid_decimal &&

> +      is_valid_decimal <= SIGRTMAX) {

> +    *pnum = is_valid_decimal;

> +    return 0;

> +  }

> +  return -1;

> +}

> --

> 2.31.1

>
Corinna Vinschen Aug. 2, 2021, 9:42 a.m. | #2
Hi Matt,

this looks good.  I pushed it with two minor changes in terms of
the documentation:

On Jul 31 15:22, Matt Joyce wrote:
> +FUNCTION

> +<<sig2str>>---translate between signal number and name

> +<<str2sig>>---translate between signal name and number


This doesn't work as desired.  I changed it to

  <<sig2str>>, <<str2sig>>---Translate between signal number and name

> +

> +INDEX

> +          sig2str

> +INDEX

> +          str2sig

> +

> +SYNOPSIS

> +          #include <signal.h>

> +          int sig2str(int <[signum]>, char *<[str]>);

> +

> +          int str2sig(const char *restrict <[str]>, int *restrict <[pnum]>);

> +

> +DESCRIPTION

> +The <<sig2str>> function translates the signal number specified by <[signum]> to

> +a signal name and stores this string in the location specified by <[str}>. The

                                                                     ^^^^^^^
opening square bracket vs. closing curly brace?  Uh oh ;)

Apart from that I created a new Makefile.in from your Makefile.am
change and added the str2sig entry to the documentation file
newlib/libc/signal/signal.tex.

I'll add the new functions as Cygwin exports later today.

Thanks for your patch and your patience while trying to get it right!


Corinna
Corinna Vinschen Aug. 2, 2021, 11:48 a.m. | #3
Hi Matt,

a collegue of mine pointed out that it might be good idea to be more
paranoid in terms of the output string size:

On Jul 31 15:22, Matt Joyce wrote:
> +sig2str(int signum, char *str)

> +{

> +  const sig_name_and_num *sptr;

> +

> +  /* If signum falls in lower half of the real time signals range, define

> +   * the saved str value as "RTMIN+n" according to the Issue 8 standard */

> +  if ((SIGRTMIN + 1) <= signum && 

> +      signum <= (SIGRTMIN + SIGRTMAX) / 2) {

> +    sprintf(str, "RTMIN+%d", (signum-SIGRTMIN));


       snprintf(str, SIG2STR_MAX, "RTMIN+%d", (signum-SIGRTMIN));

> +    return 0; 

> +  }

> +  

> +  /* If signum falls in upper half of the real time signals range, define

> +   * the saved str value as "RTMAX-m" according to the Issue 8 standard */

> +  if ((((SIGRTMIN + SIGRTMAX) / 2) + 1) <= signum &&

> +         signum <= (SIGRTMAX - 1)) {

> +    sprintf(str, "RTMAX-%d", (SIGRTMAX - signum));


       snprintf(str, SIG2STR_MAX, "RTMAX+%d", (signum-SIGRTMIN));

> +    return 0; 

> +  }

> +

> +  /* Otherwise, search for signal matching signum in sig_array. If found,

> +   * save its string value in str. */ 

> +  for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {

> +    if (sptr->sig_num == signum) {

> +      strcpy(str, sptr->sig_name);


         strlcpy(str, sptr->sig_name, SIG2STR_MAX);

What do you think?


Corinna
Matt Joyce Aug. 3, 2021, 3:57 a.m. | #4
Hi Corinna,

Thanks very much for the suggestion...that sounds sensible. I just
made the edits in a new patch (hopefully that's ok).

I'm really glad to help...thank you very much for your patience as well!

Sincerely,

Matt



On Mon, Aug 2, 2021 at 1:48 PM Corinna Vinschen <vinschen@redhat.com> wrote:
>

> Hi Matt,

>

> a collegue of mine pointed out that it might be good idea to be more

> paranoid in terms of the output string size:

>

> On Jul 31 15:22, Matt Joyce wrote:

> > +sig2str(int signum, char *str)

> > +{

> > +  const sig_name_and_num *sptr;

> > +

> > +  /* If signum falls in lower half of the real time signals range, define

> > +   * the saved str value as "RTMIN+n" according to the Issue 8 standard */

> > +  if ((SIGRTMIN + 1) <= signum &&

> > +      signum <= (SIGRTMIN + SIGRTMAX) / 2) {

> > +    sprintf(str, "RTMIN+%d", (signum-SIGRTMIN));

>

>        snprintf(str, SIG2STR_MAX, "RTMIN+%d", (signum-SIGRTMIN));

>

> > +    return 0;

> > +  }

> > +

> > +  /* If signum falls in upper half of the real time signals range, define

> > +   * the saved str value as "RTMAX-m" according to the Issue 8 standard */

> > +  if ((((SIGRTMIN + SIGRTMAX) / 2) + 1) <= signum &&

> > +         signum <= (SIGRTMAX - 1)) {

> > +    sprintf(str, "RTMAX-%d", (SIGRTMAX - signum));

>

>        snprintf(str, SIG2STR_MAX, "RTMAX+%d", (signum-SIGRTMIN));

>

> > +    return 0;

> > +  }

> > +

> > +  /* Otherwise, search for signal matching signum in sig_array. If found,

> > +   * save its string value in str. */

> > +  for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {

> > +    if (sptr->sig_num == signum) {

> > +      strcpy(str, sptr->sig_name);

>

>          strlcpy(str, sptr->sig_name, SIG2STR_MAX);

>

> What do you think?

>

>

> Corinna

>

Patch

diff --git a/newlib/libc/include/sys/signal.h b/newlib/libc/include/sys/signal.h
index 45cc0366c..9c1c0e3c2 100644
--- a/newlib/libc/include/sys/signal.h
+++ b/newlib/libc/include/sys/signal.h
@@ -12,6 +12,7 @@  extern "C" {
 #include <sys/types.h>
 #include <sys/_sigset.h>
 #include <sys/_timespec.h>
+#include <stdint.h>
 
 #if !defined(_SIGSET_T_DECLARED)
 #define	_SIGSET_T_DECLARED
@@ -238,6 +239,22 @@  int sigqueue (pid_t, int, const union sigval);
 
 #endif /* __POSIX_VISIBLE >= 199309 */
 
+/* Using __MISC_VISIBLE until POSIX Issue 8 is officially released */
+#if __MISC_VISIBLE
+
+/* POSIX Issue 8 adds sig2str() and str2sig() */
+
+#if __STDINT_EXP(INT_MAX) > 0x7fff
+#define SIG2STR_MAX (sizeof("RTMAX+") + sizeof("4294967295") - 1)
+#else
+#define SIG2STR_MAX (sizeof("RTMAX+") + sizeof("65535") - 1)
+#endif
+
+int sig2str(int, char *); 
+int str2sig(const char *__restrict, int *__restrict);
+
+#endif /* __MISC_VISIBLE */
+
 #if defined(___AM29K__)
 /* These all need to be defined for ANSI C, but I don't think they are
    meaningful.  */
diff --git a/newlib/libc/signal/Makefile.am b/newlib/libc/signal/Makefile.am
index a93dba7a9..89db26113 100644
--- a/newlib/libc/signal/Makefile.am
+++ b/newlib/libc/signal/Makefile.am
@@ -4,7 +4,7 @@  AUTOMAKE_OPTIONS = cygnus
 
 INCLUDES = $(NEWLIB_CFLAGS) $(CROSS_CFLAGS) $(TARGET_CFLAGS)
 
-LIB_SOURCES = psignal.c raise.c signal.c
+LIB_SOURCES = psignal.c raise.c signal.c sig2str.c
 
 libsignal_la_LDFLAGS = -Xcompiler -nostdlib
 
@@ -21,6 +21,6 @@  endif # USE_LIBTOOL
 
 include $(srcdir)/../../Makefile.shared
 
-CHEWOUT_FILES = psignal.def raise.def signal.def
+CHEWOUT_FILES = psignal.def raise.def signal.def sig2str.def
 
 CHAPTERS = signal.tex
diff --git a/newlib/libc/signal/sig2str.c b/newlib/libc/signal/sig2str.c
new file mode 100644
index 000000000..c02fcacbd
--- /dev/null
+++ b/newlib/libc/signal/sig2str.c
@@ -0,0 +1,298 @@ 
+/* SPDX-License-Identifier: BSD-2-Clause */
+/*
+ * Copyright (C) 2021 Matthew Joyce
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+FUNCTION
+<<sig2str>>---translate between signal number and name
+<<str2sig>>---translate between signal name and number
+
+INDEX
+          sig2str
+INDEX
+          str2sig
+
+SYNOPSIS
+          #include <signal.h>
+          int sig2str(int <[signum]>, char *<[str]>);
+
+          int str2sig(const char *restrict <[str]>, int *restrict <[pnum]>);
+
+DESCRIPTION
+The <<sig2str>> function translates the signal number specified by <[signum]> to
+a signal name and stores this string in the location specified by <[str}>. The
+application must ensure that <[str]> points to a location that can store the
+string including the terminating null byte. The symbolic constant 
+<[SIG2STR_MAX]> defined in `<<signal.h>>' gives the maximum number of bytes 
+required.
+
+The <<str2sig>> function translates the signal name in the string pointed to by 
+<[str]> to a signal number and stores this value in the location specified by 
+<[pnum]>.
+
+RETURNS
+<<sig2str>> returns <<0>> if <[signum]>> is a valid, supported signal number.
+Otherwise, it returns <<-1>>.
+
+<<str2sig>> returns <<0>> if it stores a value in the location pointed to by 
+<[pnum]>. Otherwise it returns <<-1>>.
+*/
+ 
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define SPACES_TO_N 6 /* Allows indexing to RT Signal number in str2sig */
+#define NUM_OF_SIGS (sizeof(sig_array) / sizeof(sig_name_and_num))
+
+typedef struct sig_name_and_num {
+  const char *sig_name;
+  const int  sig_num; 
+} sig_name_and_num;
+
+static const sig_name_and_num sig_array[] = {
+      { "EXIT", 0 },
+    #ifdef SIGHUP
+      { "HUP", SIGHUP },
+    #endif
+    #ifdef SIGINT
+      { "INT", SIGINT },
+    #endif
+    #ifdef SIGQUIT
+      { "QUIT", SIGQUIT },
+    #endif
+    #ifdef SIGILL
+      { "ILL", SIGILL },
+    #endif
+    #ifdef SIGTRAP
+      { "TRAP", SIGTRAP },
+    #endif
+    #ifdef SIGABRT
+      { "ABRT", SIGABRT },
+    #endif
+    #ifdef SIGIOT
+      { "IOT", SIGIOT},
+    #endif
+    #ifdef SIGEMT
+      { "EMT", SIGEMT },
+    #endif
+    #ifdef SIGFPE
+      { "FPE", SIGFPE },
+    #endif
+    #ifdef SIGKILL
+      { "KILL", SIGKILL },
+    #endif
+    #ifdef SIGBUS
+      { "BUS", SIGBUS },
+    #endif
+    #ifdef SIGSEGV
+      { "SEGV", SIGSEGV },
+    #endif
+    #ifdef SIGSYS
+      { "SYS", SIGSYS },
+    #endif
+    #ifdef SIGPIPE
+      { "PIPE", SIGPIPE },
+    #endif
+    #ifdef SIGALRM
+      { "ALRM", SIGALRM },
+    #endif
+    #ifdef SIGTERM
+      { "TERM", SIGTERM },
+    #endif
+    #ifdef SIGURG
+      { "URG", SIGURG },
+    #endif
+    #ifdef SIGSTOP
+      { "STOP", SIGSTOP },
+    #endif
+    #ifdef SIGTSTP
+      { "TSTP", SIGTSTP },
+    #endif
+    #ifdef SIGCONT
+      { "CONT", SIGCONT },
+    #endif
+    #ifdef SIGCHLD
+      { "CHLD", SIGCHLD },
+    #endif
+    #ifdef SIGCLD
+      { "CLD", SIGCLD },
+    #endif
+    #ifdef SIGTTIN
+      { "TTIN", SIGTTIN },
+    #endif
+    #ifdef SIGTTOU
+      { "TTOU", SIGTTOU },
+    #endif
+    #ifdef SIGIO
+      { "IO", SIGIO },
+    #endif
+    #ifdef SIGPOLL
+      { "POLL", SIGPOLL },
+    #endif
+    #ifdef SIGWINCH
+      { "WINCH", SIGWINCH },
+    #endif
+    #ifdef SIGUSR1
+      { "USR1", SIGUSR1 },
+    #endif
+    #ifdef SIGUSR2
+      { "USR2", SIGUSR2 },
+    #endif
+    #ifdef SIGPWR
+      { "PWR", SIGPWR },
+    #endif
+    #ifdef SIGXCPU
+      { "XCPU", SIGXCPU },
+    #endif
+    #ifdef SIGXFSZ
+      { "XFSZ", SIGXFSZ },
+    #endif
+    #ifdef SIGVTALRM
+      { "VTALRM", SIGVTALRM },
+    #endif
+    #ifdef SIGPROF
+      { "PROF", SIGPROF },
+    #endif
+    #ifdef SIGLOST
+      { "LOST", SIGLOST },
+    #endif
+    /* The Issue 8 standard requires that SIGRTMIN and SIGRTMAX be included 
+     * as valid results to be saved from calls to sig2str/str2sig.  */
+    #ifdef SIGRTMIN
+      { "RTMIN", SIGRTMIN },
+    #endif
+    #ifdef SIGRTMAX
+      { "RTMAX", SIGRTMAX }
+    #endif
+}; 
+
+int
+sig2str(int signum, char *str)
+{
+  const sig_name_and_num *sptr;
+
+  /* If signum falls in lower half of the real time signals range, define
+   * the saved str value as "RTMIN+n" according to the Issue 8 standard */
+  if ((SIGRTMIN + 1) <= signum && 
+      signum <= (SIGRTMIN + SIGRTMAX) / 2) {
+    sprintf(str, "RTMIN+%d", (signum-SIGRTMIN));
+    return 0; 
+  }
+  
+  /* If signum falls in upper half of the real time signals range, define
+   * the saved str value as "RTMAX-m" according to the Issue 8 standard */
+  if ((((SIGRTMIN + SIGRTMAX) / 2) + 1) <= signum &&
+         signum <= (SIGRTMAX - 1)) {
+    sprintf(str, "RTMAX-%d", (SIGRTMAX - signum));
+    return 0; 
+  }
+
+  /* Otherwise, search for signal matching signum in sig_array. If found,
+   * save its string value in str. */ 
+  for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {
+    if (sptr->sig_num == signum) {
+      strcpy(str, sptr->sig_name);
+      return 0; 
+    } 
+  }   
+
+  /* If signum is not a recognized signal number, return -1 */
+  return -1; 
+}
+
+int
+str2sig(const char *restrict str, int *restrict pnum)
+{
+  unsigned long j = 0; 
+  char *endp; 
+  const sig_name_and_num *sptr; 
+  unsigned long is_valid_decimal;
+
+  /* i686 Cygwin only supports one RT signal. For this case, skip checks 
+   * for "RTMIN+n" and "RTMAX-m". */
+  if (SIGRTMIN != SIGRTMAX) {
+
+    /* If str is in RT signal range, get number of of RT signal, save it as an 
+    * integer. */
+    if (strncmp(str, "RTMIN+", SPACES_TO_N) == 0) {
+      j = strtoul(&str[SPACES_TO_N], &endp, 10); 
+
+      /* If number is valid, save it in pnum. */
+      if (*endp == '\0') {
+        if (1 <= j &&
+            j <= ((SIGRTMAX - SIGRTMIN)-1)) {
+          *pnum = (SIGRTMIN + j);
+          return 0;
+        }
+        return -1; 
+      }
+      return -1;
+    }
+    
+    /* If str is in RT signal range, get number of of RT signal, save it as an 
+    * integer. */
+    if (strncmp(str, "RTMAX-", SPACES_TO_N) == 0) {
+      j = strtoul(&str[SPACES_TO_N], &endp, 10); // and endptr null check
+
+      /* If number is valid, save it in pnum. */
+      if (*endp == '\0') {
+        if (1 <= j &&
+            j <= ((SIGRTMAX - SIGRTMIN)-1)) {
+          *pnum = (SIGRTMAX - j);
+          return 0;
+        }
+        return -1; 
+      }
+      return -1;
+    }
+  }
+
+  /*If str is a valid signal name, save its corresponding number in pnum. */
+  for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {
+    if (strcmp(sptr->sig_name, str) == 0) {
+      *pnum = sptr->sig_num;
+      return 0; 
+    }    
+  }
+  
+  /* str was not found in sig_array. Check whether str is a string 
+   * representation of a valid integer. */
+  is_valid_decimal = strtoul(str, &endp, 10);
+  
+  if (*endp != '\0') {
+    return -1;
+  }
+
+  /* If str is a representation of a decimal value, save its integer value
+   * in pnum. */
+  if (1 <= is_valid_decimal &&
+      is_valid_decimal <= SIGRTMAX) {
+    *pnum = is_valid_decimal;
+    return 0; 
+  } 
+  return -1; 
+}