commit b79428b4aec5e99d9c0f1dcc07fe677c2679cf4a from: Alexander Arkhipov date: Wed Jul 13 10:35:25 2022 UTC initial commit commit - /dev/null commit + b79428b4aec5e99d9c0f1dcc07fe677c2679cf4a blob - /dev/null blob + b5e9a61d525eb0d72c5e28cc95b1817549a69aa9 (mode 644) --- /dev/null +++ Makefile @@ -0,0 +1,45 @@ +include config.mk + +.SUFFIXES: .o .c + +BIN = rene +OBJ = $(BIN:=.o) +SRC = $(BIN:=.c) +MAN = $(BIN:=.1) + +all: $(BIN) + +$(BIN): $(OBJ) + $(CC) -o $@ $(OBJ) $(LDFLAGS) + +$(OBJ): config.mk + +.c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< + +install: all + mkdir -p $(DESTDIR)$(PREFIX)/bin + install -m 755 $(BIN) $(DISTDIR)$(PREFIX)/bin/ + mkdir -p $(DESTDIR)$(MANPREFIX)/man1 + install -m 644 $(MAN) $(DISTDIR)$(MANPREFIX)/man1 + +uninstall: + cd $(DESTDIR)$(PREFIX)/bin && rm -f $(BIN) + cd $(DESTDIR)$(MANPREFIX)/man1 && rm -f $(MAN) + +dist: clean + mkdir -p rene-$(VERSION) + cp -rf TODO README Makefile config.mk t $(SRC) $(MAN) rene-$(VERSION) + tar -czf rene-$(VERSION).tar.gz rene-$(VERSION) + rm -rf rene-$(VERSION) + +clean: + -rm -f $(BIN) $(OBJ) + -rm -f rene-$(VERSION).tag.gz + -rm -f *.core + -rm -f vgcore.* + +test: + -sh ./t/t.sh + +.PHONY: all install uninstall clean dist test blob - /dev/null blob + 9e4493647aac5f594b374a9e6bad12654eee5b4c (mode 644) --- /dev/null +++ README @@ -0,0 +1,24 @@ +rene is a batch-renaming tool similar to rename from util-linux, but for all +Unix-likes. To install, edit config.mk if necessary, and then run make and +make install: + + $ $EDITOR config.mk + $ make + # make install + + +COPYING + +Copyright (c) 2022 Alexander Arkhipov + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. blob - /dev/null blob + a6d21f954682c09856c6a4342e6a35d6ba0ff935 (mode 644) --- /dev/null +++ TODO @@ -0,0 +1,3 @@ +- add options -b and -e for basic and extended regex; + +- add support for pledge(2); blob - /dev/null blob + 2241ed7407971cea3182a2144cc599bce75de4c3 (mode 644) --- /dev/null +++ config.mk @@ -0,0 +1,8 @@ +VERSION = 0.1 + +PREFIX = /usr/local +MANPREFIX = $(PREFIX)/man + +CC = cc +CFLAGS = -std=c99 -Wall -pedantic +CPPFLAGS = -D_DEFAULT_SOURCE blob - /dev/null blob + f047179ba2369365a2e2d012e784a519dfb8fe65 (mode 755) Binary files /dev/null and rene differ blob - /dev/null blob + 600a65df3c46936110b851538688167a1e4aa638 (mode 644) --- /dev/null +++ rene.1 @@ -0,0 +1,51 @@ +.Dd July 07, 2022 +.Dt RENE 1 +.Os +.Sh NAME +.Nm rene +.Op Fl ailnov +.Nd rename files +.Sh SYNOPSIS +.Nm +.Ar from to file ... +.Sh DESCRIPTION +The utility +.Nm +renames the supplied +.Ar files +by replacing the first occurence of +.Ar from +with +.Ar to . +.Pp +The options are as follows: +.Bl -tag -width Ds +.It Fl a +Replace all occurences of +.Ar from +instead of only the first one. Overrides +.Fl l . +.It Fl i +Prompt to stderr before overriding existing files. A renaming operation is only +attempted if the response form stdin begins with the character +.Dq y . +.It Fl l +Replace the last occurence of +.Ar from +instead of the first one. +.It Fl n +Don't actually rename any files. Useful with +.Fl v . +.It Fl o +Don't override existing files. Disables +.Fl i . +.It Fl v +Display the old and new names of each renamed file. +.El +.Sh EXIT STATUS +.Ex -std +.Sh SEE ALSO +.Xr mv 1 , +.Xr rename 2 +.Sh AUTHORS +.An Alexander Arkhipov Aq Mt src@mineeyes.cyou . blob - /dev/null blob + 2ab6b9e65216392e7300fb04a6f2f76a3c4d1ba2 (mode 644) --- /dev/null +++ rene.c @@ -0,0 +1,147 @@ +#include +#include +#include +#include +#include + +int interactive = 0; +int noact = 0; +int nooverride = 0; +int replaceall = 0; +int replacelast = 0; +int verbose = 0; + +void +usage(void) +{ + fprintf(stderr, "usage: rene [-ailnov] from to file ...\n"); + exit(EXIT_FAILURE); +} + +char *rene; + +void +err(const char *fmt, ...) +{ + fprintf(stderr, "%s: ", rene); + if (fmt != NULL) { + va_list argp; + va_start(argp, fmt); + vfprintf(stderr, fmt, argp); + va_end(argp); + } + fprintf(stderr, "\n"); +} + +int +strrep(char *from, char *to, char *s, char **new) +{ + char *p = strrchr(s, '/'); + if (p) { + if (*++p == '\0') + return 0; + } else + p = s; + p = strstr(p, from); + if (!p) + return 0; + int fromlen = strlen(from); + int count = 1; + if (replacelast || replaceall) { + char *temp = p; + while (temp) { + temp = strstr(temp+fromlen, from); + count = (replaceall && temp) ? count + 1 : count; + p = (replacelast && temp) ? temp : p; + } + } + + if (!(*new = malloc(strlen(s) + strlen(to)*count - fromlen*count + 1))) { + err("%s: couldn't allocate memory", s); + return 0; + } + + char *newp = *new; + char *top = to; + while (p) { + for (; s != p; *newp++ = *s++) + ; + for (; *top != '\0'; *newp++ = *top++) + ; + s += fromlen; + p = replaceall ? strstr(s, from) : strchr(s, '\0'); + p = p ? p : strchr(s, '\0'); + for (; s != p; *newp++ = *s++) + ; + p = (*p == '\0') ? NULL : p; + top = to; + } + *newp = '\0'; + return 1; +} + +int +ask(char *from, char *to) +{ + fprintf(stderr, "replace %s with %s? ", from, to); + return getchar() == 'y'; +} + +void +ren(char *from, char *to, char *f) +{ + int yes = 1; + char *new = NULL; + if (!strrep(from, to, f, &new)) + return; + if ((nooverride || interactive) && access(new, F_OK) == 0) + yes = nooverride ? 0 : ask(f, new); + if (yes && !noact) + yes -= rename(f, new); + if (verbose && yes) + printf("%s -> %s\n", f, new); + free(new); +} + +int +main(int argc, char *argv[]) +{ + char *from, *to; + rene = argv[0]; + + int c; + while ((c = getopt(argc, argv, "ailnov")) != -1) { + switch (c) { + case 'a': + replaceall = 1; + break; + case 'i': + interactive = 1; + break; + case 'l': + replacelast = 1; + break; + case 'n': + noact = 1; + break; + case 'o': + nooverride = 1; + break; + case 'v': + verbose = 1; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argc < 3) + usage(); + from = argv[0]; + to = argv[1]; + for (int i = 2; i < argc; i++) + ren(from, to, argv[i]); + return 0; +} blob - /dev/null blob + 2a7024a24d46c0da802241eb1ca2902e03ce2cca (mode 644) Binary files /dev/null and rene.o differ blob - /dev/null blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644) blob - /dev/null blob + b68c9f68791cd8985f27447a53d9bc52ae055b73 (mode 644) --- /dev/null +++ t/all.exp @@ -0,0 +1,4 @@ +foobar -> barbar +barfoo -> barbar +barfoobar -> barbarbar +foobarfoo -> barbarbar blob - /dev/null blob + 0b3927a595e3669652fc5f2f017d22350fc8fc5a (mode 644) --- /dev/null +++ t/all.t @@ -0,0 +1 @@ +./rene -nva foo bar foobar barfoo barfoobar foobarfoo foo/ bar blob - /dev/null blob + c3e4f5385af30cf0e58e43911bcb19eeb8b585f6 (mode 644) --- /dev/null +++ t/base.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +tests="$(find . -name '*.t')" + +for t in $tests; do + base=${t%%.t} + printf '%-10s ' "$(basename $base)" + sh $t >$base.out 2>$base.err + cmp $base.out $base.exp >/dev/null 2>&1 + res=$? + cmp $base.err $base.err.exp >/dev/null 2>&1 + eres=$? + if [ "$res" = 0 ] && [ "$eres" = 0 ]; then + echo OK + else + echo FAIL + fi +done blob - /dev/null blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644) blob - /dev/null blob + adb838938baad969374ccf30dca0f50da9f17ca2 (mode 644) --- /dev/null +++ t/last.exp @@ -0,0 +1,4 @@ +foobar -> barbar +barfoo -> barbar +barfoobar -> barbarbar +foobarfoo -> foobarbar blob - /dev/null blob + 30987e736f62901ccff5cd09a8bebe56a383d259 (mode 644) --- /dev/null +++ t/last.t @@ -0,0 +1 @@ +./rene -nvl foo bar foobar barfoo barfoobar foobarfoo foo/ bar blob - /dev/null blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644) blob - /dev/null blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644) blob - /dev/null blob + e704573b5fa887e354882c0e77b799d393fe9993 (mode 644) --- /dev/null +++ t/nooverride.t @@ -0,0 +1,5 @@ +tmp=/tmp/.rene.tes +mkdir -p $tmp +trap 'rm -rf $tmp' EXIT HUP INT +touch $tmp/bar +./rene -nvo foo bar $tmp/foo blob - /dev/null blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644) blob - /dev/null blob + ac6dd9e1f817c246cdef9be77b681b21c42ec6da (mode 644) --- /dev/null +++ t/norm.exp @@ -0,0 +1,4 @@ +foobar -> barbar +barfoo -> barbar +barfoobar -> barbarbar +foobarfoo -> barbarfoo blob - /dev/null blob + c85b4d4bbb6a39f698e4f1b5fb4fe68dedce850f (mode 644) --- /dev/null +++ t/norm.t @@ -0,0 +1 @@ +./rene -nv foo bar foobar barfoo barfoobar foobarfoo foo/ bar blob - /dev/null blob + 9dae219cfe88e8e6dd00b95724eb31b8cf0d87cf (mode 644) --- /dev/null +++ t/t.sh @@ -0,0 +1,8 @@ +dir="$(dirname $0)" + +echo ---- BASE ---- +sh "$dir"/base.sh + +echo +echo -- VALGRIND -- +sh "$dir"/val.sh blob - /dev/null blob + 671cb90afbfd5a0edaf9b236945f07774252ce56 (mode 644) --- /dev/null +++ t/val.sh @@ -0,0 +1,38 @@ +res() { + printf '%-10s ' "$1" + if [ $2 = $err ]; then + echo FAIL + else + echo OK + fi +} +err=1 + +echo AVERAGE +set -- foo bar foobar barfoo barfoobar foobarfoo foofoofoo foo bar +valgrind --error-exitcode=$err ./rene "$@" >/dev/null 2>&1 +res normal $? +valgrind --error-exitcode=$err ./rene -l "$@" >/dev/null 2>&1 +res last $? +valgrind --error-exitcode=$err ./rene -a "$@" >/dev/null 2>&1 +res all $? + +echo +echo SLASH +set -- foo bar foobar/ barfoo/ barfoobar/ foobarfoo/ foofoofoo/ foo/ bar/ +valgrind --error-exitcode=$err ./rene "$@" >/dev/null 2>&1 +res normal $? +valgrind --error-exitcode=$err ./rene -l "$@" >/dev/null 2>&1 +res last $? +valgrind --error-exitcode=$err ./rene -a "$@" >/dev/null 2>&1 +res all $? + +echo +echo NOFROM +set -- foo bar bar abracadebra lol abcd +valgrind --error-exitcode=$err ./rene "$@" >/dev/null 2>&1 +res normal $? +valgrind --error-exitcode=$err ./rene -l "$@" >/dev/null 2>&1 +res last $? +valgrind --error-exitcode=$err ./rene -a "$@" >/dev/null 2>&1 +res all $?