shithub: bin.rc

Download patch

ref: 25f9e2963d99c77c9c6c259820474c89076e0921
author: kvik <kvik@a-b.xyz>
date: Mon Jan 13 15:06:39 EST 2020

Slurp

--- /dev/null
+++ b/README
@@ -1,0 +1,5 @@
+# rc dump
+
+Mildly curated subset of my `$home/bin/rc`.  Largely useless even to
+the author most of these scripts got checked in for archival purposes
+and may fall off the branch as we speak.
--- /dev/null
+++ b/bin/21
@@ -1,0 +1,11 @@
+#!/bin/rc
+# 21 - poor man's acme 2-1 chord for sam
+rfork e
+for(i in `{seq 1 $#*})
+	args=($args ''''$$i'''')
+cat >/env/pgm <<'.'
+cd `{basename -d $%}
+$* $"%s
+cat
+.
+window -m 'rc /env/pgm '$"args
--- /dev/null
+++ b/bin/9plumb
@@ -1,0 +1,20 @@
+#!/bin/rc
+# 9p://
+# type is text
+# data matches '9p://([^ /]+)(/[^ ]+)?'
+# plumb start window 9plumb $1 $2
+
+host=$1
+name=$2
+if(~ $#name 0)
+	name=''
+srv $host $host /n/$host
+if(~ $name '' || test -d /n/$host/$name){
+	cd /n/$host/$name; pwd; ls -l
+}
+if not{
+	cd `{basename -d /n/$host/$name}
+	echo /n/$host/$name
+	cat /n/$host/$name
+}
+exec rc
--- /dev/null
+++ b/bin/Y
@@ -1,0 +1,12 @@
+#!/bin/rc
+# Yank [register]
+if(~ $#* 1){
+	where=/env/$1
+	echo '>cat >>'$where
+}
+if not {
+	where=/env/yXy
+	cat /dev/snarf >$where
+	echo '>cat >>'$where
+	echo '!cat $where >/dev/snarf'
+}
--- /dev/null
+++ b/bin/argz
@@ -1,0 +1,27 @@
+#!/bin/rc
+cat >/env/pgm <<.
+function parseflags(		a, i) {
+	while(ARGV[++argi] ~ /^-.+$/){
+		if(ARGV[argi] == "--"){
+			argi++
+			break
+		}
+		split(ARGV[argi], a, "")
+		if(length(a) == 2 && ARGV[argi+1] !~ /^-/){
+			flag[a[2]] = ARGV[++argi]
+			continue
+		}
+		for(i = 1; i <= length(a); i++)
+			if(a[i] != "-")
+				flag[a[i]] = 1
+	}
+}
+BEGIN{
+	parseflags()
+	for(f in flag)
+		print f " " flag[f]
+	for(; argi < ARGC; argi++)
+		print ARGV[argi]
+}
+.
+awk -f /env/pgm -- $*
--- /dev/null
+++ b/bin/bg
@@ -1,0 +1,5 @@
+#!/bin/rc
+# bg file
+ppid=`{cat /proc/$pid/ppid}
+echo -n `{cat /proc/$ppid/noteid} > /proc/$pid/noteid
+exec rc $1
--- /dev/null
+++ b/bin/c
@@ -1,0 +1,65 @@
+#!/bin/rc
+rfork e
+fn usage {>[2=1] echo 'usage:' $usage && exit 'usage'}
+usage='c [-fs] [regex] [search]
+	-f        find functions
+	-s        find structs'
+
+fn struct {
+	ignore = (/sys/include/ape)
+	search = $*
+	if(~ $#search 0)
+		search = (/sys/include .)
+	if(~ $search *^$ignore^*)
+		ignore = (cat)
+	if not
+		ignore = (grep -v -e^'^'$ignore)
+
+	files = `{walk -f $search | $ignore | grep '\.[chsyl]$'}
+
+	echo 'X ,x@^struct([^}][^;]*\n*)+};\n@ g@^struct[ 	]+'$regex'@ {
+		!echo '•' $%:$%l
+		p
+	}' | sam -d $files >[2]/dev/null
+}
+
+fn function {
+	ignore = ('\.root.s$' 'cmd/python/')
+	search = $*
+	if(~ $#search 0)
+		search = (.)
+	if(~ $search *^$ignore^*)
+		ignore = (cat)
+	if not
+		ignore = (grep -v -e^'^'$ignore)
+
+	files = `{walk -f $search | $ignore | grep '\.[chsyl]$'}
+
+	sep = '	• '
+	echo 'X ,x g@^'$regex'\(@ {
+		!echo -n $%:$%l $sep
+		p
+	}' | sam -d $files >[2]/dev/null
+}
+
+identifier = '[a-zA-Z_0-9]*'
+op = (struct)
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -f -func*
+		op = 'function'
+	case -s -struct
+		op = 'struct'
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+regex = `{echo $1 | sed 's:%:'$identifier':g'}
+if(~ $#regex 0)
+	regex = $identifier
+shift
+
+$op $*
--- /dev/null
+++ b/bin/c+
@@ -1,0 +1,8 @@
+#!/bin/rc
+switch($%){
+case *.[chs] *.myr
+	cmnt='//'
+case *
+	cmnt='#'
+}
+exec sed 's,^,'$cmnt','
--- /dev/null
+++ b/bin/c-
@@ -1,0 +1,8 @@
+#!/bin/rc
+switch($%){
+case *.[chs] *.myr
+	cmnt='//'
+case *
+	cmnt='#'
+}
+exec sed 's,^'$cmnt',,'
--- /dev/null
+++ b/bin/cc
@@ -1,0 +1,8 @@
+#!/bin/rc
+
+rfork e
+
+O=`{sed 's/^O=//; t end; D; :end; q' /$objtype/mkfile}
+CFLAGS=`{sed 's/^CFLAGS=//; t end; D; :end; q' /sys/src/mkfile.proto}
+
+$O^c $CFLAGS $1.c && $O^l -o $1 $1.$O
--- /dev/null
+++ b/bin/cin
@@ -1,0 +1,22 @@
+#!/bin/rc
+rfork e
+nl='
+'
+while(line=`$nl{read}){
+	cmd=$line
+	if(~ $#cmd 0) cmd='\r'
+	switch($cmd){
+	case '\r'
+		ci /env/code
+	case '\t'
+		time ci /env/code
+	case '\prof'
+		ci -p /env/code
+	case '\p'
+		cat /env/code
+	case '\c'
+		>/env/code
+	case *
+		echo $line >>/env/code
+	}
+}
--- /dev/null
+++ b/bin/clear
@@ -1,0 +1,7 @@
+#!/bin/rc
+if(~ $1 -a){
+	>/dev/text
+	exit
+}
+</dev/text sed '/^'^$prompt(1)^'/q' | sed '$d' >/tmp/clear
+cat /tmp/clear >/dev/text
--- /dev/null
+++ b/bin/crap
@@ -1,0 +1,118 @@
+#!/bin/rc
+# crap [ -s sandbox ]
+# commands:
+# 	empty line executes
+#	p, P - print code / sandbox
+#	c, C - clear code / sandbox
+#	e, E - open $editor on code / sandbox
+#	s - print assembly listing
+#	d - run acid(1)
+#	t - run time(1)
+
+rfork en
+
+if(~ $#editor 0)
+	editor=(ed)
+nl='
+'
+tab='	'
+sandbox0=sandbox0.$pid.c
+sandbox=sandbox.$pid.c
+tmp=tmp.$pid.c
+util=util.$pid.h
+code=code.$pid.c
+mkfile=mkfile.$pid
+
+fn generate {
+	<$sandbox >$tmp ssam '
+	/\/\*START\*\//+1 , /\/\*END\*\//-1 c/\n/
+	/\/\*START\*\//+1 r '$code
+	cp $tmp $sandbox
+}
+
+ramfs -bc -m .
+
+>$mkfile echo '
+</$objtype/mkfile
+CFLAGS=-FTVN
+default:VQ:
+	$CC $CFLAGS -o sandbox.$O '^$sandbox^'
+	$LD $LDFLAGS sandbox.$O
+asm:VQ:
+	$CC $CFLAGS -S '^$sandbox^'
+run:VQ: default
+	./$O.out
+time:VQ: default
+	time ./$O.out'
+
+>$util echo '
+char errmsg[ERRMAX];
+#define err \
+	rerrstr(errmsg, ERRMAX); \
+	if(errmsg[0] != 0) print("error: %r\n");
+#define fail \
+	rerrstr(errmsg, ERRMAX); \
+	if(errmsg[0] != 0) sysfatal("%r");'
+
+>$sandbox0 echo '
+#include <u.h>
+#include <libc.h>
+#include "'^$util^'"
+void
+main(int, char *[])
+{
+	/*START*/
+
+	/*END*/
+	exits(nil);
+}'
+
+while(! ~ $#* 0 && ~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -s
+		cp $2 $sandbox0
+		shift
+	}
+	shift
+}
+cp $sandbox0 $sandbox
+
+echo -n >$code
+while(line=`$nl{read}){
+	if(! echo $"line | grep -s '^.$' && ! ~ $#line 0){
+		echo -n $"tab >>$code
+		echo $"line >>$code
+	}
+	if not{
+		cmd=$line
+		switch($cmd){
+		case s
+			generate
+			mk -f $mkfile asm
+		case d
+			generate
+			mk -f $mkfile run
+			acid *.out
+		case t
+			generate
+			mk -f $mkfile time
+		case e
+			$editor $code
+		case E
+			$editor $sandbox
+			<$sandbox >$code ssam -n '/\/\*START\*\//+1 , /\/\*END\*\//-1 p'
+		case p
+			cat $code
+		case P
+			cat $sandbox
+		case c
+			echo >$code
+			generate
+		case C
+			cp $sandbox0 $sandbox
+		case *
+			generate
+			mk -f $mkfile run
+		}
+	}
+}
--- /dev/null
+++ b/bin/enum
@@ -1,0 +1,29 @@
+#!/bin/rc
+rfork e
+fn usage{
+	echo usage: `{basename $0} '[file ...]' >[1=2]
+	exit 'usage'
+}
+
+if(! ~ $#* 0)
+	fl=$*
+if not
+	fl=(/sys/src/libc/^(port 9sys)^/*.c)
+
+awk '
+	/^enum[ 	]*{$/ {
+		matched = 1
+		if(nfound++ > 0)
+			print ""
+		if(ARGC != 1)
+			print FILENAME ":" FNR
+	}
+
+	matched {
+		print
+	}
+
+	matched && /^}/ {
+		matched = 0
+	}
+' $fl
--- /dev/null
+++ b/bin/ep
@@ -1,0 +1,22 @@
+#!/bin/rc -e
+rfork e
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='ep'
+
+fn salt {dd -if /dev/random -count 1 -quiet 1 | sum | sed 's/ .*//'}
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(test $#* -gt 0)
+	usage
+
+file = /tmp/ep.`{salt}
+cat >$file
+plumb -d edit $file
--- /dev/null
+++ b/bin/escape
@@ -1,0 +1,2 @@
+#!/bin/rc
+exec sed 's,([.*?+()|^$\-\[\]\\]),\\\1,g'
--- /dev/null
+++ b/bin/fakeroot
@@ -1,0 +1,6 @@
+#!/bin/rc
+bind / /n/realroot
+ramfs -m /n/portroot
+unionfs -m /n/root / -c /n/portroot
+bind /n/root /
+bind -c '#e' /env
--- /dev/null
+++ b/bin/find
@@ -1,0 +1,42 @@
+#!/bin/rc -e
+rfork e
+fn usage {>[2=1] echo 'usage:' $usage && exit 'usage'}
+usage='find [-e regex ...] [type]'
+
+namefilters=()
+typefilters=(c rc)
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -e
+		namefilters=($namefilters $2)
+		shift
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(~ $#namefilters 0)
+	namefilters=('.*')
+if(test $#* -gt 0)
+	typefilters=$*
+select=''
+for(t in $typefilters)
+	select=$select^:^$t
+
+file `{walk -f | grep -e^$namefilters} | awk -F':' '
+	BEGIN {
+		split(ENVIRON["select"], select, ":")
+		delete select[1]
+	}
+	{
+		sub(/^ */, "", $2)
+		for(s in select){
+			if($2 ~ "^" select[s]){
+				print $1
+				break
+			}
+		}
+	}
+'
--- /dev/null
+++ b/bin/func
@@ -1,0 +1,35 @@
+#!/bin/rc
+# func - find C function definitions
+# func [pattern]
+
+rfork e
+
+fn sigint sighup sigexit {
+	rm -f $matches
+	exit
+}
+
+ignore='(\.root.s$)|(cmd/python/)'
+matches=/tmp/matches.$pid
+ident='([a-zA-Z_][a-zA-Z_0-9]*)'
+
+func=$1
+func=`{echo $func | sed 's,%,'$ident'?,g'}
+if(~ $#func 0)
+	func=$ident
+#patt='^([^ 	]+[ 	]+)*'$func'\('
+patt='^'$func'\('
+
+srcs=`{walk -f | grep '\.[chs]$' | grep -v $ignore}
+>$matches grep -n $patt $srcs /dev/null
+n=`{wc -l $matches}
+switch($n(1)){
+	case 0
+		exit 'no match'
+	case 1
+		plumb `{<$matches sed 's,: .*,,'}
+		exit
+	case *
+		window -m 'cat '$matches'; cat'
+		sleep 1
+}
--- /dev/null
+++ b/bin/gridup
@@ -1,0 +1,137 @@
+#!/bin/rc
+rfork e
+fn usage {
+	>[2=1] echo 'usage:' $0 '[-mst]'
+	exit usage
+}
+fn quiet {
+	if(~ $quiet 'no')
+		>[2=1] echo $*
+}
+fn fail {
+	quiet fail: $*
+	exit 'fail: '$*
+}
+
+registry='tcp!registry.9gridchan.org!6675'
+reconnect='no'
+mountonly='no'
+scriptonly='no'
+tls='no'
+quiet='no'
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -m
+		mountonly='yes'
+	case -s
+		scriptonly='yes'
+	case -t
+		tls='yes'
+		registry='tcp!registry.9gridchan.org!6675'
+	case -q
+		quiet='yes'
+		reconnect='yes'
+	case *
+		usage
+	}
+	shift
+}
+if(! ~ $#* 0)
+	usage
+
+services=( \
+	gridregistry pubregistry \
+	gridchat gridplumber \
+	gridram griddisk \
+	gridroot gridwiki)
+for(s in $services)
+	if(test -w /srv/$s)
+		reconnect='yes'
+if(~ $reconnect 'yes'){
+	if(~ $quiet 'no'){
+		echo -n 'old grid connections found in /srv, remove? [y/n]: '
+		reconnect=`{read}
+	}
+	if(~ $reconnect y*)
+		rm -f /srv/^$services
+}
+
+if(~ $mountonly 'no')
+	rfork n
+if(~ $tls 'no')
+	srv $registry gridregistry /mnt/registry || fail registry
+if not{
+	if(! test -w /mnt/factotum/ctl)
+		auth/factotum
+	>/mnt/factotum/ctl echo 'key proto=dp9ik user=glenda dom=grid !password=9gridchan' || fail factotum
+	srvtls $registry gridregistry /mnt/registry || fail registry
+}
+
+>/tmp/gridmount echo '#!/bin/rc'
+>>/tmp/gridmount </mnt/registry/index awk -v 'tls='$tls '
+	/service tlssrv/ && tls == "yes" {
+		print "srvtls -c", $1, $3, $5}
+	/service \/bin\/exportfs/ && tls == "no" {
+		print "srv -c", $1, $3, $5}
+'
+chmod +x /tmp/gridmount
+
+if(~ $scriptonly 'yes'){
+	quiet 'mount script saved in /tmp/gridmount'
+	cat /tmp/gridmount
+	exit
+}
+if(~ $mountonly 'yes'){
+	/tmp/gridmount || fail 'could not mount'
+	quiet 'grid services mounted'
+	exit
+}
+
+>/tmp/chatcat cat <<'...'
+#!/bin/rc
+label chat
+echo 'README:'
+echo '	This is chatcat(1).'
+echo '	Type a (multi-line) message ending with a newline'
+echo '	and press control-d (EOT) to send.'
+echo
+echo -n 'nick? '
+nick=`{read}
+if(~ $#nick 0)
+	nick='unknown gridster'
+echo JOIN $nick to chat >>/n/chat/chat
+cat /n/chat/chat &
+while() cat | sed '1s/^/'$nick' → /' >>/n/chat/chat
+...
+chmod +x /tmp/chatcat
+
+>/tmp/gridrio cat <<'...'
+#!/bin/rc
+if(test -x /bin/chat)
+	window -r 0 0 700 400 -scroll chat
+if not
+	window -r 0 0 700 400 -scroll /tmp/chatcat
+window -r 700 0 1300 400 acme -c1 /n/griddisk /n/griddisk/gridmsg
+window -r 0 400 700 750 mothra -a http://wiki.9gridchan.org/message_board
+window -r 700 400 1300 750 page /n/gridroot/lib/musicant.png
+...
+chmod +x /tmp/gridrio
+
+>/tmp/gridscript cat <<'...'
+#!/bin/rc
+/tmp/gridmount
+fn cpl {
+	cp $1 /n/griddisk/cpl
+	ptarg=`{basename $1}
+	plumb http://wiki.9gridchan.org/incoming/cpl/$ptarg
+}
+if(! test -e /mnt/web/ctl)
+	webfs
+rio=(rio)
+if(test -x /bin/grio)
+	rio=(grio -c 0x99009900)
+exec $rio -i /tmp/gridrio
+...
+chmod +x /tmp/gridscript
+
+window -r 0 0 1350 750 /tmp/gridscript
--- /dev/null
+++ b/bin/hd
@@ -1,0 +1,16 @@
+#!/bin/rc
+lines=3
+while(! ~ $#* 0 && ~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -[0-9]*
+		lines=`{echo $1 | sed 's:^-::'}
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(~ $#* 0)
+	'*'=*
+for(f)
+	if(test -f $f)
+		echo « $f && sed $lines^q $f && echo »
--- /dev/null
+++ b/bin/hist
@@ -1,0 +1,14 @@
+#!/bin/awk -f
+function rep(s, n,		t) {
+	n = int(n / (max+1) * 60)
+	while (n--)
+		t = t s
+	return t
+}
+{ x[int($1/10)]++ }
+END {
+	for (i = 0; i < 10; i++)
+		if (x[i] > max) max = x[i]
+	for (i = 0; i < 10; i++)
+		printf("%-10d - %s\n", x[i], rep("*", x[i]))
+}
--- /dev/null
+++ b/bin/hublog
@@ -1,0 +1,7 @@
+#!/bin/rc
+if(! test -e /srv/hublog)
+	hubfs -t -s hublog
+local mount -c /srv/hublog /mnt/log
+if(! test -e /mnt/log/log)
+	touch /mnt/log/log
+cat /mnt/log/log
--- /dev/null
+++ b/bin/i+
@@ -1,0 +1,9 @@
+#!/bin/awk -f
+BEGIN{
+	tabs = "	"
+	if(ARGC > 1){
+		n = ARGV[1]; ARGC--
+		while(--n) tabs = tabs "	"
+	}
+}
+{ print tabs $0 }
--- /dev/null
+++ b/bin/i-
@@ -1,0 +1,17 @@
+#!/bin/awk -f
+BEGIN{
+	n = 1
+	if(ARGC > 1){
+		n = ARGV[1]; ARGC--
+	}
+	for(i = 1; i < 50; i++)
+		tabs[i] = tabs[i-1] "	"
+}
+{
+	if(match($0, /^	+/) == 0){
+		print
+		next
+	}
+	sub(/^	+/, tabs[RLENGTH-n])
+	print
+}
--- /dev/null
+++ b/bin/ipatch
@@ -1,0 +1,21 @@
+#!/bin/rc
+rfork e
+fn usage {
+	>[2=1] echo $0 f1 f2
+	exit usage
+}
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(! ~ $#* 2)
+	usage
+
+cp $1 $1.orig &&
+idiff $1.orig $2 > $1
--- /dev/null
+++ b/bin/isatty
@@ -1,0 +1,6 @@
+#!/bin/awk -f
+BEGIN {
+	getline <"/fd/0ctl"
+	if($10 != "/dev/cons")
+		exit "nein"
+}
--- /dev/null
+++ b/bin/j
@@ -1,0 +1,8 @@
+#!/bin/rc
+# Join lines
+exec ssam '
+,x~.*\n~{
+	x~^[ 	]+~d
+	x~[ 	]+$~d
+}
+,x~\n~c~ ~'
--- /dev/null
+++ b/bin/joynes
@@ -1,0 +1,45 @@
+#!/bin/rc
+nusb/joy $1 | awk -safe -v 'joy='$2 '
+	BEGIN { k[0] = "" }
+
+#	/^axis 0 0/   { k[0] = "left " }
+#	/^axis 0 255/ { k[0] = "right " }
+#	/^axis 0 128/ { k[0] = "" }
+#
+#	/^axis 1 0/   { k[1] = "up " }
+#	/^axis 1 255/ { k[1] = "down " }
+#	/^axis 1 128/ { k[1] = "" }
+	
+	/^down 5$/ { k[0] = "up " }
+	/^down 6$/ { k[0] = "right " }
+	/^down 7$/ { k[0] = "down " }
+	/^down 8$/ { k[0] = "left " }
+	
+	/^down 9$/ { k[3] = "b " }
+	/^down 10$/ { k[2] = "a " }
+	/^down 16$/ { k[3] = "b " }
+	/^down 14$/ { k[2] = "a " }
+	/^down 1$/ { k[4] = "control " }
+	/^down 4$/ { k[5] = "start " }
+
+	/^up 5$/ { k[0] = "" }
+	/^up 6$/ { k[0] = "" }
+	/^up 7$/ { k[0] = "" }
+	/^up 8$/ { k[0] = "" }
+	
+	/^up 9$/ { k[3] = "" }
+	/^up 10$/ { k[2] = "" }
+	/^up 16$/ { k[3] = "" }
+	/^up 14$/ { k[2] = "" }
+	/^up 1$/ { k[4] = "" }
+	/^up 4$/ { k[5] = "" }
+
+	/^up|down/ {
+		if(joy != "")
+			printf "joy%s ", joy
+		for(i = 0; i <= 5; i++)
+			printf k[i]
+		printf "\n"
+		fflush
+	}
+'
--- /dev/null
+++ b/bin/k
@@ -1,0 +1,27 @@
+#!/bin/rc
+# k - mark position (from sam)
+
+marks=$ws/marks
+if(~ $#marks 0)
+	marks=/tmp/marks.default
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -c
+		>$marks; exit
+	case -p
+		plumb -d edit $marks
+	case -v
+		test -f $marks && window 'label marks; tail -f '$marks
+		exit
+	case *;
+		exit usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+	
+if(~ $#% 0)
+	exit notsam
+echo $%:$'%l' $* >>$marks
--- /dev/null
+++ b/bin/kprint
@@ -1,0 +1,6 @@
+#!/bin/rc
+w h 0.2 Down Right 
+>/dev/text
+label /dev/kprint
+echo scroll > /dev/wctl
+cat /dev/kprint
--- /dev/null
+++ b/bin/last
@@ -1,0 +1,21 @@
+#!/bin/rc
+
+# Repeats on standard output the textual output
+# of the last command in a current rio window.
+# May be considered a complement to "(1).
+
+awk '
+	/^'^$prompt(1)^'/ {clear = 1; next}
+	{
+		if(clear){
+			clear = 0
+			i = 0
+			delete buf
+		}
+		buf[i++] = $0
+	}
+	END{
+		for(i=0; i<length(buf); i++)
+			print buf[i]
+	}
+' /dev/text
--- /dev/null
+++ b/bin/lc
@@ -1,0 +1,10 @@
+#!/bin/rc
+rfork en
+d=/n/ram
+f=$d/list
+
+ramfs -m $d
+ls -pF $* >$f
+
+grep '/$' $f | mc
+grep -v '/$' $f | mc
--- /dev/null
+++ b/bin/live
@@ -1,0 +1,60 @@
+#!/bin/rc
+# live 'grep ~ *'
+# tilde will be replaced by the typed text, enter runs the
+# command. there's a very limited line-editing in the form
+# of backspace, and ^W and ^U, which just kill the whole line.
+rfork e
+bs=''
+cu=''
+cw=''
+del=''
+nl=`{unicode -t 0x0a}
+cmd0=$1
+cmd=echo
+killme=please
+fn prep {
+	n=`{wc -c /env/buf}
+	if(! ~ $n(1) 0){
+		cmd=`{echo $cmd0 | sed 's/~/'^`{cat /env/buf}^'/'}
+		echo -n $cmd
+	}
+	if not
+		echo -n $cmd0
+}
+fn run {
+	echo $cmd
+	@{eval $cmd} &
+	killme=$apid
+}
+fn stop {
+	if(test -f /proc/$killme/notepg)
+		echo kill >/proc/$killme/notepg
+}
+>/env/buf
+>/dev/text
+echo scroll >/dev/wctl
+>[3]/dev/consctl </dev/cons {
+	echo rawon >[1=3]
+	while(c=`{read -c 1}){
+		>/dev/text
+		switch($c){
+		case $"nl
+			run
+		case $del
+			stop
+			exit
+		case $cw $cu
+			stop
+			>/env/buf
+			prep
+		case $bs
+			stop
+			read -c `{echo `{wc -c </env/buf} - 1 | bc} </env/buf >/env/tmp
+			cp /env/tmp /env/buf
+			prep
+		case *
+			echo -n $"c >>/env/buf
+			prep
+		}
+	}
+}
--- /dev/null
+++ b/bin/loc
@@ -1,0 +1,21 @@
+#!/bin/rc
+# Print the address of a selection in acme
+nl='
+'
+w=/mnt/acme/$winid
+tag=`{cat $w/tag}
+fn regexaddr {
+	echo 'addr=dot' >$w/ctl
+	sel=`$nl{escape <$w/xdata}
+	addr=$tag(1)^':/^'$sel
+	echo $addr
+}
+fn charaddr {
+	echo 'addr=dot' >$w/ctl
+	addr=`{cat <$w/addr}
+	echo $tag(1)^':#'^$addr(1)^',#'^$addr(2)
+}
+addrfn=regexaddr
+if(test $#* -gt 0 && ~ $1 -c)
+	addrfn=charaddr
+$addrfn
--- /dev/null
+++ b/bin/local
@@ -1,0 +1,21 @@
+#!/bin/rc -e
+
+if(~ $#ws 0)
+	ws=/tmp
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -r
+		. $ws/mounts
+		plumb 'Local . '$ws'/mounts'
+		exit
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+
+echo $"* >>$ws/mounts 
+uniq $ws/mounts >$ws/mounts.q
+mv $ws/mounts.q $ws/mounts
+
+eval $* && plumb 'Local '$"*
--- /dev/null
+++ b/bin/lsman
@@ -1,0 +1,6 @@
+#!/bin/rc
+sect=1
+if(test $#* -gt 0)
+	sect=$*
+for(s in $sect)
+	ls /sys/man/$s | sed '/(INDEX|NOTICE)/d; s/^.*\///g; s/.*/&\('$s'\)/g' | mc
--- /dev/null
+++ b/bin/mkfont
@@ -1,0 +1,29 @@
+#!/bin/rc
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='mkfont [-s sizes] [-m method] fontname'
+
+rfork e
+method=antialias
+sz=(14 16 18 20)
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -m
+		method=$2; shift
+	case -s
+		sz=$2; shift
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(~ $#* 0)
+	usage
+fntname=$1
+shift
+fntfile=$fntname.ttf
+if(~ $#* 1)
+	fntfile=$1
+for(s in $sz)
+	ttf2subf -s $s -f $fntfile -n $fntname -m $method
--- /dev/null
+++ b/bin/mkservice
@@ -1,0 +1,25 @@
+#!/bin/rc
+rfork e
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='mkservice path'
+
+svpath = $1
+if(~ $#svpath 0)
+	usage
+svname = `{basename $svpath}
+cat <<. |x/run
+	set -e
+	mkdir -p $svpath
+	cd $svpath
+	touch run
+	chmod +x run
+	echo '#!/bin/sh' >>run
+	echo 'exec 2>&1' >>run
+	echo 'exec sleep 10' >>run
+	
+	mkdir log
+	touch log/run
+	chmod +x log/run
+	echo '#!/bin/sh' >>log/run
+	echo 'exec logger -t $svname -p daemon.notice' >>log/run
+.
--- /dev/null
+++ b/bin/mktxt
@@ -1,0 +1,5 @@
+#!/bin/rc
+f=/fd/0
+if(test $#* -gt 0)
+	f=$*
+troff -man -N -rL1000i $f | ssam 'x/\n\n\n+/c/\n\n/'
--- /dev/null
+++ b/bin/mnt
@@ -1,0 +1,54 @@
+#!/bin/rc
+
+fn usage {
+	>[1=2] {
+	echo mnt [mount options] [-m mtpt] [-s spec] name cmd [args ...]
+	echo mnt [mount options] [-m mtpt] [-s spec] name
+	}
+	exit usage
+}
+
+flags=()
+mtpt=()
+spec=()
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -m
+		mtpt=$2
+		shift
+	case -s
+		spec=$2
+		shift
+	case *
+		flags=($flags $1)
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+name=$1
+if(~ $#name 0)
+	usage
+shift
+if(~ $#mtpt 0)
+	mtpt=/n/$name
+cmd=$1
+if(! ~ $#cmd 0)
+	shift
+
+if(mount $flags /srv/$name $mtpt $spec )
+	exit
+if(~ $#cmd 0)
+	usage
+switch($cmd){
+case srv srvtls
+	$cmd $* $name
+case rimport
+	rimport $flags -s $name $* $mtpt
+	exit
+case ramfs
+	ramfs -S $name $*
+case *
+	$cmd -s $name $*
+}
+mount $flags /srv/$name $mtpt $spec
--- /dev/null
+++ b/bin/new
@@ -1,0 +1,37 @@
+#!/bin/rc -e
+rfork e
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='new [file]'
+
+mode = 755
+skeldir = $home/skel
+skel = $skeldir/rc
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -m
+		mode = $2
+		shift
+	case --*
+		skel = $skeldir/`{echo $1 | sed 's/^--//'}
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+
+files = $*
+if(~ $#files 0)
+	files =`{fortune <{</lib/words awk 'length($0) == 3 {print tolower($0)}'}}
+
+for(f in $files){
+	if(~ $f */*)
+		mkdir -p `{echo $f | sed 's@(.*)/.*$@\1@'}
+	if(test -e $f)
+		>[1=2] echo 'file exists:' $f
+	if not{
+		echo $f
+		cat $skel >$f
+		chmod $mode $f
+		plumb -d edit $f
+	}
+}
--- /dev/null
+++ b/bin/nsec
@@ -1,0 +1,2 @@
+#!/bin/ci
+print("%lld\n", nsec());
--- /dev/null
+++ b/bin/nu
@@ -1,0 +1,2 @@
+#!/bin/awk -f
+{printf("%d\t%s\n", NR, $0)}
--- /dev/null
+++ b/bin/p
@@ -1,0 +1,6 @@
+#!/bin/rc
+# put [register]
+where=/dev/snarf
+if(! ~ $#* 0)
+	where=/env/$1
+echo '<cat '$where
--- /dev/null
+++ b/bin/paste
@@ -1,0 +1,18 @@
+#!/bin/rc -e
+rfork en
+fn usage {
+	>[2=1] echo $0
+	exit usage
+}
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+9fs www
+for(a)
+	cp $a /n/www/tmp
--- /dev/null
+++ b/bin/pfx
@@ -1,0 +1,9 @@
+#!/bin/rc
+args=()
+for(arg){
+	if(echo $arg | grep -s '[ 	]')
+		args=($args ''''$arg'''')
+	if not
+		args=($args $arg)
+}
+sed 's:^:'^$"args^' :g'
--- /dev/null
+++ b/bin/pins
@@ -1,0 +1,14 @@
+#!/bin/rc
+dir=$1
+if(~ $#dir 0)
+	dir='out'
+</dev/audiostat awk '
+/^pin [0-9]+ '$dir'/ {
+	printf "@{echo pin %d>/dev/audioctl} #", $2
+	for(i = 4; i <= NF; i++){
+		if($i == "←")
+			break
+		printf " %s", $i
+	}
+	printf "\n"
+}'
--- /dev/null
+++ b/bin/plumb.dir
@@ -1,0 +1,21 @@
+#!/bin/rc
+rfork e
+fn usage {
+	>[2=1] echo $0
+	exit usage
+}
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+
+t=/dev/wsys/`{cat $wsdir/target}^/text
+echo cd $1 >/tmp/text
+cat $t >>/tmp/text
+cp /tmp/text $t
--- /dev/null
+++ b/bin/pwds
@@ -1,0 +1,3 @@
+#!/bin/rc
+cat /dev/text >/tmp/xxx
+cat <{echo -n 'cd '; pwd} /tmp/xxx >/dev/text
--- /dev/null
+++ b/bin/raiseplumb
@@ -1,0 +1,20 @@
+#!/bin/rc
+rfork e
+
+fn usage {
+	echo $0 port >[1=2]
+	exit usage
+}
+
+port=$1
+if(~ $#port 0)
+	usage
+{
+	while(read -c 1 /mnt/plumb/$port >/dev/null){
+		>/dev/wctl >[2]/dev/null {
+		echo -n current
+		echo -n unhide
+		}
+	}
+} &
+echo -n `{cat /proc/$pid/noteid} > /proc/$apid/noteid
--- /dev/null
+++ b/bin/rand
@@ -1,0 +1,9 @@
+#!/bin/awk -f
+BEGIN {
+	srand()
+	n = 1
+	if(ARGC == 2)
+		n = ARGV[1]
+	for(i = 0; i < n; i++)
+		print int(rand()*100)
+}
--- /dev/null
+++ b/bin/rawwer
@@ -1,0 +1,21 @@
+#!/bin/rc
+rfork e
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='rawwer cmd'
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+cmd = $*
+if(~ $#cmd 0)
+	usage
+>[3]/dev/consctl </dev/cons{
+	echo rawon >[1=3]
+	exec $cmd
+}
--- /dev/null
+++ b/bin/recv
@@ -1,0 +1,12 @@
+#!/bin/rc
+fn usage {
+	>[2=1] echo 'recv port [file]'
+	exit usage
+}
+port=$1
+if(~ $#port 0)
+	usage
+file=$2
+if(~ $#file 0)
+	file=/fd/1
+>[9=1] >[9]$file aux/listen1 -t tcp!*!$port rc -c '/bin/cat >[1=9]'
--- /dev/null
+++ b/bin/regidx
@@ -1,0 +1,6 @@
+#!/bin/rc
+mtpt=/mnt/registry
+if(test $#* -gt 0)
+	mtpt=$1
+awk '/tlssrv/{print "srvtls -c", $1, $3, $5}
+/exportfs/{print "srv -c", $1, $3, $5 }' $mtpt/index
--- /dev/null
+++ b/bin/rfc
@@ -1,0 +1,42 @@
+#!/bin/rc
+rfork e
+fn usage {
+	>[2=1] echo $0
+	exit usage
+}
+
+cmd='search'
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -s
+		cmd='search'
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+
+fn cleanupindex {
+	</lib/rfc/rfc-index awk '
+		/^ +RFC INDEX/ {i++; l = NR}
+		i >= 2 && NR > l+4 {print}
+	'
+}
+
+fn search {
+	query=$1
+	cleanupindex | awk '
+		BEGIN {RS=""}
+		/'$query'/ {
+			num = $1
+			sub(/^0+/, "", num)
+			print "RFC" num
+			sub(/^..../, "    ", $0)
+			print $0
+		}
+	'
+}
+
+$cmd $*
--- /dev/null
+++ b/bin/rn
@@ -1,0 +1,8 @@
+#!/bin/rc
+from=$1
+to=$2
+charconst='''[^'']*'''
+strconst='"([^"]|\\")*"'
+name='[a-zA-Z_][a-zA-Z_0-9]*'
+partial=.^`{echo -n $from | tr -c '' .}
+exec ssam 'y/'$charconst'/ y/'$strconst'/ x/'$name'/ g/'$from'/ v/'$partial'/ c/'$to
--- /dev/null
+++ b/bin/rs
@@ -1,0 +1,2 @@
+#!/bin/rc
+grep softscreen /dev/vgactl >/dev/vgactl
--- /dev/null
+++ b/bin/rwin
@@ -1,0 +1,12 @@
+#!/bin/rc
+rfork en
+if(test -f /mnt/acme/index){ # in acme
+	unmount /acme/bin/amd64 /bin 
+	unmount /acme/bin /bin 
+	tag=`{cat /mnt/acme/$winid/tag}
+	dir=`{basename -d $tag(1)}
+}
+if not{ # in sam
+	dir=`{basename -d $%}
+}
+exec window -m -cd $dir $*
--- /dev/null
+++ b/bin/samchat
@@ -1,0 +1,14 @@
+#!/bin/rc
+chan=/n/chat/chat
+bind '#|' /mnt/samchat
+data=/mnt/samchat/data1
+{
+	while(){
+		<$data >>$chan ssam '
+			1 x/^/ c/'$user' : /
+			,s/\n\n\n+/\n\n/g
+			$-2,$-1 s/\n\n/\n/
+			$-#1,$ v/\n/ a/\n/'
+	}
+} &
+echo `{cat /proc/$pid/noteid} >/proc/$apid/noteid
--- /dev/null
+++ b/bin/samcmd
@@ -1,0 +1,16 @@
+#!/bin/awk -f
+BEGIN{
+	plumb = "plumb -i -d edit -a 'action=Edit'"
+	if(ARGC > 1){
+		for(i = 1; i < ARGC; i++)
+			cmd = cmd " " ARGV[i]
+		print cmd | plumb
+		exit
+	}
+}
+{
+	if($1 == "!")
+		$0 = last
+	print | plumb; close(plumb)
+	last = $0
+}
--- /dev/null
+++ b/bin/samv
@@ -1,0 +1,17 @@
+#!/bin/rc
+# samv [-m] [samflags] [file ...]
+rfork e
+flags=(-a)
+while(~ $1 -*){
+	switch($1){
+	case *
+		flags=($flags $1)
+	}
+	shift
+}
+files=($%)
+if(! ~ $#* 0)
+	files=($files $*)
+cmd=(sam $flags $files)
+#ptrap edit $"files
+window -m $cmd
--- /dev/null
+++ b/bin/scr
@@ -1,0 +1,6 @@
+#!/bin/rc
+rfork e
+dst=/tmp/scr.png
+if(! ~ $#* 0)
+	dst=$1
+topng /dev/screen >$dst
--- /dev/null
+++ b/bin/scratch
@@ -1,0 +1,7 @@
+#!/bin/rc
+if(test $#* -ge 1){
+	>$1
+	window -m hold $1
+}
+if not
+	window hold
--- /dev/null
+++ b/bin/share
@@ -1,0 +1,53 @@
+#!/bin/rc
+# share - share files with the grid
+# Uploads a given file to a shared griddisk (gridram with -r)
+# directory and plumbs the resulting file path (web url with -w).
+# Option -n disables plumbing.
+rfork en
+fn usage{
+	echo share [-rwn] file [destdir] >[1=2]
+	exit usage
+}
+plumb='yes'
+urlplumb='no'
+dest='griddisk'
+if(~ $#* 0) usage
+while(! ~ $#* 0 && ~ $1 -*){
+	switch($1){
+		case -n
+			plumb='no'
+		case -r
+			dest='gridram'
+			urlplumb='no'
+		case -w
+			dest='griddisk'
+			urlplumb='yes'
+		case *
+			usage
+	}
+	shift
+}
+switch($dest){
+	case gridram
+		destdir=''
+	case griddisk
+		destdir='tmp'
+}
+if(~ $#* 2)
+	destdir=$2
+file=$1
+destpath=/n/$dest/$destdir
+if(! test -d $destpath)
+	mkdir -p $destpath
+fcp $file $destpath
+if(~ $plumb no)
+	exit
+if(test -e /srv/gridplumber)
+	mount /srv/gridplumber /mnt/plumb
+if(~ $urlplumb no)
+	plumb $destpath/`{basename $file}
+if not {
+	url='http://wiki.9gridchan.org/incoming/'$destdir/`{basename $file}
+	echo $url
+	plumb $url
+}
--- /dev/null
+++ b/bin/shr
@@ -1,0 +1,14 @@
+#!/bin/rc
+fn die {>[1=2] echo $*; exit $"*}
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='shr srv [name]'
+if(~ $#* 0)
+	usage
+srv=$1
+name=$srv
+if(~ $#* 2)
+	name=$2
+if(! test -e /srv/$srv)
+	die 'service does not exist:' $srv
+mkdir '#σc'/$name
+<>[3]/srv/$srv >'#σc'/$name/$srv echo 3
--- /dev/null
+++ b/bin/sio
@@ -1,0 +1,30 @@
+#!/bin/rc -e
+rfork e
+overwrite=no
+data=/tmp/sio.$pid
+>$data
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -i
+		cat >$data
+	case -f
+		overwrite=yes
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(! ~ $#* 0){
+	switch($1){
+	case /*
+		ndata=$1
+	case *
+		ndata=/tmp/sio.$1
+	}
+	if(~ $overwrite yes)
+		mv $data $ndata
+	data=$ndata
+}
+
+sam -a $data
+cat $data
--- /dev/null
+++ b/bin/snarfy
@@ -1,0 +1,5 @@
+#!/bin/rc
+rfork n
+aux/stub /mnt/snarfy/snarf
+bind -c /dev/snarf /mnt/snarfy/snarf
+aux/listen1 -t tcp!*!2000 /bin/exportfs -r /mnt/snarfy &
--- /dev/null
+++ b/bin/sparse
@@ -1,0 +1,7 @@
+#!/bin/rc
+if(~ $#* 0)
+	exit 'usage'
+name=$1
+shift
+sz=$*
+dd -if /dev/zero -of $name -seek `{sz $sz} -bs 1 -count 1
--- /dev/null
+++ b/bin/srvq
@@ -1,0 +1,23 @@
+#!/bin/rc
+rfork e
+
+fn usage {
+	>[2=1] echo $0 name service [proto]
+	exit usage
+}
+
+if(test $#* -lt 1)
+	usage
+name=$1
+service=$2
+if(~ $#service 0)
+	service='ssh'
+proto=$3
+if(~ $#proto 0)
+	proto='tcp'
+
+rr=`{echo _$service._$proto.$name srv | ndb/dnsquery >[2]/dev/null}
+if(echo $rr | grep -s '^!dns:')
+	exit NXDOMAIN
+echo $rr |
+	awk '{printf("%s!%s!%s\n", ENVIRON["proto"], $6, $5)}'
--- /dev/null
+++ b/bin/stash
@@ -1,0 +1,10 @@
+#!/bin/rc
+rfork e
+fn usage {
+	>[2=1] echo $0
+	exit usage
+}
+
+cat >/tmp/stash.in
+cp /dev/text /tmp/stash.text
+cat /tmp/stash.in /tmp/stash.text >/dev/text
--- /dev/null
+++ b/bin/struct
@@ -1,0 +1,32 @@
+#!/bin/rc
+rfork en
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='struct [-s] [regex] [files]'
+
+regex=()
+files=()
+search='.'
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -s
+		search='/sys/include'
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+
+regex=$1
+if(~ $#regex 0)
+	regex='[a-zA-Z_][a-zA-Z_0-9]*'
+if(test $#* -gt 1)
+	files=$*(2-)
+if not
+	files=`{walk -f $search | grep '\.[ch]$'}
+
+echo 'X ,x/^struct([^}][^;]*\n*)+};\n/ g/^struct[ 	]+'$regex'/ {
+	!echo $%:$%l
+	p
+}' | sam -d $files >[2]/dev/null
--- /dev/null
+++ b/bin/struct.old
@@ -1,0 +1,81 @@
+#!/bin/rc
+# struct - find C struct definitions
+rfork e
+
+fn usage {
+	>[2=1] echo struct [-pr] [pattern] [path ...]
+	exit usage
+}
+
+plumb=0
+recursive=0
+tag='%'
+include=(. /sys/include /$cputype/include)
+while(! ~ $#* 0 && ~ $1 -*){
+	switch($1){
+	case -p
+		plumb=1
+	case -r
+		recursive=1
+	case *
+		usage
+	}
+	shift
+}
+if(! ~ $#* 0){
+	tag=$1
+	shift
+}
+if(! ~ $#* 0)
+	include=$*
+
+wf=(-f)
+if(~ $recursive 0)
+	wf=($wf -n1)
+files=`{walk $wf $include | grep '\.[ch]$'}
+if(~ $#files 0)
+	exit 'no files'
+
+awk '
+BEGIN {
+	plumb = ENVIRON["plumb"]
+	tag = ENVIRON["tag"]
+	if(match(tag, /%/))
+		gsub(/%/, "[a-zA-Z0-9_]+", tag)
+	tag = "[ 	]" tag "[ 	{]?"
+}
+/^[ 	]*(typedef|struct|union|enum)[ 	]+(typedef|struct|union|enum)?[ 	]*([a-zA-Z_][a-zA-Z0-9_]*)?[ 	]*{/ {
+	loc = FILENAME ":" FNR
+	if(match($0, "[ 	]*}[ 	]*;[ 	]*$") && match($0, tag)){
+		if(plumb)
+			system("plumb -d edit " loc)
+		else
+			printf("%s\n%s\n", loc, $0)
+		next
+	}
+	collect = 1
+	found = 0
+	if(match($0, tag))
+		found = 1
+	if(found && plumb){
+		system("plumb -d edit " loc)
+		next
+	}
+}
+collect { ln[i++] = $0 }
+collect && /^}/{
+	if(found || match($0, tag)){
+		print loc
+		for(j = 0; j < length(ln); j++)
+			print ln[j]
+	}
+	collect = 0
+	found = 0
+	i = 0
+	delete ln
+}
+END{
+	if(found == 0)
+		exit "not found"
+}
+' $files
--- /dev/null
+++ b/bin/sz
@@ -1,0 +1,16 @@
+#!/bin/rc
+# sz -- convert computer units to bytes
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='sz x'
+
+{
+	echo -n $1 | tr -d 'a-zA-Z'
+	echo -n '*'
+	switch($1){
+	case *[kK]; echo '1024'
+	case *[mM]; echo '1024*1024'
+	case *[gG]; echo '1024*1024*1024'
+	case *[tT]; echo '1024*1024*1024*1024'
+	case *;     echo '1'
+	}
+} | bc
--- /dev/null
+++ b/bin/thes
@@ -1,0 +1,7 @@
+#!/bin/rc
+url=https://www.merriam-webster.com/thesaurus
+word=`{echo $"* | sed 's/[ 	]/\+/g'}
+if(~ $#word 0)
+	exit
+hget $url/$word | htmlfmt | ssam '0,/^Thesaurus/+ d
+/^Learn More/-3,$ d'
--- /dev/null
+++ b/bin/trim
@@ -1,0 +1,2 @@
+#!/bin/rc
+exec sed 's,[ 	]+$,,g; s,^[ 	]+,,g'
--- /dev/null
+++ b/bin/tty
@@ -1,0 +1,3 @@
+#!/bin/rc
+rfork e
+window vt -c ssh $*
--- /dev/null
+++ b/bin/var
@@ -1,0 +1,16 @@
+#!/bin/rc
+# var - find C variable declarations
+# var [pattern]
+rfork e
+
+ident='([a-zA-Z_][a-zA-Z_0-9]*)'
+var=$1
+var=`{echo $var | sed 's,%,'$ident'?,g'}
+if(~ $#var 0)
+	var=$ident
+cat >/env/decl <<.
+[ 	]*$ident([\* 	]+$ident[, 	]*)*([\* 	]+$var[, 	]*)+([\* 	]+$ident[, 	]*)*(;|=[^=]*)$
+.
+falsematch='(return|goto|typedef)[ 	]+';
+srcs=`{walk -f | grep '\.[chy]$'}
+grep -n -e `''{cat /env/decl} $srcs /dev/null | grep -v $falsematch | sed 's,[ 	]+, ,g'
--- /dev/null
+++ b/bin/vm
@@ -1,0 +1,24 @@
+#!/bin/rc -e
+rfork en
+fn usage {>[2=1] echo 'usage:' $usage && exit 'usage'}
+usage='vm name'
+
+fn alp {
+	name='alp'
+	root=$home/vmx/$name
+	mem=(-M 1G)
+	net=(-n ether0)
+	disk=(-d /dev/sdE0/disk0)
+	video=(-v vesa:640x480)
+	initrd=(-m initramfs-virt)
+	kernel=(vmlinuz-virt 'root=/dev/vda3' 'rootfstype=ext4')
+	cd $root
+	exec vmx $mem $disk $net $video $initrd $kernel
+}
+
+if(~ $#* 0)
+	usage
+select=$1; shift
+echo scrollon >/dev/wctl
+label $select
+$select
--- /dev/null
+++ b/bin/vmxcons
@@ -1,0 +1,10 @@
+#!/bin/rc
+name=$1
+if(~ $#name 0)
+	name='vmx'
+bind '#|' /n/p
+<>[3]/n/p/data1 {
+	rm -f /srv/$name
+	echo 3 >/srv/$name.cons
+	vt con /n/p/data
+}
--- /dev/null
+++ b/bin/vmxkill
@@ -1,0 +1,6 @@
+#!/bin/rc
+for(x in (0 1 2 3 4)){
+	f='#X/'^$x^'/ctl'
+	if(test -e $f)
+		echo 'quit' > $f
+}
--- /dev/null
+++ b/bin/vol
@@ -1,0 +1,28 @@
+#!/bin/rc -e
+rfork e
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='vol [-+] | [+-]vol | vol'
+
+fn expr {
+	switch($2){
+	case [-+][0-9]*
+		echo $1 $2 | bc
+	case - +
+		echo $1 $2 5 | bc
+	case *
+		echo $2
+	}
+}
+
+if(~ $#* 0)
+	usage
+
+vol=`{awk '/master/ {print $2, $3}' </dev/volume}
+switch($#*){
+case 1
+	vol=(`{expr $vol(1) $1})
+case 2
+	vol=(`{expr $vol(1) $1} `{expr $vol(2) $2})
+}
+echo master $vol
+echo master $vol >/dev/volume
--- /dev/null
+++ b/bin/w
@@ -1,0 +1,193 @@
+#!/bin/rc
+
+rfork
+
+fn usage {
+	echo 'w find [regex ...]'
+	echo 'w [-t regex] cmd ...'
+	echo 'Where cmd is one or more of the following:'
+	echo '  -c wctl'
+	echo '  hide|show'
+	echo '  bottom'
+	echo '  left|Left|center|right|Right'
+	echo '  up|Up|down|Down'
+	echo '  height|width [factor]'
+	echo '  stack [offset]'
+	echo '  tile'
+	exit usage
+}
+
+fn isnum {
+	echo $1 | grep -s '^[0-9\.]+$'
+}
+
+fn append {
+	echo $* >>/env/wctlcmd
+}
+
+fn wfind {
+	for(w in /dev/wsys/*)
+		grep -s $1 $w/label && echo $w | sed 's~.*/~~'
+}
+
+fn wwidth {
+	wf=$1
+	dx=`{echo '('$riow'-'$borderoff')*'$wf | bc | sed 's~\..*~~'}
+	append 'resize -dx '$dx
+}
+
+fn wheight {
+	hf=$1
+	dy=`{echo '('$rioh'-'$borderoff')*'$hf | bc | sed 's~\..*~~'}
+	append 'resize -dy '$dy
+}
+
+fn wmove {
+	where=$1
+	win=`{read -c 48 /dev/wsys/$wid/wctl >[2]/dev/null}
+	dx=`{echo $win(3) - $win(1) | bc}
+	dy=`{echo $win(4) - $win(2) | bc}
+	switch($where){
+	case down ; append move -miny +$dy
+	case up ; append move -miny -$dy
+	case left ; append move -minx -$dx
+	case right ; append move -minx +$dx
+	case Left centerx Right
+		switch($where){
+		case Left ; x=0
+		case centerx ; x=`{echo $riow / 2 - $dx / 2 | bc}
+		case Right ; x=$riow
+		}
+		append move -minx $x
+	case Down centery Up
+		switch($where){
+		case Down ; y=$rioh
+		case centery ; y=`{echo $rioh / 2 - $dy / 2 | bc}
+		case Up ; y=0
+		}
+		append move -miny $y
+	}
+}
+
+fn wstack {
+	off=$1
+	dirx=+
+	diry=+
+	if(test $bx -gt `{echo $riow / 2 - $off'*'$#wids | bc})
+		dirx=-
+	if(test $by -gt `{echo $rioh / 2 - $off'*'$#wids | bc})
+		diry=-
+	append move -minx $bx -miny $by
+	append move -minx $dirx$stackoff -miny $diry$stackoff
+	stackoff=`{echo $off + $stackoff | bc}
+}
+
+fn wtile {
+	@{
+		if(~ $didtile true)
+			exit
+		tf=0.`{echo 1000 / $#wids | bc}
+		for(i in `{seq 1 $#wids}){
+			for(n in `{seq 2 $i})
+				d=($d down)
+			wids=$wids($i) dow h $tf U $d
+			d=()
+		}
+	}
+	didtile=true
+}
+
+fn parse {
+	append unhide
+	append current
+	for(arg){
+		switch($1){
+		case -c ; append $2; shift
+		case width w
+			if(isnum $2){wwidth $2; shift}
+			if not {
+				x=`{stringsize -n 82}
+				x=$x(1)
+				wwidth `{echo $x' / '$riow | hoc}
+			}
+		case height h
+			if(isnum $2){wheight $2; shift}
+			if not {
+				y=`{stringsize}
+				y=$y(2)
+				wheight `{echo '(23*'$y') / '$rioh | hoc}
+			}
+		case right r ; wmove right
+		case Right R ; wmove Right
+		case left l ; wmove left
+		case Left L ; wmove Left
+		case up u ; wmove up
+		case Up U ; wmove Up
+		case down d ; wmove down
+		case Down D ; wmove Down
+		case centerx cx ; wmove centerx
+		case centery cy ; wmove centery
+		case center c ; wmove centery; wmove centerx
+		case hide hi ; append hide; return=false
+		case show s ; append top
+		case delete del ; append delete; return=false
+		case bottom b ; append bottom; return=false
+	 	case stack
+			if(isnum $2){wstack $2; shift}
+			if not {wstack 15}
+		case tile ; wtile
+		case find f
+			if(~ $#* 2) {wfind $2; shift}
+			if not {wfind '.*'}
+		}
+		shift
+	}
+}
+
+fn dow {
+	for(wid in $wids){
+		parse $*
+		read -m /env/wctlcmd >>/dev/wsys/$wid/wctl
+		>/env/wctlcmd
+	}
+	if(~ $return true)
+		echo current >>/dev/wsys/$bwid/wctl
+}
+
+>/env/wctlcmd
+wid=()
+wids=()
+border=0
+borderoff=0
+stackoff=0
+return=true
+didstack=false
+didtile=false
+scr=/dev/screen
+if(test -e /mnt/orio/window){ # we're in subrio
+	scr=/mnt/orio/window # refers to the subrio window
+	border=2
+	borderoff=4
+}
+rioscr=`{read -c 59 $scr}
+riox=$rioscr(2)
+rioy=$rioscr(3)
+riow=`{echo $rioscr(4) - $rioscr(2) | bc}
+rioh=`{echo $rioscr(5) - $rioscr(3) | bc}
+bwid=`{cat /dev/winid}
+bwin=`{read -c 48 /dev/wctl >[2]/dev/null}
+bx=`{echo $bwin(1) - $riox - $border | bc}
+by=`{echo $bwin(2) - $rioy - $border | bc}
+wids=`{cat /dev/winid}
+
+if(~ $#* 0)
+	dow w h 1
+while(~ $1 -*){
+	switch($1){
+		case -t
+			wids=`{wfind $2}
+			shift
+	}
+}
+dow $*
+exit 0
--- /dev/null
+++ b/bin/web
@@ -1,0 +1,57 @@
+#!/bin/rc
+rfork e
+
+url='http://'
+query=()
+browser=plumb
+
+fn usage {
+	echo 'usage: web [option] text...' >[1=2]
+	echo '	-g	google'
+	echo '	-gi	google image'
+	echo '	-d	duckduckgo'
+	echo '	-di	duckduckgo image'
+	echo '	-w	wikipedia'
+	echo '	-t		thesaurus'
+	echo '	-D	dictionary'
+	echo '	-b	libgen.io'
+	echo '	-h	display this message'
+	echo '	-B browser'
+	exit 'usage'
+}
+
+if(~ $#* 0)
+	usage
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case -h
+		usage; exit
+	case -B
+		browser=$2
+		shift
+	case -g
+		url='http://google.com/search?q='
+	case -gi
+		url='http://google.com/images?q='
+	case -d
+		url='http://duckduckgo.com/lite/?q='
+	case -di
+		url='http://duckduckgo.com/html/?q=!bi+'
+	case -w
+		url='http://en.m.wikipedia.org/w/index.php?search='
+	case -hw
+		url='http://hr.m.wikipedia.org/w/index.php?search='
+	case -b
+		url='http://libgen.me/search.php?req='
+	case -t
+		url='https://www.merriam-webster.com/thesaurus/'
+	case -D
+		url='https://www.merriam-webster.com/dictionary/'
+	case -m
+		url='https://marc.info/?l='
+	}
+	shift
+}
+query=`{echo $"* | sed 's:[ 	]:\+:g'}
+$browser $url^$"query
--- /dev/null
+++ b/bin/wiki
@@ -1,0 +1,5 @@
+#!/bin/rc
+title=`{echo $* | sed 's: :_:g'}
+mkdir -p /tmp/wiki
+hget 'http://en.wikipedia.org/api/rest_v1/page/html/'$title >/tmp/wiki/$title
+echo plumb 'file:///tmp/wiki/'$title
--- /dev/null
+++ b/bin/wrap
@@ -1,0 +1,24 @@
+#!/bin/rc
+rfork e
+fn usage {>[1=2] echo 'usage:' $usage && exit 'usage'}
+usage='wrap start [end]'
+
+while(~ $1 -* && ! ~ $1 --){
+	switch($1){
+	case *
+		usage
+	}
+	shift
+}
+if(~ $1 --)
+	shift
+if(~ $#* 0)
+	usage
+	
+s0 = $1
+s1 = $2
+if(~ $#* 1)
+	s1 = $s0
+echo -n $s0
+cat
+echo -n $s1
--- /dev/null
+++ b/bin/wtr
@@ -1,0 +1,4 @@
+#!/bin/rc
+if(~ $#1 0)
+	loc=varazdin
+hget http://wttr.in/~$loc.png | page -w
--- /dev/null
+++ b/bin/y
@@ -1,0 +1,6 @@
+#!/bin/rc
+# yank [register]
+where=/dev/snarf
+if(! ~ $#* 0)
+	where=/env/$1
+echo '>cat >'$where
--- /dev/null
+++ b/bin/z
@@ -1,0 +1,2 @@
+#!/bin/rc
+x/run $*