]> pd.if.org Git - pdutils/blobdiff - utils/tail/tail.c
rename utils to posix
[pdutils] / utils / tail / tail.c
diff --git a/utils/tail/tail.c b/utils/tail/tail.c
deleted file mode 100644 (file)
index 5fa8849..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * 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);
-}