sbase

suckless unix tools
git clone git://git.2f30.org/sbase
Log | Files | Refs | README | LICENSE

commit cec53d14b182c7edc0c89544fda0ef2a639df278
parent 4192b13768ca86104ab0e2359a919443fec0a15b
Author: William Haddon <william@haddonthethird.net>
Date:   Mon, 30 Jan 2012 22:41:33 +0000

implement cp and mv and improve rm
Diffstat:
MLICENSE | 1+
MMakefile | 10++++++++--
MTODO | 6------
Mconfig.mk | 2+-
Acp.1 | 22++++++++++++++++++++++
Acp.c | 27+++++++++++++++++++++++++++
Afs.h | 9+++++++++
Amv.1 | 16++++++++++++++++
Amv.c | 39+++++++++++++++++++++++++++++++++++++++
Mrm.1 | 3++-
Mrm.c | 30++++++++++++------------------
Mutil.h | 1+
Autil/cp.c | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil/enmasse.c | 14--------------
Autil/fnck.c | 15+++++++++++++++
Autil/rm.c | 17+++++++++++++++++
16 files changed, 229 insertions(+), 42 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -7,6 +7,7 @@ MIT/X Consortium License © 2011 Hiltjo Posthuma <hiltjo@codemadness.org> © 2011 pancake <pancake@youterm.com> © 2011 Random832 <random832@fastmail.us> +© 2012 William Haddon <william@haddonthethird.net> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/Makefile b/Makefile @@ -1,17 +1,20 @@ include config.mk -HDR = text.h util.h +HDR = fs.h text.h util.h LIB = \ util/afgets.o \ util/agetcwd.o \ util/apathmax.o \ util/concat.o \ + util/cp.o \ util/enmasse.o \ util/eprintf.o \ util/enprintf.o \ util/estrtol.o \ + util/fnck.o \ util/putword.o \ util/recurse.o \ + util/rm.o \ util/venprintf.o SRC = \ @@ -21,6 +24,7 @@ SRC = \ chown.c \ cksum.c \ cmp.c \ + cp.c \ date.c \ dirname.c \ echo.c \ @@ -33,6 +37,7 @@ SRC = \ ls.c \ mkdir.c \ mkfifo.c \ + mv.c \ nl.c \ nohup.c \ pwd.c \ @@ -56,7 +61,8 @@ all: $(BIN) $(OBJ): util.h config.mk $(BIN): util.a -cat.o grep.o tail.o: text.h +cat.o cp.o mv.o grep.o tail.o: text.h +cp.o mv.o rm.o: fs.h .o: @echo LD $@ diff --git a/TODO b/TODO @@ -1,17 +1,11 @@ comm [-123] file1 file2 -cp [-r] file [name] -cp [-r] [file...] [directory] - cut [-bcfs] [-d delim] list [file...] diff [-ru] file1 file2 id [-gnru] [user] -mv file [name] -mv [file...] directory - paste [-s] [-d list] [file...] printf format [argument...] diff --git a/config.mk b/config.mk @@ -10,7 +10,7 @@ MANPREFIX = $(PREFIX)/share/man LD = $(CC) CPPFLAGS = -D_POSIX_C_SOURCE=200112L CFLAGS = -Os -ansi -Wall -pedantic $(CPPFLAGS) -LDFLAGS = -static #-s +LDFLAGS = #CC = tcc #LD = $(CC) diff --git a/cp.1 b/cp.1 @@ -0,0 +1,22 @@ +.TH CP 1 sbase\-VERSION +.SH NAME +cp \- copy files and directories +.SH SYNOPSIS +.B cp +.RB [ \-r ] +.I file +.RI [ name ] +.P +.B cp +.RB [ \-r ] +.RI [ file ...] +.RI [ directory ] +.SH DESCRIPTION +.B cp +copies a given file, naming it the given name. If multiple files are listed +they will be copied into the given directory. +.SH OPTIONS +.TP +.B \-r +copies directories recursively. If this flag is not specified, directories are +not copied. diff --git a/cp.c b/cp.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include "fs.h" +#include "util.h" + +int +main(int argc, char *argv[]) +{ + struct stat st; + char c; + + while((c = getopt(argc, argv, "r")) != -1) + switch(c) { + case 'r': + cp_rflag = true; + break; + default: + exit(EXIT_FAILURE); + } + if(argc > 3 && !cp_rflag && !(stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode))) + eprintf("%s: not a directory\n", argv[argc-1]); + enmasse(argc - optind, &argv[optind], cp); + return EXIT_SUCCESS; +} diff --git a/fs.h b/fs.h @@ -0,0 +1,9 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdbool.h> + +extern bool cp_rflag; +extern bool rm_fflag; +extern bool rm_rflag; + +int cp(const char *, const char *); +void rm(const char *); diff --git a/mv.1 b/mv.1 @@ -0,0 +1,16 @@ +.TH MV 1 sbase\-VERSION +.SH NAME +mv \- move files and directories +.SH SYNOPSIS +.B mv +.I file +.RI [ name ] +.P +.B mv +.RI [ file ...] +.RI [ directory ] +.SH DESCRIPTION +.B mv +moves or renames a given file or directory, naming it the given name. If +multiple files and directories are listed they will be moved into the given +directory. diff --git a/mv.c b/mv.c @@ -0,0 +1,39 @@ +/* See LICENSE file for copyright and license details. */ +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> +#include "fs.h" +#include "util.h" + +int mv(const char *, const char *); + +int +main(int argc, char *argv[]) +{ + struct stat st; + + if(getopt(argc, argv, "") != -1) + exit(EXIT_FAILURE); + if(argc > 3 && !(stat(argv[argc-1], &st) == 0 && S_ISDIR(st.st_mode))) + eprintf("%s: not a directory\n", argv[argc-1]); + enmasse(argc - optind, &argv[optind], mv); + return EXIT_SUCCESS; +} + +int +mv (const char *s1, const char *s2) +{ + if (rename(s1, s2) == 0) + return 0; + if (errno == EXDEV) + { + cp_rflag = true; + rm_rflag = true; + cp(s1, s2); + rm(s1); + return 0; + } + return -1; +} diff --git a/rm.1 b/rm.1 @@ -14,6 +14,7 @@ removes the given files and directories. ignore files that cannot be removed. .TP .B \-r -remove directories recursively. +remove directories recursively. If this flag is not specified, directories are +not removed. .SH SEE ALSO .IR remove (3) diff --git a/rm.c b/rm.c @@ -3,39 +3,33 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <sys/stat.h> +#include "fs.h" #include "util.h" -static void rm(const char *); - -static bool fflag = false; -static bool rflag = false; - int main(int argc, char *argv[]) { char c; + struct stat st; while((c = getopt(argc, argv, "fr")) != -1) switch(c) { case 'f': - fflag = true; + rm_fflag = true; break; case 'r': - rflag = true; + rm_rflag = true; break; default: exit(EXIT_FAILURE); } - for(; optind < argc; optind++) - rm(argv[optind]); + for(; optind < argc; optind++) { + if(!rm_rflag && stat(argv[optind], &st) == 0 && + S_ISDIR(st.st_mode)) + fprintf(stderr, "%s: is a directory\n", argv[optind]); + else + rm(argv[optind]); + } return EXIT_SUCCESS; } - -void -rm(const char *path) -{ - if(rflag) - recurse(path, rm); - if(remove(path) == -1 && !fflag) - eprintf("remove %s:", path); -} diff --git a/util.h b/util.h @@ -8,5 +8,6 @@ void enmasse(int, char **, int (*)(const char *, const char *)); void eprintf(const char *, ...); void enprintf(int, const char *, ...); long estrtol(const char *, int); +void fnck(const char *, const char *, int (*)(const char *, const char *)); void putword(const char *); void recurse(const char *, void (*)(const char *)); diff --git a/util/cp.c b/util/cp.c @@ -0,0 +1,59 @@ +/* See LICENSE file for copyright and license details. */ +#include <dirent.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include "../fs.h" +#include "../text.h" +#include "../util.h" + +bool cp_rflag = false; + +int +cp(const char *s1, const char *s2) +{ + FILE *f1, *f2; + char *ns1, *ns2; + long size1, size2; + struct dirent *d; + struct stat st; + DIR *dp; + + if (stat(s1, &st) == 0 && S_ISDIR(st.st_mode)) { + if (!cp_rflag) { + eprintf("%s: is a directory\n", s1); + } + else { + if(!(dp = opendir(s1))) + eprintf("opendir %s:", s1); + if (mkdir(s2, st.st_mode) == -1 && errno != EEXIST) + eprintf("mkdir %s:", s2); + apathmax(&ns1, &size1); + apathmax(&ns2, &size2); + while((d = readdir(dp))) + if(strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) { + if(snprintf(ns1, size1, "%s/%s", s1, d->d_name) > size1) + eprintf("%s/%s: filename too long\n", s1, d->d_name); + if(snprintf(ns2, size2, "%s/%s", s2, d->d_name) > size2) + eprintf("%s/%s: filename too long\n", s2, d->d_name); + fnck(ns1, ns2, cp); + } + closedir(dp); + free(ns1); + free(ns2); + } + return 0; + } + if(!(f1 = fopen(s1, "r"))) + eprintf("fopen %s:", s1); + if(!(f2 = fopen(s2, "w"))) + eprintf("fopen %s:", s2); + concat(f1, s1, f2, s2); + fclose(f2); + fclose(f1); + return 0; +} diff --git a/util/enmasse.c b/util/enmasse.c @@ -7,8 +7,6 @@ #include <sys/stat.h> #include "../util.h" -static void fnck(const char *, const char *, int (*)(const char *, const char *)); - void enmasse(int argc, char **argv, int (*fn)(const char *, const char *)) { @@ -32,15 +30,3 @@ enmasse(int argc, char **argv, int (*fn)(const char *, const char *)) } free(buf); } - -void -fnck(const char *a, const char *b, int (*fn)(const char *, const char *)) -{ - struct stat sta, stb; - - if(stat(a, &sta) == 0 && stat(b, &stb) == 0 - && sta.st_dev == stb.st_dev && sta.st_ino == stb.st_ino) - eprintf("%s -> %s: same file\n", a, b); - if(fn(a, b) == -1) - eprintf("%s -> %s:", a, b); -} diff --git a/util/fnck.c b/util/fnck.c @@ -0,0 +1,15 @@ +/* See LICENSE file for copyright and license details. */ +#include <sys/stat.h> +#include "../util.h" + +void +fnck(const char *a, const char *b, int (*fn)(const char *, const char *)) +{ + struct stat sta, stb; + + if(stat(a, &sta) == 0 && stat(b, &stb) == 0 + && sta.st_dev == stb.st_dev && sta.st_ino == stb.st_ino) + eprintf("%s -> %s: same file\n", a, b); + if(fn(a, b) == -1) + eprintf("%s -> %s:", a, b); +} diff --git a/util/rm.c b/util/rm.c @@ -0,0 +1,17 @@ +/* See LICENSE file for copyright and license details. */ +#include <stdbool.h> +#include <stdio.h> +#include "../fs.h" +#include "../util.h" + +bool rm_fflag = false; +bool rm_rflag = false; + +void +rm(const char *path) +{ + if(rm_rflag) + recurse(path, rm); + if(remove(path) == -1 && !rm_fflag) + eprintf("remove %s:", path); +}