9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

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:
Makefile | 2++
rm/Makefile | 10++++++++++
rm/rm.1 | 28++++++++++++++++++++++++++++
rm/rm.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ssam/Makefile | 21+++++++++++++++++++++
ssam/ssam | 41+++++++++++++++++++++++++++++++++++++++++
ssam/ssam.1 | 72++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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