diff --git a/.gitignore b/.gitignore index ed955cc9..b8003009 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ heapprt if if-jl if-strict +inc/*.h incunabulum junk ll19 @@ -104,7 +105,6 @@ pipecircle piped-merge-sort pipeline pipesize -posixver.h pthread-37 pthread-? q7 diff --git a/etc/README.md b/etc/README.md new file mode 100644 index 00000000..357c3d42 --- /dev/null +++ b/etc/README.md @@ -0,0 +1,3 @@ +# Miscellaneous directory + +Initially, to hold soq.mk, the common makefile. Other files if needed. diff --git a/etc/soq.mk b/etc/soq.mk new file mode 100644 index 00000000..95972b6c --- /dev/null +++ b/etc/soq.mk @@ -0,0 +1,36 @@ +# Makefile fragment for SOQ (aka Himalayan-Yeti) GitHub Project +# +# Use: include ../../etc/soq.mk in a per-directory source file + +BASEDIR = ../.. + +LIBBASE = soq +LIBNAME = lib${LIBBASE}.a +LIBDIR = ${BASEDIR}/lib +HDRDIR = ${BASEDIR}/inc +LIBPATH = ${LIBDIR}/${LIBNAME} + +CC = gcc +SFLAGS = -std=c11 +WFLAG1 = -Wall +WFLAG2 = -Wextra +WFLAG3 = -Werror +WFLAG4 = -Wmissing-prototypes +WFLAG5 = -Wstrict-prototypes +WFLAG6 = #-Wold-style-declaration # Strict GCC only (not clang, it would seem). +WFLAG7 = -Wold-style-definition +WFLAGS = ${WFLAG1} ${WFLAG2} ${WFLAG3} ${WFLAG4} ${WFLAG5} ${WFLAG6} ${WFLAG7} +OFLAGS = -O3 +GFLAGS = -g +UFLAGS = # Set on command line +IFLAGS = -I${BASEDIR}/inc + +CFLAGS = ${SFLAGS} ${OFLAGS} ${GFLAGS} ${WFLAGS} ${UFLAGS} ${IFLAGS} + +LDFLAGS = -L${BASEDIR}/lib +LDLIBS = -lsoq + +DEBRIS = core a.out *~ *.o +RM_FR = rm -fr +RM_F = rm -f + diff --git a/inc/README.md b/inc/README.md new file mode 100644 index 00000000..eee68e3d --- /dev/null +++ b/inc/README.md @@ -0,0 +1,8 @@ +# Header directory + +I use 3-letter directories for src, bin, etc, tmp, lib — I've never seen a good reason not to use inc rather than include. + +This directory contains 'released' headers. +Headers from the library source directory are installed here when they're ready for general use. + +The directory should be ignored apart from the README.md file. diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 00000000..5be9fb19 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,6 @@ +# Library directory + +Apart from the README.md file, this is a destination for compiled libraries. +There shouldn't be any source code in here. + +The directory content should be ignored except for the README.md file. diff --git a/src/README.md b/src/README.md new file mode 100644 index 00000000..64d0c228 --- /dev/null +++ b/src/README.md @@ -0,0 +1,5 @@ +# Source directory + +Contains other directories, a makefile, and this README. + +Should not normally contain any other files. diff --git a/src/lib/README.md b/src/lib/README.md new file mode 100644 index 00000000..ae2658a4 --- /dev/null +++ b/src/lib/README.md @@ -0,0 +1,6 @@ +# Library source directory + +This is the source directory for library code which is compiled into the SOQ library. + +Most of this will be copies of code from main computers with (under protest) history missing. +Also RCS markers will be removed after an initial commit. diff --git a/src/lib/gcd.c b/src/lib/gcd.c new file mode 100644 index 00000000..dde2b6f0 --- /dev/null +++ b/src/lib/gcd.c @@ -0,0 +1,119 @@ +/* +@(#)File: gcd.c +@(#)Purpose: Implement Greatest Common Divisor for two integers +@(#)Author: J Leffler +@(#)Copyright: (C) JLSS 1993,1997,2000,2005,2012,2015-16 +@(#)Derivation: gcd.c,v 1.7 2015/06/02 03:05:40 +*/ + +/*TABSTOP=4*/ + +#include "gcd.h" + +int gcd(int x, int y) +{ + int r; + + if (x <= 0 || y <= 0) + return(0); + + while ((r = x % y) != 0) + { + x = y; + y = r; + } + return(y); +} + +unsigned long long gcd_ull(unsigned long long x, unsigned long long y) +{ + unsigned long long r; + + if (x == 0 || y == 0) + return(0); + + while ((r = x % y) != 0) + { + x = y; + y = r; + } + return(y); +} + +#if defined(TEST) + +#include +#include + +#define DIM(x) (sizeof(x)/sizeof(*(x))) + +typedef struct gcd_test +{ + int x; + int y; + int r; +} gcd_test; + +static gcd_test gcd_list[] = +{ + { 0, 1, 0 }, + { 1, 1, 1 }, + { 2, 1, 1 }, + { 3, 1, 1 }, + { 3, 2, 1 }, + { 4, 2, 2 }, + { 8, 2, 2 }, + { 16, 3, 1 }, + { 16, 4, 4 }, + { 16, 6, 2 }, + { 16, 12, 4 }, + { 4795615, 2310, 55 }, +}; + +typedef unsigned long long ULL; + +static size_t test_gcd(int x, int y, int z) +{ + size_t f = 0; + int r = gcd(x, y); + + if (r != z) + f = 1; + printf("%s GCD(%7d, %7d) = %7d (%7d expected)\n", + (r == z) ? "PASS" : "FAIL", x, y, r, z); + return(f); +} + +static size_t test_gcd_ull(unsigned long long x, unsigned long long y, unsigned long long z) +{ + size_t f = 0; + unsigned long long r = gcd_ull(x, y); + + if (r != z) + f = 1; + printf("%s GCD(%7lld, %7lld) = %7lld (%7lld expected)\n", + (r == z) ? "PASS" : "FAIL", x, y, r, z); + return(f); +} + +int main(void) +{ + size_t i; + size_t n = DIM(gcd_list); + size_t f = 0; + + for (i = 0; i < n; i++) + { + f += test_gcd(gcd_list[i].x, gcd_list[i].y, gcd_list[i].r); + f += test_gcd(gcd_list[i].y, gcd_list[i].x, gcd_list[i].r); + f += test_gcd_ull((ULL)gcd_list[i].x, (ULL)gcd_list[i].y, (ULL)gcd_list[i].r); + f += test_gcd_ull((ULL)gcd_list[i].y, (ULL)gcd_list[i].x, (ULL)gcd_list[i].r); + } + if (f != 0) + printf("*** FAILED *** (%lu tests out of %lu)\n", (unsigned long)f, (unsigned long)(2 * n)); + else + printf("=== PASSED === (%lu tests)\n", (unsigned long)(2 * n)); + return((f == 0) ? EXIT_SUCCESS : EXIT_FAILURE); +} + +#endif /* TEST */ diff --git a/src/lib/gcd.h b/src/lib/gcd.h new file mode 100644 index 00000000..84b60ea8 --- /dev/null +++ b/src/lib/gcd.h @@ -0,0 +1,15 @@ +/* +@(#)File: gcd.h +@(#)Purpose: GCD - Greatest Common Denominator +@(#)Author: J Leffler +@(#)Copyright: (C) JLSS 2005,2008,2012,2016 +@(#)Derivation: gcd.h,v 1.4 2012/06/29 15:25:57 +*/ + +#ifndef JLSS_ID_GCD_H +#define JLSS_ID_GCD_H + +extern int gcd(int x, int y); +extern unsigned long long gcd_ull(unsigned long long x, unsigned long long y); + +#endif /* JLSS_ID_GCD_H */ diff --git a/src/lib/makefile b/src/lib/makefile new file mode 100644 index 00000000..b786f484 --- /dev/null +++ b/src/lib/makefile @@ -0,0 +1,28 @@ +# Makefile for SOQ library + +include ../../etc/soq.mk + +CP = cp +CPFLAGS = -fp + +FILES.c = \ + gcd.c \ + stderr.c + +FILES.o = ${FILES.c:.c=.o} +FILES.h = ${FILES.c:.c=.h} + +all: ${LIBNAME} ${FILES.h} + +${LIBNAME}: ${FILES.o} + ${AR} ${ARFLAGS} ${LIBNAME} ${FILES.o} + +install: ${LIBNAME} ${FILES.h} + ${CP} ${CPFLAGS} ${LIBNAME} ${LIBDIR} + ${CP} ${CPFLAGS} ${FILES.h} ${HDRDIR} + +clean: + ${RM_F} ${DEBRIS} ${FILES.o} + +realclean: clean + ${RM_F} ${LIBNAME} diff --git a/src/lib/posixver.h b/src/lib/posixver.h new file mode 100644 index 00000000..4199cfed --- /dev/null +++ b/src/lib/posixver.h @@ -0,0 +1,35 @@ +/* +@(#)File: posixver.h +@(#)Purpose: Request appropriate POSIX and X/Open Support +@(#)Author: J Leffler +@(#)Copyright: (C) JLSS 2010,2015-16 +@(#)Derivation: posixver.h,v 1.3 2015/07/05 21:28:18 +*/ + +/*TABSTOP=4*/ + +#ifndef JLSS_ID_POSIXVER_H +#define JLSS_ID_POSIXVER_H + +/* +** Include this file before including system headers. By default, with +** C99 support from the compiler, it requests POSIX 2001 support. With +** C89 support only, it requests POSIX 1997 support. Override the +** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE. +*/ + +/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */ +/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */ +/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */ + +#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE) +#if defined(__cplusplus) +#define _XOPEN_SOURCE 700 /* SUS v4, POSIX 1003.1 2008/13 (POSIX 2008/13) */ +#elif __STDC_VERSION__ >= 199901L +#define _XOPEN_SOURCE 700 /* SUS v4, POSIX 1003.1 2008/13 (POSIX 2008/13) */ +#else +#define _XOPEN_SOURCE 500 /* SUS v2, POSIX 1003.1 1997 */ +#endif /* __STDC_VERSION__ */ +#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */ + +#endif /* JLSS_ID_POSIXVER_H */ diff --git a/src/lib/stderr.c b/src/lib/stderr.c new file mode 100644 index 00000000..51b4976e --- /dev/null +++ b/src/lib/stderr.c @@ -0,0 +1,500 @@ +/* +@(#)File: stderr.c +@(#)Purpose: Error reporting routines +@(#)Author: J Leffler +@(#)Copyright: (C) JLSS 1988-91,1996-99,2001,2003,2005-11,2013,2015-16 +@(#)Derivation: stderr.c,v 10.14 2015/06/02 03:04:32 +*/ + +/*TABSTOP=4*/ + +#include "posixver.h" +#include "stderr.h" /* Includes config.h if available */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#else +extern int getpid(void); +#endif /* HAVE_UNISTD_H */ + +enum { MAX_MSGLEN = 2048 }; + +/* Find sub-second timing mechanism */ +#if defined(HAVE_CLOCK_GETTIME) +/* Uses */ +#elif defined(HAVE_GETTIMEOFDAY) +/* Mac OS X 10.10.3 does not have clock_gettime() yet */ +#include +#else +/* No sub-second timing */ +#endif + +static const char def_format[] = "%Y-%m-%d %H:%M:%S"; +static const char *tm_format = def_format; +static char arg0[ERR_MAXLEN_ARGV0+1] = "**undefined**"; + +/* Permitted default error flags */ +enum { ERR_LOGTIME = ERR_STAMP | ERR_MILLI | ERR_MICRO | ERR_NANO }; +enum { ERR_LOGOPTS = ERR_NOFLUSH | ERR_EXIT | ERR_ABORT | ERR_LOGTIME | + ERR_NOARG0 | ERR_PID | ERR_ERRNO }; +static int err_flags = 0; /* Default error flags (ERR_STAMP, ERR_PID, etc) */ + +/* File where messages go */ +static FILE *errout = 0; + +/* +** err_???_print() functions are named systematically, and are all static. +** +** err_[ev][crx][fn]_print(): +** -- e takes ellipsis argument +** -- v takes va_list argument +** -- c conditionally exits +** -- r returns (no exit) +** -- x exits (no return) +** -- f takes file pointer +** -- n no file pointer (use errout) +** +** NB: no-return and printf-like can only be attached to declarations, not definitions. +*/ + +static NORETURN void err_vxf_print(FILE *fp, int flags, int estat, const char *format, va_list args); +static NORETURN void err_vxn_print(int flags, int estat, const char *format, va_list args); +static NORETURN void err_exn_print(int flags, int estat, const char *format, ...) + PRINTFLIKE(3,4); +static NORETURN void err_terminate(int flags, int estat); + +/* +** Set default log options, returning old value. +** Setting ERR_EXIT and ERR_ABORT is permitted but not recommended. +*/ +int err_setlogopts(int new_opts) +{ + int old_opts = err_flags; + err_flags = new_opts & ERR_LOGOPTS; + return(old_opts); +} + +/* Return default log options */ +int err_getlogopts(void) +{ + return(err_flags); +} + +/* Change the definition of 'stderr', reporting on the old one too */ +/* NB: using err_stderr((FILE *)0) simply reports the current 'stderr' */ +FILE *(err_stderr)(FILE *newerr) +{ + FILE *old; + + if (errout == 0) + errout = stderr; + old = errout; + if (newerr != 0) + errout = newerr; + return(old); +} + +/* Return stored basename of command */ +const char *(err_getarg0)(void) +{ + return(arg0); +} + +/* Store basename of command, excluding trailing slashes */ +void (err_setarg0)(const char *argv0) +{ + /* Ignore three pathological program names -- NULL, "/" and "" */ + if (argv0 != 0 && *argv0 != '\0' && (*argv0 != '/' || *(argv0 + 1) != '\0')) + { + const char *cp; + size_t nbytes = sizeof(arg0) - 1; + + if ((cp = strrchr(argv0, '/')) == 0) + { + /* Basename of file only */ + cp = argv0; + } + else if (*(cp + 1) != '\0') + { + /* Regular pathname containing slashes but not trailing slashes */ + cp++; + } + else + { + /* Skip backwards over trailing slashes */ + const char *ep = cp; + while (ep > argv0 && *ep == '/') + ep--; + /* Skip backwards over non-slashes */ + cp = ep; + while (cp > argv0 && *cp != '/') + cp--; + assert(ep >= cp); + cp++; + nbytes = (size_t)(ep - cp) + 1; + if (nbytes > sizeof(arg0) - 1) + nbytes = sizeof(arg0) - 1; + } + strncpy(arg0, cp, nbytes); + arg0[nbytes] = '\0'; + } +} + +const char *(err_rcs_string)(const char *s2, char *buffer, size_t buflen) +{ + const char *src = s2; + char *dst = buffer; + char *end = buffer + buflen - 1; + + /* + ** Bother RCS! We've probably been given something like: + ** "$Revision: 10.14 $ ($Date: 2015/06/02 03:04:32 $)" + ** We only want to emit "7.5 (2001/08/11 06:25:48)". + ** Skip the components between '$' and ': ', copy up to ' $', + ** repeating as necessary. And we have to test for overflow! + ** Also work with the unexpanded forms of keywords ($Keyword$). + ** Never needed this with SCCS! + */ + while (*src != '\0' && dst < end) + { + while (*src != '\0' && *src != '$') + { + *dst++ = *src++; + if (dst >= end) + break; + } + if (*src == '$') + src++; + while (*src != '\0' && *src != ':' && *src != '$') + src++; + if (*src == '\0') + break; + if (*src == '$') + { + /* Unexpanded keyword '$Keyword$' notation */ + src++; + continue; + } + if (*src == ':') + src++; + if (*src == ' ') + src++; + while (*src != '\0' && *src != '$') + { + /* Map / in 2009/02/15 to dash */ + /* Heuristic - maps slashes surrounded by digits to dashes */ + char c = *src++; + if (c == '/' && isdigit(*src) && isdigit(*(src-2))) + c = '-'; + *dst++ = c; + if (dst >= end) + break; + } + if (*src == '$') + { + if (*(dst-1) == ' ') + dst--; + src++; + } + } + *dst = '\0'; + return(buffer); +} + +/* Similar to, but different from, Time in timer.h */ +typedef struct Time +{ + time_t tv_sec; + long tv_nsec; +} Time; + +static Time now(void) +{ + Time clk; +#if defined(HAVE_CLOCK_GETTIME) + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + clk.tv_sec = ts.tv_sec; + clk.tv_nsec = ts.tv_nsec; +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval tv; + gettimeofday(&tv, 0); + clk.tv_sec = tv.tv_sec; + clk.tv_nsec = 1000 * tv.tv_usec; +#else + clk.tv_sec = time(0); + clk.tv_nsec = 0; +#endif + return clk; +} + +/* Format a time string for now (using ISO8601 format) */ +/* Allow for future settable time format with tm_format */ +static char *err_time(int flags, char *buffer, size_t buflen) +{ + Time clk = now(); + struct tm *tp = localtime(&clk.tv_sec); + size_t nb = strftime(buffer, buflen, tm_format, tp); + if (flags & (ERR_NANO | ERR_MICRO | ERR_MILLI)) + { + char subsec[12]; + size_t ss_len; + if (flags & ERR_NANO) + ss_len = snprintf(subsec, sizeof(subsec), ".%.9ld", clk.tv_nsec); + else if (flags & ERR_MICRO) + ss_len = snprintf(subsec, sizeof(subsec), ".%.6ld", clk.tv_nsec / 1000); + else /* (flags & ERR_MILLI) */ + ss_len = snprintf(subsec, sizeof(subsec), ".%.3ld", clk.tv_nsec / (1000 * 1000)); + if (ss_len + nb + 1 < buflen) + strcpy(buffer + nb, subsec); + } + return(buffer); +} + +/* err_stdio - report error via stdio */ +static void (err_stdio)(FILE *fp, int flags, int errnum, const char *format, va_list args) +{ + if ((flags & ERR_NOARG0) == 0) + fprintf(fp, "%s: ", arg0); + if (flags & ERR_LOGTIME) + { + char timbuf[48]; + fprintf(fp, "%s - ", err_time(flags, timbuf, sizeof(timbuf))); + } + if (flags & ERR_PID) + fprintf(fp, "pid=%d: ", (int)getpid()); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + vfprintf(fp, format, args); +#pragma GCC diagnostic pop + if (flags & ERR_ERRNO) + fprintf(fp, "error (%d) %s\n", errnum, strerror(errnum)); +} + +/* Most fundamental (and flexible) error message printing routine - always returns */ +static void (err_vrf_print)(FILE *fp, int flags, const char *format, va_list args) +{ + int errnum = errno; /* Capture errno before it is damaged! */ + + if ((flags & ERR_NOFLUSH) == 0) + fflush(0); + + err_stdio(fp, flags, errnum, format, args); + + fflush(fp); +} + +/* Terminate program - abort or exit */ +static void err_terminate(int flags, int estat) +{ + assert(flags & (ERR_ABORT|ERR_EXIT)); + if (flags & ERR_ABORT) + abort(); + exit(estat); +} + +/* Most fundamental (and flexible) error message printing routine - may return */ +static void (err_vcf_print)(FILE *fp, int flags, int estat, const char *format, va_list args) +{ + err_vrf_print(fp, flags, format, args); + if (flags & (ERR_ABORT|ERR_EXIT)) + err_terminate(flags, estat); +} + +/* Analog of err_vcf_print() which guarantees 'no return' */ +static void (err_vxf_print)(FILE *fp, int flags, int estat, const char *format, va_list args) +{ + err_vrf_print(fp, flags, format, args); + err_terminate(flags, estat); +} + +/* External interface to err_vcf_print() - may return */ +void (err_logmsg)(FILE *fp, int flags, int estat, const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vcf_print(fp, flags, estat, format, args); + va_end(args); +} + +/* Print error message to current error output - no return */ +static void (err_vxn_print)(int flags, int estat, const char *format, va_list args) +{ + if (errout == 0) + errout = stderr; + err_vxf_print(errout, flags, estat, format, args); +} + +/* Print error message to current error output - no return */ +static void err_exn_print(int flags, int estat, const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vxn_print(flags, estat, format, args); + va_end(args); +} + +/* Print error message to nominated output - always returns */ +static void err_erf_print(FILE *fp, int flags, const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vrf_print(fp, flags, format, args); + va_end(args); +} + +/* Print message using current error file */ +void (err_print)(int flags, int estat, const char *format, va_list args) +{ + if (errout == 0) + errout = stderr; + err_vcf_print(errout, flags, estat, format, args); +} + +static void err_vrn_print(int flags, const char *format, va_list args) +{ + if (errout == 0) + errout = stderr; + err_vrf_print(errout, flags, format, args); +} + +/* Report warning including message from errno */ +void (err_sysrem)(const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vrn_print(ERR_SYSREM | err_getlogopts(), format, args); + va_end(args); +} + +/* Report warning including message from errno */ +void (err_sysremark)(int errnum, const char *format, ...) +{ + va_list args; + int old_errno = errno; + + errno = errnum; + va_start(args, format); + err_vrn_print(ERR_SYSREM | err_getlogopts(), format, args); + va_end(args); + errno = old_errno; +} + +/* Report error including message from errno */ +void (err_syserr)(const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vxn_print(ERR_SYSERR | err_getlogopts(), ERR_STAT, format, args); + va_end(args); +} + +/* Report error including message from errno */ +void (err_syserror)(int errnum, const char *format, ...) +{ + va_list args; + int old_errno = errno; + + errno = errnum; + va_start(args, format); + err_vxn_print(ERR_SYSERR | err_getlogopts(), ERR_STAT, format, args); + va_end(args); + errno = old_errno; +} + +/* Report warning */ +void (err_remark)(const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vrn_print(ERR_REM | err_getlogopts(), format, args); + va_end(args); +} + +/* Report error */ +void (err_error)(const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vxn_print(ERR_ERR | err_getlogopts(), ERR_STAT, format, args); + va_end(args); +} + +/* Report message - sometimes exiting too */ +void (err_report)(int flags, int estat, const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_print(flags, estat, format, args); + va_end(args); +} + +/* Print usage message and exit with failure status */ +void (err_usage)(const char *s1) +{ + err_exn_print(ERR_NOARG0|ERR_EXIT, EXIT_FAILURE, "Usage: %s %s\n", err_getarg0(), s1); +} + +/* Report failure and generate core dump */ +void (err_abort)(const char *format, ...) +{ + va_list args; + + va_start(args, format); + err_vxn_print(ERR_ABORT | err_getlogopts(), EXIT_FAILURE, format, args); + va_end(args); +} + +/* Report version information (no exit), removing embedded RCS keyword strings (but not values) */ +void (err_printversion)(const char *program, const char *verinfo) +{ + char buffer[64]; + + if (strchr(verinfo, '$')) + verinfo = err_rcs_string(verinfo, buffer, sizeof(buffer)); + err_erf_print(stdout, ERR_DEFAULT, "%s Version %s\n", program, verinfo); +} + +/* Report version information and exit, removing embedded RCS keyword strings (but not values) */ +void (err_version)(const char *program, const char *verinfo) +{ + err_printversion(program, verinfo); + exit(EXIT_SUCCESS); +} + +/* Report an internal error and exit */ +/* Abort if JLSS_INTERNAL_ERROR_ABORT set in environment */ +void (err_internal)(const char *function, const char *format, ...) +{ + va_list args; + int flags = ERR_EXIT; + const char *ev = getenv("JLSS_INTERNAL_ERROR_ABORT"); + + va_start(args, format); + if (ev != 0 && *ev != '\0') + flags = ERR_ABORT; /* Generate core dump */ + err_remark("unrecoverable internal error in function %s():\n", function); + err_vxn_print(flags | err_getlogopts(), EXIT_FAILURE, format, args); + va_end(args); +} + +#ifdef TEST + +#error Use separate test program test.stderr.c + +#endif /* TEST */ diff --git a/src/lib/stderr.h b/src/lib/stderr.h new file mode 100644 index 00000000..b53fde38 --- /dev/null +++ b/src/lib/stderr.h @@ -0,0 +1,96 @@ +/* +@(#)File: stderr.h +@(#)Purpose: Header file for standard error functions +@(#)Author: J Leffler +@(#)Copyright: (C) JLSS 1989-93,1996-99,2003,2005-11,2015-16 +@(#)Derivation: stderr.h,v 10.10 2015/10/14 23:12:19 +*/ + +#if !defined(STDERR_H) +#define STDERR_H + +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include +#include + +/* Beware changing the NORETURN and PRINTFLIKE stanzas */ +#if !defined(NORETURN) +#if __STDC_VERSION__ >= 201112L +#define NORETURN _Noreturn +#elif defined(__GNUC__) +#define NORETURN __attribute__((noreturn)) +#else +#define NORETURN /* If only */ +#endif /* __STDC_VERSION__ || __GNUC__ */ +#endif /* NORETURN */ + +#if !defined(PRINTFLIKE) +#if defined(__GNUC__) +#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m))) +#else +#define PRINTFLIKE(n,m) /* If only */ +#endif /* __GNUC__ */ +#endif /* PRINTFLIKE */ + +/* -- Definitions for error handling */ + +enum { ERR_STAT = 1 }; /* Default exit status */ + +enum { ERR_DEFAULT = 0x0000 }; /* Default flag */ +enum { ERR_NOFLUSH = 0x0001 }; /* Do not flush open files */ +enum { ERR_EXIT = 0x0004 }; /* Exit -- do not return */ +enum { ERR_ABORT = 0x0008 }; /* Abort -- do not return */ +enum { ERR_STAMP = 0x0020 }; /* Timestamp messages (whole second) */ +enum { ERR_NOARG0 = 0x0040 }; /* Do not print arg0 prefix */ +enum { ERR_PID = 0x0080 }; /* Include pid=nnnnn info */ +enum { ERR_ERRNO = 0x0100 }; /* Include system error */ +enum { ERR_MILLI = 0x0200 }; /* Timestamp messages (millisecond) */ +enum { ERR_MICRO = 0x0400 }; /* Timestamp messages (microsecond) */ +enum { ERR_NANO = 0x0800 }; /* Timestamp messages (nanosecond) */ + +/* -- Standard combinations of flags */ + +enum { ERR_REM = ERR_DEFAULT }; +enum { ERR_ERR = ERR_EXIT }; +enum { ERR_ABT = ERR_ABORT }; +enum { ERR_LOG = ERR_STAMP|ERR_PID }; +enum { ERR_SYSREM = ERR_REM|ERR_ERRNO }; +enum { ERR_SYSERR = ERR_ERR|ERR_ERRNO }; + +/* -- Maximum recorded length of argv[0]; extra is truncated */ + +enum { ERR_MAXLEN_ARGV0 = 63 }; + +/* -- Global definitions */ + +extern const char *err_getarg0(void); +extern void err_setarg0(const char *argv0); + +extern FILE *err_stderr(FILE *fp); +extern const char *err_rcs_string(const char *s, char *buffer, size_t buflen); + +extern NORETURN void err_abort(const char *format, ...) PRINTFLIKE(1,2); +extern NORETURN void err_error(const char *format, ...) PRINTFLIKE(1,2); +extern NORETURN void err_help(const char *use_str, const char *hlp_str); +extern NORETURN void err_helplist(const char *use_str, const char * const *help_list); +extern NORETURN void err_internal(const char *function, const char *format, ...) PRINTFLIKE(2,3); +extern NORETURN void err_syserr(const char *format, ...) PRINTFLIKE(1,2); +extern NORETURN void err_syserror(int errnum, const char *format, ...) PRINTFLIKE(2,3); +extern NORETURN void err_usage(const char *usestr); +extern NORETURN void err_version(const char *program, const char *verinfo); + +extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5); +extern void err_print(int flags, int estat, const char *format, va_list args); +extern void err_printversion(const char *program, const char *verinfo); +extern void err_remark(const char *format, ...) PRINTFLIKE(1,2); +extern void err_report(int flags, int estat, const char *format, ...) PRINTFLIKE(3,4); +extern void err_sysrem(const char *format, ...) PRINTFLIKE(1,2); +extern void err_sysremark(int errnum, const char *format, ...) PRINTFLIKE(2,3); + +extern int err_getlogopts(void); /* Get default log options */ +extern int err_setlogopts(int new_opts); /* Set default log options */ + +#endif /* STDERR_H */ diff --git a/src/makefile b/src/makefile new file mode 100644 index 00000000..1a48571e --- /dev/null +++ b/src/makefile @@ -0,0 +1,18 @@ +# Makefile for src directory in SOQ project + +include ../etc/soq.mk + +BUILD_DIRECTORIES = \ + lib \ + so-0429-4928 \ + so-3333-8314 \ + so-3388-7484 \ + so-3757-7522 \ + so-3775-3785 \ + so-3799-7620 \ + so-3807-9550 \ + +.DEFAULT all: + +for dir in ${BUILD_DIRECTORIES}; \ + do (echo "+++ $${dir}"; cd "$${dir}" && ${MAKE} $@ && echo "--- $${dir}") \ + done diff --git a/recv.c b/src/so-0429-4928/recv.c similarity index 100% rename from recv.c rename to src/so-0429-4928/recv.c diff --git a/send.c b/src/so-0429-4928/send.c similarity index 100% rename from send.c rename to src/so-0429-4928/send.c diff --git a/sets.c b/src/so-3109-6894/sets.c similarity index 100% rename from sets.c rename to src/so-3109-6894/sets.c diff --git a/sets.h b/src/so-3109-6894/sets.h similarity index 100% rename from sets.h rename to src/so-3109-6894/sets.h diff --git a/src/so-3333-8314/README.md b/src/so-3333-8314/README.md new file mode 100644 index 00000000..f436e8f1 --- /dev/null +++ b/src/so-3333-8314/README.md @@ -0,0 +1,3 @@ +# Stack Overflow Question 3333-8314 + +[SO 33338314](http://stackoverflow.com/q/33338314) triggered this code as partial solutions. diff --git a/src/so-3333-8314/makefile b/src/so-3333-8314/makefile new file mode 100644 index 00000000..3b030902 --- /dev/null +++ b/src/so-3333-8314/makefile @@ -0,0 +1,11 @@ +# SO 3333-8314 + +include ../../etc/soq.mk + +PROG1 = ncm +PROG2 = rotcols + +all: ${PROG1} ${PROG2} + +${PROG1}: ${LIBPATH} +${PROG2}: ${LIBPATH} diff --git a/src/so-3333-8314/ncm.c b/src/so-3333-8314/ncm.c new file mode 100644 index 00000000..1b78a1c2 --- /dev/null +++ b/src/so-3333-8314/ncm.c @@ -0,0 +1,29 @@ +/* SO 33338314 - vignette (see rotcols.c for real code) */ +#include +#include "gcd.h" + +int main(void) +{ + for (int n = 4; n < 13; n++) + { + for (int m = 1; m < n; m++) + { + printf("n = %d, m = %d:\n", n, m); + int c = gcd(n, m); + for (int b = 0; b < c; b++) + { + int x = b; + int s = n / c; + printf(" Cycle %d: ", b+1); + for (int i = 0; i < s; i++) + { + printf("%3d", x); + x = (x + m) % n; + } + putchar('\n'); + } + } + putchar('\n'); + } + return 0; +} diff --git a/src/so-3333-8314/rotcols.c b/src/so-3333-8314/rotcols.c new file mode 100644 index 00000000..6b8d3a97 --- /dev/null +++ b/src/so-3333-8314/rotcols.c @@ -0,0 +1,73 @@ +/* SO 33338314 */ +#include +#include "gcd.h" + +static void dump_matrix(int m, int n, int source[m][n]) +{ + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + printf("%4d", source[i][j]); + putchar('\n'); + } +} + +static void init_matrix(int m, int n, int source[m][n]) +{ + for (int i = 0; i < m; i++) + { + for (int j = 0; j < n; j++) + source[i][j] = (i + 1) * (j + 2); + } +} + +static void rotate_1col(int n, int vector[n], int z) +{ + z %= n; + if (z != 0) + { + int c = gcd(n, z); + int s = n / c; + for (int r = 0; r < c; r++) + { + int x = r; + int t = vector[x]; + for (int i = 0; i < s; i++) + { + int j = (x + z) % n; + int v = vector[j]; + vector[j] = t; + x = j; + t = v; + } + } + } +} + +static void rotate_cols(int m, int n, int source[m][n], int z) +{ + for (int i = 0; i < m; i++) + rotate_1col(n, source[i], z); +} + +int main(void) +{ + int m = 3; + + for (int n = 2; n < 9; n++) + { + int source[m][n]; + for (int z = 0; z <= n; z++) + { + init_matrix(m, n, source); + printf("Initial:\n"); + dump_matrix(m, n, source); + rotate_cols(m, n, source, z); + printf("Post-rotate %d:\n", z); + dump_matrix(m, n, source); + putchar('\n'); + } + } + + return 0; +} diff --git a/so.3775-3785.data b/src/so-3775-3785/so.3775-3785.data similarity index 100% rename from so.3775-3785.data rename to src/so-3775-3785/so.3775-3785.data diff --git a/so.3775-3785.py b/src/so-3775-3785/so.3775-3785.py similarity index 100% rename from so.3775-3785.py rename to src/so-3775-3785/so.3775-3785.py