Commit Diff


commit - cb27443abf3d6af6ab52377c71c843e619928433
commit + 8ad517944e46710ab832350c0dc3fc4e9239f7e2
blob - befea2e347dc0e8a5abfeafbfc5e904a4be5cefe
blob + 4cee8fb5f25dd82649ab4b4704dc1229dc2f5f46
--- include/fmt.h
+++ include/fmt.h
@@ -80,6 +80,7 @@ extern	int	fmtfdflush(Fmt*);
 extern	int	fmtstrinit(Fmt*);
 extern	char*	fmtstrflush(Fmt*);
 extern	int	runefmtstrinit(Fmt*);
+extern	Rune*	runefmtstrflush(Fmt*);
 
 extern	int	quotestrfmt(Fmt *f);
 extern	void	quotefmtinstall(void);
blob - 1373ce1507f32799232f7be5c3997021c7c05c68
blob + 07a1f976581732cfc565e5e3fbb8ac3cbc9a6784
--- include/lib9.h
+++ include/lib9.h
@@ -1,874 +1,2 @@
-/*
- * Lib9 is miscellany from the Plan 9 C library that doesn't
- * fit into libutf or into libfmt, but is still missing from traditional
- * Unix C libraries.
- */
-#ifndef _LIB9_H_
-#define _LIB9_H_ 1
-#if defined(__cplusplus)
-extern "C" {
-#endif                                                                          
-
-#define _BSD_SOURCE 1
-#define _SVID_SOURCE 1
-#define _XOPEN_SOURCE 1000
-#define _XOPEN_SOURCE_EXTENDED 1
-#define _LARGEFILE64_SOURCE 1
-#define _FILE_OFFSET_BITS 64
-#define __EXTENSIONS__ 1 /* SunOS */
-
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <setjmp.h>
-#include <stddef.h>
-#include <utf.h>
-#include <fmt.h>
-#include <math.h>
-
-/*
- * OS-specific crap
- */
-#define _NEEDUCHAR 1
-#define _NEEDUSHORT 1
-#define _NEEDUINT 1
-#define _NEEDULONG 1
-
-typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
-
-#if defined(__linux__)
-#	include <sys/types.h>
-#	if defined(__USE_MISC)
-#		undef _NEEDUSHORT
-#		undef _NEEDUINT
-#		undef _NEEDULONG
-#	endif
-#endif
-#if defined(__sun__)
-#	include <sys/types.h>
-#	undef _NEEDUSHORT
-#	undef _NEEDUINT
-#	undef _NEEDULONG
-#endif
-#if defined(__FreeBSD__)
-#	include <sys/types.h>
-#	if !defined(_POSIX_SOURCE)
-#		undef _NEEDUSHORT
-#		undef _NEEDUINT
-#	endif
-#endif
-#if defined(__APPLE__)
-#	include <sys/types.h>
-#	undef _NEEDUSHORT
-#	undef _NEEDUINT
-#	define _NEEDLL 1
-#endif
-
-typedef signed char schar;
-typedef unsigned int u32int;
-#ifdef _NEEDUCHAR
-	typedef unsigned char uchar;
-#endif
-#ifdef _NEEDUSHORT
-	typedef unsigned short ushort;
-#endif
-#ifdef _NEEDUINT
-	typedef unsigned int uint;
-#endif
-#ifdef _NEEDULONG
-	typedef unsigned long ulong;
-#endif
-typedef unsigned long long uvlong;
-typedef long long vlong;
-typedef uvlong u64int;
-typedef uchar u8int;
-typedef ushort u16int;
-
-#undef _NEEDUCHAR
-#undef _NEEDUSHORT
-#undef _NEEDUINT
-#undef _NEEDULONG
-
-/*
- * Begin usual libc.h 
- */
-
-#define	nil	((void*)0)
-#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
-
-#ifndef offsetof
-#define offsetof(s, m)	(ulong)(&(((s*)0)->m))
-#endif
-
-/*
- * mem routines (provided by system <string.h>)
- *
-extern	void*	memccpy(void*, void*, int, ulong);
-extern	void*	memset(void*, int, ulong);
-extern	int	memcmp(void*, void*, ulong);
-extern	void*	memcpy(void*, void*, ulong);
-extern	void*	memmove(void*, void*, ulong);
-extern	void*	memchr(void*, int, ulong);
- */
-
-/*
- * string routines (provided by system <string.h>)
- *
-extern	char*	strcat(char*, char*);
-extern	char*	strchr(char*, int);
-extern	int	strcmp(char*, char*);
-extern	char*	strcpy(char*, char*);
- */
-extern	char*	strecpy(char*, char*, char*);
- /*
-extern	char*	strdup(char*);
-extern	char*	strncat(char*, char*, long);
-extern	char*	strncpy(char*, char*, long);
-extern	int	strncmp(char*, char*, long);
-extern	char*	strpbrk(char*, char*);
-extern	char*	strrchr(char*, int);
-extern	char*	strtok(char*, char*);
-extern	long	strlen(char*);
-extern	long	strspn(char*, char*);
-extern	long	strcspn(char*, char*);
-extern	char*	strstr(char*, char*);
- */
-extern	int	cistrncmp(char*, char*, int);
-extern	int	cistrcmp(char*, char*);
-extern	char*	cistrstr(char*, char*);
-extern	int	tokenize(char*, char**, int);
-
-/*
-enum
-{
-	UTFmax		= 3,
-	Runesync	= 0x80,
-	Runeself	= 0x80,
-	Runeerror	= 0x80,
-};
-*/
-
-/*
- * rune routines (provided by <utf.h>
- *
-extern	int	runetochar(char*, Rune*);
-extern	int	chartorune(Rune*, char*);
-extern	int	runelen(long);
-extern	int	runenlen(Rune*, int);
-extern	int	fullrune(char*, int);
-extern	int	utflen(char*);
-extern	int	utfnlen(char*, long);
-extern	char*	utfrune(char*, long);
-extern	char*	utfrrune(char*, long);
-extern	char*	utfutf(char*, char*);
-extern	char*	utfecpy(char*, char*, char*);
-
-extern	Rune*	runestrcat(Rune*, Rune*);
-extern	Rune*	runestrchr(Rune*, Rune);
-extern	int	runestrcmp(Rune*, Rune*);
-extern	Rune*	runestrcpy(Rune*, Rune*);
-extern	Rune*	runestrncpy(Rune*, Rune*, long);
-extern	Rune*	runestrecpy(Rune*, Rune*, Rune*);
-extern	Rune*	runestrdup(Rune*);
-extern	Rune*	runestrncat(Rune*, Rune*, long);
-extern	int	runestrncmp(Rune*, Rune*, long);
-extern	Rune*	runestrrchr(Rune*, Rune);
-extern	long	runestrlen(Rune*);
-extern	Rune*	runestrstr(Rune*, Rune*);
-
-extern	Rune	tolowerrune(Rune);
-extern	Rune	totitlerune(Rune);
-extern	Rune	toupperrune(Rune);
-extern	int	isalpharune(Rune);
-extern	int	islowerrune(Rune);
-extern	int	isspacerune(Rune);
-extern	int	istitlerune(Rune);
-extern	int	isupperrune(Rune);
- */
-
-/*
- * malloc (provied by system <stdlib.h>)
- *
-extern	void*	malloc(ulong);
- */
-extern	void*	p9malloc(ulong);
-extern	void*	mallocz(ulong, int);
-/*
-extern	void	free(void*);
-extern	ulong	msize(void*);
-extern	void*	calloc(ulong, ulong);
-extern	void*	realloc(void*, ulong);
- */
-extern	void		setmalloctag(void*, ulong);
-extern	void		setrealloctag(void*, ulong);
-extern	ulong	getmalloctag(void*);
-extern	ulong	getrealloctag(void*);
-/*
-extern	void*	malloctopoolblock(void*);
-*/
-#ifndef NOPLAN9DEFINES
-#define	malloc	p9malloc
-#endif
-
-/*
- * print routines (provided by <fmt.h>)
- *
-typedef struct Fmt	Fmt;
-struct Fmt{
-	uchar	runes;
-	void	*start;
-	void	*to;
-	void	*stop;
-	int	(*flush)(Fmt *);
-	void	*farg;
-	int	nfmt;
-	va_list	args;
-	int	r;
-	int	width;
-	int	prec;
-	ulong	flags;
-};
-
-enum{
-	FmtWidth	= 1,
-	FmtLeft		= FmtWidth << 1,
-	FmtPrec		= FmtLeft << 1,
-	FmtSharp	= FmtPrec << 1,
-	FmtSpace	= FmtSharp << 1,
-	FmtSign		= FmtSpace << 1,
-	FmtZero		= FmtSign << 1,
-	FmtUnsigned	= FmtZero << 1,
-	FmtShort	= FmtUnsigned << 1,
-	FmtLong		= FmtShort << 1,
-	FmtVLong	= FmtLong << 1,
-	FmtComma	= FmtVLong << 1,
-	FmtByte	= FmtComma << 1,
-
-	FmtFlag		= FmtByte << 1
-};
-
-extern	int	print(char*, ...);
-extern	char*	seprint(char*, char*, char*, ...);
-extern	char*	vseprint(char*, char*, char*, va_list);
-extern	int	snprint(char*, int, char*, ...);
-extern	int	vsnprint(char*, int, char*, va_list);
-extern	char*	smprint(char*, ...);
-extern	char*	vsmprint(char*, va_list);
-extern	int	sprint(char*, char*, ...);
-extern	int	fprint(int, char*, ...);
-extern	int	vfprint(int, char*, va_list);
-
-extern	int	runesprint(Rune*, char*, ...);
-extern	int	runesnprint(Rune*, int, char*, ...);
-extern	int	runevsnprint(Rune*, int, char*, va_list);
-extern	Rune*	runeseprint(Rune*, Rune*, char*, ...);
-extern	Rune*	runevseprint(Rune*, Rune*, char*, va_list);
-extern	Rune*	runesmprint(char*, ...);
-extern	Rune*	runevsmprint(char*, va_list);
-
-extern	int	fmtfdinit(Fmt*, int, char*, int);
-extern	int	fmtfdflush(Fmt*);
-extern	int	fmtstrinit(Fmt*);
-extern	char*	fmtstrflush(Fmt*);
-extern	int	runefmtstrinit(Fmt*);
-extern	Rune*	runefmtstrflush(Fmt*);
-
-extern	int	fmtinstall(int, int (*)(Fmt*));
-extern	int	dofmt(Fmt*, char*);
-extern	int	dorfmt(Fmt*, Rune*);
-extern	int	fmtprint(Fmt*, char*, ...);
-extern	int	fmtvprint(Fmt*, char*, va_list);
-extern	int	fmtrune(Fmt*, int);
-extern	int	fmtstrcpy(Fmt*, char*);
-extern	int	fmtrunestrcpy(Fmt*, Rune*);
- */
-
-/*
- * error string for %r
- * supplied on per os basis, not part of fmt library
- *
- * (provided by lib9, but declared in fmt.h)
- *
-extern	int	errfmt(Fmt *f);
- */
-
-/*
- * quoted strings
- */
-extern	char	*unquotestrdup(char*);
-extern	Rune	*unquoterunestrdup(Rune*);
-extern	char	*quotestrdup(char*);
-extern	Rune	*quoterunestrdup(Rune*);
-/*
- * in fmt.h
- *
-extern	void	quotefmtinstall(void);
-extern	int	quotestrfmt(Fmt*);
-extern	int	quoterunestrfmt(Fmt*);
- */
-#ifndef NOPLAN9DEFINES
-#define doquote fmtdoquote
-#endif
-extern	int	needsrcquote(int);
-
-/*
- * random number (in <stdlib.h>)
- *
-extern	void	srand(long);
-extern	int	rand(void);
- */
-extern	int	nrand(int);
-extern	long	lrand(void);
-extern	long	lnrand(long);
-extern	double	frand(void);
-extern	ulong	truerand(void);			/* uses /dev/random */
-extern	ulong	ntruerand(ulong);		/* uses /dev/random */
-
-/*
- * math
- */
-extern	ulong	getfcr(void);
-extern	void	setfsr(ulong);
-extern	ulong	getfsr(void);
-extern	void	setfcr(ulong);
-extern	double	NaN(void);
-extern	double	Inf(int);
-extern	int	isNaN(double);
-extern	int	isInf(double, int);
-extern	ulong	umuldiv(ulong, ulong, ulong);
-extern	long	muldiv(long, long, long);
-
-/*
- * provided by math.h
- *
-extern	double	pow(double, double);
-extern	double	atan2(double, double);
-extern	double	fabs(double);
-extern	double	atan(double);
-extern	double	log(double);
-extern	double	log10(double);
-extern	double	exp(double);
-extern	double	floor(double);
-extern	double	ceil(double);
-extern	double	hypot(double, double);
-extern	double	sin(double);
-extern	double	cos(double);
-extern	double	tan(double);
-extern	double	asin(double);
-extern	double	acos(double);
-extern	double	sinh(double);
-extern	double	cosh(double);
-extern	double	tanh(double);
-extern	double	sqrt(double);
-extern	double	fmod(double, double);
-#define	HUGE	3.4028234e38
-#define	PIO2	1.570796326794896619231e0
-#define	PI	(PIO2+PIO2)
- */
-#define PI	M_PI
-#define	PIO2	M_PI_2
-
-/*
- * Time-of-day
- */
-
-typedef
-struct Tm
-{
-	int	sec;
-	int	min;
-	int	hour;
-	int	mday;
-	int	mon;
-	int	year;
-	int	wday;
-	int	yday;
-	char	zone[4];
-	int	tzoff;
-} Tm;
-
-extern	Tm*	p9gmtime(long);
-extern	Tm*	p9localtime(long);
-extern	char*	p9asctime(Tm*);
-extern	char*	p9ctime(long);
-extern	double	p9cputime(void);
-extern	long	p9times(long*);
-extern	long	p9tm2sec(Tm*);
-extern	vlong	p9nsec(void);
-
-#ifndef NOPLAN9DEFINES
-#define	gmtime		p9gmtime
-#define	localtime	p9localtime
-#define	asctime		p9asctime
-#define	ctime		p9ctime
-#define	cputime		p9cputime
-#define	times		p9times
-#define	tm2sec		p9tm2sec
-#define	nsec		p9nsec
-#endif
-
-/*
- * one-of-a-kind
- */
-enum
-{
-	PNPROC		= 1,
-	PNGROUP		= 2,
-};
-
-/* extern	int	abs(int); <stdlib.h> */
-extern	int	p9atexit(void(*)(void));
-extern	void	p9atexitdont(void(*)(void));
-extern	int	atnotify(int(*)(void*, char*), int);
-/* 
- * <stdlib.h>
-extern	double	atof(char*); <stdlib.h>
-extern	int	atoi(char*);
-extern	long	atol(char*);
- */
-extern	vlong	atoll(const char*);
-extern	double	charstod(int(*)(void*), void*);
-extern	char*	cleanname(char*);
-extern	int	p9decrypt(void*, void*, int);
-extern	int	p9encrypt(void*, void*, int);
-extern	int	dec64(uchar*, int, char*, int);
-extern	int	enc64(char*, int, uchar*, int);
-extern	int	dec32(uchar*, int, char*, int);
-extern	int	enc32(char*, int, uchar*, int);
-extern	int	dec16(uchar*, int, char*, int);
-extern	int	enc16(char*, int, uchar*, int);
-extern	int	encodefmt(Fmt*);
-extern	int	dirmodefmt(Fmt*);
-extern	void	exits(char*);
-extern	double	frexp(double, int*);
-extern	ulong	getcallerpc(void*);
-extern	char*	p9getenv(char*);
-extern	int	p9putenv(char*, char*);
-extern	int	getfields(char*, char**, int, int, char*);
-extern	int	gettokens(char *, char **, int, char *);
-extern	char*	getuser(void);
-extern	char*	p9getwd(char*, int);
-extern	int	iounit(int);
-/* extern	long	labs(long); <math.h> */
-/* extern	double	ldexp(double, int); <math.h> */
-extern	void	p9longjmp(p9jmp_buf, int);
-extern	char*	mktemp(char*);
-extern	int		opentemp(char*);
-/* extern	double	modf(double, double*); <math.h> */
-extern	int	netcrypt(void*, void*);
-extern	void	p9notejmp(void*, p9jmp_buf, int);
-extern	void	perror(const char*);
-extern	int	postnote(int, int, char *);
-extern	double	pow10(int);
-/* extern	int	putenv(char*, char*); <stdlib.h. */
-/* extern	void	qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */
-/* extern	int	p9setjmp(p9jmp_buf); */
-#define p9setjmp(b)	sigsetjmp((void*)(b), 1)
-/*
- * <stdlib.h>
-extern	double	strtod(char*, char**);
-extern	long	strtol(char*, char**, int);
-extern	ulong	strtoul(char*, char**, int);
-extern	vlong	strtoll(char*, char**, int);
-extern	uvlong	strtoull(char*, char**, int);
- */
-extern	void	sysfatal(char*, ...);
-extern	void	p9syslog(int, char*, char*, ...);
-extern	long	time(long*);
-/* extern	int	tolower(int); <ctype.h> */
-/* extern	int	toupper(int); <ctype.h> */
-#ifndef NOPLAN9DEFINES
-#define atexit		p9atexit
-#define atexitdont	p9atexitdont
-#define encrypt		p9encrypt
-#define decrypt		p9decrypt
-#define getenv		p9getenv
-#define	getwd		p9getwd
-#define	longjmp		p9longjmp
-#undef  setjmp
-#define setjmp		p9setjmp
-#define putenv		p9putenv
-#define notejmp		p9notejmp
-#define jmp_buf		p9jmp_buf
-#define syslog		p9syslog
-#endif
-
-/*
- *  synchronization
- */
-typedef
-struct Lock {
-	int	val;
-} Lock;
-
-extern int	_tas(int*);
-
-extern	void	lock(Lock*);
-extern	void	unlock(Lock*);
-extern	int	canlock(Lock*);
-
-typedef struct QLp QLp;
-struct QLp
-{
-	int	inuse;
-	QLp	*next;
-	char	state;
-};
-
-typedef
-struct QLock
-{
-	Lock	lock;
-	int	locked;
-	QLp	*head;
-	QLp 	*tail;
-} QLock;
-
-extern	void	qlock(QLock*);
-extern	void	qunlock(QLock*);
-extern	int	canqlock(QLock*);
-extern	void	_qlockinit(ulong (*)(ulong, ulong));	/* called only by the thread library */
-
-typedef
-struct RWLock
-{
-	Lock	lock;
-	int	readers;	/* number of readers */
-	int	writer;		/* number of writers */
-	QLp	*head;		/* list of waiting processes */
-	QLp	*tail;
-} RWLock;
-
-extern	void	rlock(RWLock*);
-extern	void	runlock(RWLock*);
-extern	int		canrlock(RWLock*);
-extern	void	wlock(RWLock*);
-extern	void	wunlock(RWLock*);
-extern	int		canwlock(RWLock*);
-
-typedef
-struct Rendez
-{
-	QLock *l;
-	QLp	*head;
-	QLp	*tail;
-} Rendez;
-
-extern	void	rsleep(Rendez*);	/* unlocks r->l, sleeps, locks r->l again */
-extern	int	rwakeup(Rendez*);
-extern	int	rwakeupall(Rendez*);
-extern	void**	privalloc(void);
-extern	void	privfree(void**);
-
-/*
- *  network dialing
- */
-#define NETPATHLEN 40
-extern	int	p9accept(int, char*);
-extern	int	p9announce(char*, char*);
-extern	int	p9dial(char*, char*, char*, int*);
-extern	void	p9setnetmtpt(char*, int, char*);
-extern	int	p9hangup(int);
-extern	int	p9listen(char*, char*);
-extern	char*	p9netmkaddr(char*, char*, char*);
-extern	int	p9reject(int, char*, char*);
-
-#ifndef NOPLAN9DEFINES
-#define	accept		p9accept
-#define	announce	p9announce
-#define	dial		p9dial
-#define	setnetmtpt	p9setnetmtpt
-#define	hangup		p9hangup
-#define	listen		p9listen
-#define	netmkaddr	p9netmkaddr
-#define	reject		p9reject
-#endif
-
-/*
- *  encryption
- */
-extern	int	pushssl(int, char*, char*, char*, int*);
-extern	int	pushtls(int, char*, char*, int, char*, char*);
-
-/*
- *  network services
- */
-typedef struct NetConnInfo NetConnInfo;
-struct NetConnInfo
-{
-	char	*dir;		/* connection directory */
-	char	*root;		/* network root */
-	char	*spec;		/* binding spec */
-	char	*lsys;		/* local system */
-	char	*lserv;		/* local service */
-	char	*rsys;		/* remote system */
-	char	*rserv;		/* remote service */
-};
-extern	NetConnInfo*	getnetconninfo(char*, int);
-extern	void		freenetconninfo(NetConnInfo*);
-
-/*
- * system calls
- *
- */
-#define	STATMAX	65535U	/* max length of machine-independent stat structure */
-#define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */
-#define	ERRMAX	128	/* max length of error string */
-
-#define	MORDER	0x0003	/* mask for bits defining order of mounting */
-#define	MREPL	0x0000	/* mount replaces object */
-#define	MBEFORE	0x0001	/* mount goes before others in union directory */
-#define	MAFTER	0x0002	/* mount goes after others in union directory */
-#define	MCREATE	0x0004	/* permit creation in mounted directory */
-#define	MCACHE	0x0010	/* cache some data */
-#define	MMASK	0x0017	/* all bits on */
-
-#define	OREAD	0	/* open for read */
-#define	OWRITE	1	/* write */
-#define	ORDWR	2	/* read and write */
-#define	OEXEC	3	/* execute, == read but check execute permission */
-#define	OTRUNC	16	/* or'ed in (except for exec), truncate file first */
-#define	OCEXEC	32	/* or'ed in, close on exec */
-#define	ORCLOSE	64	/* or'ed in, remove on close */
-#define	OEXCL	0x1000	/* or'ed in, exclusive use (create only) */
-
-#define	AEXIST	0	/* accessible: exists */
-#define	AEXEC	1	/* execute access */
-#define	AWRITE	2	/* write access */
-#define	AREAD	4	/* read access */
-
-/* Segattch */
-#define	SG_RONLY	0040	/* read only */
-#define	SG_CEXEC	0100	/* detach on exec */
-
-#define	NCONT	0	/* continue after note */
-#define	NDFLT	1	/* terminate after note */
-#define	NSAVE	2	/* clear note but hold state */
-#define	NRSTR	3	/* restore saved state */
-
-/* bits in Qid.type */
-#define QTDIR		0x80		/* type bit for directories */
-#define QTAPPEND	0x40		/* type bit for append only files */
-#define QTEXCL		0x20		/* type bit for exclusive use files */
-#define QTMOUNT		0x10		/* type bit for mounted channel */
-#define QTAUTH		0x08		/* type bit for authentication file */
-#define QTFILE		0x00		/* plain file */
-
-/* bits in Dir.mode */
-#define DMDIR		0x80000000	/* mode bit for directories */
-#define DMAPPEND	0x40000000	/* mode bit for append only files */
-#define DMEXCL		0x20000000	/* mode bit for exclusive use files */
-#define DMMOUNT		0x10000000	/* mode bit for mounted channel */
-#define DMAUTH		0x08000000	/* mode bit for authentication file */
-#define DMREAD		0x4		/* mode bit for read permission */
-#define DMWRITE		0x2		/* mode bit for write permission */
-#define DMEXEC		0x1		/* mode bit for execute permission */
-
-#if defined(__FreeBSD__)
-#undef RFFDG
-#undef RFNOTEG
-#undef RFPROC
-#undef RFMEM
-#undef RFNOWAIT
-#undef RFCFDG
-#undef RFNAMEG
-#undef RFENVG
-#undef RFCENVG
-#undef RFCFDG
-#undef RFCNAMEG
-#endif
-
-enum
-{
-	RFNAMEG		= (1<<0), 
-	RFENVG		= (1<<1), 
-	RFFDG		= (1<<2),
-	RFNOTEG		= (1<<3),
-	RFPROC		= (1<<4),
-	RFMEM		= (1<<5),
-	RFNOWAIT	= (1<<6),
-	RFCNAMEG	= (1<<10), 
-	RFCENVG		= (1<<11), 
-	RFCFDG		= (1<<12),
-/*	RFREND		= (1<<13), */
-/*	RFNOMNT		= (1<<14) */
-};
-
-extern int		ffork(int, void(*)(void*), void*);
-
-typedef
-struct Qid
-{
-	uvlong	path;
-	ulong	vers;
-	uchar	type;
-} Qid;
-
-typedef
-struct Dir {
-	/* system-modified data */
-	ushort	type;	/* server type */
-	uint	dev;	/* server subtype */
-	/* file data */
-	Qid	qid;	/* unique id from server */
-	ulong	mode;	/* permissions */
-	ulong	atime;	/* last read time */
-	ulong	mtime;	/* last write time */
-	vlong	length;	/* file length */
-	char	*name;	/* last element of path */
-	char	*uid;	/* owner name */
-	char	*gid;	/* group name */
-	char	*muid;	/* last modifier name */
-} Dir;
-
-/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
-typedef
-struct Waitmsg
-{
-	int pid;	/* of loved one */
-	ulong time[3];	/* of loved one & descendants */
-	char	*msg;
-} Waitmsg;
-
-typedef
-struct IOchunk
-{
-	void	*addr;
-	ulong	len;
-} IOchunk;
-
-extern	void	_exits(char*);
-
-extern	void	abort(void);
-extern	int	p9access(char*, int);
-extern	long	p9alarm(ulong);
-extern	int	await(char*, int);
-extern	int	awaitnohang(char*, int);
-/* extern	int	bind(char*, char*, int); give up */
-/* extern	int	brk(void*); <unistd.h> */
-extern	int	p9chdir(char*);
-extern	int	close(int);
-extern	int	p9create(char*, int, ulong);
-extern	int	p9dup(int, int);
-extern	int	errstr(char*, uint);
-extern	int	p9exec(char*, char*[]);
-/* extern	int	execl(char*, ...); <unistd.h> */
-/* extern	int	fork(void); <unistd.h> */
-extern	int	p9rfork(int);
-/* not implemented 
-extern	int	fauth(int, char*);
-extern	int	fstat(int, uchar*, int);
-extern	int	fwstat(int, uchar*, int);
-extern	int	fversion(int, int, char*, int);
-extern	int	mount(int, int, char*, int, char*);
-extern	int	unmount(char*, char*);
-*/
-extern	int	noted(int);
-extern	int	notify(void(*)(void*, char*));
-extern	int	p9open(char*, int);
-extern	int	fd2path(int, char*, int);
-extern	int	p9pipe(int*);
-/* 
- * use defs from <unistd.h>
-extern	long	pread(int, void*, long, vlong);
-extern	long	preadv(int, IOchunk*, int, vlong);
-extern	long	pwrite(int, void*, long, vlong);
-extern	long	pwritev(int, IOchunk*, int, vlong);
-extern	long	read(int, void*, long);
- */
-extern	long	readn(int, void*, long);
-/* extern	long	readv(int, IOchunk*, int); <unistd.h> */
-extern	int	remove(const char*);
-/* extern	void*	sbrk(ulong); <unistd.h> */
-/* extern	long	oseek(int, long, int); */
-extern	vlong	p9seek(int, vlong, int);
-/* give up
-extern	long	segattach(int, char*, void*, ulong);
-extern	int	segbrk(void*, void*);
-extern	int	segdetach(void*);
-extern	int	segflush(void*, ulong);
-extern	int	segfree(void*, ulong);
-*/
-extern	int	p9sleep(long);
-/* extern	int	stat(char*, uchar*, int); give up */
-extern	Waitmsg*	p9wait(void);
-extern	Waitmsg*	waitnohang(void);
-extern	int	p9waitpid(void);
-/* <unistd.h>
-extern	long	write(int, void*, long);
-extern	long	writev(int, IOchunk*, int);
-*/
-/* extern	int	wstat(char*, uchar*, int); give up */
-extern	ulong	rendezvous(ulong, ulong);
-
-#ifndef NOPLAN9DEFINES
-#define alarm		p9alarm
-#define	dup		p9dup
-#define	exec		p9exec
-#define	seek		p9seek
-#define sleep		p9sleep
-#define wait		p9wait
-#define waitpid		p9waitpid
-#define rfork		p9rfork
-#define access		p9access
-#define create		p9create
-#define open		p9open
-#define pipe		p9pipe
-#endif
-
-extern	Dir*	dirstat(char*);
-extern	Dir*	dirfstat(int);
-extern	int	dirwstat(char*, Dir*);
-extern	int	dirfwstat(int, Dir*);
-extern	long	dirread(int, Dir**);
-extern	void	nulldir(Dir*);
-extern	long	dirreadall(int, Dir**);
-/* extern	int	getpid(void); <unistd.h> */
-/* extern	int	getppid(void); */
-extern	void	rerrstr(char*, uint);
-extern	char*	sysname(void);
-extern	void	werrstr(char*, ...);
-extern	char*	getns(void);
-extern	int	sendfd(int, int);
-extern	int	recvfd(int);
-extern	int	post9pservice(int, char*);
-
-/* external names that we don't want to step on */
-#ifndef NOPLAN9DEFINES
-#define main	p9main
-#endif
-
-/* compiler directives on plan 9 */
-#define	USED(x)	if(x){}else{}
-#define	SET(x)	((x)=0)
-
-/* command line */
-extern char	*argv0;
-extern void __fixargv0(void);
-#define	ARGBEGIN	for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
-			    argv[0] && argv[0][0]=='-' && argv[0][1];\
-			    argc--, argv++) {\
-				char *_args, *_argt;\
-				Rune _argc;\
-				_args = &argv[0][1];\
-				if(_args[0]=='-' && _args[1]==0){\
-					argc--; argv++; break;\
-				}\
-				_argc = 0;\
-				while(*_args && (_args += chartorune(&_argc, _args)))\
-				switch(_argc)
-#define	ARGEND		SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
-#define	ARGF()		(_argt=_args, _args="",\
-				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
-#define	EARGF(x)	(_argt=_args, _args="",\
-				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
-
-#define	ARGC()		_argc
-
-#if defined(__cplusplus)
-}
-#endif
-#endif	/* _LIB9_H_ */
+#include <u.h>
+#include <libc.h>
blob - d84870664e9f2ffcd6a93d5a6c514659645d39df
blob + 1a560b6fc51ada418265a76d3e16e9849e18d66d
--- include/libString.h
+++ include/libString.h
@@ -43,4 +43,4 @@ typedef struct Sinstack Sinstack;
 extern char	*s_rdinstack(Sinstack*, String*);
 extern Sinstack	*s_allocinstack(char*);
 extern void	s_freeinstack(Sinstack*);
-#endif BGETC
+#endif /* BGETC */
blob - 25b042c12623573843d640fca918fcfe163e2255
blob + 64bb086743564bc4a54d5178eaa478f5f31dddd7
--- include/libc.h
+++ include/libc.h
@@ -1,2 +1,794 @@
-#include <lib9.h>
+/*
+ * Lib9 is miscellany from the Plan 9 C library that doesn't
+ * fit into libutf or into libfmt, but is still missing from traditional
+ * Unix C libraries.
+ */
+#ifndef _LIBC_H_
+#define _LIBC_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif                                                                          
+
+/*
+ * Begin usual libc.h 
+ */
+
+#define	nil	((void*)0)
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
+
+#ifndef offsetof
+#define offsetof(s, m)	(ulong)(&(((s*)0)->m))
+#endif
+
+/*
+ * mem routines (provided by system <string.h>)
+ *
+extern	void*	memccpy(void*, void*, int, ulong);
+extern	void*	memset(void*, int, ulong);
+extern	int	memcmp(void*, void*, ulong);
+extern	void*	memcpy(void*, void*, ulong);
+extern	void*	memmove(void*, void*, ulong);
+extern	void*	memchr(void*, int, ulong);
+ */
+
+/*
+ * string routines (provided by system <string.h>)
+ *
+extern	char*	strcat(char*, char*);
+extern	char*	strchr(char*, int);
+extern	int	strcmp(char*, char*);
+extern	char*	strcpy(char*, char*);
+ */
+extern	char*	strecpy(char*, char*, char*);
+ /*
+extern	char*	strdup(char*);
+extern	char*	strncat(char*, char*, long);
+extern	char*	strncpy(char*, char*, long);
+extern	int	strncmp(char*, char*, long);
+extern	char*	strpbrk(char*, char*);
+extern	char*	strrchr(char*, int);
+extern	char*	strtok(char*, char*);
+extern	long	strlen(char*);
+extern	long	strspn(char*, char*);
+extern	long	strcspn(char*, char*);
+extern	char*	strstr(char*, char*);
+ */
+extern	int	cistrncmp(char*, char*, int);
+extern	int	cistrcmp(char*, char*);
+extern	char*	cistrstr(char*, char*);
+extern	int	tokenize(char*, char**, int);
+
+/*
+enum
+{
+	UTFmax		= 3,
+	Runesync	= 0x80,
+	Runeself	= 0x80,
+	Runeerror	= 0x80,
+};
+*/
+
+/*
+ * rune routines (provided by <utf.h>
+ *
+extern	int	runetochar(char*, Rune*);
+extern	int	chartorune(Rune*, char*);
+extern	int	runelen(long);
+extern	int	runenlen(Rune*, int);
+extern	int	fullrune(char*, int);
+extern	int	utflen(char*);
+extern	int	utfnlen(char*, long);
+extern	char*	utfrune(char*, long);
+extern	char*	utfrrune(char*, long);
+extern	char*	utfutf(char*, char*);
+extern	char*	utfecpy(char*, char*, char*);
+
+extern	Rune*	runestrcat(Rune*, Rune*);
+extern	Rune*	runestrchr(Rune*, Rune);
+extern	int	runestrcmp(Rune*, Rune*);
+extern	Rune*	runestrcpy(Rune*, Rune*);
+extern	Rune*	runestrncpy(Rune*, Rune*, long);
+extern	Rune*	runestrecpy(Rune*, Rune*, Rune*);
+extern	Rune*	runestrdup(Rune*);
+extern	Rune*	runestrncat(Rune*, Rune*, long);
+extern	int	runestrncmp(Rune*, Rune*, long);
+extern	Rune*	runestrrchr(Rune*, Rune);
+extern	long	runestrlen(Rune*);
+extern	Rune*	runestrstr(Rune*, Rune*);
+
+extern	Rune	tolowerrune(Rune);
+extern	Rune	totitlerune(Rune);
+extern	Rune	toupperrune(Rune);
+extern	int	isalpharune(Rune);
+extern	int	islowerrune(Rune);
+extern	int	isspacerune(Rune);
+extern	int	istitlerune(Rune);
+extern	int	isupperrune(Rune);
+ */
+
+/*
+ * malloc (provied by system <stdlib.h>)
+ *
+extern	void*	malloc(ulong);
+ */
+extern	void*	p9malloc(ulong);
+extern	void*	mallocz(ulong, int);
+/*
+extern	void	free(void*);
+extern	ulong	msize(void*);
+extern	void*	calloc(ulong, ulong);
+extern	void*	realloc(void*, ulong);
+ */
+extern	void		setmalloctag(void*, ulong);
+extern	void		setrealloctag(void*, ulong);
+extern	ulong	getmalloctag(void*);
+extern	ulong	getrealloctag(void*);
+/*
+extern	void*	malloctopoolblock(void*);
+*/
+#ifndef NOPLAN9DEFINES
+#define	malloc	p9malloc
+#endif
+
+/*
+ * print routines (provided by <fmt.h>)
+ *
+typedef struct Fmt	Fmt;
+struct Fmt{
+	uchar	runes;
+	void	*start;
+	void	*to;
+	void	*stop;
+	int	(*flush)(Fmt *);
+	void	*farg;
+	int	nfmt;
+	va_list	args;
+	int	r;
+	int	width;
+	int	prec;
+	ulong	flags;
+};
+
+enum{
+	FmtWidth	= 1,
+	FmtLeft		= FmtWidth << 1,
+	FmtPrec		= FmtLeft << 1,
+	FmtSharp	= FmtPrec << 1,
+	FmtSpace	= FmtSharp << 1,
+	FmtSign		= FmtSpace << 1,
+	FmtZero		= FmtSign << 1,
+	FmtUnsigned	= FmtZero << 1,
+	FmtShort	= FmtUnsigned << 1,
+	FmtLong		= FmtShort << 1,
+	FmtVLong	= FmtLong << 1,
+	FmtComma	= FmtVLong << 1,
+	FmtByte	= FmtComma << 1,
+
+	FmtFlag		= FmtByte << 1
+};
+
+extern	int	print(char*, ...);
+extern	char*	seprint(char*, char*, char*, ...);
+extern	char*	vseprint(char*, char*, char*, va_list);
+extern	int	snprint(char*, int, char*, ...);
+extern	int	vsnprint(char*, int, char*, va_list);
+extern	char*	smprint(char*, ...);
+extern	char*	vsmprint(char*, va_list);
+extern	int	sprint(char*, char*, ...);
+extern	int	fprint(int, char*, ...);
+extern	int	vfprint(int, char*, va_list);
+
+extern	int	runesprint(Rune*, char*, ...);
+extern	int	runesnprint(Rune*, int, char*, ...);
+extern	int	runevsnprint(Rune*, int, char*, va_list);
+extern	Rune*	runeseprint(Rune*, Rune*, char*, ...);
+extern	Rune*	runevseprint(Rune*, Rune*, char*, va_list);
+extern	Rune*	runesmprint(char*, ...);
+extern	Rune*	runevsmprint(char*, va_list);
+
+extern	int	fmtfdinit(Fmt*, int, char*, int);
+extern	int	fmtfdflush(Fmt*);
+extern	int	fmtstrinit(Fmt*);
+extern	char*	fmtstrflush(Fmt*);
+extern	int	runefmtstrinit(Fmt*);
+extern	Rune*	runefmtstrflush(Fmt*);
+
+extern	int	fmtinstall(int, int (*)(Fmt*));
+extern	int	dofmt(Fmt*, char*);
+extern	int	dorfmt(Fmt*, Rune*);
+extern	int	fmtprint(Fmt*, char*, ...);
+extern	int	fmtvprint(Fmt*, char*, va_list);
+extern	int	fmtrune(Fmt*, int);
+extern	int	fmtstrcpy(Fmt*, char*);
+extern	int	fmtrunestrcpy(Fmt*, Rune*);
+ */
+
+/*
+ * error string for %r
+ * supplied on per os basis, not part of fmt library
+ *
+ * (provided by lib9, but declared in fmt.h)
+ *
+extern	int	errfmt(Fmt *f);
+ */
+
+/*
+ * quoted strings
+ */
+extern	char	*unquotestrdup(char*);
+extern	Rune	*unquoterunestrdup(Rune*);
+extern	char	*quotestrdup(char*);
+extern	Rune	*quoterunestrdup(Rune*);
+/*
+ * in fmt.h
+ *
+extern	void	quotefmtinstall(void);
+extern	int	quotestrfmt(Fmt*);
+extern	int	quoterunestrfmt(Fmt*);
+ */
+#ifndef NOPLAN9DEFINES
+#define doquote fmtdoquote
+#endif
+extern	int	needsrcquote(int);
+
+/*
+ * random number (in <stdlib.h>)
+ *
+extern	void	srand(long);
+extern	int	rand(void);
+ */
+extern	int	nrand(int);
+extern	long	lrand(void);
+extern	long	lnrand(long);
+extern	double	frand(void);
+extern	ulong	truerand(void);			/* uses /dev/random */
+extern	ulong	ntruerand(ulong);		/* uses /dev/random */
+
+/*
+ * math
+ */
+extern	ulong	getfcr(void);
+extern	void	setfsr(ulong);
+extern	ulong	getfsr(void);
+extern	void	setfcr(ulong);
+extern	double	NaN(void);
+extern	double	Inf(int);
+extern	int	isNaN(double);
+extern	int	isInf(double, int);
+extern	ulong	umuldiv(ulong, ulong, ulong);
+extern	long	muldiv(long, long, long);
+
+/*
+ * provided by math.h
+ *
+extern	double	pow(double, double);
+extern	double	atan2(double, double);
+extern	double	fabs(double);
+extern	double	atan(double);
+extern	double	log(double);
+extern	double	log10(double);
+extern	double	exp(double);
+extern	double	floor(double);
+extern	double	ceil(double);
+extern	double	hypot(double, double);
+extern	double	sin(double);
+extern	double	cos(double);
+extern	double	tan(double);
+extern	double	asin(double);
+extern	double	acos(double);
+extern	double	sinh(double);
+extern	double	cosh(double);
+extern	double	tanh(double);
+extern	double	sqrt(double);
+extern	double	fmod(double, double);
+#define	HUGE	3.4028234e38
+#define	PIO2	1.570796326794896619231e0
+#define	PI	(PIO2+PIO2)
+ */
+#define PI	M_PI
+#define	PIO2	M_PI_2
+
+/*
+ * Time-of-day
+ */
+
+typedef
+struct Tm
+{
+	int	sec;
+	int	min;
+	int	hour;
+	int	mday;
+	int	mon;
+	int	year;
+	int	wday;
+	int	yday;
+	char	zone[4];
+	int	tzoff;
+} Tm;
+
+extern	Tm*	p9gmtime(long);
+extern	Tm*	p9localtime(long);
+extern	char*	p9asctime(Tm*);
+extern	char*	p9ctime(long);
+extern	double	p9cputime(void);
+extern	long	p9times(long*);
+extern	long	p9tm2sec(Tm*);
+extern	vlong	p9nsec(void);
+
+#ifndef NOPLAN9DEFINES
+#define	gmtime		p9gmtime
+#define	localtime	p9localtime
+#define	asctime		p9asctime
+#define	ctime		p9ctime
+#define	cputime		p9cputime
+#define	times		p9times
+#define	tm2sec		p9tm2sec
+#define	nsec		p9nsec
+#endif
+
+/*
+ * one-of-a-kind
+ */
+enum
+{
+	PNPROC		= 1,
+	PNGROUP		= 2,
+};
+
+/* extern	int	abs(int); <stdlib.h> */
+extern	int	p9atexit(void(*)(void));
+extern	void	p9atexitdont(void(*)(void));
+extern	int	atnotify(int(*)(void*, char*), int);
+/* 
+ * <stdlib.h>
+extern	double	atof(char*); <stdlib.h>
+extern	int	atoi(char*);
+extern	long	atol(char*);
+ */
+extern	vlong	atoll(const char*);
+extern	double	charstod(int(*)(void*), void*);
+extern	char*	cleanname(char*);
+extern	int	p9decrypt(void*, void*, int);
+extern	int	p9encrypt(void*, void*, int);
+extern	int	dec64(uchar*, int, char*, int);
+extern	int	enc64(char*, int, uchar*, int);
+extern	int	dec32(uchar*, int, char*, int);
+extern	int	enc32(char*, int, uchar*, int);
+extern	int	dec16(uchar*, int, char*, int);
+extern	int	enc16(char*, int, uchar*, int);
+extern	int	encodefmt(Fmt*);
+extern	int	dirmodefmt(Fmt*);
+extern	void	exits(char*);
+extern	double	frexp(double, int*);
+extern	ulong	getcallerpc(void*);
+extern	char*	p9getenv(char*);
+extern	int	p9putenv(char*, char*);
+extern	int	getfields(char*, char**, int, int, char*);
+extern	int	gettokens(char *, char **, int, char *);
+extern	char*	getuser(void);
+extern	char*	p9getwd(char*, int);
+extern	int	iounit(int);
+/* extern	long	labs(long); <math.h> */
+/* extern	double	ldexp(double, int); <math.h> */
+extern	void	p9longjmp(p9jmp_buf, int);
+extern	char*	mktemp(char*);
+extern	int		opentemp(char*);
+/* extern	double	modf(double, double*); <math.h> */
+extern	int	netcrypt(void*, void*);
+extern	void	p9notejmp(void*, p9jmp_buf, int);
+extern	void	perror(const char*);
+extern	int	postnote(int, int, char *);
+extern	double	pow10(int);
+/* extern	int	putenv(char*, char*); <stdlib.h. */
+/* extern	void	qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */
+/* extern	int	p9setjmp(p9jmp_buf); */
+#define p9setjmp(b)	sigsetjmp((void*)(b), 1)
+/*
+ * <stdlib.h>
+extern	double	strtod(char*, char**);
+extern	long	strtol(char*, char**, int);
+extern	ulong	strtoul(char*, char**, int);
+extern	vlong	strtoll(char*, char**, int);
+extern	uvlong	strtoull(char*, char**, int);
+ */
+extern	void	sysfatal(char*, ...);
+extern	void	p9syslog(int, char*, char*, ...);
+extern	long	p9time(long*);
+/* extern	int	tolower(int); <ctype.h> */
+/* extern	int	toupper(int); <ctype.h> */
+#ifndef NOPLAN9DEFINES
+#define atexit		p9atexit
+#define atexitdont	p9atexitdont
+#define encrypt		p9encrypt
+#define decrypt		p9decrypt
+#define getenv		p9getenv
+#define	getwd		p9getwd
+#define	longjmp		p9longjmp
+#undef  setjmp
+#define setjmp		p9setjmp
+#define putenv		p9putenv
+#define notejmp		p9notejmp
+#define jmp_buf		p9jmp_buf
+#define syslog		p9syslog
+#define time		p9time
+#endif
 
+/*
+ *  synchronization
+ */
+typedef
+struct Lock {
+	int	val;
+} Lock;
+
+extern int	_tas(int*);
+
+extern	void	lock(Lock*);
+extern	void	unlock(Lock*);
+extern	int	canlock(Lock*);
+
+typedef struct QLp QLp;
+struct QLp
+{
+	int	inuse;
+	QLp	*next;
+	char	state;
+};
+
+typedef
+struct QLock
+{
+	Lock	lock;
+	int	locked;
+	QLp	*head;
+	QLp 	*tail;
+} QLock;
+
+extern	void	qlock(QLock*);
+extern	void	qunlock(QLock*);
+extern	int	canqlock(QLock*);
+extern	void	_qlockinit(ulong (*)(ulong, ulong));	/* called only by the thread library */
+
+typedef
+struct RWLock
+{
+	Lock	lock;
+	int	readers;	/* number of readers */
+	int	writer;		/* number of writers */
+	QLp	*head;		/* list of waiting processes */
+	QLp	*tail;
+} RWLock;
+
+extern	void	rlock(RWLock*);
+extern	void	runlock(RWLock*);
+extern	int		canrlock(RWLock*);
+extern	void	wlock(RWLock*);
+extern	void	wunlock(RWLock*);
+extern	int		canwlock(RWLock*);
+
+typedef
+struct Rendez
+{
+	QLock *l;
+	QLp	*head;
+	QLp	*tail;
+} Rendez;
+
+extern	void	rsleep(Rendez*);	/* unlocks r->l, sleeps, locks r->l again */
+extern	int	rwakeup(Rendez*);
+extern	int	rwakeupall(Rendez*);
+extern	void**	privalloc(void);
+extern	void	privfree(void**);
+
+/*
+ *  network dialing
+ */
+#define NETPATHLEN 40
+extern	int	p9accept(int, char*);
+extern	int	p9announce(char*, char*);
+extern	int	p9dial(char*, char*, char*, int*);
+extern	void	p9setnetmtpt(char*, int, char*);
+extern	int	p9hangup(int);
+extern	int	p9listen(char*, char*);
+extern	char*	p9netmkaddr(char*, char*, char*);
+extern	int	p9reject(int, char*, char*);
+
+#ifndef NOPLAN9DEFINES
+#define	accept		p9accept
+#define	announce	p9announce
+#define	dial		p9dial
+#define	setnetmtpt	p9setnetmtpt
+#define	hangup		p9hangup
+#define	listen		p9listen
+#define	netmkaddr	p9netmkaddr
+#define	reject		p9reject
+#endif
+
+/*
+ *  encryption
+ */
+extern	int	pushssl(int, char*, char*, char*, int*);
+extern	int	pushtls(int, char*, char*, int, char*, char*);
+
+/*
+ *  network services
+ */
+typedef struct NetConnInfo NetConnInfo;
+struct NetConnInfo
+{
+	char	*dir;		/* connection directory */
+	char	*root;		/* network root */
+	char	*spec;		/* binding spec */
+	char	*lsys;		/* local system */
+	char	*lserv;		/* local service */
+	char	*rsys;		/* remote system */
+	char	*rserv;		/* remote service */
+};
+extern	NetConnInfo*	getnetconninfo(char*, int);
+extern	void		freenetconninfo(NetConnInfo*);
+
+/*
+ * system calls
+ *
+ */
+#define	STATMAX	65535U	/* max length of machine-independent stat structure */
+#define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */
+#define	ERRMAX	128	/* max length of error string */
+
+#define	MORDER	0x0003	/* mask for bits defining order of mounting */
+#define	MREPL	0x0000	/* mount replaces object */
+#define	MBEFORE	0x0001	/* mount goes before others in union directory */
+#define	MAFTER	0x0002	/* mount goes after others in union directory */
+#define	MCREATE	0x0004	/* permit creation in mounted directory */
+#define	MCACHE	0x0010	/* cache some data */
+#define	MMASK	0x0017	/* all bits on */
+
+#define	OREAD	0	/* open for read */
+#define	OWRITE	1	/* write */
+#define	ORDWR	2	/* read and write */
+#define	OEXEC	3	/* execute, == read but check execute permission */
+#define	OTRUNC	16	/* or'ed in (except for exec), truncate file first */
+#define	OCEXEC	32	/* or'ed in, close on exec */
+#define	ORCLOSE	64	/* or'ed in, remove on close */
+#define	OEXCL	0x1000	/* or'ed in, exclusive use (create only) */
+
+#define	AEXIST	0	/* accessible: exists */
+#define	AEXEC	1	/* execute access */
+#define	AWRITE	2	/* write access */
+#define	AREAD	4	/* read access */
+
+/* Segattch */
+#define	SG_RONLY	0040	/* read only */
+#define	SG_CEXEC	0100	/* detach on exec */
+
+#define	NCONT	0	/* continue after note */
+#define	NDFLT	1	/* terminate after note */
+#define	NSAVE	2	/* clear note but hold state */
+#define	NRSTR	3	/* restore saved state */
+
+/* bits in Qid.type */
+#define QTDIR		0x80		/* type bit for directories */
+#define QTAPPEND	0x40		/* type bit for append only files */
+#define QTEXCL		0x20		/* type bit for exclusive use files */
+#define QTMOUNT		0x10		/* type bit for mounted channel */
+#define QTAUTH		0x08		/* type bit for authentication file */
+#define QTFILE		0x00		/* plain file */
+
+/* bits in Dir.mode */
+#define DMDIR		0x80000000	/* mode bit for directories */
+#define DMAPPEND	0x40000000	/* mode bit for append only files */
+#define DMEXCL		0x20000000	/* mode bit for exclusive use files */
+#define DMMOUNT		0x10000000	/* mode bit for mounted channel */
+#define DMAUTH		0x08000000	/* mode bit for authentication file */
+#define DMREAD		0x4		/* mode bit for read permission */
+#define DMWRITE		0x2		/* mode bit for write permission */
+#define DMEXEC		0x1		/* mode bit for execute permission */
+
+#if defined(__FreeBSD__)
+#undef RFFDG
+#undef RFNOTEG
+#undef RFPROC
+#undef RFMEM
+#undef RFNOWAIT
+#undef RFCFDG
+#undef RFNAMEG
+#undef RFENVG
+#undef RFCENVG
+#undef RFCFDG
+#undef RFCNAMEG
+#endif
+
+enum
+{
+	RFNAMEG		= (1<<0), 
+	RFENVG		= (1<<1), 
+	RFFDG		= (1<<2),
+	RFNOTEG		= (1<<3),
+	RFPROC		= (1<<4),
+	RFMEM		= (1<<5),
+	RFNOWAIT	= (1<<6),
+	RFCNAMEG	= (1<<10), 
+	RFCENVG		= (1<<11), 
+	RFCFDG		= (1<<12),
+/*	RFREND		= (1<<13), */
+/*	RFNOMNT		= (1<<14) */
+};
+
+extern int		ffork(int, void(*)(void*), void*);
+
+typedef
+struct Qid
+{
+	uvlong	path;
+	ulong	vers;
+	uchar	type;
+} Qid;
+
+typedef
+struct Dir {
+	/* system-modified data */
+	ushort	type;	/* server type */
+	uint	dev;	/* server subtype */
+	/* file data */
+	Qid	qid;	/* unique id from server */
+	ulong	mode;	/* permissions */
+	ulong	atime;	/* last read time */
+	ulong	mtime;	/* last write time */
+	vlong	length;	/* file length */
+	char	*name;	/* last element of path */
+	char	*uid;	/* owner name */
+	char	*gid;	/* group name */
+	char	*muid;	/* last modifier name */
+} Dir;
+
+/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
+typedef
+struct Waitmsg
+{
+	int pid;	/* of loved one */
+	ulong time[3];	/* of loved one & descendants */
+	char	*msg;
+} Waitmsg;
+
+typedef
+struct IOchunk
+{
+	void	*addr;
+	ulong	len;
+} IOchunk;
+
+extern	void	_exits(char*);
+
+extern	void	abort(void);
+extern	int	p9access(char*, int);
+extern	long	p9alarm(ulong);
+extern	int	await(char*, int);
+extern	int	awaitnohang(char*, int);
+/* extern	int	bind(char*, char*, int); give up */
+/* extern	int	brk(void*); <unistd.h> */
+extern	int	p9chdir(char*);
+extern	int	close(int);
+extern	int	p9create(char*, int, ulong);
+extern	int	p9dup(int, int);
+extern	int	errstr(char*, uint);
+extern	int	p9exec(char*, char*[]);
+/* extern	int	execl(char*, ...); <unistd.h> */
+/* extern	int	fork(void); <unistd.h> */
+extern	int	p9rfork(int);
+/* not implemented 
+extern	int	fauth(int, char*);
+extern	int	fstat(int, uchar*, int);
+extern	int	fwstat(int, uchar*, int);
+extern	int	fversion(int, int, char*, int);
+extern	int	mount(int, int, char*, int, char*);
+extern	int	unmount(char*, char*);
+*/
+extern	int	noted(int);
+extern	int	notify(void(*)(void*, char*));
+extern	int	p9open(char*, int);
+extern	int	fd2path(int, char*, int);
+extern	int	p9pipe(int*);
+/* 
+ * use defs from <unistd.h>
+extern	long	pread(int, void*, long, vlong);
+extern	long	preadv(int, IOchunk*, int, vlong);
+extern	long	pwrite(int, void*, long, vlong);
+extern	long	pwritev(int, IOchunk*, int, vlong);
+extern	long	read(int, void*, long);
+ */
+extern	long	readn(int, void*, long);
+/* extern	long	readv(int, IOchunk*, int); <unistd.h> */
+extern	int	remove(const char*);
+/* extern	void*	sbrk(ulong); <unistd.h> */
+/* extern	long	oseek(int, long, int); */
+extern	vlong	p9seek(int, vlong, int);
+/* give up
+extern	long	segattach(int, char*, void*, ulong);
+extern	int	segbrk(void*, void*);
+extern	int	segdetach(void*);
+extern	int	segflush(void*, ulong);
+extern	int	segfree(void*, ulong);
+*/
+extern	int	p9sleep(long);
+/* extern	int	stat(char*, uchar*, int); give up */
+extern	Waitmsg*	p9wait(void);
+extern	Waitmsg*	waitnohang(void);
+extern	int	p9waitpid(void);
+/* <unistd.h>
+extern	long	write(int, void*, long);
+extern	long	writev(int, IOchunk*, int);
+*/
+/* extern	int	wstat(char*, uchar*, int); give up */
+extern	ulong	rendezvous(ulong, ulong);
+
+#ifndef NOPLAN9DEFINES
+#define alarm		p9alarm
+#define	dup		p9dup
+#define	exec		p9exec
+#define	seek		p9seek
+#define sleep		p9sleep
+#define wait		p9wait
+#define waitpid		p9waitpid
+#define rfork		p9rfork
+#define access		p9access
+#define create		p9create
+#define open		p9open
+#define pipe		p9pipe
+#endif
+
+extern	Dir*	dirstat(char*);
+extern	Dir*	dirfstat(int);
+extern	int	dirwstat(char*, Dir*);
+extern	int	dirfwstat(int, Dir*);
+extern	long	dirread(int, Dir**);
+extern	void	nulldir(Dir*);
+extern	long	dirreadall(int, Dir**);
+/* extern	int	getpid(void); <unistd.h> */
+/* extern	int	getppid(void); */
+extern	void	rerrstr(char*, uint);
+extern	char*	sysname(void);
+extern	void	werrstr(char*, ...);
+extern	char*	getns(void);
+extern	char*	get9root(void);
+extern	char*	unsharp(char*);
+extern	int	sendfd(int, int);
+extern	int	recvfd(int);
+extern	int	post9pservice(int, char*);
+
+/* external names that we don't want to step on */
+#ifndef NOPLAN9DEFINES
+#define main	p9main
+#endif
+
+/* compiler directives on plan 9 */
+#define	USED(x)	if(x){}else{}
+#define	SET(x)	((x)=0)
+
+/* command line */
+extern char	*argv0;
+extern void __fixargv0(void);
+#define	ARGBEGIN	for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
+			    argv[0] && argv[0][0]=='-' && argv[0][1];\
+			    argc--, argv++) {\
+				char *_args, *_argt;\
+				Rune _argc;\
+				_args = &argv[0][1];\
+				if(_args[0]=='-' && _args[1]==0){\
+					argc--; argv++; break;\
+				}\
+				_argc = 0;\
+				while(*_args && (_args += chartorune(&_argc, _args)))\
+				switch(_argc)
+#define	ARGEND		SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
+#define	ARGF()		(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define	EARGF(x)	(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
+
+#define	ARGC()		_argc
+
+#if defined(__cplusplus)
+}
+#endif
+#endif	/* _LIB9_H_ */
blob - e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
blob + 4716ce4f1f987092e4e103fb2b1a16685d0774c7
--- include/u.h
+++ include/u.h
@@ -0,0 +1,93 @@
+#ifndef _U_H_
+#define _U_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define _BSD_SOURCE 1
+#define _SVID_SOURCE 1
+#define _XOPEN_SOURCE 1000
+#define _XOPEN_SOURCE_EXTENDED 1
+#define _LARGEFILE64_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+#define __EXTENSIONS__ 1 /* SunOS */
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <utf.h>
+#include <fmt.h>
+#include <math.h>
+
+/*
+ * OS-specific crap
+ */
+#define _NEEDUCHAR 1
+#define _NEEDUSHORT 1
+#define _NEEDUINT 1
+#define _NEEDULONG 1
+
+typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
+
+#if defined(__linux__)
+#	include <sys/types.h>
+#	if defined(__USE_MISC)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#		undef _NEEDULONG
+#	endif
+#endif
+#if defined(__sun__)
+#	include <sys/types.h>
+#	undef _NEEDUSHORT
+#	undef _NEEDUINT
+#	undef _NEEDULONG
+#endif
+#if defined(__FreeBSD__)
+#	include <sys/types.h>
+#	if !defined(_POSIX_SOURCE)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#	endif
+#endif
+#if defined(__APPLE__)
+#	include <sys/types.h>
+#	undef _NEEDUSHORT
+#	undef _NEEDUINT
+#	define _NEEDLL 1
+#endif
+
+typedef signed char schar;
+typedef unsigned int u32int;
+#ifdef _NEEDUCHAR
+	typedef unsigned char uchar;
+#endif
+#ifdef _NEEDUSHORT
+	typedef unsigned short ushort;
+#endif
+#ifdef _NEEDUINT
+	typedef unsigned int uint;
+#endif
+#ifdef _NEEDULONG
+	typedef unsigned long ulong;
+#endif
+typedef unsigned long long uvlong;
+typedef long long vlong;
+typedef uvlong u64int;
+typedef uchar u8int;
+typedef ushort u16int;
+
+#undef _NEEDUCHAR
+#undef _NEEDUSHORT
+#undef _NEEDUINT
+#undef _NEEDULONG
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
blob - 8acd5524c8a8a0e49ea4267757663ebab9095dd4
blob + 644385c1a34f61006838ea6e15a16fd6770fb661
--- src/cmd/9pserve.c
+++ src/cmd/9pserve.c
@@ -1150,7 +1150,7 @@ rewritehdr(Fcall *f, uchar *pkt)
 	}
 }
 
-#ifdef _LIB9_H_
+#ifdef _LIBC_H_
 /* unix select-based polling */
 struct Ioproc
 {
blob - c5a2c4244d4e5e41c372ea8b8b487447d87915e3
blob + 50c0cfc92833845183ed261eadd826ddf665eb4b
--- src/cmd/9term/9term.c
+++ src/cmd/9term/9term.c
@@ -1,15 +1,24 @@
-#include "9term.h"
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <draw.h>
+#include <thread.h>
+#include <mouse.h>
+#include <cursor.h>
+#include <keyboard.h>
+#include <frame.h>
+#include <plumb.h>
+#include <complete.h>
+#include "term.h"
 
-#define fatal	sysfatal
-
 typedef struct Text	Text;
 typedef struct Readbuf	Readbuf;
 
 enum
 {
-	/* these are chosen to use malloc()'s properties well */
 	HiWater	= 640000,	/* max size of history */
-	LoWater	= 330000,	/* min size of history after max'ed */
+	LoWater	= 400000,	/* min size of history after max'ed */
+	MinWater	= 20000,
 };
 
 /* various geometric paramters */
@@ -30,21 +39,22 @@ enum
 	Scroll,
 };
 
-
-#define	SCROLLKEY	Kdown
 #define	ESC		0x1B
-#define CUT		0x18	/* ctrl-x */		
-#define COPY		0x03	/* crtl-c */
-#define PASTE		0x16	/* crtl-v */
-#define BACKSCROLLKEY	Kup
+#define	CUT		0x18	/* ctrl-x */		
+#define	COPY		0x03	/* crtl-c */
+#define	PASTE		0x16	/* crtl-v */
 
 #define	READBUFSIZE 8192
+#define TRUE 1
+#define FALSE 0
 
+
 struct Text
 {
 	Frame		*f;		/* frame ofr terminal */
 	Mouse		m;
 	uint		nr;		/* num of runes in term */
+	uint		maxr;	/* max num of runes in r */
 	Rune		*r;		/* runes for term */
 	uint		nraw;		/* num of runes in raw buffer */
 	Rune		*raw;		/* raw buffer */
@@ -72,7 +82,6 @@ void	fill(void);
 void	tcheck(void);
 void	updatesel(void);
 void	doreshape(void);
-void	rcstart(int fd[2], int, char**);
 void	runewrite(Rune*, int);
 void	consread(void);
 void	conswrite(char*, int);
@@ -99,11 +108,10 @@ void	scrdraw(void);
 void	scroll(int);
 void	hostproc(void *arg);
 void	hoststart(void);
-int	getchildwd(int, char*, int);
 void	plumbstart(void);
 void	plumb(uint, uint);
 void	plumbclick(uint*, uint*);
-int	getpts(int fd[], char *slave);
+uint	insert(Rune*, int, uint, int);
 
 #define	runemalloc(n)		malloc((n)*sizeof(Rune))
 #define	runerealloc(a, n)	realloc(a, (n)*sizeof(Rune))
@@ -115,7 +123,7 @@ int		rawon;		/* raw mode */
 int		scrolling;	/* window scrolls */
 int		clickmsec;	/* time of last click */
 uint		clickq0;	/* point of last click */
-int		rcfd[2];
+int		rcfd;
 int		rcpid;
 int		maxtab;
 int		use9wm;
@@ -211,7 +219,7 @@ threadmain(int argc, char *argv[])
 
 	mc = initmouse(nil, screen);
 	kc = initkeyboard(nil);
-	rcstart(rcfd, argc, argv);
+	rcpid = rcstart(argc, argv, &rcfd);
 	hoststart();
 	plumbstart();
 
@@ -265,8 +273,9 @@ hostproc(void *arg)
 
 	i = 0;
 	for(;;){
+		/* Let typing have a go -- maybe there's a rubout waiting. */
 		i = 1-i;	/* toggle */
-		n = threadread(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
+		n = threadread(rcfd, rcbuf[i].data, sizeof rcbuf[i].data);
 		if(n <= 0){
 			if(n < 0)
 				fprint(2, "9term: host read error: %r\n");
@@ -308,7 +317,7 @@ loop(void)
 			a[2].op = CHANNOP;;
 		switch(alt(a)) {
 		default:
-			fatal("impossible");
+			sysfatal("impossible");
 		case 0:
 			t.m = mc->m;
 			mouse();
@@ -330,23 +339,23 @@ void
 doreshape(void)
 {
 	if(getwindow(display, Refnone) < 0)
-		fatal("can't reattach to window");
+		sysfatal("can't reattach to window");
 	draw(screen, screen->r, cols[BACK], nil, ZP);
 	geom();
 	scrdraw();
 }
 
-struct winsize ows;
-
 void
 geom(void)
 {
-	struct winsize ws;
 	Point p;
 	Rectangle r;
 
 	r = screen->r;
-	scrollr = screen->r;
+	r.min.y++;
+	r.max.y--;
+
+	scrollr = r;
 	scrollr.max.x = r.min.x+Scrollwid;
 	lastsr = Rect(0,0,0,0);
 
@@ -362,13 +371,7 @@ geom(void)
 	if(p.x == 0 || p.y == 0)
 		return;
 
-	ws.ws_row = Dy(r)/p.y;
-	ws.ws_col = Dx(r)/p.x;
-	ws.ws_xpixel = Dx(r);
-	ws.ws_ypixel = Dy(r);
-	if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
-	if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
-		fprint(2, "ioctl: %r\n");
+	updatewinsize(Dy(r)/p.y, Dx(r)/p.x, Dx(r), Dy(r));
 }
 
 void
@@ -585,7 +588,10 @@ domenu2(int but)
 			show(t.q0);
 		break;
 	case Send:
-		snarf();
+		if(t.q0 != t.q1)
+			snarf();
+		else
+			snarfupdate();
 		t.q0 = t.q1 = t.nr;
 		updatesel();
 		paste(t.snarf, t.nsnarf, 1);
@@ -605,37 +611,182 @@ domenu2(int but)
 		plumb(t.q0, t.q1);
 		break;
 	default:
-		fatal("bad menu item");
+		sysfatal("bad menu item");
 	}
+}
+
+int
+windfilewidth(uint q0, int oneelement)
+{
+	uint q;
+	Rune r;
+
+	q = q0;
+	while(q > 0){
+		r = t.r[q-1];
+		if(r<=' ')
+			break;
+		if(oneelement && r=='/')
+			break;
+		--q;
+	}
+	return q0-q;
 }
 
 void
+showcandidates(Completion *c)
+{
+	int i;
+	Fmt f;
+	Rune *rp;
+	uint nr, qline, q0;
+	char *s;
+
+	runefmtstrinit(&f);
+	if (c->nmatch == 0)
+		s = "[no matches in ";
+	else
+		s = "[";
+	if(c->nfile > 32)
+		fmtprint(&f, "%s%d files]\n", s, c->nfile);
+	else{
+		fmtprint(&f, "%s", s);
+		for(i=0; i<c->nfile; i++){
+			if(i > 0)
+				fmtprint(&f, " ");
+			fmtprint(&f, "%s", c->filename[i]);
+		}
+		fmtprint(&f, "]\n");
+	}
+	/* place text at beginning of line before host point */
+	qline = t.qh;
+	while(qline>0 && t.r[qline-1] != '\n')
+		qline--;
+
+	rp = runefmtstrflush(&f);
+	nr = runestrlen(rp);
+
+	q0 = t.q0;
+	q0 += insert(rp, nr, qline, 0) - qline;
+	free(rp);
+	t.q0 = q0+nr;
+	t.q1 = q0+nr;
+	updatesel();
+}
+
+Rune*
+namecomplete(void)
+{
+	int nstr, npath;
+	Rune *rp, *path, *str;
+	Completion *c;
+	char *s, *dir, *root;
+
+	/* control-f: filename completion; works back to white space or / */
+	if(t.q0<t.nr && t.r[t.q0]>' ')	/* must be at end of word */
+		return nil;
+	nstr = windfilewidth(t.q0, TRUE);
+	str = runemalloc(nstr);
+	runemove(str, t.r+(t.q0-nstr), nstr);
+	npath = windfilewidth(t.q0-nstr, FALSE);
+	path = runemalloc(npath);
+	runemove(path, t.r+(t.q0-nstr-npath), npath);
+	rp = nil;
+
+	/* is path rooted? if not, we need to make it relative to window path */
+	if(npath>0 && path[0]=='/'){
+		dir = malloc(UTFmax*npath+1);
+		sprint(dir, "%.*S", npath, path);
+	}else{
+		if(strcmp(wdir, "") == 0)
+			root = ".";
+		else
+			root = wdir;
+		dir = malloc(strlen(root)+1+UTFmax*npath+1);
+		sprint(dir, "%s/%.*S", root, npath, path);
+	}
+	dir = cleanname(dir);
+
+	s = smprint("%.*S", nstr, str);
+	c = complete(dir, s);
+	free(s);
+	if(c == nil)
+		goto Return;
+
+	if(!c->advance)
+		showcandidates(c);
+
+	if(c->advance)
+		rp = runesmprint("%s", c->string);
+
+  Return:
+	freecompletion(c);
+	free(dir);
+	free(path);
+	free(str);
+	return rp;
+}
+
+void
 key(Rune r)
 {
-	uint sig;
+	Rune *rp;
+	int nr;
 
 	if(r == 0)
 		return;
-	if(r==SCROLLKEY){	/* scroll key */
+	switch(r){
+	case Kpgup:
+		setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
+		return;
+	case Kpgdown:
 		setorigin(line2q(t.f->maxlines*2/3), 1);
 		if(t.qh<=t.org+t.f->nchars)
 			consread();
 		return;
-	}else if(r == BACKSCROLLKEY){
-		setorigin(backnl(t.org, t.f->maxlines*2/3), 1);
+	case Kup:
+		setorigin(backnl(t.org, t.f->maxlines/3), 1);
 		return;
-	}else if(r == CUT){
+	case Kdown:
+		setorigin(line2q(t.f->maxlines/3), 1);
+		if(t.qh<=t.org+t.f->nchars)
+			consread();
+		return;
+	case Kleft:
+		if(t.q0 > 0){
+			t.q0--;
+			t.q1 = t.q0;
+			updatesel();
+			show(t.q0);
+		}
+		return;
+	case Kright:
+		if(t.q1 < t.nr){
+			t.q1++;
+			t.q0 = t.q1;
+			updatesel();
+			show(t.q1);
+		}
+		return;
+	case Khome:
+		show(0);
+		return;
+	case Kend:
+	case 0x05:
+		show(t.nr);
+		return;
+	case CUT:
 		snarf();
 		cut();
 		if(scrolling)
 			show(t.q0);
 		return;
-	}else if(r == COPY){
+	case COPY:
 		snarf();
 		if(scrolling)
 			show(t.q0);
 		return;
-	}else if(r == PASTE){
+	case PASTE:
 		snarfupdate();
 		paste(t.snarf, t.nsnarf, 0);
 		if(scrolling)
@@ -661,19 +812,21 @@ key(Rune r)
 	snarf();
 
 	switch(r) {
+	case 0x03:	/* ^C: send interrupt */
 	case 0x7F:	/* DEL: send interrupt */
 		t.qh = t.q0 = t.q1 = t.nr;
 		show(t.q0);
-		goto Default;
-fprint(2, "send interrupt to %d group\n", rcpid);
-#ifdef TIOCSIG
-		sig = 2; /* SIGINT */
-		if(ioctl(rcfd[0], TIOCSIG, &sig) < 0)
-			fprint(2, "sending interrupt: %r\n");
-#else
-		postnote(PNGROUP, rcpid, "interrupt");
-#endif
+		write(rcfd, "\x7F", 1);
 		break;
+	case 0x06:	/* ^F: file name completion */
+	case Kins:		/* Insert: file name completion */
+		rp = namecomplete();
+		if(rp == nil)
+			return;
+		nr = runestrlen(rp);
+		paste(rp, nr, 1);
+		free(rp);
+		return;
 	case 0x08:	/* ^H: erase character */
 	case 0x15:	/* ^U: erase line */
 	case 0x17:	/* ^W: erase word */
@@ -682,7 +835,6 @@ fprint(2, "send interrupt to %d group\n", rcpid);
 		cut();
 		break;
 	default:
-	Default:
 		paste(&r, 1, 1);
 		break;
 	}
@@ -773,7 +925,7 @@ consread(void)
 		}
 		/* take out control-d when not doing a zero length write */
 		n = p-buf;
-		if(write(rcfd[1], buf, n) < 0)
+		if(write(rcfd, buf, n) < 0)
 			exits(0);
 /*		mallocstats(); */
 	}
@@ -833,7 +985,6 @@ conswrite(char *p, int n)
 void
 runewrite(Rune *r, int n)
 {
-	uint m;
 	int i;
 	uint initial;
 	uint q0, q1;
@@ -896,37 +1047,7 @@ runewrite(Rune *r, int n)
 		updatesel();
 	}
 
-	if(t.nr>HiWater && t.qh>=t.org){
-		m = HiWater-LoWater;
-		if(m > t.org);
-			m = t.org;
-		t.org -= m;
-		t.qh -= m;
-		if(t.q0 > m)
-			t.q0 -= m;
-		else
-			t.q0 = 0;
-		if(t.q1 > m)
-			t.q1 -= m;
-		else
-			t.q1 = 0;
-		t.nr -= m;
-		runemove(t.r, t.r+m, t.nr);
-	}
-	t.r = runerealloc(t.r, t.nr+n);
-	runemove(t.r+t.qh+n, t.r+t.qh, t.nr-t.qh);
-	runemove(t.r+t.qh, r, n);
-	t.nr += n;
-	if(t.qh < t.org)
-		t.org += n;
-	else if(t.qh <= t.f->nchars+t.org)
-		frinsert(t.f, r, r+n, t.qh-t.org);
-	if (t.qh <= t.q0)
-		t.q0 += n;
-	if (t.qh <= t.q1)
-		t.q1 += n;
-	t.qh += n;
-	updatesel();
+	insert(r, n, t.qh, 1);
 }
 
 
@@ -1009,12 +1130,83 @@ snarf(void)
 	putsnarf(sbuf);
 }
 
+uint
+min(uint x, uint y)
+{
+	if(x < y)
+		return x;
+	return y;
+}
+
+uint
+max(uint x, uint y)
+{
+	if(x > y)
+		return x;
+	return y;
+}
+
+uint
+insert(Rune *r, int n, uint q0, int hostwrite)
+{
+	uint m;
+
+	if(n == 0)
+		return q0;
+	if(t.nr+n>HiWater && q0>=t.org && q0>=t.qh){
+		m = min(HiWater-LoWater, min(t.org, t.qh));
+		t.org -= m;
+		t.qh -= m;
+		if(t.q0 > m)
+			t.q0 -= m;
+		else
+			t.q0 = 0;
+		if(t.q1 > m)
+			t.q1 -= m;
+		else
+			t.q1 = 0;
+		t.nr -= m;
+		runemove(t.r, t.r+m, t.nr);
+		q0 -= m;
+	}
+	if(t.nr+n > t.maxr){
+		/*
+		 * Minimize realloc breakage:
+		 *	Allocate at least MinWater
+		 * 	Double allocation size each time
+		 *	But don't go much above HiWater
+		 */
+		m = max(min(2*(t.nr+n), HiWater), t.nr+n)+MinWater;
+		if(m > HiWater)
+			m = max(HiWater+MinWater, t.nr+n);
+		if(m > t.maxr){
+			t.r = runerealloc(t.r, m);
+			t.maxr = m;
+		}
+	}
+	runemove(t.r+q0+n, t.r+q0, t.nr-q0);
+	runemove(t.r+q0, r, n);
+	t.nr += n;
+	/* if output touches, advance selection, not qh; works best for keyboard and output */
+	if(q0 <= t.q1)
+		t.q1 += n;
+	if(q0 <= t.q0)
+		t.q0 += n;
+	if(q0 < t.qh || (q0==t.qh && hostwrite))
+		t.qh += n;
+	else
+		consread();
+	if(q0 < t.org)
+		t.org += n;
+	else if(q0 <= t.org+t.f->nchars)
+		frinsert(t.f, r, r+n, q0-t.org);
+	return q0;
+}
+
 void
 paste(Rune *r, int n, int advance)
 {
 	Rune *rbuf;
-	uint m;
-	uint q0;
 
 	if(rawon && t.q0==t.nr){
 		addraw(r, n);
@@ -1024,6 +1216,7 @@ paste(Rune *r, int n, int advance)
 	cut();
 	if(n == 0)
 		return;
+
 	/*
 	 * if this is a button2 execute then we might have been passed
 	 * runes inside the buffer.  must save them before realloc.
@@ -1033,38 +1226,9 @@ paste(Rune *r, int n, int advance)
 		rbuf = runemalloc(n);
 		runemove(rbuf, r, n);
 		r = rbuf;
-	}
-
-	if(t.nr>HiWater && t.q0>=t.org && t.q0>=t.qh){
-		m = HiWater-LoWater;
-		if(m > t.org)
-			m = t.org;
-		if(m > t.qh);
-			m = t.qh;
-		t.org -= m;
-		t.qh -= m;
-		t.q0 -= m;
-		t.q1 -= m;
-		t.nr -= m;
-		runemove(t.r, t.r+m, t.nr);
 	}
 
-	t.r = runerealloc(t.r, t.nr+n);
-	q0 = t.q0;
-	runemove(t.r+q0+n, t.r+q0, t.nr-q0);
-	runemove(t.r+q0, r, n);
-	t.nr += n;
-	if(q0 < t.qh)
-		t.qh += n;
-	else
-		consread();
-	if(q0 < t.org)
-		t.org += n;
-	else if(q0 <= t.f->nchars+t.org)
-		frinsert(t.f, r, r+n, q0-t.org);
-	if(advance)
-		t.q0 += n;
-	t.q1 += n;
+	insert(r, n, t.q0, 0);
 	updatesel();
 	free(rbuf);
 }
@@ -1322,61 +1486,6 @@ clickmatch(int cl, int cr, int dir, uint *q)
 }
 
 void
-rcstart(int fd[2], int argc, char **argv)
-{
-	int pid;
-	char *xargv[3];
-	char slave[256];
-	int sfd;
-
-	if(argc == 0){
-		argc = 2;
-		argv = xargv;
-		argv[0] = getenv("SHELL");
-		if(argv[0] == 0)
-			argv[0] = "rc";
-		argv[1] = "-i";
-		argv[2] = 0;
-	}
-	/*
-	 * fd0 is slave (tty), fd1 is master (pty)
-	 */
-	fd[0] = fd[1] = -1;
-	if(getpts(fd, slave) < 0)
-		fprint(2, "getpts: %r\n");
-
-	switch(pid = fork()) {
-	case 0:
-		putenv("TERM", "9term");
-		close(fd[1]);
-		setsid();
-//		tcsetpgrp(0, pid);
-		sfd = open(slave, ORDWR);
-		if(sfd < 0)
-			fprint(2, "open %s: %r\n", slave);
-		if(ioctl(sfd, TIOCSCTTY, 0) < 0)
-			fprint(2, "ioctl TIOCSCTTY: %r\n");
-//		ioctl(sfd, I_PUSH, "ptem");
-//		ioctl(sfd, I_PUSH, "ldterm");
-		dup(sfd, 0);
-		dup(sfd, 1);
-		dup(sfd, 2);
-		system("stty tabs -onlcr -echo erase ^h intr ^?");
-		execvp(argv[0], argv);
-		fprint(2, "exec %s failed: %r\n", argv[0]);
-		_exits("oops");
-		break;
-	case -1:
-		fatal("proc failed: %r");
-		break;
-	}
-	close(fd[0]);
-	fd[0] = fd[1];
-
-	rcpid = pid;
-}
-
-void
 tcheck(void)
 {
 	Frame *f;
@@ -1421,7 +1530,7 @@ scrdraw(void)
 			freeimage(scrx);
 		scrx = allocimage(display, Rect(0, 0, 32, r.max.y), screen->chan, 1, DPaleyellow);
 		if(scrx == 0)
-			fatal("scroll balloc");
+			sysfatal("scroll balloc");
 	}
 	r1.min.x = 0;
 	r1.max.x = Dx(r);
@@ -1525,16 +1634,11 @@ plumb(uint q0, uint q1)
 	char *p;
 	int i, p0, n;
 	char cbuf[100];
-	char *w;
 
-	if(getchildwd(rcpid, childwdir, sizeof childwdir) == 0)
-		w = childwdir;
-	else
-		w = wdir;
 	pm = malloc(sizeof(Plumbmsg));
 	pm->src = strdup("9term");
 	pm->dst = 0;
-	pm->wdir = strdup(w);
+	pm->wdir = strdup(wdir);
 	pm->type = strdup("text");
 	pm->data = nil;
 	if(q1 > q0)
blob - 4e8d61f3887e441116c1c29fc1aa70226fc10962
blob + 57a8359e14a0285ea0f2162eb61a27a0f92175fe
--- src/cmd/9term/9term.h
+++ src/cmd/9term/9term.h
@@ -1,19 +1,4 @@
-#include <u.h>
-#include <libc.h>
-#include <ctype.h>
-#include <draw.h>
-#include <thread.h>
-#include <mouse.h>
-#include <cursor.h>
-#include <keyboard.h>
-#include <frame.h>
-#include <plumb.h>
-#include <termios.h>
-#include <sys/termios.h>
-#ifdef __linux__
-#include <pty.h>
-#endif
-
-extern int getchildwd(int, char*, int);
 extern int getpts(int[], char*);
-
+extern int childpty(int[], char*);
+extern void updatewinsize(int, int, int, int);
+extern int rcfd[];
blob - e8b894dc83698fd802a3df51fef6c87a8d32cc60
blob + 7022d4d97bbcc6463743c5896671c5b72df537eb
--- src/cmd/9term/FreeBSD.c
+++ src/cmd/9term/FreeBSD.c
@@ -1,17 +1,43 @@
 #include "9term.h"
+#include <termios.h>
+#include <sys/termios.h>
 #include <libutil.h>
 
 int
-getchildwd(int pid, char *wdir, int bufn)
+getpts(int fd[], char *slave)
 {
-	USED(pid);
-	USED(wdir);
-	USED(bufn);
-	return -1;
+	return openpty(&fd[1], &fd[0], slave, 0, 0);
 }
 
 int
-getpts(int fd[], char *slave)
+childpty(int fd[], char *slave)
 {
-	return openpty(&fd[1], &fd[0], slave, 0, 0);
+	int sfd;
+
+	close(fd[1]);
+	setsid();
+	sfd = open(slave, ORDWR);
+	if(sfd < 0)
+		sysfatal("open %s: %r\n", slave);
+	if(ioctl(sfd, TIOCSCTTY, 0) < 0)
+		fprint(2, "ioctl TIOCSCTTY: %r\n");
+	return sfd;
 }
+
+struct winsize ows;
+
+void
+updatewinsize(int row, int col, int dx, int dy)
+{
+	struct winsize ws;
+
+	ws.ws_row = row;
+	ws.ws_col = col;
+	ws.ws_xpixel = dx;
+	ws.ws_ypixel = dy;
+	if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
+	if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
+		fprint(2, "ioctl: %r\n");
+	ows = ws;
+}
+
blob - 7dd22371be723649b347508f25bcd58ac0b2a4f6
blob + 872417e6c501b8c3f1f8d0bcaba529e0f6110c67
--- src/cmd/9term/Linux.c
+++ src/cmd/9term/Linux.c
@@ -1,22 +1,46 @@
+#include <u.h>
+#include <termios.h>
+#include <sys/termios.h>
+#include <pty.h>
+#include <libc.h>
 #include "9term.h"
 
 int
-getchildwd(int pid, char *wdir, int bufn)
+getpts(int fd[], char *slave)
 {
-	char path[256];
-	int n;
-
-	snprint(path, sizeof path, "/proc/%d/cwd", pid);
-	n = readlink(path, wdir, bufn);
-	if(n < 0)
-		return -1;
-	wdir[n] = '\0';
+	openpty(&fd[1], &fd[0], slave, 0, 0);
 	return 0;
 }
 
 int
-getpts(int fd[], char *slave)
+childpty(int fd[], char *slave)
 {
-	openpty(&fd[1], &fd[0], slave, 0, 0);
-	return 0;
+	int sfd;
+
+	close(fd[1]);
+	setsid();
+	sfd = open(slave, ORDWR);
+	if(sfd < 0)
+		sysfatal("open %s: %r\n", slave);
+	if(ioctl(sfd, TIOCSCTTY, 0) < 0)
+		fprint(2, "ioctl TIOCSCTTY: %r\n");
+	return sfd;
 }
+
+struct winsize ows;
+
+void
+updatewinsize(int row, int col, int dx, int dy)
+{
+	struct winsize ws;
+
+	ws.ws_row = row;
+	ws.ws_col = col;
+	ws.ws_xpixel = dx;
+	ws.ws_ypixel = dy;
+	if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
+	if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
+		fprint(2, "ioctl: %r\n");
+	ows = ws;
+}
+
blob - 6a37ab337851a56a2708834897f164ae930f066c
blob + d7db9fc5de818620c1d86962c3a4befd6154d506
--- src/cmd/9term/SunOS.c
+++ src/cmd/9term/SunOS.c
@@ -1,23 +1,8 @@
 #include "9term.h"
+#include <termios.h>
+#include <sys/termios.h>
 
 int
-getchildwd(int pid, char *wdir, int bufn)
-{
-	char path[256];
-	char cwd[256];
-
-	if(getcwd(cwd, sizeof cwd) < 0)
-		return -1;
-	snprint(path, sizeof path, "/proc/%d/cwd", pid);
-	if(chdir(path) < 0)
-		return -1;
-	if(getcwd(wdir, bufn) < 0)
-		return -1;
-	chdir(cwd);
-	return 0;
-}
-
-int
 getpts(int fd[], char *slave)
 {
 	fd[1] = open("/dev/ptmx", ORDWR);
@@ -28,3 +13,21 @@ getpts(int fd[], char *slave)
 	fd[0] = open(slave, OREAD);
 	return 0;
 }
+
+struct winsize ows;
+
+void
+updatewinsize(int row, int col, int dx, int dy)
+{
+	struct winsize ws;
+
+	ws.ws_row = row;
+	ws.ws_col = col;
+	ws.ws_xpixel = dx;
+	ws.ws_ypixel = dy;
+	if(ws.ws_row != ows.ws_row || ws.ws_col != ows.ws_col)
+	if(ioctl(rcfd[0], TIOCSWINSZ, &ws) < 0)
+		fprint(2, "ioctl: %r\n");
+	ows = ws;
+}
+
blob - d0d5ca727ee2bbde366ff4a1fe5983b5a9c0facb
blob + 8701ad9c4f21d9c76b8dbe9bbfcde00720c1c51e
--- src/cmd/9term/mkfile
+++ src/cmd/9term/mkfile
@@ -1,15 +1,15 @@
 PLAN9=../../..
 <$PLAN9/src/mkhdr
 
-TARG=9term
+TARG=9term win
 
 OFILES=\
-	9term.$O\
+	rcstart.$O\
 	$SYSNAME.$O\
 
-SHORTLIB=frame draw plumb fs mux thread 9
+SHORTLIB=complete frame draw plumb fs mux thread 9
 
-<$PLAN9/src/mkone
+<$PLAN9/src/mkmany
 
 LDFLAGS=-L$X11/lib -lX11 -lutil
 
blob - /dev/null
blob + 7596bc41dabe45627fe6e7a63ca4a6d545bde70d (mode 644)
--- /dev/null
+++ src/cmd/9term/rcstart.c
@@ -0,0 +1,51 @@
+#include <u.h>
+#include <libc.h>
+#include "term.h"
+
+int
+rcstart(int argc, char **argv, int *pfd)
+{
+	int pid;
+	int fd[2];
+	char *xargv[3];
+	char slave[256];
+	int sfd;
+
+	if(argc == 0){
+		argc = 2;
+		argv = xargv;
+		argv[0] = getenv("SHELL");
+		if(argv[0] == 0)
+			argv[0] = "rc";
+		argv[1] = "-i";
+		argv[2] = 0;
+	}
+	/*
+	 * fd0 is slave (tty), fd1 is master (pty)
+	 */
+	fd[0] = fd[1] = -1;
+	if(getpts(fd, slave) < 0)
+		fprint(2, "getpts: %r\n");
+
+
+	switch(pid = fork()) {
+	case 0:
+		putenv("TERM", "9term");
+		sfd = childpty(fd, slave);
+		dup(sfd, 0);
+		dup(sfd, 1);
+		dup(sfd, 2);
+		system("stty tabs -onlcr -echo erase ^h intr ^?");
+		execvp(argv[0], argv);
+		fprint(2, "exec %s failed: %r\n", argv[0]);
+		_exits("oops");
+		break;
+	case -1:
+		sysfatal("proc failed: %r");
+		break;
+	}
+	close(fd[0]);
+	*pfd = fd[1];
+	return pid;
+}
+
blob - /dev/null
blob + a608b7edf837e9ed63229c934b86ee54be73ce8d (mode 644)
--- /dev/null
+++ src/cmd/9term/term.h
@@ -0,0 +1,5 @@
+extern int getpts(int[], char*);
+extern int childpty(int[], char*);
+extern void updatewinsize(int, int, int, int);
+extern int rcfd;
+extern int rcstart(int, char*[], int*);
blob - /dev/null
blob + 95d84a32fa8fb64afae6a062f45c08f989dffdb5 (mode 644)
--- /dev/null
+++ src/cmd/9term/win.c
@@ -0,0 +1,693 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <fcall.h>
+#include <fs.h>
+#include "term.h"
+
+#define	EVENTSIZE	256
+#define	STACK	32768
+
+typedef struct Event Event;
+typedef struct Q Q;
+
+struct Event
+{
+	int	c1;
+	int	c2;
+	int	q0;
+	int	q1;
+	int	flag;
+	int	nb;
+	int	nr;
+	char	b[EVENTSIZE*UTFmax+1];
+	Rune	r[EVENTSIZE+1];
+};
+
+Event blank = {
+	'M',
+	'X',
+	0, 0, 0, 1, 1,
+	{ ' ', 0 },
+	{ ' ', 0 },
+};
+
+struct Q
+{
+	QLock	lk;
+	int		p;
+	int		k;
+};
+
+Q	q;
+
+Fid *eventfd;
+Fid *addrfd;
+Fid *datafd;
+Fid *ctlfd;
+// int bodyfd;
+
+char	*typing;
+int	ntypeb;
+int	ntyper;
+int	ntypebreak;
+int	debug;
+int	rcfd;
+
+char *name;
+
+char **prog;
+Channel *cwait;
+int pid = -1;
+
+int	label(char*, int);
+void	error(char*);
+void	stdinproc(void*);
+void	stdoutproc(void*);
+void	type(Event*, int, Fid*, Fid*);
+void	sende(Event*, int, Fid*, Fid*, Fid*, int);
+char	*onestring(int, char**);
+int	delete(Event*);
+void	deltype(uint, uint);
+void	runproc(void*);
+
+int
+fsfidprint(Fid *fid, char *fmt, ...)
+{
+	char buf[256];
+	va_list arg;
+	int n;
+
+	va_start(arg, fmt);
+	n = vsnprint(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	return fswrite(fid, buf, n);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: win cmd args...\n");
+	threadexitsall("usage");
+}
+
+int
+nopipes(void *v, char *msg)
+{
+	USED(v);
+	if(strcmp(msg, "sys: write on closed pipe") == 0)
+		return 1;
+	return 0;
+}
+
+void
+waitthread(void *v)
+{
+	recvp(cwait);
+	threadexitsall(nil);
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	int fd, id;
+	char buf[256];
+	char buf1[128];
+	Fsys *fs;
+
+	ARGBEGIN{
+	case 'd':
+		debug = 1;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	prog = argv;
+
+	if(argc > 0){
+		name = argv[0];
+		argc--;
+		argv++;
+	}else
+		name = "gnot";
+
+	threadnotify(nopipes, 1);
+	if((fs = nsmount("acme", "")) < 0)
+		sysfatal("nsmount acme: %r");
+	ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
+	if(ctlfd < 0 || fsread(ctlfd, buf, 12) != 12)
+		sysfatal("ctl: %r");
+	id = atoi(buf);
+	sprint(buf, "%d/tag", id);
+	fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
+	write(fd, " Send Delete", 12);
+	close(fd);
+	sprint(buf, "%d/event", id);
+	eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
+	sprint(buf, "%d/addr", id);
+	addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
+	sprint(buf, "%d/data", id);
+	datafd = fsopen(fs, buf, ORDWR|OCEXEC);
+	sprint(buf, "%d/body", id);
+/*	bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
+	if(eventfd==nil || addrfd==nil || datafd==nil)
+		sysfatal("data files: %r");
+/*
+	if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
+		sysfatal("data files: %r");
+*/
+	fsunmount(fs);
+
+	cwait = threadwaitchan();
+	threadcreate(waitthread, nil, STACK);
+	pid = rcstart(argc, argv, &rcfd);
+	if(pid == -1)
+		sysfatal("exec failed");
+
+	getwd(buf1, sizeof buf1);
+	sprint(buf, "name %s/-%s\n0\n", buf1, name);
+	fswrite(ctlfd, buf, strlen(buf));
+	sprint(buf, "dumpdir %s/\n", buf1);
+	fswrite(ctlfd, buf, strlen(buf));
+	sprint(buf, "dump %s\n", onestring(argc, argv));
+	fswrite(ctlfd, buf, strlen(buf));
+	
+	threadcreate(stdoutproc, nil, STACK);
+	stdinproc(nil);
+}
+
+void
+error(char *s)
+{
+	if(s)
+		fprint(2, "win: %s: %r\n", s);
+	else
+		s = "kill";
+	if(pid != -1)
+		postnote(PNGROUP, pid, "hangup");
+	threadexitsall(s);
+}
+
+char*
+onestring(int argc, char **argv)
+{
+	char *p;
+	int i, n;
+	static char buf[1024];
+
+	if(argc == 0)
+		return "";
+	p = buf;
+	for(i=0; i<argc; i++){
+		n = strlen(argv[i]);
+		if(p+n+1 >= buf+sizeof buf)
+			break;
+		memmove(p, argv[i], n);
+		p += n;
+		*p++ = ' ';
+	}
+	p[-1] = 0;
+	return buf;
+}
+
+int
+getec(Fid *efd)
+{
+	static char buf[8192];
+	static char *bufp;
+	static int nbuf;
+
+	if(nbuf == 0){
+		nbuf = fsread(efd, buf, sizeof buf);
+		if(nbuf <= 0)
+			error(nil);
+		bufp = buf;
+	}
+	--nbuf;
+	return *bufp++;
+}
+
+int
+geten(Fid *efd)
+{
+	int n, c;
+
+	n = 0;
+	while('0'<=(c=getec(efd)) && c<='9')
+		n = n*10+(c-'0');
+	if(c != ' ')
+		error("event number syntax");
+	return n;
+}
+
+int
+geter(Fid *efd, char *buf, int *nb)
+{
+	Rune r;
+	int n;
+
+	r = getec(efd);
+	buf[0] = r;
+	n = 1;
+	if(r < Runeself)
+		goto Return;
+	while(!fullrune(buf, n))
+		buf[n++] = getec(efd);
+	chartorune(&r, buf);
+    Return:
+	*nb = n;
+	return r;
+}
+
+void
+gete(Fid *efd, Event *e)
+{
+	int i, nb;
+
+	e->c1 = getec(efd);
+	e->c2 = getec(efd);
+	e->q0 = geten(efd);
+	e->q1 = geten(efd);
+	e->flag = geten(efd);
+	e->nr = geten(efd);
+	if(e->nr > EVENTSIZE)
+		error("event string too long");
+	e->nb = 0;
+	for(i=0; i<e->nr; i++){
+		e->r[i] = geter(efd, e->b+e->nb, &nb);
+		e->nb += nb;
+	}
+	e->r[e->nr] = 0;
+	e->b[e->nb] = 0;
+	if(getec(efd) != '\n')
+		error("event syntax 2");
+}
+
+int
+nrunes(char *s, int nb)
+{
+	int i, n;
+	Rune r;
+
+	n = 0;
+	for(i=0; i<nb; n++)
+		i += chartorune(&r, s+i);
+	return n;
+}
+
+void
+stdinproc(void *v)
+{
+	Fid *cfd = ctlfd;
+	Fid *efd = eventfd;
+	Fid *dfd = datafd;
+	Fid *afd = addrfd;
+	int fd0 = rcfd;
+	Event e, e2, e3, e4;
+
+	USED(v);
+
+	for(;;){
+		if(debug)
+			fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
+		gete(efd, &e);
+		if(debug)
+			fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
+		qlock(&q.lk);
+		switch(e.c1){
+		default:
+		Unknown:
+			print("unknown message %c%c\n", e.c1, e.c2);
+			break;
+
+		case 'E':	/* write to body; can't affect us */
+			if(debug)
+				fprint(2, "shift typing %d... ", e.q1-e.q0);
+			q.p += e.q1-e.q0;
+			break;
+
+		case 'F':	/* generated by our actions; ignore */
+			break;
+
+		case 'K':
+		case 'M':
+			switch(e.c2){
+			case 'I':
+				if(e.q0 < q.p){
+					if(debug)
+						fprint(2, "shift typing %d... ", e.q1-e.q0);
+					q.p += e.q1-e.q0;
+				}
+				else if(e.q0 <= q.p+ntyper){
+					if(debug)
+						fprint(2, "type... ");
+					type(&e, fd0, afd, dfd);
+				}
+				break;
+
+			case 'D':
+				q.p -= delete(&e);
+				break;
+
+			case 'x':
+			case 'X':
+				if(e.flag & 2)
+					gete(efd, &e2);
+				if(e.flag & 8){
+					gete(efd, &e3);
+					gete(efd, &e4);
+				}
+				if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
+					/* send it straight back */
+					fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
+					break;
+				}
+				if(e.q0==e.q1 && (e.flag&2)){
+					e2.flag = e.flag;
+					e = e2;
+				}
+				if(e.flag & 8){
+					if(e.q1 != e.q0){
+						sende(&e, fd0, cfd, afd, dfd, 0);
+						sende(&blank, fd0, cfd, afd, dfd, 0);
+					}
+					sende(&e3, fd0, cfd, afd, dfd, 1);
+				}else	 if(e.q1 != e.q0)
+					sende(&e, fd0, cfd, afd, dfd, 1);
+				break;
+
+			case 'l':
+			case 'L':
+				/* just send it back */
+				if(e.flag & 2)
+					gete(efd, &e2);
+				fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
+				break;
+
+			case 'd':
+			case 'i':
+				break;
+
+			default:
+				goto Unknown;
+			}
+		}
+		qunlock(&q.lk);
+	}
+}
+
+void
+stdoutproc(void *v)
+{
+	int fd1 = rcfd;
+	Fid *afd = addrfd;
+	Fid *dfd = datafd;
+	int n, m, w, npart;
+	char *buf, *s, *t;
+	Rune r;
+	char x[16], hold[UTFmax];
+
+	USED(v);
+	threadnotify(nopipes, 1);
+	buf = malloc(8192+UTFmax+1);
+	npart = 0;
+	for(;;){
+		/* Let typing have a go -- maybe there's a rubout waiting. */
+		yield();
+		n = threadread(fd1, buf+npart, 8192);
+		if(n < 0)
+			error(nil);
+		if(n == 0)
+			continue;
+
+		/* squash NULs */
+		s = memchr(buf+npart, 0, n);
+		if(s){
+			for(t=s; s<buf+npart+n; s++)
+				if(*t = *s)	/* assign = */
+					t++;
+			n = t-(buf+npart);
+		}
+
+		n += npart;
+
+		/* hold on to final partial rune */
+		npart = 0;
+		while(n>0 && (buf[n-1]&0xC0)){
+			--n;
+			npart++;
+			if((buf[n]&0xC0)!=0x80){
+				if(fullrune(buf+n, npart)){
+					w = chartorune(&r, buf+n);
+					n += w;
+					npart -= w;
+				}
+				break;
+			}
+		}
+		if(n > 0){
+			memmove(hold, buf+n, npart);
+			buf[n] = 0;
+			n = label(buf, n);
+			buf[n] = 0;
+			qlock(&q.lk);
+			m = sprint(x, "#%d", q.p);
+			if(fswrite(afd, x, m) != m)
+				error("stdout writing address");
+			if(fswrite(dfd, buf, n) != n)
+				error("stdout writing body");
+			q.p += nrunes(buf, n);
+			qunlock(&q.lk);
+			memmove(buf, hold, npart);
+		}
+	}
+}
+
+char wdir[256];
+int
+label(char *sr, int n)
+{
+	char *sl, *el, *er, *r;
+
+	er = sr+n;
+	for(r=er-1; r>=sr; r--)
+		if(*r == '\007')
+			break;
+	if(r < sr)
+		return n;
+
+	el = r+1;
+	if(el-sr > sizeof wdir)
+		sr = el - sizeof wdir;
+	for(sl=el-3; sl>=sr; sl--)
+		if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
+			break;
+	if(sl < sr)
+		return n;
+
+	*r = 0;
+	snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
+	fswrite(ctlfd, wdir, strlen(wdir));
+
+	memmove(sl, el, er-el);
+	n -= (el-sl);
+	return n;
+}
+
+int
+delete(Event *e)
+{
+	uint q0, q1;
+	int deltap;
+
+	q0 = e->q0;
+	q1 = e->q1;
+	if(q1 <= q.p)
+		return e->q1-e->q0;
+	if(q0 >= q.p+ntyper)
+		return 0;
+	deltap = 0;
+	if(q0 < q.p){
+		deltap = q.p-q0;
+		q0 = 0;
+	}else
+		q0 -= q.p;
+	if(q1 > q.p+ntyper)
+		q1 = ntyper;
+	else
+		q1 -= q.p;
+	deltype(q0, q1);
+	return deltap;
+}
+
+void
+addtype(int c, uint p0, char *b, int nb, int nr)
+{
+	int i, w;
+	Rune r;
+	uint p;
+	char *b0;
+
+	for(i=0; i<nb; i+=w){
+		w = chartorune(&r, b+i);
+		if((r==0x7F||r==3) && c=='K'){
+			write(rcfd, "\x7F", 1);
+			/* toss all typing */
+			q.p += ntyper+nr;
+			ntypebreak = 0;
+			ntypeb = 0;
+			ntyper = 0;
+			/* buglet:  more than one delete ignored */
+			return;
+		}
+		if(r=='\n' || r==0x04)
+			ntypebreak++;
+	}
+	typing = realloc(typing, ntypeb+nb);
+	if(typing == nil)
+		error("realloc");
+	if(p0 == ntyper)
+		memmove(typing+ntypeb, b, nb);
+	else{
+		b0 = typing;
+		for(p=0; p<p0 && b0<typing+ntypeb; p++){
+			w = chartorune(&r, b0+i);
+			b0 += w;
+		}
+		if(p != p0)
+			error("typing: findrune");
+		memmove(b0+nb, b0, (typing+ntypeb)-b0);
+		memmove(b0, b, nb);
+	}
+	ntypeb += nb;
+	ntyper += nr;
+}
+
+void
+sendtype(int fd0)
+{
+	int i, n, nr;
+
+	while(ntypebreak){
+		for(i=0; i<ntypeb; i++)
+			if(typing[i]=='\n' || typing[i]==0x04){
+				n = i + (typing[i] == '\n');
+				i++;
+				if(write(fd0, typing, n) != n)
+					error("sending to program");
+				nr = nrunes(typing, i);
+				q.p += nr;
+				ntyper -= nr;
+				ntypeb -= i;
+				memmove(typing, typing+i, ntypeb);
+				ntypebreak--;
+				goto cont2;
+			}
+		print("no breakchar\n");
+		ntypebreak = 0;
+cont2:;
+	}
+}
+
+void
+deltype(uint p0, uint p1)
+{
+	int w;
+	uint p, b0, b1;
+	Rune r;
+
+	/* advance to p0 */
+	b0 = 0;
+	for(p=0; p<p0 && b0<ntypeb; p++){
+		w = chartorune(&r, typing+b0);
+		b0 += w;
+	}
+	if(p != p0)
+		error("deltype 1");
+	/* advance to p1 */
+	b1 = b0;
+	for(; p<p1 && b1<ntypeb; p++){
+		w = chartorune(&r, typing+b1);
+		b1 += w;
+		if(r=='\n' || r==0x04)
+			ntypebreak--;
+	}
+	if(p != p1)
+		error("deltype 2");
+	memmove(typing+b0, typing+b1, ntypeb-b1);
+	ntypeb -= b1-b0;
+	ntyper -= p1-p0;
+}
+
+void
+type(Event *e, int fd0, Fid *afd, Fid *dfd)
+{
+	int m, n, nr;
+	char buf[128];
+
+	if(e->nr > 0)
+		addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
+	else{
+		m = e->q0;
+		while(m < e->q1){
+			n = sprint(buf, "#%d", m);
+			fswrite(afd, buf, n);
+			n = fsread(dfd, buf, sizeof buf);
+			nr = nrunes(buf, n);
+			while(m+nr > e->q1){
+				do; while(n>0 && (buf[--n]&0xC0)==0x80);
+				--nr;
+			}
+			if(n == 0)
+				break;
+			addtype(e->c1, m-q.p, buf, n, nr);
+			m += nr;
+		}
+	}
+	sendtype(fd0);
+}
+
+void
+sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
+{
+	int l, m, n, nr, lastc, end;
+	char abuf[16], buf[128];
+
+	end = q.p+ntyper;
+	l = sprint(abuf, "#%d", end);
+	fswrite(afd, abuf, l);
+	if(e->nr > 0){
+		fswrite(dfd, e->b, e->nb);
+		addtype(e->c1, ntyper, e->b, e->nb, e->nr);
+		lastc = e->r[e->nr-1];
+	}else{
+		m = e->q0;
+		lastc = 0;
+		while(m < e->q1){
+			n = sprint(buf, "#%d", m);
+			fswrite(afd, buf, n);
+			n = fsread(dfd, buf, sizeof buf);
+			nr = nrunes(buf, n);
+			while(m+nr > e->q1){
+				do; while(n>0 && (buf[--n]&0xC0)==0x80);
+				--nr;
+			}
+			if(n == 0)
+				break;
+			l = sprint(abuf, "#%d", end);
+			fswrite(afd, abuf, l);
+			fswrite(dfd, buf, n);
+			addtype(e->c1, ntyper, buf, n, nr);
+			lastc = buf[n-1];
+			m += nr;
+			end += nr;
+		}
+	}
+	if(donl && lastc!='\n'){
+		fswrite(dfd, "\n", 1);
+		addtype(e->c1, ntyper, "\n", 1, 1);
+	}
+	fswrite(cfd, "dot=addr", 8);
+	sendtype(fd0);
+}
blob - d4b4cad83e152a40020d96e612c506e031dab5bf
blob + 9636beab1bb66efaf56d803295ed0d052c0100f1
--- src/cmd/acme/acme.c
+++ src/cmd/acme/acme.c
@@ -161,7 +161,8 @@ threadmain(int argc, char *argv[])
 	cerr = chancreate(sizeof(char*), 0);
 	cedit = chancreate(sizeof(int), 0);
 	cexit = chancreate(sizeof(int), 0);
-	if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil){
+	cwarn = chancreate(sizeof(void*), 1);
+	if(cwait==nil || ccommand==nil || ckill==nil || cxfidalloc==nil || cxfidfree==nil || cerr==nil || cexit==nil || cwarn==nil){
 		fprint(2, "acme: can't create initial channels: %r\n");
 		exits("channels");
 	}
@@ -251,7 +252,7 @@ readfile(Column *c, char *s)
 
 	w = coladd(c, nil, nil, -1);
 	cvttorunes(s, strlen(s), rb, &nb, &nr, nil);
-	rs = cleanrname((Runestr){rb, nr});
+	rs = cleanrname(runestr(rb, nr));
 	winsetname(w, rs.r, rs.nr);
 	textload(&w->body, 0, s, 1);
 	w->body.file->mod = FALSE;
@@ -403,7 +404,6 @@ keyboardthread(void *v)
 				winlock(t->w, 'K');
 				wincommit(t->w, t);
 				winunlock(t->w);
-				flushwarnings(1);
 				flushimage(display, 1);
 			}
 			alts[KTimer].c = nil;
@@ -430,7 +430,6 @@ keyboardthread(void *v)
 			}
 			if(nbrecv(keyboardctl->c, &r) > 0)
 				goto casekeyboard;
-			flushwarnings(1);
 			flushimage(display, 1);
 			break;
 		}
@@ -447,7 +446,7 @@ mousethread(void *v)
 	Plumbmsg *pm;
 	Mouse m;
 	char *act;
-	enum { MResize, MMouse, MPlumb, NMALT };
+	enum { MResize, MMouse, MPlumb, MWarnings, NMALT };
 	static Alt alts[NMALT+1];
 
 	USED(v);
@@ -461,11 +460,18 @@ mousethread(void *v)
 	alts[MPlumb].c = cplumb;
 	alts[MPlumb].v = &pm;
 	alts[MPlumb].op = CHANRCV;
+	alts[MWarnings].c = cwarn;
+	alts[MWarnings].v = nil;
+	alts[MWarnings].op = CHANRCV;
 	if(cplumb == nil)
 		alts[MPlumb].op = CHANNOP;
 	alts[NMALT].op = CHANEND;
 	
 	for(;;){
+		qlock(&row.lk);
+		flushwarnings();
+		qunlock(&row.lk);
+		flushimage(display, 1);
 		switch(alt(alts)){
 		case MResize:
 			if(getwindow(display, Refnone) < 0)
@@ -473,8 +479,6 @@ mousethread(void *v)
 			draw(screen, screen->r, display->white, nil, ZP);
 			scrlresize();
 			rowresize(&row, screen->clipr);
-			flushwarnings(1);
-			flushimage(display, 1);
 			break;
 		case MPlumb:
 			if(strcmp(pm->type, "text") == 0){
@@ -484,10 +488,10 @@ mousethread(void *v)
 				else if(strcmp(act, "showdata")==0)
 					plumbshow(pm);
 			}
-			flushwarnings(1);
-			flushimage(display, 1);
-			plumbfree(pm);
+			plumbfree(pm);
 			break;
+		case MWarnings:
+			break;
 		case MMouse:
 			/*
 			 * Make a copy so decisions are consistent; mousectl changes
@@ -570,8 +574,6 @@ mousethread(void *v)
 				goto Continue;
 			}
     Continue:
-			flushwarnings(0);
-			flushimage(display, 1);
 			qunlock(&row.lk);
 			break;
 		}
blob - 94cfa38314bd8e724ad7924f39c662e171407604
blob + 338a1ff8ca054a81a9f15302314472f0467d0876
--- src/cmd/acme/dat.h
+++ src/cmd/acme/dat.h
@@ -543,5 +543,6 @@ Channel	*mouseexit1;	/* chan(int) */
 Channel	*cexit;		/* chan(int) */
 Channel	*cerr;		/* chan(char*) */
 Channel	*cedit;		/* chan(int) */
+Channel	*cwarn;		/* chan(void*)[1] (really chan(unit)[1]) */
 
 #define	STACK	32768
blob - 0dfae90a11fd9952836e9fb0e0ff28dbe9ff0cb6
blob + 7ccb9427291d83264fb5b72f58febf03d6d87cb3
--- src/cmd/acme/ecmd.c
+++ src/cmd/acme/ecmd.c
@@ -268,7 +268,7 @@ D_cmd(Text *t, Cmd *cp)
 			runemove(n, dir.r, dir.nr);
 			n[dir.nr] = '/';
 			runemove(n+dir.nr+1, r, nn);
-			rs = cleanrname((Runestr){n, dir.nr+1+nn});
+			rs = cleanrname(runestr(n, dir.nr+1+nn));
 		}
 		w = lookfile(rs.r, rs.nr);
 		if(w == nil){
blob - 74f9f47ced2be1ef35faca6300f8ec6837e8276f
blob + 0e3389d627b1d0cb7c27b4b0b33caa8dfdaabee2
--- src/cmd/acme/exec.c
+++ src/cmd/acme/exec.c
@@ -25,6 +25,7 @@ void	fontx(Text*, Text*, Text*, int, int, Rune*, int);
 void	get(Text*, Text*, Text*, int, int, Rune*, int);
 void	id(Text*, Text*, Text*, int, int, Rune*, int);
 void	incl(Text*, Text*, Text*, int, int, Rune*, int);
+void	indent(Text*, Text*, Text*, int, int, Rune*, int);
 void	xkill(Text*, Text*, Text*, int, int, Rune*, int);
 void	local(Text*, Text*, Text*, int, int, Rune*, int);
 void	look(Text*, Text*, Text*, int, int, Rune*, int);
@@ -58,6 +59,7 @@ static Rune LFont[] = { 'F', 'o', 'n', 't', 0 };
 static Rune LGet[] = { 'G', 'e', 't', 0 };
 static Rune LID[] = { 'I', 'D', 0 };
 static Rune LIncl[] = { 'I', 'n', 'c', 'l', 0 };
+static Rune LIndent[] = { 'I', 'n', 'd', 'e', 'n', 't', 0 };
 static Rune LKill[] = { 'K', 'i', 'l', 'l', 0 };
 static Rune LLoad[] = { 'L', 'o', 'a', 'd', 0 };
 static Rune LLocal[] = { 'L', 'o', 'c', 'a', 'l', 0 };
@@ -87,6 +89,7 @@ Exectab exectab[] = {
 	{ LGet,		get,		FALSE,	TRUE,	XXX		},
 	{ LID,		id,		FALSE,	XXX,		XXX		},
 	{ LIncl,		incl,		FALSE,	XXX,		XXX		},
+	{ LIndent,		indent,	FALSE,	XXX,		XXX		},
 	{ LKill,		xkill,		FALSE,	XXX,		XXX		},
 	{ LLoad,		dump,	FALSE,	FALSE,	XXX		},
 	{ LLocal,		local,	FALSE,	XXX,		XXX		},
@@ -1443,7 +1446,6 @@ runproc(void *argvp)
 	goto Fail;
 
 Hard:
-
 	/*
 	 * ugly: set path = (. $cputype /bin)
 	 * should honor $path if unusual.
blob - 9fba7d7ad79ec07cd4e8ee6de84a0b62b65b0626
blob + c164bb3b50755773e3c3e2c6b38168a8d0611d81
--- src/cmd/acme/fns.h
+++ src/cmd/acme/fns.h
@@ -69,6 +69,7 @@ Rune*	bytetorune(char*, int*);
 void	fsysinit(void);
 Mntdir*	fsysmount(Rune*, int, Rune**, int);
 void		fsysdelid(Mntdir*);
+void		fsysincid(Mntdir*);
 Xfid*		respond(Xfid*, Fcall*, char*);
 int		rxcompile(Rune*);
 int		rgetc(void*, uint);
@@ -86,9 +87,11 @@ int	expand(Text*, uint, uint, Expand*);
 Rune*	skipbl(Rune*, int, int*);
 Rune*	findbl(Rune*, int, int*);
 char*	edittext(Window*, int, Rune*, int);
-void		flushwarnings(int);
+void		flushwarnings(void);
 void		startplumbing(void);
 
+Runestr	runestr(Rune*, uint);
+
 #define	runemalloc(a)		(Rune*)emalloc((a)*sizeof(Rune))
 #define	runerealloc(a, b)	(Rune*)erealloc((a), (b)*sizeof(Rune))
 #define	runemove(a, b, c)	memmove((a), (b), (c)*sizeof(Rune))
blob - f178f864977513bfc7ca4175b7ce6d449383b8cb
blob + af4255c8af359c8647a591be9f3f7cdc1a05acb8
--- src/cmd/acme/fsys.c
+++ src/cmd/acme/fsys.c
@@ -37,22 +37,25 @@ static	Xfid*	fsysremove(Xfid*, Fid*);
 static	Xfid*	fsysstat(Xfid*, Fid*);
 static	Xfid*	fsyswstat(Xfid*, Fid*);
 
-Xfid* 	(*fcall[Tmax])(Xfid*, Fid*) =
+Xfid* 	(*fcall[Tmax])(Xfid*, Fid*);
+
+static void
+initfcall(void)
 {
-	[Tflush]	= fsysflush,
-	[Tversion]	= fsysversion,
-	[Tauth]	= fsysauth,
-	[Tattach]	= fsysattach,
-	[Twalk]	= fsyswalk,
-	[Topen]	= fsysopen,
-	[Tcreate]	= fsyscreate,
-	[Tread]	= fsysread,
-	[Twrite]	= fsyswrite,
-	[Tclunk]	= fsysclunk,
-	[Tremove]= fsysremove,
-	[Tstat]	= fsysstat,
-	[Twstat]	= fsyswstat,
-};
+	fcall[Tflush]	= fsysflush;
+	fcall[Tversion]	= fsysversion;
+	fcall[Tauth]	= fsysauth;
+	fcall[Tattach]	= fsysattach;
+	fcall[Twalk]	= fsyswalk;
+	fcall[Topen]	= fsysopen;
+	fcall[Tcreate]	= fsyscreate;
+	fcall[Tread]	= fsysread;
+	fcall[Twrite]	= fsyswrite;
+	fcall[Tclunk]	= fsysclunk;
+	fcall[Tremove]= fsysremove;
+	fcall[Tstat]	= fsysstat;
+	fcall[Twstat]	= fsyswstat;
+}
 
 char Eperm[] = "permission denied";
 char Eexist[] = "file does not exist";
@@ -113,6 +116,7 @@ fsysinit(void)
 	int p[2];
 	char *u;
 
+	initfcall();
 	if(pipe(p) < 0)
 		error("can't create pipe");
 	if(post9pservice(p[0], "acme") < 0)
@@ -187,6 +191,14 @@ fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
 }
 
 void
+fsysincid(Mntdir *m)
+{
+	qlock(&mnt.lk);
+	m->ref++;
+	qunlock(&mnt.lk);
+}
+
+void
 fsysdelid(Mntdir *idm)
 {
 	Mntdir *m, *prev;
@@ -331,7 +343,7 @@ fsysattach(Xfid *x, Fid *f)
 			m->ref++;
 			break;
 		}
-	if(m == nil){
+	if(m == nil && x->fcall.aname[0]){
 		snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
 		sendp(cerr, estrdup(buf));
 	}
blob - f6c4d4ee5c8abff98f844c983e6dd1aae1463954
blob + 7023382677f9f931f0a5025fcfb1e13de16c3983
--- src/cmd/acme/look.c
+++ src/cmd/acme/look.c
@@ -259,7 +259,7 @@ plumbshow(Plumbmsg *m)
 	}
 	cvttorunes(name, strlen(name), rb, &nb, &nr, nil);
 	free(p);
-	rs = cleanrname((Runestr){rb, nr});
+	rs = cleanrname(runestr(rb, nr));
 	winsetname(w, rs.r, rs.nr);
 	r = runemalloc(m->ndata);
 	cvttorunes(m->data, m->ndata, r, &nb, &nr, nil);
@@ -385,13 +385,13 @@ includefile(Rune *dir, Rune *file, int nfile)
 	n = access(a, 0);
 	free(a);
 	if(n < 0)
-		return (Runestr){nil, 0};
+		return runestr(nil, 0);
 	r = runemalloc(m+1+nfile);
 	runemove(r, dir, m);
 	runemove(r+m, Lslash, 1);
 	runemove(r+m+1, file, nfile);
 	free(file);
-	return cleanrname((Runestr){r, m+1+nfile});
+	return cleanrname(runestr(r, m+1+nfile));
 }
 
 static	Rune	*objdir;
@@ -442,7 +442,7 @@ includename(Text *t, Rune *r, int n)
 	return file;
 
     Rescue:
-	return (Runestr){r, n};
+	return runestr(r, n);
 }
 
 Runestr
@@ -475,11 +475,11 @@ dirname(Text *t, Rune *r, int n)
 		goto Rescue;
 	runemove(b+slash+1, r, n);
 	free(r);
-	return cleanrname((Runestr){b, slash+1+n});
+	return cleanrname(runestr(b, slash+1+n));
 
     Rescue:
 	free(b);
-	tmp = (Runestr){r, n};
+	tmp = runestr(r, n);
 	if(r)
 		return cleanrname(tmp);
 	return tmp;
blob - 8bdf0b78c5cca413f6a7f4381490db61ab81262a
blob + c0cd7ec150e41361dff3593adeadd1f6b27528d7
--- src/cmd/acme/text.c
+++ src/cmd/acme/text.c
@@ -578,7 +578,7 @@ textcomplete(Text *t)
 		path[i] = textreadc(t, q++);
 	/* is path rooted? if not, we need to make it relative to window path */
 	if(npath>0 && path[0]=='/')
-		dir = (Runestr){path, npath};
+		dir = runestr(path, npath);
 	else{
 		dir = dirname(t, nil, 0);
 		if(dir.nr + 1 + npath > nelem(tmp)){
blob - de71107a5215298b0f46040b6779e55c060c97e6
blob + a7307e0665ecd8b8f81d4216042ccba7fc4950ca
--- src/cmd/acme/util.c
+++ src/cmd/acme/util.c
@@ -14,6 +14,16 @@
 static	Point		prevmouse;
 static	Window	*mousew;
 
+Runestr
+runestr(Rune *r, uint n)
+{
+	Runestr rs;
+
+	rs.r = r;
+	rs.nr = n;
+	return rs;
+}
+
 void
 cvttorunes(char *p, int n, Rune *r, int *nb, int *nr, int *nulls)
 {
@@ -133,12 +143,17 @@ addwarningtext(Mntdir *md, Rune *r, int nr)
 	}
 	warn = emalloc(sizeof(Warning));
 	warn->next = warnings;
+	warn->md = md;
+	if(md)
+		fsysincid(md);
 	warnings = warn;
 	bufinsert(&warn->buf, 0, r, nr);
+	nbsendp(cwarn, 0);
 }
 
+/* called while row is locked */
 void
-flushwarnings(int dolock)
+flushwarnings(void)
 {
 	Warning *warn, *next;
 	Window *w;
@@ -146,8 +161,6 @@ flushwarnings(int dolock)
 	int owner, nr, q0, n;
 	Rune *r;
 
-	if(dolock)
-		qlock(&row.lk);
 	if(row.ncol == 0){	/* really early error */
 		rowinit(&row, screen->clipr);
 		rowadd(&row, nil, -1);
@@ -189,11 +202,11 @@ flushwarnings(int dolock)
 		winunlock(w);
 		bufclose(&warn->buf);
 		next = warn->next;
+		if(warn->md)
+			fsysdelid(warn->md);
 		free(warn);
 	}
 	warnings = nil;
-	if(dolock)
-		qunlock(&row.lk);
 }
 
 void
blob - b3bef2cd51f648934d4cd4728a211bccefb01dc4
blob + 839308eee1f3a485087ebb2a4b961be738fea8e8
--- src/cmd/acme/xfid.c
+++ src/cmd/acme/xfid.c
@@ -543,7 +543,6 @@ xfidwrite(Xfid *x)
 	}
 	if(w)
 		winunlock(w);
-	flushwarnings(1);
 }
 
 void
@@ -814,7 +813,6 @@ xfideventwrite(Xfid *x, Window *w)
 			qunlock(&row.lk);
 			goto Rescue;
 		}
-		flushwarnings(0);
 		qunlock(&row.lk);
 
 	}
@@ -1032,7 +1030,6 @@ xfidindexread(Xfid *x)
 			b[n++] = '\n';
 		}
 	}
-	flushwarnings(0);
 	qunlock(&row.lk);
 	off = x->fcall.offset;
 	cnt = x->fcall.count;
blob - 8cbf6aac077348accfa714b9d871c472b25009f9
blob + a3ddd890c606e526e29a48d967e2d7675718d955
--- src/cmd/dict/dict.c
+++ src/cmd/dict/dict.c
@@ -119,6 +119,8 @@ main(int argc, char **argv)
 		line = malloc(strlen(p)+5);
 		sprint(line, "/%s/P\n", p);
 	}
+	dict->path = unsharp(dict->path);
+	dict->indexpath = unsharp(dict->indexpath);
 	bdict = Bopen(dict->path, OREAD);
 	if(!bdict) {
 		err("can't open dictionary %s", dict->path);
blob - 8e56765fa12bc6e937f89a7b89919d6f218a7919
blob + c809ae81345741acd7d0bc5886606404cb033ba6
--- src/cmd/diff/diff.h
+++ src/cmd/diff/diff.h
@@ -1,3 +1,5 @@
+#define stdout bstdout
+
 char mode;			/* '\0', 'e', 'f', 'h' */
 char bflag;			/* ignore multiple and trailing blanks */
 char rflag;			/* recurse down directory trees */
blob - 43eb6dd1c4821af23b1924d1ef4a0154ef0980fe
blob + 00f69a3ec78788334760781c74263cb0e47c05ac
--- src/cmd/diff/main.c
+++ src/cmd/diff/main.c
@@ -26,6 +26,8 @@ void	
 done(int status)
 {
 	rmtmpfiles();
+Bflush(&stdout);
+Bterm(&stdout);
 	switch(status)
 	{
 	case 0:
blob - f3acfca22cac1dfab9881af5c8d5e4f90cd8b47f
blob + 4aa895fec4d0f21d530c4e58a2ec9d76a56cd616
--- src/cmd/fortune.c
+++ src/cmd/fortune.c
@@ -4,8 +4,8 @@
 
 #define index findex
 char choice[2048];
-char index[] = "/sys/games/lib/fortunes.index";
-char fortunes[] = "/sys/games/lib/fortunes";
+char *index = "#9/lib/fortunes.index";
+char *fortunes = "#9/lib/fortunes";
 
 #define lrand rand
 
@@ -21,6 +21,9 @@ main(int argc, char *argv[])
 	Dir *fbuf, *ixbuf;
 	Biobuf *f, g;
 
+	index = unsharp(index);
+	fortunes = unsharp(index);
+
 	newindex = 0;
 	oldindex = 0;
 	ix = offs = 0;
@@ -55,6 +58,7 @@ main(int argc, char *argv[])
 		}
 	}
 	if(oldindex){
+		srand(getpid());
 		seek(ix, lrand()%(ixbuf->length/sizeof(offs))*sizeof(offs), 0);
 		read(ix, off, sizeof(off));
 		Bseek(f, off[0]|(off[1]<<8)|(off[2]<<16)|(off[3]<<24), 0);
blob - /dev/null
blob + 4a3f3e8f4f80ce77a3caea6b83bb546d3d3296df (mode 644)
--- /dev/null
+++ src/cmd/grep/comp.c
@@ -0,0 +1,277 @@
+#include	"grep.h"
+
+/*
+ * incremental compiler.
+ * add the branch c to the
+ * state s.
+ */
+void
+increment(State *s, int c)
+{
+	int i;
+	State *t, **tt;
+	Re *re1, *re2;
+
+	nfollow = 0;
+	gen++;
+	matched = 0;
+	for(i=0; i<s->count; i++)
+		fol1(s->re[i], c);
+	qsort(follow, nfollow, sizeof(*follow), fcmp);
+	for(tt=&state0; t = *tt;) {
+		if(t->count > nfollow) {
+			tt = &t->linkleft;
+			goto cont;
+		}
+		if(t->count < nfollow) {
+			tt = &t->linkright;
+			goto cont;
+		}
+		for(i=0; i<nfollow; i++) {
+			re1 = t->re[i];
+			re2 = follow[i];
+			if(re1 > re2) {
+				tt = &t->linkleft;
+				goto cont;
+			}
+			if(re1 < re2) {
+				tt = &t->linkright;
+				goto cont;
+			}
+		}
+		if(!!matched && !t->match) {
+			tt = &t->linkleft;
+			goto cont;
+		}
+		if(!matched && !!t->match) {
+			tt = &t->linkright;
+			goto cont;
+		}
+		s->next[c] = t;
+		return;
+	cont:;
+	}
+
+	t = sal(nfollow);
+	*tt = t;
+	for(i=0; i<nfollow; i++) {
+		re1 = follow[i];
+		t->re[i] = re1;
+	}
+	s->next[c] = t;
+	t->match = matched;
+}
+
+int
+fcmp(const void *va, const void *vb)
+{
+	Re **aa, **bb;
+	Re *a, *b;
+
+	aa = (Re**)va;
+	bb = (Re**)vb;
+	a = *aa;
+	b = *bb;
+	if(a > b)
+		return 1;
+	if(a < b)
+		return -1;
+	return 0;
+}
+
+void
+fol1(Re *r, int c)
+{
+	Re *r1;
+
+loop:
+	if(r->gen == gen)
+		return;
+	if(nfollow >= maxfollow)
+		error("nfollow");
+	r->gen = gen;
+	switch(r->type) {
+	default:
+		error("fol1");
+
+	case Tcase:
+		if(c >= 0 && c < 256)
+		if(r1 = r->cases[c])
+			follow[nfollow++] = r1;
+		if(r = r->next)
+			goto loop;
+		break;
+
+	case Talt:
+	case Tor:
+		fol1(r->alt, c);
+		r = r->next;
+		goto loop;
+
+	case Tbegin:
+		if(c == '\n' || c == Cbegin)
+			follow[nfollow++] = r->next;
+		break;
+
+	case Tend:
+		if(c == '\n')
+			matched = 1;
+		break;
+
+	case Tclass:
+		if(c >= r->lo && c <= r->hi)
+			follow[nfollow++] = r->next;
+		break;
+	}
+}
+
+Rune	tab1[] =
+{
+	0x007f,
+	0x07ff,
+};
+Rune	tab2[] =
+{
+	0x003f,
+	0x0fff,
+};
+
+Re2
+rclass(Rune p0, Rune p1)
+{
+	char xc0[6], xc1[6];
+	int i, n, m;
+	Re2 x;
+
+	if(p0 > p1)
+		return re2char(0xff, 0xff);	// no match
+
+	/*
+	 * bust range into same length
+	 * character sequences
+	 */
+	for(i=0; i<nelem(tab1); i++) {
+		m = tab1[i];
+		if(p0 <= m && p1 > m)
+			return re2or(rclass(p0, m), rclass(m+1, p1));
+	}
+
+	/*
+	 * bust range into part of a single page
+	 * or into full pages
+	 */
+	for(i=0; i<nelem(tab2); i++) {
+		m = tab2[i];
+		if((p0 & ~m) != (p1 & ~m)) {
+			if((p0 & m) != 0)
+				return re2or(rclass(p0, p0|m), rclass((p0|m)+1, p1));
+			if((p1 & m) != m)
+				return re2or(rclass(p0, (p1&~m)-1), rclass(p1&~m, p1));
+		}
+	}
+
+	n = runetochar(xc0, &p0);
+	i = runetochar(xc1, &p1);
+	if(i != n)
+		error("length");
+
+	x = re2char(xc0[0], xc1[0]);
+	for(i=1; i<n; i++)
+		x = re2cat(x, re2char(xc0[i], xc1[i]));
+	return x;
+}
+
+int
+pcmp(const void *va, const void *vb)
+{
+	int n;
+	Rune *a, *b;
+
+	a = (Rune*)va;
+	b = (Rune*)vb;
+
+	n = a[0] - b[0];
+	if(n)
+		return n;
+	return a[1] - b[1];
+}
+
+/*
+ * convert character chass into
+ * run-pair ranges of matches.
+ * this is 10646/utf specific and
+ * needs to be changed for some
+ * other input character set.
+ * this is the key to a fast
+ * regular search of characters
+ * by looking at sequential bytes.
+ */
+Re2
+re2class(char *s)
+{
+	Rune pairs[200], *p, *q, ov;
+	int nc;
+	Re2 x;
+
+	nc = 0;
+	if(*s == '^') {
+		nc = 1;
+		s++;
+	}
+
+	p = pairs;
+	s += chartorune(p, s);
+	for(;;) {
+		if(*p == '\\')
+			s += chartorune(p, s);
+		if(*p == 0)
+			break;
+		p[1] = *p;
+		p += 2;
+		s += chartorune(p, s);
+		if(*p != '-')
+			continue;
+		s += chartorune(p, s);
+		if(*p == '\\')
+			s += chartorune(p, s);
+		if(*p == 0)
+			break;
+		p[-1] = *p;
+		s += chartorune(p, s);
+	}
+	*p = 0;
+	qsort(pairs, (p-pairs)/2, 2*sizeof(*pairs), pcmp);
+
+	q = pairs;
+	for(p=pairs+2; *p; p+=2) {
+		if(p[0] > p[1])
+			continue;
+		if(p[0] > q[1] || p[1] < q[0]) {
+			q[2] = p[0];
+			q[3] = p[1];
+			q += 2;
+			continue;
+		}
+		if(p[0] < q[0])
+			q[0] = p[0];
+		if(p[1] > q[1])
+			q[1] = p[1];
+	}
+	q[2] = 0;
+
+	p = pairs;
+	if(nc) {
+		x = rclass(0, p[0]-1);
+		ov = p[1]+1;
+		for(p+=2; *p; p+=2) {
+			x = re2or(x, rclass(ov, p[0]-1));
+			ov = p[1]+1;
+		}
+		x = re2or(x, rclass(ov, 0xffff));
+	} else {
+		x = rclass(p[0], p[1]);
+		for(p+=2; *p; p+=2)
+			x = re2or(x, rclass(p[0], p[1]));
+	}
+	return x;
+}
blob - /dev/null
blob + 8445df54a53ffbe2ecb74e2e5fafb2ff7be9a992 (mode 644)
--- /dev/null
+++ src/cmd/grep/grep.h
@@ -0,0 +1,125 @@
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+typedef	struct	Re	Re;
+typedef	struct	Re2	Re2;
+typedef	struct	State	State;
+
+struct	State
+{
+	int	count;
+	int	match;
+	Re**	re;
+	State*	linkleft;
+	State*	linkright;
+	State*	next[256];
+};
+struct	Re2
+{
+	Re*	beg;
+	Re*	end;
+};
+struct	Re
+{
+	uchar	type;
+	ushort	gen;
+	union
+	{
+		Re*	alt;	/* Talt */
+		Re**	cases;	/* case */
+		struct		/* class */
+		{
+			Rune	lo;
+			Rune	hi;
+		};	
+		Rune	val;	/* char */
+	};
+	Re*	next;
+};
+
+enum
+{
+	Talt		= 1,
+	Tbegin,
+	Tcase,
+	Tclass,
+	Tend,
+	Tor,
+
+	Caselim		= 7,
+	Nhunk		= 1<<16,
+	Cbegin		= 0x10000,
+	Flshcnt		= (1<<9)-1,
+
+	Cflag		= 1<<0,
+	Hflag		= 1<<1,
+	Iflag		= 1<<2,
+	Llflag		= 1<<3,
+	LLflag		= 1<<4,
+	Nflag		= 1<<5,
+	Sflag		= 1<<6,
+	Vflag		= 1<<7,
+	Bflag		= 1<<8
+};
+
+EXTERN	union
+{
+	char	string[16*1024];
+	struct
+	{
+		/*
+		 * if a line requires multiple reads, we keep shifting
+		 * buf down into pre and then do another read into
+		 * buf.  so you'll get the last 16-32k of the matching line.
+		 * if pre were smaller than buf you'd get a suffix of the
+		 * line with a hole cut out.
+		 */
+		uchar	pre[16*1024];	/* to save to previous '\n' */
+		uchar	buf[16*1024];	/* input buffer */
+	};
+} u;
+
+EXTERN	char	*filename;
+EXTERN	Biobuf	bout;
+EXTERN	char	flags[256];
+EXTERN	Re**	follow;
+EXTERN	ushort	gen;
+EXTERN	char*	input;
+EXTERN	long	lineno;
+EXTERN	int	literal;
+EXTERN	int	matched;
+EXTERN	long	maxfollow;
+EXTERN	long	nfollow;
+EXTERN	int	peekc;
+EXTERN	Biobuf*	rein;
+EXTERN	State*	state0;
+EXTERN	Re2	topre;
+
+extern	Re*	addcase(Re*);
+extern	void	appendnext(Re*, Re*);
+extern	void	error(char*);
+extern	int	fcmp(const void*, const void*); 	/* (Re**, Re**) */
+extern	void	fol1(Re*, int);
+extern	int	getrec(void);
+extern	void	increment(State*, int);
+#define initstate grepinitstate
+extern	State*	initstate(Re*);
+extern	void*	mal(int);
+extern	void	patchnext(Re*, Re*);
+extern	Re*	ral(int);
+extern	Re2	re2cat(Re2, Re2);
+extern	Re2	re2class(char*);
+extern	Re2	re2or(Re2, Re2);
+extern	Re2	re2char(int, int);
+extern	Re2	re2star(Re2);
+extern	State*	sal(int);
+extern	int	search(char*, int);
+extern	void	str2top(char*);
+extern	int	yyparse(void);
+extern	void	reprint(char*, Re*);
+extern	void	yyerror(char*, ...);
blob - /dev/null
blob + 94a744cf96931a2244c69961b0b5f1c5c74f339d (mode 644)
--- /dev/null
+++ src/cmd/grep/grep.y
@@ -0,0 +1,226 @@
+%{
+#include	"grep.h"
+%}
+
+%union
+{
+	int	val;
+	char*	str;
+	Re2	re;
+}
+
+%type	<re>	expr prog
+%type	<re>	expr0 expr1 expr2 expr3 expr4
+%token	<str>	LCLASS
+%token	<val>	LCHAR
+%token		LLPAREN LRPAREN LALT LSTAR LPLUS LQUES
+%token		LBEGIN LEND LDOT LBAD LNEWLINE
+%%
+
+prog:
+	expr newlines
+	{
+		$$.beg = ral(Tend);
+		$$.end = $$.beg;
+		$$ = re2cat(re2star(re2or(re2char(0x00, '\n'-1), re2char('\n'+1, 0xff))), $$);
+		$$ = re2cat($1, $$);
+		$$ = re2cat(re2star(re2char(0x00, 0xff)), $$);
+		topre = $$;
+	}
+
+expr:
+	expr0
+|	expr newlines expr0
+	{
+		$$ = re2or($1, $3);
+	}
+
+expr0:
+	expr1
+|	LSTAR { literal = 1; } expr1
+	{
+		$$ = $3;
+	}
+
+expr1:
+	expr2
+|	expr1 LALT expr2
+	{
+		$$ = re2or($1, $3);
+	}
+
+expr2:
+	expr3
+|	expr2 expr3
+	{
+		$$ = re2cat($1, $2);
+	}
+
+expr3:
+	expr4
+|	expr3 LSTAR
+	{
+		$$ = re2star($1);
+	}
+|	expr3 LPLUS
+	{
+		$$.beg = ral(Talt);
+		patchnext($1.end, $$.beg);
+		$$.beg->alt = $1.beg;
+		$$.end = $$.beg;
+		$$.beg = $1.beg;
+	}
+|	expr3 LQUES
+	{
+		$$.beg = ral(Talt);
+		$$.beg->alt = $1.beg;
+		$$.end = $1.end;
+		appendnext($$.end,  $$.beg);
+	}
+
+expr4:
+	LCHAR
+	{
+		$$.beg = ral(Tclass);
+		$$.beg->lo = $1;
+		$$.beg->hi = $1;
+		$$.end = $$.beg;
+	}
+|	LBEGIN
+	{
+		$$.beg = ral(Tbegin);
+		$$.end = $$.beg;
+	}
+|	LEND
+	{
+		$$.beg = ral(Tend);
+		$$.end = $$.beg;
+	}
+|	LDOT
+	{
+		$$ = re2class("^\n");
+	}
+|	LCLASS
+	{
+		$$ = re2class($1);
+	}
+|	LLPAREN expr1 LRPAREN
+	{
+		$$ = $2;
+	}
+
+newlines:
+	LNEWLINE
+|	newlines LNEWLINE
+%%
+
+void
+yyerror(char *e, ...)
+{
+	if(filename)
+		fprint(2, "grep: %s:%ld: %s\n", filename, lineno, e);
+	else
+		fprint(2, "grep: %s\n", e);
+	exits("syntax");
+}
+
+long
+yylex(void)
+{
+	char *q, *eq;
+	int c, s;
+
+	if(peekc) {
+		s = peekc;
+		peekc = 0;
+		return s;
+	}
+	c = getrec();
+	if(literal) {
+		if(c != 0 && c != '\n') {
+			yylval.val = c;
+			return LCHAR;
+		}
+		literal = 0;
+	}
+	switch(c) {
+	default:
+		yylval.val = c;
+		s = LCHAR;
+		break;
+	case '\\':
+		c = getrec();
+		yylval.val = c;
+		s = LCHAR;
+		if(c == '\n')
+			s = LNEWLINE;
+		break;
+	case '[':
+		goto getclass;
+	case '(':
+		s = LLPAREN;
+		break;
+	case ')':
+		s = LRPAREN;
+		break;
+	case '|':
+		s = LALT;
+		break;
+	case '*':
+		s = LSTAR;
+		break;
+	case '+':
+		s = LPLUS;
+		break;
+	case '?':
+		s = LQUES;
+		break;
+	case '^':
+		s = LBEGIN;
+		break;
+	case '$':
+		s = LEND;
+		break;
+	case '.':
+		s = LDOT;
+		break;
+	case 0:
+		peekc = -1;
+	case '\n':
+		s = LNEWLINE;
+		break;
+	}
+	return s;
+
+getclass:
+	q = u.string;
+	eq = q + nelem(u.string) - 5;
+	c = getrec();
+	if(c == '^') {
+		q[0] = '^';
+		q[1] = '\n';
+		q[2] = '-';
+		q[3] = '\n';
+		q += 4;
+		c = getrec();
+	}
+	for(;;) {
+		if(q >= eq)
+			error("class too long");
+		if(c == ']' || c == 0)
+			break;
+		if(c == '\\') {
+			*q++ = c;
+			c = getrec();
+			if(c == 0)
+				break;
+		}
+		*q++ = c;
+		c = getrec();
+	}
+	*q = 0;
+	if(c == 0)
+		return LBAD;
+	yylval.str = u.string;
+	return LCLASS;
+}
blob - /dev/null
blob + f2a6e040465890d6aef6cb0a21680cd65b70f143 (mode 644)
--- /dev/null
+++ src/cmd/grep/main.c
@@ -0,0 +1,260 @@
+#define	EXTERN
+#include	"grep.h"
+
+char *validflags = "bchiLlnsv";
+void
+usage(void)
+{
+	fprint(2, "usage: grep [-%s] [-f file] [-e expr] [file ...]\n", validflags);
+	exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+	int i, status;
+
+	ARGBEGIN {
+	default:
+		if(utfrune(validflags, ARGC()) == nil)
+			usage();
+		flags[ARGC()]++;
+		break;
+
+	case 'e':
+		flags['e']++;
+		lineno = 0;
+		str2top(ARGF());
+		break;
+
+	case 'f':
+		flags['f']++;
+		filename = ARGF();
+		rein = Bopen(filename, OREAD);
+		if(rein == 0) {
+			fprint(2, "grep: can't open %s: %r\n", filename);
+			exits("open");
+		}
+		lineno = 1;
+		str2top(filename);
+		break;
+	} ARGEND
+
+	if(flags['f'] == 0 && flags['e'] == 0) {
+		if(argc <= 0)
+			usage();
+		str2top(argv[0]);
+		argc--;
+		argv++;
+	}
+
+	follow = mal(maxfollow*sizeof(*follow));
+	state0 = initstate(topre.beg);
+
+	Binit(&bout, 1, OWRITE);
+	switch(argc) {
+	case 0:
+		status = search(0, 0);
+		break;
+	case 1:
+		status = search(argv[0], 0);
+		break;
+	default:
+		status = 0;
+		for(i=0; i<argc; i++)
+			status |= search(argv[i], Hflag);
+		break;
+	}
+	if(status)
+		exits(0);
+	exits("no matches");
+}
+
+int
+search(char *file, int flag)
+{
+	State *s, *ns;
+	int c, fid, eof, nl, empty;
+	long count, lineno, n;
+	uchar *elp, *lp, *bol;
+
+	if(file == 0) {
+		file = "stdin";
+		fid = 0;
+		flag |= Bflag;
+	} else
+		fid = open(file, OREAD);
+
+	if(fid < 0) {
+		fprint(2, "grep: can't open %s: %r\n", file);
+		return 0;
+	}
+
+	if(flags['b'])
+		flag ^= Bflag;		/* dont buffer output */
+	if(flags['c'])
+		flag |= Cflag;		/* count */
+	if(flags['h'])
+		flag &= ~Hflag;		/* do not print file name in output */
+	if(flags['i'])
+		flag |= Iflag;		/* fold upper-lower */
+	if(flags['l'])
+		flag |= Llflag;		/* print only name of file if any match */
+	if(flags['L'])
+		flag |= LLflag;		/* print only name of file if any non match */
+	if(flags['n'])
+		flag |= Nflag;		/* count only */
+	if(flags['s'])
+		flag |= Sflag;		/* status only */
+	if(flags['v'])
+		flag |= Vflag;		/* inverse match */
+
+	s = state0;
+	lineno = 0;
+	count = 0;
+	eof = 0;
+	empty = 1;
+	nl = 0;
+	lp = u.buf;
+	bol = lp;
+
+loop0:
+	n = lp-bol;
+	if(n > sizeof(u.pre))
+		n = sizeof(u.pre);
+	memmove(u.buf-n, bol, n);
+	bol = u.buf-n;
+	n = read(fid, u.buf, sizeof(u.buf));
+	/* if file has no final newline, simulate one to emit matches to last line */
+	if(n > 0) {
+		empty = 0;
+		nl = u.buf[n-1]=='\n';
+	} else {
+		if(n < 0){
+			fprint(2, "grep: read error on %s: %r\n", file);
+			return count != 0;
+		}
+		if(!eof && !nl && !empty) {
+			u.buf[0] = '\n';
+			n = 1;
+			eof = 1;
+		}
+	}
+	if(n <= 0) {
+		close(fid);
+		if(flag & Cflag) {
+			if(flag & Hflag)
+				Bprint(&bout, "%s:", file);
+			Bprint(&bout, "%ld\n", count);
+		}
+		if(((flag&Llflag) && count != 0) || ((flag&LLflag) && count == 0))
+			Bprint(&bout, "%s\n", file);
+		Bflush(&bout);
+		return count != 0;
+	}
+	lp = u.buf;
+	elp = lp+n;
+	if(flag & Iflag)
+		goto loopi;
+
+/*
+ * normal character loop
+ */
+loop:
+	c = *lp;
+	ns = s->next[c];
+	if(ns == 0) {
+		increment(s, c);
+		goto loop;
+	}
+//	if(flags['2'])
+//		if(s->match)
+//			print("%d: %.2x**\n", s, c);
+//		else
+//			print("%d: %.2x\n", s, c);
+	lp++;
+	s = ns;
+	if(c == '\n') {
+		lineno++;
+		if(!!s->match == !(flag&Vflag)) {
+			count++;
+			if(flag & (Cflag|Sflag|Llflag|LLflag))
+				goto cont;
+			if(flag & Hflag)
+				Bprint(&bout, "%s:", file);
+			if(flag & Nflag)
+				Bprint(&bout, "%ld: ", lineno);
+			/* suppress extra newline at EOF unless we are labeling matches with file name */
+			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
+			if(flag & Bflag)
+				Bflush(&bout);
+		}
+		if((lineno & Flshcnt) == 0)
+			Bflush(&bout);
+	cont:
+		bol = lp;
+	}
+	if(lp != elp)
+		goto loop;
+	goto loop0;
+
+/*
+ * character loop for -i flag
+ * for speed
+ */
+loopi:
+	c = *lp;
+	if(c >= 'A' && c <= 'Z')
+		c += 'a'-'A';
+	ns = s->next[c];
+	if(ns == 0) {
+		increment(s, c);
+		goto loopi;
+	}
+	lp++;
+	s = ns;
+	if(c == '\n') {
+		lineno++;
+		if(!!s->match == !(flag&Vflag)) {
+			count++;
+			if(flag & (Cflag|Sflag|Llflag|LLflag))
+				goto conti;
+			if(flag & Hflag)
+				Bprint(&bout, "%s:", file);
+			if(flag & Nflag)
+				Bprint(&bout, "%ld: ", lineno);
+			/* suppress extra newline at EOF unless we are labeling matches with file name */
+			Bwrite(&bout, bol, lp-bol-(eof && !(flag&Hflag)));
+			if(flag & Bflag)
+				Bflush(&bout);
+		}
+		if((lineno & Flshcnt) == 0)
+			Bflush(&bout);
+	conti:
+		bol = lp;
+	}
+	if(lp != elp)
+		goto loopi;
+	goto loop0;
+}
+
+State*
+initstate(Re *r)
+{
+	State *s;
+	int i;
+
+	addcase(r);
+	if(flags['1'])
+		reprint("r", r);
+	nfollow = 0;
+	gen++;
+	fol1(r, Cbegin);
+	follow[nfollow++] = r;
+	qsort(follow, nfollow, sizeof(*follow), fcmp);
+
+	s = sal(nfollow);
+	for(i=0; i<nfollow; i++)
+		s->re[i] = follow[i];
+	return s;
+}
blob - /dev/null
blob + fd17abdd08f5e050fbf90d8d0f55912aa62e9814 (mode 644)
--- /dev/null
+++ src/cmd/grep/mkfile
@@ -0,0 +1,20 @@
+PLAN9=../../..
+<$PLAN9/src/mkhdr
+
+# Calling this grep breaks a LOT.  Like egrep on Linux.
+# And probably configure.
+
+TARG=9grep
+HFILES=\
+	grep.h\
+
+OFILES=\
+	y.tab.$O\
+	main.$O\
+	comp.$O\
+	sub.$O\
+
+YFILES=grep.y\
+
+SHORTLIB=bio 9
+<$PLAN9/src/mkone
blob - /dev/null
blob + be2acee35846f9908f2d1e11f26b9a57508f6974 (mode 644)
--- /dev/null
+++ src/cmd/grep/sub.c
@@ -0,0 +1,317 @@
+#include	"grep.h"
+
+void*
+mal(int n)
+{
+	static char *s;
+	static int m = 0;
+	void *v;
+
+	n = (n+3) & ~3;
+	if(m < n) {
+		if(n > Nhunk) {
+			v = sbrk(n);
+			memset(v, 0, n);
+			return v;
+		}
+		s = sbrk(Nhunk);
+		m = Nhunk;
+	}
+	v = s;
+	s += n;
+	m -= n;
+	memset(v, 0, n);
+	return v;
+}
+
+State*
+sal(int n)
+{
+	State *s;
+
+	s = mal(sizeof(*s));
+//	s->next = mal(256*sizeof(*s->next));
+	s->count = n;
+	s->re = mal(n*sizeof(*state0->re));
+	return s;
+}
+
+Re*
+ral(int type)
+{
+	Re *r;
+
+	r = mal(sizeof(*r));
+	r->type = type;
+	maxfollow++;
+	return r;
+}
+
+void
+error(char *s)
+{
+	fprint(2, "grep: internal error: %s\n", s);
+	exits(s);
+}
+
+int
+countor(Re *r)
+{
+	int n;
+
+	n = 0;
+loop:
+	switch(r->type) {
+	case Tor:
+		n += countor(r->alt);
+		r = r->next;
+		goto loop;
+	case Tclass:
+		return n + r->hi - r->lo + 1;
+	}
+	return n;
+}
+
+Re*
+oralloc(int t, Re *r, Re *b)
+{
+	Re *a;
+
+	if(b == 0)
+		return r;
+	a = ral(t);
+	a->alt = r;
+	a->next = b;
+	return a;
+}
+
+void
+case1(Re *c, Re *r)
+{
+	int n;
+
+loop:
+	switch(r->type) {
+	case Tor:
+		case1(c, r->alt);
+		r = r->next;
+		goto loop;
+
+	case Tclass:	/* add to character */
+		for(n=r->lo; n<=r->hi; n++)
+			c->cases[n] = oralloc(Tor, r->next, c->cases[n]);
+		break;
+
+	default:	/* add everything unknown to next */
+		c->next = oralloc(Talt, r, c->next);
+		break;
+	}
+}
+
+Re*
+addcase(Re *r)
+{
+	int i, n;
+	Re *a;
+
+	if(r->gen == gen)
+		return r;
+	r->gen = gen;
+	switch(r->type) {
+	default:
+		error("addcase");
+
+	case Tor:
+		n = countor(r);
+		if(n >= Caselim) {
+			a = ral(Tcase);
+			a->cases = mal(256*sizeof(*a->cases));
+			case1(a, r);
+			for(i=0; i<256; i++)
+				if(a->cases[i]) {
+					r = a->cases[i];
+					if(countor(r) < n)
+						a->cases[i] = addcase(r);
+				}
+			return a;
+		}
+		return r;
+
+	case Talt:
+		r->next = addcase(r->next);
+		r->alt = addcase(r->alt);
+		return r;
+
+	case Tbegin:
+	case Tend:
+	case Tclass:
+		return r;
+	}
+}
+
+void
+str2top(char *p)
+{
+	Re2 oldtop;
+
+	oldtop = topre;
+	input = p;
+	topre.beg = 0;
+	topre.end = 0;
+	yyparse();
+	gen++;
+	if(topre.beg == 0)
+		yyerror("syntax");
+	if(oldtop.beg)
+		topre = re2or(oldtop, topre);
+}
+
+void
+appendnext(Re *a, Re *b)
+{
+	Re *n;
+
+	while(n = a->next)
+		a = n;
+	a->next = b;
+}
+
+void
+patchnext(Re *a, Re *b)
+{
+	Re *n;
+
+	while(a) {
+		n = a->next;
+		a->next = b;
+		a = n;
+	}
+}
+
+int
+getrec(void)
+{
+	int c;
+
+	if(flags['f']) {
+		c = Bgetc(rein);
+		if(c <= 0)
+			return 0;
+	} else
+		c = *input++ & 0xff;
+	if(flags['i'] && c >= 'A' && c <= 'Z')
+		c += 'a'-'A';
+	if(c == '\n')
+		lineno++;
+	return c;
+}
+
+Re2
+re2cat(Re2 a, Re2 b)
+{
+	Re2 c;
+
+	c.beg = a.beg;
+	c.end = b.end;
+	patchnext(a.end, b.beg);
+	return c;
+}
+
+Re2
+re2star(Re2 a)
+{
+	Re2 c;
+
+	c.beg = ral(Talt);
+	c.beg->alt = a.beg;
+	patchnext(a.end, c.beg);
+	c.end = c.beg;
+	return c;
+}
+
+Re2
+re2or(Re2 a, Re2 b)
+{
+	Re2 c;
+
+	c.beg = ral(Tor);
+	c.beg->alt = b.beg;
+	c.beg->next = a.beg;
+	c.end = b.end;
+	appendnext(c.end,  a.end);
+	return c;
+}
+
+Re2
+re2char(int c0, int c1)
+{
+	Re2 c;
+
+	c.beg = ral(Tclass);
+	c.beg->lo = c0 & 0xff;
+	c.beg->hi = c1 & 0xff;
+	c.end = c.beg;
+	return c;
+}
+
+void
+reprint1(Re *a)
+{
+	int i, j;
+
+loop:
+	if(a == 0)
+		return;
+	if(a->gen == gen)
+		return;
+	a->gen = gen;
+	print("%p: ", a);
+	switch(a->type) {
+	default:
+		print("type %d\n", a->type);
+		error("print1 type");
+
+	case Tcase:
+		print("case ->%p\n", a->next);
+		for(i=0; i<256; i++)
+			if(a->cases[i]) {
+				for(j=i+1; j<256; j++)
+					if(a->cases[i] != a->cases[j])
+						break;
+				print("	[%.2x-%.2x] ->%p\n", i, j-1, a->cases[i]);
+				i = j-1;
+			}
+		for(i=0; i<256; i++)
+			reprint1(a->cases[i]);
+		break;
+
+	case Tbegin:
+		print("^ ->%p\n", a->next);
+		break;
+
+	case Tend:
+		print("$ ->%p\n", a->next);
+		break;
+
+	case Tclass:
+		print("[%.2x-%.2x] ->%p\n", a->lo, a->hi, a->next);
+		break;
+
+	case Tor:
+	case Talt:
+		print("| %p ->%p\n", a->alt, a->next);
+		reprint1(a->alt);
+		break;
+	}
+	a = a->next;
+	goto loop;
+}
+
+void
+reprint(char *s, Re *r)
+{
+	print("%s:\n", s);
+	gen++;
+	reprint1(r);
+	print("\n\n");
+}
blob - 3ad7ea7a99c444c1502a21d18c3da4b6cb8f9339
blob + 292c051be4bb8679de5007ddbb5a58b09c3e0f5b
--- src/cmd/mkfile
+++ src/cmd/mkfile
@@ -3,11 +3,11 @@ PLAN9=../..
 
 TARG=`ls *.c | sed 's/\.c//'`
 LDFLAGS=$LDFLAGS
-SHORTLIB=sec fs mux regexp9 thread bio 9
+SHORTLIB=mach sec fs mux regexp9 thread bio 9
 
 <$PLAN9/src/mkmany
 
-BUGGERED='CVS|9term|faces|factotum|htmlfmt|mk|rio|upas|vac|venti'
+BUGGERED='CVS|faces|factotum|htmlfmt|mk|upas|vac|venti'
 DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
 
 <$PLAN9/src/mkdirs
blob - 4776d1278a28a6102a5bbc3689489f14c0244311
blob + 33a4458e04b0f86655b4106c7c84c40eb26fa856
--- src/cmd/plumb/fsys.c
+++ src/cmd/plumb/fsys.c
@@ -97,6 +97,7 @@ static Dirtab dir[NDIR] =
 static int	ndir = NQID;
 
 static int		srvfd;
+#define clock plumbclock	/* SunOS name clash */
 static int		clock;
 static Fid		*fids[Nhash];
 static QLock	readlock;
blob - 80a57af3ee40e134770b1f70576ceb9cbc2fca67
blob + bf7afa3f80f128e820e1c1665c18009b9b2c92c7
--- src/cmd/plumb/plumber.c
+++ src/cmd/plumb/plumber.c
@@ -54,9 +54,10 @@ threadmain(int argc, char *argv[])
 		error("can't initialize $user or $home: %r");
 	if(plumbfile == nil){
 		sprint(buf, "%s/lib/plumbing", home);
-		if(access(buf, 0) < 0)
-			sprint(buf, "#9/plumb/initial.plumbing");
-		plumbfile = estrdup(buf);
+		if(access(buf, 0) >= 0)
+			plumbfile = estrdup(buf);
+		else
+			plumbfile = unsharp("#9/plumb/initial.plumbing");
 	}
 
 	fd = open(plumbfile, OREAD);
blob - 689edf5983b22367e7c99e2946f3d7b1a8bb1fc2
blob + ab27787d670cd4dfcfcc7b4e69f89cb8101c38ee
--- src/cmd/plumb/rules.c
+++ src/cmd/plumb/rules.c
@@ -415,7 +415,7 @@ include(char *s)
 	fd = open(t, OREAD);
 	if(fd<0 && t[0]!='/' && strncmp(t, "./", 2)!=0 && strncmp(t, "../", 3)!=0){
 		snprint(buf, sizeof buf, "#9/plumb/%s", t);
-		t = buf;
+		t = unsharp(buf);
 		fd = open(t, OREAD);
 	}
 	if(fd < 0)
blob - eb93a4f5280d82b0e65ba73d76180f4eff03644c
blob + 6b32a2277c2a9f9d09e6f9bb5c47e9e2dfed3a23
--- src/cmd/rc/plan9ish.c
+++ src/cmd/rc/plan9ish.c
@@ -27,20 +27,10 @@ char *syssigname[]={
 char*
 Rcmain(void)
 {
-	return "#9/rcmain";
-/*
-	static char buf[256];
-	char *root;
-
-	root = getenv("PLAN9");
-	if(root == nil)
-		root = "/usr/local/plan9";
-	snprint(buf, sizeof buf, "%s/rcmain", root);
-	return buf;
-*/
+	return unsharp("#9/rcmain");
 }
 
-char Fdprefix[]="#d/";
+char Fdprefix[]="/dev/fd/";
 void execfinit(void);
 void execbind(void);
 void execmount(void);
blob - /dev/null
blob + 43a789318cdba6a358d75ecb3643e16167ea2a5e (mode 644)
--- /dev/null
+++ src/cmd/rio/Imakefile
@@ -0,0 +1,27 @@
+INCLUDES = -I$(TOP)
+DEPLIBS = $(DEPXLIB)
+LOCAL_LIBRARIES = $(XLIB)
+DEFINES = -DSHAPE # -g3 -DDEBUG -DDEBUG_EV
+SRCS = main.c event.c manage.c menu.c client.c grab.c cursor.c error.c color.c
+OBJS = main.o event.o manage.o menu.o client.o grab.o cursor.o error.o color.o
+HFILES = dat.h fns.h patchlevel.h
+MFILES = README 9wm.man Imakefile Makefile.no-imake
+
+ComplexProgramTarget(rio)
+
+bun:
+	bundle $(MFILES) $(SRCS) $(HFILES) >bun
+
+dist:
+	bundle $(MFILES) main.c event.c manage.c >bun1
+	bundle menu.c client.c grab.c cursor.c error.c $(HFILES) >bun2
+
+trout: 9wm.man
+	troff -man 9wm.man >trout
+
+vu: trout
+	xditview trout
+
+clean::
+	$(RM) bun bun[12] trout core
+
blob - 8c5346601466149f832202c4647d0d3e82190e71
blob + 0e3c8d89d49b5875b786f67b13ae3f8e79d32ef1
--- src/cmd/rio/color.c
+++ src/cmd/rio/color.c
@@ -8,7 +8,7 @@
 #include "fns.h"
 
 unsigned long
-colorpixel(Display *dpy, int depth, ulong rgb)
+colorpixel(Display *dpy, int depth, unsigned long rgb)
 {
 	int r, g, b;
 
blob - 0953f1bded98082226ed3e0157f505e119d3797c
blob + 029297735066658d059295bd595e63279b159437
--- src/cmd/rio/main.c
+++ src/cmd/rio/main.c
@@ -9,6 +9,9 @@
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
 #include <X11/Xatom.h>
+#ifdef SHAPE
+#include <X11/extensions/shape.h>
+#endif
 #include "dat.h"
 #include "fns.h"
 #include "patchlevel.h"
@@ -70,12 +73,15 @@ main(int argc, char *argv[])
 	int i, background, do_exit, do_restart;
 	char *fname;
 	int shape_event;
+#ifdef SHAPE
+	int dummy;
+#endif
 
 	shape_event = 0;
 	myargv = argv;			/* for restart */
 
 	do_exit = do_restart = 0;
-	background = 1;
+	background = 0;
 	font = 0;
 	fname = 0;
 	for (i = 1; i < argc; i++)
@@ -289,12 +295,11 @@ initscreen(ScreenInfo *s, int i, int background)
 	XSync(dpy, False);
 
 	if (background) {
-/*
 		XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap);
 		XClearWindow(dpy, s->root);
-*/
+	} else
 		system("xsetroot -solid grey30");
-	}
+
 	s->menuwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 2, colorpixel(dpy, s->depth, 0x88CC88), colorpixel(dpy, s->depth, 0xE9FFE9));
 	s->sweepwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 4, s->red, colorpixel(dpy, s->depth, 0xEEEEEE));
 }
blob - 8881190c78b5285c442cb9f2d3aba398a344c416
blob + b5e8b11098ad1aa6743b6f0373853af1b4c931fe
--- src/cmd/rio/mkfile
+++ src/cmd/rio/mkfile
@@ -1,3 +1,4 @@
+PLAN9=../../..
 <$PLAN9/src/mkhdr
 
 OFILES=\
@@ -18,3 +19,7 @@ TARG=rio
 LDFLAGS=-L$X11/lib -lXext -lX11
 
 <$PLAN9/src/mkone
+
+CFLAGS=$CFLAGS -DSHAPE -I$X11/include
+
+
blob - e63fbb8705a5c6b413801ff46c0ac7fac81a6cf2
blob + 8d5519efc32b6cf8e0241295c7b207ca5ae43b37
--- src/cmd/spell/sprog.c
+++ src/cmd/spell/sprog.c
@@ -460,6 +460,9 @@ main(int argc, char *argv[])
 	int low;
 	Bits h;
 
+	codefile = unsharp(codefile);
+	brfile = unsharp(brfile);
+
 	Binit(&bin, 0, OREAD);
 	Binit(&bout, 1, OWRITE);
 	for(i=0; c = "aeiouyAEIOUY"[i]; i++)
blob - 7f15f0578886b4bae6df95e1678624a817b82c4d (mode 644)
blob + /dev/null
--- src/cmd/win.c
+++ /dev/null
@@ -1,717 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include <fcall.h>
-#include <fs.h>
-
-#define	EVENTSIZE	256
-#define	STACK	32768
-
-typedef struct Event Event;
-typedef struct Q Q;
-
-struct Event
-{
-	int	c1;
-	int	c2;
-	int	q0;
-	int	q1;
-	int	flag;
-	int	nb;
-	int	nr;
-	char	b[EVENTSIZE*UTFmax+1];
-	Rune	r[EVENTSIZE+1];
-};
-
-Event blank = {
-	'M',
-	'X',
-	0, 0, 0, 1, 1,
-	{ ' ', 0 },
-	{ ' ', 0 },
-};
-
-struct Q
-{
-	QLock	lk;
-	int		p;
-	int		k;
-};
-
-Q	q;
-
-Fid *eventfd;
-Fid *addrfd;
-Fid *datafd;
-Fid *ctlfd;
-// int bodyfd;
-
-char	*typing;
-int	ntypeb;
-int	ntyper;
-int	ntypebreak;
-int	debug;
-char *name;
-
-char **prog;
-int p[2];
-Channel *cpid;
-Channel *cwait;
-int pid = -1;
-
-int	label(char*, int);
-void	error(char*);
-void	stdinproc(void*);
-void	stdoutproc(void*);
-void	type(Event*, int, Fid*, Fid*);
-void	sende(Event*, int, Fid*, Fid*, Fid*, int);
-char	*onestring(int, char**);
-int	delete(Event*);
-void	deltype(uint, uint);
-void	runproc(void*);
-
-int
-fsfidprint(Fid *fid, char *fmt, ...)
-{
-	char buf[256];
-	va_list arg;
-	int n;
-
-	va_start(arg, fmt);
-	n = vsnprint(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	return fswrite(fid, buf, n);
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: win cmd args...\n");
-	threadexitsall("usage");
-}
-
-int
-nopipes(void *v, char *msg)
-{
-	USED(v);
-	if(strcmp(msg, "sys: write on closed pipe") == 0)
-		return 1;
-	return 0;
-}
-
-void
-waitthread(void *v)
-{
-	recvp(cwait);
-	threadexitsall(nil);
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	int fd, id;
-	char buf[256];
-	char buf1[128];
-	Fsys *fs;
-
-	ARGBEGIN{
-	case 'd':
-		debug = 1;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	prog = argv;
-
-	if(argc > 0)
-		name = argv[0];
-	else
-		name = "gnot";
-
-	threadnotify(nopipes, 1);
-	if((fs = nsmount("acme", "")) < 0)
-		sysfatal("nsmount acme: %r");
-	ctlfd = fsopen(fs, "new/ctl", ORDWR|OCEXEC);
-	if(ctlfd < 0 || fsread(ctlfd, buf, 12) != 12)
-		sysfatal("ctl: %r");
-	id = atoi(buf);
-	sprint(buf, "%d/tag", id);
-	fd = fsopenfd(fs, buf, OWRITE|OCEXEC);
-	write(fd, " Send Delete", 12);
-	close(fd);
-	sprint(buf, "%d/event", id);
-	eventfd = fsopen(fs, buf, ORDWR|OCEXEC);
-	sprint(buf, "%d/addr", id);
-	addrfd = fsopen(fs, buf, ORDWR|OCEXEC);
-	sprint(buf, "%d/data", id);
-	datafd = fsopen(fs, buf, ORDWR|OCEXEC);
-	sprint(buf, "%d/body", id);
-/*	bodyfd = fsopenfd(fs, buf, ORDWR|OCEXEC); */
-	if(eventfd==nil || addrfd==nil || datafd==nil)
-		sysfatal("data files: %r");
-/*
-	if(eventfd<0 || addrfd<0 || datafd<0 || bodyfd<0)
-		sysfatal("data files: %r");
-*/
-	fsunmount(fs);
-
-	if(pipe(p) < 0)
-		sysfatal("pipe: %r");
-
-	cpid = chancreate(sizeof(ulong), 1);
-	cwait = threadwaitchan();
-	threadcreate(waitthread, nil, STACK);
-	threadcreate(runproc, nil, STACK);
-	pid = recvul(cpid);
-	if(pid == -1)
-		sysfatal("exec failed");
-
-	getwd(buf1, sizeof buf1);
-	sprint(buf, "name %s/-%s\n0\n", buf1, name);
-	fswrite(ctlfd, buf, strlen(buf));
-	sprint(buf, "dumpdir %s/\n", buf1);
-	fswrite(ctlfd, buf, strlen(buf));
-	sprint(buf, "dump %s\n", onestring(argc, argv));
-	fswrite(ctlfd, buf, strlen(buf));
-	
-	threadcreate(stdoutproc, nil, STACK);
-	stdinproc(nil);
-}
-
-char *shell[] = { "rc", "-i", 0 };
-void
-runproc(void *v)
-{
-	int fd[3];
-	char *sh;
-
-	USED(v);
-
-	fd[0] = p[1];
-//	fd[1] = bodyfd;
-//	fd[2] = bodyfd;
-	fd[1] = p[1];
-	fd[2] = p[1];
-
-	if(prog[0] == nil){
-		prog = shell;
-		if((sh = getenv("SHELL")) != nil)
-			shell[0] = sh;
-	}
-	threadexec(cpid, fd, prog[0], prog);
-	threadexits(nil);
-}
-
-void
-error(char *s)
-{
-	if(s)
-		fprint(2, "win: %s: %r\n", s);
-	else
-		s = "kill";
-	if(pid != -1)
-		postnote(PNGROUP, pid, "hangup");
-	threadexitsall(s);
-}
-
-char*
-onestring(int argc, char **argv)
-{
-	char *p;
-	int i, n;
-	static char buf[1024];
-
-	if(argc == 0)
-		return "";
-	p = buf;
-	for(i=0; i<argc; i++){
-		n = strlen(argv[i]);
-		if(p+n+1 >= buf+sizeof buf)
-			break;
-		memmove(p, argv[i], n);
-		p += n;
-		*p++ = ' ';
-	}
-	p[-1] = 0;
-	return buf;
-}
-
-int
-getec(Fid *efd)
-{
-	static char buf[8192];
-	static char *bufp;
-	static int nbuf;
-
-	if(nbuf == 0){
-		nbuf = fsread(efd, buf, sizeof buf);
-		if(nbuf <= 0)
-			error(nil);
-		bufp = buf;
-	}
-	--nbuf;
-	return *bufp++;
-}
-
-int
-geten(Fid *efd)
-{
-	int n, c;
-
-	n = 0;
-	while('0'<=(c=getec(efd)) && c<='9')
-		n = n*10+(c-'0');
-	if(c != ' ')
-		error("event number syntax");
-	return n;
-}
-
-int
-geter(Fid *efd, char *buf, int *nb)
-{
-	Rune r;
-	int n;
-
-	r = getec(efd);
-	buf[0] = r;
-	n = 1;
-	if(r < Runeself)
-		goto Return;
-	while(!fullrune(buf, n))
-		buf[n++] = getec(efd);
-	chartorune(&r, buf);
-    Return:
-	*nb = n;
-	return r;
-}
-
-void
-gete(Fid *efd, Event *e)
-{
-	int i, nb;
-
-	e->c1 = getec(efd);
-	e->c2 = getec(efd);
-	e->q0 = geten(efd);
-	e->q1 = geten(efd);
-	e->flag = geten(efd);
-	e->nr = geten(efd);
-	if(e->nr > EVENTSIZE)
-		error("event string too long");
-	e->nb = 0;
-	for(i=0; i<e->nr; i++){
-		e->r[i] = geter(efd, e->b+e->nb, &nb);
-		e->nb += nb;
-	}
-	e->r[e->nr] = 0;
-	e->b[e->nb] = 0;
-	if(getec(efd) != '\n')
-		error("event syntax 2");
-}
-
-int
-nrunes(char *s, int nb)
-{
-	int i, n;
-	Rune r;
-
-	n = 0;
-	for(i=0; i<nb; n++)
-		i += chartorune(&r, s+i);
-	return n;
-}
-
-void
-stdinproc(void *v)
-{
-	Fid *cfd = ctlfd;
-	Fid *efd = eventfd;
-	Fid *dfd = datafd;
-	Fid *afd = addrfd;
-	int fd0 = p[0];
-	Event e, e2, e3, e4;
-
-	USED(v);
-
-	for(;;){
-		if(debug)
-			fprint(2, "typing[%d,%d)\n", q.p, q.p+ntyper);
-		gete(efd, &e);
-		if(debug)
-			fprint(2, "msg %c%c q[%d,%d)... ", e.c1, e.c2, e.q0, e.q1);
-		qlock(&q.lk);
-		switch(e.c1){
-		default:
-		Unknown:
-			print("unknown message %c%c\n", e.c1, e.c2);
-			break;
-
-		case 'E':	/* write to body; can't affect us */
-			if(debug)
-				fprint(2, "shift typing %d... ", e.q1-e.q0);
-			q.p += e.q1-e.q0;
-			break;
-
-		case 'F':	/* generated by our actions; ignore */
-			break;
-
-		case 'K':
-		case 'M':
-			switch(e.c2){
-			case 'I':
-				if(e.q0 < q.p){
-					if(debug)
-						fprint(2, "shift typing %d... ", e.q1-e.q0);
-					q.p += e.q1-e.q0;
-				}
-				else if(e.q0 <= q.p+ntyper){
-					if(debug)
-						fprint(2, "type... ");
-					type(&e, fd0, afd, dfd);
-				}
-				break;
-
-			case 'D':
-				q.p -= delete(&e);
-				break;
-
-			case 'x':
-			case 'X':
-				if(e.flag & 2)
-					gete(efd, &e2);
-				if(e.flag & 8){
-					gete(efd, &e3);
-					gete(efd, &e4);
-				}
-				if(e.flag&1 || (e.c2=='x' && e.nr==0 && e2.nr==0)){
-					/* send it straight back */
-					fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
-					break;
-				}
-				if(e.q0==e.q1 && (e.flag&2)){
-					e2.flag = e.flag;
-					e = e2;
-				}
-				if(e.flag & 8){
-					if(e.q1 != e.q0){
-						sende(&e, fd0, cfd, afd, dfd, 0);
-						sende(&blank, fd0, cfd, afd, dfd, 0);
-					}
-					sende(&e3, fd0, cfd, afd, dfd, 1);
-				}else	 if(e.q1 != e.q0)
-					sende(&e, fd0, cfd, afd, dfd, 1);
-				break;
-
-			case 'l':
-			case 'L':
-				/* just send it back */
-				if(e.flag & 2)
-					gete(efd, &e2);
-				fsfidprint(efd, "%c%c%d %d\n", e.c1, e.c2, e.q0, e.q1);
-				break;
-
-			case 'd':
-			case 'i':
-				break;
-
-			default:
-				goto Unknown;
-			}
-		}
-		qunlock(&q.lk);
-	}
-}
-
-void
-stdoutproc(void *v)
-{
-	int fd1 = p[0];
-	Fid *afd = addrfd;
-	Fid *dfd = datafd;
-	int n, m, w, npart;
-	char *buf, *s, *t;
-	Rune r;
-	char x[16], hold[UTFmax];
-
-	USED(v);
-	threadnotify(nopipes, 1);
-	buf = malloc(8192+UTFmax+1);
-	npart = 0;
-	for(;;){
-		n = threadread(fd1, buf+npart, 8192);
-		if(n < 0)
-			error(nil);
-		if(n == 0)
-			continue;
-
-		/* squash NULs */
-		s = memchr(buf+npart, 0, n);
-		if(s){
-			for(t=s; s<buf+npart+n; s++)
-				if(*t = *s)	/* assign = */
-					t++;
-			n = t-(buf+npart);
-		}
-
-		n += npart;
-
-		/* hold on to final partial rune */
-		npart = 0;
-		while(n>0 && (buf[n-1]&0xC0)){
-			--n;
-			npart++;
-			if((buf[n]&0xC0)!=0x80){
-				if(fullrune(buf+n, npart)){
-					w = chartorune(&r, buf+n);
-					n += w;
-					npart -= w;
-				}
-				break;
-			}
-		}
-		if(n > 0){
-			memmove(hold, buf+n, npart);
-			buf[n] = 0;
-			n = label(buf, n);
-			buf[n] = 0;
-			qlock(&q.lk);
-			m = sprint(x, "#%d", q.p);
-			if(fswrite(afd, x, m) != m)
-				error("stdout writing address");
-			if(fswrite(dfd, buf, n) != n)
-				error("stdout writing body");
-			q.p += nrunes(buf, n);
-			qunlock(&q.lk);
-			memmove(buf, hold, npart);
-		}
-	}
-}
-
-char wdir[256];
-int
-label(char *sr, int n)
-{
-	char *sl, *el, *er, *r;
-
-	er = sr+n;
-	for(r=er-1; r>=sr; r--)
-		if(*r == '\007')
-			break;
-	if(r < sr)
-		return n;
-
-	el = r+1;
-	if(el-sr > sizeof wdir)
-		sr = el - sizeof wdir;
-	for(sl=el-3; sl>=sr; sl--)
-		if(sl[0]=='\033' && sl[1]==']' && sl[2]==';')
-			break;
-	if(sl < sr)
-		return n;
-
-	*r = 0;
-	snprint(wdir, sizeof wdir, "name %s/-%s\n0\n", sl+3, name);
-	fswrite(ctlfd, wdir, strlen(wdir));
-
-	memmove(sl, el, er-el);
-	n -= (el-sl);
-	return n;
-}
-
-int
-delete(Event *e)
-{
-	uint q0, q1;
-	int deltap;
-
-	q0 = e->q0;
-	q1 = e->q1;
-	if(q1 <= q.p)
-		return e->q1-e->q0;
-	if(q0 >= q.p+ntyper)
-		return 0;
-	deltap = 0;
-	if(q0 < q.p){
-		deltap = q.p-q0;
-		q0 = 0;
-	}else
-		q0 -= q.p;
-	if(q1 > q.p+ntyper)
-		q1 = ntyper;
-	else
-		q1 -= q.p;
-	deltype(q0, q1);
-	return deltap;
-}
-
-void
-addtype(int c, uint p0, char *b, int nb, int nr)
-{
-	int i, w;
-	Rune r;
-	uint p;
-	char *b0;
-
-	for(i=0; i<nb; i+=w){
-		w = chartorune(&r, b+i);
-		if((r==0x7F||r==3) && c=='K'){
-			postnote(PNGROUP, pid, "interrupt");
-			/* toss all typing */
-			q.p += ntyper+nr;
-			ntypebreak = 0;
-			ntypeb = 0;
-			ntyper = 0;
-			/* buglet:  more than one delete ignored */
-			return;
-		}
-		if(r=='\n' || r==0x04)
-			ntypebreak++;
-	}
-	typing = realloc(typing, ntypeb+nb);
-	if(typing == nil)
-		error("realloc");
-	if(p0 == ntyper)
-		memmove(typing+ntypeb, b, nb);
-	else{
-		b0 = typing;
-		for(p=0; p<p0 && b0<typing+ntypeb; p++){
-			w = chartorune(&r, b0+i);
-			b0 += w;
-		}
-		if(p != p0)
-			error("typing: findrune");
-		memmove(b0+nb, b0, (typing+ntypeb)-b0);
-		memmove(b0, b, nb);
-	}
-	ntypeb += nb;
-	ntyper += nr;
-}
-
-void
-sendtype(int fd0)
-{
-	int i, n, nr;
-
-	while(ntypebreak){
-		for(i=0; i<ntypeb; i++)
-			if(typing[i]=='\n' || typing[i]==0x04){
-				n = i + (typing[i] == '\n');
-				i++;
-				if(write(fd0, typing, n) != n)
-					error("sending to program");
-				nr = nrunes(typing, i);
-				q.p += nr;
-				ntyper -= nr;
-				ntypeb -= i;
-				memmove(typing, typing+i, ntypeb);
-				ntypebreak--;
-				goto cont2;
-			}
-		print("no breakchar\n");
-		ntypebreak = 0;
-cont2:;
-	}
-}
-
-void
-deltype(uint p0, uint p1)
-{
-	int w;
-	uint p, b0, b1;
-	Rune r;
-
-	/* advance to p0 */
-	b0 = 0;
-	for(p=0; p<p0 && b0<ntypeb; p++){
-		w = chartorune(&r, typing+b0);
-		b0 += w;
-	}
-	if(p != p0)
-		error("deltype 1");
-	/* advance to p1 */
-	b1 = b0;
-	for(; p<p1 && b1<ntypeb; p++){
-		w = chartorune(&r, typing+b1);
-		b1 += w;
-		if(r=='\n' || r==0x04)
-			ntypebreak--;
-	}
-	if(p != p1)
-		error("deltype 2");
-	memmove(typing+b0, typing+b1, ntypeb-b1);
-	ntypeb -= b1-b0;
-	ntyper -= p1-p0;
-}
-
-void
-type(Event *e, int fd0, Fid *afd, Fid *dfd)
-{
-	int m, n, nr;
-	char buf[128];
-
-	if(e->nr > 0)
-		addtype(e->c1, e->q0-q.p, e->b, e->nb, e->nr);
-	else{
-		m = e->q0;
-		while(m < e->q1){
-			n = sprint(buf, "#%d", m);
-			fswrite(afd, buf, n);
-			n = fsread(dfd, buf, sizeof buf);
-			nr = nrunes(buf, n);
-			while(m+nr > e->q1){
-				do; while(n>0 && (buf[--n]&0xC0)==0x80);
-				--nr;
-			}
-			if(n == 0)
-				break;
-			addtype(e->c1, m-q.p, buf, n, nr);
-			m += nr;
-		}
-	}
-	sendtype(fd0);
-}
-
-void
-sende(Event *e, int fd0, Fid *cfd, Fid *afd, Fid *dfd, int donl)
-{
-	int l, m, n, nr, lastc, end;
-	char abuf[16], buf[128];
-
-	end = q.p+ntyper;
-	l = sprint(abuf, "#%d", end);
-	fswrite(afd, abuf, l);
-	if(e->nr > 0){
-		fswrite(dfd, e->b, e->nb);
-		addtype(e->c1, ntyper, e->b, e->nb, e->nr);
-		lastc = e->r[e->nr-1];
-	}else{
-		m = e->q0;
-		lastc = 0;
-		while(m < e->q1){
-			n = sprint(buf, "#%d", m);
-			fswrite(afd, buf, n);
-			n = fsread(dfd, buf, sizeof buf);
-			nr = nrunes(buf, n);
-			while(m+nr > e->q1){
-				do; while(n>0 && (buf[--n]&0xC0)==0x80);
-				--nr;
-			}
-			if(n == 0)
-				break;
-			l = sprint(abuf, "#%d", end);
-			fswrite(afd, abuf, l);
-			fswrite(dfd, buf, n);
-			addtype(e->c1, ntyper, buf, n, nr);
-			lastc = buf[n-1];
-			m += nr;
-			end += nr;
-		}
-	}
-	if(donl && lastc!='\n'){
-		fswrite(dfd, "\n", 1);
-		addtype(e->c1, ntyper, "\n", 1, 1);
-	}
-	fswrite(cfd, "dot=addr", 8);
-	sendtype(fd0);
-}
blob - 0ff114bda442cba2b11264a84e65d9e8202ca6fd
blob + 6614414dffba4790fd17b8ea871f948de0fb859d
--- src/cmd/yacc.c
+++ src/cmd/yacc.c
@@ -399,7 +399,7 @@ others(void)
 {
 	int c, i, j;
 
-	finput = Bopen(parser, OREAD);
+	finput = Bopen(unsharp(parser), OREAD);
 	if(finput == 0)
 		error("cannot open parser %s: %r", parser);
 	warray("yyr1", levprd, nprod);
blob - 4eb6eac9869b53fcafbf301a4f7f596c02ceb242
blob + 84cd65caedb79829a0d3b445b7be553761f47184
--- src/lib9/_p9translate.c
+++ src/lib9/_p9translate.c
@@ -14,7 +14,7 @@ static struct {
 };
 
 char*
-_p9translate(char *old)
+plan9translate(char *old)
 {
 	char *new;
 	int i, olen, nlen, len;
@@ -36,7 +36,7 @@ _p9translate(char *old)
 		len = strlen(old)+nlen-olen;
 		new = malloc(len+1);
 		if(new == nil)
-			return nil;
+			return "<out of memory>";
 		strcpy(new, replace[i].new);
 		strcpy(new+nlen, old+olen);
 		assert(strlen(new) == len);
blob - 20b00c32744d1d1cf75af6196b1dbeb9b6905be9 (mode 644)
blob + /dev/null
--- src/lib9/access.c
+++ /dev/null
@@ -1,19 +0,0 @@
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-char *_p9translate(char*);
-
-int
-p9access(char *xname, int what)
-{
-	int ret;
-	char *name;
-
-	if((name = _p9translate(xname)) == nil)
-		return -1;
-	ret = access(name, what);
-	if(name != xname)
-		free(name);
-	return ret;
-}
blob - 9f07bd2293c96907db947cf5003832c035491786
blob + 8fdf1d40c610b4826f04830e3b618a2c488f3809
--- src/lib9/announce.c
+++ src/lib9/announce.c
@@ -40,7 +40,8 @@ p9announce(char *addr, char *dir)
 	char *net;
 	u32int host;
 	int port, s;
-	int n, sn;
+	int n;
+	socklen_t sn;
 	struct sockaddr_in sa;
 	struct sockaddr_un sun;
 
@@ -72,7 +73,7 @@ p9announce(char *addr, char *dir)
 	if((s = socket(AF_INET, proto, 0)) < 0)
 		return -1;
 	sn = sizeof n;
-	if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&n, &sn) >= 0
+	if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
 	&& n == SOCK_STREAM){
 		n = 1;
 		setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
blob - bdad5f6a0c8f8e69a6b0f594255deb43adc6ccf7
blob + 97f6e7e2a2540b09548fe7881751401c556a5b9e
--- src/lib9/create.c
+++ src/lib9/create.c
@@ -3,17 +3,11 @@
 #include <libc.h>
 #include <sys/stat.h>
 
-extern char *_p9translate(char*);
-
 int
-p9create(char *xpath, int mode, ulong perm)
+p9create(char *path, int mode, ulong perm)
 {
 	int fd, cexec, umode, rclose;
-	char *path;
 
-	if((path = _p9translate(xpath)) == nil)
-		return -1;
-
 	cexec = mode&OCEXEC;
 	rclose = mode&ORCLOSE;
 	mode &= ~(ORCLOSE|OCEXEC);
@@ -48,7 +42,5 @@ out:
 		if(rclose)
 			remove(path);
 	}
-	if(path != xpath)
-		free(path);
 	return fd;
 }
blob - e9d971bf69d310b26e00a5fcbbfb58ab187234c7
blob + 0782d099feacdb1a59f797fa707967543f57c28a
--- src/lib9/ctime.c
+++ src/lib9/ctime.c
@@ -15,6 +15,7 @@ ct_numb(char *cp, int n)
 char*
 asctime(Tm *t)
 {
+	int i;
 	char *ncp;
 	static char cbuf[30];
 
@@ -32,6 +33,12 @@ asctime(Tm *t)
 	ct_numb(cbuf+14, t->min+100);
 	ct_numb(cbuf+17, t->sec+100);
 	ncp = t->zone;
+	for(i=0; i<3; i++)
+		if(ncp[i] == 0)
+			break;
+	for(; i<3; i++)
+		ncp[i] = '?';
+	ncp = t->zone;
 	cbuf[20] = *ncp++;
 	cbuf[21] = *ncp++;
 	cbuf[22] = *ncp;
blob - 8ece0c688819408c91609118d132a62759f967de
blob + 8f852de294f80d7971852ac8da157906f3c6bce0
--- src/lib9/date.c
+++ src/lib9/date.c
@@ -1,6 +1,5 @@
-#include <stdlib.h> /* setenv etc. */
-
 #include <u.h>
+#include <stdlib.h> /* setenv etc. */
 #define NOPLAN9DEFINES
 #include <libc.h>
 #include <time.h>
@@ -25,6 +24,8 @@ static Tm bigtm;
 static void
 tm2Tm(struct tm *tm, Tm *bigtm)
 {
+	char *s;
+
 	memset(bigtm, 0, sizeof *bigtm);
 	bigtm->sec = tm->tm_sec;
 	bigtm->min = tm->tm_min;
@@ -39,6 +40,13 @@ tm2Tm(struct tm *tm, Tm *bigtm)
 #ifdef _HAVETZOFF
 	bigtm->tzoff = tm->tm_gmtoff;
 #endif
+	if(bigtm->zone[0] == 0){
+		s = getenv("TIMEZONE");
+		if(s){
+			strecpy(bigtm->zone, bigtm->zone+4, tm->tm_zone);
+			free(s);
+		}
+	}
 }
 
 static void
blob - aef0102f85fae9bb11e921ee5dda0aab3aa5c018
blob + 0a72d62e4d0848176f0bd17fe7e322092faf9d4e
--- src/lib9/dirread.c
+++ src/lib9/dirread.c
@@ -18,7 +18,7 @@ mygetdents(int fd, struct dirent *buf, int n)
 	nn = getdirentries(fd, (void*)buf, n, &off);
 	return nn;
 }
-#elif defined(__APPLE__) || defined(__FreeBSD__)
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
 static int
 mygetdents(int fd, struct dirent *buf, int n)
 {
@@ -171,7 +171,7 @@ dirreadall(int fd, Dir **d)
 		ts += n;
 	}
 	if(ts >= 0)
-		ts = dirpackage(fd, buf, ts, d);
+		ts = dirpackage(fd, (char*)buf, ts, d);
 	free(buf);
 	if(ts == 0 && n < 0)
 		return -1;
blob - 0c6ab315d608390321d8864a7b77c56cb8bec82a
blob + 578f4895e7fdbe7b24abba707c414f3d8c070593
--- src/lib9/errstr.c
+++ src/lib9/errstr.c
@@ -5,9 +5,10 @@
  * okay.
  */
 
+#include <u.h>
 #include <errno.h>
 #include <string.h>
-#include <lib9.h>
+#include <libc.h>
 
 enum
 {
blob - /dev/null
blob + 5e677f72e45ae45af3b3d6c6d7a744c881f99cdc (mode 644)
--- /dev/null
+++ src/lib9/ffork-OpenBSD.c
@@ -0,0 +1 @@
+#include "ffork-pthread.c"
blob - b53a3892ea57cc897b447af11b7fb56a53cd70dd
blob + 09c070419fcf7b0da6e424eca4f277894247243c
--- src/lib9/getuser.c
+++ src/lib9/getuser.c
@@ -1,6 +1,5 @@
-#include <pwd.h>
-
 #include <u.h>
+#include <pwd.h>
 #include <libc.h>
 
 char*
blob - 5d6f2f3e154a56e67cc612b6923393708ad3197e
blob + e97b967f2076b2a9abdf07db6143571cd29d3ebe
--- src/lib9/lock.c
+++ src/lib9/lock.c
@@ -1,6 +1,7 @@
+#include <u.h>
 #include <unistd.h>
 #include <sched.h>
-#include <lib9.h>
+#include <libc.h>
 
 int _ntas;
 static int
blob - c631300887cd2d5adf3062f6c7e7a979717a5926
blob + a3e91510b17797b6b4287f44a601d1fc43c6806d
--- src/lib9/mallocz.c
+++ src/lib9/mallocz.c
@@ -1,6 +1,7 @@
+#include <u.h>
 #include <unistd.h>
 #include <string.h>
-#include <lib9.h>
+#include <libc.h>
 
 void*
 mallocz(unsigned long n, int clr)
blob - d388d224e9787a3328043b613193caede3d1ab22
blob + 4dda2e19fd25a41447294d6f63969d08d2250dba
--- src/lib9/mkfile
+++ src/lib9/mkfile
@@ -69,8 +69,6 @@ LIB9OFILES=\
 	_p9dialparse.$O\
 	_p9dir.$O\
 	_p9proc.$O\
-	_p9translate.$O\
-	access.$O\
 	announce.$O\
 	argv0.$O\
 	atexit.$O\
@@ -100,6 +98,7 @@ LIB9OFILES=\
 	exec.$O\
 	fcallfmt.$O\
 	ffork-$SYSNAME.$O\
+	get9root.$O\
 	getcallerpc-$OBJTYPE.$O\
 	getenv.$O\
 	getfields.$O\
@@ -142,6 +141,7 @@ LIB9OFILES=\
 	u16.$O\
 	u32.$O\
 	u64.$O\
+	unsharp.$O\
 	wait.$O\
 	waitpid.$O\
 
blob - 2e589de750352136856816e158011977e6a92b2d
blob + 4d2a79efc69006750f6a0e526d2812bb09be677c
--- src/lib9/notify.c
+++ src/lib9/notify.c
@@ -1,6 +1,5 @@
-#include <signal.h>
-
 #include <u.h>
+#include <signal.h>
 #define NOPLAN9DEFINES
 #include <libc.h>
 #include "9proc.h"
blob - bb597e8f2171fcf792f8ac5b591c0ecd5771981b
blob + 0356a7dabc561721f96dfe4fc29cab25526404ae
--- src/lib9/open.c
+++ src/lib9/open.c
@@ -2,12 +2,9 @@
 #define NOPLAN9DEFINES
 #include <libc.h>
 
-extern char* _p9translate(char*);
-
 int
-p9open(char *xname, int mode)
+p9open(char *name, int mode)
 {
-	char *name;
 	int cexec, rclose;
 	int fd, umode;
 
@@ -23,8 +20,6 @@ p9open(char *xname, int mode)
 		werrstr("mode not supported");
 		return -1;
 	}
-	if((name = _p9translate(xname)) == nil)
-		return -1;
 	fd = open(name, umode);
 	if(fd >= 0){
 		if(cexec)
@@ -32,7 +27,5 @@ p9open(char *xname, int mode)
 		if(rclose)
 			remove(name);
 	}
-	if(name != xname)
-		free(name);
 	return fd;
 }
blob - 05c52ae734310ff4b438ce004313a539c33d7723
blob + 673818e05550b72a45b9e5b1832403be53f78186
--- src/lib9/rendez-Linux.c
+++ src/lib9/rendez-Linux.c
@@ -1 +1,3 @@
+/* Could use futex(2) here instead of signals? */
+
 #include "rendez-signal.c"
blob - /dev/null
blob + 05c52ae734310ff4b438ce004313a539c33d7723 (mode 644)
--- /dev/null
+++ src/lib9/rendez-OpenBSD.c
@@ -0,0 +1 @@
+#include "rendez-signal.c"
blob - b4b95f21d56fe32fe97d1de8d7014a3673eb5382
blob + fe930cef28e9cb52998b7961046f98494d43eb93
--- src/lib9/rendez-pthread.c
+++ src/lib9/rendez-pthread.c
@@ -32,9 +32,10 @@
  * shared memory and mutexes.
  */
 
+#include <u.h>
 #include <pthread.h>
 #include <signal.h>
-#include <lib9.h>
+#include <libc.h>
 
 enum
 {
blob - 169a82f50287cfd9b64a4b4f9f531b96c168c517
blob + 367063678baf5c1e46c9ae06145dea695f5a1f7a
--- src/lib9/time.c
+++ src/lib9/time.c
@@ -1,7 +1,7 @@
+#include <u.h>
 #include <sys/time.h>
+#include <time.h>
 #include <sys/resource.h>
-
-#include <u.h>
 #define NOPLAN9DEFINES
 #include <libc.h>
 
blob - a359327b598ca6382449b1d8bacfe2495f1dc61d
blob + 05370eacc95899850aaadde56bfd897dd27c6fbe
--- src/libdraw/openfont.c
+++ src/libdraw/openfont.c
@@ -18,8 +18,10 @@ openfont(Display *d, char *name)
 		nambuf = smprint("#9/font/%s", name+14);
 		if(nambuf == nil)
 			return 0;
+		nambuf = unsharp(nambuf);
+		if(nambuf == nil)
+			return 0;
 		if((fd = open(nambuf, OREAD)) < 0){
-fprint(2, "failed at %s\n", nambuf);
 			free(nambuf);
 			return 0;
 		}
blob - 1283f430f09ef8b88ea7845511598eeb88f288d4
blob + c959eee4c98e8c7766e4758267c21a1fa2833e8c
--- src/libdraw/x11-init.c
+++ src/libdraw/x11-init.c
@@ -185,26 +185,22 @@ xattach(char *label)
 	/* 
 	 * Figure out underlying screen format.
 	 */
-	_x.depth = DefaultDepth(_x.display, xrootid);
 	if(XMatchVisualInfo(_x.display, xrootid, 16, TrueColor, &xvi)
 	|| XMatchVisualInfo(_x.display, xrootid, 16, DirectColor, &xvi)){
 		_x.vis = xvi.visual;
 		_x.depth = 16;
-		_x.usetable = 1;
 	}
 	else
 	if(XMatchVisualInfo(_x.display, xrootid, 15, TrueColor, &xvi)
 	|| XMatchVisualInfo(_x.display, xrootid, 15, DirectColor, &xvi)){
 		_x.vis = xvi.visual;
 		_x.depth = 15;
-		_x.usetable = 1;
 	}
 	else
 	if(XMatchVisualInfo(_x.display, xrootid, 24, TrueColor, &xvi)
 	|| XMatchVisualInfo(_x.display, xrootid, 24, DirectColor, &xvi)){
 		_x.vis = xvi.visual;
 		_x.depth = 24;
-		_x.usetable = 1;
 	}
 	else
 	if(XMatchVisualInfo(_x.display, xrootid, 8, PseudoColor, &xvi)
@@ -218,6 +214,7 @@ xattach(char *label)
 		_x.depth = 8;
 	}
 	else{
+		_x.depth = DefaultDepth(_x.display, xrootid);
 		if(_x.depth != 8){
 			werrstr("can't understand depth %d screen", _x.depth);
 			goto err0;
@@ -225,6 +222,9 @@ xattach(char *label)
 		_x.vis = DefaultVisual(_x.display, xrootid);
 	}
 
+	if(DefaultDepth(_x.display, xrootid) == _x.depth)
+		_x.usetable = 1;
+
 	/*
 	 * _x.depth is only the number of significant pixel bits,
 	 * not the total number of pixel bits.  We need to walk the
@@ -298,7 +298,7 @@ xattach(char *label)
 		Dx(r),		/* width */
 	 	Dy(r),		/* height */
 		0,		/* border width */
-		DefaultDepthOfScreen(xscreen),	/* depth */
+		_x.depth,	/* depth */
 		InputOutput,	/* class */
 		_x.vis,		/* visual */
 				/* valuemask */
@@ -563,6 +563,18 @@ setupcmap(XWindow w)
 
 	if(_x.depth >= 24) {
 		/*
+		 * This is needed for SunOS.  Ask Axel Belinfante.
+		 */
+		if(_x.usetable == 0){
+			_x.cmap = XCreateColormap(_x.display, w, _x.vis, AllocAll); 
+			XStoreColors(_x.display, _x.cmap, _x.map, 256);
+			for(i = 0; i < 256; i++){
+				_x.tox11[i] = i;
+				_x.toplan9[i] = i;
+			}
+		}
+
+		/*
 		 * The pixel value returned from XGetPixel needs to
 		 * be converted to RGB so we can call rgb2cmap()
 		 * to translate between 24 bit X and our color. Unfortunately,
@@ -573,7 +585,6 @@ setupcmap(XWindow w)
 		 * some displays say MSB even though they run on LSB.
 		 * Besides, this is more anal.
 		 */
-
 		c = _x.map[19];	/* known to have different R, G, B values */
 		if(!XAllocColor(_x.display, _x.cmap, &c)){
 			werrstr("XAllocColor: %r");
blob - 8e72b011e66d53e9ea0a2a29a7d27f70adea3384
blob + 509b55cfca5067d01dbae74c4dce6643a9796692
--- src/libdraw/x11-itrans.c
+++ src/libdraw/x11-itrans.c
@@ -11,6 +11,9 @@
 #include <keyboard.h>
 #include "x11-memdraw.h"
 
+#undef time
+
+
 static int
 __xtoplan9kbd(XEvent *e)
 {
blob - c4094fa485c45e39500cc4a3baabf197000bf5f9
blob + 4b2786955cb006ce47083802e184ea2b5e0348fd
--- src/libplumb/mesg.c
+++ src/libplumb/mesg.c
@@ -68,7 +68,6 @@ plumbsendtofid(Fid *fid, Plumbmsg *m)
 	if(buf == nil)
 		return -1;
 	n = fswrite(fid, buf, n);
-fprint(2, "fswrite %d\n", n);
 	free(buf);
 	return n;
 }
blob - /dev/null
blob + 35e2ab6f87f746e3acc9434f2e5571c0184b4145 (mode 644)
--- /dev/null
+++ src/libthread/asm-OpenBSD-386.s
@@ -0,0 +1,49 @@
+.globl	_setlabel
+.type	_setlabel,@function
+
+_setlabel:
+	movl	4(%esp), %eax
+	movl	0(%esp), %edx
+	movl	%edx, 0(%eax)
+	movl	%ebx, 4(%eax)
+	movl	%esp, 8(%eax)
+	movl	%ebp, 12(%eax)
+	movl	%esi, 16(%eax)
+	movl	%edi, 20(%eax)
+	xorl	%eax, %eax
+	ret
+
+.globl	_gotolabel
+.type	_gotolabel,@function
+
+_gotolabel:
+	movl	4(%esp), %edx
+	movl	0(%edx), %ecx
+	movl	4(%edx), %ebx
+	movl	8(%edx), %esp
+	movl	12(%edx), %ebp
+	movl	16(%edx), %esi
+	movl	20(%edx), %edi
+	xorl	%eax, %eax
+	incl	%eax
+	movl	%ecx, 0(%esp)
+	ret
+
+
+# .globl	_xinc
+# _xinc:
+# 	movl 4(%esp), %eax
+# 	lock incl 0(%eax)
+# 	ret
+# 
+# .globl	_xdec
+# _xdec:
+# 	movl 4(%esp), %eax
+# 	lock decl 0(%eax)
+# 	jz iszero
+# 	movl $1, %eax
+# 	ret
+# iszero:
+# 	movl $0, %eax
+# 	ret
+# 
blob - bfffa14d4cf6a2d639605e20c9001b506748d7a7
blob + eb31e99e76c4aaa573b1722395dd610c72d4f1f5
--- src/libthread/exec-unix.c
+++ src/libthread/exec-unix.c
@@ -3,8 +3,8 @@
 #include "threadimpl.h"
 
 static void efork(int[3], int[2], char*, char**);
-void
-threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
+static void
+_threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
 {
 	int pfd[2];
 	int n, pid;
@@ -40,6 +40,8 @@ threadexec(Channel *pidc, int fd[3], char *prog, char 
 		efork(fd, pfd, prog, args);
 		_exit(0);
 	default:
+		if(freeargs)
+			free(args);
 		break;
 	}
 
@@ -69,9 +71,42 @@ Bad:
 }
 
 void
+threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
+{
+	_threadexec(pidc, fd, prog, args, 0);
+}
+
+/*
+ * The &f+1 trick doesn't work on SunOS, so we might 
+ * as well bite the bullet and do this correctly.
+ */
+void
 threadexecl(Channel *pidc, int fd[3], char *f, ...)
 {
-	threadexec(pidc, fd, f, &f+1);
+	char **args, *s;
+	int n;
+	va_list arg;
+
+	va_start(arg, f);
+	for(n=0; va_arg(arg, char*) != 0; n++)
+		;
+	n++;
+	va_end(arg);
+
+	args = malloc(n*sizeof(args[0]));
+	if(args == nil){
+		if(pidc)
+			sendul(pidc, ~0);
+		return;
+	}
+
+	va_start(arg, f);
+	for(n=0; (s=va_arg(arg, char*)) != 0; n++)
+		args[n] = s;
+	args[n] = 0;
+	va_end(arg);
+
+	_threadexec(pidc, fd, f, args, 1);
 }
 
 static void
blob - 874fb070f5239dbf1aa1a3b58c149fe0948fc067
blob + 5161e3738095cabb3968ccd220ca0966bc6439a0
--- src/libthread/label.h
+++ src/libthread/label.h
@@ -7,7 +7,7 @@
 typedef struct Label Label;
 #define LABELDPC 0
 
-#if defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__))
+#if defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__) || defined(__OpenBSD__))
 struct Label
 {
 	ulong pc;
blob - 45683608e52ebb5bcf763e113846686d4af82af0
blob + a81246cd7a13b657f64e2d996a9d3708f32885cd
--- src/mkfile
+++ src/mkfile
@@ -1,6 +1,6 @@
 <mkhdr
 
-BUGGERED='9p|html|httpd|ip|venti'
+BUGGERED='9p|fmt|html|httpd|ip|utf|venti'
 LIBDIRS=`ls -ld lib* | sed -n 's/^d.* //p' |egrep -v "^lib($BUGGERED)$"`
 
 DIRS=\