From 5b0de797fd0249067fe06bf193cc22de50b4b47a Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Wed, 13 Dec 2017 19:40:42 +0100 Subject: initial import of rnl --- Makefile | 23 +++++++++++++ rnl.1 | 53 ++++++++++++++++++++++++++++++ rnl.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 Makefile create mode 100644 rnl.1 create mode 100644 rnl.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ec1a17c --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +ALL=rnl + +CFLAGS=-g -O2 -Wall -Wno-switch -Wextra -Wwrite-strings + +DESTDIR= +PREFIX=/usr/local +BINDIR=$(PREFIX)/bin +MANDIR=$(PREFIX)/share/man + +all: $(ALL) + +README: rnl.1 + mandoc -Tutf8 $< | col -bx >$@ + +clean: FRC + rm -f $(ALL) + +install: FRC all + mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 + install -m0755 $(ALL) $(DESTDIR)$(BINDIR) + install -m0644 $(ALL:=.1) $(DESTDIR)$(MANDIR)/man1 + +FRC: diff --git a/rnl.1 b/rnl.1 new file mode 100644 index 0000000..38c6769 --- /dev/null +++ b/rnl.1 @@ -0,0 +1,53 @@ +.Dd December 13, 2017 +.Dt RNL 1 +.Os +.Sh NAME +.Nm rnl +.Nd remove trailing newlines +.Sh SYNOPSIS +.Nm +.Op Fl 01sz +.Op Ar files\ ... +.Sh DESCRIPTION +.Nm +removes trailing newlines from the specified input +.Ar files . +The files are modified in-place! +.Pp +When used without arguments, +.Nm +copies standard input to standard output, +removing trailing newlines. +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl 0 +Remove +.Em all +trailing newlines. +.It Fl 1 +Remove just +.Em one +trailing newline. +.It Fl s +Strip all but one newline at the end. +(This is the default.) +.It Fl z +Remove final NUL bytes instead of newlines. +.El +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Xr tr 1 +.Sh AUTHORS +.An Leah Neukirchen Aq Mt leah@vuxu.org +.Sh LICENSE +.Nm +is in the public domain. +.Pp +To the extent possible under law, +the creator of this work +has waived all copyright and related or +neighboring rights to this work. +.Pp +.Lk http://creativecommons.org/publicdomain/zero/1.0/ diff --git a/rnl.c b/rnl.c new file mode 100644 index 0000000..b1bac2a --- /dev/null +++ b/rnl.c @@ -0,0 +1,113 @@ +/* rnl - remove final newlines */ + +#include +#include + +#include +#include +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + int c; + int i, n = 0; + int mode = -1; + char nl = '\n'; + + while ((c = getopt(argc, argv, "01sz")) != -1) + switch (c) { + case '0': mode = 0; break; + case '1': mode = 1; break; + case 's': mode = -1; break; + case 'z': nl = '\0'; break; + default: + fprintf(stderr, +"Usage: %s [-01sz] < INPUT writes to stdout\n" +" %s [-01sz] INPUT... modifies in-place!\n" +" -0 strip all newlines at end\n" +" -1 strip one newline at end\n" +" -s default: strip all but one newline at end\n" +" -z strip NUL bytes instead of newlines\n", + argv[0], argv[0]); + exit(1); + } + + if (optind == argc) { + /* pipe mode stdin -> stdout */ + + while ((c = getchar()) != EOF) { + if (c == nl) { + n++; + continue; + } + for (i = 0; i < n; i++) + putchar(nl); + n = 0; + putchar(c); + } + if (mode == 1) + for (i = 0; i < n - 1; i++) + putchar(nl); + else if (mode == -1 && n > 0) + putchar(nl); + /* else (mode == 0) ; do nothing */ + + return 0; + } + + /* in-place mode */ + for (i = optind; i < argc; i++) { + int fd = open(argv[i], O_RDWR); + if (fd < 0) + perror("rnl: open"); + + off_t pos = lseek(fd, 0, SEEK_END); + + if (mode == 1) { + if (pos > 0) { + char buf; + if (pread(fd, &buf, 1, pos - 1) != 1) + perror("rnl: pread"); + if (buf == nl) + if (ftruncate(fd, pos - 1) < 0) + perror("rnl: ftruncate"); + + } + } else { + char buf[1024]; + off_t n = 0; + + off_t endpos = pos; + ssize_t rd; + do { + off_t l = sizeof buf; + if (pos > l) + pos -= l; + else { + l = pos; + pos = 0; + } + rd = pread(fd, buf, l, pos); + while (rd > 0 && buf[--rd] == nl) + n++; + } while (rd == 0 && n > 0 && pos > 0); + + if (rd < 0) + perror("rnl: pread"); + + if (mode == -1 && n > 0) + n--; + + if (n > 0) + if (ftruncate(fd, endpos - n) < 0) + perror("rnl: ftruncate"); + } + + close(fd); + } + + return 0; +} -- cgit 1.4.1