commit 443de6b2ff7295c63811275a5e97659a11a5d5c0
parent 6d2a7da4aae588f1bb970dbe40d66a8585d4c0bb
Author: Anselm R Garbe <anselm@garbe.us>
Date: Sun, 8 May 2011 08:26:38 +0000
applied sl's patch, thanks Stanley!
Diffstat:
M | Makefile | | | 2 | ++ |
A | rm/Makefile | | | 10 | ++++++++++ |
A | rm/rm.1 | | | 28 | ++++++++++++++++++++++++++++ |
A | rm/rm.c | | | 112 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ssam/Makefile | | | 21 | +++++++++++++++++++++ |
A | ssam/ssam | | | 41 | +++++++++++++++++++++++++++++++++++++++++ |
A | ssam/ssam.1 | | | 72 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | std.mk | | | 2 | +- |
8 files changed, 287 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
@@ -38,6 +38,7 @@ SUBDIRS = lib9\
primes\
rc\
read\
+ rm\
sam\
sha1sum\
sed\
@@ -45,6 +46,7 @@ SUBDIRS = lib9\
sleep\
sort\
split\
+ ssam\
strings\
tail\
tee\
diff --git a/rm/Makefile b/rm/Makefile
@@ -0,0 +1,10 @@
+# rm - rm unix port from plan9
+# Depends on ../lib9
+
+TARG = rm
+
+include ../std.mk
+
+pre-uninstall:
+
+post-install:
diff --git a/rm/rm.1 b/rm/rm.1
@@ -0,0 +1,28 @@
+.TH RM 1
+.SH NAME
+rm \- remove files
+.SH SYNOPSIS
+.B rm
+[
+.B -fr
+]
+.I file ...
+.SH DESCRIPTION
+.I Rm
+removes files or directories.
+A directory is removed only if it is empty.
+Removal of a file requires write permission in its directory,
+but neither read nor write permission on the file itself.
+The options are
+.TP
+.B -f
+Don't report files that can't be removed.
+.TP
+.B -r
+Recursively delete the
+entire contents of a directory
+and the directory itself.
+.SH SOURCE
+.B \*9/src/cmd/rm.c
+.SH "SEE ALSO"
+.IR remove (3)
diff --git a/rm/rm.c b/rm/rm.c
@@ -0,0 +1,112 @@
+#include <u.h>
+#include <sys/stat.h>
+#include <libc.h>
+
+#define rmdir p9rmdir
+
+char errbuf[ERRMAX];
+int ignerr = 0;
+
+static void
+err(char *f)
+{
+ if(!ignerr){
+ errbuf[0] = '\0';
+ errstr(errbuf, sizeof errbuf);
+ fprint(2, "rm: %s: %s\n", f, errbuf);
+ }
+}
+
+int
+issymlink(char *name)
+{
+ struct stat s;
+ return lstat(name, &s) >= 0 && S_ISLNK(s.st_mode);
+}
+
+/*
+ * f is a non-empty directory. Remove its contents and then it.
+ */
+void
+rmdir(char *f)
+{
+ char *name;
+ int fd, i, j, n, ndir, nname;
+ Dir *dirbuf;
+
+ fd = open(f, OREAD);
+ if(fd < 0){
+ err(f);
+ return;
+ }
+ n = dirreadall(fd, &dirbuf);
+ close(fd);
+ if(n < 0){
+ err("dirreadall");
+ return;
+ }
+
+ nname = strlen(f)+1+STATMAX+1; /* plenty! */
+ name = malloc(nname);
+ if(name == 0){
+ err("memory allocation");
+ return;
+ }
+
+ ndir = 0;
+ for(i=0; i<n; i++){
+ snprint(name, nname, "%s/%s", f, dirbuf[i].name);
+ if(remove(name) != -1 || issymlink(name))
+ dirbuf[i].qid.type = QTFILE; /* so we won't recurse */
+ else{
+ if(dirbuf[i].qid.type & QTDIR)
+ ndir++;
+ else
+ err(name);
+ }
+ }
+ if(ndir)
+ for(j=0; j<n; j++)
+ if(dirbuf[j].qid.type & QTDIR){
+ snprint(name, nname, "%s/%s", f, dirbuf[j].name);
+ rmdir(name);
+ }
+ if(remove(f) == -1)
+ err(f);
+ free(name);
+ free(dirbuf);
+}
+void
+main(int argc, char *argv[])
+{
+ int i;
+ int recurse;
+ char *f;
+ Dir *db;
+
+ ignerr = 0;
+ recurse = 0;
+ ARGBEGIN{
+ case 'r':
+ recurse = 1;
+ break;
+ case 'f':
+ ignerr = 1;
+ break;
+ default:
+ fprint(2, "usage: rm [-fr] file ...\n");
+ exits("usage");
+ }ARGEND
+ for(i=0; i<argc; i++){
+ f = argv[i];
+ if(remove(f) != -1)
+ continue;
+ db = nil;
+ if(recurse && (db=dirstat(f))!=nil && (db->qid.type&QTDIR))
+ rmdir(f);
+ else
+ err(f);
+ free(db);
+ }
+ exits(errbuf);
+}
diff --git a/ssam/Makefile b/ssam/Makefile
@@ -0,0 +1,21 @@
+# ssam - stream interface for sam
+# Depends on ../lib9
+
+include ../config.mk
+
+all:
+ @echo built ssam
+
+install:
+ @cp -f ssam ${DESTDIR}${PREFIX}/bin/
+ @chmod 755 ${DESTDIR}${PREFIX}/bin/ssam
+ @cp -f ssam.1 ${DESTDIR}${MANPREFIX}/man1/
+ @chmod 444 ${DESTDIR}${MANPREFIX}/man1/ssam.1
+
+uninstall:
+ @rm -f ${DESTDIR}${PREFIX}/bin/ssam
+ @rm -f ${DESTDIR}${MANPREFIX}/man1/ssam.1
+
+clean:
+ @true
+
diff --git a/ssam/ssam b/ssam/ssam
@@ -0,0 +1,41 @@
+#!/usr/local/plan9/bin/rc
+# ssam - stream interface to sam
+
+flagfmt='n,e script,f sfile'
+args='[ file ... ]'
+if(! ifs=() eval `{getflags $*}){
+ usage
+ exit usage
+}
+
+if(~ $#flage 0 && ~ $#flagf 0) {
+ if(~ $#* 0) {
+ usage
+ exit usage
+ }
+ flage=$1
+ shift
+}
+
+if(~ $#TMPDIR 0)
+ TMPDIR=/tmp
+tmp=$TMPDIR/ssam.tmp.$USER.$pid
+cat $* >$tmp
+
+{
+ # select entire file
+ echo ',{'
+ echo k
+ echo '}'
+ echo 0k
+
+ # run scripts, print
+ if(! ~ $#flagf 0)
+ cat $flagf
+ if(! ~ $#flage 0)
+ echo $flage
+ if(~ $#flagn 0)
+ echo ,
+} | sam -d $tmp >[2]/dev/null
+
+rm -f $tmp
diff --git a/ssam/ssam.1 b/ssam/ssam.1
@@ -0,0 +1,72 @@
+.TH SSAM 1
+.SH NAME
+ssam \- stream interface to sam
+.SH SYNOPSIS
+.B ssam
+[
+.B -n
+]
+[
+.B -e
+.I script
+]
+[
+.B -f
+.I sfile
+]
+[
+.I file ...
+]
+.SH DESCRIPTION
+.I Ssam
+copies the named
+.I files
+(standard input default) to the standard output, edited by a script of
+.IR sam
+commands (q.v.).
+When the script starts, the entire input is selected.
+The
+.B -f
+option causes the script to be taken from file
+.IR sfile .
+If there is a
+.B -e
+option and no
+.BR -f ,
+the flag
+.B -e
+may be omitted.
+The
+.B -n
+option suppresses the default output.
+.ne 4
+.SH EXAMPLES
+.TP
+.B ssam -n ,10p file
+Print first 10 lines of file.
+.TP
+.B ssam 'y/[a-zA-Z]+/ c/\en/' *.ms
+Print one word per line.
+.TP
+.B ssam 's/\en\en+/\en/g'
+Delete empty lines from standard input.
+.TP
+.B ssam 's/UNIX/& system/g'
+Replace every instance of
+.L UNIX
+by
+.LR "UNIX system" .
+.TP
+.B ssam 'y/[a-zA-Z]+/ c/\en/' | grep . | sort | uniq -c
+Count frequency of words read from standard input.
+.SH SOURCE
+.B \*9/bin/ssam
+.SH SEE ALSO
+.IR sed (1),
+.IR sam (1),
+.IR regexp (7)
+.PP
+Rob Pike,
+``The text editor sam''.
+.SH BUGS
+Ssam consumes all of standard input before running the script.
diff --git a/std.mk b/std.mk
@@ -6,7 +6,7 @@ MANFILE ?= ${TARG}.1
include ../config.mk
all: ${TARG}
- @strip ${TARG}
+# @strip ${TARG}
@echo built ${TARG}
install: install-default post-install