build-sys: Relocate lib/
test files in lib go to src/tests include/ goes to local/ lib/*.c goes to local/ Signed-off-by: Craig Small <csmall@dropbear.xyz>
This commit is contained in:
10
local/Makefile.am
Normal file
10
local/Makefile.am
Normal file
@@ -0,0 +1,10 @@
|
||||
dist_noinst_HEADERS = \
|
||||
c.h \
|
||||
fileutils.h \
|
||||
nls.h \
|
||||
procio.h \
|
||||
rpmatch.h \
|
||||
signals.h \
|
||||
strutils.h \
|
||||
tests.h \
|
||||
xalloc.h
|
||||
162
local/c.h
Normal file
162
local/c.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* This header was copied from util-linux at fall 2011.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Fundamental C definitions.
|
||||
*/
|
||||
|
||||
#ifndef PROCPS_NG_C_H
|
||||
#define PROCPS_NG_C_H
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_ERROR_H
|
||||
#include <error.h>
|
||||
#else
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Compiler specific stuff
|
||||
*/
|
||||
#ifndef __GNUC_PREREQ
|
||||
# if defined __GNUC__ && defined __GNUC_MINOR__
|
||||
# define __GNUC_PREREQ(maj, min) \
|
||||
((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
|
||||
# else
|
||||
# define __GNUC_PREREQ(maj, min) 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function attributes
|
||||
*/
|
||||
#ifndef __ul_alloc_size
|
||||
# if __GNUC_PREREQ (4, 3)
|
||||
# define __ul_alloc_size(s) __attribute__((alloc_size(s)))
|
||||
# else
|
||||
# define __ul_alloc_size(s)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef __ul_calloc_size
|
||||
# if __GNUC_PREREQ (4, 3)
|
||||
# define __ul_calloc_size(n, s) __attribute__((alloc_size(n, s)))
|
||||
# else
|
||||
# define __ul_calloc_size(n, s)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Misc
|
||||
*/
|
||||
#ifndef PATH_MAX
|
||||
# define PATH_MAX 4096
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
# define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
# define FALSE 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Program name.
|
||||
*/
|
||||
#ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME
|
||||
# ifdef HAVE___PROGNAME
|
||||
extern char *__progname;
|
||||
# define program_invocation_short_name __progname
|
||||
# else
|
||||
# ifdef HAVE_GETEXECNAME
|
||||
# define program_invocation_short_name \
|
||||
prog_inv_sh_nm_from_file(getexecname(), 0)
|
||||
# else
|
||||
# define program_invocation_short_name \
|
||||
prog_inv_sh_nm_from_file(__FILE__, 1)
|
||||
# endif
|
||||
static char prog_inv_sh_nm_buf[256];
|
||||
static inline char *prog_inv_sh_nm_from_file(char *f, char stripext)
|
||||
{
|
||||
char *t;
|
||||
|
||||
if ((t = strrchr(f, '/')) != NULL)
|
||||
t++;
|
||||
else
|
||||
t = f;
|
||||
|
||||
strncpy(prog_inv_sh_nm_buf, t, sizeof(prog_inv_sh_nm_buf) - 1);
|
||||
prog_inv_sh_nm_buf[sizeof(prog_inv_sh_nm_buf) - 1] = '\0';
|
||||
|
||||
if (stripext && (t = strrchr(prog_inv_sh_nm_buf, '.')) != NULL)
|
||||
*t = '\0';
|
||||
|
||||
return prog_inv_sh_nm_buf;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Error printing.
|
||||
*/
|
||||
#ifndef HAVE_ERROR_H
|
||||
/* Emulate the error() function from glibc */
|
||||
__attribute__((__format__(__printf__, 3, 4)))
|
||||
static void error(int status, int errnum, const char *format, ...)
|
||||
{
|
||||
va_list argp;
|
||||
fprintf(stderr, "%s: ", program_invocation_short_name);
|
||||
va_start(argp, format);
|
||||
vfprintf(stderr, format, argp);
|
||||
va_end(argp);
|
||||
if (errnum != 0)
|
||||
fprintf(stderr, ": %s", strerror(errnum));
|
||||
fprintf(stderr, "\n");
|
||||
if (status != 0)
|
||||
exit(status);
|
||||
}
|
||||
|
||||
/* Emulate the error_at_line() function from glibc */
|
||||
__attribute__((__format__(__printf__, 5, 6)))
|
||||
static void error_at_line(int status, int errnum, const char *filename,
|
||||
unsigned int linenum, const char *format, ...)
|
||||
{
|
||||
va_list argp;
|
||||
fprintf(stderr, "%s:%s:%u: ", program_invocation_short_name,
|
||||
filename, linenum);
|
||||
va_start(argp, format);
|
||||
vfprintf(stderr, format, argp);
|
||||
va_end(argp);
|
||||
if (errnum != 0)
|
||||
fprintf(stderr, ": error code %d", errnum);
|
||||
fprintf(stderr, "\n");
|
||||
if (status != 0)
|
||||
exit(status);
|
||||
}
|
||||
#endif
|
||||
#define xwarn(...) error(0, errno, __VA_ARGS__)
|
||||
#define xwarnx(...) error(0, 0, __VA_ARGS__)
|
||||
#define xerr(STATUS, ...) error(STATUS, errno, __VA_ARGS__)
|
||||
#define xerrx(STATUS, ...) error(STATUS, 0, __VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Constant strings for usage() functions.
|
||||
*/
|
||||
#define USAGE_HEADER _("\nUsage:\n")
|
||||
#define USAGE_OPTIONS _("\nOptions:\n")
|
||||
#define USAGE_SEPARATOR _("\n")
|
||||
#define USAGE_HELP _(" -h, --help display this help and exit\n")
|
||||
#define USAGE_VERSION _(" -V, --version output version information and exit\n")
|
||||
#define USAGE_MAN_TAIL(_man) _("\nFor more details see %s.\n"), _man
|
||||
|
||||
#define PROCPS_NG_VERSION _("%s from %s\n"), program_invocation_short_name, PACKAGE_STRING
|
||||
|
||||
#endif /* PROCPS_NG_C_H */
|
||||
45
local/fileutils.c
Normal file
45
local/fileutils.c
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_ERROR_H
|
||||
# include <error.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDIO_EXT_H
|
||||
# include <stdio_ext.h>
|
||||
#else
|
||||
/* FIXME: use a more portable definition of __fpending() (from gnulib?) */
|
||||
# include <stdio.h>
|
||||
# define __fpending(fp) ((fp)->_p - (fp)->_bf._base)
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "nls.h"
|
||||
#include "fileutils.h"
|
||||
#ifndef HAVE_ERROR_H
|
||||
# include "c.h" /* for error() emulation */
|
||||
#endif
|
||||
|
||||
int close_stream(FILE * stream)
|
||||
{
|
||||
const int some_pending = (__fpending(stream) != 0);
|
||||
const int prev_fail = (ferror(stream) != 0);
|
||||
const int fclose_fail = (fclose(stream) != 0);
|
||||
if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) {
|
||||
if (!fclose_fail && errno != EPIPE)
|
||||
errno = 0;
|
||||
return EOF;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Use atexit(); */
|
||||
void close_stdout(void)
|
||||
{
|
||||
if (close_stream(stdout) != 0 && !(errno == EPIPE)) {
|
||||
char const *write_error = _("write error");
|
||||
error(0, errno, "%s", write_error);
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (close_stream(stderr) != 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
7
local/fileutils.h
Normal file
7
local/fileutils.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef PROCPS_NG_FILEUTILS
|
||||
#define PROCPS_NG_FILEUTILS
|
||||
|
||||
int close_stream(FILE * stream);
|
||||
void close_stdout(void);
|
||||
|
||||
#endif
|
||||
114
local/nls.h
Normal file
114
local/nls.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This header was copied from util-linux at fall 2011.
|
||||
*/
|
||||
|
||||
#ifndef PROCPS_NG_NLS_H
|
||||
#define PROCPS_NG_NLS_H
|
||||
|
||||
/* programs issuing textdomain() need PACKAGE string */
|
||||
#include "config.h"
|
||||
|
||||
/* programs issuing bindtextdomain() also need LOCALEDIR string */
|
||||
#ifndef LOCALEDIR
|
||||
#define LOCALEDIR "/usr/share/locale"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#else
|
||||
# undef setlocale
|
||||
# define setlocale(Category, Locale) /* empty */
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(Text) gettext (Text)
|
||||
# ifdef gettext_noop
|
||||
# define N_(String) gettext_noop (String)
|
||||
# else
|
||||
# define N_(String) (String)
|
||||
# endif
|
||||
# define P_(Singular, Plural, n) ngettext (Singular, Plural, n)
|
||||
#else
|
||||
# undef bindtextdomain
|
||||
# define bindtextdomain(Domain, Directory) /* empty */
|
||||
# undef textdomain
|
||||
# define textdomain(Domain) /* empty */
|
||||
# define _(Text) (Text)
|
||||
# define N_(Text) (Text)
|
||||
# define P_(Singular, Plural, n) ((n) == 1 ? (Singular) : (Plural))
|
||||
#endif /* ENABLE_NLS */
|
||||
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
# include <langinfo.h>
|
||||
#else
|
||||
|
||||
typedef int nl_item;
|
||||
extern char *langinfo_fallback(nl_item item);
|
||||
|
||||
# define nl_langinfo langinfo_fallback
|
||||
|
||||
enum {
|
||||
CODESET = 1,
|
||||
RADIXCHAR,
|
||||
THOUSEP,
|
||||
D_T_FMT,
|
||||
D_FMT,
|
||||
T_FMT,
|
||||
T_FMT_AMPM,
|
||||
AM_STR,
|
||||
PM_STR,
|
||||
|
||||
DAY_1,
|
||||
DAY_2,
|
||||
DAY_3,
|
||||
DAY_4,
|
||||
DAY_5,
|
||||
DAY_6,
|
||||
DAY_7,
|
||||
|
||||
ABDAY_1,
|
||||
ABDAY_2,
|
||||
ABDAY_3,
|
||||
ABDAY_4,
|
||||
ABDAY_5,
|
||||
ABDAY_6,
|
||||
ABDAY_7,
|
||||
|
||||
MON_1,
|
||||
MON_2,
|
||||
MON_3,
|
||||
MON_4,
|
||||
MON_5,
|
||||
MON_6,
|
||||
MON_7,
|
||||
MON_8,
|
||||
MON_9,
|
||||
MON_10,
|
||||
MON_11,
|
||||
MON_12,
|
||||
|
||||
ABMON_1,
|
||||
ABMON_2,
|
||||
ABMON_3,
|
||||
ABMON_4,
|
||||
ABMON_5,
|
||||
ABMON_6,
|
||||
ABMON_7,
|
||||
ABMON_8,
|
||||
ABMON_9,
|
||||
ABMON_10,
|
||||
ABMON_11,
|
||||
ABMON_12,
|
||||
|
||||
ERA_D_FMT,
|
||||
ERA_D_T_FMT,
|
||||
ERA_T_FMT,
|
||||
ALT_DIGITS,
|
||||
CRNCYSTR,
|
||||
YESEXPR,
|
||||
NOEXPR
|
||||
};
|
||||
|
||||
#endif /* !HAVE_LANGINFO_H */
|
||||
#endif /* PROCPS_NG_NLS_H */
|
||||
292
local/procio.c
Normal file
292
local/procio.c
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* procio.c -- Replace stdio for read and write on files below
|
||||
* proc to be able to read and write large buffers as well.
|
||||
*
|
||||
* Copyright (C) 2017 Werner Fink
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef struct pcookie {
|
||||
char *buf;
|
||||
size_t count;
|
||||
size_t length;
|
||||
off_t offset;
|
||||
int fd;
|
||||
int delim;
|
||||
int final:1;
|
||||
} pcookie_t;
|
||||
|
||||
static ssize_t proc_read(void *, char *, size_t);
|
||||
static ssize_t proc_write(void *, const char *, size_t);
|
||||
static int proc_close(void *);
|
||||
|
||||
__extension__
|
||||
static cookie_io_functions_t procio = {
|
||||
.read = proc_read,
|
||||
.write = proc_write,
|
||||
.seek = NULL,
|
||||
.close = proc_close,
|
||||
};
|
||||
|
||||
FILE *fprocopen(const char *path, const char *mode)
|
||||
{
|
||||
pcookie_t *cookie = NULL;
|
||||
FILE *handle = NULL;
|
||||
mode_t flags = 0;
|
||||
size_t len = 0;
|
||||
int c, delim;
|
||||
|
||||
if (!mode || !(len = strlen(mode))) {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* No append mode possible */
|
||||
switch (mode[0]) {
|
||||
case 'r':
|
||||
flags |= O_RDONLY;
|
||||
break;
|
||||
case 'w':
|
||||
flags |= O_WRONLY|O_TRUNC;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
delim = ','; /* default delimeter is the comma */
|
||||
for (c = 1; c < len; c++) {
|
||||
switch (mode[c]) {
|
||||
case '\0':
|
||||
break;
|
||||
case '+':
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
case 'e':
|
||||
flags |= O_CLOEXEC;
|
||||
continue;
|
||||
case 'b':
|
||||
case 'm':
|
||||
case 'x':
|
||||
/* ignore this */
|
||||
continue;
|
||||
default:
|
||||
if (mode[c] == ' ' || (mode[c] >= ',' && mode[c] <= '.') || mode[c] == ':')
|
||||
delim = mode[c];
|
||||
else {
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
cookie = (pcookie_t *)malloc(sizeof(pcookie_t));
|
||||
if (!cookie)
|
||||
goto out;
|
||||
cookie->count = BUFSIZ;
|
||||
cookie->buf = (char *)malloc(cookie->count);
|
||||
if (!cookie->buf) {
|
||||
int errsv = errno;
|
||||
free(cookie);
|
||||
errno = errsv;
|
||||
goto out;
|
||||
}
|
||||
cookie->final = 0;
|
||||
cookie->offset = 0;
|
||||
cookie->length = 0;
|
||||
cookie->delim = delim;
|
||||
|
||||
cookie->fd = openat(AT_FDCWD, path, flags);
|
||||
if (cookie->fd < 0) {
|
||||
int errsv = errno;
|
||||
free(cookie->buf);
|
||||
free(cookie);
|
||||
errno = errsv;
|
||||
goto out;
|
||||
}
|
||||
|
||||
handle = fopencookie(cookie, mode, procio);
|
||||
if (!handle) {
|
||||
int errsv = errno;
|
||||
close(cookie->fd);
|
||||
free(cookie->buf);
|
||||
free(cookie);
|
||||
errno = errsv;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return handle;
|
||||
}
|
||||
|
||||
static
|
||||
ssize_t proc_read(void *c, char *buf, size_t count)
|
||||
{
|
||||
pcookie_t *cookie = c;
|
||||
ssize_t len = -1;
|
||||
void *ptr;
|
||||
|
||||
if (cookie->count < count) {
|
||||
ptr = realloc(cookie->buf, count);
|
||||
if (!ptr)
|
||||
goto out;
|
||||
cookie->buf = ptr;
|
||||
cookie->count = count;
|
||||
}
|
||||
|
||||
while (!cookie->final) {
|
||||
len = read(cookie->fd, cookie->buf, cookie->count);
|
||||
|
||||
if (len <= 0) {
|
||||
if (len == 0) {
|
||||
/* EOF */
|
||||
cookie->final = 1;
|
||||
cookie->buf[cookie->length] = '\0';
|
||||
break;
|
||||
}
|
||||
goto out; /* error or done */
|
||||
}
|
||||
|
||||
cookie->length = len;
|
||||
|
||||
if (cookie->length < cookie->count)
|
||||
continue;
|
||||
|
||||
/* Likly to small buffer here */
|
||||
|
||||
lseek(cookie->fd, 0, SEEK_SET); /* reset for a retry */
|
||||
|
||||
ptr = realloc(cookie->buf, cookie->count += BUFSIZ);
|
||||
if (!ptr)
|
||||
goto out;
|
||||
cookie->buf = ptr;
|
||||
}
|
||||
|
||||
len = count;
|
||||
if (cookie->length - cookie->offset < len)
|
||||
len = cookie->length - cookie->offset;
|
||||
|
||||
if (len < 0)
|
||||
len = 0;
|
||||
|
||||
if (len) {
|
||||
(void)memcpy(buf, cookie->buf+cookie->offset, len);
|
||||
cookie->offset += len;
|
||||
} else
|
||||
len = EOF;
|
||||
out:
|
||||
return len;
|
||||
}
|
||||
|
||||
#define LINELEN 4096
|
||||
|
||||
static
|
||||
ssize_t proc_write(void *c, const char *buf, size_t count)
|
||||
{
|
||||
pcookie_t *cookie = c;
|
||||
ssize_t len = -1;
|
||||
void *ptr;
|
||||
|
||||
if (!count) {
|
||||
len = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* NL is the final input */
|
||||
cookie->final = memrchr(buf, '\n', count) ? 1 : 0;
|
||||
|
||||
while (cookie->count < cookie->offset + count) {
|
||||
ptr = realloc(cookie->buf, cookie->count += count);
|
||||
if (!ptr)
|
||||
goto out;
|
||||
cookie->buf = ptr;
|
||||
}
|
||||
|
||||
len = count;
|
||||
(void)memcpy(cookie->buf+cookie->offset, buf, count);
|
||||
cookie->offset += count;
|
||||
|
||||
if (cookie->final) {
|
||||
len = write(cookie->fd, cookie->buf, cookie->offset);
|
||||
if (len < 0 && errno == EINVAL) {
|
||||
size_t offset;
|
||||
off_t amount;
|
||||
char *token;
|
||||
/*
|
||||
* Oops buffer might be to large, split buffer into
|
||||
* pieces at delimeter if provided
|
||||
*/
|
||||
if (!cookie->delim)
|
||||
goto out; /* Hey dude?! */
|
||||
offset = 0;
|
||||
do {
|
||||
token = NULL;
|
||||
if (cookie->offset > LINELEN)
|
||||
token = (char*)memrchr(cookie->buf+offset, cookie->delim, LINELEN);
|
||||
else
|
||||
token = (char*)memrchr(cookie->buf+offset, '\n', cookie->offset);
|
||||
if (token)
|
||||
*token = '\n';
|
||||
else {
|
||||
errno = EINVAL;
|
||||
len = -1;
|
||||
goto out; /* Wrong/Missing delimeter? */
|
||||
}
|
||||
if (offset > 0)
|
||||
lseek(cookie->fd, 1, SEEK_CUR);
|
||||
|
||||
amount = token-(cookie->buf+offset)+1;
|
||||
ptr = cookie->buf+offset;
|
||||
|
||||
len = write(cookie->fd, ptr, amount);
|
||||
if (len < 1 || len >= cookie->offset)
|
||||
break;
|
||||
|
||||
offset += len;
|
||||
cookie->offset -= len;
|
||||
|
||||
} while (cookie->offset > 0);
|
||||
}
|
||||
if (len > 0)
|
||||
len = count;
|
||||
}
|
||||
out:
|
||||
return len;
|
||||
}
|
||||
|
||||
static
|
||||
int proc_close(void *c)
|
||||
{
|
||||
pcookie_t *cookie = c;
|
||||
close(cookie->fd);
|
||||
free(cookie->buf);
|
||||
free(cookie);
|
||||
return 0;
|
||||
}
|
||||
6
local/procio.h
Normal file
6
local/procio.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef PROCPS_PROC_PROCIO_H
|
||||
#define PROCPS_PROC_PROCIO_H
|
||||
|
||||
FILE *fprocopen(const char *path, const char *mode);
|
||||
|
||||
#endif
|
||||
9
local/rpmatch.h
Normal file
9
local/rpmatch.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef PROCPS_NG_RPMATCH_H
|
||||
#define PROCPS_NG_RPMATCH_H
|
||||
|
||||
#ifndef HAVE_RPMATCH
|
||||
#define rpmatch(r) \
|
||||
(*r == 'y' || *r == 'Y' ? 1 : *r == 'n' || *r == 'N' ? 0 : -1)
|
||||
#endif
|
||||
|
||||
#endif /* PROCPS_NG_RPMATCH_H */
|
||||
316
local/signals.c
Normal file
316
local/signals.c
Normal file
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* signals.c - signal name, and number, conversions
|
||||
* Copyright 1998-2003 by Albert Cahalan
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "signals.h"
|
||||
#include "c.h"
|
||||
|
||||
/* Linux signals:
|
||||
*
|
||||
* SIGSYS is required by Unix98.
|
||||
* SIGEMT is part of SysV, BSD, and ancient UNIX tradition.
|
||||
*
|
||||
* They are provided by these Linux ports: alpha, mips, sparc, and sparc64.
|
||||
* You get SIGSTKFLT and SIGUNUSED instead on i386, m68k, ppc, and arm.
|
||||
* (this is a Linux & libc bug -- both must be fixed)
|
||||
*
|
||||
* Total garbage: SIGIO SIGINFO SIGIOT SIGCLD
|
||||
* (popular ones are handled as aliases)
|
||||
* SIGLOST
|
||||
* (except on the Hurd; reused to mean a server died)
|
||||
* Nearly garbage: SIGSTKFLT SIGUNUSED (nothing else to fill slots)
|
||||
*/
|
||||
|
||||
/* Linux 2.3.29 replaces SIGUNUSED with the standard SIGSYS signal */
|
||||
#ifndef SIGSYS
|
||||
# warning Standards require that <signal.h> define SIGSYS
|
||||
# define SIGSYS SIGUNUSED
|
||||
#endif
|
||||
|
||||
/* If we see both, it is likely SIGSTKFLT (junk) was replaced. */
|
||||
#ifdef SIGEMT
|
||||
# undef SIGSTKFLT
|
||||
#endif
|
||||
|
||||
#ifndef SIGRTMIN
|
||||
# warning Standards require that <signal.h> define SIGRTMIN; assuming 32
|
||||
# define SIGRTMIN 32
|
||||
#endif
|
||||
|
||||
/* It seems the SPARC libc does not know the kernel supports SIGPWR. */
|
||||
#if defined(__linux__) && !defined(SIGPWR)
|
||||
# warning Your header files lack SIGPWR. (assuming it is number 29)
|
||||
# define SIGPWR 29
|
||||
#endif
|
||||
|
||||
typedef struct mapstruct {
|
||||
const char *name;
|
||||
int num;
|
||||
} mapstruct;
|
||||
|
||||
|
||||
static const mapstruct sigtable[] = {
|
||||
{"ABRT", SIGABRT}, /* IOT */
|
||||
{"ALRM", SIGALRM},
|
||||
{"BUS", SIGBUS},
|
||||
{"CHLD", SIGCHLD}, /* CLD */
|
||||
{"CONT", SIGCONT},
|
||||
#ifdef SIGEMT
|
||||
{"EMT", SIGEMT},
|
||||
#endif
|
||||
{"FPE", SIGFPE},
|
||||
{"HUP", SIGHUP},
|
||||
{"ILL", SIGILL},
|
||||
{"INT", SIGINT},
|
||||
{"KILL", SIGKILL},
|
||||
#if defined(__GNU__)
|
||||
{"LOST", SIGLOST}, /* Hurd-specific */
|
||||
#endif
|
||||
{"PIPE", SIGPIPE},
|
||||
{"POLL", SIGPOLL}, /* IO */
|
||||
{"PROF", SIGPROF},
|
||||
#ifdef SIGPWR
|
||||
{"PWR", SIGPWR},
|
||||
#endif
|
||||
{"QUIT", SIGQUIT},
|
||||
{"SEGV", SIGSEGV},
|
||||
#ifdef SIGSTKFLT
|
||||
{"STKFLT", SIGSTKFLT},
|
||||
#endif
|
||||
{"STOP", SIGSTOP},
|
||||
{"SYS", SIGSYS}, /* UNUSED */
|
||||
{"TERM", SIGTERM},
|
||||
{"TRAP", SIGTRAP},
|
||||
{"TSTP", SIGTSTP},
|
||||
{"TTIN", SIGTTIN},
|
||||
{"TTOU", SIGTTOU},
|
||||
{"URG", SIGURG},
|
||||
{"USR1", SIGUSR1},
|
||||
{"USR2", SIGUSR2},
|
||||
{"VTALRM", SIGVTALRM},
|
||||
{"WINCH", SIGWINCH},
|
||||
{"XCPU", SIGXCPU},
|
||||
{"XFSZ", SIGXFSZ}
|
||||
};
|
||||
|
||||
|
||||
#define number_of_signals (sizeof(sigtable)/sizeof(mapstruct))
|
||||
|
||||
#define XJOIN(a, b) JOIN(a, b)
|
||||
#define JOIN(a, b) a##b
|
||||
#define STATIC_ASSERT(x) typedef int XJOIN(static_assert_on_line_,__LINE__)[(x) ? 1 : -1]
|
||||
|
||||
/* sanity check */
|
||||
#if defined(__linux__)
|
||||
STATIC_ASSERT(number_of_signals == 31);
|
||||
#elif defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
|
||||
STATIC_ASSERT(number_of_signals == 30);
|
||||
#elif defined(__GNU__)
|
||||
STATIC_ASSERT(number_of_signals == 31);
|
||||
#elif defined(__CYGWIN__)
|
||||
STATIC_ASSERT(number_of_signals == 31);
|
||||
#else
|
||||
# warning Unknown operating system; assuming number_of_signals is correct
|
||||
#endif
|
||||
|
||||
static int compare_signal_names(const void *a, const void *b){
|
||||
return strcasecmp( ((const mapstruct*)a)->name, ((const mapstruct*)b)->name );
|
||||
}
|
||||
|
||||
|
||||
const char *get_sigtable_name(int row)
|
||||
{
|
||||
if (row < 0 || row >= number_of_signals)
|
||||
return NULL;
|
||||
return sigtable[row].name;
|
||||
}
|
||||
|
||||
const int get_sigtable_num(int row)
|
||||
{
|
||||
if (row < 0 || row >= number_of_signals)
|
||||
return -1;
|
||||
return sigtable[row].num;
|
||||
}
|
||||
|
||||
/* return -1 on failure */
|
||||
int signal_name_to_number(const char *restrict name){
|
||||
long val;
|
||||
int offset;
|
||||
|
||||
/* clean up name */
|
||||
if(!strncasecmp(name,"SIG",3))
|
||||
name += 3;
|
||||
|
||||
if(!strcasecmp(name,"CLD"))
|
||||
return SIGCHLD;
|
||||
if(!strcasecmp(name,"IO"))
|
||||
return SIGPOLL;
|
||||
if(!strcasecmp(name,"IOT"))
|
||||
return SIGABRT;
|
||||
/* search the table */
|
||||
{
|
||||
const mapstruct ms = {name,0};
|
||||
const mapstruct *restrict const ptr = bsearch(
|
||||
&ms,
|
||||
sigtable,
|
||||
number_of_signals,
|
||||
sizeof(mapstruct),
|
||||
compare_signal_names);
|
||||
if(ptr)
|
||||
return ptr->num;
|
||||
}
|
||||
|
||||
if(!strcasecmp(name,"RTMIN"))
|
||||
return SIGRTMIN;
|
||||
if(!strcasecmp(name,"EXIT"))
|
||||
return 0;
|
||||
if(!strcasecmp(name,"NULL"))
|
||||
return 0;
|
||||
|
||||
offset = 0;
|
||||
if(!strncasecmp(name,"RTMIN+",6)) {
|
||||
name += 6;
|
||||
offset = SIGRTMIN;
|
||||
}
|
||||
|
||||
/* not found, so try as a number */
|
||||
{
|
||||
char *endp;
|
||||
val = strtol(name,&endp,10);
|
||||
if(*endp || endp==name)
|
||||
return -1; /* not valid */
|
||||
}
|
||||
if(val<0 || val+SIGRTMIN>127)
|
||||
return -1; /* not valid */
|
||||
return val+offset;
|
||||
}
|
||||
|
||||
const char *signal_number_to_name(int signo)
|
||||
{
|
||||
static char buf[32];
|
||||
int n = number_of_signals;
|
||||
signo &= 0x7f; /* need to process exit values too */
|
||||
while (n--) {
|
||||
if(sigtable[n].num==signo)
|
||||
return sigtable[n].name;
|
||||
}
|
||||
if (signo == SIGRTMIN)
|
||||
return "RTMIN";
|
||||
if (signo)
|
||||
sprintf(buf, "RTMIN+%d", signo-SIGRTMIN);
|
||||
else
|
||||
strcpy(buf,"0"); /* AIX has NULL; Solaris has EXIT */
|
||||
return buf;
|
||||
}
|
||||
|
||||
int skill_sig_option(int *argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
int signo = -1;
|
||||
for (i = 1; i < *argc; i++) {
|
||||
if (argv[i][0] == '-') {
|
||||
signo = signal_name_to_number(argv[i] + 1);
|
||||
if (-1 < signo) {
|
||||
memmove(argv + i, argv + i + 1,
|
||||
sizeof(char *) * (*argc - i));
|
||||
(*argc)--;
|
||||
return signo;
|
||||
}
|
||||
}
|
||||
}
|
||||
return signo;
|
||||
}
|
||||
|
||||
|
||||
/* strtosig is similar to print_given_signals() with exception, that
|
||||
* this function takes a string, and converts it to a signal name or
|
||||
* a number string depending on which way a round conversion is
|
||||
* queried. Non-existing signals return NULL. Notice that the
|
||||
* returned string should be freed after use.
|
||||
*/
|
||||
char *strtosig(const char *restrict s)
|
||||
{
|
||||
char *converted = NULL, *copy, *p, *endp;
|
||||
int i, numsignal = 0;
|
||||
|
||||
copy = strdup(s);
|
||||
if (!copy)
|
||||
xerrx(EXIT_FAILURE, "cannot duplicate string");
|
||||
for (p = copy; *p != '\0'; p++)
|
||||
*p = toupper(*p);
|
||||
p = copy;
|
||||
if (p[0] == 'S' && p[1] == 'I' && p[2] == 'G')
|
||||
p += 3;
|
||||
if (isdigit(*p)){
|
||||
numsignal = strtol(s,&endp,10);
|
||||
if(*endp || endp==s){
|
||||
free(p);
|
||||
return NULL; /* not valid */
|
||||
}
|
||||
}
|
||||
if (numsignal){
|
||||
for (i = 0; i < number_of_signals; i++){
|
||||
if (numsignal == get_sigtable_num(i)){
|
||||
converted = strdup(get_sigtable_name(i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < number_of_signals; i++){
|
||||
if (strcmp(p, get_sigtable_name(i)) == 0){
|
||||
converted = malloc(12);
|
||||
if (converted)
|
||||
snprintf(converted, 12, "%d", sigtable[i].num);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(copy);
|
||||
return converted;
|
||||
}
|
||||
|
||||
void unix_print_signals(void)
|
||||
{
|
||||
int pos = 0;
|
||||
int i = 0;
|
||||
while(++i <= number_of_signals){
|
||||
if(i-1) printf("%c", (pos>73)?(pos=0,'\n'):(pos++,' ') );
|
||||
pos += printf("%s", signal_number_to_name(i));
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void pretty_print_signals(void)
|
||||
{
|
||||
int i = 0;
|
||||
while(++i <= number_of_signals){
|
||||
int n;
|
||||
n = printf("%2d %s", i, signal_number_to_name(i));
|
||||
if(n>0 && i%7)
|
||||
printf("%s", " \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + n);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
if((i-1)%7) printf("\n");
|
||||
}
|
||||
|
||||
33
local/signals.h
Normal file
33
local/signals.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef PROC_SIG_H
|
||||
#define PROC_SIG_H
|
||||
/*
|
||||
* Copyright 1998-2003 by Albert Cahalan; all rights resered.
|
||||
* This file may be used subject to the terms and conditions of the
|
||||
* GNU Library General Public License Version 2, or any later version
|
||||
* at your option, as published by the Free Software Foundation.
|
||||
* 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 Library General Public License for more details.
|
||||
*/
|
||||
|
||||
extern const int number_of_signals;
|
||||
|
||||
extern const char *get_sigtable_name(int row);
|
||||
|
||||
extern const int get_sigtable_num(int row);
|
||||
|
||||
/* return -1 on failure */
|
||||
extern int signal_name_to_number(const char *__restrict name);
|
||||
|
||||
extern const char *signal_number_to_name(int signo);
|
||||
|
||||
extern int skill_sig_option(int *argc, char **argv);
|
||||
|
||||
extern char *strtosig(const char *restrict s);
|
||||
|
||||
extern void pretty_print_signals(void);
|
||||
|
||||
extern void unix_print_signals(void);
|
||||
|
||||
#endif
|
||||
123
local/strutils.c
Normal file
123
local/strutils.c
Normal file
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* strutils.c - various string routines shared by commands
|
||||
* This file was copied from util-linux at fall 2011.
|
||||
*
|
||||
* Copyright (C) 2010 Karel Zak <kzak@redhat.com>
|
||||
* Copyright (C) 2010 Davidlohr Bueso <dave@gnu.org>
|
||||
*
|
||||
* 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 2
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "c.h"
|
||||
#include "strutils.h"
|
||||
|
||||
/*
|
||||
* same as strtol(3) but exit on failure instead of returning crap
|
||||
*/
|
||||
long strtol_or_err(const char *str, const char *errmesg)
|
||||
{
|
||||
long num;
|
||||
char *end = NULL;
|
||||
|
||||
if (str != NULL && *str != '\0') {
|
||||
errno = 0;
|
||||
num = strtol(str, &end, 10);
|
||||
if (errno == 0 && str != end && end != NULL && *end == '\0')
|
||||
return num;
|
||||
}
|
||||
error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* same as strtod(3) but exit on failure instead of returning crap
|
||||
*/
|
||||
double strtod_or_err(const char *str, const char *errmesg)
|
||||
{
|
||||
double num;
|
||||
char *end = NULL;
|
||||
|
||||
if (str != NULL && *str != '\0') {
|
||||
errno = 0;
|
||||
num = strtod(str, &end);
|
||||
if (errno == 0 && str != end && end != NULL && *end == '\0')
|
||||
return num;
|
||||
}
|
||||
error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Covert a string into a double in a non-locale aware way.
|
||||
* This means the decimal point can be either . or ,
|
||||
* Also means you cannot use the other for thousands separator
|
||||
*
|
||||
* Exits on failure like its other _or_err cousins
|
||||
*/
|
||||
double strtod_nol_or_err(char *str, const char *errmesg)
|
||||
{
|
||||
double num;
|
||||
const char *cp, *radix;
|
||||
double mult;
|
||||
int negative = 0;
|
||||
|
||||
if (str != NULL && *str != '\0') {
|
||||
num = 0.0;
|
||||
cp = str;
|
||||
/* strip leading spaces */
|
||||
while (isspace(*cp))
|
||||
cp++;
|
||||
|
||||
/* get sign */
|
||||
if (*cp == '-') {
|
||||
negative = 1;
|
||||
cp++;
|
||||
} else if (*cp == '+')
|
||||
cp++;
|
||||
|
||||
/* find radix */
|
||||
radix = cp;
|
||||
mult=0.1;
|
||||
while(isdigit(*radix)) {
|
||||
radix++;
|
||||
mult *= 10;
|
||||
}
|
||||
while(isdigit(*cp)) {
|
||||
num += (*cp - '0') * mult;
|
||||
mult /= 10;
|
||||
cp++;
|
||||
}
|
||||
/* got the integers */
|
||||
if (*cp == '\0')
|
||||
return (negative?-num:num);
|
||||
if (*cp != '.' && *cp != ',')
|
||||
error(EXIT_FAILURE, EINVAL, "%s: '%s'", errmesg, str);
|
||||
|
||||
cp++;
|
||||
mult = 0.1;
|
||||
while(isdigit(*cp)) {
|
||||
num += (*cp - '0') * mult;
|
||||
mult /= 10;
|
||||
cp++;
|
||||
}
|
||||
if (*cp == '\0')
|
||||
return (negative?-num:num);
|
||||
}
|
||||
error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str);
|
||||
return 0;
|
||||
}
|
||||
12
local/strutils.h
Normal file
12
local/strutils.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* This header was copied from util-linux at fall 2011.
|
||||
*/
|
||||
|
||||
#ifndef PROCPS_NG_STRUTILS
|
||||
#define PROCPS_NG_STRUTILS
|
||||
|
||||
extern long strtol_or_err(const char *str, const char *errmesg);
|
||||
extern double strtod_or_err(const char *str, const char *errmesg);
|
||||
double strtod_nol_or_err(char *str, const char *errmesg);
|
||||
|
||||
#endif
|
||||
158
local/strverscmp.c
Normal file
158
local/strverscmp.c
Normal file
@@ -0,0 +1,158 @@
|
||||
/* Compare strings while treating digits characters numerically.
|
||||
Copyright (C) 1997, 2002, 2005 Free Software Foundation, Inc.
|
||||
This file is part of the libiberty library.
|
||||
Contributed by Jean-Fran<61>ois Bignolles <bignolle@ecoledoc.ibp.fr>, 1997.
|
||||
|
||||
Libiberty is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
Libiberty 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with the GNU C Library; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA. */
|
||||
|
||||
/* #include "libiberty.h" */
|
||||
/* #include "safe-ctype.h" */
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
@deftypefun int strverscmp (const char *@var{s1}, const char *@var{s2})
|
||||
The @code{strverscmp} function compares the string @var{s1} against
|
||||
@var{s2}, considering them as holding indices/version numbers. Return
|
||||
value follows the same conventions as found in the @code{strverscmp}
|
||||
function. In fact, if @var{s1} and @var{s2} contain no digits,
|
||||
@code{strverscmp} behaves like @code{strcmp}.
|
||||
|
||||
Basically, we compare strings normally (character by character), until
|
||||
we find a digit in each string - then we enter a special comparison
|
||||
mode, where each sequence of digits is taken as a whole. If we reach the
|
||||
end of these two parts without noticing a difference, we return to the
|
||||
standard comparison mode. There are two types of numeric parts:
|
||||
"integral" and "fractional" (those begin with a '0'). The types
|
||||
of the numeric parts affect the way we sort them:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
integral/integral: we compare values as you would expect.
|
||||
|
||||
@item
|
||||
fractional/integral: the fractional part is less than the integral one.
|
||||
Again, no surprise.
|
||||
|
||||
@item
|
||||
fractional/fractional: the things become a bit more complex.
|
||||
If the common prefix contains only leading zeroes, the longest part is less
|
||||
than the other one; else the comparison behaves normally.
|
||||
@end itemize
|
||||
|
||||
@smallexample
|
||||
strverscmp ("no digit", "no digit")
|
||||
@result{} 0 // @r{same behavior as strcmp.}
|
||||
strverscmp ("item#99", "item#100")
|
||||
@result{} <0 // @r{same prefix, but 99 < 100.}
|
||||
strverscmp ("alpha1", "alpha001")
|
||||
@result{} >0 // @r{fractional part inferior to integral one.}
|
||||
strverscmp ("part1_f012", "part1_f01")
|
||||
@result{} >0 // @r{two fractional parts.}
|
||||
strverscmp ("foo.009", "foo.0")
|
||||
@result{} <0 // @r{idem, but with leading zeroes only.}
|
||||
@end smallexample
|
||||
|
||||
This function is especially useful when dealing with filename sorting,
|
||||
because filenames frequently hold indices/version numbers.
|
||||
@end deftypefun
|
||||
|
||||
*/
|
||||
|
||||
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing
|
||||
fractional parts, S_Z: idem but with leading Zeroes only */
|
||||
#define S_N 0x0
|
||||
#define S_I 0x4
|
||||
#define S_F 0x8
|
||||
#define S_Z 0xC
|
||||
|
||||
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */
|
||||
#define CMP 2
|
||||
#define LEN 3
|
||||
|
||||
|
||||
/* Compare S1 and S2 as strings holding indices/version numbers,
|
||||
returning less than, equal to or greater than zero if S1 is less than,
|
||||
equal to or greater than S2 (for more info, see the Glibc texinfo doc). */
|
||||
|
||||
int
|
||||
strverscmp (const char *s1, const char *s2)
|
||||
{
|
||||
const unsigned char *p1 = (const unsigned char *) s1;
|
||||
const unsigned char *p2 = (const unsigned char *) s2;
|
||||
unsigned char c1, c2;
|
||||
int state;
|
||||
int diff;
|
||||
|
||||
/* Symbol(s) 0 [1-9] others (padding)
|
||||
Transition (10) 0 (01) d (00) x (11) - */
|
||||
static const unsigned int next_state[] =
|
||||
{
|
||||
/* state x d 0 - */
|
||||
/* S_N */ S_N, S_I, S_Z, S_N,
|
||||
/* S_I */ S_N, S_I, S_I, S_I,
|
||||
/* S_F */ S_N, S_F, S_F, S_F,
|
||||
/* S_Z */ S_N, S_F, S_Z, S_Z
|
||||
};
|
||||
|
||||
static const int result_type[] =
|
||||
{
|
||||
/* state x/x x/d x/0 x/- d/x d/d d/0 d/-
|
||||
0/x 0/d 0/0 0/- -/x -/d -/0 -/- */
|
||||
|
||||
/* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
|
||||
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP,
|
||||
+1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP,
|
||||
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
|
||||
/* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP,
|
||||
-1, CMP, CMP, CMP
|
||||
};
|
||||
|
||||
if (p1 == p2)
|
||||
return 0;
|
||||
|
||||
c1 = *p1++;
|
||||
c2 = *p2++;
|
||||
/* Hint: '0' is a digit too. */
|
||||
state = S_N | ((c1 == '0') + (isdigit (c1) != 0));
|
||||
|
||||
while ((diff = c1 - c2) == 0 && c1 != '\0')
|
||||
{
|
||||
state = next_state[state];
|
||||
c1 = *p1++;
|
||||
c2 = *p2++;
|
||||
state |= (c1 == '0') + (isdigit (c1) != 0);
|
||||
}
|
||||
|
||||
state = result_type[state << 2 | (((c2 == '0') + (isdigit (c2) != 0)))];
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case CMP:
|
||||
return diff;
|
||||
|
||||
case LEN:
|
||||
while (isdigit (*p1++))
|
||||
if (!isdigit (*p2++))
|
||||
return 1;
|
||||
|
||||
return isdigit (*p2) ? -1 : diff;
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
29
local/tests.h
Normal file
29
local/tests.h
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef PROCPS_NG_TESTS_H
|
||||
#define PROCPS_NG_TESTS_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef int (*TestFunction)(void *data);
|
||||
|
||||
char *testname;
|
||||
|
||||
|
||||
static inline int run_tests(TestFunction *list, void *data)
|
||||
{
|
||||
int i;
|
||||
TestFunction current;
|
||||
|
||||
for (i=0; list[i] != NULL; i++) {
|
||||
testname = NULL;
|
||||
current = list[i];
|
||||
if (!current(data)) {
|
||||
fprintf(stderr, "FAIL: %s\n", testname);
|
||||
return EXIT_FAILURE;
|
||||
} else {
|
||||
fprintf(stderr, "PASS: %s\n", testname);
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
60
local/xalloc.h
Normal file
60
local/xalloc.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This header was copied from util-linux at fall 2011.
|
||||
*/
|
||||
|
||||
/*
|
||||
* General memory allocation wrappers for malloc, realloc, calloc
|
||||
* and strdup.
|
||||
*/
|
||||
|
||||
#ifndef PROCPS_NG_XALLOC_H
|
||||
#define PROCPS_NG_XALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "c.h"
|
||||
|
||||
#ifndef XALLOC_EXIT_CODE
|
||||
# define XALLOC_EXIT_CODE EXIT_FAILURE
|
||||
#endif
|
||||
|
||||
static inline __ul_alloc_size(1)
|
||||
void *xmalloc(const size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
if (!ret && size)
|
||||
xerrx(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline __ul_alloc_size(2)
|
||||
void *xrealloc(void *ptr, const size_t size)
|
||||
{
|
||||
void *ret = realloc(ptr, size);
|
||||
if (!ret && size)
|
||||
xerrx(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline __ul_calloc_size(1, 2)
|
||||
void *xcalloc(const size_t nelems, const size_t size)
|
||||
{
|
||||
void *ret = calloc(nelems, size);
|
||||
if (!ret && size && nelems)
|
||||
xerrx(XALLOC_EXIT_CODE, "cannot allocate %zu bytes", size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char *xstrdup(const char *str)
|
||||
{
|
||||
char *ret;
|
||||
if (!str)
|
||||
return NULL;
|
||||
ret = strdup(str);
|
||||
if (!ret)
|
||||
xerrx(XALLOC_EXIT_CODE, "cannot duplicate string");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* PROCPS_NG_XALLOC_H */
|
||||
Reference in New Issue
Block a user