]> pd.if.org Git - pdutils/commitdiff
Added implementations from pdcore
authorNathan Wagner <nw@hydaspes.if.org>
Sat, 19 Oct 2013 13:51:28 +0000 (13:51 +0000)
committerNathan Wagner <nw@hydaspes.if.org>
Sat, 19 Oct 2013 13:51:28 +0000 (13:51 +0000)
Found implementations of several utilities at
https://github.com/mooseman/pdcore

20 files changed:
utils/cat/cat.1 [new file with mode: 0644]
utils/cat/cat.c [new file with mode: 0644]
utils/cksum/cksum.1 [new file with mode: 0644]
utils/cksum/cksum.c [new file with mode: 0644]
utils/cmp/cmp.1 [new file with mode: 0644]
utils/cmp/cmp.c [new file with mode: 0644]
utils/comm/comm.1 [new file with mode: 0644]
utils/comm/comm.c [new file with mode: 0644]
utils/dirname/dirname.1 [new file with mode: 0644]
utils/dirname/dirname.c [new file with mode: 0644]
utils/false/false.1 [new file with mode: 0644]
utils/false/false.c [new file with mode: 0644]
utils/head/head.1 [new file with mode: 0644]
utils/head/head.c [new file with mode: 0644]
utils/tail/tail.1 [new file with mode: 0644]
utils/tail/tail.c [new file with mode: 0644]
utils/tee/tee.1 [new file with mode: 0644]
utils/tee/tee.c [new file with mode: 0644]
utils/true/true.1 [new file with mode: 0644]
utils/true/true.c [new file with mode: 0644]

diff --git a/utils/cat/cat.1 b/utils/cat/cat.1
new file mode 100644 (file)
index 0000000..d8b6bc8
--- /dev/null
@@ -0,0 +1,36 @@
+.TH CAT 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+cat \- concatenate file(s) to standard output
+.SH SYNOPSIS
+.B cat
+[-u] [file ...]
+.SH DESCRIPTION
+Sequentially read input files and write their contents to standard output.
+.SH OPTIONS
+.TP
+-u
+Fully unbuffered read and write.
+.SH OPERANDS
+.TP
+file
+Input file(s). If none provided, or the filename '-' is passed to cat,
+standard input will be used.
+.SH NOTES
+As files are processed sequentially, beware of shell commands like
+.P
+.RS
+cat x y > x
+.RE
+.P
+which destroy input files before reading them.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/cat.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/cat/cat.c b/utils/cat/cat.c
new file mode 100644 (file)
index 0000000..c109550
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * cat.c - concatenate file(s) to standard output
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o cat cat.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/cat.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define USAGE   "usage: cat [-u] [file ...]\n"
+#define BUFSIZE 4096
+
+static void catfile(int fd, char *fn);
+static void error(char *s);
+
+static int exitstatus;
+static int optu;
+
+
+int main(int argc, char **argv)
+{
+    extern int opterr, optind;
+    int c, fd;
+    char *fn;
+
+    setlocale(LC_ALL, "");
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "u")) != -1)
+        switch (c)
+        {
+        case 'u':
+            optu = 1;
+            break;
+        default:
+            fprintf(stderr, USAGE);
+            return(1);
+        }
+
+    if (optind >= argc)
+        catfile(STDIN_FILENO, "stdin");
+    else
+        while (optind < argc)
+        {
+            fn = argv[optind++];
+
+            if (strcmp(fn, "-") == 0)
+                catfile(STDIN_FILENO, "stdin");
+            else
+                if ((fd = open(fn, O_RDONLY)) == -1)
+                    error(fn);
+                else
+                {
+                    catfile(fd, fn);
+                    if (close(fd) == -1)
+                        error(fn);
+                }
+        }
+
+    return(exitstatus);
+}
+
+
+void catfile(int fd, char *fn)
+{
+    unsigned char buf[BUFSIZE];
+    ssize_t n;
+
+    while ((n = read(fd, buf, (optu ? 1 : BUFSIZE))) > 0)
+        if (write(STDOUT_FILENO, buf, (size_t)n) != n)
+        {
+            error("stdout");
+            break;
+        }
+
+    if (n < 0)
+        error(fn);
+}
+
+
+void error(char *s)
+{
+    fprintf(stderr, "cat: %s: %s\n", s, strerror(errno));
+    exitstatus = 1;
+}
diff --git a/utils/cksum/cksum.1 b/utils/cksum/cksum.1
new file mode 100644 (file)
index 0000000..cd44936
--- /dev/null
@@ -0,0 +1,27 @@
+.TH CKSUM 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+cksum \- report checksum and octet count of file(s)
+.SH SYNOPSIS
+.B cksum
+[file ...]
+.SH DESCRIPTION
+Display CRC check value and octet count of given file(s).
+.SH OPTIONS
+.TP
+None
+.SH OPERANDS
+.TP
+file
+Input file. If none provided, or the filename '-' is passed to cksum,
+standard input will be used.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/cksum.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/cksum/cksum.c b/utils/cksum/cksum.c
new file mode 100644 (file)
index 0000000..daba540
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * cksum - report checksum and octet count of file(s)
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o cksum cksum.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/cksum.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <locale.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define BUFSIZE 4096
+
+static void cksumfile(int fd, char *fn);
+static void error(char *s);
+
+static int exitstatus;
+
+
+int main(int argc, char **argv)
+{
+    int i, fd, hasrun = 0;
+    char *fn;
+
+    setlocale(LC_ALL, "");
+
+    for (i = 1; i < argc; i++)
+    {
+        fn = argv[i];
+
+        if (strcmp(fn, "--") == 0)
+            continue;
+        else
+        {
+            hasrun = 1;
+
+            if (strcmp(fn, "-") == 0)
+                cksumfile(STDIN_FILENO, "stdin");
+            else
+                if ((fd = open(fn, O_RDONLY)) == -1)
+                    error(fn);
+                else
+                {
+                    cksumfile(fd, fn);
+                    if (close(fd) == -1)
+                        error(fn);
+                }
+        }
+    }
+
+    if (! hasrun)
+        cksumfile(STDIN_FILENO, "stdin");
+
+    return(exitstatus);
+}
+
+
+void cksumfile(int fd, char *fn)
+{
+    unsigned char buf[BUFSIZE];
+    ssize_t cnt, n;
+    uint32_t crctab[256], crc, i;
+    int j;
+
+    for (i = 0; i < 256; ++i)
+    {
+        for (crc = i << 24, j = 0; j < 8; j++)
+            crc = (crc << 1) ^ (crc & 0x80000000 ? 0x04c11db7 : 0);
+        crctab[i] = crc;
+    }
+
+    cnt = crc = 0;
+
+    while ((n = read(fd, buf, BUFSIZE)) > 0)
+    {
+        cnt += n;
+
+        for (i = 0; i < (size_t)n; i++)
+            crc = crctab[((crc >> 24) ^ buf[i]) & 0xFF] ^ (crc << 8);
+    }
+
+    if (n < 0)
+        error(fn);
+    else
+    {
+        for (i = cnt; i != 0; i >>= 8)
+            crc = crctab[((crc >> 24) ^ i) & 0xFF] ^ (crc << 8);
+
+        printf("%lu %lu", (unsigned long)~crc, (unsigned long)cnt);
+        if (fd != STDIN_FILENO)
+            printf(" %s", fn);
+        printf("\n");
+    }
+}
+
+
+void error(char *s)
+{
+    fprintf(stderr, "cksum: %s: %s\n", s, strerror(errno));
+    exitstatus = 1;
+}
diff --git a/utils/cmp/cmp.1 b/utils/cmp/cmp.1
new file mode 100644 (file)
index 0000000..b7e9081
--- /dev/null
@@ -0,0 +1,37 @@
+.TH CMP 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+cmp \- compare two files
+.SH SYNOPSIS
+.B cmp
+[-l|-s] file1 file2
+.SH DESCRIPTION
+Compare two files. If the contents are the same, produce no output and return
+an exit status of 0. If they differ, report the line and byte position of the
+first difference, and return an exit status of 1. An exit status of 2 will be
+returned in the event of any error.
+.SH OPTIONS
+.TP
+-l
+List all differences, not just the first.
+.TP
+-s
+Silent. No output under any circumstances; returns exit status only.
+.P
+Note that options -l and -s are mutually exclusive.
+.SH OPERANDS
+.TP
+file1, file2
+Input files. If none provided, or the filename '-' is passed to cmp, standard
+input will be used. Note that standard input may only be used for one of the
+file inputs.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/cmp.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/cmp/cmp.c b/utils/cmp/cmp.c
new file mode 100644 (file)
index 0000000..a1c0572
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * cmp.c - compare two files
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o cmp cmp.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/cmp.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define USAGE      "usage: cmp [-l|-s] file1 file2\n"
+#define ELSMUTEXCL "Options -l and -s are mutually exclusive"
+#define EBOTHSTDIN "Input files must be different"
+#define BUFSIZE    4096
+#define SYSERR     1
+#define APPERR     0
+
+static int cmpfiles(int fd1, char *fn1, int fd2, char *fn2);
+static void fatal(int errtype, char *s);
+
+static int optl, opts;
+
+
+int main(int argc, char **argv)
+{
+    extern int opterr, optind;
+    int c, exitstatus = 0;
+    int fd1, fd2;
+    char *fn1, *fn2;
+
+    setlocale(LC_ALL, "");
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "ls")) != -1)
+        switch (c)
+        {
+        case 'l':
+            optl = 1;
+            break;
+        case 's':
+            opts = 1;
+            break;
+        default:
+            fprintf(stderr, USAGE);
+            exit(2);
+        }
+
+    argc -= optind;
+    argv += optind;
+
+    if (optl && opts)
+        fatal(APPERR, ELSMUTEXCL);
+
+    if (argc != 2)
+        fatal(APPERR, USAGE);
+
+    fn1 = argv[0];
+    if (strcmp(fn1, "-") == 0)
+        fd1 = STDIN_FILENO;
+    else
+        if ((fd1 = open(fn1, O_RDONLY)) == -1)
+            fatal(SYSERR, fn1);
+
+    fn2 = argv[1];
+    if (strcmp(fn2, "-") == 0)
+        fd2 = STDIN_FILENO;
+    else
+        if ((fd2 = open(fn2, O_RDONLY)) == -1)
+            fatal(SYSERR, fn2);
+
+    if (fd1 == STDIN_FILENO && fd2 == STDIN_FILENO)
+        fatal(APPERR, EBOTHSTDIN);
+
+    exitstatus = cmpfiles(fd1, fn1, fd2, fn2);
+
+    if (fd1 != STDIN_FILENO && (close(fd1) == -1))
+        fatal(SYSERR, fn1);
+
+    if (fd2 != STDIN_FILENO && (close(fd2) == -1))
+        fatal(SYSERR, fn2);
+
+    return(exitstatus);
+}
+
+
+int cmpfiles(int fd1, char *fn1, int fd2, char *fn2)
+{
+    unsigned char buf1[BUFSIZE], buf2[BUFSIZE];
+    ssize_t n1, n2, byte = 1, line = 1;
+    int cnt, i, eof = 0, differ = 0, shorter = 0;
+
+    while (! eof)
+    {
+        if ((n1 = read(fd1, buf1, BUFSIZE)) == -1)
+            fatal(SYSERR, fn1);
+
+        if ((n2 = read(fd2, buf2, BUFSIZE)) == -1)
+            fatal(SYSERR, fn2);
+
+        if (n1 != BUFSIZE || n2 != BUFSIZE)
+        {
+            eof = 1;
+            if (n1 != n2)
+                shorter = (n1 < n2) ? 1 : 2;
+        }
+
+        cnt = (n1 < n2) ? n1 : n2;
+        for (i = 0; i < cnt; i++)
+        {
+            if (buf1[i] != buf2[i])
+            {
+                if (! differ && ! optl && ! opts)
+                {
+                    printf("%s %s differ: char %d, line %d\n", fn1, fn2, byte, line);
+                    return(1);  /* only need to report first mismatch */
+                }
+
+                differ = 1;
+
+                if (optl)
+                    printf("%d %o %o\n", byte, buf1[i], buf2[i]);
+            }
+
+            byte++;
+            if (buf1[i] == '\n')
+                line++;
+        }
+    }
+
+    if (shorter && (optl || (! opts && ! differ)))
+    {
+        differ = 1;
+        fprintf(stderr, "cmp: EOF on %s\n", (shorter == 1 ? fn1 : fn2));
+    }
+
+    return(differ || shorter);
+}
+
+
+void fatal(int errtype, char *s)
+{
+    if (errtype == SYSERR)
+        fprintf(stderr, "cmp: %s: %s\n", s, strerror(errno));
+    else
+        fprintf(stderr, "cmp: %s\n", s);
+
+    exit(2);
+}
diff --git a/utils/comm/comm.1 b/utils/comm/comm.1
new file mode 100644 (file)
index 0000000..db37d1d
--- /dev/null
@@ -0,0 +1,37 @@
+.TH COMM 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+comm \- select or reject lines common to two files
+.SH SYNOPSIS
+.B comm
+[-123] file1 file2
+.SH DESCRIPTION
+Read 'file1' and 'file2', both of which should be ordered in the current
+collating sequence, and produce three text columns as output: lines unique
+to 'file1', lines unique to 'file2', and lines common to both files.
+.SH OPTIONS
+.TP
+-1
+Suppress output of column one (lines unique to 'file1').
+.TP
+-2
+Suppress output of column two (lines unique to 'file2').
+.TP
+-3
+Suppress output of column three (lines common to both files).
+.P
+.SH OPERANDS
+.TP
+file1, file2
+Input files. If none provided, or the filename '-' is passed to comm,
+standard input will be used.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/comm.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/comm/comm.c b/utils/comm/comm.c
new file mode 100644 (file)
index 0000000..72aba31
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * comm.c - select or reject lines common to two files
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o comm comm.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/comm.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define USAGE     "usage: comm [-123] file1 file2\n"
+#define ENOMALLOC "Unable to allocate memory for read buffer"
+#define BUFSIZE   4096
+#define LINESIZE  64
+#define SYSERR    1
+#define APPERR    0
+
+typedef struct { int     fd;
+                 char   *fn;
+                 int     eof;
+                 char    buf[BUFSIZE];
+                 size_t  bufpos;
+                 size_t  eobuf;
+                 char   *line;
+                 size_t  linesz;
+               } FINFO;
+
+static void initfile(FINFO *file, char *fn);
+static void cleanup(FINFO *file);
+static void commfiles(FINFO *file1, FINFO *file2);
+static int getline(FINFO *file);
+static void fillbuf(FINFO *file);
+static void fatal(int errtype, char *s);
+
+static int opt1, opt2, opt3;
+
+
+int main(int argc, char **argv)
+{
+    extern int optind, opterr;
+    int c;
+    FINFO file1, file2;
+
+    setlocale(LC_ALL, "");
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "123")) != -1)
+        switch (c)
+        {
+        case '1':
+            opt1 = 1;
+            break;
+        case '2':
+            opt2 = 1;
+            break;
+        case '3':
+            opt3 = 1;
+            break;
+        default:
+            fprintf(stderr, USAGE);
+            exit(1);
+        }
+
+    argc -= optind;
+    argv += optind;
+
+    if (argc != 2)
+        fatal(APPERR, USAGE);
+
+    initfile(&file1, argv[0]);
+    initfile(&file2, argv[1]);
+
+    commfiles(&file1, &file2);
+
+    cleanup(&file1);
+    cleanup(&file2);
+
+    return(0);
+}
+
+
+void initfile(FINFO *file, char *fn)
+{
+    int fd;
+
+    if (strcmp(fn, "-") == 0)
+        fd = STDIN_FILENO;
+    else
+        if ((fd = open(fn, O_RDONLY)) == -1)
+            fatal(SYSERR, fn);
+
+    file->fd     = fd;
+    file->fn     = fn;
+    file->eof    = 0;
+    file->bufpos = 0;
+    file->eobuf  = 0;
+    file->linesz = LINESIZE;
+
+    if ((file->line = malloc(file->linesz)) == NULL)
+        fatal(APPERR, ENOMALLOC);
+}
+
+
+void cleanup(FINFO *file)
+{
+    free(file->line);
+
+    if (strcmp(file->fn, "-") != 0 && close(file->fd) == -1)
+        fatal(SYSERR, file->fn);
+}
+
+
+void commfiles(FINFO *file1, FINFO *file2)
+{
+    int cmp;
+
+    if (getline(file1) && getline(file2))
+        while(1)
+        {
+            cmp = strcoll(file1->line, file2->line);
+
+            if (cmp == 0)
+            {
+                if (! opt3)
+                    printf("%s%s%s\n", (opt1 ? "" : "\t"), (opt2 ? "" : "\t"), file1->line);
+
+                if ((getline(file1) + getline(file2)) < 2)
+                    break;
+            }
+
+            else if (cmp > 0)
+            {
+                if (! opt2)
+                    printf("%s%s\n", (opt1 ? "" : "\t"), file2->line);
+
+                if (! getline(file2))
+                    break;
+            }
+
+            else   /* cmp < 0 */
+            {
+                if (! opt1)
+                    printf("%s\n", file1->line);
+
+                if (! getline(file1))
+                    break;
+            }
+        }
+
+    while(! file1->eof && ! opt1)
+    {
+        printf("%s\n", file1->line);
+        getline(file1);
+    }
+
+    while(! file2->eof && ! opt2)
+    {
+        printf("%s%s\n", (opt1 ? "" : "\t"), file2->line);
+        getline(file2);
+    }
+}
+
+
+int getline(FINFO *file)
+{
+    int success = 0;
+    size_t i = 0;
+
+    if (! file->eof)
+    {
+        while(1)
+        {
+            if (i == file->linesz)
+            {
+                file->linesz = file->linesz + LINESIZE;
+                if ((file->line = realloc(file->line, file->linesz)) == NULL)
+                    fatal(APPERR, ENOMALLOC);
+            }
+
+            if (file->bufpos >= file->eobuf)
+            {
+                fillbuf(file);
+                if (file->eof)
+                {
+                    if (i > 0)
+                    {
+                        file->line[i] = '\0';
+                        success = 1;
+                    }
+                    break;
+                }
+            }
+
+            if (file->buf[file->bufpos] == '\n')
+            {
+                file->bufpos++;
+                file->line[i] = '\0';
+                success = 1;
+                break;
+            }
+            else
+                file->line[i++] = file->buf[file->bufpos++];
+        }
+    }
+
+    return(success);
+}
+
+
+void fillbuf(FINFO *file)
+{
+    ssize_t n;
+
+    if (! file->eof)
+    {
+        if ((n = read(file->fd, file->buf, BUFSIZE)) < 0)
+            fatal(SYSERR, file->fn);
+
+        if (n == 0)
+            file->eof = 1;
+        else
+        {
+            file->bufpos = 0;
+            file->eobuf  = n;
+        }
+    }
+}
+
+
+void fatal(int errtype, char *s)
+{
+    if (errtype == SYSERR)
+        fprintf(stderr, "comm: %s: %s\n", s, strerror(errno));
+    else
+        fprintf(stderr, "comm: %s\n", s);
+
+    exit(1);
+}
diff --git a/utils/dirname/dirname.1 b/utils/dirname/dirname.1
new file mode 100644 (file)
index 0000000..f7230e4
--- /dev/null
@@ -0,0 +1,26 @@
+.TH DIRNAME 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+dirname \- return the directory portion of a pathname
+.SH SYNOPSIS
+.B dirname
+string
+.SH DESCRIPTION
+Return the directory portion of a path/filename string.
+.SH OPTIONS
+.TP
+None
+.SH OPERANDS
+.TP
+string
+Input pathname
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/dirname.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/dirname/dirname.c b/utils/dirname/dirname.c
new file mode 100644 (file)
index 0000000..c490a56
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * dirname.c - return the directory portion of a pathname
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o dirname dirname.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/dirname.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <locale.h>
+#include <stdio.h>
+
+#define USAGE "usage: dirname string\n"
+
+
+int main(int argc, char **argv)
+{
+    char *head, *tail;
+
+    setlocale (LC_ALL, "");
+
+    if (argc != 2)
+    {
+        fprintf(stderr, USAGE);
+        return(1);
+    }
+
+    head = tail = argv[1];
+    while (*tail)
+        tail++;
+
+    while (tail > head && tail[-1] == '/')
+        tail--;
+    while (tail > head && tail[-1] != '/')
+        tail--;
+    while (tail > head && tail[-1] == '/')
+        tail--;
+
+    if (head == tail)
+        printf(*head == '/' ? "/\n" : ".\n");
+    else
+        printf("%.*s\n", (tail - head), head);
+
+    return(0);
+}
diff --git a/utils/false/false.1 b/utils/false/false.1
new file mode 100644 (file)
index 0000000..439608f
--- /dev/null
@@ -0,0 +1,24 @@
+.TH FALSE 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+false \- return false value
+.SH SYNOPSIS
+.B true
+.SH DESCRIPTION
+Return with a non-zero exit status.
+.SH OPTIONS
+.TP
+None
+.SH OPERANDS
+.TP
+None
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/false.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/false/false.c b/utils/false/false.c
new file mode 100644 (file)
index 0000000..49ed57c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * false.c - return false value
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o false false.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/false.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+
+int main(void)
+{
+    return(1);
+}
diff --git a/utils/head/head.1 b/utils/head/head.1
new file mode 100644 (file)
index 0000000..9869db0
--- /dev/null
@@ -0,0 +1,33 @@
+.TH HEAD 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+head \- copy the first part of files
+.SH SYNOPSIS
+.B head
+[-n number] [file ...]
+.SH DESCRIPTION
+Copy the first 'number' lines of the input files to standard output.
+.SH OPTIONS
+.TP
+-n number
+Where 'number' is a positive integer indicating the number of lines to copy.
+If omitted, head will default to copying the first 10 lines of input.
+.SH OPERANDS
+.TP
+file
+Input file(s). If none provided, or the filename '-' is passed to head,
+standard input will be used.
+.SH NOTES
+Prior versions of head allowed '-x' as an option, with 'x' representing
+the number of lines to be copied. The equivalent acceptable syntax is
+now '-n x'.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/head.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/head/head.c b/utils/head/head.c
new file mode 100644 (file)
index 0000000..bf83ab3
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * head.c - copy the first part of files
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o head head.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/head.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define USAGE   "usage: head [-n number] [file ...]\n"
+#define BUFSIZE 4096
+
+static long ctol(char *s);
+static void headfile(int fd, char *fn, int lines);
+static void error(char *s);
+
+static int exitstatus;
+
+
+int main(int argc, char **argv)
+{
+    extern int opterr, optind;
+    extern char *optarg;
+    int c, fd, many, first;
+    char *fn;
+    long lines = 10;
+
+    setlocale(LC_ALL, "");
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "n:")) != -1)
+        switch (c)
+        {
+        case 'n':
+            if (*optarg && (lines = ctol(optarg)) > 0)
+                break;
+            /* else fall through */
+        default:
+            fprintf(stderr, USAGE);
+            exit(1);
+        }
+
+    if (optind >= argc)
+        headfile(STDIN_FILENO, "stdin", lines);
+    else
+    {
+        many  = (optind + 1 < argc) ? 1 : 0;
+        first = 1;
+
+        while (optind < argc)
+        {
+            fn = argv[optind++];
+
+            if (many)
+            {
+                if (first)
+                    first = 0;
+                else
+                    printf("\n");
+                printf("==> %s <==\n", fn);
+            }
+
+            if (strcmp(fn, "-") == 0)
+                headfile(STDIN_FILENO, "stdin", lines);
+            else
+                if ((fd = open(fn, O_RDONLY)) == -1)
+                    error(fn);
+                else
+                {
+                    headfile(fd, fn, lines);
+                    if (close(fd) == -1)
+                        error(fn);
+                }
+        }
+    }
+
+    return(exitstatus);
+}
+
+
+long ctol(char *s)
+{
+    int badch = 0;
+    char *c = s;
+
+    /* only copes with non-zero, optionally signed, */
+    /* decimal integers; that's all we need         */
+    if (! (isdigit(*c) || *c == '+' || *c == '-'))
+        badch = 1;
+    else
+        for (c++; *c; c++)
+            if (! isdigit(*c))
+                badch = 1;
+
+    return (badch ? 0 : atol(s));
+}
+
+
+void headfile(int fd, char *fn, int lines)
+{
+    unsigned char buf[BUFSIZE], *c;
+    ssize_t n, o;
+
+    while (lines)
+    {
+        if ((n = read(fd, buf, BUFSIZE)) <= 0)
+            break;
+
+        for (c = buf; lines && c < (buf + n); c++)
+            if (*c == '\n')
+                lines--;
+
+        o = lines ? n : c - buf;
+        if (write(STDOUT_FILENO, buf, (size_t)o) != o)
+        {
+            error("stdout");
+            break;
+        }
+    }
+
+    if (n < 0)
+        error(fn);
+}
+
+
+void error(char *s)
+{
+    fprintf(stderr, "head: %s: %s\n", s, strerror(errno));
+    exitstatus = 1;
+}
diff --git a/utils/tail/tail.1 b/utils/tail/tail.1
new file mode 100644 (file)
index 0000000..1299399
--- /dev/null
@@ -0,0 +1,54 @@
+.TH TAIL 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+tail \- copy the last part of a file
+.SH SYNOPSIS
+.B tail
+[-f] [-c number | -n number] [file]
+.SH DESCRIPTION
+Copy the input file to standard output, starting from a specified location.
+.SH OPTIONS
+.TP
+-f
+Follow the file; keep updating tail's output as the input file grows. Note that
+this option is only available for regular files and FIFOs that are named as
+the 'file' operand, and will be ignored for other inputs (such as unnamed
+pipes).
+.TP
+-c number
+Byte offset of the input file at which output will commence.
+.TP
+-n number
+Line offset of the input file at which output will commence.
+.P
+Byte and line offsets commence at the value 1. If 'number' includes a
+leading '+', the offset is from the start of the input file. If 'number'
+includes a leading '-' or has no prefix, it indicates that the desired
+offset is backwards from the end of the input file.
+.P
+For example, '-n +3' will output the contents of the input file commencing from
+the third line; '-c 20' or '-c -20' starts output twenty bytes prior to the end
+of the input file.
+.P
+For byte offsets, a 'number' value of zero is not permitted. For line offsets,
+the POSIX standard states that the option '-n 0' is valid, but outputs nothing,
+whilst '-n +0' is invalid.
+.P
+Options '-c' and '-n' are mutually exclusive. If neither is specified,
+the default behaviour of tail is to output the last ten lines of the input
+file, as if it had been invoked with the option '-n 10'.
+.SH OPERANDS
+.TP
+file
+Input file. If none provided, or the filename '-' is passed to tail,
+standard input will be used.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/tail.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/tail/tail.c b/utils/tail/tail.c
new file mode 100644 (file)
index 0000000..5fa8849
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ * tail.c - copy the last part of a file
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o tail tail.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/tail.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define USAGE     "usage: tail [-f] [-c number] [-n number] [file]\n"
+#define NOMALLOC  "Unable to allocate memory for read buffer"
+#define NOFOLLOW  "tail: Option [-f] ignored; can only follow regular files and FIFOs\n"
+#define BADBYTES  "Option [-c] requires non-zero byte offset"
+#define BADLINES  "Option [-n] requires integer line offset"
+#define CNMUTEXCL "Options [-c] and [-n] are mutually exclusive"
+#define FVANISH   "Followed file has vanished"
+#define FSHRUNK   "Followed file has shrunk"
+#define SYSERR    1
+#define APPERR    0
+
+static int isdecint(char *s);
+static void tailfile(int fd, char *fn);
+static void tailbyteoffset(int fd, char *fn, int isregfile, ssize_t len);
+static void taillineoffset(int fd, char *fn, int isregfile, ssize_t len);
+static void copytoeof(int fd, char *fn);
+static void fatal(int errtype, char *s);
+
+static unsigned char* buf;
+static ssize_t bufsize, offset;
+static int optf, optc, optn;
+
+
+int main(int argc, char **argv)
+{
+    extern int opterr, optind;
+    extern char *optarg;
+    int c, fd;
+    char *fn;
+
+    setlocale(LC_ALL, "");
+    opterr = 0;
+
+    /*
+     * try to get a buffer _twice_ the size mandated by the standard as in
+     * later processing we may be paging through the file in _half_ buffer
+     * increments; this way we guarentee POSIX buffer size conformance
+     */
+    bufsize = sysconf(_SC_LINE_MAX) * 20;   /* POSIX says [{LINE_MAX)*10] */
+    bufsize = bufsize < 4096 ? 4096 : bufsize;
+
+    if ((buf = malloc(bufsize)) == NULL)
+        fatal(APPERR, NOMALLOC);
+
+    while ((c = getopt(argc, argv, "fc:n:")) != -1)
+        switch (c)
+        {
+        case 'f':   /* follow file */
+            optf = 1;
+            break;
+
+        case 'c':   /* offset in bytes */
+            optc = 1;
+            offset = 0;
+            if (*optarg && isdecint(optarg))
+            {
+                offset = atol(optarg);
+                offset = isdigit(*optarg) ? -offset : offset;
+            }
+
+            if (offset == 0)
+                fatal(APPERR, BADBYTES);
+            else
+                break;
+
+        case 'n':   /* offset in lines */
+            optn = 1;
+            if (*optarg && isdecint(optarg))
+            {
+                offset = atol(optarg);
+                offset = isdigit(*optarg) ? -offset : offset;
+
+                /* the standard says [-n 0] is OK, but [-n +0] isn't &_& */
+                if (offset != 0 || (offset == 0 && *optarg != '+'))
+                    break;
+            }
+            fatal(APPERR, BADLINES);
+
+        default:
+            fprintf(stderr, USAGE);
+            exit(1);
+        }
+
+    if (! optc && ! optn)   /* if none, set the default options */
+    {
+        optn = 1;
+        offset = -10;
+    }
+
+    if (optc && optn)
+        fatal(APPERR, CNMUTEXCL);
+
+    if (optind >= argc)
+        tailfile(STDIN_FILENO, "stdin");
+    else
+    {
+        fn = argv[optind++];
+
+        if (strcmp(fn, "-") == 0)
+            tailfile(STDIN_FILENO, "stdin");
+        else
+            if ((fd = open(fn, O_RDONLY)) == -1)
+                fatal(SYSERR, fn);
+            else
+            {
+                tailfile(fd, fn);
+                if (close(fd) == -1)
+                    fatal(SYSERR, fn);
+            }
+    }
+
+    return(0);
+}
+
+
+int isdecint(char *s)
+{
+    int badch = 0;
+    char *c = s;
+
+    if (! (isdigit(*c) || *c == '+' || *c == '-'))
+        badch = 1;
+    else
+        for (c++; *c; c++)
+            if (! isdigit(*c))
+                badch = 1;
+
+    return (! badch);
+}
+
+
+void tailfile(int fd, char *fn)
+{
+    struct stat sbuf;
+    int isregfile;
+    ssize_t n, len;
+
+    if (fstat(fd, &sbuf) == -1)
+        fatal(SYSERR, fn);
+
+    if (S_ISREG(sbuf.st_mode))
+    {
+        isregfile = 1;
+        len = sbuf.st_size;
+    }
+    else
+        isregfile = len = 0;
+
+    if (offset != 0)   /* [-n 0] is permitted; but no point processing that */
+    {
+        if (optc)
+            tailbyteoffset(fd, fn, isregfile, len);
+        else
+            taillineoffset(fd, fn, isregfile, len);
+    }
+
+    if (optf)
+    {
+        if (fd == STDIN_FILENO)   /* can't follow; warn then exit no error */
+        {
+            fprintf(stderr, NOFOLLOW);
+            exit(0);
+        }
+
+        while(1)   /* follow forever */
+        {
+            sleep(1);
+
+            if (isregfile)   /* if we can, be polite to the user */
+            {
+                if (stat(fn, &sbuf) == -1)
+                    fatal(APPERR, FVANISH);
+                else if (sbuf.st_size < len)
+                    fatal(APPERR, FSHRUNK);
+
+                len = sbuf.st_size;
+            }
+
+            while ((n = read(fd, buf, bufsize)) > 0)
+                if (write(STDOUT_FILENO, buf, n) != n)
+                    fatal(SYSERR, "stdout");
+
+            if (n < 0)
+                fatal(SYSERR, fn);
+        }
+    }
+}
+
+
+void tailbyteoffset(int fd, char *fn, int isregfile, ssize_t len)
+{
+    ssize_t n, halfbuf;
+
+    if (isregfile)   /* should be seekable, so we'll do so; it's fastest */
+    {
+        if (offset > 0)
+            offset = (offset - 1) > len ? len : offset - 1;
+        else
+            offset = (len + offset) > 0 ? len + offset : 0;
+
+        if (lseek(fd, (off_t)offset, SEEK_SET) == (off_t)-1)
+            fatal(SYSERR, fn);
+
+        copytoeof(fd, fn);
+    }
+
+    else   /* possibly non-seekable */
+    {
+        if (offset > 0)   /* forwards through file */
+        {
+            offset--;
+
+            while(1)
+            {
+                if ((n = read(fd, buf, bufsize)) < 0)
+                    fatal(SYSERR, fn);
+
+                if (n == 0)
+                    offset = 0;
+
+                if (offset <= n)
+                    break;
+                else
+                    offset -= n;
+            }
+
+            if (write(STDOUT_FILENO, buf + offset, n - offset) != n - offset)
+                fatal(SYSERR, "stdout");
+
+            copytoeof(fd, fn);
+        }
+
+        else   /* backwards through file; remember that offset is negative */
+        {
+            halfbuf = bufsize / 2;
+
+            if ((n = read(fd, buf, bufsize)) < 0)
+                fatal(SYSERR, fn);
+
+            if (n < bufsize)   /* we've got the whole file */
+            {
+                offset = (n + offset) < 0 ? 0 : n + offset;
+                len = n - offset;
+            }
+
+            else   /* we haven't got the whole file */
+            {
+                while(1)   /* page through the file, half a buffer at a time */
+                {
+                    memcpy(buf, buf + halfbuf, halfbuf);
+
+                    if ((n = read(fd, buf + halfbuf, halfbuf)) < 0)
+                        fatal(SYSERR, fn);
+                    else if (n < halfbuf)
+                        break;
+                }
+
+                offset = (halfbuf + n + offset) < 0 ? 0 : halfbuf + n + offset;
+                len = halfbuf + n - offset;
+            }
+
+            if (write(STDOUT_FILENO, buf + offset, len) != len)
+                fatal(SYSERR, "stdout");
+        }
+    }
+}
+
+
+void taillineoffset(int fd, char *fn, int isregfile, ssize_t len)
+{
+    ssize_t n, i, halfbuf;
+
+    if (offset > 0)   /* forwards through file */
+    {
+        offset--;
+
+        while(1)
+        {
+            if ((n = read(fd, buf, bufsize)) < 0)
+                fatal(SYSERR, fn);
+
+            if (n == 0)
+            {
+                offset = 0;
+                break;
+            }
+
+            for (i = 0; i < n && offset > 0; i++)
+                if (buf[i] == '\n')
+                    offset--;
+
+            if (offset == 0)
+            {
+                offset = i;
+                break;
+            }
+        }
+
+        if (write(STDOUT_FILENO, buf + offset, n - offset) != n - offset)
+            fatal(SYSERR, "stdout");
+
+        copytoeof(fd, fn);
+    }
+
+    else   /* backwards through file; remember that offset is negative */
+    {
+        if (isregfile && len > 0)   /* should be seekable, so we'll do so */
+        {
+            n = (len - bufsize) < 0 ? 0 : len - bufsize;
+
+            if (lseek(fd, (off_t)n, SEEK_SET) == (off_t)-1)
+                fatal(SYSERR, fn);
+
+            if ((n = read(fd, buf, bufsize)) < 0)
+                fatal(SYSERR, fn);
+
+            if (buf[n-1] == '\n')
+                offset--;
+
+            for (i = n - 1; i >= 0 && offset < 0; i--)
+                if (buf[i] == '\n')
+                    offset++;
+
+            if (offset == 0)
+                offset = i + 2;
+            else
+                offset = 0;
+
+            len = n - offset;
+
+            if (write(STDOUT_FILENO, buf + offset, len) != len)
+                fatal(SYSERR, "stdout");
+        }
+
+        else
+        {
+            halfbuf = bufsize / 2;
+
+            if ((n = read(fd, buf, bufsize)) < 0)
+                fatal(SYSERR, fn);
+
+            if (n < bufsize)   /* we've got the whole file */
+            {
+                if (n == 0)
+                    offset = 0;
+                else
+                {
+                    if (buf[n-1] == '\n')
+                        offset--;
+
+                    for (i = n - 1; i >= 0 && offset < 0; i--)
+                        if (buf[i] == '\n')
+                            offset++;
+
+                    if (offset == 0)
+                        offset = i + 2;
+                    else
+                        offset = 0;
+                }
+
+                len = n - offset;
+            }
+
+            else   /* we haven't got the whole file */
+            {
+                while(1)   /* page through the file, half a buffer at a time */
+                {
+                    memcpy(buf, buf + halfbuf, halfbuf);
+
+                    if ((n = read(fd, buf + halfbuf, halfbuf)) < 0)
+                        fatal(SYSERR, fn);
+                    else if (n < halfbuf)
+                        break;
+                }
+
+                if (buf[halfbuf+n-1] == '\n')
+                    offset--;
+
+                for (i = halfbuf + n - 1; i >= 0 && offset < 0; i--)
+                    if (buf[i] == '\n')
+                        offset++;
+
+                if (offset == 0)
+                    offset = i + 2;
+                else
+                    offset = 0;
+
+                len = halfbuf + n - offset;
+            }
+
+            if (write(STDOUT_FILENO, buf + offset, len) != len)
+                fatal(SYSERR, "stdout");
+        }
+    }
+}
+
+
+void copytoeof(int fd, char *fn)
+{
+    ssize_t n;
+
+    while ((n = read(fd, buf, bufsize)) > 0)
+        if (write(STDOUT_FILENO, buf, n) != n)
+            fatal(SYSERR, "stdout");
+
+    if (n < 0)
+        fatal(SYSERR, fn);
+}
+
+
+void fatal(int errtype, char *s)
+{
+    if (errtype == SYSERR)
+        fprintf(stderr, "tail: %s: %s\n", s, strerror(errno));
+    else
+        fprintf(stderr, "tail: %s\n", s);
+
+    exit(1);
+}
diff --git a/utils/tee/tee.1 b/utils/tee/tee.1
new file mode 100644 (file)
index 0000000..2c13d79
--- /dev/null
@@ -0,0 +1,30 @@
+.TH TEE 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+tee \- duplicate standard input
+.SH SYNOPSIS
+.B tee
+[-ai] [file ...]
+.SH DESCRIPTION
+Copy standard input to standard output and any other named files.
+.SH OPTIONS
+.TP
+-a
+Append output to existing files rather than overwriting them.
+.TP
+-i
+Ignore the SIGINT signal.
+.SH OPERANDS
+.TP
+file
+File(s) to duplicate standard input into.
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/tee.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/tee/tee.c b/utils/tee/tee.c
new file mode 100644 (file)
index 0000000..9b6d4cb
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * tee.c - duplicate standard input
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o tee tee.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/tee.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define USAGE    "usage: tee [-ai] [file ...]\n"
+#define AMBIGOPT "tee: Ambiguous [-]; operand or bad option?\n"
+#define FLIMIT   "tee: Maximum of %d output files exceeded\n"
+#define BUFSIZE  4096
+#define MAXFILES 13
+
+static void error(char *s);
+
+static int exitstatus;
+
+
+int main(int argc, char **argv)
+{
+    extern int opterr, optind;
+    int c, i;
+    unsigned char buf[BUFSIZE];
+    ssize_t n;
+    int slot, fdfn[MAXFILES + 1][2], mode = O_WRONLY | O_CREAT | O_TRUNC;
+
+    setlocale(LC_ALL, "");
+    opterr = 0;
+
+    while ((c = getopt(argc, argv, "ai")) != -1)
+        switch (c)
+        {
+        case 'a':   /* append to rather than overwrite file(s) */
+            mode = O_WRONLY | O_CREAT | O_APPEND;
+            break;
+
+        case 'i':   /* ignore the SIGINT signal */
+            signal(SIGINT, SIG_IGN);
+            break;
+
+        default:
+            fprintf(stderr, USAGE);
+            return(1);
+        }
+
+    i = optind;
+    fdfn[0][0] = STDOUT_FILENO;
+
+    for (slot = 1; i < argc ; i++)
+    {
+        if (slot > MAXFILES)
+            fprintf(stderr, FLIMIT, MAXFILES);
+        else
+        {
+            if ((fdfn[slot][0] = open(argv[i], mode, 0666)) == -1)
+                error(argv[i]);
+            else
+                fdfn[slot++][1] = i;
+        }
+    }
+
+    while ((n = read(STDIN_FILENO, buf, BUFSIZE)) > 0)
+    {
+        for (i = 0; i < slot; i++)
+            if (write(fdfn[i][0], buf, (size_t)n) != n)
+                error(argv[fdfn[i][1]]);
+    }
+
+    if (n < 0)
+        error("stdin");
+
+    for (i = 1; i < slot; i++)
+        if (close(fdfn[i][0]) == -1)
+            error(argv[fdfn[i][1]]);
+
+    return(exitstatus);
+}
+
+
+void error(char *s)
+{
+    fprintf(stderr, "tee: %s: %s\n", s, strerror(errno));
+    exitstatus = 1;
+}
diff --git a/utils/true/true.1 b/utils/true/true.1
new file mode 100644 (file)
index 0000000..570117c
--- /dev/null
@@ -0,0 +1,24 @@
+.TH TRUE 1 "2008-1.01" "pdcore utilities" "User Commands"
+.SH NAME
+true \- return true value
+.SH SYNOPSIS
+.B true
+.SH DESCRIPTION
+Return with an exit status of zero.
+.SH OPTIONS
+.TP
+None
+.SH OPERANDS
+.TP
+None
+.SH "AUTHORITATIVE DOCUMENTATION"
+<http://www.opengroup.org/onlinepubs/9699919799/utilities/true.html>
+.SH VERSION AND COMPLIANCE
+Utility version 1.01
+.P
+Functional compliance with POSIX:2008 (IEEE Std 1003.1-2008;
+Shell and Utilities, Base Specifications Issue 7).
+.SH UNLICENSE
+This is free and unencumbered software released into the public domain,
+provided "as is", without warranty of any kind, express or implied. See the
+file UNLICENSE and the website <http://unlicense.org> for further details.
diff --git a/utils/true/true.c b/utils/true/true.c
new file mode 100644 (file)
index 0000000..23afd93
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * true.c - return true value
+ *
+ * Version: 2008-1.01
+ * Build:   c89 -o true true.c
+ * Source:  <http://pdcore.sourceforge.net/>
+ * Spec:    <http://www.opengroup.org/onlinepubs/9699919799/utilities/true.html>
+ *
+ * This is free and unencumbered software released into the public domain,
+ * provided "as is", without warranty of any kind, express or implied. See the
+ * file UNLICENSE and the website <http://unlicense.org> for further details.
+ */
+
+
+#define _POSIX_SOURCE
+
+
+int main(void)
+{
+    return(0);
+}