Commit Diff


commit - 5f7d5e8d1899f41b0e5366c0251530ea1dc753d0
commit + b2cfc4e2e71d0f0a5113ddfbd93c8285cc4d74e4
blob - /dev/null
blob + c4812392d35836556ae21c6b5280b36fe50b9404 (mode 644)
--- /dev/null
+++ include/bio.h
@@ -0,0 +1,79 @@
+#ifndef _BIOH_
+#define _BIOH_ 1
+
+#include <sys/types.h>	/* for off_t */
+#include <fcntl.h>	/* for O_RDONLY, O_WRONLY */
+
+typedef	struct	Biobuf	Biobuf;
+
+enum
+{
+	Bsize		= 8*1024,
+	Bungetsize	= 4,		/* space for ungetc */
+	Bmagic		= 0x314159,
+	Beof		= -1,
+	Bbad		= -2,
+
+	Binactive	= 0,		/* states */
+	Bractive,
+	Bwactive,
+	Bracteof,
+
+	Bend
+};
+
+struct	Biobuf
+{
+	int	icount;		/* neg num of bytes at eob */
+	int	ocount;		/* num of bytes at bob */
+	int	rdline;		/* num of bytes after rdline */
+	int	runesize;		/* num of bytes of last getrune */
+	int	state;		/* r/w/inactive */
+	int	fid;		/* open file */
+	int	flag;		/* magic if malloc'ed */
+	off_t	offset;		/* offset of buffer in file */
+	int	bsize;		/* size of buffer */
+	unsigned char*	bbuf;		/* pointer to beginning of buffer */
+	unsigned char*	ebuf;		/* pointer to end of buffer */
+	unsigned char*	gbuf;		/* pointer to good data in buf */
+	unsigned char	b[Bungetsize+Bsize];
+};
+
+#define	BGETC(bp)\
+	((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
+#define	BPUTC(bp,c)\
+	((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
+#define	BOFFSET(bp)\
+	(((bp)->state==Bractive)?\
+		(bp)->offset + (bp)->icount:\
+	(((bp)->state==Bwactive)?\
+		(bp)->offset + ((bp)->bsize + (bp)->ocount):\
+		-1))
+#define	BLINELEN(bp)\
+	(bp)->rdline
+#define	BFILDES(bp)\
+	(bp)->fid
+
+int	Bbuffered(Biobuf*);
+int	Bfildes(Biobuf*);
+int	Bflush(Biobuf*);
+int	Bgetc(Biobuf*);
+int	Bgetd(Biobuf*, double*);
+int	Binit(Biobuf*, int, int);
+int	Binits(Biobuf*, int, int, unsigned char*, int);
+int	Blinelen(Biobuf*);
+off_t	Boffset(Biobuf*);
+Biobuf*	Bopen(char*, int);
+int	Bprint(Biobuf*, char*, ...);
+int	Bputc(Biobuf*, int);
+void*	Brdline(Biobuf*, int);
+long	Bread(Biobuf*, void*, long);
+off_t	Bseek(Biobuf*, off_t, int);
+int	Bterm(Biobuf*);
+int	Bungetc(Biobuf*);
+long	Bwrite(Biobuf*, void*, long);
+char*	Brdstr(Biobuf*, int, int);
+long	Bgetrune(Biobuf*);
+int	Bputrune(Biobuf*, long);
+
+#endif
blob - /dev/null
blob + 105cd0eff35c958b0902dcb709204b40d9e85bc8 (mode 644)
--- /dev/null
+++ include/cursor.h
@@ -0,0 +1,7 @@
+typedef struct Cursor Cursor;
+struct	Cursor
+{
+	Point	offset;
+	uchar	clr[2*16];
+	uchar	set[2*16];
+};
blob - /dev/null
blob + 0f9ba63aeb6e1f2ad3539c8e3e304583266af299 (mode 644)
--- /dev/null
+++ include/draw.h
@@ -0,0 +1,520 @@
+typedef struct	Cachefont Cachefont;
+typedef struct	Cacheinfo Cacheinfo;
+typedef struct	Cachesubf Cachesubf;
+typedef struct	Display Display;
+typedef struct	Font Font;
+typedef struct	Fontchar Fontchar;
+typedef struct	Image Image;
+typedef struct	Mouse Mouse;
+typedef struct	Point Point;
+typedef struct	Rectangle Rectangle;
+typedef struct	RGB RGB;
+typedef struct	Screen Screen;
+typedef struct	Subfont Subfont;
+
+extern	int	Rfmt(Fmt*);
+extern	int	Pfmt(Fmt*);
+
+enum
+{
+	DOpaque		= 0xFFFFFFFF,
+	DTransparent	= 0x00000000,		/* only useful for allocimage, memfillcolor */
+	DBlack		= 0x000000FF,
+	DWhite		= 0xFFFFFFFF,
+	DRed		= 0xFF0000FF,
+	DGreen		= 0x00FF00FF,
+	DBlue		= 0x0000FFFF,
+	DCyan		= 0x00FFFFFF,
+	DMagenta		= 0xFF00FFFF,
+	DYellow		= 0xFFFF00FF,
+	DPaleyellow	= 0xFFFFAAFF,
+	DDarkyellow	= 0xEEEE9EFF,
+	DDarkgreen	= 0x448844FF,
+	DPalegreen	= 0xAAFFAAFF,
+	DMedgreen	= 0x88CC88FF,
+	DDarkblue	= 0x000055FF,
+	DPalebluegreen= 0xAAFFFFFF,
+	DPaleblue		= 0x0000BBFF,
+	DBluegreen	= 0x008888FF,
+	DGreygreen	= 0x55AAAAFF,
+	DPalegreygreen	= 0x9EEEEEFF,
+	DYellowgreen	= 0x99994CFF,
+	DMedblue		= 0x000099FF,
+	DGreyblue	= 0x005DBBFF,
+	DPalegreyblue	= 0x4993DDFF,
+	DPurpleblue	= 0x8888CCFF,
+
+	DNotacolor	= 0xFFFFFF00,
+	DNofill		= DNotacolor,
+	
+};
+
+enum
+{
+	Displaybufsize	= 8000,
+	ICOSSCALE	= 1024,
+	Borderwidth =	4,
+};
+
+enum
+{
+	/* refresh methods */
+	Refbackup	= 0,
+	Refnone		= 1,
+	Refmesg		= 2
+};
+#define	NOREFRESH	((void*)-1)
+
+enum
+{
+	/* line ends */
+	Endsquare	= 0,
+	Enddisc		= 1,
+	Endarrow	= 2,
+	Endmask		= 0x1F
+};
+
+#define	ARROW(a, b, c)	(Endarrow|((a)<<5)|((b)<<14)|((c)<<23))
+
+typedef enum
+{
+	/* Porter-Duff compositing operators */
+	Clear	= 0,
+
+	SinD	= 8,
+	DinS	= 4,
+	SoutD	= 2,
+	DoutS	= 1,
+
+	S		= SinD|SoutD,
+	SoverD	= SinD|SoutD|DoutS,
+	SatopD	= SinD|DoutS,
+	SxorD	= SoutD|DoutS,
+
+	D		= DinS|DoutS,
+	DoverS	= DinS|DoutS|SoutD,
+	DatopS	= DinS|SoutD,
+	DxorS	= DoutS|SoutD,	/* == SxorD */
+
+	Ncomp = 12,
+} Drawop;
+
+/*
+ * image channel descriptors 
+ */
+enum {
+	CRed = 0,
+	CGreen,
+	CBlue,
+	CGrey,
+	CAlpha,
+	CMap,
+	CIgnore,
+	NChan,
+};
+
+#define __DC(type, nbits)	((((type)&15)<<4)|((nbits)&15))
+#define CHAN1(a,b)	__DC(a,b)
+#define CHAN2(a,b,c,d)	(CHAN1((a),(b))<<8|__DC((c),(d)))
+#define CHAN3(a,b,c,d,e,f)	(CHAN2((a),(b),(c),(d))<<8|__DC((e),(f)))
+#define CHAN4(a,b,c,d,e,f,g,h)	(CHAN3((a),(b),(c),(d),(e),(f))<<8|__DC((g),(h)))
+
+#define NBITS(c) ((c)&15)
+#define TYPE(c) (((c)>>4)&15)
+
+enum {
+	GREY1	= CHAN1(CGrey, 1),
+	GREY2	= CHAN1(CGrey, 2),
+	GREY4	= CHAN1(CGrey, 4),
+	GREY8	= CHAN1(CGrey, 8),
+	CMAP8	= CHAN1(CMap, 8),
+	RGB15	= CHAN4(CIgnore, 1, CRed, 5, CGreen, 5, CBlue, 5),
+	RGB16	= CHAN3(CRed, 5, CGreen, 6, CBlue, 5),
+	RGB24	= CHAN3(CRed, 8, CGreen, 8, CBlue, 8),
+	BGR24	= CHAN3(CBlue, 8, CGreen, 8, CRed, 8),
+	RGBA32	= CHAN4(CRed, 8, CGreen, 8, CBlue, 8, CAlpha, 8),
+	ARGB32	= CHAN4(CAlpha, 8, CRed, 8, CGreen, 8, CBlue, 8),	/* stupid VGAs */
+	XRGB32  = CHAN4(CIgnore, 8, CRed, 8, CGreen, 8, CBlue, 8),
+	XBGR32  = CHAN4(CIgnore, 8, CBlue, 8, CGreen, 8, CRed, 8),
+};
+
+extern	char*	chantostr(char*, u32int);
+extern	u32int	strtochan(char*);
+extern	int		chantodepth(u32int);
+
+struct	Point
+{
+	int	x;
+	int	y;
+};
+
+struct Rectangle
+{
+	Point	min;
+	Point	max;
+};
+
+typedef void	(*Reffn)(Image*, Rectangle, void*);
+
+struct Screen
+{
+	Display	*display;	/* display holding data */
+	int	id;		/* id of system-held Screen */
+	Image	*image;		/* unused; for reference only */
+	Image	*fill;		/* color to paint behind windows */
+};
+
+struct Display
+{
+	QLock		qlock;
+	int		locking;	/*program is using lockdisplay */
+	int		dirno;
+	int		imageid;
+	int		local;
+	void		(*error)(Display*, char*);
+	char		*devdir;
+	char		*windir;
+	char		oldlabel[64];
+	u32int		dataqid;
+	Image		*image;
+	Image		*white;
+	Image		*black;
+	Image		*opaque;
+	Image		*transparent;
+	uchar		*buf;
+	int		bufsize;
+	uchar		*bufp;
+	uchar		*obuf;
+	int		obufsize;
+	uchar		*obufp;
+	Font		*defaultfont;
+	Subfont		*defaultsubfont;
+	Image		*windows;
+	Image		*screenimage;
+	int		_isnewdisplay;
+};
+
+struct Image
+{
+	Display		*display;	/* display holding data */
+	int		id;		/* id of system-held Image */
+	Rectangle	r;		/* rectangle in data area, local coords */
+	Rectangle 	clipr;		/* clipping region */
+	int		depth;		/* number of bits per pixel */
+	u32int	chan;
+	int		repl;		/* flag: data replicates to tile clipr */
+	Screen		*screen;	/* 0 if not a window */
+	Image		*next;	/* next in list of windows */
+};
+
+struct RGB
+{
+	u32int	red;
+	u32int	green;
+	u32int	blue;
+};
+
+/*
+ * Subfonts
+ *
+ * given char c, Subfont *f, Fontchar *i, and Point p, one says
+ *	i = f->info+c;
+ *	draw(b, Rect(p.x+i->left, p.y+i->top,
+ *		p.x+i->left+((i+1)->x-i->x), p.y+i->bottom),
+ *		color, f->bits, Pt(i->x, i->top));
+ *	p.x += i->width;
+ * to draw characters in the specified color (itself an Image) in Image b.
+ */
+
+struct	Fontchar
+{
+	int		x;		/* left edge of bits */
+	uchar		top;		/* first non-zero scan-line */
+	uchar		bottom;		/* last non-zero scan-line + 1 */
+	char		left;		/* offset of baseline */
+	uchar		width;		/* width of baseline */
+};
+
+struct	Subfont
+{
+	char		*name;
+	short		n;		/* number of chars in font */
+	uchar		height;		/* height of image */
+	char		ascent;		/* top of image to baseline */
+	Fontchar 	*info;		/* n+1 character descriptors */
+	Image		*bits;		/* of font */
+	int		ref;
+};
+
+enum
+{
+	/* starting values */
+	LOG2NFCACHE =	6,
+	NFCACHE =	(1<<LOG2NFCACHE),	/* #chars cached */
+	NFLOOK =	5,			/* #chars to scan in cache */
+	NFSUBF =	2,			/* #subfonts to cache */
+	/* max value */
+	MAXFCACHE =	1024+NFLOOK,		/* upper limit */
+	MAXSUBF =	50,			/* generous upper limit */
+	/* deltas */
+	DSUBF = 	4,
+	/* expiry ages */
+	SUBFAGE	=	10000,
+	CACHEAGE =	10000
+};
+
+struct Cachefont
+{
+	Rune		min;	/* lowest rune value to be taken from subfont */
+	Rune		max;	/* highest rune value+1 to be taken from subfont */
+	int		offset;	/* position in subfont of character at min */
+	char		*name;			/* stored in font */
+	char		*subfontname;		/* to access subfont */
+};
+
+struct Cacheinfo
+{
+	ushort		x;		/* left edge of bits */
+	uchar		width;		/* width of baseline */
+	schar		left;		/* offset of baseline */
+	Rune		value;	/* value of character at this slot in cache */
+	ushort		age;
+};
+
+struct Cachesubf
+{
+	u32int		age;	/* for replacement */
+	Cachefont	*cf;	/* font info that owns us */
+	Subfont		*f;	/* attached subfont */
+};
+
+struct Font
+{
+	char		*name;
+	Display		*display;
+	short		height;	/* max height of image, interline spacing */
+	short		ascent;	/* top of image to baseline */
+	short		width;	/* widest so far; used in caching only */	
+	short		nsub;	/* number of subfonts */
+	u32int		age;	/* increasing counter; used for LRU */
+	int		maxdepth;	/* maximum depth of all loaded subfonts */
+	int		ncache;	/* size of cache */
+	int		nsubf;	/* size of subfont list */
+	Cacheinfo	*cache;
+	Cachesubf	*subf;
+	Cachefont	**sub;	/* as read from file */
+	Image		*cacheimage;
+};
+
+#define	Dx(r)	((r).max.x-(r).min.x)
+#define	Dy(r)	((r).max.y-(r).min.y)
+
+/*
+ * Image management
+ */
+extern Image*	_allocimage(Image*, Display*, Rectangle, u32int, int, u32int, int, int);
+extern Image*	allocimage(Display*, Rectangle, u32int, int, u32int);
+extern uchar*	bufimage(Display*, int);
+extern int	bytesperline(Rectangle, int);
+extern void	closedisplay(Display*);
+extern void	drawerror(Display*, char*);
+extern int	flushimage(Display*, int);
+extern int	freeimage(Image*);
+extern int	_freeimage1(Image*);
+extern int	geninitdraw(char*, void(*)(Display*, char*), char*, char*, char*, int);
+extern int	initdraw(void(*)(Display*, char*), char*, char*);
+extern int	newwindow(char*);
+extern int	loadimage(Image*, Rectangle, uchar*, int);
+extern int	cloadimage(Image*, Rectangle, uchar*, int);
+extern int	getwindow(Display*, int);
+extern int	gengetwindow(Display*, char*, Image**, Screen**, int);
+extern Image* readimage(Display*, int, int);
+extern Image* creadimage(Display*, int, int);
+extern int	unloadimage(Image*, Rectangle, uchar*, int);
+extern int	wordsperline(Rectangle, int);
+extern int	writeimage(int, Image*, int);
+extern Image*	namedimage(Display*, char*);
+extern int	nameimage(Image*, char*, int);
+extern Image* allocimagemix(Display*, u32int, u32int);
+
+/*
+ * Colors
+ */
+extern	void	readcolmap(Display*, RGB*);
+extern	void	writecolmap(Display*, RGB*);
+extern	u32int	setalpha(u32int, uchar);
+
+/*
+ * Windows
+ */
+extern Screen*	allocscreen(Image*, Image*, int);
+extern Image*	_allocwindow(Image*, Screen*, Rectangle, int, u32int);
+extern Image*	allocwindow(Screen*, Rectangle, int, u32int);
+extern void	bottomnwindows(Image**, int);
+extern void	bottomwindow(Image*);
+extern int	freescreen(Screen*);
+extern Screen*	publicscreen(Display*, int, u32int);
+extern void	topnwindows(Image**, int);
+extern void	topwindow(Image*);
+extern int	originwindow(Image*, Point, Point);
+
+/*
+ * Geometry
+ */
+extern Point		Pt(int, int);
+extern Rectangle	Rect(int, int, int, int);
+extern Rectangle	Rpt(Point, Point);
+extern Point		addpt(Point, Point);
+extern Point		subpt(Point, Point);
+extern Point		divpt(Point, int);
+extern Point		mulpt(Point, int);
+extern int		eqpt(Point, Point);
+extern int		eqrect(Rectangle, Rectangle);
+extern Rectangle	insetrect(Rectangle, int);
+extern Rectangle	rectaddpt(Rectangle, Point);
+extern Rectangle	rectsubpt(Rectangle, Point);
+extern Rectangle	canonrect(Rectangle);
+extern int		rectXrect(Rectangle, Rectangle);
+extern int		rectinrect(Rectangle, Rectangle);
+extern void		combinerect(Rectangle*, Rectangle);
+extern int		rectclip(Rectangle*, Rectangle);
+extern int		ptinrect(Point, Rectangle);
+extern void		replclipr(Image*, int, Rectangle);
+extern int		drawreplxy(int, int, int);	/* used to be drawsetxy */
+extern Point	drawrepl(Rectangle, Point);
+extern int		rgb2cmap(int, int, int);
+extern int		cmap2rgb(int);
+extern int		cmap2rgba(int);
+extern void		icossin(int, int*, int*);
+extern void		icossin2(int, int, int*, int*);
+
+/*
+ * Graphics
+ */
+extern void	draw(Image*, Rectangle, Image*, Image*, Point);
+extern void	drawop(Image*, Rectangle, Image*, Image*, Point, Drawop);
+extern void	gendraw(Image*, Rectangle, Image*, Point, Image*, Point);
+extern void	gendrawop(Image*, Rectangle, Image*, Point, Image*, Point, Drawop);
+extern void	line(Image*, Point, Point, int, int, int, Image*, Point);
+extern void	lineop(Image*, Point, Point, int, int, int, Image*, Point, Drawop);
+extern void	poly(Image*, Point*, int, int, int, int, Image*, Point);
+extern void	polyop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
+extern void	fillpoly(Image*, Point*, int, int, Image*, Point);
+extern void	fillpolyop(Image*, Point*, int, int, Image*, Point, Drawop);
+extern Point	string(Image*, Point, Image*, Point, Font*, char*);
+extern Point	stringop(Image*, Point, Image*, Point, Font*, char*, Drawop);
+extern Point	stringn(Image*, Point, Image*, Point, Font*, char*, int);
+extern Point	stringnop(Image*, Point, Image*, Point, Font*, char*, int, Drawop);
+extern Point	runestring(Image*, Point, Image*, Point, Font*, Rune*);
+extern Point	runestringop(Image*, Point, Image*, Point, Font*, Rune*, Drawop);
+extern Point	runestringn(Image*, Point, Image*, Point, Font*, Rune*, int);
+extern Point	runestringnop(Image*, Point, Image*, Point, Font*, Rune*, int, Drawop);
+extern Point	stringbg(Image*, Point, Image*, Point, Font*, char*, Image*, Point);
+extern Point	stringbgop(Image*, Point, Image*, Point, Font*, char*, Image*, Point, Drawop);
+extern Point	stringnbg(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point);
+extern Point	stringnbgop(Image*, Point, Image*, Point, Font*, char*, int, Image*, Point, Drawop);
+extern Point	runestringbg(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point);
+extern Point	runestringbgop(Image*, Point, Image*, Point, Font*, Rune*, Image*, Point, Drawop);
+extern Point	runestringnbg(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point);
+extern Point	runestringnbgop(Image*, Point, Image*, Point, Font*, Rune*, int, Image*, Point, Drawop);
+extern Point	_string(Image*, Point, Image*, Point, Font*, char*, Rune*, int, Rectangle, Image*, Point, Drawop);
+extern Point	stringsubfont(Image*, Point, Image*, Subfont*, char*);
+extern int		bezier(Image*, Point, Point, Point, Point, int, int, int, Image*, Point);
+extern int		bezierop(Image*, Point, Point, Point, Point, int, int, int, Image*, Point, Drawop);
+extern int		bezspline(Image*, Point*, int, int, int, int, Image*, Point);
+extern int		bezsplineop(Image*, Point*, int, int, int, int, Image*, Point, Drawop);
+extern int		bezsplinepts(Point*, int, Point**);
+extern int		fillbezier(Image*, Point, Point, Point, Point, int, Image*, Point);
+extern int		fillbezierop(Image*, Point, Point, Point, Point, int, Image*, Point, Drawop);
+extern int		fillbezspline(Image*, Point*, int, int, Image*, Point);
+extern int		fillbezsplineop(Image*, Point*, int, int, Image*, Point, Drawop);
+extern void	ellipse(Image*, Point, int, int, int, Image*, Point);
+extern void	ellipseop(Image*, Point, int, int, int, Image*, Point, Drawop);
+extern void	fillellipse(Image*, Point, int, int, Image*, Point);
+extern void	fillellipseop(Image*, Point, int, int, Image*, Point, Drawop);
+extern void	arc(Image*, Point, int, int, int, Image*, Point, int, int);
+extern void	arcop(Image*, Point, int, int, int, Image*, Point, int, int, Drawop);
+extern void	fillarc(Image*, Point, int, int, Image*, Point, int, int);
+extern void	fillarcop(Image*, Point, int, int, Image*, Point, int, int, Drawop);
+extern void	border(Image*, Rectangle, int, Image*, Point);
+extern void	borderop(Image*, Rectangle, int, Image*, Point, Drawop);
+
+/*
+ * Font management
+ */
+extern Font*	openfont(Display*, char*);
+extern Font*	buildfont(Display*, char*, char*);
+extern void	freefont(Font*);
+extern Font*	mkfont(Subfont*, Rune);
+extern int	cachechars(Font*, char**, Rune**, ushort*, int, int*, char**);
+extern void	agefont(Font*);
+extern Subfont*	allocsubfont(char*, int, int, int, Fontchar*, Image*);
+extern Subfont*	lookupsubfont(Display*, char*);
+extern void	installsubfont(char*, Subfont*);
+extern void	uninstallsubfont(Subfont*);
+extern void	freesubfont(Subfont*);
+extern Subfont*	readsubfont(Display*, char*, int, int);
+extern Subfont*	readsubfonti(Display*, char*, int, Image*, int);
+extern int	writesubfont(int, Subfont*);
+extern void	_unpackinfo(Fontchar*, uchar*, int);
+extern Point	stringsize(Font*, char*);
+extern int	stringwidth(Font*, char*);
+extern int	stringnwidth(Font*, char*, int);
+extern Point	runestringsize(Font*, Rune*);
+extern int	runestringwidth(Font*, Rune*);
+extern int	runestringnwidth(Font*, Rune*, int);
+extern Point	strsubfontwidth(Subfont*, char*);
+extern int	loadchar(Font*, Rune, Cacheinfo*, int, int, char**);
+extern char*	subfontname(char*, char*, int);
+extern Subfont*	_getsubfont(Display*, char*);
+extern Subfont*	getdefont(Display*);
+extern void		lockdisplay(Display*);
+extern void	unlockdisplay(Display*);
+extern int		drawlsetrefresh(u32int, int, void*, void*);
+
+/*
+ * Predefined 
+ */
+extern	uchar	defontdata[];
+extern	int		sizeofdefont;
+extern	Point		ZP;
+extern	Rectangle	ZR;
+
+/*
+ * Set up by initdraw()
+ */
+extern	Display	*display;
+extern	Font		*font;
+extern	Image	*screen;
+extern	Screen	*_screen;
+extern	int	_cursorfd;
+extern	int	_drawdebug;	/* set to 1 to see errors from flushimage */
+extern	void	_setdrawop(Display*, Drawop);
+extern	Display	*_initdisplay(void(*)(Display*,char*), char*);
+
+#define	BGSHORT(p)		(((p)[0]<<0) | ((p)[1]<<8))
+#define	BGLONG(p)		((BGSHORT(p)<<0) | (BGSHORT(p+2)<<16))
+#define	BPSHORT(p, v)		((p)[0]=(v), (p)[1]=((v)>>8))
+#define	BPLONG(p, v)		(BPSHORT(p, (v)), BPSHORT(p+2, (v)>>16))
+
+/*
+ * Compressed image file parameters and helper routines
+ */
+#define	NMATCH	3		/* shortest match possible */
+#define	NRUN	(NMATCH+31)	/* longest match possible */
+#define	NMEM	1024		/* window size */
+#define	NDUMP	128		/* maximum length of dump */
+#define	NCBLOCK	6000		/* size of compressed blocks */
+extern	void	_twiddlecompressed(uchar*, int);
+extern	int	_compblocksize(Rectangle, int);
+
+/* XXX backwards helps; should go */
+extern	int		log2[];
+extern	u32int	drawld2chan[];
+extern	void		drawsetdebug(int);
+
+/*
+ * Port magic.
+ */
+int	_drawmsgread(Display*, void*, int);
+int	_drawmsgwrite(Display*, void*, int);
blob - /dev/null
blob + e74183d4efedcfd33146569a3ff2c28bf5523e66 (mode 644)
--- /dev/null
+++ include/event.h
@@ -0,0 +1,63 @@
+typedef struct	Event Event;
+typedef struct	Menu Menu;
+
+enum
+{
+	Emouse		= 1,
+	Ekeyboard	= 2,
+};
+
+enum
+{
+	MAXSLAVE = 32,
+	EMAXMSG = 128+8192,	/* size of 9p header+data */
+};
+
+struct	Mouse
+{
+	int	buttons;	/* bit array: LMR=124 */
+	Point	xy;
+	ulong	msec;
+};
+
+struct	Event
+{
+	int	kbdc;
+	Mouse	mouse;
+	int	n;		/* number of characters in message */
+	void	*v;		/* data unpacked by general event-handling function */
+	uchar	data[EMAXMSG];	/* message from an arbitrary file descriptor */
+};
+
+struct Menu
+{
+	char	**item;
+	char	*(*gen)(int);
+	int	lasthit;
+};
+
+/*
+ * Events
+ */
+extern void	 einit(ulong);
+extern ulong	 estart(ulong, int, int);
+extern ulong	 estartfn(ulong, int, int, int (*fn)(int, Event*, uchar*, int));
+extern ulong	 etimer(ulong, int);
+extern ulong	 event(Event*);
+extern ulong	 eread(ulong, Event*);
+extern Mouse	 emouse(void);
+extern int	 ekbd(void);
+extern int	 ecanread(ulong);
+extern int	 ecanmouse(void);
+extern int	 ecankbd(void);
+extern void	 eresized(int);	/* supplied by user */
+extern int	 emenuhit(int, Mouse*, Menu*);
+extern int	eatomouse(Mouse*, char*, int);
+extern Rectangle	getrect(int, Mouse*);
+struct Cursor;
+extern void	 esetcursor(struct Cursor*);
+extern void	 emoveto(Point);
+extern Rectangle	egetrect(int, Mouse*);
+extern void		edrawgetrect(Rectangle, int);
+extern int		ereadmouse(Mouse*);
+extern int		eatomouse(Mouse*, char*, int);
blob - /dev/null
blob + c913e14a05887a86a8973cd7fff02f3cde9a100f (mode 644)
--- /dev/null
+++ include/fmt.h
@@ -0,0 +1,100 @@
+
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#ifndef _FMTH_
+#define _FMTH_ 1
+
+#include <stdarg.h>
+
+#ifndef _UTFH_
+#include <utf.h>
+#endif
+
+typedef struct Fmt	Fmt;
+struct Fmt{
+	unsigned char	runes;		/* output buffer is runes or chars? */
+	void	*start;			/* of buffer */
+	void	*to;			/* current place in the buffer */
+	void	*stop;			/* end of the buffer; overwritten if flush fails */
+	int	(*flush)(Fmt *);	/* called when to == stop */
+	void	*farg;			/* to make flush a closure */
+	int	nfmt;			/* num chars formatted so far */
+	va_list	args;			/* args passed to dofmt */
+	int	r;			/* % format Rune */
+	int	width;
+	int	prec;
+	unsigned long	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,
+	FmtLDouble	= FmtByte << 1,
+
+	FmtFlag		= FmtLDouble << 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	int	quotestrfmt(Fmt *f);
+extern	void	quotefmtinstall(void);
+extern	int	(*fmtdoquote)(int);
+
+
+extern	int	fmtinstall(int, int (*)(Fmt*));
+extern	int	dofmt(Fmt*, char*);
+extern	int	fmtprint(Fmt*, char*, ...);
+extern	int	fmtvprint(Fmt*, char*, va_list);
+extern	int	fmtrune(Fmt*, int);
+extern	int	fmtstrcpy(Fmt*, char*);
+
+extern	double	fmtstrtod(const char *, char **);
+extern	double	fmtcharstod(int(*)(void*), void*);
+
+#endif
blob - /dev/null
blob + 9b8194b726b72bc69995dffd0600cc342f41ccf5 (mode 644)
--- /dev/null
+++ include/frame.h
@@ -0,0 +1,85 @@
+typedef struct Frbox Frbox;
+typedef struct Frame Frame;
+
+enum{
+	BACK,
+	HIGH,
+	BORD,
+	TEXT,
+	HTEXT,
+	NCOL
+};
+
+#define	FRTICKW	3
+
+struct Frbox
+{
+	long		wid;		/* in pixels */
+	long		nrune;		/* <0 ==> negate and treat as break char */
+	uchar	*ptr;
+	short	bc;	/* break char */
+	short	minwid;
+};
+
+struct Frame
+{
+	Font		*font;		/* of chars in the frame */
+	Display		*display;	/* on which frame appears */
+	Image		*b;		/* on which frame appears */
+	Image		*cols[NCOL];	/* text and background colors */
+	Rectangle	r;		/* in which text appears */
+	Rectangle	entire;		/* of full frame */
+	void			(*scroll)(Frame*, int);	/* scroll function provided by application */
+	Frbox		*box;
+	ulong		p0, p1;		/* selection */
+	ushort		nbox, nalloc;
+	ushort		maxtab;		/* max size of tab, in pixels */
+	ushort		nchars;		/* # runes in frame */
+	ushort		nlines;		/* # lines with text */
+	ushort		maxlines;	/* total # lines in frame */
+	ushort		lastlinefull;	/* last line fills frame */
+	ushort		modified;	/* changed since frselect() */
+	Image		*tick;	/* typing tick */
+	Image		*tickback;	/* saved image under tick */
+	int			ticked;	/* flag: is tick onscreen? */
+};
+
+ulong	frcharofpt(Frame*, Point);
+Point	frptofchar(Frame*, ulong);
+int	frdelete(Frame*, ulong, ulong);
+void	frinsert(Frame*, Rune*, Rune*, ulong);
+void	frselect(Frame*, Mousectl*);
+void	frselectpaint(Frame*, Point, Point, Image*);
+void	frdrawsel(Frame*, Point, ulong, ulong, int);
+void	frdrawsel0(Frame*, Point, ulong, ulong, Image*, Image*);
+void	frinit(Frame*, Rectangle, Font*, Image*, Image**);
+void	frsetrects(Frame*, Rectangle, Image*);
+void	frclear(Frame*, int);
+
+uchar	*_frallocstr(Frame*, unsigned);
+void	_frinsure(Frame*, int, unsigned);
+Point	_frdraw(Frame*, Point);
+void	_frgrowbox(Frame*, int);
+void	_frfreebox(Frame*, int, int);
+void	_frmergebox(Frame*, int);
+void	_frdelbox(Frame*, int, int);
+void	_frsplitbox(Frame*, int, int);
+int	_frfindbox(Frame*, int, ulong, ulong);
+void	_frclosebox(Frame*, int, int);
+int	_frcanfit(Frame*, Point, Frbox*);
+void	_frcklinewrap(Frame*, Point*, Frbox*);
+void	_frcklinewrap0(Frame*, Point*, Frbox*);
+void	_fradvance(Frame*, Point*, Frbox*);
+int	_frnewwid(Frame*, Point, Frbox*);
+int	_frnewwid0(Frame*, Point, Frbox*);
+void	_frclean(Frame*, Point, int, int);
+void	_frredraw(Frame*, Point);
+void	_fraddbox(Frame*, int, int);
+Point	_frptofcharptb(Frame*, ulong, Point, int);
+Point	_frptofcharnb(Frame*, ulong, int);
+int	_frstrlen(Frame*, int);
+void	frtick(Frame*, Point, int);
+void	frinittick(Frame*);
+
+#define	NRUNE(b)	((b)->nrune<0? 1 : (b)->nrune)
+#define	NBYTE(b)	strlen((char*)(b)->ptr)
blob - /dev/null
blob + a6d99bf6ae3e6493068236a86f34507074fbd9ea (mode 644)
--- /dev/null
+++ include/keyboard.h
@@ -0,0 +1,36 @@
+typedef struct 	Keyboardctl Keyboardctl;
+
+struct	Keyboardctl
+{
+	struct Channel	*c;	/* chan(Rune)[20] */
+
+	char		*file;
+	int		consfd;		/* to cons file */
+	int		ctlfd;		/* to ctl file */
+	int		pid;		/* of slave proc */
+};
+
+
+extern	Keyboardctl*	initkeyboard(char*);
+extern	int			ctlkeyboard(Keyboardctl*, char*);
+extern	void			closekeyboard(Keyboardctl*);
+
+enum {
+	KF=	0xF000,	/* Rune: beginning of private Unicode space */
+	/* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
+	Khome=	KF|0x0D,
+	Kup=	KF|0x0E,
+	Kpgup=	KF|0x0F,
+	Kprint=	KF|0x10,
+	Kleft=	KF|0x11,
+	Kright=	KF|0x12,
+	Kdown=	0x80,
+	Kview=	0x80,
+	Kpgdown=	KF|0x13,
+	Kins=	KF|0x14,
+	Kend=	'\r',	/* [sic] */
+
+	Kalt=		KF|0x15,
+	Kshift=	KF|0x16,
+	Kctl=		KF|0x17,
+};
blob - /dev/null
blob + dd6244844e1252e3fd7afc531762e58bf569cff5 (mode 644)
--- /dev/null
+++ include/lib9.h
@@ -0,0 +1,254 @@
+/*
+ * 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 _LIB9H_
+#define _LIB9H_ 1
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+                                                                                
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <setjmp.h>
+
+#ifndef _FMTH_
+#	include <fmt.h>
+#endif
+
+#define	nil	((void*)0)
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
+
+#define _NEEDUCHAR 1
+#define _NEEDUSHORT 1
+#define _NEEDUINT 1
+#define _NEEDULONG 1
+
+#if defined(__linux__)
+#	include <sys/types.h>
+#	if defined(__USE_MISC)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#		undef _NEEDULONG
+#	endif
+#endif
+#if defined(__FreeBSD__)
+#	include <sys/types.h>
+#	if !defined(_POSIX_SOURCE)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#	endif
+#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;
+
+/* rfork to create new process running fn(arg) */
+
+#if defined(__FreeBSD__)
+#undef RFFDG
+#undef RFNOTEG
+#undef RFPROC
+#undef RFMEM
+#undef RFNOWAIT
+#undef RFCFDG
+#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*);
+
+/* wait for processes */
+#define wait _p9wait
+typedef struct Waitmsg Waitmsg;
+struct Waitmsg
+{
+	int pid;	/* of loved one */
+	ulong time[3];	/* of loved one & descendants */
+	char	*msg;
+};
+extern	int		await(char*, int);
+extern	Waitmsg*	wait(void);
+
+/* synchronization */
+typedef struct Lock Lock;
+struct Lock
+{
+	int val;
+};
+
+extern int		_tas(void*);
+extern void	lock(Lock*);
+extern void	unlock(Lock*);
+extern int		canlock(Lock*);
+
+typedef struct QLp QLp;
+struct QLp
+{
+	int		inuse;
+	QLp		*next;
+	int		state;
+};
+
+typedef struct QLock QLock;
+struct QLock
+{
+	Lock	lock;
+	int		locked;
+	QLp		*head;
+	QLp		*tail;
+};
+
+extern void	qlock(QLock*);
+extern void	qunlock(QLock*);
+extern int		canqlock(QLock*);
+extern void	_qlockinit(ulong (*)(ulong, ulong));
+
+typedef struct RWLock RWLock;
+struct RWLock
+{
+	Lock	lock;
+	int		readers;
+	int		writer;
+	QLp		*head;
+	QLp		*tail;
+};
+
+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 Rendez;
+struct Rendez
+{
+	QLock	*l;
+	QLp		*head;
+	QLp		*tail;
+};
+
+extern void	rsleep(Rendez*);
+extern int		rwakeup(Rendez*);
+extern int		rwakeupall(Rendez*);
+
+extern ulong	rendezvous(ulong, ulong);
+
+/* one of a kind */
+extern void	sysfatal(char*, ...);
+extern int		nrand(int);
+extern void	setmalloctag(void*, ulong);
+extern void	setrealloctag(void*, ulong);
+extern void	*mallocz(ulong, int);
+extern long	readn(int, void*, long);
+extern void	exits(char*);
+extern void	_exits(char*);
+extern ulong	getcallerpc(void*);
+
+/* string routines */
+extern char*	strecpy(char*, char*, char*);
+extern int		tokenize(char*, char**, int);
+extern int		cistrncmp(char*, char*, int);
+extern int		cistrcmp(char*, char*);
+extern char*	cistrstr(char*, char*);
+extern int		getfields(char*, char**, int, int, char*);
+extern int		gettokens(char *, char **, int, char *);
+
+/* formatting helpers */
+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*);
+
+/* error string */
+enum
+{
+	ERRMAX = 128
+};
+extern void	rerrstr(char*, uint);
+extern void	werrstr(char*, ...);
+extern int		errstr(char*, uint);
+
+/* compiler directives on plan 9 */
+#define	USED(x)	if(x){}else{}
+#define	SET(x)	((x)=0)
+
+/* command line */
+extern char	*argv0;
+#define	ARGBEGIN	for((argv0||(argv0=*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
+
+#define OREAD O_RDONLY
+#define OWRITE O_WRONLY
+#define AEXIST 0
+#define AREAD 4
+#define AWRITE 2
+#define AEXEC 1
+#define ORCLOSE 8
+#define OCEXEC 16
+
+#define dup dup2
+#define exec execv
+#define seek lseek
+#define getwd getcwd
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif	/* _LIB9H_ */
blob - /dev/null
blob + 25b042c12623573843d640fca918fcfe163e2255 (mode 644)
--- /dev/null
+++ include/libc.h
@@ -0,0 +1,2 @@
+#include <lib9.h>
+
blob - /dev/null
blob + f0a0f697523863e3910a405bf6528a9f06aab175 (mode 644)
--- /dev/null
+++ include/mouse.h
@@ -0,0 +1,44 @@
+typedef struct	Menu Menu;
+typedef struct 	Mousectl Mousectl;
+
+struct	Mouse
+{
+	int	buttons;	/* bit array: LMR=124 */
+	Point	xy;
+	ulong	msec;
+};
+
+struct Mousectl
+{
+	Mouse	m;
+	struct Channel	*c;	/* chan(Mouse) */
+	struct Channel	*resizec;	/* chan(int)[2] */
+			/* buffered in case client is waiting for a mouse action before handling resize */
+
+	char		*file;
+	int		mfd;		/* to mouse file */
+	int		cfd;		/* to cursor file */
+	int		pid;		/* of slave proc */
+	Display		*display;
+	/*Image*	image;	/ * of associated window/display */
+};
+
+struct Menu
+{
+	char	**item;
+	char	*(*gen)(int);
+	int	lasthit;
+};
+
+/*
+ * Mouse
+ */
+extern Mousectl*	initmouse(char*, Image*);
+extern void		moveto(Mousectl*, Point);
+extern int			readmouse(Mousectl*);
+extern void		closemouse(Mousectl*);
+struct Cursor;
+extern void		setcursor(Mousectl*, struct Cursor*);
+extern void		drawgetrect(Rectangle, int);
+extern Rectangle	getrect(int, Mousectl*);
+extern int	 		menuhit(int, Mousectl*, Menu*, Screen*);
blob - /dev/null
blob + e25658a35cecf85b926ed607106c792ba6e66613 (mode 644)
--- /dev/null
+++ include/regexp9.h
@@ -0,0 +1,71 @@
+#ifndef _REGEXP9H_
+
+#define _REGEXP9H_ 1
+#include <utf.h>
+
+typedef struct Resub		Resub;
+typedef struct Reclass		Reclass;
+typedef struct Reinst		Reinst;
+typedef struct Reprog		Reprog;
+
+/*
+ *	Sub expression matches
+ */
+struct Resub{
+	union
+	{
+		char *sp;
+		Rune *rsp;
+	}s;
+	union
+	{
+		char *ep;
+		Rune *rep;
+	}e;
+};
+
+/*
+ *	character class, each pair of rune's defines a range
+ */
+struct Reclass{
+	Rune	*end;
+	Rune	spans[64];
+};
+
+/*
+ *	Machine instructions
+ */
+struct Reinst{
+	int	type;
+	union	{
+		Reclass	*cp;		/* class pointer */
+		Rune	r;		/* character */
+		int	subid;		/* sub-expression id for RBRA and LBRA */
+		Reinst	*right;		/* right child of OR */
+	}u1;
+	union {	/* regexp relies on these two being in the same union */
+		Reinst *left;		/* left child of OR */
+		Reinst *next;		/* next instruction for CAT & LBRA */
+	}u2;
+};
+
+/*
+ *	Reprogram definition
+ */
+struct Reprog{
+	Reinst	*startinst;	/* start pc */
+	Reclass	class[16];	/* .data */
+	Reinst	firstinst[5];	/* .text */
+};
+
+extern Reprog	*regcomp(char*);
+extern Reprog	*regcomplit(char*);
+extern Reprog	*regcompnl(char*);
+extern void	regerror(char*);
+extern int	regexec(Reprog*, char*, Resub*, int);
+extern void	regsub(char*, char*, int, Resub*, int);
+
+extern int	rregexec(Reprog*, Rune*, Resub*, int);
+extern void	rregsub(Rune*, Rune*, Resub*, int);
+
+#endif
blob - /dev/null
blob + 10aac284824e67af1bff25a3ed7d25090769550d (mode 644)
--- /dev/null
+++ include/thread.h
@@ -0,0 +1,132 @@
+#ifndef _THREADH_
+#define _THREADH_ 1
+
+/* avoid conflicts with socket library */
+#undef send
+#define send _threadsend
+#undef recv
+#define recv _threadrecv
+
+typedef struct Alt	Alt;
+typedef struct Channel	Channel;
+typedef struct Ref	Ref;
+
+/* Channel structure.  S is the size of the buffer.  For unbuffered channels
+ * s is zero.  v is an array of s values.  If s is zero, v is unused.
+ * f and n represent the state of the queue pointed to by v.
+ */
+
+enum {
+	Nqwds = 2,
+	Nqshift = 5,	// 2log #of bits in long
+	Nqmask =  - 1,
+	Nqbits = (1 << Nqshift) * 2,
+};
+
+struct Channel {
+	int			s;		// Size of the channel (may be zero)
+	unsigned int	f;		// Extraction point (insertion pt: (f + n) % s)
+	unsigned int	n;		// Number of values in the channel
+	int			e;		// Element size
+	int			freed;	// Set when channel is being deleted
+	volatile Alt	**qentry;	// Receivers/senders waiting (malloc)
+	volatile int	nentry;	// # of entries malloc-ed
+	unsigned char		v[1];		// Array of s values in the channel
+};
+
+
+/* Channel operations for alt: */
+typedef enum {
+	CHANEND,
+	CHANSND,
+	CHANRCV,
+	CHANNOP,
+	CHANNOBLK,
+} ChanOp;
+
+struct Alt {
+	Channel	*c;		/* channel */
+	void		*v;		/* pointer to value */
+	ChanOp	op;		/* operation */
+
+	/* the next variables are used internally to alt
+	 * they need not be initialized
+	 */
+	Channel	**tag;	/* pointer to rendez-vous tag */
+	int		entryno;	/* entry number */
+};
+
+struct Ref {
+	long ref;
+};
+
+int		alt(Alt alts[]);
+Channel*	chancreate(int elemsize, int bufsize);
+int		chaninit(Channel *c, int elemsize, int elemcnt);
+void		chanfree(Channel *c);
+int		chanprint(Channel *, char *, ...);
+long		decref(Ref *r);		/* returns 0 iff value is now zero */
+void		incref(Ref *r);
+int		nbrecv(Channel *c, void *v);
+void*		nbrecvp(Channel *c);
+unsigned long		nbrecvul(Channel *c);
+int		nbsend(Channel *c, void *v);
+int		nbsendp(Channel *c, void *v);
+int		nbsendul(Channel *c, unsigned long v);
+int		proccreate(void (*f)(void *arg), void *arg, unsigned int stacksize);
+int		procrfork(void (*f)(void *arg), void *arg, unsigned int stacksize, int flag);
+void**		procdata(void);
+void		procexec(Channel *, char *, char *[]);
+void		procexecl(Channel *, char *, ...);
+int		recv(Channel *c, void *v);
+void*		recvp(Channel *c);
+unsigned long		recvul(Channel *c);
+int		send(Channel *c, void *v);
+int		sendp(Channel *c, void *v);
+int		sendul(Channel *c, unsigned long v);
+int		threadcreate(void (*f)(void *arg), void *arg, unsigned int stacksize);
+void**		threaddata(void);
+void		threadexits(char *);
+void		threadexitsall(char *);
+int		threadgetgrp(void);	/* return thread group of current thread */
+char*		threadgetname(void);
+void		threadint(int);	/* interrupt thread */
+void		threadintgrp(int);	/* interrupt threads in grp */
+void		threadkill(int);	/* kill thread */
+void		threadkillgrp(int);	/* kill threads in group */
+void		threadmain(int argc, char *argv[]);
+void		threadnonotes(void);
+int		threadnotify(int (*f)(void*, char*), int in);
+int		threadid(void);
+int		threadpid(int);
+int		threadsetgrp(int);	/* set thread group, return old */
+void		threadsetname(char *name);
+Channel*	threadwaitchan(void);
+int	tprivalloc(void);
+void	tprivfree(int);
+void	**tprivaddr(int);
+void		yield(void);
+
+long		threadstack(void);
+
+extern	int		mainstacksize;
+
+/* slave I/O processes */
+typedef struct Ioproc Ioproc;
+
+Ioproc*	ioproc(void);
+void		closeioproc(Ioproc*);
+void		iointerrupt(Ioproc*);
+
+int		ioclose(Ioproc*, int);
+int		iodial(Ioproc*, char*, char*, char*, int*);
+int		ioopen(Ioproc*, char*, int);
+long		ioread(Ioproc*, int, void*, long);
+long		ioreadn(Ioproc*, int, void*, long);
+long		iowrite(Ioproc*, int, void*, long);
+int		iosleep(Ioproc*, long);
+
+long		iocall(Ioproc*, long (*)(va_list*), ...);
+void		ioret(Ioproc*, int);
+
+#endif	/* _THREADH_ */
blob - /dev/null
blob + e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 (mode 644)
blob - /dev/null
blob + 623bfda949c012d56e415408716a85fa0ad55004 (mode 644)
--- /dev/null
+++ include/utf.h
@@ -0,0 +1,51 @@
+#ifndef _UTFH_
+#define _UTFH_ 1
+
+typedef unsigned short Rune;	/* 16 bits */
+
+enum
+{
+	UTFmax		= 3,		/* maximum bytes per rune */
+	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
+	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
+	Runeerror	= 0x80,		/* decoding error in UTF */
+};
+
+/*
+ * rune routines
+ */
+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);
+
+#endif
blob - /dev/null
blob + cf504631c819673260b2e20b57d579eeb46c06e0 (mode 644)
--- /dev/null
+++ man/man3/bio.3
@@ -0,0 +1,336 @@
+.TH BIO 3
+.SH NAME
+Bopen, Binit, Binits, Brdline, Brdstr, Bgetc, Bgetd, Bungetc, Bread, Bseek, Boffset, Bfildes, Blinelen, Bputc, Bprint, Bvprint, Bwrite, Bflush, Bterm, Bbuffered \- buffered input/output
+.SH SYNOPSIS
+.ta \w'Biobuf* 'u
+.B #include <fmt.h>
+.B #include <bio.h>
+.PP
+.B
+Biobuf* Bopen(char *file, int mode)
+.PP
+.B
+int	Binit(Biobuf *bp, int fd, int mode)
+.PP
+.B
+int	Bterm(Biobuf *bp)
+.PP
+.B
+int	Bprint(Biobuf *bp, char *format, ...)
+.PP
+.B
+int	Bvprint(Biobuf *bp, char *format, va_list arglist);
+.PP
+.B
+void*	Brdline(Biobuf *bp, int delim)
+.PP
+.B
+char*	Brdstr(Biobuf *bp, int delim, int nulldelim)
+.PP
+.B
+int	Blinelen(Biobuf *bp)
+.PP
+.B
+off_t	Boffset(Biobuf *bp)
+.PP
+.B
+int	Bfildes(Biobuf *bp)
+.PP
+.B
+int	Bgetc(Biobuf *bp)
+.PP
+.B
+long	Bgetrune(Biobufhdr *bp)
+.PP
+.B
+int	Bgetd(Biobuf *bp, double *d)
+.PP
+.B
+int	Bungetc(Biobuf *bp)
+.PP
+.B
+int	Bungetrune(Biobufhdr *bp)
+.PP
+.B
+off_t	Bseek(Biobuf *bp, off_t n, int type)
+.PP
+.B
+int	Bputc(Biobuf *bp, int c)
+.PP
+.B
+int	Bputrune(Biobufhdr *bp, long c)
+.PP
+.B
+long	Bread(Biobuf *bp, void *addr, long nbytes)
+.PP
+.B
+long	Bwrite(Biobuf *bp, void *addr, long nbytes)
+.PP
+.B
+int	Bflush(Biobuf *bp)
+.PP
+.B
+int	Bbuffered(Biobuf *bp)
+.PP
+.SH DESCRIPTION
+These routines implement fast buffered I/O.
+I/O on different file descriptors is independent.
+.PP
+.I Bopen
+opens
+.I file
+for mode
+.B O_RDONLY
+or creates for mode
+.BR O_WRONLY .
+It calls
+.IR malloc (3)
+to allocate a buffer.
+.PP
+.I Binit
+initializes a buffer
+with the open file descriptor passed in
+by the user.
+.PP
+Arguments
+of types pointer to Biobuf and pointer to Biobuf
+can be used interchangeably in the following routines.
+.PP
+.IR Bopen ,
+.IR Binit ,
+or
+.I Binits
+should be called before any of the
+other routines on that buffer.
+.I Bfildes
+returns the integer file descriptor of the associated open file.
+.PP
+.I Bterm
+flushes the buffer for
+.IR bp .
+If the buffer was allocated by
+.IR Bopen ,
+the buffer is
+.I freed
+and the file is closed.
+.PP
+.I Brdline
+reads a string from the file associated with
+.I bp
+up to and including the first
+.I delim
+character.
+The delimiter character at the end of the line is
+not altered.
+.I Brdline
+returns a pointer to the start of the line or
+.L 0
+on end-of-file or read error.
+.I Blinelen
+returns the length (including the delimiter)
+of the most recent string returned by
+.IR Brdline .
+.PP
+.I Brdstr
+returns a
+.IR malloc (3)-allocated
+buffer containing the next line of input delimited by
+.IR delim ,
+terminated by a NUL (0) byte.
+Unlike
+.IR Brdline ,
+which returns when its buffer is full even if no delimiter has been found,
+.I Brdstr
+will return an arbitrarily long line in a single call.
+If
+.I nulldelim
+is set, the terminal delimiter will be overwritten with a NUL.
+After a successful call to
+.IR Brdstr ,
+the return value of
+.I Blinelen
+will be the length of the returned buffer, excluding the NUL.
+.PP
+.I Bgetc
+returns the next byte from
+.IR bp ,
+or a negative value
+at end of file.
+.I Bungetc
+may be called immediately after
+.I Bgetc
+to allow the same byte to be reread.
+.PP
+.I Bgetrune
+calls
+.I Bgetc
+to read the bytes of the next
+.SM UTF
+sequence in the input stream and returns the value of the rune
+represented by the sequence.
+It returns a negative value
+at end of file.
+.I Bungetrune
+may be called immediately after
+.I Bgetrune
+to allow the same
+.SM UTF
+sequence to be reread as either bytes or a rune.
+.I Bungetc
+and
+.I Bungetrune
+may back up a maximum of five bytes.
+.PP
+.I Bgetd
+uses
+.I fmtcharstod
+(undocumented)
+and
+.I Bgetc
+to read the formatted
+floating-point number in the input stream,
+skipping initial blanks and tabs.
+The value is stored in
+.BR *d.
+.PP
+.I Bread
+reads
+.I nbytes
+of data from
+.I bp
+into memory starting at
+.IR addr .
+The number of bytes read is returned on success
+and a negative value is returned if a read error occurred.
+.PP
+.I Bseek
+applies
+.IR lseek (2)
+to
+.IR bp .
+It returns the new file offset.
+.I Boffset
+returns the file offset of the next character to be processed.
+.PP
+.I Bputc
+outputs the low order 8 bits of
+.I c
+on
+.IR bp .
+If this causes a
+.IR write
+to occur and there is an error,
+a negative value is returned.
+Otherwise, a zero is returned.
+.PP
+.I Bputrune
+calls
+.I Bputc
+to output the low order
+16 bits of
+.I c
+as a rune
+in
+.SM UTF
+format
+on the output stream.
+.PP
+.I Bprint
+is a buffered interface to
+.IR print (2).
+If this causes a
+.IR write
+to occur and there is an error,
+a negative value
+.RB ( Beof )
+is returned.
+Otherwise, the number of bytes output is returned.
+.I Bvprint
+does the same except it takes as argument a
+.B va_list
+parameter, so it can be called within a variadic function.
+.PP
+.I Bwrite
+outputs
+.I nbytes
+of data starting at
+.I addr
+to
+.IR bp .
+If this causes a
+.IR write
+to occur and there is an error,
+a negative value is returned.
+Otherwise, the number of bytes written is returned.
+.PP
+.I Bflush
+causes any buffered output associated with
+.I bp
+to be written.
+The return is as for
+.IR Bputc .
+.I Bflush
+is called on
+exit for every buffer still open
+for writing.
+.PP
+.I Bbuffered
+returns the number of bytes in the buffer.
+When reading, this is the number of bytes still available from the last
+read on the file; when writing, it is the number of bytes ready to be
+written.
+.PP
+This library uses
+.IR fmt (3)
+for diagnostic messages about internal errors,
+as well as for the implementation of
+.I Bprint
+and
+.IR Bvprint .
+It uses
+.IR utf (3)
+for the implementation of
+.I Bgetrune
+and
+.IR Bputrune .
+.SH SEE ALSO
+.IR atexit (3).
+.IR open (2),
+.IR print (3),
+.IR utf (7)
+.SH DIAGNOSTICS
+.I Bio
+routines that return integers yield
+.B Beof
+if 
+.I bp
+is not the descriptor of an open file.
+.I Bopen
+returns zero if the file cannot be opened in the given mode.
+.SH HISTORY
+The
+.IR bio (3)
+library originally appeared in Plan 9.
+This is a port of the Plan 9 bio library.
+.SH BUGS
+.I Brdline
+returns an error on strings longer than the buffer associated
+with the file
+and also if the end-of-file is encountered
+before a delimiter.
+.I Blinelen
+will tell how many characters are available
+in these cases.
+In the case of a true end-of-file,
+.I Blinelen
+will return zero.
+At the cost of allocating a buffer,
+.I Brdstr
+sidesteps these issues.
+.PP
+The data returned by
+.I Brdline
+may be overwritten by calls to any other
+.I bio
+routine on the same
+.IR bp.
blob - /dev/null
blob + 2a0e55bf164c92bbf6d34b02105d38e2190fc00f (mode 644)
--- /dev/null
+++ man/man3/fmtinstall.3
@@ -0,0 +1,346 @@
+.TH FMTINSTALL 3
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.SH NAME
+fmtinstall, dofmt, fmtprint, fmtvprint, fmtstrcpy, fmtfdinit, fmtfdflush, fmtstrinit, fmtstrflush \- support for user-defined print formats and output routines
+.SH SYNOPSIS
+.B #include <fmt.h>
+.PP
+.ft L
+.nf
+.ta \w'    'u +\w'    'u +\w'    'u +\w'    'u +\w'    'u
+typedef struct Fmt	Fmt;
+struct Fmt{
+	void	*start;		/* of buffer */
+	void	*to;		/* current place in the buffer */
+	void	*stop;		/* end of the buffer; overwritten if flush fails */
+	int		(*flush)(Fmt*);	/* called when to == stop */
+	void	*farg;		/* to make flush a closure */
+	int		nfmt;		/* num chars formatted so far */
+	va_list	args;		/* args passed to dofmt */
+	int		r;			/* % format character */
+	int		width;
+	int		prec;
+	unsigned long	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,
+	FmtLDouble	= FmtByte << 1,
+
+	FmtFlag		= FmtLDouble << 1
+};
+.fi
+.PP
+.B
+.ta \w'\fLchar* 'u
+
+.PP
+.B
+int	fmtfdinit(Fmt *f, int fd, char *buf, int nbuf);
+.PP
+.B
+int	fmtfdflush(Fmt *f);
+.PP
+.B
+int	fmtstrinit(Fmt *f);
+.PP
+.B
+char*	fmtstrflush(Fmt *f);
+.PP
+.B
+int	fmtinstall(int c, int (*fn)(Fmt*));
+.PP
+.B
+int	dofmt(Fmt *f, char *fmt);
+.PP
+.B
+int	fmtprint(Fmt *f, char *fmt, ...);
+.PP
+.B
+int	fmtvprint(Fmt *f, char *fmt, va_list v);
+.PP
+.B
+int	fmtrune(Fmt *f, int r);
+.PP
+.B
+int	fmtstrcpy(Fmt *f, char *s);
+.SH DESCRIPTION
+The interface described here allows the construction of custom
+.IR print (3)
+verbs and output routines.
+In essence, they provide access to the workings of the formatted print code.
+.PP
+The
+.IR print (3)
+suite maintains its state with a data structure called
+.BR Fmt .
+A typical call to
+.IR print (3)
+or its relatives initializes a
+.B Fmt
+structure, passes it to subsidiary routines to process the output,
+and finishes by emitting any saved state recorded in the
+.BR Fmt .
+The details of the
+.B Fmt
+are unimportant to outside users, except insofar as the general
+design influences the interface.
+The
+.B Fmt
+records
+the verb being processed, its precision and width,
+and buffering parameters.
+Most important, it also records a
+.I flush
+routine that the library will call if a buffer overflows.
+When printing to a file descriptor, the flush routine will
+emit saved characters and reset the buffer; when printing
+to an allocated string, it will resize the string to receive more output.
+The flush routine is nil when printing to fixed-size buffers.
+User code need never provide a flush routine; this is done internally
+by the library.
+.SS Custom output routines
+To write a custom output routine, such as an error handler that
+formats and prints custom error messages, the output sequence can be run
+from outside the library using the routines described here.
+There are two main cases: output to an open file descriptor
+and output to a string.
+.PP
+To write to a file descriptor, call
+.I fmtfdinit
+to initialize the local
+.B Fmt
+structure
+.IR f ,
+giving the file descriptor
+.IR fd ,
+the buffer
+.IR buf ,
+and its size
+.IR nbuf .
+Then call
+.IR fmtprint
+or
+.IR fmtvprint
+to generate the output.
+These behave just like
+.B fprint
+(see
+.IR print (3))
+or
+.B vfprint
+except that the characters are buffered until
+.I fmtfdflush
+is called.
+A typical example of this sequence appears in the Examples section.
+.PP
+The same basic sequence applies when outputting to an allocated string:
+call
+.I fmtstrinit
+to initialize the
+.BR Fmt ,
+then call
+.I fmtprint
+and
+.I fmtvprint
+to generate the output.
+Finally,
+.I fmtstrflush
+will return the allocated string, which should be freed after use.
+Regardless of the output style or type,
+.I fmtprint
+or
+.I fmtvprint
+generates the characters.
+.SS Custom format verbs
+.I Fmtinstall
+is used to install custom verbs and flags labeled by character
+.IR c ,
+which may be any non-zero Unicode character.
+.I Fn
+should be declared as
+.IP
+.EX
+int	fn(Fmt*)
+.EE
+.PP
+.IB Fp ->r
+is the flag or verb character to cause
+.I fn
+to be called.
+In
+.IR fn ,
+.IB fp ->width ,
+.IB fp ->prec
+are the width and precision, and
+.IB fp ->flags
+the decoded flags for the verb (see
+.IR print (3)
+for a description of these items).
+The standard flag values are:
+.B FmtSign
+.RB ( + ),
+.B FmtLeft
+.RB ( - ),
+.B FmtSpace
+.RB ( '\ ' ),
+.B FmtSharp
+.RB ( # ),
+.B FmtComma
+.RB ( , ),
+.B FmtLong
+.RB ( l ),
+.B FmtShort
+.RB ( h ),
+.B FmtByte
+.RB ( hh ),
+.B FmtUnsigned
+.RB ( u ),
+.B FmtLDouble
+.RB ( L ),
+and
+.B FmtVLong
+.RB ( ll ).
+The flag bits
+.B FmtWidth
+and
+.B FmtPrec
+identify whether a width and precision were specified.
+.PP
+.I Fn
+is passed a pointer to the
+.B Fmt
+structure recording the state of the output.
+If
+.IB fp ->r
+is a verb (rather than a flag),
+.I fn
+should use 
+.B Fmt->args
+to fetch its argument from the list,
+then format it, and return zero.
+If
+.IB fp ->r
+is a flag,
+.I fn
+should return a negative value:
+the negation of one of the above flag values, or some otherwise unused power of two.
+All interpretation of
+.IB fp ->width\f1,
+.IB fp ->prec\f1,
+and
+.IB fp-> flags
+is left up to the conversion routine.
+.I Fmtinstall
+returns 0 if the installation succeeds, \-1 if it fails.
+.PP
+.IR Fmtprint
+and
+.IR fmtvprint
+may be called to
+help prepare output in custom conversion routines.
+However, these functions clear the width, precision, and flags.
+The function
+.I dofmt
+is the underlying formatter; it
+uses the existing contents of
+.B Fmt
+and should be called only by sophisticated conversion routines.
+All these routines return the number of characters
+produced.
+.PP
+Some internal functions may be useful to format primitive types.
+They honor the width, precision and flags as described in
+.IR print (3).
+.I Fmtrune
+formats a single character
+.BR r .
+.I Fmtstrcpy
+formats a string
+.BR s .
+All these routines return zero for successful execution.
+.SH EXAMPLES
+This function prints an error message with a variable
+number of arguments and then quits.
+Compared to the corresponding example in
+.IR print (3),
+this version uses a smaller buffer, will never truncate
+the output message, but might generate multiple
+.B write
+system calls to produce its output.
+.IP
+.EX
+.ta 6n +6n +6n +6n +6n +6n +6n +6n +6n
+
+void fatal(char *fmt, ...)
+{
+	Fmt f;
+	char buf[64];
+	va_list arg;
+
+	fmtfdinit(&f, 1, buf, sizeof buf);
+	fmtprint(&f, "fatal: ");
+	va_start(arg, fmt);
+	fmtvprint(&f, fmt, arg);
+	va_end(arg);
+	fmtprint(&f, "\en");
+	fmtfdflush(&f);
+	exits("fatal error");
+}
+.EE
+.PP
+This example adds a verb to print complex numbers.
+.IP
+.EX
+typedef
+struct {
+	double	r, i;
+} Complex;
+
+int
+Xfmt(Fmt *f)
+{
+	Complex c;
+
+	c = va_arg(f->args, Complex);
+	return fmtprint(f, "(%g,%g)", c.r, c.i);
+}
+
+main(...)
+{
+	Complex x;
+
+	x.r = 1.5;
+	x.i = -2.3;
+
+	fmtinstall('X', Xfmt);
+	print("x = %X\en", x);
+}
+.EE
+.SH SEE ALSO
+.IR print (3)
+.SH HISTORY
+This formatted print library originally
+appeared as part of the Plan 9 C library.
+.SH BUGS
+The Plan 9 version supports Unicode strings and produces UTF output.
+This version assumes that characters are always represented by 1-byte values.
blob - /dev/null
blob + 1cada2de268c8218fb38b23db5efcb1abd370348 (mode 644)
--- /dev/null
+++ man/man3/ioproc.3
@@ -0,0 +1,179 @@
+.TH IOPROC 2
+.SH NAME
+closeioproc,
+iocall,
+ioclose,
+iointerrupt,
+iodial,
+ioopen,
+ioproc,
+ioread,
+ioreadn,
+iowrite \- slave I/O processes for threaded programs
+.SH SYNOPSIS
+.PP
+.de XX
+.ift .sp 0.5
+.ifn .sp
+..
+.EX
+.ta \w'Ioproc* 'u
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+.sp
+typedef struct Ioproc Ioproc;
+.sp
+Ioproc*	ioproc(void);
+.XX
+int	ioopen(Ioproc *io, char *file, int omode);
+int	ioclose(Ioproc *io, int fd);
+long	ioread(Ioproc *io, int fd, void *a, long n);
+long	ioreadn(Ioproc *io, int fd, void *a, long n);
+long	iowrite(Ioproc *io, int fd, void *a, long n);
+int	iodial(Ioproc *io, char *addr, char *local, char *dir, char *cdfp);
+.XX
+void	iointerrupt(Ioproc *io);
+void	closeioproc(Ioproc *io);
+.XX
+long	iocall(Ioproc *io, long (*op)(va_list *arg), ...);
+.EE
+.SH DESCRIPTION
+.PP
+These routines provide access to I/O in slave procs.
+Since the I/O itself is done in a slave proc, other threads
+in the calling proc can run while the calling thread
+waits for the I/O to complete.
+.PP
+.I Ioproc
+forks a new slave proc and returns a pointer to the
+.B Ioproc
+associated with it.
+.I Ioproc
+uses
+.I mallocz
+and
+.IR proccreate ;
+if either fails, it calls
+.I sysfatal
+rather than return an error.
+.PP
+.IR Ioopen ,
+.IR ioclose ,
+.IR ioread ,
+.IR ioreadn ,
+.IR iowrite ,
+and
+.IR iodial
+are execute the
+similarly named library or system calls
+(see
+.IR open (2),
+.IR read (2),
+and
+.IR dial (2))
+in the slave process associated with
+.IR io .
+It is an error to execute more than one call
+at a time in an I/O proc.
+.PP
+.I Iointerrupt
+interrupts the call currently executing in the I/O proc.
+If no call is executing,
+.IR iointerrupt
+is a no-op.
+.PP
+.I Closeioproc
+terminates the I/O proc and frees the associated
+.B Ioproc .
+.PP
+.I Iocall
+is a primitive that may be used to implement
+more slave I/O routines.
+.I Iocall
+arranges for
+.I op
+to be called in
+.IR io 's
+proc, with
+.I arg
+set to the variable parameter list,
+returning the value that
+.I op
+returns.
+.SH EXAMPLE
+Relay messages between two file descriptors,
+counting the total number of bytes seen:
+.IP
+.EX
+.ta +\w'xxxx'u +\w'xxxx'u +\w'xxxx'u
+int tot;
+
+void
+relaythread(void *v)
+{
+	int *fd, n;
+	char buf[1024];
+	Ioproc *io;
+
+	fd = v;
+	io = ioproc();
+	while((n = ioread(io, fd[0], buf, sizeof buf)) > 0){
+		if(iowrite(io, fd[1], buf, n) != n)
+			sysfatal("iowrite: %r");
+		tot += n;
+	}
+	closeioproc(io);
+}
+
+void
+relay(int fd0, int fd1)
+{
+	int fd[4];
+
+	fd[0] = fd[3] = fd0;
+	fd[1] = fd[2] = fd1;
+	threadcreate(relaythread, fd, 8192);
+	threadcreate(relaythread, fd+2, 8192);
+}
+.EE
+.LP
+If the two
+.I relaythread
+instances were running in different procs, the
+common access to
+.I tot
+would be unsafe.
+.EE
+.PP
+Implement
+.IR ioread :
+.IP
+.EX
+static long
+_ioread(va_list *arg)
+{
+	int fd;
+	void *a;
+	long n;
+
+	fd = va_arg(*arg, int);
+	a = va_arg(*arg, void*);
+	n = va_arg(*arg, long);
+	return read(fd, a, n);
+}
+
+long
+ioread(Ioproc *io, int fd, void *a, long n)
+{
+	return iocall(io, _ioread, fd, a, n);
+}
+.EE
+.SH SOURCE
+.B /sys/src/libthread/io*.c
+.SH SEE ALSO
+.IR dial (2),
+.IR open (2),
+.IR read (2),
+.IR thread (2)
+
blob - /dev/null
blob + f9f58cdeab383474bf922659265beb7134597940 (mode 644)
--- /dev/null
+++ man/man3/isalpharune.3
@@ -0,0 +1,47 @@
+.TH ISALPHARUNE 3
+.SH NAME
+isalpharune, islowerrune, isspacerune, istitlerune, isupperrune, tolowerrune, totitlerune, toupperrune \- Unicode character classes and cases
+.SH SYNOPSIS
+.B #include <utf.h>
+.PP
+.B
+int isalpharune(Rune c)
+.PP
+.B
+int islowerrune(Rune c)
+.PP
+.B
+int isspacerune(Rune c)
+.PP
+.B
+int istitlerune(Rune c)
+.PP
+.B
+int isupperrune(Rune c)
+.PP
+.B
+Rune tolowerrune(Rune c)
+.PP
+.B
+Rune totitlerune(Rune c)
+.PP
+.B
+Rune toupperrune(Rune c)
+.SH DESCRIPTION
+These routines examine and operate on Unicode characters,
+in particular a subset of their properties as defined in the Unicode standard.
+Unicode defines some characters as alphabetic and specifies three cases:
+upper, lower, and title.
+Analogously to
+.IR ctype (3)
+for
+.SM ASCII\c
+,
+these routines
+test types and modify cases for Unicode characters.
+The names are self-explanatory.
+.PP
+The case-conversion routines return the character unchanged if it has no case.
+.SH "SEE ALSO
+.IR ctype (3) ,
+.IR "The Unicode Standard" .
blob - /dev/null
blob + 1fab0ad804bf93d81d5beb3a5ede971af2228a2d (mode 644)
--- /dev/null
+++ man/man3/print.3
@@ -0,0 +1,469 @@
+.TH PRINT 3
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.SH NAME
+print, fprint, sprint, snprint, seprint, smprint, vfprint, vsnprint, vseprint, vsmprint \- print formatted output
+.SH SYNOPSIS
+.B #include <utf.h>
+.PP
+.B #include <fmt.h>
+.PP
+.ta \w'\fLchar* 'u
+.B
+int	print(char *format, ...)
+.PP
+.B
+int	fprint(int fd, char *format, ...)
+.PP
+.B
+int	sprint(char *s, char *format, ...)
+.PP
+.B
+int	snprint(char *s, int len, char *format, ...)
+.PP
+.B
+char*	seprint(char *s, char *e, char *format, ...)
+.PP
+.B
+char*	smprint(char *format, ...)
+.PP
+.B
+int	runesprint(Rune *s, char *format, ...)
+.PP
+.B
+int	runesnprint(Rune *s, int len, char *format, ...)
+.PP
+.B
+Rune*	runeseprint(Rune *s, Rune *e, char *format, ...)
+.PP
+.B
+Rune*	runesmprint(char *format, ...)
+.PP
+.B
+int	vfprint(int fd, char *format, va_list v)
+.PP
+.B
+int	vsnprint(char *s, int len, char *format, va_list v)
+.PP
+.B
+char*	vseprint(char *s, char *e, char *format, va_list v)
+.PP
+.B
+char*	vsmprint(char *format, va_list v)
+.PP
+.B
+int	runevsnprint(Rune *s, int len, char *format, va_list v)
+.PP
+.B
+Rune*	runevseprint(Rune *s, Rune *e, char *format, va_list v)
+.PP
+.B
+Rune*	runevsmprint(Rune *format, va_list v)
+.PP
+.B
+.SH DESCRIPTION
+.I Print
+writes text to the standard output.
+.I Fprint
+writes to the named output
+file descriptor.
+.I Sprint
+places text
+followed by the NUL character
+.RB ( \e0 )
+in consecutive bytes starting at
+.IR s ;
+it is the user's responsibility to ensure that
+enough storage is available.
+Each function returns the number of bytes
+transmitted (not including the NUL
+in the case of
+.IR sprint ),
+or
+a negative value if an output error was encountered.
+.PP
+.I Snprint
+is like
+.IR sprint ,
+but will not place more than
+.I len
+bytes in
+.IR s .
+Its result is always NUL-terminated and holds the maximal
+number of characters that can fit.
+.I Seprint
+is like
+.IR snprint ,
+except that the end is indicated by a pointer
+.I e
+rather than a count and the return value points to the terminating NUL of the
+resulting string.
+.I Smprint
+is like
+.IR sprint ,
+except that it prints into and returns a string of the required length, which is
+allocated by
+.IR malloc (3).
+.PP
+The routines
+.IR runesprint ,
+.IR runesnprint ,
+.IR runeseprint ,
+and
+.I runesmprint
+are the same as
+.IR sprint ,
+.IR snprint ,
+.IR seprint
+and
+.I smprint
+except that their output is rune strings instead of byte strings.
+.PP
+Finally, the routines
+.IR vfprint ,
+.IR vsnprint ,
+.IR vseprint ,
+.IR vsmprint ,
+.IR runevsnprint ,
+.IR runevseprint ,
+and
+.I runevsmprint
+are like their
+.BR v-less
+relatives except they take as arguments a
+.B va_list
+parameter, so they can be called within a variadic function.
+The Example section shows a representative usage.
+.PP
+Each of these functions
+converts, formats, and prints its
+trailing arguments
+under control of a
+.IR format 
+string.
+The
+format
+contains two types of objects:
+plain characters, which are simply copied to the
+output stream,
+and conversion specifications,
+each of which results in fetching of
+zero or more
+arguments.
+The results are undefined if there are arguments of the
+wrong type or too few
+arguments for the format.
+If the format is exhausted while
+arguments remain, the excess
+is ignored.
+.PP
+Each conversion specification has the following format:
+.IP
+.B "% [flags] verb
+.PP
+The verb is a single character and each flag is a single character or a
+(decimal) numeric string.
+Up to two numeric strings may be used;
+the first is called
+.IR width ,
+the second
+.IR precision .
+A period can be used to separate them, and if the period is
+present then
+.I width
+and
+.I precision
+are taken to be zero if missing, otherwise they are `omitted'.
+Either or both of the numbers may be replaced with the character
+.BR * ,
+meaning that the actual number will be obtained from the argument list
+as an integer.
+The flags and numbers are arguments to
+the
+.I verb
+described below.
+.PP
+The numeric verbs
+.BR d ,
+.BR i ,
+.BR u ,
+.BR o ,
+.BR b ,
+.BR x ,
+and
+.B X
+format their arguments in decimal, decimal,
+unsigned decimal, octal, binary, hexadecimal, and upper case hexadecimal.
+Each interprets the flags
+.BR 0 ,
+.BR h ,
+.BR hh ,
+.BR l ,
+.BR + ,
+.BR - ,
+.BR , ,
+and
+.B #
+to mean pad with zeros,
+short, byte, long, always print a sign, left justified, commas every three digits,
+and alternate format.
+Also, a space character in the flag
+position is like
+.BR + ,
+but prints a space instead of a plus sign for non-negative values.
+If neither
+short nor long is specified,
+then the argument is an
+.BR int .
+If an unsigned verb is specified,
+then the argument is interpreted as a
+positive number and no sign is output;
+space and
+.B +
+flags are ignored for unsigned verbs.
+If two
+.B l
+flags are given,
+then the argument is interpreted as a
+.B vlong
+(usually an 8-byte, sometimes a 4-byte integer).
+If
+.I precision
+is not omitted, the number is padded on the left with zeros
+until at least
+.I precision
+digits appear.
+If
+.I precision
+is explicitly 0, and the number is 0,
+no digits are generated, and alternate formatting
+does not apply.
+Then, if alternate format is specified,
+for
+.B o
+conversion, the number is preceded by a
+.B 0
+if it doesn't already begin with one.
+For non-zero numbers and
+.B x
+conversion, the number is preceded by
+.BR 0x ;
+for
+.B X
+conversion, the number is preceded by
+.BR 0X .
+Finally, if
+.I width
+is not omitted, the number is padded on the left (or right, if
+left justification is specified) with enough blanks to
+make the field at least
+.I width
+characters long.
+.PP
+The floating point verbs
+.BR f ,
+.BR e ,
+.BR E ,
+.BR g ,
+and
+.B G
+take a
+.B double
+argument.
+Each interprets the flags
+.BR 0 ,
+.BR L
+.BR + ,
+.BR - ,
+and
+.B #
+to mean pad with zeros,
+long double argument,
+always print a sign,
+left justified,
+and
+alternate format.
+.I Width
+is the minimum field width and,
+if the converted value takes up less than
+.I width
+characters, it is padded on the left (or right, if `left justified')
+with spaces.
+.I Precision
+is the number of digits that are converted after the decimal place for
+.BR e ,
+.BR E ,
+and
+.B f
+conversions,
+and
+.I precision
+is the maximum number of significant digits for
+.B g
+and
+.B G
+conversions.
+The 
+.B f
+verb produces output of the form
+.RB [ - ] digits [ .digits\fR].
+.B E
+conversion appends an exponent
+.BR E [ - ] digits ,
+and
+.B e
+conversion appends an exponent
+.BR e [ - ] digits .
+The
+.B g
+verb will output the argument in either
+.B e
+or
+.B f
+with the goal of producing the smallest output.
+Also, trailing zeros are omitted from the fraction part of
+the output, and a trailing decimal point appears only if it is followed
+by a digit.
+The
+.B G
+verb is similar, but uses
+.B E
+format instead of
+.BR e .
+When alternate format is specified, the result will always contain a decimal point,
+and for
+.B g
+and
+.B G
+conversions, trailing zeros are not removed.
+.PP
+The
+.B s
+verb copies a string
+(pointer to
+.BR char )
+to the output.
+The number of characters copied
+.RI ( n )
+is the minimum
+of the size of the string and
+.IR precision .
+These
+.I n
+characters are justified within a field of
+.I width
+characters as described above.
+If a
+.I precision
+is given, it is safe for the string not to be nul-terminated
+as long as it is at least
+.I precision
+characters (not bytes!) long.
+The
+.B S
+verb is similar, but it interprets its pointer as an array
+of runes (see
+.IR utf (7));
+the runes are converted to
+.SM UTF
+before output.
+.PP
+The
+.B c
+verb copies a single
+.B char
+(promoted to
+.BR int )
+justified within a field of
+.I width
+characters as described above.
+The
+.B C
+verb is similar, but works on runes.
+.PP
+The
+.B p
+verb formats a pointer value.
+At the moment, it is a synonym for
+.BR x ,
+but that will change if pointers and integers are different sizes.
+.PP
+The
+.B r
+verb takes no arguments; it copies the error string returned by a call to
+.IR strerror (3)
+with an argument of
+.IR errno.
+.PP
+Custom verbs may be installed using
+.IR fmtinstall (3).
+.SH EXAMPLE
+This function prints an error message with a variable
+number of arguments and then quits.
+.IP
+.EX
+.ta 6n +6n +6n
+void fatal(char *msg, ...)
+{
+	char buf[1024], *out;
+	va_list arg;
+
+	out = vseprint(buf, buf+sizeof buf, "Fatal error: ");
+	va_start(arg, msg);
+	out = vseprint(out, buf+sizeof buf, msg, arg);
+	va_end(arg);
+	write(2, buf, out-buf);
+	exit(1);
+}
+.EE
+.SH SEE ALSO
+.IR fmtinstall (3),
+.IR fprintf (3),
+.IR utf (7)
+.SH DIAGNOSTICS
+Routines that write to a file descriptor or call
+.IR malloc
+set
+.IR errstr .
+.SH BUGS
+The formatting is close to that specified for ANSI
+.IR fprintf (3);
+the main difference is that
+.B b
+and
+.B r
+are not in ANSI and some
+.B C9X
+verbs are missing.
+Also, and distinctly not a bug,
+.I print
+and friends generate
+.SM UTF
+rather than
+.SM ASCII.
+.PP
+There is no
+.BR runeprint ,
+.BR runefprint ,
+etc. because runes are byte-order dependent and should not be written directly to a file; use the
+UTF output of
+.I print
+or
+.I fprint
+instead.
+Also,
+.I sprint
+is deprecated for safety reasons; use
+.IR snprint ,
+.IR seprint ,
+or
+.I smprint
+instead.
+Safety also precludes the existence of
+.IR runesprint .
blob - /dev/null
blob + f26035625b810c723f12371267d3fc7e9b10afe2 (mode 644)
--- /dev/null
+++ man/man3/regexp9.3
@@ -0,0 +1,227 @@
+.TH REGEXP9 3
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.de LR
+.if t .BR \\$1 \\$2
+.if n .RB ` \\$1 '\\$2
+..
+.de L
+.nh
+.if t .B \\$1
+.if n .RB ` \\$1 '
+..
+.SH NAME
+regcomp, regcomplit, regcompnl, regexec, regsub, regerror \- Plan 9 regular expression library
+.SH SYNOPSIS
+.B #include <regexp9.h>
+.PP
+.ta \w'\fLRegprog 'u
+.B
+Reprog	*regcomp(char *exp)
+.PP
+.B
+Reprog	*regcomplit(char *exp)
+.PP
+.B
+Reprog	*regcompnl(char *exp)
+.PP
+.nf
+.B
+int  regexec(Reprog *prog, char *string, Resub *match, int msize)
+.PP
+.nf
+.B
+void regsub(char *source, char *dest, int dlen, Resub *match, int msize)
+.PP
+.nf
+.B
+int  rregexec(Reprog *prog, Rune *string, Resub *match, int msize)
+.PP
+.nf
+.B
+void rregsub(Rune *source, Rune *dest, int dlen, Resub *match, int msize)
+.PP
+.B
+void regerror(char *msg)
+.SH DESCRIPTION
+.I Regcomp
+compiles a
+regular expression and returns
+a pointer to the generated description.
+The space is allocated by
+.IR malloc (3)
+and may be released by
+.IR free .
+Regular expressions are exactly as in
+.IR regexp9 (7).
+.PP
+.I Regcomplit
+is like
+.I regcomp
+except that all characters are treated literally.
+.I Regcompnl
+is like
+.I regcomp
+except that the
+.B .
+metacharacter matches all characters, including newlines.
+.PP
+.I Regexec
+matches a null-terminated
+.I string
+against the compiled regular expression in
+.IR prog .
+If it matches,
+.I regexec
+returns
+.B 1
+and fills in the array
+.I match
+with character pointers to the substrings of
+.I string
+that correspond to the
+parenthesized subexpressions of 
+.IR exp :
+.BI match[ i ].sp
+points to the beginning and
+.BI match[ i ].ep
+points just beyond
+the end of the
+.IR i th
+substring.
+(Subexpression
+.I i
+begins at the
+.IR i th
+left parenthesis, counting from 1.)
+Pointers in
+.B match[0]
+pick out the substring that corresponds to
+the whole regular expression.
+Unused elements of
+.I match
+are filled with zeros.
+Matches involving
+.LR * ,
+.LR + ,
+and 
+.L ?
+are extended as far as possible.
+The number of array elements in 
+.I match
+is given by
+.IR msize .
+The structure of elements of
+.I match 
+is:
+.IP
+.EX
+typedef struct {
+	union {
+	   char *sp;
+	   Rune *rsp;
+	} s;
+	union {
+	   char *ep;
+	   Rune *rep;
+	} e;
+} Resub;
+.EE
+.LP
+If
+.B match[0].s.sp
+is nonzero on entry,
+.I regexec
+starts matching at that point within
+.IR string .
+If
+.B match[0].e.ep
+is nonzero on entry,
+the last character matched is the one
+preceding that point.
+.PP
+.I Regsub
+places in
+.I dest
+a substitution instance of
+.I source
+in the context of the last
+.I regexec
+performed using
+.IR match .
+Each instance of
+.BI \e n\f1,
+where
+.I n
+is a digit, is replaced by the
+string delimited by
+.BI match[ n ].s.sp
+and
+.BI match[ n ].e.ep\f1.
+Each instance of 
+.L &
+is replaced by the string delimited by
+.B match[0].s.sp
+and
+.BR match[0].e.ep .
+The substitution will always be null terminated and
+trimmed to fit into dlen bytes.
+.PP
+.IR Regerror ,
+called whenever an error is detected in
+.IR regcomp ,
+writes the string
+.I msg
+on the standard error file and exits.
+.I Regerror
+can be replaced to perform
+special error processing.
+If the user supplied
+.I regerror
+returns rather than exits,
+.I regcomp
+will return 0. 
+.PP
+.I Rregexec
+and
+.I rregsub
+are variants of 
+.I regexec
+and
+.I regsub
+that use strings of
+.B Runes
+instead of strings of
+.BR chars .
+With these routines, the 
+.I rsp
+and
+.I rep
+fields of the
+.I match
+array elements should be used.
+.SH "SEE ALSO"
+.IR grep (1),
+.IR regexp9 (7)
+.SH DIAGNOSTICS
+.I Regcomp
+returns 
+.B 0
+for an illegal expression
+or other failure.
+.I Regexec
+returns 0
+if
+.I string
+is not matched.
+.SH HISTORY
+This particular regular expression was first written by Rob Pike for Plan 9.
+It has also appeared as part of the Inferno operating system.
+.SH BUGS
+There is no way to specify or match a NUL character; NULs terminate patterns and strings.
blob - /dev/null
blob + 7ce978aed6129fcddddd3f934d4cab541ba103f5 (mode 644)
--- /dev/null
+++ man/man3/rune.3
@@ -0,0 +1,187 @@
+.TH RUNE 3
+.SH NAME
+runetochar, chartorune, runelen, runenlen, fullrune, utfecpy, utflen, utfnlen, utfrune, utfrrune, utfutf \- rune/UTF conversion
+.SH SYNOPSIS
+.ta \w'\fLchar*xx'u
+.B #include <utf.h>
+.PP
+.B
+int	runetochar(char *s, Rune *r)
+.PP
+.B
+int	chartorune(Rune *r, char *s)
+.PP
+.B
+int	runelen(long r)
+.PP
+.B
+int	runenlen(Rune *r, int n)
+.PP
+.B
+int	fullrune(char *s, int n)
+.PP
+.B
+char*	utfecpy(char *s1, char *es1, char *s2)
+.PP
+.B
+int	utflen(char *s)
+.PP
+.B
+int	utfnlen(char *s, long n)
+.PP
+.B
+char*	utfrune(char *s, long c)
+.PP
+.B
+char*	utfrrune(char *s, long c)
+.PP
+.B
+char*	utfutf(char *s1, char *s2)
+.SH DESCRIPTION
+These routines convert to and from a
+.SM UTF
+byte stream and runes.
+.PP
+.I Runetochar
+copies one rune at
+.I r
+to at most
+.B UTFmax
+bytes starting at
+.I s
+and returns the number of bytes copied.
+.BR UTFmax ,
+defined as
+.B 3
+in
+.BR <libc.h> ,
+is the maximum number of bytes required to represent a rune.
+.PP
+.I Chartorune
+copies at most
+.B UTFmax
+bytes starting at
+.I s
+to one rune at
+.I r
+and returns the number of bytes copied.
+If the input is not exactly in
+.SM UTF
+format,
+.I chartorune
+will convert to 0x80 and return 1.
+.PP
+.I Runelen
+returns the number of bytes
+required to convert
+.I r
+into
+.SM UTF.
+.PP
+.I Runenlen
+returns the number of bytes
+required to convert the
+.I n
+runes pointed to by
+.I r
+into
+.SM UTF.
+.PP
+.I Fullrune
+returns 1 if the string
+.I s
+of length
+.I n
+is long enough to be decoded by
+.I chartorune
+and 0 otherwise.
+This does not guarantee that the string
+contains a legal
+.SM UTF
+encoding.
+This routine is used by programs that
+obtain input a byte at
+a time and need to know when a full rune
+has arrived.
+.PP
+The following routines are analogous to the
+corresponding string routines with
+.B utf
+substituted for
+.B str
+and
+.B rune
+substituted for
+.BR chr .
+.PP
+.I Utfecpy
+copies UTF sequences until a null sequence has been copied, but writes no 
+sequences beyond
+.IR es1 .
+If any sequences are copied,
+.I s1
+is terminated by a null sequence, and a pointer to that sequence is returned.
+Otherwise, the original
+.I s1
+is returned.
+.PP
+.I Utflen
+returns the number of runes that
+are represented by the
+.SM UTF
+string
+.IR s .
+.PP
+.I Utfnlen
+returns the number of complete runes that
+are represented by the first
+.I n
+bytes of
+.SM UTF
+string
+.IR s .
+If the last few bytes of the string contain an incompletely coded rune,
+.I utfnlen
+will not count them; in this way, it differs from
+.IR utflen ,
+which includes every byte of the string.
+.PP
+.I Utfrune
+.RI ( utfrrune )
+returns a pointer to the first (last)
+occurrence of rune
+.I c
+in the
+.SM UTF
+string
+.IR s ,
+or 0 if
+.I c
+does not occur in the string.
+The NUL byte terminating a string is considered to
+be part of the string
+.IR s .
+.PP
+.I Utfutf
+returns a pointer to the first occurrence of
+the
+.SM UTF
+string
+.I s2
+as a
+.SM UTF
+substring of
+.IR s1 ,
+or 0 if there is none.
+If
+.I s2
+is the null string,
+.I utfutf
+returns
+.IR s1 .
+.SH HISTORY
+These routines were written by Rob Pike and Ken Thompson
+and first appeared in Plan 9.
+.SH SEE ALSO
+.IR utf (7),
+.IR tcs (1)
blob - /dev/null
blob + c012e59e54834ecdc151ffabc2372b2c095f79f5 (mode 644)
--- /dev/null
+++ man/man3/runestrcat.3
@@ -0,0 +1,65 @@
+.TH RUNESTRCAT 3
+.SH NAME
+runestrcat, 
+runestrncat,
+runestrcmp,
+runestrncmp,
+runestrcpy,
+runestrncpy,
+runestrecpy,
+runestrlen,
+runestrchr,
+runestrrchr,
+runestrdup,
+runestrstr \- rune string operations
+.SH SYNOPSIS
+.B #include <utf.h>
+.PP
+.ta \w'\fLRune* \fP'u
+.B
+Rune*	runestrcat(Rune *s1, Rune *s2)
+.PP
+.B
+Rune*	runestrncat(Rune *s1, Rune *s2, long n)
+.PP
+.B
+int	runestrcmp(Rune *s1, Rune *s2)
+.PP
+.B
+int	runestrncmp(Rune *s1, Rune *s2, long n)
+.PP
+.B
+Rune*	runestrcpy(Rune *s1, Rune *s2)
+.PP
+.B
+Rune*	runestrncpy(Rune *s1, Rune *s2, long n)
+.PP
+.B
+Rune*	runestrecpy(Rune *s1, Rune *es1, Rune *s2)
+.PP
+.B
+long	runestrlen(Rune *s)
+.PP
+.B
+Rune*	runestrchr(Rune *s, Rune c)
+.PP
+.B
+Rune*	runestrrchr(Rune *s, Rune c)
+.PP
+.B
+Rune*	runestrdup(Rune *s)
+.PP
+.B
+Rune*	runestrstr(Rune *s1, Rune *s2)
+.SH DESCRIPTION
+These functions are rune string analogues of
+the corresponding functions in 
+.IR strcat (3).
+.SH HISTORY
+These routines first appeared in Plan 9.
+.SH SEE ALSO
+.IR memmove (3),
+.IR rune (3),
+.IR strcat (2)
+.SH BUGS
+The outcome of overlapping moves varies among implementations.
blob - /dev/null
blob + 3009ac8478712c799d758bfb93e7ef67825cdf5c (mode 644)
--- /dev/null
+++ man/man3/thread.3
@@ -0,0 +1,576 @@
+.TH THREAD 2
+.SH NAME
+alt,
+chancreate,
+chanfree,
+chaninit,
+chanprint,
+mainstacksize,
+proccreate,
+procdata,
+procexec,
+procexecl,
+procrfork,
+recv,
+recvp,
+recvul,
+send,
+sendp,
+sendul,
+nbrecv,
+nbrecvp,
+nbrecvul,
+nbsend,
+nbsendp,
+nbsendul,
+threadcreate,
+threaddata,
+threadexits,
+threadexitsall,
+threadgetgrp,
+threadgetname,
+threadint,
+threadintgrp,
+threadkill,
+threadkillgrp,
+threadmain,
+threadnotify,
+threadid,
+threadpid,
+threadsetgrp,
+threadsetname,
+threadwaitchan,
+yield \- thread and proc management
+.SH SYNOPSIS
+.PP
+.EX
+.ta 4n +4n +4n +4n +4n +4n +4n
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+.sp
+#define	CHANEND		0
+#define	CHANSND		1
+#define	CHANRCV		2
+#define	CHANNOP		3
+#define	CHANNOBLK	4
+.sp
+.ta \w'    'u +\w'Channel 'u
+typedef struct Alt Alt;
+struct Alt {
+	Channel	*c;
+	void	*v;
+	int	op;
+	Channel	**tag;
+	int	entryno;
+};
+.fi
+.de XX
+.ift .sp 0.5
+.ifn .sp
+..
+.PP
+.nf
+.ft L
+.ta \w'\fLChannel* 'u +4n +4n +4n +4n
+void	threadmain(int argc, char *argv[])
+int	mainstacksize
+int	proccreate(void (*fn)(void*), void *arg, uint stacksize)
+int	procrfork(void (*fn)(void*), void *arg, uint stacksize,
+		int rforkflag)
+int	threadcreate(void (*fn)(void*), void *arg, uint stacksize)
+void	threadexits(char *status)
+void	threadexitsall(char *status)
+void	yield(void)
+.XX
+int	threadid(void)
+int	threadgrp(void)
+int	threadsetgrp(int group)
+int	threadpid(int id)
+.XX
+int	threadint(int id)
+int	threadintgrp(int group)
+int	threadkill(int id)
+int	threadkillgrp(int group)
+.XX
+void	threadsetname(char *name)
+char*	threadgetname(void)
+.XX
+void**	threaddata(void)
+void**	procdata(void)
+.XX
+int	chaninit(Channel *c, int elsize, int nel)
+Channel*	chancreate(int elsize, int nel)
+void	chanfree(Channel *c)
+.XX
+int	alt(Alt *alts)
+int	recv(Channel *c, void *v)
+void*	recvp(Channel *c)
+ulong	recvul(Channel *c)
+int	nbrecv(Channel *c, void *v)
+void*	nbrecvp(Channel *c)
+ulong	nbrecvul(Channel *c)
+int	send(Channel *c, void *v)
+int	sendp(Channel *c, void *v)
+int	sendul(Channel *c, ulong v)
+int	nbsend(Channel *c, void *v)
+int	nbsendp(Channel *c, void *v)
+int	nbsendul(Channel *c, ulong v)
+int	chanprint(Channel *c, char *fmt, ...)
+.XX
+int	procexecl(Channel *cpid, char *file, ...)
+int	procexec(Channel *cpid, char *file, char *args[])
+Channel*	threadwaitchan(void)
+.XX
+int	threadnotify(int (*f)(void*, char*), int in)
+.EE
+.SH DESCRIPTION
+.PP
+The thread library provides parallel programming support similar to that
+of the languages
+Alef and Newsqueak.
+Threads
+and
+procs
+occupy a shared address space,
+communicating and synchronizing through
+.I channels
+and shared variables.
+.PP
+A
+.I proc
+is a Plan 9 process that contains one or more cooperatively scheduled
+.IR threads .
+Programs using threads must replace
+.I main
+by
+.IR threadmain .
+The thread library provides a
+.I main
+function that sets up a proc with a single thread executing
+.I threadmain
+on a stack of size
+.I mainstacksize
+(default eight kilobytes).
+To set
+.IR mainstacksize ,
+declare a global variable
+initialized to the desired value
+.RI ( e.g. ,
+.B int
+.B mainstacksize
+.B =
+.BR 1024 ).
+.PP
+.I Threadcreate
+creates a new thread in the calling proc, returning a unique integer
+identifying the thread; the thread
+executes
+.I fn(arg)
+on a stack of size
+.IR stacksize .
+Thread stacks are allocated in shared memory, making it valid to pass 
+pointers to stack variables between threads and procs.
+.I Procrfork
+creates a new proc, and inside that proc creates
+a single thread as
+.I threadcreate
+would,
+returning the id of the created thread.
+.I Procrfork
+creates the new proc by calling
+.B rfork
+(see
+.IR fork (2))
+with flags
+.BR RFPROC|RFMEM|RFNOWAIT| \fIrforkflag\fR.
+(The thread library depends on all its procs
+running in the same rendezvous group.
+Do not include
+.B RFREND
+in
+.IR rforkflag .)
+.I Proccreate
+is identical to 
+.I procrfork
+with
+.I rforkflag
+set to zero.
+Be aware that the calling thread may continue
+execution before
+the newly created proc and thread
+are scheduled.
+Because of this,
+.I arg
+should not point to data on the stack of a function that could
+return before the new process is scheduled.
+.PP
+.I Threadexits
+terminates the calling thread.
+If the thread is the last in its proc,
+.I threadexits
+also terminates the proc, using
+.I status
+as the exit status.
+.I Threadexitsall
+terminates all procs in the program,
+using
+.I status
+as the exit status.
+.PP
+The threads in a proc are coroutines, scheduled nonpreemptively
+in a round-robin fashion.
+A thread must explicitly relinquish control of the processor
+before another thread in the same proc is run.
+Calls that do this are
+.IR yield ,
+.IR proccreate ,
+.IR procexec ,
+.IR procexecl ,
+.IR threadexits ,
+.IR alt ,
+.IR send ,
+and
+.I recv
+(and the calls related to
+.I send
+and
+.IR recv \(emsee
+their descriptions further on).
+Procs are scheduled by the operating system.
+Therefore, threads in different procs can preempt one another
+in arbitrary ways and should synchronize their
+actions using
+.B qlocks
+(see
+.IR lock (2))
+or channel communication.
+System calls such as
+.IR read (2)
+block the entire proc;
+all threads in a proc block until the system call finishes.
+.PP
+As mentioned above, each thread has a unique integer thread id.
+Thread ids are not reused; they are unique across the life of the program.
+.I Threadid
+returns the id for the current thread.
+Each thread also has a thread group id.
+The initial thread has a group id of zero.
+Each new thread inherits the group id of
+the thread that created it.
+.I Threadgrp
+returns the group id for the current thread;
+.I threadsetgrp
+sets it.
+.I Threadpid
+returns the pid of the Plan 9 process containing
+the thread identified by
+.IR id ,
+or \-1
+if no such thread is found.
+.PP
+.I Threadint
+interrupts a thread that is blocked in a channel operation
+or system call.
+.I Threadintgrp
+interrupts all threads with the given group id.
+.I Threadkill
+marks a thread to die when it next relinquishes the processor
+(via one of the calls listed above).
+If the thread is blocked in a channel operation or system call,
+it is also interrupted.
+.I Threadkillgrp
+kills all threads with the given group id.
+Note that
+.I threadkill
+and
+.I threadkillgrp
+will not terminate a thread that never relinquishes
+the processor.
+.PP
+Primarily for debugging,
+threads can have string names associated with them.
+.I Threadgetname
+returns the current thread's name;
+.I threadsetname
+sets it.
+The pointer returned by
+.I threadgetname
+is only valid until the next call to
+.IR threadsetname .
+.PP
+.I Threaddata
+returns a pointer to a per-thread pointer
+that may be modified by threaded programs for
+per-thread storage.
+Similarly, 
+.I procdata
+returns a pointer to a per-proc pointer.
+.PP
+.I Procexecl
+and
+.I procexec
+are threaded analogues of
+.I exec
+and
+.I execl
+(see
+.IR exec (2));
+on success,
+they replace the calling thread (which must be the only thread in its proc)
+and invoke the external program, never returning.
+On error, they return \-1.
+If
+.I cpid
+is not null, the pid of the invoked program
+will be sent along
+.I cpid
+once the program has been started, or \-1 will be sent if an
+error occurs.
+.I Procexec
+and
+.I procexecl
+will not access their arguments after sending a result
+along
+.IR cpid .
+Thus, programs that malloc the
+.I argv
+passed to
+.I procexec
+can safely free it once they have
+received the
+.I cpid
+response.
+.I Threadwaitchan
+returns a channel of pointers to
+.B Waitmsg
+structures (see
+.IR wait (2)).
+When an exec'ed process exits, a pointer to a
+.B Waitmsg
+is sent to this channel.
+These
+.B Waitmsg
+structures have been allocated with
+.IR malloc (2)
+and should be freed after use.
+.PP
+A
+.B Channel
+is a buffered or unbuffered queue for fixed-size messages.
+Procs and threads
+.I send
+messages into the channel and
+.I recv
+messages from the channel.  If the channel is unbuffered, a
+.I send
+operation blocks until the corresponding
+.I recv
+operation occurs and
+.IR "vice versa" .
+.I Chaninit
+initializes a 
+.B Channel
+for messages of size
+.I elsize 
+and with a buffer holding
+.I nel
+messages.
+If
+.I nel
+is zero, the channel is unbuffered.
+.IR Chancreate
+allocates a new channel and initializes it.
+.I Chanfree
+frees a channel that is no longer used.
+.I Chanfree
+can be called by either sender or receiver after the last item has been
+sent or received.  Freeing the channel will be delayed if there is a thread
+blocked on it until that thread unblocks (but
+.I chanfree
+returns immediately).
+.PP
+.I Send
+sends the element pointed at by
+.I v
+to the channel
+.IR c .
+If
+.I v
+is null, zeros are sent.
+.I Recv
+receives an element from
+.I c
+and stores it in
+.IR v .
+If
+.I v
+is null,
+the received value is discarded.
+.I Send
+and
+.I recv
+return 1 on success, \-1 if interrupted.
+.I Nbsend
+and
+.I nbrecv
+behave similarly, but return 0 rather than blocking.
+.PP
+.IR Sendp ,
+.IR nbsendp ,
+.IR sendul ,
+and
+.I nbsendul
+send a pointer or an unsigned long; the channel must
+have been initialized with the appropriate
+.IR elsize .
+.IR Recvp ,
+.IR nbrecvp ,
+.IR recvul ,
+and
+.I nbrecvul
+receive a pointer or an unsigned long;
+they return zero when a zero is received,
+when interrupted, or
+(for
+.I nbrecvp
+and
+.IR nbrecvul )
+when the operation would have blocked.
+To distinguish between these three cases,
+use
+.I recv
+or
+.IR nbrecv .
+.PP
+.I Alt
+can be used to recv from or send to one of a number of channels,
+as directed by an array of
+.B Alt
+structures,
+each of which describes a potential send or receive operation.
+In an
+.B Alt
+structure,
+.B c
+is the channel;
+.B v
+the value pointer (which may be null); and
+.B op
+the operation:
+.B CHANSND
+for a send operation,
+.B CHANRECV
+for a recv operation;
+.B CHANNOP
+for no operation
+(useful
+when
+.I alt
+is called with a varying set of operations).
+The array of
+.B Alt
+structures is terminated by an entry with
+.I op
+.B CHANEND
+or
+.BR CHANNOBLK .
+If at least one
+.B Alt
+structure can proceed, one of them is
+chosen at random to be executed.
+.I Alt
+returns the index of the chosen structure.
+If no operations can proceed and the list is terminated with
+.BR CHANNOBLK ,
+.I alt
+returns the index of the terminating
+.B CHANNOBLK
+structure.
+Otherwise,
+.I alt
+blocks until one of the operations can proceed,
+eventually returning the index of the structure executes.
+.I Alt
+returns \-1 when interrupted.
+The
+.B tag
+and
+.B entryno
+fields in the
+.B Alt
+structure are used internally by
+.I alt
+and need not be initialized.
+They are not used between
+.I alt
+calls.
+.PP
+.I Chanprint
+formats its arguments in the manner of
+.IR print (2)
+and sends the result to the channel
+.IR c.
+The string delivered by
+.I chanprint
+is allocated with
+.IR malloc (2)
+and should be freed upon receipt.
+.PP
+Thread library functions do not return on failure;
+if errors occur, the entire program is aborted.
+.PP
+Threaded programs should use
+.I threadnotify
+in place of
+.I atnotify
+(see
+.IR notify (2)).
+.PP
+It is safe to use
+.B sysfatal
+(see
+.IR perror (2))
+in threaded programs.
+.I Sysfatal
+will print the error string and call
+.IR threadexitsall .
+.PP
+It is safe to use 
+.IR rfork
+(see
+.IR fork (2))
+to manage the namespace, file descriptors, note group, and environment of a
+single process.
+That is, it is safe to call
+.I rfork
+with the flags
+.BR RFNAMEG ,
+.BR RFFDG ,
+.BR RFCFDG ,
+.BR RFNOTEG ,
+.BR RFENVG ,
+and
+.BR RFCENVG.
+(To create new processes, use
+.I proccreate
+and 
+.IR procrfork .)
+As mentioned above,
+the thread library depends on all procs being in the
+same rendezvous group; do not change the rendezvous
+group with
+.IR rfork .
+.SH FILES
+.B /sys/lib/acid/thread
+contains useful
+.IR acid (1)
+functions for debugging threaded programs.
+.PP
+.B /sys/src/libthread/example.c
+contains a full example program.
+.SH SOURCE
+.B /sys/src/libthread
+.SH SEE ALSO
+.IR intro (2),
+.IR ioproc (2)
blob - /dev/null
blob + 5b1a8a4ee18973b42b1a658ada6309683abd2830 (mode 755)
--- /dev/null
+++ package
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+rm -rf ../9tmp
+mkdir ../9tmp
+mkdir ../9pkg
+cp -R * ../9tmp
+cd ../9tmp
+rm -rf `find . -name CVS`
+rm lib/*
+rm */*.o
+rm */*.a
+rm mk/mk
+rm sam/sam
+rm man/*/*
+for i in libfmt libbio lib9 libthread libutf libregexp sam mk 
+do
+	tar cf - $i |gzip >../9pkg/$i.tar.gz
+done
+tar cf - . | gzip > ../9pkg/all.tar.gz
blob - /dev/null
blob + a5d7d87d79f0af66f7a5f54320edabb411b0e803 (mode 644)
--- /dev/null
+++ src/lib9/LICENSE
@@ -0,0 +1,258 @@
+The Plan 9 software is provided under the terms of the
+Lucent Public License, Version 1.02, reproduced below,
+with the following exceptions:
+
+1. No right is granted to create derivative works of or
+   to redistribute (other than with the Plan 9 Operating System)
+   the screen imprinter fonts identified in subdirectory
+   /lib/font/bit/lucida and printer fonts (Lucida Sans Unicode, Lucida
+   Sans Italic, Lucida Sans Demibold, Lucida Typewriter, Lucida Sans
+   Typewriter83), identified in subdirectory /sys/lib/postscript/font.
+   These directories contain material copyrights by B&H Inc. and Y&Y Inc.
+
+2. The printer fonts identified in subdirectory /sys/lib/ghostscript/font
+   are subject to the GNU GPL, reproduced in the file /LICENSE.gpl.
+
+3. The ghostscript program in the subdirectory /sys/src/cmd/gs is
+   covered by the Aladdin Free Public License, reproduced in the file
+   /LICENSE.afpl.
+
+===================================================================
+
+Lucent Public License Version 1.02
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
+     Program, and
+  b. in the case of each Contributor,
+
+     i. changes to the Program, and
+    ii. additions to the Program;
+
+    where such changes and/or additions to the Program were added to the
+    Program by such Contributor itself or anyone acting on such
+    Contributor's behalf, and the Contributor explicitly consents, in
+    accordance with Section 3C, to characterization of the changes and/or
+    additions as Contributions.
+
+"Contributor" means LUCENT and any other entity that has Contributed a
+Contribution to the Program.
+
+"Distributor" means a Recipient that distributes the Program,
+modifications to the Program, or any part thereof.
+
+"Licensed Patents" mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+
+"Original Program" means the original version of the software
+accompanying this Agreement as released by LUCENT, including source
+code, object code and documentation, if any.
+
+"Program" means the Original Program and Contributions or any part
+thereof
+
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free copyright
+    license to reproduce, prepare derivative works of, publicly display,
+    publicly perform, distribute and sublicense the Contribution of such
+    Contributor, if any, and such derivative works, in source code and
+    object code form.
+    
+ b. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free patent
+    license under Licensed Patents to make, use, sell, offer to sell,
+    import and otherwise transfer the Contribution of such Contributor, if
+    any, in source code and object code form. The patent license granted
+    by a Contributor shall also apply to the combination of the
+    Contribution of that Contributor and the Program if, at the time the
+    Contribution is added by the Contributor, such addition of the
+    Contribution causes such combination to be covered by the Licensed
+    Patents. The patent license granted by a Contributor shall not apply
+    to (i) any other combinations which include the Contribution, nor to
+    (ii) Contributions of other Contributors. No hardware per se is
+    licensed hereunder.
+    
+ c. Recipient understands that although each Contributor grants the
+    licenses to its Contributions set forth herein, no assurances are
+    provided by any Contributor that the Program does not infringe the
+    patent or other intellectual property rights of any other entity. Each
+    Contributor disclaims any liability to Recipient for claims brought by
+    any other entity based on infringement of intellectual property rights
+    or otherwise. As a condition to exercising the rights and licenses
+    granted hereunder, each Recipient hereby assumes sole responsibility
+    to secure any other intellectual property rights needed, if any. For
+    example, if a third party patent license is required to allow
+    Recipient to distribute the Program, it is Recipient's responsibility
+    to acquire that license before distributing the Program.
+
+ d. Each Contributor represents that to its knowledge it has sufficient
+    copyright rights in its Contribution, if any, to grant the copyright
+    license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A. Distributor may choose to distribute the Program in any form under
+this Agreement or under its own license agreement, provided that:
+
+ a. it complies with the terms and conditions of this Agreement;
+
+ b. if the Program is distributed in source code or other tangible
+    form, a copy of this Agreement or Distributor's own license agreement
+    is included with each copy of the Program; and
+
+ c. if distributed under Distributor's own license agreement, such
+    license agreement:
+
+      i. effectively disclaims on behalf of all Contributors all warranties
+         and conditions, express and implied, including warranties or
+         conditions of title and non-infringement, and implied warranties or
+         conditions of merchantability and fitness for a particular purpose;
+     ii. effectively excludes on behalf of all Contributors all liability
+         for damages, including direct, indirect, special, incidental and
+         consequential damages, such as lost profits; and
+    iii. states that any provisions which differ from this Agreement are
+         offered by that Contributor alone and not by any other party.
+
+B. Each Distributor must include the following in a conspicuous
+   location in the Program:
+
+   Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
+   Reserved.
+
+C. In addition, each Contributor must identify itself as the
+originator of its Contribution in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+Also, each Contributor must agree that the additions and/or changes
+are intended to be a Contribution. Once a Contribution is contributed,
+it may not thereafter be revoked.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use
+of the Program, the Distributor who includes the Program in a
+commercial product offering should do so in a manner which does not
+create potential liability for Contributors. Therefore, if a
+Distributor includes the Program in a commercial product offering,
+such Distributor ("Commercial Distributor") hereby agrees to defend
+and indemnify every Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively"Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the acts
+or omissions of such Commercial Distributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement.
+In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Distributor in writing of such claim, and b)
+allow the Commercial Distributor to control, and cooperate with the
+Commercial Distributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such
+claim at its own expense.
+
+For example, a Distributor might include the Program in a commercial
+product offering, Product X. That Distributor is then a Commercial
+Distributor. If that Commercial Distributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Distributor's responsibility
+alone. Under this section, the Commercial Distributor would have to
+defend claims against the Contributors related to those performance
+claims and warranties, and if a court requires any Contributor to pay
+any damages as a result, the Commercial Distributor must pay those
+damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement, including but not limited to
+the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. EXPORT CONTROL
+
+Recipient agrees that Recipient alone is responsible for compliance
+with the United States export administration regulations (and the
+export control laws and regulation of any other countries).
+
+8. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with
+respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that
+Contributor to such Recipient under this Agreement shall terminate as
+of the date such litigation is filed. In addition, if Recipient
+institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and
+survive.
+
+LUCENT may publish new versions (including revisions) of this
+Agreement from time to time. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to
+distribute the Program (including its Contributions) under the new
+version. No one other than LUCENT has the right to modify this
+Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property
+of any Contributor under this Agreement, whether expressly, by
+implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No
+party to this Agreement will bring a legal action under this Agreement
+more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.
+
blob - /dev/null
blob + 14b8d4e7925867693d110c320d9c5a67dcd16758 (mode 644)
--- /dev/null
+++ src/lib9/Make.Darwin-PowerMacintosh
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/lib9/Make.FreeBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + edbdc111a2a0c008975e297c7ca60e46199397a9 (mode 644)
--- /dev/null
+++ src/lib9/Make.HP-UX-9000
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS=-O -c -Ae -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 74b0252c6eae6331b48ede7fcfa1ed760609d1a3 (mode 644)
--- /dev/null
+++ src/lib9/Make.Linux-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/lib9/Make.NetBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 3d45279bba28dbe69c00f89568c444ab83a4ac72 (mode 644)
--- /dev/null
+++ src/lib9/Make.OSF1-alpha
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + c5fe67b82d86c731a56c101e522e804390e5bd5a (mode 644)
--- /dev/null
+++ src/lib9/Make.SunOS-sun4u
@@ -0,0 +1,2 @@
+include Make.SunOS-sun4u-$(CC)
+NAN=nan64.$O
blob - /dev/null
blob + 829301de8649d40632eb809ae512598af11d48c5 (mode 644)
--- /dev/null
+++ src/lib9/Make.SunOS-sun4u-cc
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I. -O
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 5c41594812a4a27eb848d384cbc356d206c0a44b (mode 644)
--- /dev/null
+++ src/lib9/Make.SunOS-sun4u-gcc
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 595db7879960cf99426d2225aa20e034ca1d9aca (mode 644)
--- /dev/null
+++ src/lib9/Makefile
@@ -0,0 +1,120 @@
+
+# this works in gnu make
+SYSNAME:=${shell uname}
+OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
+
+# this works in bsd make
+SYSNAME!=uname
+OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
+
+# the gnu rules will mess up bsd but not vice versa,
+# hence the gnu rules come first.
+
+include Make.$(SYSNAME)-$(OBJTYPE)
+
+PREFIX=/usr/local
+
+NUKEFILES=
+
+TGZFILES=
+
+LIB=lib9.a
+VERSION=2.0
+PORTPLACE=devel/lib9
+NAME=lib9
+
+OFILES=\
+	_exits.$O\
+	argv0.$O\
+	await.$O\
+	encodefmt.$O\
+	errstr.$O\
+	exits.$O\
+	ffork-$(SYSNAME).$O\
+	getcallerpc-$(OBJTYPE).$O\
+	getfields.$O\
+	lock.$O\
+	malloctag.$O\
+	mallocz.$O\
+	nrand.$O\
+	qlock.$O\
+	readn.$O\
+	rendez.$O\
+	strecpy.$O\
+	sysfatal.$O\
+	tas-$(OBJTYPE).$O\
+	tokenize.$O\
+	u16.$O\
+	u32.$O\
+	u64.$O\
+	wait.$O\
+	werrstr.$O\
+
+HFILES=\
+	lib9.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	# install -m 0644 lib9.3 $(PREFIX)/man/man3/lib9.3
+	install -m 0644 lib9.h $(PREFIX)/include/lib9.h
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+test: $(LIB) test.$O
+	$(CC) -o test test.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf
+
+testfork: $(LIB) testfork.$O
+	$(CC) -o testfork testfork.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf
+
+$(LIB): $(OFILES)
+	$(AR) $(ARFLAGS) $(LIB) $(OFILES)
+
+NUKEFILES+=$(LIB)
+.c.$O:
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+%.$O: %.c
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+
+$(OFILES): $(HFILES)
+
+tgz:
+	rm -rf $(NAME)-$(VERSION)
+	mkdir $(NAME)-$(VERSION)
+	cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION)
+	tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz
+	rm -rf $(NAME)-$(VERSION)
+
+clean:
+	rm -f $(OFILES) $(LIB)
+
+nuke:
+	rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES)
+
+rpm:
+	make tgz
+	cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES
+	rpm -ba rpm.spec
+	cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm .
+	cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm .
+	scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software
+
+PORTDIR=/usr/ports/$(PORTPLACE)
+
+ports:
+	make tgz
+	rm -rf $(PORTDIR)
+	mkdir $(PORTDIR)
+	cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles
+	cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}')
+	(cd $(PORTDIR); make makesum)
+	(cd $(PORTDIR); make)
+	(cd $(PORTDIR); /usr/local/bin/portlint)
+	rm -rf $(PORTDIR)/work
+	shar `find $(PORTDIR)` > ports.shar
+	(cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz
+	scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software
+
+.phony: all clean nuke install tgz rpm ports
blob - /dev/null
blob + 8b3584cbd1d1609ccebb43d3a6df492bf219bd0c (mode 644)
--- /dev/null
+++ src/lib9/Makefile.MID
@@ -0,0 +1,49 @@
+LIB=lib9.a
+VERSION=2.0
+PORTPLACE=devel/lib9
+NAME=lib9
+
+OFILES=\
+	_exits.$O\
+	argv0.$O\
+	await.$O\
+	encodefmt.$O\
+	errstr.$O\
+	exits.$O\
+	ffork-$(SYSNAME).$O\
+	getcallerpc-$(OBJTYPE).$O\
+	getfields.$O\
+	lock.$O\
+	malloctag.$O\
+	mallocz.$O\
+	nrand.$O\
+	qlock.$O\
+	readn.$O\
+	rendez.$O\
+	strecpy.$O\
+	sysfatal.$O\
+	tas-$(OBJTYPE).$O\
+	tokenize.$O\
+	u16.$O\
+	u32.$O\
+	u64.$O\
+	wait.$O\
+	werrstr.$O\
+
+HFILES=\
+	lib9.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	# install -m 0644 lib9.3 $(PREFIX)/man/man3/lib9.3
+	install -m 0644 lib9.h $(PREFIX)/include/lib9.h
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+test: $(LIB) test.$O
+	$(CC) -o test test.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf
+
+testfork: $(LIB) testfork.$O
+	$(CC) -o testfork testfork.$O $(LIB) -L$(PREFIX)/lib -lfmt -lutf
+
blob - /dev/null
blob + 35ff4e672821e8e316df7264cef7a2b65f0fb38f (mode 644)
--- /dev/null
+++ src/lib9/_exits.c
@@ -0,0 +1,9 @@
+#include <lib9.h>
+
+void
+_exits(char *s)
+{
+	if(s && *s)
+		_exit(1);
+	_exit(0);
+}
blob - /dev/null
blob + 2c846f4d327ad54b84d43c80b83d64301fc2e4c7 (mode 644)
--- /dev/null
+++ src/lib9/argv0.c
@@ -0,0 +1,4 @@
+#include <lib9.h>
+
+char *argv0;
+
blob - /dev/null
blob + 9df7faa5c2264e487ec01e0af2fc1b2a07095023 (mode 644)
--- /dev/null
+++ src/lib9/await.c
@@ -0,0 +1,105 @@
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+#include <lib9.h>
+
+static struct {
+	int sig;
+	char *str;
+} tab[] = {
+	SIGHUP,		"hangup",
+	SIGINT,		"interrupt",
+	SIGQUIT,		"quit",
+	SIGILL,		"sys: trap: illegal instruction",
+	SIGTRAP,		"sys: trace trap",
+	SIGABRT,		"sys: abort",
+#ifdef SIGEMT
+	SIGEMT,		"sys: emulate instruction executed",
+#endif
+	SIGFPE,		"sys: fp: trap",
+	SIGKILL,		"sys: kill",
+	SIGBUS,		"sys: bus error",
+	SIGSEGV,		"sys: segmentation violation",
+	SIGALRM,		"alarm",
+	SIGTERM,		"kill",
+	SIGURG,		"sys: urgent condition on socket",
+	SIGSTOP,		"sys: stop",
+	SIGTSTP,		"sys: tstp",
+	SIGCONT,		"sys: cont",
+	SIGCHLD,		"sys: child",
+	SIGTTIN,		"sys: ttin",
+	SIGTTOU,		"sys: ttou",
+	SIGIO,		"sys: i/o possible on fd",
+	SIGXCPU,		"sys: cpu time limit exceeded",
+	SIGXFSZ,		"sys: file size limit exceeded",
+	SIGVTALRM,	"sys: virtual time alarm",
+	SIGPROF,		"sys: profiling timer alarm",
+	SIGWINCH,	"sys: window size change",
+#ifdef SIGINFO
+	SIGINFO,		"sys: status request",
+#endif
+	SIGUSR1,		"sys: usr1",
+	SIGUSR2,		"sys: usr2",
+};
+	
+static char*
+_p9sigstr(int sig, char *tmp)
+{
+	int i;
+
+	for(i=0; i<nelem(tab); i++)
+		if(tab[i].sig == sig)
+			return tab[i].str;
+	sprint(tmp, "sys: signal %d", sig);
+	return tmp;
+}
+
+/*
+static int
+_p9strsig(char *s)
+{
+	int i;
+
+	for(i=0; i<nelem(tab); i++)
+		if(strcmp(s, tab[i].str) == 0)
+			return tab[i].sig;
+	return 0;
+}
+*/
+
+int
+await(char *str, int n)
+{
+	int pid, status, cd;
+	struct rusage ru;
+	char buf[128], tmp[64];
+	ulong u, s;
+
+	for(;;){
+		pid = wait3(&status, 0, &ru);
+		if(pid < 0)
+			return -1;
+		u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
+		s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
+		if(WIFEXITED(status)){
+			status = WEXITSTATUS(status);
+			if(status)
+				snprint(buf, sizeof buf, "%d %lu %lu %lu %d", pid, u, s, u+s, status);
+			else
+				snprint(buf, sizeof buf, "%d %lu %lu %lu ''", pid, u, s, u+s);
+			strecpy(str, str+n, buf);
+			return strlen(str);
+		}
+		if(WIFSIGNALED(status)){
+			cd = WCOREDUMP(status);
+			USED(cd);
+			snprint(buf, sizeof buf, "%d %lu %lu %lu '%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp));
+			strecpy(str, str+n, buf);
+			return strlen(str);
+		}
+	}
+}
blob - /dev/null
blob + 9a5cbfc4eed326745255212c85d18b1807fe1ad6 (mode 644)
--- /dev/null
+++ src/lib9/encodefmt.c
@@ -0,0 +1,69 @@
+#include <lib9.h>
+
+int
+encodefmt(Fmt *f)
+{
+	char *out;
+	char *buf;
+	int len;
+	int ilen;
+	int rv;
+	uchar *b;
+	char obuf[64];	// rsc optimization
+
+	if(!(f->flags&FmtPrec) || f->prec < 1)
+		goto error;
+
+	b = va_arg(f->args, uchar*);
+
+	ilen = f->prec;
+	f->prec = 0;
+	f->flags &= ~FmtPrec;
+	switch(f->r){
+	case '<':
+		len = (8*ilen+4)/5 + 3;
+		break;
+	case '[':
+		len = (8*ilen+5)/6 + 4;
+		break;
+	case 'H':
+		len = 2*ilen + 1;
+		break;
+	default:
+		goto error;
+	}
+
+	if(len > sizeof(obuf)){
+		buf = malloc(len);
+		if(buf == nil)
+			goto error;
+	} else
+		buf = obuf;
+
+	// convert
+	out = buf;
+	switch(f->r){
+	case '<':
+		rv = enc32(out, len, b, ilen);
+		break;
+	case '[':
+		rv = enc64(out, len, b, ilen);
+		break;
+	case 'H':
+		rv = enc16(out, len, b, ilen);
+		break;
+	default:
+		rv = -1;
+		break;
+	}
+	if(rv < 0)
+		goto error;
+
+	fmtstrcpy(f, buf);
+	if(buf != obuf)
+		free(buf);
+	return 0;
+
+error:
+	return fmtstrcpy(f, "<encodefmt>");
+}
blob - /dev/null
blob + e576b12bcfd98fde5c800ae68d3a43f4cdca2255 (mode 644)
--- /dev/null
+++ src/lib9/errstr.c
@@ -0,0 +1,68 @@
+/*
+ * We assume there's only one error buffer for the whole system.
+ * If you use ffork, you need to provide a _syserrstr.  Since most
+ * people will use libthread (which provides a _syserrstr), this is
+ * okay.
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <lib9.h>
+
+enum
+{
+	EPLAN9 = 0x19283745,
+};
+
+char *(*_syserrstr)(void);
+static char xsyserr[ERRMAX];
+static char*
+getsyserr(void)
+{
+	char *s;
+
+	s = nil;
+	if(_syserrstr)
+		s = (*_syserrstr)();
+	if(s == nil)
+		s = xsyserr;
+	return s;
+}
+
+int
+errstr(char *err, uint n)
+{
+	char tmp[ERRMAX];
+	char *syserr;
+
+	syserr = getsyserr();
+	if(errno != EPLAN9)
+		strcpy(syserr, strerror(errno));
+
+	strecpy(tmp, tmp+ERRMAX, syserr);
+	strecpy(syserr, syserr+ERRMAX, err);
+	strecpy(err, err+n, tmp);
+	errno = EPLAN9;
+	return 0;
+}
+
+void
+rerrstr(char *err, uint n)
+{
+	char *syserr;
+
+	syserr = getsyserr();
+	if(errno != EPLAN9)
+		strcpy(syserr, strerror(errno));
+	strecpy(err, err+n, syserr);
+}
+
+/* replaces __errfmt in libfmt */
+
+int
+__errfmt(Fmt *f)
+{
+	if(errno == EPLAN9)
+		return fmtstrcpy(f, getsyserr());
+	return fmtstrcpy(f, strerror(errno));
+}
blob - /dev/null
blob + a449f68e67de2f1414681101cd55be3ad924743e (mode 644)
--- /dev/null
+++ src/lib9/exits.c
@@ -0,0 +1,10 @@
+#include <lib9.h>
+
+void
+exits(char *s)
+{
+	if(s && *s)
+		exit(1);
+	exit(0);
+}
+
blob - /dev/null
blob + a7c82e64f738cdf70832c9be47174caf41825ef9 (mode 644)
--- /dev/null
+++ src/lib9/ffork-FreeBSD.c
@@ -0,0 +1,33 @@
+#include <lib9.h>
+
+extern int __isthreaded;
+int
+ffork(int flags, void(*fn)(void*), void *arg)
+{
+	void *p;
+
+	__isthreaded = 1;
+	p = malloc(16384);
+	if(p == nil)
+		return -1;
+	memset(p, 0xFE, 16384);
+	return rfork_thread(RFPROC|flags, (char*)p+16000, (int(*)(void*))fn, arg);
+}
+
+/*
+ * For FreeBSD libc.
+ */
+
+typedef struct {
+	volatile long	access_lock;
+	volatile long	lock_owner;
+	volatile char	*fname;
+	volatile int	lineno;
+} spinlock_t;
+
+void
+_spinlock(spinlock_t *lk)
+{
+	lock((Lock*)&lk->access_lock);
+}
+
blob - /dev/null
blob + aad80041b642d79660e98eca92d1d26c9a7a74c4 (mode 644)
--- /dev/null
+++ src/lib9/ffork-Linux.c
@@ -0,0 +1,39 @@
+#include <sched.h>
+#include <signal.h>
+#include <lib9.h>
+
+int fforkstacksize = 16384;
+
+int
+ffork(int flags, void (*fn)(void*), void *arg)
+{
+	char *p;
+	int cloneflag, pid;
+
+	p = malloc(fforkstacksize);
+	if(p == nil)
+		return -1;
+	cloneflag = 0;
+	flags &= ~RFPROC;
+	if(flags&RFMEM){
+		cloneflag |= CLONE_VM;
+		flags &= ~RFMEM;
+	}
+	if(!(flags&RFFDG))
+		cloneflag |= CLONE_FILES;
+	else
+		flags &= ~RFFDG;
+	if(!(flags&RFNOWAIT))
+		cloneflag |= SIGCHLD;
+	else
+		flags &= ~RFNOWAIT;
+	if(flags){
+		fprint(2, "unknown rfork flags %x\n", flags);
+		return -1;
+	}
+	pid = clone((int(*)(void*))fn, p+fforkstacksize-16, cloneflag, arg);
+	if(pid < 0)
+		free(p);
+	return pid;
+}
+
blob - /dev/null
blob + 1367370e93737504e23f9d9460166ea770c27887 (mode 644)
--- /dev/null
+++ src/lib9/getcallerpc-386.c
@@ -0,0 +1,7 @@
+#include <lib9.h>
+
+ulong
+getcallerpc(void *x)
+{
+	return (((ulong*)(x))[-1]);
+}
blob - /dev/null
blob + 79f7abad38365c5be3ddba15cae77107071cdfc3 (mode 644)
--- /dev/null
+++ src/lib9/getfields.c
@@ -0,0 +1,36 @@
+#include <lib9.h>
+
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+	Rune r;
+	int nr, intok, narg;
+
+	if(max <= 0)
+		return 0;
+
+	narg = 0;
+	args[narg] = str;
+	if(!mflag)
+		narg++;
+	intok = 0;
+	for(;; str += nr) {
+		nr = chartorune(&r, str);
+		if(r == 0)
+			break;
+		if(utfrune(set, r)) {
+			if(narg >= max)
+				break;
+			*str = 0;
+			intok = 0;
+			args[narg] = str + nr;
+			if(!mflag)
+				narg++;
+		} else {
+			if(!intok && mflag)
+				narg++;
+			intok = 1;
+		}
+	}
+	return narg;
+}
blob - /dev/null
blob + bb7e5404712c5d84ab48919e8954d924d64edfb7 (mode 644)
--- /dev/null
+++ src/lib9/lib9.h
@@ -0,0 +1,246 @@
+/*
+ * 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 _LIB9H_
+#define _LIB9H_ 1
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+                                                                                
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#ifndef _FMTH_
+#	include <fmt.h>
+#endif
+
+#define	nil	((void*)0)
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
+
+#define _NEEDUCHAR 1
+#define _NEEDUSHORT 1
+#define _NEEDUINT 1
+#define _NEEDULONG 1
+
+#if defined(__linux__)
+#	include <sys/types.h>
+#	if defined(__USE_MISC)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#		undef _NEEDULONG
+#	endif
+#endif
+#if defined(__FreeBSD__)
+#	include <sys/types.h>
+#	if !defined(_POSIX_SOURCE)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#	endif
+#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;
+
+/* rfork to create new process running fn(arg) */
+
+#if defined(__FreeBSD__)
+#undef RFFDG
+#undef RFNOTEG
+#undef RFPROC
+#undef RFMEM
+#undef RFNOWAIT
+#undef RFCFDG
+#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*);
+
+/* wait for processes */
+#define wait _p9wait
+typedef struct Waitmsg Waitmsg;
+struct Waitmsg
+{
+	int pid;	/* of loved one */
+	ulong time[3];	/* of loved one & descendants */
+	char	*msg;
+};
+extern	int		await(char*, int);
+extern	Waitmsg*	wait(void);
+
+/* synchronization */
+typedef struct Lock Lock;
+struct Lock
+{
+	int val;
+};
+
+extern int		_tas(void*);
+extern void	lock(Lock*);
+extern void	unlock(Lock*);
+extern int		canlock(Lock*);
+
+typedef struct QLp QLp;
+struct QLp
+{
+	int		inuse;
+	QLp		*next;
+	int		state;
+};
+
+typedef struct QLock QLock;
+struct QLock
+{
+	Lock	lock;
+	int		locked;
+	QLp		*head;
+	QLp		*tail;
+};
+
+extern void	qlock(QLock*);
+extern void	qunlock(QLock*);
+extern int		canqlock(QLock*);
+extern void	_qlockinit(ulong (*)(ulong, ulong));
+
+typedef struct RWLock RWLock;
+struct RWLock
+{
+	Lock	lock;
+	int		readers;
+	int		writer;
+	QLp		*head;
+	QLp		*tail;
+};
+
+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 Rendez;
+struct Rendez
+{
+	QLock	*l;
+	QLp		*head;
+	QLp		*tail;
+};
+
+extern void	rsleep(Rendez*);
+extern int		rwakeup(Rendez*);
+extern int		rwakeupall(Rendez*);
+
+extern ulong	rendezvous(ulong, ulong);
+
+/* one of a kind */
+extern void	sysfatal(char*, ...);
+extern int		nrand(int);
+extern void	setmalloctag(void*, ulong);
+extern void	setrealloctag(void*, ulong);
+extern void	*mallocz(ulong, int);
+extern long	readn(int, void*, long);
+extern void	exits(char*);
+extern void	_exits(char*);
+extern ulong	getcallerpc(void*);
+
+/* string routines */
+extern char*	strecpy(char*, char*, char*);
+extern int		tokenize(char*, char**, int);
+extern int		cistrncmp(char*, char*, int);
+extern int		cistrcmp(char*, char*);
+extern char*	cistrstr(char*, char*);
+extern int		getfields(char*, char**, int, int, char*);
+extern int		gettokens(char *, char **, int, char *);
+
+/* formatting helpers */
+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*);
+
+/* error string */
+enum
+{
+	ERRMAX = 128
+};
+extern void	rerrstr(char*, uint);
+extern void	werrstr(char*, ...);
+extern int		errstr(char*, uint);
+
+/* compiler directives on plan 9 */
+#define	USED(x)	if(x){}else{}
+#define	SET(x)	((x)=0)
+
+/* command line */
+extern char	*argv0;
+#define	ARGBEGIN	for((argv0||(argv0=*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
+
+#define OREAD O_RDONLY
+#define OWRITE O_WRONLY
+#define AEXIST 0
+#define AREAD 4
+#define AWRITE 2
+#define AEXEC 1
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif	/* _LIB9H_ */
blob - /dev/null
blob + 2da736267cbb850d21146c975baea983fcd9d76c (mode 644)
--- /dev/null
+++ src/lib9/lock.c
@@ -0,0 +1,54 @@
+#include <unistd.h>
+#include <sched.h>
+#include <lib9.h>
+
+int _ntas;
+static int
+_xtas(void *v)
+{
+	int x;
+
+_ntas++;
+	x = _tas(v);
+	if(x == 0 || x == 0xCAFEBABE)
+		return x;
+	fprint(2, "%d: tas %p got %ux\n", getpid(), v, x);
+	abort();
+}
+
+int
+canlock(Lock *l)
+{
+	return !_xtas(&l->val);
+}
+
+void
+unlock(Lock *l)
+{
+	l->val = 0;
+}
+
+void
+lock(Lock *lk)
+{
+	int i;
+
+	/* once fast */
+	if(!_xtas(&lk->val))
+		return;
+	/* a thousand times pretty fast */
+	for(i=0; i<1000; i++){
+		if(!_xtas(&lk->val))
+			return;
+		sched_yield();
+	}
+	/* now nice and slow */
+	for(i=0; i<1000; i++){
+		if(!_xtas(&lk->val))
+			return;
+		usleep(100*1000);
+	}
+	/* take your time */
+	while(_xtas(&lk->val))
+		usleep(1000*1000);
+}
blob - /dev/null
blob + e5682bc72bb7d7a7522fc052ef856898d653607c (mode 644)
--- /dev/null
+++ src/lib9/malloctag.c
@@ -0,0 +1,15 @@
+#include <lib9.h>
+
+void
+setmalloctag(void *v, ulong t)
+{
+	USED(v);
+	USED(t);
+}
+
+void
+setrealloctag(void *v, ulong t)
+{
+	USED(v);
+	USED(t);
+}
blob - /dev/null
blob + c631300887cd2d5adf3062f6c7e7a979717a5926 (mode 644)
--- /dev/null
+++ src/lib9/mallocz.c
@@ -0,0 +1,14 @@
+#include <unistd.h>
+#include <string.h>
+#include <lib9.h>
+
+void*
+mallocz(unsigned long n, int clr)
+{
+	void *v;
+
+	v = malloc(n);
+	if(clr && v)
+		memset(v, 0, n);
+	return v;
+}
blob - /dev/null
blob + 703f6b06d8e3b134af7b4f1b01b739e1b5a86593 (mode 644)
--- /dev/null
+++ src/lib9/mkfile
@@ -0,0 +1,2 @@
+<../libutf/mkfile
+
blob - /dev/null
blob + cf9c17c33fbe023951892a063117438ff409b9b0 (mode 644)
--- /dev/null
+++ src/lib9/nrand.c
@@ -0,0 +1,17 @@
+#include <lib9.h>
+
+#define	MASK	0x7fffffffL
+
+int
+nrand(int n)
+{
+	long slop, v;
+
+	if(n < 0)
+		return n;
+	slop = MASK % n;
+	do
+		v = lrand();
+	while(v <= slop);
+	return v % n;
+}
blob - /dev/null
blob + 55a18466c0b794fc3bd1e10bc43d0155ecabbd43 (mode 644)
--- /dev/null
+++ src/lib9/qlock.c
@@ -0,0 +1,360 @@
+#include <lib9.h>
+
+static struct {
+	QLp	*p;
+	QLp	x[1024];
+} ql = {
+	ql.x
+};
+
+enum
+{
+	Queuing,
+	QueuingR,
+	QueuingW,
+	Sleeping,
+};
+
+static ulong	(*_rendezvousp)(ulong, ulong) = rendezvous;
+
+/* this gets called by the thread library ONLY to get us to use its rendezvous */
+void
+_qlockinit(ulong (*r)(ulong, ulong))
+{
+	_rendezvousp = r;
+}
+
+/* find a free shared memory location to queue ourselves in */
+static QLp*
+getqlp(void)
+{
+	QLp *p, *op;
+
+	op = ql.p;
+	for(p = op+1; ; p++){
+		if(p == &ql.x[nelem(ql.x)])
+			p = ql.x;
+		if(p == op)
+			abort();
+		if(_tas(&(p->inuse)) == 0){
+			ql.p = p;
+			p->next = nil;
+			break;
+		}
+	}
+	return p;
+}
+
+void
+qlock(QLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(!q->locked){
+		q->locked = 1;
+		unlock(&q->lock);
+		return;
+	}
+
+
+	/* chain into waiting list */
+	mp = getqlp();
+	p = q->tail;
+	if(p == nil)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->state = Queuing;
+	unlock(&q->lock);
+
+	/* wait */
+	while((*_rendezvousp)((ulong)mp, 1) == ~0)
+		;
+	mp->inuse = 0;
+}
+
+void
+qunlock(QLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	p = q->head;
+	if(p != nil){
+		/* wakeup head waiting process */
+		q->head = p->next;
+		if(q->head == nil)
+			q->tail = nil;
+		unlock(&q->lock);
+		while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
+			;
+		return;
+	}
+	q->locked = 0;
+	unlock(&q->lock);
+}
+
+int
+canqlock(QLock *q)
+{
+	if(!canlock(&q->lock))
+		return 0;
+	if(!q->locked){
+		q->locked = 1;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+rlock(RWLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(q->writer == 0 && q->head == nil){
+		/* no writer, go for it */
+		q->readers++;
+		unlock(&q->lock);
+		return;
+	}
+
+	mp = getqlp();
+	p = q->tail;
+	if(p == 0)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->next = nil;
+	mp->state = QueuingR;
+	unlock(&q->lock);
+
+	/* wait in kernel */
+	while((*_rendezvousp)((ulong)mp, 1) == ~0)
+		;
+	mp->inuse = 0;
+}
+
+int
+canrlock(RWLock *q)
+{
+	lock(&q->lock);
+	if (q->writer == 0 && q->head == nil) {
+		/* no writer; go for it */
+		q->readers++;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+runlock(RWLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	if(q->readers <= 0)
+		abort();
+	p = q->head;
+	if(--(q->readers) > 0 || p == nil){
+		unlock(&q->lock);
+		return;
+	}
+
+	/* start waiting writer */
+	if(p->state != QueuingW)
+		abort();
+	q->head = p->next;
+	if(q->head == 0)
+		q->tail = 0;
+	q->writer = 1;
+	unlock(&q->lock);
+
+	/* wakeup waiter */
+	while((*_rendezvousp)((ulong)p, 0) == ~0)
+		;
+}
+
+void
+wlock(RWLock *q)
+{
+	QLp *p, *mp;
+
+	lock(&q->lock);
+	if(q->readers == 0 && q->writer == 0){
+		/* noone waiting, go for it */
+		q->writer = 1;
+		unlock(&q->lock);
+		return;
+	}
+
+	/* wait */
+	p = q->tail;
+	mp = getqlp();
+	if(p == nil)
+		q->head = mp;
+	else
+		p->next = mp;
+	q->tail = mp;
+	mp->next = nil;
+	mp->state = QueuingW;
+	unlock(&q->lock);
+
+	/* wait in kernel */
+	while((*_rendezvousp)((ulong)mp, 1) == ~0)
+		;
+	mp->inuse = 0;
+}
+
+int
+canwlock(RWLock *q)
+{
+	lock(&q->lock);
+	if (q->readers == 0 && q->writer == 0) {
+		/* no one waiting; go for it */
+		q->writer = 1;
+		unlock(&q->lock);
+		return 1;
+	}
+	unlock(&q->lock);
+	return 0;
+}
+
+void
+wunlock(RWLock *q)
+{
+	QLp *p;
+
+	lock(&q->lock);
+	if(q->writer == 0)
+		abort();
+	p = q->head;
+	if(p == nil){
+		q->writer = 0;
+		unlock(&q->lock);
+		return;
+	}
+	if(p->state == QueuingW){
+		/* start waiting writer */
+		q->head = p->next;
+		if(q->head == nil)
+			q->tail = nil;
+		unlock(&q->lock);
+		while((*_rendezvousp)((ulong)p, 0) == ~0)
+			;
+		return;
+	}
+
+	if(p->state != QueuingR)
+		abort();
+
+	/* wake waiting readers */
+	while(q->head != nil && q->head->state == QueuingR){
+		p = q->head;
+		q->head = p->next;
+		q->readers++;
+		while((*_rendezvousp)((ulong)p, 0) == ~0)
+			;
+	}
+	if(q->head == nil)
+		q->tail = nil;
+	q->writer = 0;
+	unlock(&q->lock);
+}
+
+void
+rsleep(Rendez *r)
+{
+	QLp *t, *me;
+
+	if(!r->l)
+		abort();
+	lock(&r->l->lock);
+	/* we should hold the qlock */
+	if(!r->l->locked)
+		abort();
+
+	/* add ourselves to the wait list */
+	me = getqlp();
+	me->state = Sleeping;
+	if(r->head == nil)
+		r->head = me;
+	else
+		r->tail->next = me;
+	me->next = nil;
+	r->tail = me;
+
+	/* pass the qlock to the next guy */
+	t = r->l->head;
+	if(t){
+		r->l->head = t->next;
+		if(r->l->head == nil)
+			r->l->tail = nil;
+		unlock(&r->l->lock);
+		while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
+			;
+	}else{
+		r->l->locked = 0;
+		unlock(&r->l->lock);
+	}
+
+	/* wait for a wakeup */
+	while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
+		;
+	me->inuse = 0;
+	if(!r->l->locked)
+		abort();
+}
+
+int
+rwakeup(Rendez *r)
+{
+	QLp *t;
+
+	/*
+	 * take off wait and put on front of queue
+	 * put on front so guys that have been waiting will not get starved
+	 */
+	
+	if(!r->l)
+		abort();
+	lock(&r->l->lock);
+	if(!r->l->locked)
+		abort();
+
+	t = r->head;
+	if(t == nil){
+		unlock(&r->l->lock);
+		return 0;
+	}
+
+	r->head = t->next;
+	if(r->head == nil)
+		r->tail = nil;
+
+	t->next = r->l->head;
+	r->l->head = t;
+	if(r->l->tail == nil)
+		r->l->tail = t;
+
+	t->state = Queuing;
+	unlock(&r->l->lock);
+	return 1;
+}
+
+int
+rwakeupall(Rendez *r)
+{
+	int i;
+
+	for(i=0; rwakeup(r); i++)
+		;
+	return i;
+}
blob - /dev/null
blob + 34f77ecaaff6385c732fce5e697f1013907bc260 (mode 644)
--- /dev/null
+++ src/lib9/rand.c
@@ -0,0 +1,89 @@
+#include	<lib9.h>
+
+/*
+ *	algorithm by
+ *	D. P. Mitchell & J. A. Reeds
+ */
+
+#define	LEN	607
+#define	TAP	273
+#define	MASK	0x7fffffffL
+#define	A	48271
+#define	M	2147483647
+#define	Q	44488
+#define	R	3399
+#define	NORM	(1.0/(1.0+MASK))
+
+static	ulong	rng_vec[LEN];
+static	ulong*	rng_tap = rng_vec;
+static	ulong*	rng_feed = 0;
+static	Lock	lk;
+
+static void
+isrand(long seed)
+{
+	long lo, hi, x;
+	int i;
+
+	rng_tap = rng_vec;
+	rng_feed = rng_vec+LEN-TAP;
+	seed = seed%M;
+	if(seed < 0)
+		seed += M;
+	if(seed == 0)
+		seed = 89482311;
+	x = seed;
+	/*
+	 *	Initialize by x[n+1] = 48271 * x[n] mod (2**31 - 1)
+	 */
+	for(i = -20; i < LEN; i++) {
+		hi = x / Q;
+		lo = x % Q;
+		x = A*lo - R*hi;
+		if(x < 0)
+			x += M;
+		if(i >= 0)
+			rng_vec[i] = x;
+	}
+}
+
+void
+srand(long seed)
+{
+	lock(&lk);
+	isrand(seed);
+	unlock(&lk);
+}
+
+long
+lrand(void)
+{
+	ulong x;
+
+	lock(&lk);
+
+	rng_tap--;
+	if(rng_tap < rng_vec) {
+		if(rng_feed == 0) {
+			isrand(1);
+			rng_tap--;
+		}
+		rng_tap += LEN;
+	}
+	rng_feed--;
+	if(rng_feed < rng_vec)
+		rng_feed += LEN;
+	x = (*rng_feed + *rng_tap) & MASK;
+	*rng_feed = x;
+
+	unlock(&lk);
+
+	return x;
+}
+
+int
+rand(void)
+{
+	return lrand() & 0x7fff;
+}
+
blob - /dev/null
blob + e7b9d138b32d41bb50e0e1ccdcefa3e1ef77729e (mode 644)
--- /dev/null
+++ src/lib9/readn.c
@@ -0,0 +1,21 @@
+#include <lib9.h>
+
+long
+readn(int f, void *av, long n)
+{
+	char *a;
+	long m, t;
+
+	a = av;
+	t = 0;
+	while(t < n){
+		m = read(f, a+t, n-t);
+		if(m <= 0){
+			if(t == 0)
+				return m;
+			break;
+		}
+		t += m;
+	}
+	return t;
+}
blob - /dev/null
blob + 320bd11af47826c2ec6cb8521a17eb09fe841ba1 (mode 644)
--- /dev/null
+++ src/lib9/rendez.c
@@ -0,0 +1,180 @@
+/*
+     NAME
+          rendezvous - user level process synchronization
+
+     SYNOPSIS
+          ulong rendezvous(ulong tag, ulong value)
+
+     DESCRIPTION
+          The rendezvous system call allows two processes to synchro-
+          nize and exchange a value.  In conjunction with the shared
+          memory system calls (see segattach(2) and fork(2)), it
+          enables parallel programs to control their scheduling.
+
+          Two processes wishing to synchronize call rendezvous with a
+          common tag, typically an address in memory they share.  One
+          process will arrive at the rendezvous first; it suspends
+          execution until a second arrives.  When a second process
+          meets the rendezvous the value arguments are exchanged
+          between the processes and returned as the result of the
+          respective rendezvous system calls.  Both processes are
+          awakened when the rendezvous succeeds.
+
+          The set of tag values which two processes may use to
+          rendezvous-their tag space-is inherited when a process
+          forks, unless RFREND is set in the argument to rfork; see
+          fork(2).
+
+          If a rendezvous is interrupted the return value is ~0, so
+          that value should not be used in normal communication.
+
+ * This simulates rendezvous with shared memory, pause, and SIGUSR1.
+ */
+
+#include <signal.h>
+#include <lib9.h>
+
+enum
+{
+	VOUSHASH = 257,
+};
+
+typedef struct Vous Vous;
+struct Vous
+{
+	Vous *link;
+	Lock lk;
+	int pid;
+	ulong val;
+	ulong tag;
+};
+
+static void
+ign(int x)
+{
+	USED(x);
+}
+
+void /*__attribute__((constructor))*/
+ignusr1(void)
+{
+	signal(SIGUSR1, ign);
+}
+
+static Vous vouspool[2048];
+static int nvousused;
+static Vous *vousfree;
+static Vous *voushash[VOUSHASH];
+static Lock vouslock;
+
+static Vous*
+getvous(void)
+{
+	Vous *v;
+
+	if(vousfree){
+		v = vousfree;
+		vousfree = v->link;
+	}else if(nvousused < nelem(vouspool))
+		v = &vouspool[nvousused++];
+	else
+		abort();
+	return v;
+}
+
+static void
+putvous(Vous *v)
+{
+	lock(&vouslock);
+	v->link = vousfree;
+	vousfree = v;
+	unlock(&vouslock);
+}
+
+static Vous*
+findvous(ulong tag, ulong val, int pid)
+{
+	int h;
+	Vous *v, **l;
+
+	lock(&vouslock);
+	h = tag%VOUSHASH;
+	for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){
+		if(v->tag == tag){
+			*l = v->link;
+			unlock(&vouslock);
+			return v;
+		}
+	}
+	v = getvous();
+	v->pid = pid;
+	v->link = voushash[h];
+	v->val = val;
+	v->tag = tag;
+	lock(&v->lk);
+	voushash[h] = v;
+	unlock(&vouslock);
+	return v;
+}
+
+#define DBG 0
+ulong
+rendezvous(ulong tag, ulong val)
+{
+	int me, vpid;
+	ulong rval;
+	Vous *v;
+	sigset_t mask;
+
+	me = getpid();
+	v = findvous(tag, val, me);
+	if(v->pid == me){
+		if(DBG)fprint(2, "pid is %d tag %lux, sleeping\n", me, tag);
+		/*
+		 * No rendezvous partner was found; the next guy
+		 * through will find v and wake us, so we must go
+		 * to sleep.
+		 *
+		 * To go to sleep:
+		 *	1. disable USR1 signals.
+		 *	2. unlock v->lk (tells waker okay to signal us).
+		 *	3. atomically suspend and enable USR1 signals.
+		 *
+		 * The call to ignusr1() could be done once at 
+		 * process creation instead of every time through rendezvous.
+		 */
+		v->val = val;
+		ignusr1();
+		sigprocmask(SIG_SETMASK, NULL, &mask);
+		sigaddset(&mask, SIGUSR1);
+		sigprocmask(SIG_SETMASK, &mask, NULL);
+		sigdelset(&mask, SIGUSR1);
+		unlock(&v->lk);
+		sigsuspend(&mask);
+		rval = v->val;
+		if(DBG)fprint(2, "pid is %d, awake\n", me);
+		putvous(v);
+	}else{
+		/*
+		 * Found someone to meet.  Wake him:
+		 *
+		 *	A. lock v->lk (waits for him to get to his step 2)
+		 *	B. send a USR1
+		 *
+		 * He won't get the USR1 until he suspends, which
+		 * means it must wake him up (it can't get delivered
+		 * before he sleeps).
+		 */
+		vpid = v->pid;
+		lock(&v->lk);
+		rval = v->val;
+		v->val = val;
+		unlock(&v->lk);
+		if(kill(vpid, SIGUSR1) < 0){
+			if(DBG)fprint(2, "pid is %d, kill %d failed: %r\n", me, vpid);
+			abort();
+		}
+	}
+	return rval;
+}
+
blob - /dev/null
blob + 7d2f2277c3d69c104d121e00ea942015556a4e23 (mode 644)
--- /dev/null
+++ src/lib9/strecpy.c
@@ -0,0 +1,16 @@
+#include <lib9.h>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+	if(to >= e)
+		return to;
+	to = memccpy(to, from, '\0', e - to);
+	if(to == nil){
+		to = e - 1;
+		*to = '\0';
+	}else{
+		to--;
+	}
+	return to;
+}
blob - /dev/null
blob + f9ab69857f6937cc159358ee31fbaa07121afbab (mode 644)
--- /dev/null
+++ src/lib9/sysfatal.c
@@ -0,0 +1,20 @@
+#include <lib9.h>
+
+void (*_sysfatal)(char*, ...);
+
+void
+sysfatal(char *fmt, ...)
+{
+	char buf[256];
+	va_list arg;
+
+	va_start(arg, fmt);
+	if(_sysfatal)
+		(*_sysfatal)(fmt, arg);
+	vseprint(buf, buf+sizeof buf, fmt, arg);
+	va_end(arg);
+
+	fprint(2, "%s; %s\n", argv0 ? argv0 : "<prog>", buf);
+	exits("fatal");
+}
+
blob - /dev/null
blob + 7a62d2d32c3ac7c7da493b260ef704e99ff424f3 (mode 644)
--- /dev/null
+++ src/lib9/tas-386.s
@@ -0,0 +1,6 @@
+.globl _tas
+_tas:
+	movl $0xCAFEBABE, %eax
+	movl 4(%esp), %ecx
+	xchgl %eax, 0(%ecx)
+	ret
blob - /dev/null
blob + 3a358c6c933d450c8986dcae2e0c2c2c64f25dd3 (mode 644)
--- /dev/null
+++ src/lib9/test.c
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+int
+main(int argc, char **argv)
+{
+	werrstr("hello world");
+	print("%r\n");
+}
blob - /dev/null
blob + a5e637188df4b079e22d36f745171896ef4d3b93 (mode 644)
--- /dev/null
+++ src/lib9/testfork.c
@@ -0,0 +1,21 @@
+#include <lib9.h>
+
+void
+sayhi(void *v)
+{
+	USED(v);
+
+	print("hello from subproc\n");
+	print("rendez got %lu from main\n", rendezvous(0x1234, 1234));
+	exits(0);
+}
+
+int
+main(int argc, char **argv)
+{
+	print("hello from main\n");
+	ffork(RFMEM|RFPROC, sayhi, nil);
+
+	print("rendez got %lu from subproc\n", rendezvous(0x1234, 0));
+	exits(0);
+}
blob - /dev/null
blob + 6fa9fc7320b3d8fa51777a3af912286949ee4366 (mode 644)
--- /dev/null
+++ src/lib9/tokenize.c
@@ -0,0 +1,106 @@
+#include <lib9.h>
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+	int quoting;
+	char *t;
+
+	quoting = 0;
+	t = s;	/* s is output string, t is input string */
+	while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+		if(*t != '\''){
+			*s++ = *t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t++;
+		*s++ = *t++;
+	}
+	if(*s != '\0'){
+		*s = '\0';
+		if(t == s)
+			t++;
+	}
+	return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+	int quoting;
+
+	/* move to end of next token */
+	quoting = 0;
+	while(*t!='\0' && (quoting || utfrune(sep, *t)==nil)){
+		if(*t != '\''){
+			t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t += 2;
+	}
+	return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(sep, *s)!=nil)
+			*s++ = '\0';
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = etoken(s, sep);
+	}
+
+	return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(qsep, *s)!=nil)
+			s++;
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = qtoken(s, qsep);
+	}
+
+	return nargs;
+}
blob - /dev/null
blob + d9f41e462c2dc65a0e8fd3eca556fb2a82255874 (mode 644)
--- /dev/null
+++ src/lib9/u16.c
@@ -0,0 +1,52 @@
+#include <lib9.h>
+static char t16e[] = "0123456789ABCDEF";
+
+int
+dec16(uchar *out, int lim, char *in, int n)
+{
+	int c, w = 0, i = 0;
+	uchar *start = out;
+	uchar *eout = out + lim;
+
+	while(n-- > 0){
+		c = *in++;
+		if('0' <= c && c <= '9')
+			c = c - '0';
+		else if('a' <= c && c <= 'z')
+			c = c - 'a' + 10;
+		else if('A' <= c && c <= 'Z')
+			c = c - 'A' + 10;
+		else
+			continue;
+		w = (w<<4) + c;
+		i++;
+		if(i == 2){
+			if(out + 1 > eout)
+				goto exhausted;
+			*out++ = w;
+			w = 0;
+			i = 0;
+		}
+	}
+exhausted:
+	return out - start;
+}
+
+int
+enc16(char *out, int lim, uchar *in, int n)
+{
+	uint c;
+	char *eout = out + lim;
+	char *start = out;
+
+	while(n-- > 0){
+		c = *in++;
+		if(out + 2 >= eout)
+			goto exhausted;
+		*out++ = t16e[c>>4];
+		*out++ = t16e[c&0xf];
+	}
+exhausted:
+	*out = 0;
+	return out - start;
+}
blob - /dev/null
blob + 1eb0c6e048e830ce256280a2bd110f918ce71bbf (mode 644)
--- /dev/null
+++ src/lib9/u32.c
@@ -0,0 +1,109 @@
+#include <lib9.h>
+
+int
+dec32(uchar *dest, int ndest, char *src, int nsrc)
+{
+	char *s, *tab;
+	uchar *start;
+	int i, u[8];
+
+	if(ndest+1 < (5*nsrc+7)/8)
+		return -1;
+	start = dest;
+	tab = "23456789abcdefghijkmnpqrstuvwxyz";
+	while(nsrc>=8){
+		for(i=0; i<8; i++){
+			s = strchr(tab,(int)src[i]);
+			u[i] = s ? s-tab : 0;
+		}
+		*dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+		*dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+		*dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+		*dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+		*dest++ = ((0x7 & u[6])<<5) | u[7];
+		src  += 8;
+		nsrc -= 8;
+	}
+	if(nsrc > 0){
+		if(nsrc == 1 || nsrc == 3 || nsrc == 6)
+			return -1;
+		for(i=0; i<nsrc; i++){
+			s = strchr(tab,(int)src[i]);
+			u[i] = s ? s-tab : 0;
+		}
+		*dest++ = (u[0]<<3) | (0x7 & (u[1]>>2));
+		if(nsrc == 2)
+			goto out;
+		*dest++ = ((0x3 & u[1])<<6) | (u[2]<<1) | (0x1 & (u[3]>>4));
+		if(nsrc == 4)
+			goto out;
+		*dest++ = ((0xf & u[3])<<4) | (0xf & (u[4]>>1));
+		if(nsrc == 5)
+			goto out;
+		*dest++ = ((0x1 & u[4])<<7) | (u[5]<<2) | (0x3 & (u[6]>>3));
+	}
+out:
+	return dest-start;
+}
+
+int
+enc32(char *dest, int ndest, uchar *src, int nsrc)
+{
+	char *tab, *start;
+	int j;
+
+	if(ndest <= (8*nsrc+4)/5 )
+		return -1;
+	start = dest;
+	tab = "23456789abcdefghijkmnpqrstuvwxyz";
+	while(nsrc>=5){
+		j = (0x1f & (src[0]>>3));
+		*dest++ = tab[j];
+		j = (0x1c & (src[0]<<2)) | (0x03 & (src[1]>>6));
+		*dest++ = tab[j];
+		j = (0x1f & (src[1]>>1));
+		*dest++ = tab[j];
+		j = (0x10 & (src[1]<<4)) | (0x0f & (src[2]>>4));
+		*dest++ = tab[j];
+		j = (0x1e & (src[2]<<1)) | (0x01 & (src[3]>>7));
+		*dest++ = tab[j];
+		j = (0x1f & (src[3]>>2));
+		*dest++ = tab[j];
+		j = (0x18 & (src[3]<<3)) | (0x07 & (src[4]>>5));
+		*dest++ = tab[j];
+		j = (0x1f & (src[4]));
+		*dest++ = tab[j];
+		src  += 5;
+		nsrc -= 5;
+	}
+	if(nsrc){
+		j = (0x1f & (src[0]>>3));
+		*dest++ = tab[j];
+		j = (0x1c & (src[0]<<2));
+		if(nsrc == 1)
+			goto out;
+		j |= (0x03 & (src[1]>>6));
+		*dest++ = tab[j];
+		j = (0x1f & (src[1]>>1));
+		if(nsrc == 2)
+			goto out;
+		*dest++ = tab[j];
+		j = (0x10 & (src[1]<<4));
+		if(nsrc == 3)
+			goto out;
+		j |= (0x0f & (src[2]>>4));
+		*dest++ = tab[j];
+		j = (0x1e & (src[2]<<1));
+		if(nsrc == 4)
+			goto out;
+		j |= (0x01 & (src[3]>>7));
+		*dest++ = tab[j];
+		j = (0x1f & (src[3]>>2));
+		*dest++ = tab[j];
+		j = (0x18 & (src[3]<<3));
+out:
+		*dest++ = tab[j];
+	}
+	*dest = 0;
+	return dest-start;
+}
blob - /dev/null
blob + a17bdf1d579df9fb8367b7d2d7c0e667966dfe90 (mode 644)
--- /dev/null
+++ src/lib9/u64.c
@@ -0,0 +1,126 @@
+#include <lib9.h>
+
+enum {
+	INVAL=	255
+};
+
+static uchar t64d[256] = {
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,   62,INVAL,INVAL,INVAL,   63,
+      52,   53,   54,   55,   56,   57,   58,   59,   60,   61,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,    0,    1,    2,    3,    4,    5,    6,    7,    8,    9,   10,   11,   12,   13,   14,
+      15,   16,   17,   18,   19,   20,   21,   22,   23,   24,   25,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,   26,   27,   28,   29,   30,   31,   32,   33,   34,   35,   36,   37,   38,   39,   40,
+      41,   42,   43,   44,   45,   46,   47,   48,   49,   50,   51,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,
+   INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL,INVAL
+};
+static char t64e[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int
+dec64(uchar *out, int lim, char *in, int n)
+{
+	ulong b24;
+	uchar *start = out;
+	uchar *e = out + lim;
+	int i, c;
+
+	b24 = 0;
+	i = 0;
+	while(n-- > 0){
+ 
+		c = t64d[*(uchar*)in++];
+		if(c == INVAL)
+			continue;
+		switch(i){
+		case 0:
+			b24 = c<<18;
+			break;
+		case 1:
+			b24 |= c<<12;
+			break;
+		case 2:
+			b24 |= c<<6;
+			break;
+		case 3:
+			if(out + 3 > e)
+				goto exhausted;
+
+			b24 |= c;
+			*out++ = b24>>16;
+			*out++ = b24>>8;
+			*out++ = b24;
+			i = -1;
+			break;
+		}
+		i++;
+	}
+	switch(i){
+	case 2:
+		if(out + 1 > e)
+			goto exhausted;
+		*out++ = b24>>16;
+		break;
+	case 3:
+		if(out + 2 > e)
+			goto exhausted;
+		*out++ = b24>>16;
+		*out++ = b24>>8;
+		break;
+	}
+exhausted:
+	return out - start;
+}
+
+int
+enc64(char *out, int lim, uchar *in, int n)
+{
+	int i;
+	ulong b24;
+	char *start = out;
+	char *e = out + lim;
+
+	for(i = n/3; i > 0; i--){
+		b24 = (*in++)<<16;
+		b24 |= (*in++)<<8;
+		b24 |= *in++;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = t64e[(b24>>6)&0x3f];
+		*out++ = t64e[(b24)&0x3f];
+	}
+
+	switch(n%3){
+	case 2:
+		b24 = (*in++)<<16;
+		b24 |= (*in)<<8;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = t64e[(b24>>6)&0x3f];
+		*out++ = '=';
+		break;
+	case 1:
+		b24 = (*in)<<16;
+		if(out + 4 >= e)
+			goto exhausted;
+		*out++ = t64e[(b24>>18)];
+		*out++ = t64e[(b24>>12)&0x3f];
+		*out++ = '=';
+		*out++ = '=';
+		break;
+	}
+exhausted:
+	*out = 0;
+	return out - start;
+}
blob - /dev/null
blob + 14af715685be4051f7723d483389019a23d76750 (mode 644)
--- /dev/null
+++ src/lib9/wait.c
@@ -0,0 +1,30 @@
+#include <lib9.h>
+
+Waitmsg*
+wait(void)
+{
+	int n, l;
+	char buf[512], *fld[5];
+	Waitmsg *w;
+
+	n = await(buf, sizeof buf-1);
+	if(n < 0)
+		return nil;
+	buf[n] = '\0';
+	if(tokenize(buf, fld, nelem(fld)) != nelem(fld)){
+		werrstr("couldn't parse wait message");
+		return nil;
+	}
+	l = strlen(fld[4])+1;
+	w = malloc(sizeof(Waitmsg)+l);
+	if(w == nil)
+		return nil;
+	w->pid = atoi(fld[0]);
+	w->time[0] = atoi(fld[1]);
+	w->time[1] = atoi(fld[2]);
+	w->time[2] = atoi(fld[3]);
+	w->msg = (char*)&w[1];
+	memmove(w->msg, fld[4], l);
+	return w;
+}
+
blob - /dev/null
blob + 7fa1f2ea6dbcdb2dbfcbd9f4708be80fb9c3568c (mode 644)
--- /dev/null
+++ src/lib9/werrstr.c
@@ -0,0 +1,13 @@
+#include <lib9.h>
+
+void
+werrstr(char *fmt, ...)
+{
+	va_list arg;
+	char buf[ERRMAX];
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+ERRMAX, fmt, arg);
+	va_end(arg);
+	errstr(buf, ERRMAX);
+}
blob - /dev/null
blob + a5d7d87d79f0af66f7a5f54320edabb411b0e803 (mode 644)
--- /dev/null
+++ src/libbio/LICENSE
@@ -0,0 +1,258 @@
+The Plan 9 software is provided under the terms of the
+Lucent Public License, Version 1.02, reproduced below,
+with the following exceptions:
+
+1. No right is granted to create derivative works of or
+   to redistribute (other than with the Plan 9 Operating System)
+   the screen imprinter fonts identified in subdirectory
+   /lib/font/bit/lucida and printer fonts (Lucida Sans Unicode, Lucida
+   Sans Italic, Lucida Sans Demibold, Lucida Typewriter, Lucida Sans
+   Typewriter83), identified in subdirectory /sys/lib/postscript/font.
+   These directories contain material copyrights by B&H Inc. and Y&Y Inc.
+
+2. The printer fonts identified in subdirectory /sys/lib/ghostscript/font
+   are subject to the GNU GPL, reproduced in the file /LICENSE.gpl.
+
+3. The ghostscript program in the subdirectory /sys/src/cmd/gs is
+   covered by the Aladdin Free Public License, reproduced in the file
+   /LICENSE.afpl.
+
+===================================================================
+
+Lucent Public License Version 1.02
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
+     Program, and
+  b. in the case of each Contributor,
+
+     i. changes to the Program, and
+    ii. additions to the Program;
+
+    where such changes and/or additions to the Program were added to the
+    Program by such Contributor itself or anyone acting on such
+    Contributor's behalf, and the Contributor explicitly consents, in
+    accordance with Section 3C, to characterization of the changes and/or
+    additions as Contributions.
+
+"Contributor" means LUCENT and any other entity that has Contributed a
+Contribution to the Program.
+
+"Distributor" means a Recipient that distributes the Program,
+modifications to the Program, or any part thereof.
+
+"Licensed Patents" mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+
+"Original Program" means the original version of the software
+accompanying this Agreement as released by LUCENT, including source
+code, object code and documentation, if any.
+
+"Program" means the Original Program and Contributions or any part
+thereof
+
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free copyright
+    license to reproduce, prepare derivative works of, publicly display,
+    publicly perform, distribute and sublicense the Contribution of such
+    Contributor, if any, and such derivative works, in source code and
+    object code form.
+    
+ b. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free patent
+    license under Licensed Patents to make, use, sell, offer to sell,
+    import and otherwise transfer the Contribution of such Contributor, if
+    any, in source code and object code form. The patent license granted
+    by a Contributor shall also apply to the combination of the
+    Contribution of that Contributor and the Program if, at the time the
+    Contribution is added by the Contributor, such addition of the
+    Contribution causes such combination to be covered by the Licensed
+    Patents. The patent license granted by a Contributor shall not apply
+    to (i) any other combinations which include the Contribution, nor to
+    (ii) Contributions of other Contributors. No hardware per se is
+    licensed hereunder.
+    
+ c. Recipient understands that although each Contributor grants the
+    licenses to its Contributions set forth herein, no assurances are
+    provided by any Contributor that the Program does not infringe the
+    patent or other intellectual property rights of any other entity. Each
+    Contributor disclaims any liability to Recipient for claims brought by
+    any other entity based on infringement of intellectual property rights
+    or otherwise. As a condition to exercising the rights and licenses
+    granted hereunder, each Recipient hereby assumes sole responsibility
+    to secure any other intellectual property rights needed, if any. For
+    example, if a third party patent license is required to allow
+    Recipient to distribute the Program, it is Recipient's responsibility
+    to acquire that license before distributing the Program.
+
+ d. Each Contributor represents that to its knowledge it has sufficient
+    copyright rights in its Contribution, if any, to grant the copyright
+    license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A. Distributor may choose to distribute the Program in any form under
+this Agreement or under its own license agreement, provided that:
+
+ a. it complies with the terms and conditions of this Agreement;
+
+ b. if the Program is distributed in source code or other tangible
+    form, a copy of this Agreement or Distributor's own license agreement
+    is included with each copy of the Program; and
+
+ c. if distributed under Distributor's own license agreement, such
+    license agreement:
+
+      i. effectively disclaims on behalf of all Contributors all warranties
+         and conditions, express and implied, including warranties or
+         conditions of title and non-infringement, and implied warranties or
+         conditions of merchantability and fitness for a particular purpose;
+     ii. effectively excludes on behalf of all Contributors all liability
+         for damages, including direct, indirect, special, incidental and
+         consequential damages, such as lost profits; and
+    iii. states that any provisions which differ from this Agreement are
+         offered by that Contributor alone and not by any other party.
+
+B. Each Distributor must include the following in a conspicuous
+   location in the Program:
+
+   Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
+   Reserved.
+
+C. In addition, each Contributor must identify itself as the
+originator of its Contribution in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+Also, each Contributor must agree that the additions and/or changes
+are intended to be a Contribution. Once a Contribution is contributed,
+it may not thereafter be revoked.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use
+of the Program, the Distributor who includes the Program in a
+commercial product offering should do so in a manner which does not
+create potential liability for Contributors. Therefore, if a
+Distributor includes the Program in a commercial product offering,
+such Distributor ("Commercial Distributor") hereby agrees to defend
+and indemnify every Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively"Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the acts
+or omissions of such Commercial Distributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement.
+In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Distributor in writing of such claim, and b)
+allow the Commercial Distributor to control, and cooperate with the
+Commercial Distributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such
+claim at its own expense.
+
+For example, a Distributor might include the Program in a commercial
+product offering, Product X. That Distributor is then a Commercial
+Distributor. If that Commercial Distributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Distributor's responsibility
+alone. Under this section, the Commercial Distributor would have to
+defend claims against the Contributors related to those performance
+claims and warranties, and if a court requires any Contributor to pay
+any damages as a result, the Commercial Distributor must pay those
+damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement, including but not limited to
+the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. EXPORT CONTROL
+
+Recipient agrees that Recipient alone is responsible for compliance
+with the United States export administration regulations (and the
+export control laws and regulation of any other countries).
+
+8. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with
+respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that
+Contributor to such Recipient under this Agreement shall terminate as
+of the date such litigation is filed. In addition, if Recipient
+institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and
+survive.
+
+LUCENT may publish new versions (including revisions) of this
+Agreement from time to time. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to
+distribute the Program (including its Contributions) under the new
+version. No one other than LUCENT has the right to modify this
+Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property
+of any Contributor under this Agreement, whether expressly, by
+implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No
+party to this Agreement will bring a legal action under this Agreement
+more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.
+
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libbio/Make.FreeBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + edbdc111a2a0c008975e297c7ca60e46199397a9 (mode 644)
--- /dev/null
+++ src/libbio/Make.HP-UX-9000
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS=-O -c -Ae -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 74b0252c6eae6331b48ede7fcfa1ed760609d1a3 (mode 644)
--- /dev/null
+++ src/libbio/Make.Linux-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libbio/Make.NetBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 3d45279bba28dbe69c00f89568c444ab83a4ac72 (mode 644)
--- /dev/null
+++ src/libbio/Make.OSF1-alpha
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + c5fe67b82d86c731a56c101e522e804390e5bd5a (mode 644)
--- /dev/null
+++ src/libbio/Make.SunOS-sun4u
@@ -0,0 +1,2 @@
+include Make.SunOS-sun4u-$(CC)
+NAN=nan64.$O
blob - /dev/null
blob + 829301de8649d40632eb809ae512598af11d48c5 (mode 644)
--- /dev/null
+++ src/libbio/Make.SunOS-sun4u-cc
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I. -O
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 5c41594812a4a27eb848d384cbc356d206c0a44b (mode 644)
--- /dev/null
+++ src/libbio/Make.SunOS-sun4u-gcc
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 2d1a0caddce6eb56d1c146f26172368371fa2a42 (mode 644)
--- /dev/null
+++ src/libbio/Makefile
@@ -0,0 +1,108 @@
+
+# this works in gnu make
+SYSNAME:=${shell uname}
+OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
+
+# this works in bsd make
+SYSNAME!=uname
+OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
+
+# the gnu rules will mess up bsd but not vice versa,
+# hence the gnu rules come first.
+
+include Make.$(SYSNAME)-$(OBJTYPE)
+
+PREFIX=/usr/local
+
+NUKEFILES=
+
+TGZFILES=
+
+LIB=libbio.a
+VERSION=2.0
+PORTPLACE=devel/libbio
+NAME=libbio
+
+OFILES=\
+	bbuffered.$O\
+	bfildes.$O\
+	bflush.$O\
+	bgetc.$O\
+	bgetd.$O\
+	binit.$O\
+	boffset.$O\
+	bprint.$O\
+	bputc.$O\
+	brdline.$O\
+	brdstr.$O\
+	bread.$O\
+	bseek.$O\
+	bwrite.$O\
+	bgetrune.$O\
+	bputrune.$O\
+
+HFILES=\
+	bio.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	install -m 0644 bio.3 $(PREFIX)/man/man3/bio.3
+	install -m 0644 bio.h $(PREFIX)/include
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+bcat: bcat.$O $(LIB)
+	$(CC) -o bcat bcat.$O $(LIB) -L/usr/local/lib -lfmt -lutf
+
+$(LIB): $(OFILES)
+	$(AR) $(ARFLAGS) $(LIB) $(OFILES)
+
+NUKEFILES+=$(LIB)
+.c.$O:
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+%.$O: %.c
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+
+$(OFILES): $(HFILES)
+
+tgz:
+	rm -rf $(NAME)-$(VERSION)
+	mkdir $(NAME)-$(VERSION)
+	cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION)
+	tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz
+	rm -rf $(NAME)-$(VERSION)
+
+clean:
+	rm -f $(OFILES) $(LIB)
+
+nuke:
+	rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES)
+
+rpm:
+	make tgz
+	cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES
+	rpm -ba rpm.spec
+	cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm .
+	cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm .
+	scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software
+
+PORTDIR=/usr/ports/$(PORTPLACE)
+
+ports:
+	make tgz
+	rm -rf $(PORTDIR)
+	mkdir $(PORTDIR)
+	cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles
+	cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}')
+	(cd $(PORTDIR); make makesum)
+	(cd $(PORTDIR); make)
+	(cd $(PORTDIR); /usr/local/bin/portlint)
+	rm -rf $(PORTDIR)/work
+	shar `find $(PORTDIR)` > ports.shar
+	(cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz
+	scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software
+
+.phony: all clean nuke install tgz rpm ports
blob - /dev/null
blob + 610659ba9bf48c7a127e4a88f9924478747c70d5 (mode 644)
--- /dev/null
+++ src/libbio/Makefile.MID
@@ -0,0 +1,37 @@
+LIB=libbio.a
+VERSION=2.0
+PORTPLACE=devel/libbio
+NAME=libbio
+
+OFILES=\
+	bbuffered.$O\
+	bfildes.$O\
+	bflush.$O\
+	bgetc.$O\
+	bgetd.$O\
+	binit.$O\
+	boffset.$O\
+	bprint.$O\
+	bputc.$O\
+	brdline.$O\
+	brdstr.$O\
+	bread.$O\
+	bseek.$O\
+	bwrite.$O\
+	bgetrune.$O\
+	bputrune.$O\
+
+HFILES=\
+	bio.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	install -m 0644 bio.3 $(PREFIX)/man/man3/bio.3
+	install -m 0644 bio.h $(PREFIX)/include
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+bcat: bcat.$O $(LIB)
+	$(CC) -o bcat bcat.$O $(LIB) -L/usr/local/lib -lfmt -lutf
+
blob - /dev/null
blob + 9911f992adecbfd45ea14229ff7d354d2d925ab1 (mode 644)
--- /dev/null
+++ src/libbio/NOTICE
@@ -0,0 +1,27 @@
+Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+Portions Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk).  All rights reserved.
+Portions Copyright © 1997-1999 Vita Nuova Limited.  All rights reserved.
+Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Under a licence agreement with Lucent Technologies Inc. effective 1st March 2000,
+Vita Nuova Holdings Limited has the right to determine (within a specified scope)
+the form and content of sublicences for this software.
+
+Vita Nuova Holdings Limited now makes this software available as Free
+Software under the terms of the `GNU General Public LIcense, Version 2'
+(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for
+the full terms and conditions).  One of the conditions of that licence
+is that you must keep intact all notices that refer to that licence and to the absence of
+of any warranty: for this software, note that includes this NOTICE file in particular.
+  
+This suite of programs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+`GNU General Public License' for more details.
+
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices above.
blob - /dev/null
blob + 8efb3b63a9c3c009124c93aa6d3c5b636f495713 (mode 644)
--- /dev/null
+++ src/libbio/README
@@ -0,0 +1,7 @@
+This is a Unix port of the Plan 9 buffered I/O library,
+originally done for the Inferno operating system.
+
+Russ Cox repackaged this to build as a standalone
+Unix library.  Send comments about packaging to
+Russ Cox <rsc@post.harvard.edu>
+
blob - /dev/null
blob + dfc0cf5351844799e708ca50dd5622e0d26fe734 (mode 644)
--- /dev/null
+++ src/libbio/bbuffered.c
@@ -0,0 +1,20 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bbuffered(Biobuf *bp)
+{
+	switch(bp->state) {
+	case Bracteof:
+	case Bractive:
+		return -bp->icount;
+
+	case Bwactive:
+		return bp->bsize + bp->ocount;
+
+	case Binactive:
+		return 0;
+	}
+	fprint(2, "Bbuffered: unknown state %d\n", bp->state);
+	return 0;
+}
blob - /dev/null
blob + dea346a55c2125e7bbbe53fac960fc917fef5839 (mode 644)
--- /dev/null
+++ src/libbio/bcat.c
@@ -0,0 +1,42 @@
+#include <fmt.h>
+#include "bio.h"
+
+Biobuf bout;
+
+void
+bcat(Biobuf *b, char *name)
+{
+	char buf[1000];
+	int n;
+
+	while((n = Bread(b, buf, sizeof buf)) > 0){
+		if(Bwrite(&bout, buf, n) < 0)
+			fprint(2, "writing during %s: %r\n", name);
+	}
+	if(n < 0)
+		fprint(2, "reading %s: %r\n", name);	
+}
+
+int
+main(int argc, char **argv)
+{
+	int i;
+	Biobuf b, *bp;
+
+	Binit(&bout, 1, O_WRONLY);
+
+	if(argc == 1){
+		Binit(&b, 0, O_RDONLY);
+		bcat(&b, "<stdin>");
+	}else{
+		for(i=1; i<argc; i++){
+			if((bp = Bopen(argv[i], O_RDONLY)) == 0){
+				fprint(2, "Bopen %s: %r\n", argv[i]);
+				continue;
+			}
+			bcat(bp, argv[i]);
+			Bterm(bp);
+		}
+	}
+	exit(0);
+}
blob - /dev/null
blob + 5188180f8a9b9857c90c74897bcc8883cca05ac7 (mode 644)
--- /dev/null
+++ src/libbio/bfildes.c
@@ -0,0 +1,9 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bfildes(Biobuf *bp)
+{
+
+	return bp->fid;
+}
blob - /dev/null
blob + 0ab81267f3a7640926b3f6c6c01bb014f9a48589 (mode 644)
--- /dev/null
+++ src/libbio/bflush.c
@@ -0,0 +1,33 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bflush(Biobuf *bp)
+{
+	int n, c;
+
+	switch(bp->state) {
+	case Bwactive:
+		n = bp->bsize+bp->ocount;
+		if(n == 0)
+			return 0;
+		c = write(bp->fid, bp->bbuf, n);
+		if(n == c) {
+			bp->offset += n;
+			bp->ocount = -bp->bsize;
+			return 0;
+		}
+		bp->state = Binactive;
+		bp->ocount = 0;
+		break;
+
+	case Bracteof:
+		bp->state = Bractive;
+
+	case Bractive:
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+		return 0;
+	}
+	return Beof;
+}
blob - /dev/null
blob + 4c8ae90c9b626b05625924e3df58f317bd83155a (mode 644)
--- /dev/null
+++ src/libbio/bgetc.c
@@ -0,0 +1,52 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bgetc(Biobuf *bp)
+{
+	int i;
+
+loop:
+	i = bp->icount;
+	if(i != 0) {
+		bp->icount = i+1;
+		return bp->ebuf[i];
+	}
+	if(bp->state != Bractive) {
+		if(bp->state == Bracteof)
+			bp->state = Bractive;
+		return Beof;
+	}
+	/*
+	 * get next buffer, try to keep Bungetsize
+	 * characters pre-catenated from the previous
+	 * buffer to allow that many ungets.
+	 */
+	memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
+	i = read(bp->fid, bp->bbuf, bp->bsize);
+	bp->gbuf = bp->bbuf;
+	if(i <= 0) {
+		if(i < 0)
+			bp->state = Binactive;
+		return Beof;
+	}
+	if(i < bp->bsize) {
+		memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
+		bp->gbuf = bp->ebuf-i;
+	}
+	bp->icount = -i;
+	bp->offset += i;
+	goto loop;
+}
+
+int
+Bungetc(Biobuf *bp)
+{
+
+	if(bp->state == Bracteof)
+		bp->state = Bractive;
+	if(bp->state != Bractive)
+		return Beof;
+	bp->icount--;
+	return 1;
+}
blob - /dev/null
blob + e7dd305dcd65b5c004f103c18e7a480f6e6963bf (mode 644)
--- /dev/null
+++ src/libbio/bgetd.c
@@ -0,0 +1,36 @@
+#include "lib9.h"
+#include <bio.h>
+
+struct	bgetd
+{
+	Biobuf*	b;
+	int		eof;
+};
+
+static int
+Bgetdf(void *vp)
+{
+	int c;
+	struct bgetd *bg = vp;
+
+	c = Bgetc(bg->b);
+	if(c == Beof)
+		bg->eof = 1;
+	return c;
+}
+
+int
+Bgetd(Biobuf *bp, double *dp)
+{
+	double d;
+	struct bgetd b;
+
+	b.b = bp;
+	b.eof = 0;
+	d = fmtcharstod(Bgetdf, &b);
+	if(b.eof)
+		return -1;
+	Bungetc(bp);
+	*dp = d;
+	return 1;
+}
blob - /dev/null
blob + f1b065bcee408c25c163162aed6da34eb61cc815 (mode 644)
--- /dev/null
+++ src/libbio/bgetrune.c
@@ -0,0 +1,47 @@
+#include	"lib9.h"
+#include	<bio.h>
+#include	<utf.h>
+
+long
+Bgetrune(Biobuf *bp)
+{
+	int c, i;
+	Rune rune;
+	char str[4];
+
+	c = Bgetc(bp);
+	if(c < Runeself) {		/* one char */
+		bp->runesize = 1;
+		return c;
+	}
+	str[0] = c;
+
+	for(i=1;;) {
+		c = Bgetc(bp);
+		if(c < 0)
+			return c;
+		str[i++] = c;
+
+		if(fullrune(str, i)) {
+			bp->runesize = chartorune(&rune, str);
+			while(i > bp->runesize) {
+				Bungetc(bp);
+				i--;
+			}
+			return rune;
+		}
+	}
+}
+
+int
+Bungetrune(Biobuf *bp)
+{
+
+	if(bp->state == Bracteof)
+		bp->state = Bractive;
+	if(bp->state != Bractive)
+		return Beof;
+	bp->icount -= bp->runesize;
+	bp->runesize = 0;
+	return 1;
+}
blob - /dev/null
blob + d76168b7fdba8169c16f8c1c375e3c1b9a14dece (mode 644)
--- /dev/null
+++ src/libbio/binit.c
@@ -0,0 +1,142 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+enum
+{
+	MAXBUFS	= 20
+};
+
+static	Biobuf*	wbufs[MAXBUFS];
+static	int		atexitflag;
+
+static
+void
+batexit(void)
+{
+	Biobuf *bp;
+	int i;
+
+	for(i=0; i<MAXBUFS; i++) {
+		bp = wbufs[i];
+		if(bp != 0) {
+			wbufs[i] = 0;
+			Bflush(bp);
+		}
+	}
+}
+
+static
+void
+deinstall(Biobuf *bp)
+{
+	int i;
+
+	for(i=0; i<MAXBUFS; i++)
+		if(wbufs[i] == bp)
+			wbufs[i] = 0;
+}
+
+static
+void
+install(Biobuf *bp)
+{
+	int i;
+
+	deinstall(bp);
+	for(i=0; i<MAXBUFS; i++)
+		if(wbufs[i] == 0) {
+			wbufs[i] = bp;
+			break;
+		}
+	if(atexitflag == 0) {
+		atexitflag = 1;
+		atexit(batexit);
+	}
+}
+
+int
+Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
+{
+
+	p += Bungetsize;	/* make room for Bungets */
+	size -= Bungetsize;
+
+	switch(mode) {
+	default:
+		fprint(2, "Bopen: unknown mode %d\n", mode);
+		return Beof;
+
+	case OREAD:
+		bp->state = Bractive;
+		bp->ocount = 0;
+		break;
+
+	case OWRITE:
+		install(bp);
+		bp->state = Bwactive;
+		bp->ocount = -size;
+		break;
+	}
+	bp->bbuf = p;
+	bp->ebuf = p+size;
+	bp->bsize = size;
+	bp->icount = 0;
+	bp->gbuf = bp->ebuf;
+	bp->fid = f;
+	bp->flag = 0;
+	bp->rdline = 0;
+	bp->offset = 0;
+/*	bp->runesize = 0; */
+	return 0;
+}
+
+
+int
+Binit(Biobuf *bp, int f, int mode)
+{
+	return Binits(bp, f, mode, bp->b, sizeof(bp->b));
+}
+
+Biobuf*
+Bopen(char *name, int mode)
+{
+	Biobuf *bp;
+	int f;
+
+	switch(mode) {
+	default:
+		fprint(2, "Bopen: unknown mode %d\n", mode);
+		return 0;
+
+	case OREAD:
+		f = open(name, OREAD);
+		if(f < 0)
+			return 0;
+		break;
+
+	case OWRITE:
+		f = creat(name, 0666);
+		if(f < 0)
+			return 0;
+	}
+	bp = malloc(sizeof(Biobuf));
+	if(bp == 0)
+		return 0;
+	Binits(bp, f, mode, bp->b, sizeof(bp->b));
+	bp->flag = Bmagic;
+	return bp;
+}
+
+int
+Bterm(Biobuf *bp)
+{
+
+	deinstall(bp);
+	Bflush(bp);
+	if(bp->flag == Bmagic) {
+		bp->flag = 0;
+		close(bp->fid);
+		free(bp);
+	}
+	return 0;
+}
blob - /dev/null
blob + cf504631c819673260b2e20b57d579eeb46c06e0 (mode 644)
--- /dev/null
+++ src/libbio/bio.3
@@ -0,0 +1,336 @@
+.TH BIO 3
+.SH NAME
+Bopen, Binit, Binits, Brdline, Brdstr, Bgetc, Bgetd, Bungetc, Bread, Bseek, Boffset, Bfildes, Blinelen, Bputc, Bprint, Bvprint, Bwrite, Bflush, Bterm, Bbuffered \- buffered input/output
+.SH SYNOPSIS
+.ta \w'Biobuf* 'u
+.B #include <fmt.h>
+.B #include <bio.h>
+.PP
+.B
+Biobuf* Bopen(char *file, int mode)
+.PP
+.B
+int	Binit(Biobuf *bp, int fd, int mode)
+.PP
+.B
+int	Bterm(Biobuf *bp)
+.PP
+.B
+int	Bprint(Biobuf *bp, char *format, ...)
+.PP
+.B
+int	Bvprint(Biobuf *bp, char *format, va_list arglist);
+.PP
+.B
+void*	Brdline(Biobuf *bp, int delim)
+.PP
+.B
+char*	Brdstr(Biobuf *bp, int delim, int nulldelim)
+.PP
+.B
+int	Blinelen(Biobuf *bp)
+.PP
+.B
+off_t	Boffset(Biobuf *bp)
+.PP
+.B
+int	Bfildes(Biobuf *bp)
+.PP
+.B
+int	Bgetc(Biobuf *bp)
+.PP
+.B
+long	Bgetrune(Biobufhdr *bp)
+.PP
+.B
+int	Bgetd(Biobuf *bp, double *d)
+.PP
+.B
+int	Bungetc(Biobuf *bp)
+.PP
+.B
+int	Bungetrune(Biobufhdr *bp)
+.PP
+.B
+off_t	Bseek(Biobuf *bp, off_t n, int type)
+.PP
+.B
+int	Bputc(Biobuf *bp, int c)
+.PP
+.B
+int	Bputrune(Biobufhdr *bp, long c)
+.PP
+.B
+long	Bread(Biobuf *bp, void *addr, long nbytes)
+.PP
+.B
+long	Bwrite(Biobuf *bp, void *addr, long nbytes)
+.PP
+.B
+int	Bflush(Biobuf *bp)
+.PP
+.B
+int	Bbuffered(Biobuf *bp)
+.PP
+.SH DESCRIPTION
+These routines implement fast buffered I/O.
+I/O on different file descriptors is independent.
+.PP
+.I Bopen
+opens
+.I file
+for mode
+.B O_RDONLY
+or creates for mode
+.BR O_WRONLY .
+It calls
+.IR malloc (3)
+to allocate a buffer.
+.PP
+.I Binit
+initializes a buffer
+with the open file descriptor passed in
+by the user.
+.PP
+Arguments
+of types pointer to Biobuf and pointer to Biobuf
+can be used interchangeably in the following routines.
+.PP
+.IR Bopen ,
+.IR Binit ,
+or
+.I Binits
+should be called before any of the
+other routines on that buffer.
+.I Bfildes
+returns the integer file descriptor of the associated open file.
+.PP
+.I Bterm
+flushes the buffer for
+.IR bp .
+If the buffer was allocated by
+.IR Bopen ,
+the buffer is
+.I freed
+and the file is closed.
+.PP
+.I Brdline
+reads a string from the file associated with
+.I bp
+up to and including the first
+.I delim
+character.
+The delimiter character at the end of the line is
+not altered.
+.I Brdline
+returns a pointer to the start of the line or
+.L 0
+on end-of-file or read error.
+.I Blinelen
+returns the length (including the delimiter)
+of the most recent string returned by
+.IR Brdline .
+.PP
+.I Brdstr
+returns a
+.IR malloc (3)-allocated
+buffer containing the next line of input delimited by
+.IR delim ,
+terminated by a NUL (0) byte.
+Unlike
+.IR Brdline ,
+which returns when its buffer is full even if no delimiter has been found,
+.I Brdstr
+will return an arbitrarily long line in a single call.
+If
+.I nulldelim
+is set, the terminal delimiter will be overwritten with a NUL.
+After a successful call to
+.IR Brdstr ,
+the return value of
+.I Blinelen
+will be the length of the returned buffer, excluding the NUL.
+.PP
+.I Bgetc
+returns the next byte from
+.IR bp ,
+or a negative value
+at end of file.
+.I Bungetc
+may be called immediately after
+.I Bgetc
+to allow the same byte to be reread.
+.PP
+.I Bgetrune
+calls
+.I Bgetc
+to read the bytes of the next
+.SM UTF
+sequence in the input stream and returns the value of the rune
+represented by the sequence.
+It returns a negative value
+at end of file.
+.I Bungetrune
+may be called immediately after
+.I Bgetrune
+to allow the same
+.SM UTF
+sequence to be reread as either bytes or a rune.
+.I Bungetc
+and
+.I Bungetrune
+may back up a maximum of five bytes.
+.PP
+.I Bgetd
+uses
+.I fmtcharstod
+(undocumented)
+and
+.I Bgetc
+to read the formatted
+floating-point number in the input stream,
+skipping initial blanks and tabs.
+The value is stored in
+.BR *d.
+.PP
+.I Bread
+reads
+.I nbytes
+of data from
+.I bp
+into memory starting at
+.IR addr .
+The number of bytes read is returned on success
+and a negative value is returned if a read error occurred.
+.PP
+.I Bseek
+applies
+.IR lseek (2)
+to
+.IR bp .
+It returns the new file offset.
+.I Boffset
+returns the file offset of the next character to be processed.
+.PP
+.I Bputc
+outputs the low order 8 bits of
+.I c
+on
+.IR bp .
+If this causes a
+.IR write
+to occur and there is an error,
+a negative value is returned.
+Otherwise, a zero is returned.
+.PP
+.I Bputrune
+calls
+.I Bputc
+to output the low order
+16 bits of
+.I c
+as a rune
+in
+.SM UTF
+format
+on the output stream.
+.PP
+.I Bprint
+is a buffered interface to
+.IR print (2).
+If this causes a
+.IR write
+to occur and there is an error,
+a negative value
+.RB ( Beof )
+is returned.
+Otherwise, the number of bytes output is returned.
+.I Bvprint
+does the same except it takes as argument a
+.B va_list
+parameter, so it can be called within a variadic function.
+.PP
+.I Bwrite
+outputs
+.I nbytes
+of data starting at
+.I addr
+to
+.IR bp .
+If this causes a
+.IR write
+to occur and there is an error,
+a negative value is returned.
+Otherwise, the number of bytes written is returned.
+.PP
+.I Bflush
+causes any buffered output associated with
+.I bp
+to be written.
+The return is as for
+.IR Bputc .
+.I Bflush
+is called on
+exit for every buffer still open
+for writing.
+.PP
+.I Bbuffered
+returns the number of bytes in the buffer.
+When reading, this is the number of bytes still available from the last
+read on the file; when writing, it is the number of bytes ready to be
+written.
+.PP
+This library uses
+.IR fmt (3)
+for diagnostic messages about internal errors,
+as well as for the implementation of
+.I Bprint
+and
+.IR Bvprint .
+It uses
+.IR utf (3)
+for the implementation of
+.I Bgetrune
+and
+.IR Bputrune .
+.SH SEE ALSO
+.IR atexit (3).
+.IR open (2),
+.IR print (3),
+.IR utf (7)
+.SH DIAGNOSTICS
+.I Bio
+routines that return integers yield
+.B Beof
+if 
+.I bp
+is not the descriptor of an open file.
+.I Bopen
+returns zero if the file cannot be opened in the given mode.
+.SH HISTORY
+The
+.IR bio (3)
+library originally appeared in Plan 9.
+This is a port of the Plan 9 bio library.
+.SH BUGS
+.I Brdline
+returns an error on strings longer than the buffer associated
+with the file
+and also if the end-of-file is encountered
+before a delimiter.
+.I Blinelen
+will tell how many characters are available
+in these cases.
+In the case of a true end-of-file,
+.I Blinelen
+will return zero.
+At the cost of allocating a buffer,
+.I Brdstr
+sidesteps these issues.
+.PP
+The data returned by
+.I Brdline
+may be overwritten by calls to any other
+.I bio
+routine on the same
+.IR bp.
blob - /dev/null
blob + c4812392d35836556ae21c6b5280b36fe50b9404 (mode 644)
--- /dev/null
+++ src/libbio/bio.h
@@ -0,0 +1,79 @@
+#ifndef _BIOH_
+#define _BIOH_ 1
+
+#include <sys/types.h>	/* for off_t */
+#include <fcntl.h>	/* for O_RDONLY, O_WRONLY */
+
+typedef	struct	Biobuf	Biobuf;
+
+enum
+{
+	Bsize		= 8*1024,
+	Bungetsize	= 4,		/* space for ungetc */
+	Bmagic		= 0x314159,
+	Beof		= -1,
+	Bbad		= -2,
+
+	Binactive	= 0,		/* states */
+	Bractive,
+	Bwactive,
+	Bracteof,
+
+	Bend
+};
+
+struct	Biobuf
+{
+	int	icount;		/* neg num of bytes at eob */
+	int	ocount;		/* num of bytes at bob */
+	int	rdline;		/* num of bytes after rdline */
+	int	runesize;		/* num of bytes of last getrune */
+	int	state;		/* r/w/inactive */
+	int	fid;		/* open file */
+	int	flag;		/* magic if malloc'ed */
+	off_t	offset;		/* offset of buffer in file */
+	int	bsize;		/* size of buffer */
+	unsigned char*	bbuf;		/* pointer to beginning of buffer */
+	unsigned char*	ebuf;		/* pointer to end of buffer */
+	unsigned char*	gbuf;		/* pointer to good data in buf */
+	unsigned char	b[Bungetsize+Bsize];
+};
+
+#define	BGETC(bp)\
+	((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
+#define	BPUTC(bp,c)\
+	((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
+#define	BOFFSET(bp)\
+	(((bp)->state==Bractive)?\
+		(bp)->offset + (bp)->icount:\
+	(((bp)->state==Bwactive)?\
+		(bp)->offset + ((bp)->bsize + (bp)->ocount):\
+		-1))
+#define	BLINELEN(bp)\
+	(bp)->rdline
+#define	BFILDES(bp)\
+	(bp)->fid
+
+int	Bbuffered(Biobuf*);
+int	Bfildes(Biobuf*);
+int	Bflush(Biobuf*);
+int	Bgetc(Biobuf*);
+int	Bgetd(Biobuf*, double*);
+int	Binit(Biobuf*, int, int);
+int	Binits(Biobuf*, int, int, unsigned char*, int);
+int	Blinelen(Biobuf*);
+off_t	Boffset(Biobuf*);
+Biobuf*	Bopen(char*, int);
+int	Bprint(Biobuf*, char*, ...);
+int	Bputc(Biobuf*, int);
+void*	Brdline(Biobuf*, int);
+long	Bread(Biobuf*, void*, long);
+off_t	Bseek(Biobuf*, off_t, int);
+int	Bterm(Biobuf*);
+int	Bungetc(Biobuf*);
+long	Bwrite(Biobuf*, void*, long);
+char*	Brdstr(Biobuf*, int, int);
+long	Bgetrune(Biobuf*);
+int	Bputrune(Biobuf*, long);
+
+#endif
blob - /dev/null
blob + df28aaf76ab1f27f47f6c9c2c39ef8bafde3cae7 (mode 644)
--- /dev/null
+++ src/libbio/boffset.c
@@ -0,0 +1,25 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+off_t
+Boffset(Biobuf *bp)
+{
+	off_t n;
+
+	switch(bp->state) {
+	default:
+		fprint(2, "Boffset: unknown state %d\n", bp->state);
+		n = Beof;
+		break;
+
+	case Bracteof:
+	case Bractive:
+		n = bp->offset + bp->icount;
+		break;
+
+	case Bwactive:
+		n = bp->offset + (bp->bsize + bp->ocount);
+		break;
+	}
+	return n;
+}
blob - /dev/null
blob + 81e71e5ec8a53a1f808e8e17b71b1f307f255761 (mode 644)
--- /dev/null
+++ src/libbio/bprint.c
@@ -0,0 +1,28 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bprint(Biobuf *bp, char *fmt, ...)
+{
+	va_list	ap;
+	char *ip, *ep, *out;
+	int n;
+
+	ep = (char*)bp->ebuf;
+	ip = ep + bp->ocount;
+	va_start(ap, fmt);
+	out = vseprint(ip, ep, fmt, ap);
+	va_end(ap);
+	if(out == 0 || out >= ep-5) {
+		Bflush(bp);
+		ip = ep + bp->ocount;
+		va_start(ap, fmt);
+		out = vseprint(ip, ep, fmt, ap);
+		va_end(ap);
+		if(out >= ep-5)
+			return Beof;
+	}
+	n = out-ip;
+	bp->ocount += n;
+	return n;
+}
blob - /dev/null
blob + 5f0fba5925c7a9047931ae1075e6c026e8ab9d85 (mode 644)
--- /dev/null
+++ src/libbio/bputc.c
@@ -0,0 +1,29 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+int
+Bputc(Biobuf *bp, int c)
+{
+	int i, j;
+
+loop:
+	i = bp->ocount;
+	j = i+1;
+	if(i != 0) {
+		bp->ocount = j;
+		bp->ebuf[i] = c;
+		return 0;
+	}
+	if(bp->state != Bwactive)
+		return Beof;
+	j = write(bp->fid, bp->bbuf, bp->bsize);
+	if(j == bp->bsize) {
+		bp->ocount = -bp->bsize;
+		bp->offset += j;
+		goto loop;
+	}
+	fprint(2, "Bputc: write error\n");
+	bp->state = Binactive;
+	bp->ocount = 0;
+	return Beof;
+}
blob - /dev/null
blob + a2eaa83ec28212f175c199290c7931c7ed11671f (mode 644)
--- /dev/null
+++ src/libbio/bputrune.c
@@ -0,0 +1,23 @@
+#include	"lib9.h"
+#include	<bio.h>
+#include	<utf.h>
+
+int
+Bputrune(Biobuf *bp, long c)
+{
+	Rune rune;
+	char str[4];
+	int n;
+
+	rune = c;
+	if(rune < Runeself) {
+		Bputc(bp, rune);
+		return 1;
+	}
+	n = runetochar(str, &rune);
+	if(n == 0)
+		return Bbad;
+	if(Bwrite(bp, str, n) != n)
+		return Beof;
+	return n;
+}
blob - /dev/null
blob + 4ac6316aff54bcf407c5466cdaf6964b5a369c88 (mode 644)
--- /dev/null
+++ src/libbio/brdline.c
@@ -0,0 +1,94 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+void*
+Brdline(Biobuf *bp, int delim)
+{
+	char *ip, *ep;
+	int i, j;
+
+	i = -bp->icount;
+	if(i == 0) {
+		/*
+		 * eof or other error
+		 */
+		if(bp->state != Bractive) {
+			if(bp->state == Bracteof)
+				bp->state = Bractive;
+			bp->rdline = 0;
+			bp->gbuf = bp->ebuf;
+			return 0;
+		}
+	}
+
+	/*
+	 * first try in remainder of buffer (gbuf doesn't change)
+	 */
+	ip = (char*)bp->ebuf - i;
+	ep = memchr(ip, delim, i);
+	if(ep) {
+		j = (ep - ip) + 1;
+		bp->rdline = j;
+		bp->icount += j;
+		return ip;
+	}
+
+	/*
+	 * copy data to beginning of buffer
+	 */
+	if(i < bp->bsize)
+		memmove(bp->bbuf, ip, i);
+	bp->gbuf = bp->bbuf;
+
+	/*
+	 * append to buffer looking for the delim
+	 */
+	ip = (char*)bp->bbuf + i;
+	while(i < bp->bsize) {
+		j = read(bp->fid, ip, bp->bsize-i);
+		if(j <= 0) {
+			/*
+			 * end of file with no delim
+			 */
+			memmove(bp->ebuf-i, bp->bbuf, i);
+			bp->rdline = i;
+			bp->icount = -i;
+			bp->gbuf = bp->ebuf-i;
+			return 0;
+		}
+		bp->offset += j;
+		i += j;
+		ep = memchr(ip, delim, j);
+		if(ep) {
+			/*
+			 * found in new piece
+			 * copy back up and reset everything
+			 */
+			ip = (char*)bp->ebuf - i;
+			if(i < bp->bsize){
+				memmove(ip, bp->bbuf, i);
+				bp->gbuf = (unsigned char*)ip;
+			}
+			j = (ep - (char*)bp->bbuf) + 1;
+			bp->rdline = j;
+			bp->icount = j - i;
+			return ip;
+		}
+		ip += j;
+	}
+
+	/*
+	 * full buffer without finding
+	 */
+	bp->rdline = bp->bsize;
+	bp->icount = -bp->bsize;
+	bp->gbuf = bp->bbuf;
+	return 0;
+}
+
+int
+Blinelen(Biobuf *bp)
+{
+
+	return bp->rdline;
+}
blob - /dev/null
blob + b3612a5356973dfa81535f416b282e6c5873f351 (mode 644)
--- /dev/null
+++ src/libbio/brdstr.c
@@ -0,0 +1,112 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+static char*
+badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
+{
+	int n;
+
+	n = *np;
+	p = realloc(p, n+ndata+1);
+	if(p){
+		memmove(p+n, data, ndata);
+		n += ndata;
+		if(n>0 && nulldelim && p[n-1]==delim)
+			p[--n] = '\0';
+		else
+			p[n] = '\0';
+		*np = n;
+	}
+	return p;
+}
+
+char*
+Brdstr(Biobuf *bp, int delim, int nulldelim)
+{
+	char *ip, *ep, *p;
+	int i, j;
+
+	i = -bp->icount;
+	bp->rdline = 0;
+	if(i == 0) {
+		/*
+		 * eof or other error
+		 */
+		if(bp->state != Bractive) {
+			if(bp->state == Bracteof)
+				bp->state = Bractive;
+			bp->gbuf = bp->ebuf;
+			return nil;
+		}
+	}
+
+	/*
+	 * first try in remainder of buffer (gbuf doesn't change)
+	 */
+	ip = (char*)bp->ebuf - i;
+	ep = memchr(ip, delim, i);
+	if(ep) {
+		j = (ep - ip) + 1;
+		bp->icount += j;
+		return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
+	}
+
+	/*
+	 * copy data to beginning of buffer
+	 */
+	if(i < bp->bsize)
+		memmove(bp->bbuf, ip, i);
+	bp->gbuf = bp->bbuf;
+
+	/*
+	 * append to buffer looking for the delim
+	 */
+	p = nil;
+	for(;;){
+		ip = (char*)bp->bbuf + i;
+		while(i < bp->bsize) {
+			j = read(bp->fid, ip, bp->bsize-i);
+			if(j <= 0 && i == 0)
+				return p;
+			if(j <= 0 && i > 0){
+				/*
+				 * end of file but no delim. pretend we got a delim
+				 * by making the delim \0 and smashing it with nulldelim.
+				 */
+				j = 1;
+				ep = ip;
+				delim = '\0';
+				nulldelim = 1;
+				*ep = delim;	/* there will be room for this */
+			}else{
+				bp->offset += j;
+				ep = memchr(ip, delim, j);
+			}
+			i += j;
+			if(ep) {
+				/*
+				 * found in new piece
+				 * copy back up and reset everything
+				 */
+				ip = (char*)bp->ebuf - i;
+				if(i < bp->bsize){
+					memmove(ip, bp->bbuf, i);
+					bp->gbuf = (unsigned char*)ip;
+				}
+				j = (ep - (char*)bp->bbuf) + 1;
+				bp->icount = j - i;
+				return badd(p, &bp->rdline, ip, j, delim, nulldelim);
+			}
+			ip += j;
+		}
+	
+		/*
+		 * full buffer without finding; add to user string and continue
+		 */
+		p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
+		i = 0;
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+	}
+	return 0;	/* never happens */
+}
blob - /dev/null
blob + 0254d017c15b3f796b9e86e5f754e40659d2ea7d (mode 644)
--- /dev/null
+++ src/libbio/bread.c
@@ -0,0 +1,45 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+long
+Bread(Biobuf *bp, void *ap, long count)
+{
+	long c;
+	unsigned char *p;
+	int i, n, ic;
+
+	p = ap;
+	c = count;
+	ic = bp->icount;
+
+	while(c > 0) {
+		n = -ic;
+		if(n > c)
+			n = c;
+		if(n == 0) {
+			if(bp->state != Bractive)
+				break;
+			i = read(bp->fid, bp->bbuf, bp->bsize);
+			if(i <= 0) {
+				bp->state = Bracteof;
+				if(i < 0)
+					bp->state = Binactive;
+				break;
+			}
+			bp->gbuf = bp->bbuf;
+			bp->offset += i;
+			if(i < bp->bsize) {
+				memmove(bp->ebuf-i, bp->bbuf, i);
+				bp->gbuf = bp->ebuf-i;
+			}
+			ic = -i;
+			continue;
+		}
+		memmove(p, bp->ebuf+ic, n);
+		c -= n;
+		ic += n;
+		p += n;
+	}
+	bp->icount = ic;
+	return count-c;
+}
blob - /dev/null
blob + f4325fb8732473c27e4a9d7c166d8b4c770b50e6 (mode 644)
--- /dev/null
+++ src/libbio/bseek.c
@@ -0,0 +1,56 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+off_t
+Bseek(Biobuf *bp, off_t offset, int base)
+{
+	off_t n, d;
+
+	switch(bp->state) {
+	default:
+		fprint(2, "Bseek: unknown state %d\n", bp->state);
+		return Beof;
+
+	case Bracteof:
+		bp->state = Bractive;
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+
+	case Bractive:
+		n = offset;
+		if(base == 1) {
+			n += Boffset(bp);
+			base = 0;
+		}
+
+		/*
+		 * try to seek within buffer
+		 */
+		if(base == 0) {
+			d = n - Boffset(bp);
+			bp->icount += d;
+			if(d >= 0) {
+				if(bp->icount <= 0)
+					return n;
+			} else {
+				if(bp->ebuf - bp->gbuf >= -bp->icount)
+					return n;
+			}
+		}
+
+		/*
+		 * reset the buffer
+		 */
+		n = lseek(bp->fid, n, base);
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+		break;
+
+	case Bwactive:
+		Bflush(bp);
+		n = lseek(bp->fid, offset, base);
+		break;
+	}
+	bp->offset = n;
+	return n;
+}
blob - /dev/null
blob + bea32d3475ba5ff22dc2b5f06a30bc996972a085 (mode 644)
--- /dev/null
+++ src/libbio/bundle.ports
@@ -0,0 +1,45 @@
+--- Makefile ---
+# New ports collection makefile for: libbio
+# Date Created:		11 Feb 2003
+# Whom:			rsc
+#
+# THIS LINE NEEDS REPLACING.  IT'S HERE TO GET BY PORTLINT
+# $FreeBSD: ports/devel/libbio/Makefile,v 1.1 2003/02/12 00:51:22 rsc Exp $
+
+PORTNAME=	libbio
+PORTVERSION=	2.0
+CATEGORIES=	devel
+MASTER_SITES=	http://pdos.lcs.mit.edu/~rsc/software/
+EXTRACT_SUFX=	.tgz
+
+MAINTAINER=	rsc@post.harvard.edu
+
+DEPENDS=	${PORTSDIR}/devel/libfmt ${PORTSDIR}/devel/libutf
+
+MAN3=		bio.3
+USE_REINPLACE=	yes
+
+.include <bsd.port.pre.mk>
+
+post-patch:
+	${REINPLACE_CMD} -e 's,$$(PREFIX),${PREFIX},g' ${WRKSRC}/Makefile
+
+.include <bsd.port.post.mk>
+--- pkg-comment ---
+Simple buffered I/O library from Plan 9
+--- pkg-descr ---
+Libbio is a port of Plan 9's formatted I/O library.
+It provides most of the same functionality as stdio or sfio,
+but with a simpler interface and smaller footprint.
+
+WWW: http://pdos.lcs.mit.edu/~rsc/software/#libbio
+http://plan9.bell-labs.com/magic/man2html/2/bio
+
+Russ Cox
+rsc@post.harvard.edu
+--- pkg-plist ---
+lib/libbio.a
+include/bio.h
+--- /dev/null ---
+This is just a way to make sure blank lines don't
+creep into pkg-plist.
blob - /dev/null
blob + 2dfeaaad04cb0d8ef4d68966eb1f18b4389227aa (mode 644)
--- /dev/null
+++ src/libbio/bwrite.c
@@ -0,0 +1,38 @@
+#include	"lib9.h"
+#include	<bio.h>
+
+long
+Bwrite(Biobuf *bp, void *ap, long count)
+{
+	long c;
+	unsigned char *p;
+	int i, n, oc;
+
+	p = ap;
+	c = count;
+	oc = bp->ocount;
+
+	while(c > 0) {
+		n = -oc;
+		if(n > c)
+			n = c;
+		if(n == 0) {
+			if(bp->state != Bwactive)
+				return Beof;
+			i = write(bp->fid, bp->bbuf, bp->bsize);
+			if(i != bp->bsize) {
+				bp->state = Binactive;
+				return Beof;
+			}
+			bp->offset += i;
+			oc = -bp->bsize;
+			continue;
+		}
+		memmove(bp->ebuf+oc, p, n);
+		oc += n;
+		c -= n;
+		p += n;
+	}
+	bp->ocount = oc;
+	return count-c;
+}
blob - /dev/null
blob + 843f7558cadb8033a33a0c7dfb3be5e0daff3952 (mode 644)
--- /dev/null
+++ src/libbio/lib9.h
@@ -0,0 +1,12 @@
+#include <fmt.h>
+#include <fcntl.h>
+#include	<string.h>
+#include	<unistd.h>
+#include <stdlib.h>
+
+#define OREAD O_RDONLY
+#define OWRITE O_WRONLY
+
+#include <utf.h>
+
+#define nil ((void*)0)
blob - /dev/null
blob + bb99a25ab4d41b82f60096fe078cf4374b5fa108 (mode 644)
--- /dev/null
+++ src/libbio/mkfile
@@ -0,0 +1 @@
+<../libutf/mkfile
blob - /dev/null
blob + 5cb9830cd6e10d838b2b3b4f3965f755a8180c5e (mode 644)
--- /dev/null
+++ src/libbio/rpm.spec
@@ -0,0 +1,30 @@
+Summary: Simple buffered I/O library from Plan 9
+Name: libbio
+Version: 2.0
+Release: 1
+Group: Development/C
+Copyright: LGPL
+Packager: Russ Cox <rsc@post.harvard.edu>
+Source: http://pdos.lcs.mit.edu/~rsc/software/libbio-2.0.tgz
+URL: http://pdos.lcs.mit.edu/~rsc/software/#libbio
+Requires: libfmt libutf
+
+%description
+Libbio is a port of Plan 9's formatted I/O library.
+It provides most of the same functionality as stdio or sfio,
+but with a simpler interface and smaller footprint.
+
+http://plan9.bell-labs.com/magic/man2html/2/bio
+%prep
+%setup
+
+%build
+make
+
+%install
+make install
+
+%files
+/usr/local/include/bio.h
+/usr/local/lib/libbio.a
+/usr/local/man/man3/bio.3
blob - /dev/null
blob + 5dc21cb5f04d1288ed2c03ba141e5b89f04deeea (mode 644)
--- /dev/null
+++ src/libfmt/LICENSE
@@ -0,0 +1,19 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *		Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+*/
+
+This is a Unix port of the Plan 9 formatted I/O package.
+
+Please send comments about the packaging
+to Russ Cox <rsc@post.harvard.edu>.
+
blob - /dev/null
blob + 14b8d4e7925867693d110c320d9c5a67dcd16758 (mode 644)
--- /dev/null
+++ src/libfmt/Make.Darwin-PowerMacintosh
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 9799dcbb656a8014884566234263a188172fe585 (mode 644)
--- /dev/null
+++ src/libfmt/Make.FreeBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include -pg
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + edbdc111a2a0c008975e297c7ca60e46199397a9 (mode 644)
--- /dev/null
+++ src/libfmt/Make.HP-UX-9000
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS=-O -c -Ae -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 204328281a9393003647e58e2f347ba3da6a7327 (mode 644)
--- /dev/null
+++ src/libfmt/Make.Linux-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -DNEEDLL
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libfmt/Make.NetBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 3d45279bba28dbe69c00f89568c444ab83a4ac72 (mode 644)
--- /dev/null
+++ src/libfmt/Make.OSF1-alpha
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + c5fe67b82d86c731a56c101e522e804390e5bd5a (mode 644)
--- /dev/null
+++ src/libfmt/Make.SunOS-sun4u
@@ -0,0 +1,2 @@
+include Make.SunOS-sun4u-$(CC)
+NAN=nan64.$O
blob - /dev/null
blob + 829301de8649d40632eb809ae512598af11d48c5 (mode 644)
--- /dev/null
+++ src/libfmt/Make.SunOS-sun4u-cc
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I. -O
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 5c41594812a4a27eb848d384cbc356d206c0a44b (mode 644)
--- /dev/null
+++ src/libfmt/Make.SunOS-sun4u-gcc
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 4b8ff604b686d25e43063334db58622800682439 (mode 644)
--- /dev/null
+++ src/libfmt/Makefile
@@ -0,0 +1,134 @@
+
+# this works in gnu make
+SYSNAME:=${shell uname}
+OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
+
+# this works in bsd make
+SYSNAME!=uname
+OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
+
+# the gnu rules will mess up bsd but not vice versa,
+# hence the gnu rules come first.
+
+include Make.$(SYSNAME)-$(OBJTYPE)
+
+PREFIX=/usr/local
+
+NUKEFILES=
+
+TGZFILES=
+
+LIB=libfmt.a
+VERSION=2.0
+PORTPLACE=devel/libfmt
+NAME=libfmt
+
+NUM=\
+	charstod.$O\
+	pow10.$O\
+
+OFILES=\
+	dofmt.$O\
+	errfmt.$O\
+	fltfmt.$O\
+	fmt.$O\
+	fmtfd.$O\
+	fmtfdflush.$O\
+	fmtlock.$O\
+	fmtprint.$O\
+	fmtquote.$O\
+	fmtrune.$O\
+	fmtstr.$O\
+	fmtvprint.$O\
+	fprint.$O\
+	print.$O\
+	runefmtstr.$O\
+	runeseprint.$O\
+	runesmprint.$O\
+	runesnprint.$O\
+	runesprint.$O\
+	runevseprint.$O\
+	runevsmprint.$O\
+	runevsnprint.$O\
+	seprint.$O\
+	smprint.$O\
+	snprint.$O\
+	sprint.$O\
+	strtod.$O\
+	vfprint.$O\
+	vseprint.$O\
+	vsmprint.$O\
+	vsnprint.$O\
+	$(NUM)\
+	$(NAN)\
+
+HFILES=\
+	fmtdef.h\
+	fmt.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	install -m 0644 print.3 $(PREFIX)/man/man3/print.3
+	install -m 0644 fmtinstall.3 $(PREFIX)/man/man3/fmtinstall.3
+	install -m 0644 fmt.h $(PREFIX)/include/fmt.h
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+$(NAN).$O: nan.h
+strtod.$O: nan.h
+
+test: $(LIB) test.$O
+	$(CC) -o test test.$O $(LIB) -L$(PREFIX)/lib -lutf
+
+$(LIB): $(OFILES)
+	$(AR) $(ARFLAGS) $(LIB) $(OFILES)
+
+NUKEFILES+=$(LIB)
+.c.$O:
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+%.$O: %.c
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+
+$(OFILES): $(HFILES)
+
+tgz:
+	rm -rf $(NAME)-$(VERSION)
+	mkdir $(NAME)-$(VERSION)
+	cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION)
+	tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz
+	rm -rf $(NAME)-$(VERSION)
+
+clean:
+	rm -f $(OFILES) $(LIB)
+
+nuke:
+	rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES)
+
+rpm:
+	make tgz
+	cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES
+	rpm -ba rpm.spec
+	cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm .
+	cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm .
+	scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software
+
+PORTDIR=/usr/ports/$(PORTPLACE)
+
+ports:
+	make tgz
+	rm -rf $(PORTDIR)
+	mkdir $(PORTDIR)
+	cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles
+	cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}')
+	(cd $(PORTDIR); make makesum)
+	(cd $(PORTDIR); make)
+	(cd $(PORTDIR); /usr/local/bin/portlint)
+	rm -rf $(PORTDIR)/work
+	shar `find $(PORTDIR)` > ports.shar
+	(cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz
+	scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software
+
+.phony: all clean nuke install tgz rpm ports
blob - /dev/null
blob + 8302c281c2279bf88a3be92c57fb5cc7cebc0d54 (mode 644)
--- /dev/null
+++ src/libfmt/Makefile.MID
@@ -0,0 +1,63 @@
+LIB=libfmt.a
+VERSION=2.0
+PORTPLACE=devel/libfmt
+NAME=libfmt
+
+NUM=\
+	charstod.$O\
+	pow10.$O\
+
+OFILES=\
+	dofmt.$O\
+	errfmt.$O\
+	fltfmt.$O\
+	fmt.$O\
+	fmtfd.$O\
+	fmtfdflush.$O\
+	fmtlock.$O\
+	fmtprint.$O\
+	fmtquote.$O\
+	fmtrune.$O\
+	fmtstr.$O\
+	fmtvprint.$O\
+	fprint.$O\
+	print.$O\
+	runefmtstr.$O\
+	runeseprint.$O\
+	runesmprint.$O\
+	runesnprint.$O\
+	runesprint.$O\
+	runevseprint.$O\
+	runevsmprint.$O\
+	runevsnprint.$O\
+	seprint.$O\
+	smprint.$O\
+	snprint.$O\
+	sprint.$O\
+	strtod.$O\
+	vfprint.$O\
+	vseprint.$O\
+	vsmprint.$O\
+	vsnprint.$O\
+	$(NUM)\
+	$(NAN)\
+
+HFILES=\
+	fmtdef.h\
+	fmt.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	install -m 0644 print.3 $(PREFIX)/man/man3/print.3
+	install -m 0644 fmtinstall.3 $(PREFIX)/man/man3/fmtinstall.3
+	install -m 0644 fmt.h $(PREFIX)/include/fmt.h
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+$(NAN).$O: nan.h
+strtod.$O: nan.h
+
+test: $(LIB) test.$O
+	$(CC) -o test test.$O $(LIB) -L$(PREFIX)/lib -lutf
+
blob - /dev/null
blob + 5dc21cb5f04d1288ed2c03ba141e5b89f04deeea (mode 644)
--- /dev/null
+++ src/libfmt/NOTICE
@@ -0,0 +1,19 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *		Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+*/
+
+This is a Unix port of the Plan 9 formatted I/O package.
+
+Please send comments about the packaging
+to Russ Cox <rsc@post.harvard.edu>.
+
blob - /dev/null
blob + 5dc21cb5f04d1288ed2c03ba141e5b89f04deeea (mode 644)
--- /dev/null
+++ src/libfmt/README
@@ -0,0 +1,19 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *		Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+*/
+
+This is a Unix port of the Plan 9 formatted I/O package.
+
+Please send comments about the packaging
+to Russ Cox <rsc@post.harvard.edu>.
+
blob - /dev/null
blob + 9ecf6a245410a906378cf958d99dae5e5b701b95 (mode 644)
--- /dev/null
+++ src/libfmt/bundle.ports
@@ -0,0 +1,51 @@
+--- Makefile ---
+# New ports collection makefile for: libfmt
+# Date Created:		11 Feb 2003
+# Whom:			rsc
+#
+# THIS LINE NEEDS REPLACING.  IT'S HERE TO GET BY PORTLINT
+# $FreeBSD: ports/devel/libfmt/Makefile,v 1.1 2003/02/12 00:51:22 rsc Exp $
+
+PORTNAME=	libfmt
+PORTVERSION=	2.0
+CATEGORIES=	devel
+MASTER_SITES=	http://pdos.lcs.mit.edu/~rsc/software/
+EXTRACT_SUFX=	.tgz
+
+MAINTAINER=	rsc@post.harvard.edu
+
+DEPENDS=	${PORTSDIR}/devel/libutf
+
+MAN3=		print.3 fmtinstall.3
+
+USE_REINPLACE=yes
+
+.include <bsd.port.pre.mk>
+
+post-patch:
+	${REINPLACE_CMD} -e 's,$$(PREFIX),${PREFIX},g' ${WRKSRC}/Makefile
+
+.include <bsd.port.post.mk>
+--- pkg-comment ---
+Extensible formatted print C library (printf with user-defined verbs)
+--- pkg-descr ---
+Libfmt is a port of Plan 9's formatted print library.
+As a base it provides all the syntax of ANSI printf
+but adds the ability for client programs to install
+new print verbs.  One such print verb (installed by
+default) is %r, which prints the system error string.
+Instead of perror("foo"), you can write fprint(2, "foo: %r\n"). 
+This is especially nice when you write verbs to format
+the data structures used by your particular program.
+
+WWW: http://pdos.lcs.mit.edu/~rsc/software/#libfmt
+http://plan9.bell-labs.com/magic/man2html/2/print
+
+Russ Cox
+rsc@post.harvard.edu
+--- pkg-plist ---
+lib/libfmt.a
+include/fmt.h
+--- /dev/null ---
+This is just a way to make sure blank lines don't
+creep into pkg-plist.
blob - /dev/null
blob + ec403b11bb6dc85b167b5e6c3f6e1a5ea2f738df (mode 644)
--- /dev/null
+++ src/libfmt/charstod.c
@@ -0,0 +1,85 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp).  The last call it makes to f terminates the
+ * scan, so is not a character in the number.  It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+double
+fmtcharstod(int(*f)(void*), void *vp)
+{
+	double num, dem;
+	int neg, eneg, dig, exp, c;
+
+	num = 0;
+	neg = 0;
+	dig = 0;
+	exp = 0;
+	eneg = 0;
+
+	c = (*f)(vp);
+	while(c == ' ' || c == '\t')
+		c = (*f)(vp);
+	if(c == '-' || c == '+'){
+		if(c == '-')
+			neg = 1;
+		c = (*f)(vp);
+	}
+	while(c >= '0' && c <= '9'){
+		num = num*10 + c-'0';
+		c = (*f)(vp);
+	}
+	if(c == '.')
+		c = (*f)(vp);
+	while(c >= '0' && c <= '9'){
+		num = num*10 + c-'0';
+		dig++;
+		c = (*f)(vp);
+	}
+	if(c == 'e' || c == 'E'){
+		c = (*f)(vp);
+		if(c == '-' || c == '+'){
+			if(c == '-'){
+				dig = -dig;
+				eneg = 1;
+			}
+			c = (*f)(vp);
+		}
+		while(c >= '0' && c <= '9'){
+			exp = exp*10 + c-'0';
+			c = (*f)(vp);
+		}
+	}
+	exp -= dig;
+	if(exp < 0){
+		exp = -exp;
+		eneg = !eneg;
+	}
+	dem = __fmtpow10(exp);
+	if(eneg)
+		num /= dem;
+	else
+		num *= dem;
+	if(neg)
+		return -num;
+	return num;
+}
blob - /dev/null
blob + d26f7158780f309edc93caca77e13640d52ce80d (mode 644)
--- /dev/null
+++ src/libfmt/dofmt.c
@@ -0,0 +1,558 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+int
+dofmt(Fmt *f, char *fmt)
+{
+	Rune rune, *rt, *rs;
+	int r;
+	char *t, *s;
+	int n, nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = (Rune*)f->to;
+			rs = (Rune*)f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself)
+					fmt++;
+				else{
+					fmt += chartorune(&rune, fmt);
+					r = rune;
+				}
+				FMTRCHAR(f, rt, rs, r);
+			}
+			fmt++;
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = (char*)f->to;
+			s = (char*)f->stop;
+			while((r = *(uchar*)fmt) && r != '%'){
+				if(r < Runeself){
+					FMTCHAR(f, t, s, r);
+					fmt++;
+				}else{
+					n = chartorune(&rune, fmt);
+					if(t + n > s){
+						t = (char*)__fmtflush(f, t, n);
+						if(t != nil)
+							s = (char*)f->stop;
+						else
+							return -1;
+					}
+					while(n--)
+						*t++ = *fmt++;
+				}
+			}
+			fmt++;
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = (char*)__fmtdispatch(f, fmt, 0);
+		if(fmt == nil)
+			return -1;
+	}
+	return 0;	/* not reached */
+}
+
+void *
+__fmtflush(Fmt *f, void *t, int len)
+{
+	if(f->runes)
+		f->nfmt += (Rune*)t - (Rune*)f->to;
+	else
+		f->nfmt += (char*)t - (char *)f->to;
+	f->to = t;
+	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+		f->stop = f->to;
+		return nil;
+	}
+	return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width charactes
+ */
+int
+__fmtpad(Fmt *f, int n)
+{
+	char *t, *s;
+	int i;
+
+	t = (char*)f->to;
+	s = (char*)f->stop;
+	for(i = 0; i < n; i++)
+		FMTCHAR(f, t, s, ' ');
+	f->nfmt += t - (char *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+__rfmtpad(Fmt *f, int n)
+{
+	Rune *t, *s;
+	int i;
+
+	t = (Rune*)f->to;
+	s = (Rune*)f->stop;
+	for(i = 0; i < n; i++)
+		FMTRCHAR(f, t, s, ' ');
+	f->nfmt += t - (Rune *)f->to;
+	f->to = t;
+	return 0;
+}
+
+int
+__fmtcpy(Fmt *f, const void *vm, int n, int sz)
+{
+	Rune *rt, *rs, r;
+	char *t, *s, *m, *me;
+	ulong fl;
+	int nc, w;
+
+	m = (char*)vm;
+	me = m + sz;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRCHAR(f, rt, rs, r);
+		}
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(m < me)
+			return -1;
+		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+			return -1;
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+__fmtrcpy(Fmt *f, const void *vm, int n)
+{
+	Rune r, *m, *me, *rt, *rs;
+	char *t, *s;
+	ulong fl;
+	int w;
+
+	m = (Rune*)vm;
+	w = f->width;
+	fl = f->flags;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(me = m + n; m < me; m++)
+			FMTRCHAR(f, rt, rs, *m);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+			return -1;
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(me = m + n; m < me; m++){
+			r = *m;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/* fmt out one character */
+int
+__charfmt(Fmt *f)
+{
+	char x[1];
+
+	x[0] = va_arg(f->args, int);
+	f->prec = 1;
+	return __fmtcpy(f, (const char*)x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+__runefmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = va_arg(f->args, int);
+	return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+	int p, i;
+	if(!s)
+		return __fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(i = 0; i < p; i++)
+			if(s[i] == 0)
+				break;
+		return __fmtcpy(f, s, utfnlen(s, i), i);	/* BUG?: won't print a partial rune at end */
+	}
+
+	return __fmtcpy(f, s, utflen(s), strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+__strfmt(Fmt *f)
+{
+	char *s;
+
+	s = va_arg(f->args, char *);
+	return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+	Rune *e;
+	int n, p;
+
+	if(!s)
+		return __fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(n = 0; n < p; n++)
+			if(s[n] == 0)
+				break;
+	}else{
+		for(e = s; *e; e++)
+			;
+		n = e - s;
+	}
+	return __fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+__runesfmt(Fmt *f)
+{
+	Rune *s;
+
+	s = va_arg(f->args, Rune *);
+	return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+__percentfmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = f->r;
+	f->prec = 1;
+	return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* fmt an integer */
+int
+__ifmt(Fmt *f)
+{
+	char buf[70], *p, *conv;
+	uvlong vu;
+	ulong u;
+	int neg, base, i, n, fl, w, isv;
+
+	neg = 0;
+	fl = f->flags;
+	isv = 0;
+	vu = 0;
+	u = 0;
+	/*
+	 * Unsigned verbs
+	 */
+	switch(f->r){
+	case 'o':
+	case 'u':
+	case 'x':
+	case 'X':
+		fl |= FmtUnsigned;
+		break;
+	}
+	if(f->r == 'p'){
+		u = (ulong)va_arg(f->args, void*);
+		f->r = 'x';
+		fl |= FmtUnsigned;
+	}else if(fl & FmtVLong){
+		isv = 1;
+		if(fl & FmtUnsigned)
+			vu = va_arg(f->args, uvlong);
+		else
+			vu = va_arg(f->args, vlong);
+	}else if(fl & FmtLong){
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, ulong);
+		else
+			u = va_arg(f->args, long);
+	}else if(fl & FmtByte){
+		if(fl & FmtUnsigned)
+			u = (uchar)va_arg(f->args, int);
+		else
+			u = (char)va_arg(f->args, int);
+	}else if(fl & FmtShort){
+		if(fl & FmtUnsigned)
+			u = (ushort)va_arg(f->args, int);
+		else
+			u = (short)va_arg(f->args, int);
+	}else{
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, uint);
+		else
+			u = va_arg(f->args, int);
+	}
+	conv = "0123456789abcdef";
+	switch(f->r){
+	case 'd':
+	case 'i':
+		base = 10;
+		break;
+	case 'u':
+		base = 10;
+		break;
+	case 'x':
+		base = 16;
+		break;
+	case 'X':
+		base = 16;
+		conv = "0123456789ABCDEF";
+		break;
+	case 'b':
+		base = 2;
+		break;
+	case 'o':
+		base = 8;
+		break;
+	default:
+		return -1;
+	}
+	if(!(fl & FmtUnsigned)){
+		if(isv && (vlong)vu < 0){
+			vu = -(vlong)vu;
+			neg = 1;
+		}else if(!isv && (long)u < 0){
+			u = -(long)u;
+			neg = 1;
+		}
+	}else{
+		fl &= ~(FmtSign|FmtSpace);	/* no + for unsigned conversions */
+	}
+	p = buf + sizeof buf - 1;
+	n = 0;
+	if(isv){
+		while(vu){
+			i = vu % base;
+			vu /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}else{
+		while(u){
+			i = u % base;
+			u /= base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}
+	if(n == 0){
+		if(!(fl & FmtPrec) || f->prec != 0){
+			*p-- = '0';
+			n = 1;
+		}
+		fl &= ~FmtSharp;
+	}
+	for(w = f->prec; n < w && p > buf+3; n++)
+		*p-- = '0';
+	if(neg || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(fl & FmtSharp){
+		if(base == 16)
+			n += 2;
+		else if(base == 8){
+			if(p[1] == '0')
+				fl &= ~FmtSharp;
+			else
+				n++;
+		}
+	}
+	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
+		for(w = f->width; n < w && p > buf+3; n++)
+			*p-- = '0';
+		f->width = 0;
+	}
+	if(fl & FmtSharp){
+		if(base == 16)
+			*p-- = f->r;
+		if(base == 16 || base == 8)
+			*p-- = '0';
+	}
+	if(neg)
+		*p-- = '-';
+	else if(fl & FmtSign)
+		*p-- = '+';
+	else if(fl & FmtSpace)
+		*p-- = ' ';
+	f->flags &= ~FmtPrec;
+	return __fmtcpy(f, p + 1, n, n);
+}
+
+int
+__countfmt(Fmt *f)
+{
+	void *p;
+	ulong fl;
+
+	fl = f->flags;
+	p = va_arg(f->args, void*);
+	if(fl & FmtVLong){
+		*(vlong*)p = f->nfmt;
+	}else if(fl & FmtLong){
+		*(long*)p = f->nfmt;
+	}else if(fl & FmtByte){
+		*(char*)p = f->nfmt;
+	}else if(fl & FmtShort){
+		*(short*)p = f->nfmt;
+	}else{
+		*(int*)p = f->nfmt;
+	}
+	return 0;
+}
+
+int
+__flagfmt(Fmt *f)
+{
+	switch(f->r){
+	case ',':
+		f->flags |= FmtComma;
+		break;
+	case '-':
+		f->flags |= FmtLeft;
+		break;
+	case '+':
+		f->flags |= FmtSign;
+		break;
+	case '#':
+		f->flags |= FmtSharp;
+		break;
+	case ' ':
+		f->flags |= FmtSpace;
+		break;
+	case 'u':
+		f->flags |= FmtUnsigned;
+		break;
+	case 'h':
+		if(f->flags & FmtShort)
+			f->flags |= FmtByte;
+		f->flags |= FmtShort;
+		break;
+	case 'L':
+		f->flags |= FmtLDouble;
+		break;
+	case 'l':
+		if(f->flags & FmtLong)
+			f->flags |= FmtVLong;
+		f->flags |= FmtLong;
+		break;
+	}
+	return 1;
+}
+
+/* default error format */
+int
+__badfmt(Fmt *f)
+{
+	char x[3];
+
+	x[0] = '%';
+	x[1] = f->r;
+	x[2] = '%';
+	f->prec = 3;
+	__fmtcpy(f, (const void*)x, 3, 3);
+	return 0;
+}
blob - /dev/null
blob + cdaee8a5f0c7a02fd2ef7893f6e3536b660d42f8 (mode 644)
--- /dev/null
+++ src/libfmt/dorfmt.c
@@ -0,0 +1,61 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/* format the output into f->to and return the number of characters fmted  */
+
+int
+dorfmt(Fmt *f, const Rune *fmt)
+{
+	Rune *rt, *rs;
+	int r;
+	char *t, *s;
+	int nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = f->to;
+			rs = f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRCHAR(f, rt, rs, r);
+			}
+			f->nfmt += rt - (Rune *)f->to;
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = f->to;
+			s = f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRUNE(f, t, f->stop, r);
+			}
+			f->nfmt += t - (char *)f->to;
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = __fmtdispatch(f, fmt, 1);
+		if(fmt == nil)
+			return -1;
+	}
+	return 0;		/* not reached */
+}
blob - /dev/null
blob + 2184705426ca459a31e50dc20fae2627b1641ce7 (mode 644)
--- /dev/null
+++ src/libfmt/errfmt.c
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+__errfmt(Fmt *f)
+{
+	char *s;
+
+	s = strerror(errno);
+	return fmtstrcpy(f, s);
+}
blob - /dev/null
blob + 234f03d9c5d0e2e17c89143cf1b54f92a3478794 (mode 644)
--- /dev/null
+++ src/libfmt/fltfmt.c
@@ -0,0 +1,610 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdio.h>
+#include <math.h>
+#include <float.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+#include "nan.h"
+
+enum
+{
+	FDEFLT	= 6,
+	NSIGNIF	= 17
+};
+
+/*
+ * first few powers of 10, enough for about 1/2 of the
+ * total space for doubles.
+ */
+static double pows10[] =
+{
+	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,  
+	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,  
+	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,  
+	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,  
+	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,  
+	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,  
+	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,  
+	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,  
+	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,  
+	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,  
+	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109, 
+	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119, 
+	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129, 
+	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139, 
+	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 
+	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, 
+};
+
+static double
+pow10(int n)
+{
+	double d;
+	int neg;
+
+	neg = 0;
+	if(n < 0){
+		if(n < DBL_MIN_10_EXP){
+			return 0.;
+		}
+		neg = 1;
+		n = -n;
+	}else if(n > DBL_MAX_10_EXP){
+		return HUGE_VAL;
+	}
+	if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
+		d = pows10[n];
+	else{
+		d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+		for(;;){
+			n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
+			if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
+				d *= pows10[n];
+				break;
+			}
+			d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+		}
+	}
+	if(neg){
+		return 1./d;
+	}
+	return d;
+}
+
+static int
+xadd(char *a, int n, int v)
+{
+	char *b;
+	int c;
+
+	if(n < 0 || n >= NSIGNIF)
+		return 0;
+	for(b = a+n; b >= a; b--) {
+		c = *b + v;
+		if(c <= '9') {
+			*b = c;
+			return 0;
+		}
+		*b = '0';
+		v = 1;
+	}
+	*a = '1';	/* overflow adding */
+	return 1;
+}
+
+static int
+xsub(char *a, int n, int v)
+{
+	char *b;
+	int c;
+
+	for(b = a+n; b >= a; b--) {
+		c = *b - v;
+		if(c >= '0') {
+			*b = c;
+			return 0;
+		}
+		*b = '9';
+		v = 1;
+	}
+	*a = '9';	/* underflow subtracting */
+	return 1;
+}
+
+static void
+xaddexp(char *p, int e)
+{
+	char se[9];
+	int i;
+
+	*p++ = 'e';
+	if(e < 0) {
+		*p++ = '-';
+		e = -e;
+	}
+	i = 0;
+	while(e) {
+		se[i++] = e % 10 + '0';
+		e /= 10;
+	}
+	if(i == 0) {
+		*p++ = '0';
+	} else {
+		while(i > 0)
+			*p++ = se[--i];
+	}
+	*p++ = '\0';
+}
+
+static char*
+xdodtoa(char *s1, double f, int chr, int prec, int *decpt, int *rsign)
+{
+	char s2[NSIGNIF+10];
+	double g, h;
+	int e, d, i;
+	int c2, sign, oerr;
+
+	if(chr == 'F')
+		chr = 'f';
+	if(prec > NSIGNIF)
+		prec = NSIGNIF;
+	if(prec < 0)
+		prec = 0;
+	if(__isNaN(f)) {
+		*decpt = 9999;
+		*rsign = 0;
+		strcpy(s1, "nan");
+		return &s1[3];
+	}
+	sign = 0;
+	if(f < 0) {
+		f = -f;
+		sign++;
+	}
+	*rsign = sign;
+	if(__isInf(f, 1) || __isInf(f, -1)) {
+		*decpt = 9999;
+		strcpy(s1, "inf");
+		return &s1[3];
+	}
+
+	e = 0;
+	g = f;
+	if(g != 0) {
+		frexp(f, &e);
+		e = (int)(e * .301029995664);
+		if(e >= -150 && e <= +150) {
+			d = 0;
+			h = f;
+		} else {
+			d = e/2;
+			h = f * pow10(-d);
+		}
+		g = h * pow10(d-e);
+		while(g < 1) {
+			e--;
+			g = h * pow10(d-e);
+		}
+		while(g >= 10) {
+			e++;
+			g = h * pow10(d-e);
+		}
+	}
+
+	/*
+	 * convert NSIGNIF digits and convert
+	 * back to get accuracy.
+	 */
+	for(i=0; i<NSIGNIF; i++) {
+		d = (int)g;
+		s1[i] = d + '0';
+		g = (g - d) * 10;
+	}
+	s1[i] = 0;
+
+	/*
+	 * try decimal rounding to eliminate 9s
+	 */
+	c2 = prec + 1;
+	if(chr == 'f')
+		c2 += e;
+	oerr = errno;
+	if(c2 >= NSIGNIF-2) {
+		strcpy(s2, s1);
+		d = e;
+		s1[NSIGNIF-2] = '0';
+		s1[NSIGNIF-1] = '0';
+		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+		g = fmtstrtod(s1, nil);
+		if(g == f)
+			goto found;
+		if(xadd(s1, NSIGNIF-3, 1)) {
+			e++;
+			xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+		}
+		g = fmtstrtod(s1, nil);
+		if(g == f)
+			goto found;
+		strcpy(s1, s2);
+		e = d;
+	}
+
+	/*
+	 * convert back so s1 gets exact answer
+	 */
+	for(d = 0; d < 10; d++) {
+		xaddexp(s1+NSIGNIF, e-NSIGNIF+1);
+		g = fmtstrtod(s1, nil);
+		if(f > g) {
+			if(xadd(s1, NSIGNIF-1, 1))
+				e--;
+			continue;
+		}
+		if(f < g) {
+			if(xsub(s1, NSIGNIF-1, 1))
+				e++;
+			continue;
+		}
+		break;
+	}
+
+found:
+	errno = oerr;
+
+	/*
+	 * sign
+	 */
+	d = 0;
+	i = 0;
+
+	/*
+	 * round & adjust 'f' digits
+	 */
+	c2 = prec + 1;
+	if(chr == 'f'){
+		if(xadd(s1, c2+e, 5))
+			e++;
+		c2 += e;
+		if(c2 < 0){
+			c2 = 0;
+			e = -prec - 1;
+		}
+	}else{
+		if(xadd(s1, c2, 5))
+			e++;
+	}
+	if(c2 > NSIGNIF){
+		c2 = NSIGNIF;
+	}
+
+	*decpt = e + 1;
+
+	/*
+	 * terminate the converted digits
+	 */
+	s1[c2] = '\0';
+	return &s1[c2];
+}
+
+/*
+ * this function works like the standard dtoa, if you want it.
+ */
+#if 0
+static char*
+__dtoa(double f, int mode, int ndigits, int *decpt, int *rsign, char **rve)
+{
+	static char s2[NSIGNIF + 10];
+	char *es;
+	int chr, prec;
+
+	switch(mode) {
+	/* like 'e' */
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+		chr = 'e';
+		break;
+	/* like 'g' */
+	case 0:
+	case 1:
+	default:
+		chr = 'g';
+		break;
+	/* like 'f' */
+	case 3:
+	case 5:
+	case 7:
+	case 9:
+		chr = 'f';
+		break;
+	}
+
+	if(chr != 'f' && ndigits){
+		ndigits--;
+	}
+	prec = ndigits;
+	if(prec > NSIGNIF)
+		prec = NSIGNIF;
+	if(ndigits == 0)
+		prec = NSIGNIF;
+	es = xdodtoa(s2, f, chr, prec, decpt, rsign);
+
+	/*
+	 * strip trailing 0
+	 */
+	for(; es > s2 + 1; es--){
+		if(es[-1] != '0'){
+			break;
+		}
+	}
+	*es = '\0';
+	if(rve != NULL)
+		*rve = es;
+	return s2;
+}
+#endif
+
+static int
+fmtzdotpad(Fmt *f, int n, int pt)
+{
+	char *t, *s;
+	int i;
+	Rune *rt, *rs;
+
+	if(f->runes){
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(i = 0; i < n; i++){
+			if(i == pt){
+				FMTRCHAR(f, rt, rs, '.');
+			}
+			FMTRCHAR(f, rt, rs, '0');
+		}
+		f->nfmt += rt - (Rune*)f->to;
+		f->to = rt;
+	}else{
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(i = 0; i < n; i++){
+			if(i == pt){
+				FMTCHAR(f, t, s, '.');
+			}
+			FMTCHAR(f, t, s, '0');
+		}
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+	}
+	return 0;
+}
+
+int
+__efgfmt(Fmt *fmt)
+{
+	double f;
+	char s1[NSIGNIF+10];
+	int e, d, n;
+	int c1, c2, c3, c4, ucase, sign, chr, prec, fl;
+
+	f = va_arg(fmt->args, double);
+	prec = FDEFLT;
+	fl = fmt->flags;
+	fmt->flags = 0;
+	if(fl & FmtPrec)
+		prec = fmt->prec;
+	chr = fmt->r;
+	ucase = 0;
+	if(chr == 'E'){
+		chr = 'e';
+		ucase = 1;
+	}else if(chr == 'F'){
+		chr = 'f';
+		ucase = 1;
+	}else if(chr == 'G'){
+		chr = 'g';
+		ucase = 1;
+	}
+	if(prec > 0 && chr == 'g')
+		prec--;
+	if(prec < 0)
+		prec = 0;
+
+	xdodtoa(s1, f, chr, prec, &e, &sign);
+	e--;
+	if(*s1 == 'i' || *s1 == 'n'){
+		if(ucase){
+			if(*s1 == 'i'){
+				strcpy(s1, "INF");
+			}else{
+				strcpy(s1, "NAN");
+			}
+		}
+		fmt->flags = fl & (FmtWidth|FmtLeft);
+		return __fmtcpy(fmt, (const void*)s1, 3, 3);
+	}
+
+	/*
+	 * copy into final place
+	 * c1 digits of leading '0'
+	 * c2 digits from conversion
+	 * c3 digits of trailing '0'
+	 * c4 digits after '.'
+	 */
+	c1 = 0;
+	c2 = prec + 1;
+	c3 = 0;
+	c4 = prec;
+	switch(chr) {
+	default:
+		chr = 'e';
+		break;
+	case 'g':
+		/*
+		 * decide on 'e' of 'f' style convers
+		 */
+		if(e >= -4 && e <= prec) {
+			c1 = -e;
+			c4 = prec - e;
+			chr = 'h';	/* flag for 'f' style */
+		}
+		break;
+	case 'f':
+		c1 = -e;
+		if(c1 > prec)
+			c1 = prec + 1;
+		c2 += e;
+		break;
+	}
+
+	/*
+	 * clean up c1 c2 and c3
+	 */
+	if(c1 < 0)
+		c1 = 0;
+	if(c2 < 0)
+		c2 = 0;
+	if(c2 > NSIGNIF) {
+		c3 = c2-NSIGNIF;
+		c2 = NSIGNIF;
+	}
+
+	/*
+	 * trim trailing zeros for %g
+	 */
+	if(!(fl & FmtSharp)
+	&& (chr == 'g' || chr == 'h')){
+		if(c4 >= c3){
+			c4 -= c3;
+			c3 = 0;
+		}else{
+			c3 -= c4;
+			c4 = 0;
+		}
+		while(c4 && c2 > 1 && s1[c2 - 1] == '0'){
+			c4--;
+			c2--;
+		}
+	}
+
+	/*
+	 * calculate the total length
+	 */
+	n = c1 + c2 + c3;
+	if(sign || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(c4 || (fl & FmtSharp)){
+		n++;
+	}
+	if(chr == 'e' || chr == 'g'){
+		n += 4;
+		if(e >= 100)
+			n++;
+	}
+
+	/*
+	 * pad to width if right justified
+	 */
+	if((fl & (FmtWidth|FmtLeft)) == FmtWidth && n < fmt->width){
+		if(fl & FmtZero){
+			c1 += fmt->width - n;
+		}else{
+			if(__fmtpad(fmt, fmt->width - n) < 0){
+				return -1;
+			}
+		}
+	}
+
+	/*
+	 * sign
+	 */
+	d = 0;
+	if(sign)
+		d = '-';
+	else if(fl & FmtSign)
+		d = '+';
+	else if(fl & FmtSpace)
+		d = ' ';
+	if(d && fmtrune(fmt, d) < 0){
+		return -1;
+	}
+
+	/*
+	 * copy digits
+	 */
+	c4 = c1 + c2 + c3 - c4;
+	if(c1 > 0){
+		if(fmtzdotpad(fmt, c1, c4) < 0){
+			return -1;
+		}
+		c4 -= c1;
+	}
+	d = 0;
+	if(c4 >= 0 && c4 < c2){
+		if(__fmtcpy(fmt, s1, c4, c4) < 0 || fmtrune(fmt, '.') < 0)
+			return -1;
+		d = c4;
+		c2 -= c4;
+		c4 = -1;
+	}
+	if(__fmtcpy(fmt, (const void*)(s1 + d), c2, c2) < 0){
+		return -1;
+	}
+	c4 -= c2;
+	if(c3 > 0){
+		if(fmtzdotpad(fmt, c3, c4) < 0){
+			return -1;
+		}
+		c4 -= c3;
+	}
+
+	/*
+	 * strip trailing '0' on g conv
+	 */
+	if((fl & FmtSharp) && c4 == 0 && fmtrune(fmt, '.') < 0){
+		return -1;
+	}
+	if(chr == 'e' || chr == 'g') {
+		d = 0;
+		if(ucase)
+			s1[d++] = 'E';
+		else
+			s1[d++] = 'e';
+		c1 = e;
+		if(c1 < 0) {
+			s1[d++] = '-';
+			c1 = -c1;
+		} else
+			s1[d++] = '+';
+		if(c1 >= 100) {
+			s1[d++] = c1/100 + '0';
+			c1 = c1%100;
+		}
+		s1[d++] = c1/10 + '0';
+		s1[d++] = c1%10 + '0';
+		if(__fmtcpy(fmt, s1, d, d) < 0){
+			return -1;
+		}
+	}
+	if((fl & (FmtWidth|FmtLeft)) == (FmtWidth|FmtLeft) && n < fmt->width){
+		if(__fmtpad(fmt, fmt->width - n) < 0){
+			return -1;
+		}
+	}
+	return 0;
+}
blob - /dev/null
blob + 06f6c950ec4181462931edc3732f1990feec9f5f (mode 644)
--- /dev/null
+++ src/libfmt/fmt.c
@@ -0,0 +1,221 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+enum
+{
+	Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+	int	c;
+	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+struct
+{
+	/* lock by calling __fmtlock, __fmtunlock */
+	int	nfmt;
+	Convfmt	fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+	' ',	__flagfmt,
+	'#',	__flagfmt,
+	'%',	__percentfmt,
+	'+',	__flagfmt,
+	',',	__flagfmt,
+	'-',	__flagfmt,
+	'C',	__runefmt,	/* Plan 9 addition */
+	'E',	__efgfmt,
+	'F',	__efgfmt,	/* ANSI only */
+	'G',	__efgfmt,
+	'L',	__flagfmt,	/* ANSI only */
+	'S',	__runesfmt,	/* Plan 9 addition */
+	'X',	__ifmt,
+	'b',	__ifmt,		/* Plan 9 addition */
+	'c',	__charfmt,
+	'd',	__ifmt,
+	'e',	__efgfmt,
+	'f',	__efgfmt,
+	'g',	__efgfmt,
+	'h',	__flagfmt,
+	'i',	__ifmt,		/* ANSI only */
+	'l',	__flagfmt,
+	'n',	__countfmt,
+	'o',	__ifmt,
+	'p',	__ifmt,
+	'r',	__errfmt,
+	's',	__strfmt,
+	'u',	__ifmt,		/* in Plan 9, __flagfmt */
+	'x',	__ifmt,
+	0,	nil,
+};
+
+
+int	(*fmtdoquote)(int);
+
+/*
+ * __fmtlock() must be set
+ */
+static int
+__fmtinstall(int c, Fmts f)
+{
+	Convfmt *p, *ep;
+
+	if(c<=0 || c>=65536)
+		return -1;
+	if(!f)
+		f = __badfmt;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			break;
+
+	if(p == &fmtalloc.fmt[Maxfmt])
+		return -1;
+
+	p->fmt = f;
+	if(p == ep){	/* installing a new format character */
+		fmtalloc.nfmt++;
+		p->c = c;
+	}
+
+	return 0;
+}
+
+int
+fmtinstall(int c, Fmts f)
+{
+	int ret;
+
+	__fmtlock();
+	ret = __fmtinstall(c, f);
+	__fmtunlock();
+	return ret;
+}
+
+static Fmts
+fmtfmt(int c)
+{
+	Convfmt *p, *ep;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c){
+			while(p->fmt == nil)	/* loop until value is updated */
+				;
+			return p->fmt;
+		}
+
+	/* is this a predefined format char? */
+	__fmtlock();
+	for(p=knownfmt; p->c; p++)
+		if(p->c == c){
+			__fmtinstall(p->c, p->fmt);
+			__fmtunlock();
+			return p->fmt;
+		}
+	__fmtunlock();
+
+	return __badfmt;
+}
+
+void*
+__fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+	Rune rune, r;
+	int i, n;
+
+	f->flags = 0;
+	f->width = f->prec = 0;
+
+	for(;;){
+		if(isrunes){
+			r = *(Rune*)fmt;
+			fmt = (Rune*)fmt + 1;
+		}else{
+			fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
+			r = rune;
+		}
+		f->r = r;
+		switch(r){
+		case '\0':
+			return nil;
+		case '.':
+			f->flags |= FmtWidth|FmtPrec;
+			continue;
+		case '0':
+			if(!(f->flags & FmtWidth)){
+				f->flags |= FmtZero;
+				continue;
+			}
+			/* fall through */
+		case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			i = 0;
+			while(r >= '0' && r <= '9'){
+				i = i * 10 + r - '0';
+				if(isrunes){
+					r = *(Rune*)fmt;
+					fmt = (Rune*)fmt + 1;
+				}else{
+					r = *(char*)fmt;
+					fmt = (char*)fmt + 1;
+				}
+			}
+			if(isrunes)
+				fmt = (Rune*)fmt - 1;
+			else
+				fmt = (char*)fmt - 1;
+		numflag:
+			if(f->flags & FmtWidth){
+				f->flags |= FmtPrec;
+				f->prec = i;
+			}else{
+				f->flags |= FmtWidth;
+				f->width = i;
+			}
+			continue;
+		case '*':
+			i = va_arg(f->args, int);
+			if(i < 0){
+				/*
+				 * negative precision =>
+				 * ignore the precision.
+				 */
+				if(f->flags & FmtPrec){
+					f->flags &= ~FmtPrec;
+					f->prec = 0;
+					continue;
+				}
+				i = -i;
+				f->flags |= FmtLeft;
+			}
+			goto numflag;
+		}
+		n = (*fmtfmt(r))(f);
+		if(n < 0)
+			return nil;
+		if(n == 0)
+			return fmt;
+	}
+}
blob - /dev/null
blob + c913e14a05887a86a8973cd7fff02f3cde9a100f (mode 644)
--- /dev/null
+++ src/libfmt/fmt.h
@@ -0,0 +1,100 @@
+
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#ifndef _FMTH_
+#define _FMTH_ 1
+
+#include <stdarg.h>
+
+#ifndef _UTFH_
+#include <utf.h>
+#endif
+
+typedef struct Fmt	Fmt;
+struct Fmt{
+	unsigned char	runes;		/* output buffer is runes or chars? */
+	void	*start;			/* of buffer */
+	void	*to;			/* current place in the buffer */
+	void	*stop;			/* end of the buffer; overwritten if flush fails */
+	int	(*flush)(Fmt *);	/* called when to == stop */
+	void	*farg;			/* to make flush a closure */
+	int	nfmt;			/* num chars formatted so far */
+	va_list	args;			/* args passed to dofmt */
+	int	r;			/* % format Rune */
+	int	width;
+	int	prec;
+	unsigned long	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,
+	FmtLDouble	= FmtByte << 1,
+
+	FmtFlag		= FmtLDouble << 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	int	quotestrfmt(Fmt *f);
+extern	void	quotefmtinstall(void);
+extern	int	(*fmtdoquote)(int);
+
+
+extern	int	fmtinstall(int, int (*)(Fmt*));
+extern	int	dofmt(Fmt*, char*);
+extern	int	fmtprint(Fmt*, char*, ...);
+extern	int	fmtvprint(Fmt*, char*, va_list);
+extern	int	fmtrune(Fmt*, int);
+extern	int	fmtstrcpy(Fmt*, char*);
+
+extern	double	fmtstrtod(const char *, char **);
+extern	double	fmtcharstod(int(*)(void*), void*);
+
+#endif
blob - /dev/null
blob + ca2010ab71954c7588be5cdb1061a6b1f326cac7 (mode 644)
--- /dev/null
+++ src/libfmt/fmtdef.h
@@ -0,0 +1,121 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+#define uchar _fmtuchar
+#define ushort _fmtushort
+#define uint _fmtuint
+#define ulong _fmtulong
+#define vlong _fmtvlong
+#define uvlong _fmtuvlong
+
+#define USED(x) if(x);else
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
+#ifndef NOVLONGS
+typedef unsigned long long	uvlong;
+typedef long long		vlong;
+#endif
+
+#define nil		0	/* cannot be ((void*)0) because used for function pointers */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+	int	quoted;		/* if set, string must be quoted */
+	int	nrunesin;	/* number of input runes that can be accepted */
+	int	nbytesin;	/* number of input bytes that can be accepted */
+	int	nrunesout;	/* number of runes that will be generated */
+	int	nbytesout;	/* number of bytes that will be generated */
+};
+
+void	*__fmtflush(Fmt*, void*, int);
+void	*__fmtdispatch(Fmt*, void*, int);
+int	__floatfmt(Fmt*, double);
+int	__fmtpad(Fmt*, int);
+int	__rfmtpad(Fmt*, int);
+int	__fmtFdFlush(Fmt*);
+
+int	__efgfmt(Fmt*);
+int	__charfmt(Fmt*);
+int	__runefmt(Fmt*);
+int	__runesfmt(Fmt*);
+int	__countfmt(Fmt*);
+int	__flagfmt(Fmt*);
+int	__percentfmt(Fmt*);
+int	__ifmt(Fmt*);
+int	__strfmt(Fmt*);
+int	__badfmt(Fmt*);
+int	__fmtcpy(Fmt*, const void*, int, int);
+int	__fmtrcpy(Fmt*, const void*, int n);
+int	__errfmt(Fmt *f);
+
+double	__fmtpow10(int);
+
+void	__fmtlock(void);
+void	__fmtunlock(void);
+
+#define FMTCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (char*)s){\
+		t = __fmtflush(f, t, 1);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (Rune*)s){\
+		t = __fmtflush(f, t, sizeof(Rune));\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = c;\
+	}while(0)
+
+#define FMTRUNE(f, t, s, r)\
+	do{\
+	Rune _rune;\
+	int _runelen;\
+	if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+		t = __fmtflush(f, t, _runelen);\
+		if(t != nil)\
+			s = f->stop;\
+		else\
+			return -1;\
+	}\
+	if(r < Runeself)\
+		*t++ = r;\
+	else{\
+		_rune = r;\
+		t += runetochar(t, &_rune);\
+	}\
+	}while(0)
blob - /dev/null
blob + d4251402aa64e76b968af7728479e3a9dfb3b8a2 (mode 644)
--- /dev/null
+++ src/libfmt/fmtfd.c
@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * public routine for final flush of a formatting buffer
+ * to a file descriptor; returns total char count.
+ */
+int
+fmtfdflush(Fmt *f)
+{
+	if(__fmtFdFlush(f) <= 0)
+		return -1;
+	return f->nfmt;
+}
+
+/*
+ * initialize an output buffer for buffered printing
+ */
+int
+fmtfdinit(Fmt *f, int fd, char *buf, int size)
+{
+	f->runes = 0;
+	f->start = buf;
+	f->to = buf;
+	f->stop = buf + size;
+	f->flush = __fmtFdFlush;
+	f->farg = (void*)fd;
+	f->nfmt = 0;
+	return 0;
+}
blob - /dev/null
blob + 796feab23d5dcb4e819e3849a885a0bdc20dc43c (mode 644)
--- /dev/null
+++ src/libfmt/fmtfdflush.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <unistd.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * generic routine for flushing a formatting buffer
+ * to a file descriptor
+ */
+int
+__fmtFdFlush(Fmt *f)
+{
+	int n;
+
+	n = (char*)f->to - (char*)f->start;
+	if(n && write((int)f->farg, f->start, n) != n)
+		return 0;
+	f->to = f->start;
+	return 1;
+}
blob - /dev/null
blob + 2a0e55bf164c92bbf6d34b02105d38e2190fc00f (mode 644)
--- /dev/null
+++ src/libfmt/fmtinstall.3
@@ -0,0 +1,346 @@
+.TH FMTINSTALL 3
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.SH NAME
+fmtinstall, dofmt, fmtprint, fmtvprint, fmtstrcpy, fmtfdinit, fmtfdflush, fmtstrinit, fmtstrflush \- support for user-defined print formats and output routines
+.SH SYNOPSIS
+.B #include <fmt.h>
+.PP
+.ft L
+.nf
+.ta \w'    'u +\w'    'u +\w'    'u +\w'    'u +\w'    'u
+typedef struct Fmt	Fmt;
+struct Fmt{
+	void	*start;		/* of buffer */
+	void	*to;		/* current place in the buffer */
+	void	*stop;		/* end of the buffer; overwritten if flush fails */
+	int		(*flush)(Fmt*);	/* called when to == stop */
+	void	*farg;		/* to make flush a closure */
+	int		nfmt;		/* num chars formatted so far */
+	va_list	args;		/* args passed to dofmt */
+	int		r;			/* % format character */
+	int		width;
+	int		prec;
+	unsigned long	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,
+	FmtLDouble	= FmtByte << 1,
+
+	FmtFlag		= FmtLDouble << 1
+};
+.fi
+.PP
+.B
+.ta \w'\fLchar* 'u
+
+.PP
+.B
+int	fmtfdinit(Fmt *f, int fd, char *buf, int nbuf);
+.PP
+.B
+int	fmtfdflush(Fmt *f);
+.PP
+.B
+int	fmtstrinit(Fmt *f);
+.PP
+.B
+char*	fmtstrflush(Fmt *f);
+.PP
+.B
+int	fmtinstall(int c, int (*fn)(Fmt*));
+.PP
+.B
+int	dofmt(Fmt *f, char *fmt);
+.PP
+.B
+int	fmtprint(Fmt *f, char *fmt, ...);
+.PP
+.B
+int	fmtvprint(Fmt *f, char *fmt, va_list v);
+.PP
+.B
+int	fmtrune(Fmt *f, int r);
+.PP
+.B
+int	fmtstrcpy(Fmt *f, char *s);
+.SH DESCRIPTION
+The interface described here allows the construction of custom
+.IR print (3)
+verbs and output routines.
+In essence, they provide access to the workings of the formatted print code.
+.PP
+The
+.IR print (3)
+suite maintains its state with a data structure called
+.BR Fmt .
+A typical call to
+.IR print (3)
+or its relatives initializes a
+.B Fmt
+structure, passes it to subsidiary routines to process the output,
+and finishes by emitting any saved state recorded in the
+.BR Fmt .
+The details of the
+.B Fmt
+are unimportant to outside users, except insofar as the general
+design influences the interface.
+The
+.B Fmt
+records
+the verb being processed, its precision and width,
+and buffering parameters.
+Most important, it also records a
+.I flush
+routine that the library will call if a buffer overflows.
+When printing to a file descriptor, the flush routine will
+emit saved characters and reset the buffer; when printing
+to an allocated string, it will resize the string to receive more output.
+The flush routine is nil when printing to fixed-size buffers.
+User code need never provide a flush routine; this is done internally
+by the library.
+.SS Custom output routines
+To write a custom output routine, such as an error handler that
+formats and prints custom error messages, the output sequence can be run
+from outside the library using the routines described here.
+There are two main cases: output to an open file descriptor
+and output to a string.
+.PP
+To write to a file descriptor, call
+.I fmtfdinit
+to initialize the local
+.B Fmt
+structure
+.IR f ,
+giving the file descriptor
+.IR fd ,
+the buffer
+.IR buf ,
+and its size
+.IR nbuf .
+Then call
+.IR fmtprint
+or
+.IR fmtvprint
+to generate the output.
+These behave just like
+.B fprint
+(see
+.IR print (3))
+or
+.B vfprint
+except that the characters are buffered until
+.I fmtfdflush
+is called.
+A typical example of this sequence appears in the Examples section.
+.PP
+The same basic sequence applies when outputting to an allocated string:
+call
+.I fmtstrinit
+to initialize the
+.BR Fmt ,
+then call
+.I fmtprint
+and
+.I fmtvprint
+to generate the output.
+Finally,
+.I fmtstrflush
+will return the allocated string, which should be freed after use.
+Regardless of the output style or type,
+.I fmtprint
+or
+.I fmtvprint
+generates the characters.
+.SS Custom format verbs
+.I Fmtinstall
+is used to install custom verbs and flags labeled by character
+.IR c ,
+which may be any non-zero Unicode character.
+.I Fn
+should be declared as
+.IP
+.EX
+int	fn(Fmt*)
+.EE
+.PP
+.IB Fp ->r
+is the flag or verb character to cause
+.I fn
+to be called.
+In
+.IR fn ,
+.IB fp ->width ,
+.IB fp ->prec
+are the width and precision, and
+.IB fp ->flags
+the decoded flags for the verb (see
+.IR print (3)
+for a description of these items).
+The standard flag values are:
+.B FmtSign
+.RB ( + ),
+.B FmtLeft
+.RB ( - ),
+.B FmtSpace
+.RB ( '\ ' ),
+.B FmtSharp
+.RB ( # ),
+.B FmtComma
+.RB ( , ),
+.B FmtLong
+.RB ( l ),
+.B FmtShort
+.RB ( h ),
+.B FmtByte
+.RB ( hh ),
+.B FmtUnsigned
+.RB ( u ),
+.B FmtLDouble
+.RB ( L ),
+and
+.B FmtVLong
+.RB ( ll ).
+The flag bits
+.B FmtWidth
+and
+.B FmtPrec
+identify whether a width and precision were specified.
+.PP
+.I Fn
+is passed a pointer to the
+.B Fmt
+structure recording the state of the output.
+If
+.IB fp ->r
+is a verb (rather than a flag),
+.I fn
+should use 
+.B Fmt->args
+to fetch its argument from the list,
+then format it, and return zero.
+If
+.IB fp ->r
+is a flag,
+.I fn
+should return a negative value:
+the negation of one of the above flag values, or some otherwise unused power of two.
+All interpretation of
+.IB fp ->width\f1,
+.IB fp ->prec\f1,
+and
+.IB fp-> flags
+is left up to the conversion routine.
+.I Fmtinstall
+returns 0 if the installation succeeds, \-1 if it fails.
+.PP
+.IR Fmtprint
+and
+.IR fmtvprint
+may be called to
+help prepare output in custom conversion routines.
+However, these functions clear the width, precision, and flags.
+The function
+.I dofmt
+is the underlying formatter; it
+uses the existing contents of
+.B Fmt
+and should be called only by sophisticated conversion routines.
+All these routines return the number of characters
+produced.
+.PP
+Some internal functions may be useful to format primitive types.
+They honor the width, precision and flags as described in
+.IR print (3).
+.I Fmtrune
+formats a single character
+.BR r .
+.I Fmtstrcpy
+formats a string
+.BR s .
+All these routines return zero for successful execution.
+.SH EXAMPLES
+This function prints an error message with a variable
+number of arguments and then quits.
+Compared to the corresponding example in
+.IR print (3),
+this version uses a smaller buffer, will never truncate
+the output message, but might generate multiple
+.B write
+system calls to produce its output.
+.IP
+.EX
+.ta 6n +6n +6n +6n +6n +6n +6n +6n +6n
+
+void fatal(char *fmt, ...)
+{
+	Fmt f;
+	char buf[64];
+	va_list arg;
+
+	fmtfdinit(&f, 1, buf, sizeof buf);
+	fmtprint(&f, "fatal: ");
+	va_start(arg, fmt);
+	fmtvprint(&f, fmt, arg);
+	va_end(arg);
+	fmtprint(&f, "\en");
+	fmtfdflush(&f);
+	exits("fatal error");
+}
+.EE
+.PP
+This example adds a verb to print complex numbers.
+.IP
+.EX
+typedef
+struct {
+	double	r, i;
+} Complex;
+
+int
+Xfmt(Fmt *f)
+{
+	Complex c;
+
+	c = va_arg(f->args, Complex);
+	return fmtprint(f, "(%g,%g)", c.r, c.i);
+}
+
+main(...)
+{
+	Complex x;
+
+	x.r = 1.5;
+	x.i = -2.3;
+
+	fmtinstall('X', Xfmt);
+	print("x = %X\en", x);
+}
+.EE
+.SH SEE ALSO
+.IR print (3)
+.SH HISTORY
+This formatted print library originally
+appeared as part of the Plan 9 C library.
+.SH BUGS
+The Plan 9 version supports Unicode strings and produces UTF output.
+This version assumes that characters are always represented by 1-byte values.
blob - /dev/null
blob + fffe81cfcce099b044848539bc56d319ea29c9f8 (mode 644)
--- /dev/null
+++ src/libfmt/fmtlock.c
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+void
+__fmtlock(void)
+{
+	;
+}
+
+void
+__fmtunlock(void)
+{
+	;
+}
blob - /dev/null
blob + fe2ad3cc8c262face66ae8bed8bff68fa9e2be39 (mode 644)
--- /dev/null
+++ src/libfmt/fmtprint.c
@@ -0,0 +1,47 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va = f->args;
+	va_start(f->args, fmt);
+	n = dofmt(f, fmt);
+	va_end(f->args);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	f->args = va;
+	if(n >= 0)
+		return 0;
+	return n;
+}
+
blob - /dev/null
blob + 9d5633d6cd706733f80055be4251e19b790dea72 (mode 644)
--- /dev/null
+++ src/libfmt/fmtquote.c
@@ -0,0 +1,262 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by __quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ *	NUL in input
+ *	count exceeded in input
+ *	count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+	int w;
+	Rune c;
+
+	q->quoted = 0;
+	q->nbytesout = 0;
+	q->nrunesout = 0;
+	q->nbytesin = 0;
+	q->nrunesin = 0;
+	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+		if(nout < 2)
+			return;
+		q->quoted = 1;
+		q->nbytesout = 2;
+		q->nrunesout = 2;
+	}
+	for(; nin!=0; nin-=w){
+		if(s)
+			w = chartorune(&c, s);
+		else{
+			c = *r;
+			w = runelen(c);
+		}
+
+		if(c == '\0')
+			break;
+		if(runesout){
+			if(q->nrunesout+1 > nout)
+				break;
+		}else{
+			if(q->nbytesout+w > nout)
+				break;
+		}
+
+		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote(c))){
+			if(!q->quoted){
+				if(runesout){
+					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
+						break;
+				}
+				q->nrunesout += 2;	/* include quotes */
+				q->nbytesout += 2;	/* include quotes */
+				q->quoted = 1;
+			}
+			if(c == '\'')	{
+				if(runesout){
+					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w > nout)	/* no room for quotes */
+						break;
+				}
+				q->nbytesout++;
+				q->nrunesout++;	/* quotes reproduce as two characters */
+			}
+		}
+
+		/* advance input */
+		if(s)
+			s += w;
+		else
+			r++;
+		q->nbytesin += w;
+		q->nrunesin++;
+
+		/* advance output */
+		q->nbytesout += w;
+		q->nrunesout++;
+	}
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+	Rune r, *rm, *rme;
+	char *t, *s, *m, *me;
+	Rune *rt, *rs;
+	ulong fl;
+	int nc, w;
+
+	m = sin;
+	me = m + q->nbytesin;
+	rm = rin;
+	rme = rm + q->nrunesin;
+
+	w = f->width;
+	fl = f->flags;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	t = (char*)f->to;
+	s = (char*)f->stop;
+	rt = (Rune*)f->to;
+	rs = (Rune*)f->stop;
+	if(f->runes)
+		FMTRCHAR(f, rt, rs, '\'');
+	else
+		FMTRUNE(f, t, s, '\'');
+	for(nc = q->nrunesin; nc > 0; nc--){
+		if(sin){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, me-m))
+				m += chartorune(&r, m);
+			else
+				break;
+		}else{
+			if(rm >= rme)
+				break;
+			r = *(uchar*)rm++;
+		}
+		if(f->runes){
+			FMTRCHAR(f, rt, rs, r);
+			if(r == '\'')
+				FMTRCHAR(f, rt, rs, r);
+		}else{
+			FMTRUNE(f, t, s, r);
+			if(r == '\'')
+				FMTRUNE(f, t, s, r);
+		}
+	}
+
+	if(f->runes){
+		FMTRCHAR(f, rt, rs, '\'');
+		USED(rs);
+		f->nfmt += rt - (Rune *)f->to;
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		FMTRUNE(f, t, s, '\'');
+		USED(s);
+		f->nfmt += t - (char *)f->to;
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+__quotestrfmt(int runesin, Fmt *f)
+{
+	int outlen;
+	Rune *r;
+	char *s;
+	Quoteinfo q;
+
+	f->flags &= ~FmtPrec;	/* ignored for %q %Q, so disable for %s %S in easy case */
+	if(runesin){
+		r = va_arg(f->args, Rune *);
+		s = nil;
+	}else{
+		s = va_arg(f->args, char *);
+		r = nil;
+	}
+	if(!s && !r)
+		return __fmtcpy(f, (void*)"<nil>", 5, 5);
+
+	if(f->flush)
+		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
+	else if(f->runes)
+		outlen = (Rune*)f->stop - (Rune*)f->to;
+	else
+		outlen = (char*)f->stop - (char*)f->to;
+
+	__quotesetup(s, r, -1, outlen, &q, f->flags&FmtSharp, f->runes);
+//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+
+	if(runesin){
+		if(!q.quoted)
+			return __fmtrcpy(f, r, q.nrunesin);
+		return qstrfmt(nil, r, &q, f);
+	}
+
+	if(!q.quoted)
+		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
+	return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+	return __quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+	return __quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+	fmtinstall('q', quotestrfmt);
+	fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+__needsquotes(char *s, int *quotelenp)
+{
+	Quoteinfo q;
+
+	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nbytesout;
+
+	return q.quoted;
+}
+
+int
+__runeneedsquotes(Rune *r, int *quotelenp)
+{
+	Quoteinfo q;
+
+	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nrunesout;
+
+	return q.quoted;
+}
blob - /dev/null
blob + a034546bccf294e3cca51c05b9a47962da16ee93 (mode 644)
--- /dev/null
+++ src/libfmt/fmtrune.c
@@ -0,0 +1,40 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+fmtrune(Fmt *f, int r)
+{
+	Rune *rt;
+	char *t;
+	int n;
+
+	if(f->runes){
+		rt = (Rune*)f->to;
+		FMTRCHAR(f, rt, f->stop, r);
+		f->to = rt;
+		n = 1;
+	}else{
+		t = (char*)f->to;
+		FMTRUNE(f, t, f->stop, r);
+		n = t - (char*)f->to;
+		f->to = t;
+	}
+	f->nfmt += n;
+	return 0;
+}
blob - /dev/null
blob + 7af1fa241c42c1f029ba1775053abc205e699630 (mode 644)
--- /dev/null
+++ src/libfmt/fmtstr.c
@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+	char *s;
+	int n;
+
+	n = (int)f->farg;
+	n += 256;
+	f->farg = (void*)n;
+	s = (char*)f->start;
+	f->start = realloc(s, n);
+	if(f->start == nil){
+		f->start = s;
+		return 0;
+	}
+	f->to = (char*)f->start + ((char*)f->to - s);
+	f->stop = (char*)f->start + n - 1;
+	return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+	int n;
+
+	f->runes = 0;
+	n = 32;
+	f->start = malloc(n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (char*)f->start + n - 1;
+	f->flush = fmtStrFlush;
+	f->farg = (void*)n;
+	f->nfmt = 0;
+	return 0;
+}
+
+char*
+fmtstrflush(Fmt *f)
+{
+	*(char*)f->to = '\0';
+	f->to = f->start;
+	return (char*)f->start;
+}
blob - /dev/null
blob + 6aed013d95c82a1cd3150d4ba1b01287570dbaa4 (mode 644)
--- /dev/null
+++ src/libfmt/fmtvprint.c
@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+
+/*
+ * format a string into the output buffer
+ * designed for formats which themselves call fmt,
+ * but ignore any width flags
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+	va_list va;
+	int n;
+
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	va = f->args;
+	f->args = args;
+	n = dofmt(f, fmt);
+	f->flags = 0;
+	f->width = 0;
+	f->prec = 0;
+	f->args = va;
+	if(n >= 0)
+		return 0;
+	return n;
+}
+
blob - /dev/null
blob + c8b889de61cacb0a4c9cd3b44fea1724b954534c (mode 644)
--- /dev/null
+++ src/libfmt/fprint.c
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "utf.h"
+#include "fmt.h"
+
+int
+fprint(int fd, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(fd, fmt, args);
+	va_end(args);
+	return n;
+}
blob - /dev/null
blob + bb99a25ab4d41b82f60096fe078cf4374b5fa108 (mode 644)
--- /dev/null
+++ src/libfmt/mkfile
@@ -0,0 +1 @@
+<../libutf/mkfile
blob - /dev/null
blob + be78e14e520ee1daa9604cc3090de1ef7d4054ee (mode 644)
--- /dev/null
+++ src/libfmt/nan.h
@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern int __isNaN(double);
+extern int __isInf(double, int);
blob - /dev/null
blob + dbd03fc6cd33a1e393845c4d2dab7e3d99e4f995 (mode 644)
--- /dev/null
+++ src/libfmt/nan64.c
@@ -0,0 +1,72 @@
+/*
+ * 64-bit IEEE not-a-number routines.
+ * This is big/little-endian portable assuming that 
+ * the 64-bit doubles and 64-bit integers have the
+ * same byte ordering.
+ */
+
+#include "nan.h"
+
+typedef unsigned long long uvlong;
+typedef unsigned long ulong;
+
+#ifdef NEEDLL
+static uvlong uvnan    = 0x7FF0000000000001LL;
+static uvlong uvinf    = 0x7FF0000000000000LL;
+static uvlong uvneginf = 0xFFF0000000000000LL;
+#else
+static uvlong uvnan    = 0x7FF0000000000001;
+static uvlong uvinf    = 0x7FF0000000000000;
+static uvlong uvneginf = 0xFFF0000000000000;
+#endif
+
+double
+__NaN(void)
+{
+	uvlong *p;
+
+	/* gcc complains about "return *(double*)&uvnan;" */
+	p = &uvnan;
+	return *(double*)p;
+}
+
+int
+__isNaN(double d)
+{
+	uvlong x;
+	double *p;
+
+	p = &d;
+	x = *(uvlong*)p;
+	return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
+}
+
+double
+__Inf(int sign)
+{
+	uvlong *p;
+
+	if(sign < 0)
+		p = &uvinf;
+	else
+		p = &uvneginf;
+	return *(double*)p;
+}
+
+int
+__isInf(double d, int sign)
+{
+	uvlong x;
+	double *p;
+
+	p = &d;
+	x = *(uvlong*)p;
+	if(sign == 0)
+		return x==uvinf || x==uvneginf;
+	else if(sign > 0)
+		return x==uvinf;
+	else
+		return x==uvneginf;
+}
+
+
blob - /dev/null
blob + 65a426c30f87ed0feb314fc6d49d7d3e5cab4094 (mode 644)
--- /dev/null
+++ src/libfmt/pow10.c
@@ -0,0 +1,57 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+
+static
+double	tab[] =
+{
+	1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
+	1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
+	1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
+	1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
+	1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
+	1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
+	1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
+};
+
+double
+__fmtpow10(int n)
+{
+	int m;
+
+	if(n < 0) {
+		n = -n;
+		if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+			return 1/tab[n];
+		m = n/2;
+		return __fmtpow10(-m) * __fmtpow10(m-n);
+	}
+	if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+		return tab[n];
+	m = n/2;
+	return __fmtpow10(m) * __fmtpow10(n-m);
+}
blob - /dev/null
blob + 1fab0ad804bf93d81d5beb3a5ede971af2228a2d (mode 644)
--- /dev/null
+++ src/libfmt/print.3
@@ -0,0 +1,469 @@
+.TH PRINT 3
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.SH NAME
+print, fprint, sprint, snprint, seprint, smprint, vfprint, vsnprint, vseprint, vsmprint \- print formatted output
+.SH SYNOPSIS
+.B #include <utf.h>
+.PP
+.B #include <fmt.h>
+.PP
+.ta \w'\fLchar* 'u
+.B
+int	print(char *format, ...)
+.PP
+.B
+int	fprint(int fd, char *format, ...)
+.PP
+.B
+int	sprint(char *s, char *format, ...)
+.PP
+.B
+int	snprint(char *s, int len, char *format, ...)
+.PP
+.B
+char*	seprint(char *s, char *e, char *format, ...)
+.PP
+.B
+char*	smprint(char *format, ...)
+.PP
+.B
+int	runesprint(Rune *s, char *format, ...)
+.PP
+.B
+int	runesnprint(Rune *s, int len, char *format, ...)
+.PP
+.B
+Rune*	runeseprint(Rune *s, Rune *e, char *format, ...)
+.PP
+.B
+Rune*	runesmprint(char *format, ...)
+.PP
+.B
+int	vfprint(int fd, char *format, va_list v)
+.PP
+.B
+int	vsnprint(char *s, int len, char *format, va_list v)
+.PP
+.B
+char*	vseprint(char *s, char *e, char *format, va_list v)
+.PP
+.B
+char*	vsmprint(char *format, va_list v)
+.PP
+.B
+int	runevsnprint(Rune *s, int len, char *format, va_list v)
+.PP
+.B
+Rune*	runevseprint(Rune *s, Rune *e, char *format, va_list v)
+.PP
+.B
+Rune*	runevsmprint(Rune *format, va_list v)
+.PP
+.B
+.SH DESCRIPTION
+.I Print
+writes text to the standard output.
+.I Fprint
+writes to the named output
+file descriptor.
+.I Sprint
+places text
+followed by the NUL character
+.RB ( \e0 )
+in consecutive bytes starting at
+.IR s ;
+it is the user's responsibility to ensure that
+enough storage is available.
+Each function returns the number of bytes
+transmitted (not including the NUL
+in the case of
+.IR sprint ),
+or
+a negative value if an output error was encountered.
+.PP
+.I Snprint
+is like
+.IR sprint ,
+but will not place more than
+.I len
+bytes in
+.IR s .
+Its result is always NUL-terminated and holds the maximal
+number of characters that can fit.
+.I Seprint
+is like
+.IR snprint ,
+except that the end is indicated by a pointer
+.I e
+rather than a count and the return value points to the terminating NUL of the
+resulting string.
+.I Smprint
+is like
+.IR sprint ,
+except that it prints into and returns a string of the required length, which is
+allocated by
+.IR malloc (3).
+.PP
+The routines
+.IR runesprint ,
+.IR runesnprint ,
+.IR runeseprint ,
+and
+.I runesmprint
+are the same as
+.IR sprint ,
+.IR snprint ,
+.IR seprint
+and
+.I smprint
+except that their output is rune strings instead of byte strings.
+.PP
+Finally, the routines
+.IR vfprint ,
+.IR vsnprint ,
+.IR vseprint ,
+.IR vsmprint ,
+.IR runevsnprint ,
+.IR runevseprint ,
+and
+.I runevsmprint
+are like their
+.BR v-less
+relatives except they take as arguments a
+.B va_list
+parameter, so they can be called within a variadic function.
+The Example section shows a representative usage.
+.PP
+Each of these functions
+converts, formats, and prints its
+trailing arguments
+under control of a
+.IR format 
+string.
+The
+format
+contains two types of objects:
+plain characters, which are simply copied to the
+output stream,
+and conversion specifications,
+each of which results in fetching of
+zero or more
+arguments.
+The results are undefined if there are arguments of the
+wrong type or too few
+arguments for the format.
+If the format is exhausted while
+arguments remain, the excess
+is ignored.
+.PP
+Each conversion specification has the following format:
+.IP
+.B "% [flags] verb
+.PP
+The verb is a single character and each flag is a single character or a
+(decimal) numeric string.
+Up to two numeric strings may be used;
+the first is called
+.IR width ,
+the second
+.IR precision .
+A period can be used to separate them, and if the period is
+present then
+.I width
+and
+.I precision
+are taken to be zero if missing, otherwise they are `omitted'.
+Either or both of the numbers may be replaced with the character
+.BR * ,
+meaning that the actual number will be obtained from the argument list
+as an integer.
+The flags and numbers are arguments to
+the
+.I verb
+described below.
+.PP
+The numeric verbs
+.BR d ,
+.BR i ,
+.BR u ,
+.BR o ,
+.BR b ,
+.BR x ,
+and
+.B X
+format their arguments in decimal, decimal,
+unsigned decimal, octal, binary, hexadecimal, and upper case hexadecimal.
+Each interprets the flags
+.BR 0 ,
+.BR h ,
+.BR hh ,
+.BR l ,
+.BR + ,
+.BR - ,
+.BR , ,
+and
+.B #
+to mean pad with zeros,
+short, byte, long, always print a sign, left justified, commas every three digits,
+and alternate format.
+Also, a space character in the flag
+position is like
+.BR + ,
+but prints a space instead of a plus sign for non-negative values.
+If neither
+short nor long is specified,
+then the argument is an
+.BR int .
+If an unsigned verb is specified,
+then the argument is interpreted as a
+positive number and no sign is output;
+space and
+.B +
+flags are ignored for unsigned verbs.
+If two
+.B l
+flags are given,
+then the argument is interpreted as a
+.B vlong
+(usually an 8-byte, sometimes a 4-byte integer).
+If
+.I precision
+is not omitted, the number is padded on the left with zeros
+until at least
+.I precision
+digits appear.
+If
+.I precision
+is explicitly 0, and the number is 0,
+no digits are generated, and alternate formatting
+does not apply.
+Then, if alternate format is specified,
+for
+.B o
+conversion, the number is preceded by a
+.B 0
+if it doesn't already begin with one.
+For non-zero numbers and
+.B x
+conversion, the number is preceded by
+.BR 0x ;
+for
+.B X
+conversion, the number is preceded by
+.BR 0X .
+Finally, if
+.I width
+is not omitted, the number is padded on the left (or right, if
+left justification is specified) with enough blanks to
+make the field at least
+.I width
+characters long.
+.PP
+The floating point verbs
+.BR f ,
+.BR e ,
+.BR E ,
+.BR g ,
+and
+.B G
+take a
+.B double
+argument.
+Each interprets the flags
+.BR 0 ,
+.BR L
+.BR + ,
+.BR - ,
+and
+.B #
+to mean pad with zeros,
+long double argument,
+always print a sign,
+left justified,
+and
+alternate format.
+.I Width
+is the minimum field width and,
+if the converted value takes up less than
+.I width
+characters, it is padded on the left (or right, if `left justified')
+with spaces.
+.I Precision
+is the number of digits that are converted after the decimal place for
+.BR e ,
+.BR E ,
+and
+.B f
+conversions,
+and
+.I precision
+is the maximum number of significant digits for
+.B g
+and
+.B G
+conversions.
+The 
+.B f
+verb produces output of the form
+.RB [ - ] digits [ .digits\fR].
+.B E
+conversion appends an exponent
+.BR E [ - ] digits ,
+and
+.B e
+conversion appends an exponent
+.BR e [ - ] digits .
+The
+.B g
+verb will output the argument in either
+.B e
+or
+.B f
+with the goal of producing the smallest output.
+Also, trailing zeros are omitted from the fraction part of
+the output, and a trailing decimal point appears only if it is followed
+by a digit.
+The
+.B G
+verb is similar, but uses
+.B E
+format instead of
+.BR e .
+When alternate format is specified, the result will always contain a decimal point,
+and for
+.B g
+and
+.B G
+conversions, trailing zeros are not removed.
+.PP
+The
+.B s
+verb copies a string
+(pointer to
+.BR char )
+to the output.
+The number of characters copied
+.RI ( n )
+is the minimum
+of the size of the string and
+.IR precision .
+These
+.I n
+characters are justified within a field of
+.I width
+characters as described above.
+If a
+.I precision
+is given, it is safe for the string not to be nul-terminated
+as long as it is at least
+.I precision
+characters (not bytes!) long.
+The
+.B S
+verb is similar, but it interprets its pointer as an array
+of runes (see
+.IR utf (7));
+the runes are converted to
+.SM UTF
+before output.
+.PP
+The
+.B c
+verb copies a single
+.B char
+(promoted to
+.BR int )
+justified within a field of
+.I width
+characters as described above.
+The
+.B C
+verb is similar, but works on runes.
+.PP
+The
+.B p
+verb formats a pointer value.
+At the moment, it is a synonym for
+.BR x ,
+but that will change if pointers and integers are different sizes.
+.PP
+The
+.B r
+verb takes no arguments; it copies the error string returned by a call to
+.IR strerror (3)
+with an argument of
+.IR errno.
+.PP
+Custom verbs may be installed using
+.IR fmtinstall (3).
+.SH EXAMPLE
+This function prints an error message with a variable
+number of arguments and then quits.
+.IP
+.EX
+.ta 6n +6n +6n
+void fatal(char *msg, ...)
+{
+	char buf[1024], *out;
+	va_list arg;
+
+	out = vseprint(buf, buf+sizeof buf, "Fatal error: ");
+	va_start(arg, msg);
+	out = vseprint(out, buf+sizeof buf, msg, arg);
+	va_end(arg);
+	write(2, buf, out-buf);
+	exit(1);
+}
+.EE
+.SH SEE ALSO
+.IR fmtinstall (3),
+.IR fprintf (3),
+.IR utf (7)
+.SH DIAGNOSTICS
+Routines that write to a file descriptor or call
+.IR malloc
+set
+.IR errstr .
+.SH BUGS
+The formatting is close to that specified for ANSI
+.IR fprintf (3);
+the main difference is that
+.B b
+and
+.B r
+are not in ANSI and some
+.B C9X
+verbs are missing.
+Also, and distinctly not a bug,
+.I print
+and friends generate
+.SM UTF
+rather than
+.SM ASCII.
+.PP
+There is no
+.BR runeprint ,
+.BR runefprint ,
+etc. because runes are byte-order dependent and should not be written directly to a file; use the
+UTF output of
+.I print
+or
+.I fprint
+instead.
+Also,
+.I sprint
+is deprecated for safety reasons; use
+.IR snprint ,
+.IR seprint ,
+or
+.I smprint
+instead.
+Safety also precludes the existence of
+.IR runesprint .
blob - /dev/null
blob + 381a1da9253f60b4f82805d0c1768cc70681e7a9 (mode 644)
--- /dev/null
+++ src/libfmt/print.c
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "utf.h"
+#include "fmt.h"
+
+int
+print(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(1, fmt, args);
+	va_end(args);
+	return n;
+}
blob - /dev/null
blob + 2cd51484bf4be5529d9cbc88c39f3ff7e00f85e1 (mode 644)
--- /dev/null
+++ src/libfmt/rpm.spec
@@ -0,0 +1,34 @@
+Summary: Extensible formatted print library.  (Printf with user-defined verbs.)
+Name: libfmt
+Version: 2.0
+Release: 1
+Group: Development/C
+Copyright: BSD-like
+Packager: Russ Cox <rsc@post.harvard.edu>
+Source: http://pdos.lcs.mit.edu/~rsc/software/libfmt-2.0.tgz
+URL: http://pdos.lcs.mit.edu/~rsc/software/#libfmt
+Requires: libutf
+
+%description
+Libfmt is a port of Plan 9's formatted print library.
+As a base it provides all the syntax of ANSI printf
+but adds the ability for client programs to install
+new print verbs.  One such print verb (installed by
+default) is %r, which prints the system error string.
+Instead of perror("foo"), you can write fprint(2, "foo: %r\n"). 
+This is especially nice when you write verbs to format
+the data structures used by your particular program.
+%prep
+%setup
+
+%build
+make
+
+%install
+make install
+
+%files
+/usr/local/include/fmt.h
+/usr/local/lib/libfmt.a
+/usr/local/man/man3/print.3
+/usr/local/man/man3/fmtinstall.3
blob - /dev/null
blob + a2ec6cb484c814c886b50ef37c1ab32db312458e (mode 644)
--- /dev/null
+++ src/libfmt/runefmtstr.c
@@ -0,0 +1,65 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+static int
+runeFmtStrFlush(Fmt *f)
+{
+	Rune *s;
+	int n;
+
+	n = (int)f->farg;
+	n += 256;
+	f->farg = (void*)n;
+	s = (Rune*)f->start;
+	f->start = realloc(s, sizeof(Rune)*n);
+	if(f->start == nil){
+		f->start = s;
+		return 0;
+	}
+	f->to = (Rune*)f->start + ((Rune*)f->to - s);
+	f->stop = (Rune*)f->start + n - 1;
+	return 1;
+}
+
+int
+runefmtstrinit(Fmt *f)
+{
+	int n;
+
+	f->runes = 1;
+	n = 32;
+	f->start = malloc(sizeof(Rune)*n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (Rune*)f->start + n - 1;
+	f->flush = runeFmtStrFlush;
+	f->farg = (void*)n;
+	f->nfmt = 0;
+	return 0;
+}
+
+Rune*
+runefmtstrflush(Fmt *f)
+{
+	*(Rune*)f->to = '\0';
+	f->to = f->start;
+	return f->start;
+}
blob - /dev/null
blob + 7829a4399ed3aa9ac77def2c8281525fe7d2983e (mode 644)
--- /dev/null
+++ src/libfmt/runeseprint.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+Rune*
+runeseprint(Rune *buf, Rune *e, char *fmt, ...)
+{
+	Rune *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = runevseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}
blob - /dev/null
blob + 538ae0ee308d69dab05d8a2e1c91d78f3875d4b7 (mode 644)
--- /dev/null
+++ src/libfmt/runesmprint.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+Rune*
+runesmprint(char *fmt, ...)
+{
+	va_list args;
+	Rune *p;
+
+	va_start(args, fmt);
+	p = runevsmprint(fmt, args);
+	va_end(args);
+	return p;
+}
blob - /dev/null
blob + 5abb6dbf1f31dbe08a5fb187a11291a0e6a6c4da (mode 644)
--- /dev/null
+++ src/libfmt/runesnprint.c
@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+runesnprint(Rune *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = runevsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+
blob - /dev/null
blob + 8abfeb65897fefad201ee63a6f2f97953d037b83 (mode 644)
--- /dev/null
+++ src/libfmt/runesprint.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+runesprint(Rune *buf, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = runevsnprint(buf, 256, fmt, args);
+	va_end(args);
+	return n;
+}
blob - /dev/null
blob + e4cc1ea87d1db23580570fc3fb8ac7899faf16e5 (mode 644)
--- /dev/null
+++ src/libfmt/runevseprint.c
@@ -0,0 +1,39 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+Rune*
+runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 1;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(Rune*)f.to = '\0';
+	return (Rune*)f.to;
+}
+
blob - /dev/null
blob + 71c23d844d3b1791692eb1f898ac591d9dbc5bd8 (mode 644)
--- /dev/null
+++ src/libfmt/runevsmprint.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * print into an allocated string buffer
+ */
+Rune*
+runevsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(runefmtstrinit(&f) < 0)
+		return nil;
+	f.args = args;
+	n = dofmt(&f, fmt);
+	if(n < 0)
+		return nil;
+	*(Rune*)f.to = '\0';
+	return (Rune*)f.start;
+}
blob - /dev/null
blob + 933a04ca9b2a6eb226319243ebba717b52a73a01 (mode 644)
--- /dev/null
+++ src/libfmt/runevsnprint.c
@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+runevsnprint(Rune *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 1;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = nil;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(Rune*)f.to = '\0';
+	return (Rune*)f.to - buf;
+}
blob - /dev/null
blob + d5031a2b16c6de2208dc98d5db603036f797c002 (mode 644)
--- /dev/null
+++ src/libfmt/seprint.c
@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+	char *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = vseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}
blob - /dev/null
blob + 543411a0ad260fc0b31207d2f01b8e8047ae2fca (mode 644)
--- /dev/null
+++ src/libfmt/smprint.c
@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+char*
+smprint(char *fmt, ...)
+{
+	va_list args;
+	char *p;
+
+	va_start(args, fmt);
+	p = vsmprint(fmt, args);
+	va_end(args);
+	return p;
+}
blob - /dev/null
blob + 594606d21eac12a48d9ca7bc5601ef96ebf512c9 (mode 644)
--- /dev/null
+++ src/libfmt/snprint.c
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+int
+snprint(char *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+
blob - /dev/null
blob + 57150c36b205bd2f55f3598079bd814ef2104295 (mode 644)
--- /dev/null
+++ src/libfmt/sprint.c
@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+
+int
+sprint(char *buf, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, 65536, fmt, args);	/* big number, but sprint is deprecated anyway */
+	va_end(args);
+	return n;
+}
blob - /dev/null
blob + 685b7faea4dc34a86d63e977cf738e74fc378f22 (mode 644)
--- /dev/null
+++ src/libfmt/strtod.c
@@ -0,0 +1,539 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <math.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "fmt.h"
+#include "nan.h"
+
+#ifndef nelem
+#define nelem(x)	(sizeof(x)/sizeof *(x))
+#endif
+#define nil ((void*)0)
+#define ulong _fmtulong
+typedef unsigned long ulong;
+
+static ulong
+umuldiv(ulong a, ulong b, ulong c)
+{
+	double d;
+
+	d = ((double)a * (double)b) / (double)c;
+	if(d >= 4294967295.)
+		d = 4294967295.;
+	return (ulong)d;
+}
+
+/*
+ * This routine will convert to arbitrary precision
+ * floating point entirely in multi-precision fixed.
+ * The answer is the closest floating point number to
+ * the given decimal number. Exactly half way are
+ * rounded ala ieee rules.
+ * Method is to scale input decimal between .500 and .999...
+ * with external power of 2, then binary search for the
+ * closest mantissa to this decimal number.
+ * Nmant is is the required precision. (53 for ieee dp)
+ * Nbits is the max number of bits/word. (must be <= 28)
+ * Prec is calculated - the number of words of fixed mantissa.
+ */
+enum
+{
+	Nbits	= 28,				/* bits safely represented in a ulong */
+	Nmant	= 53,				/* bits of precision required */
+	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
+	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
+	Ndig	= 1500,
+	One	= (ulong)(1<<Nbits),
+	Half	= (ulong)(One>>1),
+	Maxe	= 310,
+
+	Fsign	= 1<<0,		/* found - */
+	Fesign	= 1<<1,		/* found e- */
+	Fdpoint	= 1<<2,		/* found . */
+
+	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
+	S1,			/* _+		#S2	.S3 */
+	S2,			/* _+#		#S2	.S4	eS5 */
+	S3,			/* _+.		#S4 */
+	S4,			/* _+#.#	#S4	eS5 */
+	S5,			/* _+#.#e	+S6	#S7 */
+	S6,			/* _+#.#e+	#S7 */
+	S7,			/* _+#.#e+#	#S7 */
+};
+
+static	int	xcmp(char*, char*);
+static	int	fpcmp(char*, ulong*);
+static	void	frnorm(ulong*);
+static	void	divascii(char*, int*, int*, int*);
+static	void	mulascii(char*, int*, int*, int*);
+
+typedef	struct	Tab	Tab;
+struct	Tab
+{
+	int	bp;
+	int	siz;
+	char*	cmp;
+};
+
+double
+fmtstrtod(const char *as, char **aas)
+{
+	int na, ex, dp, bp, c, i, flag, state;
+	ulong low[Prec], hig[Prec], mid[Prec];
+	double d;
+	char *s, a[Ndig];
+
+	flag = 0;	/* Fsign, Fesign, Fdpoint */
+	na = 0;		/* number of digits of a[] */
+	dp = 0;		/* na of decimal point */
+	ex = 0;		/* exonent */
+
+	state = S0;
+	for(s=(char*)as;; s++) {
+		c = *s;
+		if(c >= '0' && c <= '9') {
+			switch(state) {
+			case S0:
+			case S1:
+			case S2:
+				state = S2;
+				break;
+			case S3:
+			case S4:
+				state = S4;
+				break;
+
+			case S5:
+			case S6:
+			case S7:
+				state = S7;
+				ex = ex*10 + (c-'0');
+				continue;
+			}
+			if(na == 0 && c == '0') {
+				dp--;
+				continue;
+			}
+			if(na < Ndig-50)
+				a[na++] = c;
+			continue;
+		}
+		switch(c) {
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			if(state == S0)
+				continue;
+			break;
+		case '-':
+			if(state == S0)
+				flag |= Fsign;
+			else
+				flag |= Fesign;
+		case '+':
+			if(state == S0)
+				state = S1;
+			else
+			if(state == S5)
+				state = S6;
+			else
+				break;	/* syntax */
+			continue;
+		case '.':
+			flag |= Fdpoint;
+			dp = na;
+			if(state == S0 || state == S1) {
+				state = S3;
+				continue;
+			}
+			if(state == S2) {
+				state = S4;
+				continue;
+			}
+			break;
+		case 'e':
+		case 'E':
+			if(state == S2 || state == S4) {
+				state = S5;
+				continue;
+			}
+			break;
+		}
+		break;
+	}
+
+	/*
+	 * clean up return char-pointer
+	 */
+	switch(state) {
+	case S0:
+		if(xcmp(s, "nan") == 0) {
+			if(aas != nil)
+				*aas = s+3;
+			goto retnan;
+		}
+	case S1:
+		if(xcmp(s, "infinity") == 0) {
+			if(aas != nil)
+				*aas = s+8;
+			goto retinf;
+		}
+		if(xcmp(s, "inf") == 0) {
+			if(aas != nil)
+				*aas = s+3;
+			goto retinf;
+		}
+	case S3:
+		if(aas != nil)
+			*aas = (char*)as;
+		goto ret0;	/* no digits found */
+	case S6:
+		s--;		/* back over +- */
+	case S5:
+		s--;		/* back over e */
+		break;
+	}
+	if(aas != nil)
+		*aas = s;
+
+	if(flag & Fdpoint)
+	while(na > 0 && a[na-1] == '0')
+		na--;
+	if(na == 0)
+		goto ret0;	/* zero */
+	a[na] = 0;
+	if(!(flag & Fdpoint))
+		dp = na;
+	if(flag & Fesign)
+		ex = -ex;
+	dp += ex;
+	if(dp < -Maxe){
+		errno = ERANGE;
+		goto ret0;	/* underflow by exp */
+	} else
+	if(dp > +Maxe)
+		goto retinf;	/* overflow by exp */
+
+	/*
+	 * normalize the decimal ascii number
+	 * to range .[5-9][0-9]* e0
+	 */
+	bp = 0;		/* binary exponent */
+	while(dp > 0)
+		divascii(a, &na, &dp, &bp);
+	while(dp < 0 || a[0] < '5')
+		mulascii(a, &na, &dp, &bp);
+
+	/* close approx by naive conversion */
+	mid[0] = 0;
+	mid[1] = 1;
+	for(i=0; c=a[i]; i++) {
+		mid[0] = mid[0]*10 + (c-'0');
+		mid[1] = mid[1]*10;
+		if(i >= 8)
+			break;
+	}
+	low[0] = umuldiv(mid[0], One, mid[1]);
+	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
+	for(i=1; i<Prec; i++) {
+		low[i] = 0;
+		hig[i] = One-1;
+	}
+
+	/* binary search for closest mantissa */
+	for(;;) {
+		/* mid = (hig + low) / 2 */
+		c = 0;
+		for(i=0; i<Prec; i++) {
+			mid[i] = hig[i] + low[i];
+			if(c)
+				mid[i] += One;
+			c = mid[i] & 1;
+			mid[i] >>= 1;
+		}
+		frnorm(mid);
+
+		/* compare */
+		c = fpcmp(a, mid);
+		if(c > 0) {
+			c = 1;
+			for(i=0; i<Prec; i++)
+				if(low[i] != mid[i]) {
+					c = 0;
+					low[i] = mid[i];
+				}
+			if(c)
+				break;	/* between mid and hig */
+			continue;
+		}
+		if(c < 0) {
+			for(i=0; i<Prec; i++)
+				hig[i] = mid[i];
+			continue;
+		}
+
+		/* only hard part is if even/odd roundings wants to go up */
+		c = mid[Prec-1] & (Sigbit-1);
+		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
+			mid[Prec-1] -= c;
+		break;	/* exactly mid */
+	}
+
+	/* normal rounding applies */
+	c = mid[Prec-1] & (Sigbit-1);
+	mid[Prec-1] -= c;
+	if(c >= Sigbit/2) {
+		mid[Prec-1] += Sigbit;
+		frnorm(mid);
+	}
+	goto out;
+
+ret0:
+	return 0;
+
+retnan:
+	return __NaN();
+
+retinf:
+	/*
+	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
+	errno = ERANGE;
+	if(flag & Fsign)
+		return -HUGE_VAL;
+	return HUGE_VAL;
+
+out:
+	d = 0;
+	for(i=0; i<Prec; i++)
+		d = d*One + mid[i];
+	if(flag & Fsign)
+		d = -d;
+	d = ldexp(d, bp - Prec*Nbits);
+	if(d == 0){	/* underflow */
+		errno = ERANGE;
+	}
+	return d;
+}
+
+static void
+frnorm(ulong *f)
+{
+	int i, c;
+
+	c = 0;
+	for(i=Prec-1; i>0; i--) {
+		f[i] += c;
+		c = f[i] >> Nbits;
+		f[i] &= One-1;
+	}
+	f[0] += c;
+}
+
+static int
+fpcmp(char *a, ulong* f)
+{
+	ulong tf[Prec];
+	int i, d, c;
+
+	for(i=0; i<Prec; i++)
+		tf[i] = f[i];
+
+	for(;;) {
+		/* tf *= 10 */
+		for(i=0; i<Prec; i++)
+			tf[i] = tf[i]*10;
+		frnorm(tf);
+		d = (tf[0] >> Nbits) + '0';
+		tf[0] &= One-1;
+
+		/* compare next digit */
+		c = *a;
+		if(c == 0) {
+			if('0' < d)
+				return -1;
+			if(tf[0] != 0)
+				goto cont;
+			for(i=1; i<Prec; i++)
+				if(tf[i] != 0)
+					goto cont;
+			return 0;
+		}
+		if(c > d)
+			return +1;
+		if(c < d)
+			return -1;
+		a++;
+	cont:;
+	}
+	return 0;
+}
+
+static void
+divby(char *a, int *na, int b)
+{
+	int n, c;
+	char *p;
+
+	p = a;
+	n = 0;
+	while(n>>b == 0) {
+		c = *a++;
+		if(c == 0) {
+			while(n) {
+				c = n*10;
+				if(c>>b)
+					break;
+				n = c;
+			}
+			goto xx;
+		}
+		n = n*10 + c-'0';
+		(*na)--;
+	}
+	for(;;) {
+		c = n>>b;
+		n -= c<<b;
+		*p++ = c + '0';
+		c = *a++;
+		if(c == 0)
+			break;
+		n = n*10 + c-'0';
+	}
+	(*na)++;
+xx:
+	while(n) {
+		n = n*10;
+		c = n>>b;
+		n -= c<<b;
+		*p++ = c + '0';
+		(*na)++;
+	}
+	*p = 0;
+}
+
+static	Tab	tab1[] =
+{
+	 1,  0, "",
+	 3,  1, "7",
+	 6,  2, "63",
+	 9,  3, "511",
+	13,  4, "8191",
+	16,  5, "65535",
+	19,  6, "524287",
+	23,  7, "8388607",
+	26,  8, "67108863",
+	27,  9, "134217727",
+};
+
+static void
+divascii(char *a, int *na, int *dp, int *bp)
+{
+	int b, d;
+	Tab *t;
+
+	d = *dp;
+	if(d >= (int)(nelem(tab1)))
+		d = (int)(nelem(tab1))-1;
+	t = tab1 + d;
+	b = t->bp;
+	if(memcmp(a, t->cmp, t->siz) > 0)
+		d--;
+	*dp -= d;
+	*bp += b;
+	divby(a, na, b);
+}
+
+static void
+mulby(char *a, char *p, char *q, int b)
+{
+	int n, c;
+
+	n = 0;
+	*p = 0;
+	for(;;) {
+		q--;
+		if(q < a)
+			break;
+		c = *q - '0';
+		c = (c<<b) + n;
+		n = c/10;
+		c -= n*10;
+		p--;
+		*p = c + '0';
+	}
+	while(n) {
+		c = n;
+		n = c/10;
+		c -= n*10;
+		p--;
+		*p = c + '0';
+	}
+}
+
+static	Tab	tab2[] =
+{
+	 1,  1, "",				/* dp = 0-0 */
+	 3,  3, "125",
+	 6,  5, "15625",
+	 9,  7, "1953125",
+	13, 10, "1220703125",
+	16, 12, "152587890625",
+	19, 14, "19073486328125",
+	23, 17, "11920928955078125",
+	26, 19, "1490116119384765625",
+	27, 19, "7450580596923828125",		/* dp 8-9 */
+};
+
+static void
+mulascii(char *a, int *na, int *dp, int *bp)
+{
+	char *p;
+	int d, b;
+	Tab *t;
+
+	d = -*dp;
+	if(d >= (int)(nelem(tab2)))
+		d = (int)(nelem(tab2))-1;
+	t = tab2 + d;
+	b = t->bp;
+	if(memcmp(a, t->cmp, t->siz) < 0)
+		d--;
+	p = a + *na;
+	*bp -= b;
+	*dp += d;
+	*na += d;
+	mulby(a, p+d, p, b);
+}
+
+static int
+xcmp(char *a, char *b)
+{
+	int c1, c2;
+
+	while(c1 = *b++) {
+		c2 = *a++;
+		if(isupper(c2))
+			c2 = tolower(c2);
+		if(c1 != c2)
+			return 1;
+	}
+	return 0;
+}
blob - /dev/null
blob + 82c3d46eb05d27d1d66b8c1c903c0ec976eeb514 (mode 644)
--- /dev/null
+++ src/libfmt/strtod.h
@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern double __isNaN(double);
+extern double __isInf(double, int);
blob - /dev/null
blob + a1a1d5edc05d8ad2fcf6d32b146d8db1d2ff0a9f (mode 644)
--- /dev/null
+++ src/libfmt/test.c
@@ -0,0 +1,39 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <utf.h>
+#include "fmt.h"
+
+int
+main(int argc, char *argv[])
+{
+	quotefmtinstall();
+	print("hello world\n");
+	print("x: %x\n", 0x87654321);
+	print("u: %u\n", 0x87654321);
+	print("d: %d\n", 0x87654321);
+	print("s: %s\n", "hi there");
+	print("q: %q\n", "hi i'm here");
+	print("c: %c\n", '!');
+	print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("smiley: %C\n", (Rune)0x263a);
+	print("%g %.18\n", 2e25, 2e25);
+	print("%2.18g\n", 1.0);
+	print("%f\n", 3.1415927/4);
+	print("%d\n", 23);
+	print("%i\n", 23);
+	return 0;
+}
blob - /dev/null
blob + e4ab82acbd3837a90d8267f8c41acb5b53156fc1 (mode 644)
--- /dev/null
+++ src/libfmt/vfprint.c
@@ -0,0 +1,31 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+vfprint(int fd, char *fmt, va_list args)
+{
+	Fmt f;
+	char buf[256];
+	int n;
+
+	fmtfdinit(&f, fd, buf, sizeof(buf));
+	f.args = args;
+	n = dofmt(&f, fmt);
+	if(n > 0 && __fmtFdFlush(&f) == 0)
+		return -1;
+	return n;
+}
blob - /dev/null
blob + 85ed810bd535bcb4caa29a40664db3484562c5a8 (mode 644)
--- /dev/null
+++ src/libfmt/vseprint.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = 0;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(char*)f.to = '\0';
+	return (char*)f.to;
+}
+
blob - /dev/null
blob + 38ace62d72cab15ec012342a5ef35214c6833a91 (mode 644)
--- /dev/null
+++ src/libfmt/vsmprint.c
@@ -0,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(fmtstrinit(&f) < 0)
+		return nil;
+	f.args = args;
+	n = dofmt(&f, fmt);
+	if(n < 0)
+		return nil;
+	*(char*)f.to = '\0';
+	return (char*)f.start;
+}
blob - /dev/null
blob + 21662e6d435232962ce4dfb31a628affa1a439d3 (mode 644)
--- /dev/null
+++ src/libfmt/vsnprint.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include "fmt.h"
+#include "fmtdef.h"
+
+int
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = 0;
+	f.farg = nil;
+	f.nfmt = 0;
+	f.args = args;
+	dofmt(&f, fmt);
+	*(char*)f.to = '\0';
+	return (char*)f.to - buf;
+}
blob - /dev/null
blob + a5d7d87d79f0af66f7a5f54320edabb411b0e803 (mode 644)
--- /dev/null
+++ src/libregexp/LICENSE
@@ -0,0 +1,258 @@
+The Plan 9 software is provided under the terms of the
+Lucent Public License, Version 1.02, reproduced below,
+with the following exceptions:
+
+1. No right is granted to create derivative works of or
+   to redistribute (other than with the Plan 9 Operating System)
+   the screen imprinter fonts identified in subdirectory
+   /lib/font/bit/lucida and printer fonts (Lucida Sans Unicode, Lucida
+   Sans Italic, Lucida Sans Demibold, Lucida Typewriter, Lucida Sans
+   Typewriter83), identified in subdirectory /sys/lib/postscript/font.
+   These directories contain material copyrights by B&H Inc. and Y&Y Inc.
+
+2. The printer fonts identified in subdirectory /sys/lib/ghostscript/font
+   are subject to the GNU GPL, reproduced in the file /LICENSE.gpl.
+
+3. The ghostscript program in the subdirectory /sys/src/cmd/gs is
+   covered by the Aladdin Free Public License, reproduced in the file
+   /LICENSE.afpl.
+
+===================================================================
+
+Lucent Public License Version 1.02
+
+THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS PUBLIC
+LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE
+PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
+
+1. DEFINITIONS
+
+"Contribution" means:
+
+  a. in the case of Lucent Technologies Inc. ("LUCENT"), the Original
+     Program, and
+  b. in the case of each Contributor,
+
+     i. changes to the Program, and
+    ii. additions to the Program;
+
+    where such changes and/or additions to the Program were added to the
+    Program by such Contributor itself or anyone acting on such
+    Contributor's behalf, and the Contributor explicitly consents, in
+    accordance with Section 3C, to characterization of the changes and/or
+    additions as Contributions.
+
+"Contributor" means LUCENT and any other entity that has Contributed a
+Contribution to the Program.
+
+"Distributor" means a Recipient that distributes the Program,
+modifications to the Program, or any part thereof.
+
+"Licensed Patents" mean patent claims licensable by a Contributor
+which are necessarily infringed by the use or sale of its Contribution
+alone or when combined with the Program.
+
+"Original Program" means the original version of the software
+accompanying this Agreement as released by LUCENT, including source
+code, object code and documentation, if any.
+
+"Program" means the Original Program and Contributions or any part
+thereof
+
+"Recipient" means anyone who receives the Program under this
+Agreement, including all Contributors.
+
+2. GRANT OF RIGHTS
+
+ a. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free copyright
+    license to reproduce, prepare derivative works of, publicly display,
+    publicly perform, distribute and sublicense the Contribution of such
+    Contributor, if any, and such derivative works, in source code and
+    object code form.
+    
+ b. Subject to the terms of this Agreement, each Contributor hereby
+    grants Recipient a non-exclusive, worldwide, royalty-free patent
+    license under Licensed Patents to make, use, sell, offer to sell,
+    import and otherwise transfer the Contribution of such Contributor, if
+    any, in source code and object code form. The patent license granted
+    by a Contributor shall also apply to the combination of the
+    Contribution of that Contributor and the Program if, at the time the
+    Contribution is added by the Contributor, such addition of the
+    Contribution causes such combination to be covered by the Licensed
+    Patents. The patent license granted by a Contributor shall not apply
+    to (i) any other combinations which include the Contribution, nor to
+    (ii) Contributions of other Contributors. No hardware per se is
+    licensed hereunder.
+    
+ c. Recipient understands that although each Contributor grants the
+    licenses to its Contributions set forth herein, no assurances are
+    provided by any Contributor that the Program does not infringe the
+    patent or other intellectual property rights of any other entity. Each
+    Contributor disclaims any liability to Recipient for claims brought by
+    any other entity based on infringement of intellectual property rights
+    or otherwise. As a condition to exercising the rights and licenses
+    granted hereunder, each Recipient hereby assumes sole responsibility
+    to secure any other intellectual property rights needed, if any. For
+    example, if a third party patent license is required to allow
+    Recipient to distribute the Program, it is Recipient's responsibility
+    to acquire that license before distributing the Program.
+
+ d. Each Contributor represents that to its knowledge it has sufficient
+    copyright rights in its Contribution, if any, to grant the copyright
+    license set forth in this Agreement.
+
+3. REQUIREMENTS
+
+A. Distributor may choose to distribute the Program in any form under
+this Agreement or under its own license agreement, provided that:
+
+ a. it complies with the terms and conditions of this Agreement;
+
+ b. if the Program is distributed in source code or other tangible
+    form, a copy of this Agreement or Distributor's own license agreement
+    is included with each copy of the Program; and
+
+ c. if distributed under Distributor's own license agreement, such
+    license agreement:
+
+      i. effectively disclaims on behalf of all Contributors all warranties
+         and conditions, express and implied, including warranties or
+         conditions of title and non-infringement, and implied warranties or
+         conditions of merchantability and fitness for a particular purpose;
+     ii. effectively excludes on behalf of all Contributors all liability
+         for damages, including direct, indirect, special, incidental and
+         consequential damages, such as lost profits; and
+    iii. states that any provisions which differ from this Agreement are
+         offered by that Contributor alone and not by any other party.
+
+B. Each Distributor must include the following in a conspicuous
+   location in the Program:
+
+   Copyright (C) 2003, Lucent Technologies Inc. and others. All Rights
+   Reserved.
+
+C. In addition, each Contributor must identify itself as the
+originator of its Contribution in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution.
+Also, each Contributor must agree that the additions and/or changes
+are intended to be a Contribution. Once a Contribution is contributed,
+it may not thereafter be revoked.
+
+4. COMMERCIAL DISTRIBUTION
+
+Commercial distributors of software may accept certain
+responsibilities with respect to end users, business partners and the
+like. While this license is intended to facilitate the commercial use
+of the Program, the Distributor who includes the Program in a
+commercial product offering should do so in a manner which does not
+create potential liability for Contributors. Therefore, if a
+Distributor includes the Program in a commercial product offering,
+such Distributor ("Commercial Distributor") hereby agrees to defend
+and indemnify every Contributor ("Indemnified Contributor") against
+any losses, damages and costs (collectively"Losses") arising from
+claims, lawsuits and other legal actions brought by a third party
+against the Indemnified Contributor to the extent caused by the acts
+or omissions of such Commercial Distributor in connection with its
+distribution of the Program in a commercial product offering. The
+obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement.
+In order to qualify, an Indemnified Contributor must: a) promptly
+notify the Commercial Distributor in writing of such claim, and b)
+allow the Commercial Distributor to control, and cooperate with the
+Commercial Distributor in, the defense and any related settlement
+negotiations. The Indemnified Contributor may participate in any such
+claim at its own expense.
+
+For example, a Distributor might include the Program in a commercial
+product offering, Product X. That Distributor is then a Commercial
+Distributor. If that Commercial Distributor then makes performance
+claims, or offers warranties related to Product X, those performance
+claims and warranties are such Commercial Distributor's responsibility
+alone. Under this section, the Commercial Distributor would have to
+defend claims against the Contributors related to those performance
+claims and warranties, and if a court requires any Contributor to pay
+any damages as a result, the Commercial Distributor must pay those
+damages.
+
+5. NO WARRANTY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS
+PROVIDED ON AN"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY
+WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY
+OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and
+distributing the Program and assumes all risks associated with its
+exercise of rights under this Agreement, including but not limited to
+the risks and costs of program errors, compliance with applicable
+laws, damage to or loss of data, programs or equipment, and
+unavailability or interruption of operations.
+
+6. DISCLAIMER OF LIABILITY
+
+EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR
+ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING
+WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR
+DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+7. EXPORT CONTROL
+
+Recipient agrees that Recipient alone is responsible for compliance
+with the United States export administration regulations (and the
+export control laws and regulation of any other countries).
+
+8. GENERAL
+
+If any provision of this Agreement is invalid or unenforceable under
+applicable law, it shall not affect the validity or enforceability of
+the remainder of the terms of this Agreement, and without further
+action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.
+
+If Recipient institutes patent litigation against a Contributor with
+respect to a patent applicable to software (including a cross-claim or
+counterclaim in a lawsuit), then any patent licenses granted by that
+Contributor to such Recipient under this Agreement shall terminate as
+of the date such litigation is filed. In addition, if Recipient
+institutes patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Program
+itself (excluding combinations of the Program with other software or
+hardware) infringes such Recipient's patent(s), then such Recipient's
+rights granted under Section 2(b) shall terminate as of the date such
+litigation is filed.
+
+All Recipient's rights under this Agreement shall terminate if it
+fails to comply with any of the material terms or conditions of this
+Agreement and does not cure such failure in a reasonable period of
+time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use
+and distribution of the Program as soon as reasonably practicable.
+However, Recipient's obligations under this Agreement and any licenses
+granted by Recipient relating to the Program shall continue and
+survive.
+
+LUCENT may publish new versions (including revisions) of this
+Agreement from time to time. Each new version of the Agreement will be
+given a distinguishing version number. The Program (including
+Contributions) may always be distributed subject to the version of the
+Agreement under which it was received. In addition, after a new
+version of the Agreement is published, Contributor may elect to
+distribute the Program (including its Contributions) under the new
+version. No one other than LUCENT has the right to modify this
+Agreement. Except as expressly stated in Sections 2(a) and 2(b) above,
+Recipient receives no rights or licenses to the intellectual property
+of any Contributor under this Agreement, whether expressly, by
+implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.
+
+This Agreement is governed by the laws of the State of New York and
+the intellectual property laws of the United States of America. No
+party to this Agreement will bring a legal action under this Agreement
+more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.
+
blob - /dev/null
blob + 14b8d4e7925867693d110c320d9c5a67dcd16758 (mode 644)
--- /dev/null
+++ src/libregexp/Make.Darwin-PowerMacintosh
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libregexp/Make.FreeBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + edbdc111a2a0c008975e297c7ca60e46199397a9 (mode 644)
--- /dev/null
+++ src/libregexp/Make.HP-UX-9000
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS=-O -c -Ae -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 74b0252c6eae6331b48ede7fcfa1ed760609d1a3 (mode 644)
--- /dev/null
+++ src/libregexp/Make.Linux-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libregexp/Make.NetBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 3d45279bba28dbe69c00f89568c444ab83a4ac72 (mode 644)
--- /dev/null
+++ src/libregexp/Make.OSF1-alpha
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + c5fe67b82d86c731a56c101e522e804390e5bd5a (mode 644)
--- /dev/null
+++ src/libregexp/Make.SunOS-sun4u
@@ -0,0 +1,2 @@
+include Make.SunOS-sun4u-$(CC)
+NAN=nan64.$O
blob - /dev/null
blob + 829301de8649d40632eb809ae512598af11d48c5 (mode 644)
--- /dev/null
+++ src/libregexp/Make.SunOS-sun4u-cc
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I. -O
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 5c41594812a4a27eb848d384cbc356d206c0a44b (mode 644)
--- /dev/null
+++ src/libregexp/Make.SunOS-sun4u-gcc
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 498359a3e04b3425f1538a11c51af0c7549619c3 (mode 644)
--- /dev/null
+++ src/libregexp/Makefile
@@ -0,0 +1,106 @@
+
+# this works in gnu make
+SYSNAME:=${shell uname}
+OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
+
+# this works in bsd make
+SYSNAME!=uname
+OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
+
+# the gnu rules will mess up bsd but not vice versa,
+# hence the gnu rules come first.
+
+include Make.$(SYSNAME)-$(OBJTYPE)
+
+PREFIX=/usr/local
+
+NUKEFILES=
+
+TGZFILES=
+
+LIB=libregexp9.a
+VERSION=2.0
+PORTPLACE=devel/libregexp9
+NAME=libregexp9
+
+OFILES=\
+	regcomp.$O\
+	regerror.$O\
+	regexec.$O\
+	regsub.$O\
+	regaux.$O\
+	rregsub.$O\
+	rregaux.$O\
+	rregexec.$O\
+
+HFILES=\
+	regexp9.h\
+	regcomp.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	test -d $(PREFIX)/man/man7 || mkdir $(PREFIX)/man/man7
+	install -m 0644 regexp9.3 $(PREFIX)/man/man3/regexp9.3
+	install -m 0644 regexp9.7 $(PREFIX)/man/man7/regexp9.7
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+	install -m 0644 regexp9.h $(PREFIX)/include/regexp9.h
+
+test: test.$O $(LIB)
+	$(CC) -o test test.$O $(LIB) -L/usr/local/lib -lfmt -lutf
+
+test2: test2.$O $(LIB)
+	$(CC) -o test2 test2.$O $(LIB) -L/usr/local/lib -lfmt -lutf
+
+$(LIB): $(OFILES)
+	$(AR) $(ARFLAGS) $(LIB) $(OFILES)
+
+NUKEFILES+=$(LIB)
+.c.$O:
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+%.$O: %.c
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+
+$(OFILES): $(HFILES)
+
+tgz:
+	rm -rf $(NAME)-$(VERSION)
+	mkdir $(NAME)-$(VERSION)
+	cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION)
+	tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz
+	rm -rf $(NAME)-$(VERSION)
+
+clean:
+	rm -f $(OFILES) $(LIB)
+
+nuke:
+	rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES)
+
+rpm:
+	make tgz
+	cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES
+	rpm -ba rpm.spec
+	cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm .
+	cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm .
+	scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software
+
+PORTDIR=/usr/ports/$(PORTPLACE)
+
+ports:
+	make tgz
+	rm -rf $(PORTDIR)
+	mkdir $(PORTDIR)
+	cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles
+	cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}')
+	(cd $(PORTDIR); make makesum)
+	(cd $(PORTDIR); make)
+	(cd $(PORTDIR); /usr/local/bin/portlint)
+	rm -rf $(PORTDIR)/work
+	shar `find $(PORTDIR)` > ports.shar
+	(cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz
+	scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software
+
+.phony: all clean nuke install tgz rpm ports
blob - /dev/null
blob + fa8a3a931e3d38f05609f8dd188391a195c4bb64 (mode 644)
--- /dev/null
+++ src/libregexp/Makefile.MID
@@ -0,0 +1,34 @@
+LIB=libregexp9.a
+VERSION=2.0
+PORTPLACE=devel/libregexp9
+NAME=libregexp9
+
+OFILES=\
+	regcomp.$O\
+	regerror.$O\
+	regexec.$O\
+	regsub.$O\
+	regaux.$O\
+	rregsub.$O\
+	rregaux.$O\
+
+HFILES=\
+	regexp9.h\
+	regcomp.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	test -d $(PREFIX)/man/man7 || mkdir $(PREFIX)/man/man7
+	install -m 0644 regexp9.3 $(PREFIX)/man/man3/regexp9.3
+	install -m 0644 regexp9.7 $(PREFIX)/man/man7/regexp9.7
+	install -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+	install -m 0644 regexp9.h $(PREFIX)/include/regexp9.h
+
+test: test.$O $(LIB)
+	$(CC) -o test test.$O $(LIB) -L/usr/local/lib -lfmt -lutf
+
+test2: test2.$O $(LIB)
+	$(CC) -o test2 test2.$O $(LIB) -L/usr/local/lib -lfmt -lutf
+
blob - /dev/null
blob + 784ee1d0eae0699b0407ea60e65a144eedef42da (mode 644)
--- /dev/null
+++ src/libregexp/NOTICE
@@ -0,0 +1,25 @@
+Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+
+Under a licence agreement with Lucent Technologies Inc. effective 1st March 2000,
+Vita Nuova Holdings Limited has the right to determine (within a specified scope)
+the form and content of sublicences for this software.
+
+Vita Nuova Holdings Limited now makes this software available as Free
+Software under the terms of the `GNU Lesser Public License, Version 2.1'
+(see the file LICENCE or http://www.fsf.org/copyleft/lesser.html for
+the full terms and conditions).  One of the conditions of that licence
+is that you must keep intact all notices that refer to that licence and to the absence of
+of any warranty: for this software, note that includes this NOTICE file in particular.
+  
+This suite of programs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+`GNU General Public License' for more details.
+
+This copyright NOTICE applies to all files in this directory and
+subdirectories, unless another copyright notice appears in a given
+file or subdirectory.  If you take code from this software to use in
+other programs, you must somehow include with it an appropriate
+copyright notice that includes the copyright notice and the other
+notices above.
blob - /dev/null
blob + 1f625112ee36a10edc55a42421b76f2801d61d4a (mode 644)
--- /dev/null
+++ src/libregexp/README
@@ -0,0 +1,7 @@
+This is a Unix port of the Plan 9 regular expression library,
+originally done for the Inferno operating system.
+
+Russ Cox repackaged this to build as a standalone
+Unix library.  Send comments about packaging to
+Russ Cox <rsc@post.harvard.edu>
+
blob - /dev/null
blob + 2205e4b94535176a1d4ec978df7cbded1ee482b2 (mode 644)
--- /dev/null
+++ src/libregexp/bundle.ports
@@ -0,0 +1,51 @@
+--- Makefile ---
+# New ports collection makefile for: libbio
+# Date Created:		11 Feb 2003
+# Whom:			rsc
+#
+# THIS LINE NEEDS REPLACING.  IT'S HERE TO GET BY PORTLINT
+# $FreeBSD: ports/devel/libbio/Makefile,v 1.1 2003/02/12 00:51:22 rsc Exp $
+
+PORTNAME=	libregexp9
+PORTVERSION=	2.0
+CATEGORIES=	devel
+MASTER_SITES=	http://pdos.lcs.mit.edu/~rsc/software/
+EXTRACT_SUFX=	.tgz
+
+MAINTAINER=	rsc@post.harvard.edu
+
+DEPENDS=	${PORTSDIR}/devel/libfmt ${PORTSDIR}/devel/libutf
+
+MAN3=		regexp9.3
+MAN7=		regexp9.7
+USE_REINPLACE=	yes
+
+.include <bsd.port.pre.mk>
+
+post-patch:
+	${REINPLACE_CMD} -e 's,$$(PREFIX),${PREFIX},g' ${WRKSRC}/Makefile
+
+.include <bsd.port.post.mk>
+--- pkg-comment ---
+Simple regular expression library from Plan 9
+--- pkg-descr ---
+Libregexp9 is a port of Plan 9's regexp library.
+It is small and simple and provides the traditional
+extended regular expressions (as opposed to the
+current extended regular expressions, which add {}
+and various \x character classes, among other 
+complications).
+
+It handles Unicode in wide character or UTF8 format!
+
+WWW: http://pdos.lcs.mit.edu/~rsc/software/
+http://plan9.bell-labs.com/magic/man2html/2/regexp
+
+Russ Cox
+rsc@post.harvard.edu
+--- pkg-plist ---
+lib/libregexp9.a
+include/regex9.h
+--- /dev/null ---
+This is just a way to make sure blank lines don't
+creep into pkg-plist.
blob - /dev/null
blob + d022656d3a471e87175696097046c89b7a739a77 (mode 644)
--- /dev/null
+++ src/libregexp/lib9.h
@@ -0,0 +1,6 @@
+#include <fmt.h>
+#include <setjmp.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
blob - /dev/null
blob + bb99a25ab4d41b82f60096fe078cf4374b5fa108 (mode 644)
--- /dev/null
+++ src/libregexp/mkfile
@@ -0,0 +1 @@
+<../libutf/mkfile
blob - /dev/null
blob + 956c1eb06c71d75ca34627825403e0ed31a267b4 (mode 644)
--- /dev/null
+++ src/libregexp/regaux.c
@@ -0,0 +1,76 @@
+#include "lib9.h"
+#include "regexp9.h"
+#include "regcomp.h"
+
+
+/*
+ *  save a new match in mp
+ */
+extern void
+_renewmatch(Resub *mp, int ms, Resublist *sp)
+{
+	int i;
+
+	if(mp==0 || ms<=0)
+		return;
+	if(mp[0].s.sp==0 || sp->m[0].s.sp<mp[0].s.sp ||
+	   (sp->m[0].s.sp==mp[0].s.sp && sp->m[0].e.ep>mp[0].e.ep)){
+		for(i=0; i<ms && i<NSUBEXP; i++)
+			mp[i] = sp->m[i];
+		for(; i<ms; i++)
+			mp[i].s.sp = mp[i].e.ep = 0;
+	}
+}
+
+/*
+ * Note optimization in _renewthread:
+ * 	*lp must be pending when _renewthread called; if *l has been looked
+ *		at already, the optimization is a bug.
+ */
+extern Relist*
+_renewthread(Relist *lp,	/* _relist to add to */
+	Reinst *ip,		/* instruction to add */
+	Resublist *sep)		/* pointers to subexpressions */
+{
+	Relist *p;
+
+	for(p=lp; p->inst; p++){
+		if(p->inst == ip){
+			if((sep)->m[0].s.sp < p->se.m[0].s.sp)
+				p->se = *sep;
+			return 0;
+		}
+	}
+	p->inst = ip;
+	p->se = *sep;
+	(++p)->inst = 0;
+	return p;
+}
+
+/*
+ * same as renewthread, but called with
+ * initial empty start pointer.
+ */
+extern Relist*
+_renewemptythread(Relist *lp,	/* _relist to add to */
+	Reinst *ip,		/* instruction to add */
+	char *sp)		/* pointers to subexpressions */
+{
+	Relist *p;
+
+	for(p=lp; p->inst; p++){
+		if(p->inst == ip){
+			if(sp < p->se.m[0].s.sp) {
+				memset((void *)&p->se, 0, sizeof(p->se));
+				p->se.m[0].s.sp = sp;
+			}
+			return 0;
+		}
+	}
+	p->inst = ip;
+	memset((void *)&p->se, 0, sizeof(p->se));
+	p->se.m[0].s.sp = sp;
+	(++p)->inst = 0;
+	return p;
+}
+
blob - /dev/null
blob + 6c6939c6de65fc4fc03e20cd9ff85fed1a56d9df (mode 644)
--- /dev/null
+++ src/libregexp/regcomp.c
@@ -0,0 +1,557 @@
+#include "lib9.h"
+#include "regexp9.h"
+#include "regcomp.h"
+
+#define	TRUE	1
+#define	FALSE	0
+
+/*
+ * Parser Information
+ */
+typedef
+struct Node
+{
+	Reinst*	first;
+	Reinst*	last;
+}Node;
+
+Reprog	RePrOg;
+
+#define	NSTACK	20
+static	Node	andstack[NSTACK];
+static	Node	*andp;
+static	int	atorstack[NSTACK];
+static	int*	atorp;
+static	int	cursubid;		/* id of current subexpression */
+static	int	subidstack[NSTACK];	/* parallel to atorstack */
+static	int*	subidp;
+static	int	lastwasand;	/* Last token was operand */
+static	int	nbra;
+static	char*	exprp;		/* pointer to next character in source expression */
+static	int	lexdone;
+static	int	nclass;
+static	Reclass*classp;
+static	Reinst*	freep;
+static	int	errors;
+static	Rune	yyrune;		/* last lex'd rune */
+static	Reclass*yyclassp;	/* last lex'd class */
+
+/* predeclared crap */
+static	void	operator(int);
+static	void	pushand(Reinst*, Reinst*);
+static	void	pushator(int);
+static	void	evaluntil(int);
+static	int	bldcclass(void);
+
+static jmp_buf regkaboom;
+
+static	void
+rcerror(char *s)
+{
+	errors++;
+	regerror(s);
+	longjmp(regkaboom, 1);
+}
+
+static	Reinst*
+newinst(int t)
+{
+	freep->type = t;
+	freep->u2.left = 0;
+	freep->u1.right = 0;
+	return freep++;
+}
+
+static	void
+operand(int t)
+{
+	Reinst *i;
+
+	if(lastwasand)
+		operator(CAT);	/* catenate is implicit */
+	i = newinst(t);
+
+	if(t == CCLASS || t == NCCLASS)
+		i->u1.cp = yyclassp;
+	if(t == RUNE)
+		i->u1.r = yyrune;
+
+	pushand(i, i);
+	lastwasand = TRUE;
+}
+
+static	void
+operator(int t)
+{
+	if(t==RBRA && --nbra<0)
+		rcerror("unmatched right paren");
+	if(t==LBRA){
+		if(++cursubid >= NSUBEXP)
+			rcerror ("too many subexpressions");
+		nbra++;
+		if(lastwasand)
+			operator(CAT);
+	} else
+		evaluntil(t);
+	if(t != RBRA)
+		pushator(t);
+	lastwasand = FALSE;
+	if(t==STAR || t==QUEST || t==PLUS || t==RBRA)
+		lastwasand = TRUE;	/* these look like operands */
+}
+
+static	void
+regerr2(char *s, int c)
+{
+	char buf[100];
+	char *cp = buf;
+	while(*s)
+		*cp++ = *s++;
+	*cp++ = c;
+	*cp = '\0'; 
+	rcerror(buf);
+}
+
+static	void
+cant(char *s)
+{
+	char buf[100];
+	strcpy(buf, "can't happen: ");
+	strcat(buf, s);
+	rcerror(buf);
+}
+
+static	void
+pushand(Reinst *f, Reinst *l)
+{
+	if(andp >= &andstack[NSTACK])
+		cant("operand stack overflow");
+	andp->first = f;
+	andp->last = l;
+	andp++;
+}
+
+static	void
+pushator(int t)
+{
+	if(atorp >= &atorstack[NSTACK])
+		cant("operator stack overflow");
+	*atorp++ = t;
+	*subidp++ = cursubid;
+}
+
+static	Node*
+popand(int op)
+{
+	Reinst *inst;
+
+	if(andp <= &andstack[0]){
+		regerr2("missing operand for ", op);
+		inst = newinst(NOP);
+		pushand(inst,inst);
+	}
+	return --andp;
+}
+
+static	int
+popator(void)
+{
+	if(atorp <= &atorstack[0])
+		cant("operator stack underflow");
+	--subidp;
+	return *--atorp;
+}
+
+static	void
+evaluntil(int pri)
+{
+	Node *op1, *op2;
+	Reinst *inst1, *inst2;
+
+	while(pri==RBRA || atorp[-1]>=pri){
+		switch(popator()){
+		default:
+			rcerror("unknown operator in evaluntil");
+			break;
+		case LBRA:		/* must have been RBRA */
+			op1 = popand('(');
+			inst2 = newinst(RBRA);
+			inst2->u1.subid = *subidp;
+			op1->last->u2.next = inst2;
+			inst1 = newinst(LBRA);
+			inst1->u1.subid = *subidp;
+			inst1->u2.next = op1->first;
+			pushand(inst1, inst2);
+			return;
+		case OR:
+			op2 = popand('|');
+			op1 = popand('|');
+			inst2 = newinst(NOP);
+			op2->last->u2.next = inst2;
+			op1->last->u2.next = inst2;
+			inst1 = newinst(OR);
+			inst1->u1.right = op1->first;
+			inst1->u2.left = op2->first;
+			pushand(inst1, inst2);
+			break;
+		case CAT:
+			op2 = popand(0);
+			op1 = popand(0);
+			op1->last->u2.next = op2->first;
+			pushand(op1->first, op2->last);
+			break;
+		case STAR:
+			op2 = popand('*');
+			inst1 = newinst(OR);
+			op2->last->u2.next = inst1;
+			inst1->u1.right = op2->first;
+			pushand(inst1, inst1);
+			break;
+		case PLUS:
+			op2 = popand('+');
+			inst1 = newinst(OR);
+			op2->last->u2.next = inst1;
+			inst1->u1.right = op2->first;
+			pushand(op2->first, inst1);
+			break;
+		case QUEST:
+			op2 = popand('?');
+			inst1 = newinst(OR);
+			inst2 = newinst(NOP);
+			inst1->u2.left = inst2;
+			inst1->u1.right = op2->first;
+			op2->last->u2.next = inst2;
+			pushand(inst1, inst2);
+			break;
+		}
+	}
+}
+
+static	Reprog*
+optimize(Reprog *pp)
+{
+	Reinst *inst, *target;
+	int size;
+	Reprog *npp;
+	Reclass *cl;
+	int diff;
+
+	/*
+	 *  get rid of NOOP chains
+	 */
+	for(inst=pp->firstinst; inst->type!=END; inst++){
+		target = inst->u2.next;
+		while(target->type == NOP)
+			target = target->u2.next;
+		inst->u2.next = target;
+	}
+
+	/*
+	 *  The original allocation is for an area larger than
+	 *  necessary.  Reallocate to the actual space used
+	 *  and then relocate the code.
+	 */
+	size = sizeof(Reprog) + (freep - pp->firstinst)*sizeof(Reinst);
+	npp = (Reprog *)realloc(pp, size);
+	if(npp==0 || npp==pp)
+		return pp;
+	diff = (char *)npp - (char *)pp;
+	freep = (Reinst *)((char *)freep + diff);
+	for(inst=npp->firstinst; inst<freep; inst++){
+		switch(inst->type){
+		case OR:
+		case STAR:
+		case PLUS:
+		case QUEST:
+			*(char **)&inst->u1.right += diff;
+			break;
+		case CCLASS:
+		case NCCLASS:
+			*(char **)&inst->u1.right += diff;
+			cl = inst->u1.cp;
+			*(char **)&cl->end += diff;
+			break;
+		}
+		*(char **)&inst->u2.left += diff;
+	}
+	*(char **)&npp->startinst += diff;
+	return npp;
+}
+
+#ifdef	DEBUG
+static	void
+dumpstack(void){
+	Node *stk;
+	int *ip;
+
+	print("operators\n");
+	for(ip=atorstack; ip<atorp; ip++)
+		print("0%o\n", *ip);
+	print("operands\n");
+	for(stk=andstack; stk<andp; stk++)
+		print("0%o\t0%o\n", stk->first->type, stk->last->type);
+}
+
+static	void
+dump(Reprog *pp)
+{
+	Reinst *l;
+	Rune *p;
+
+	l = pp->firstinst;
+	do{
+		print("%d:\t0%o\t%d\t%d", l-pp->firstinst, l->type,
+			l->u2.left-pp->firstinst, l->u1.right-pp->firstinst);
+		if(l->type == RUNE)
+			print("\t%C\n", l->r);
+		else if(l->type == CCLASS || l->type == NCCLASS){
+			print("\t[");
+			if(l->type == NCCLASS)
+				print("^");
+			for(p = l->cp->spans; p < l->cp->end; p += 2)
+				if(p[0] == p[1])
+					print("%C", p[0]);
+				else
+					print("%C-%C", p[0], p[1]);
+			print("]\n");
+		} else
+			print("\n");
+	}while(l++->type);
+}
+#endif
+
+static	Reclass*
+newclass(void)
+{
+	if(nclass >= NCLASS)
+		regerr2("too many character classes; limit", NCLASS+'0');
+	return &(classp[nclass++]);
+}
+
+static	int
+nextc(Rune *rp)
+{
+	if(lexdone){
+		*rp = 0;
+		return 1;
+	}
+	exprp += chartorune(rp, exprp);
+	if(*rp == L'\\'){
+		exprp += chartorune(rp, exprp);
+		return 1;
+	}
+	if(*rp == 0)
+		lexdone = 1;
+	return 0;
+}
+
+static	int
+lex(int literal, int dot_type)
+{
+	int quoted;
+
+	quoted = nextc(&yyrune);
+	if(literal || quoted){
+		if(yyrune == 0)
+			return END;
+		return RUNE;
+	}
+
+	switch(yyrune){
+	case 0:
+		return END;
+	case L'*':
+		return STAR;
+	case L'?':
+		return QUEST;
+	case L'+':
+		return PLUS;
+	case L'|':
+		return OR;
+	case L'.':
+		return dot_type;
+	case L'(':
+		return LBRA;
+	case L')':
+		return RBRA;
+	case L'^':
+		return BOL;
+	case L'$':
+		return EOL;
+	case L'[':
+		return bldcclass();
+	}
+	return RUNE;
+}
+
+static int
+bldcclass(void)
+{
+	int type;
+	Rune r[NCCRUNE];
+	Rune *p, *ep, *np;
+	Rune rune;
+	int quoted;
+
+	/* we have already seen the '[' */
+	type = CCLASS;
+	yyclassp = newclass();
+
+	/* look ahead for negation */
+	/* SPECIAL CASE!!! negated classes don't match \n */
+	ep = r;
+	quoted = nextc(&rune);
+	if(!quoted && rune == L'^'){
+		type = NCCLASS;
+		quoted = nextc(&rune);
+		*ep++ = L'\n';
+		*ep++ = L'\n';
+	}
+
+	/* parse class into a set of spans */
+	for(; ep<&r[NCCRUNE];){
+		if(rune == 0){
+			rcerror("malformed '[]'");
+			return 0;
+		}
+		if(!quoted && rune == L']')
+			break;
+		if(!quoted && rune == L'-'){
+			if(ep == r){
+				rcerror("malformed '[]'");
+				return 0;
+			}
+			quoted = nextc(&rune);
+			if((!quoted && rune == L']') || rune == 0){
+				rcerror("malformed '[]'");
+				return 0;
+			}
+			*(ep-1) = rune;
+		} else {
+			*ep++ = rune;
+			*ep++ = rune;
+		}
+		quoted = nextc(&rune);
+	}
+
+	/* sort on span start */
+	for(p = r; p < ep; p += 2){
+		for(np = p; np < ep; np += 2)
+			if(*np < *p){
+				rune = np[0];
+				np[0] = p[0];
+				p[0] = rune;
+				rune = np[1];
+				np[1] = p[1];
+				p[1] = rune;
+			}
+	}
+
+	/* merge spans */
+	np = yyclassp->spans;
+	p = r;
+	if(r == ep)
+		yyclassp->end = np;
+	else {
+		np[0] = *p++;
+		np[1] = *p++;
+		for(; p < ep; p += 2)
+			if(p[0] <= np[1]){
+				if(p[1] > np[1])
+					np[1] = p[1];
+			} else {
+				np += 2;
+				np[0] = p[0];
+				np[1] = p[1];
+			}
+		yyclassp->end = np+2;
+	}
+
+	return type;
+}
+
+static	Reprog*
+regcomp1(char *s, int literal, int dot_type)
+{
+	int token;
+	Reprog *pp;
+
+	/* get memory for the program */
+	pp = (Reprog *)malloc(sizeof(Reprog) + 6*sizeof(Reinst)*strlen(s));
+	if(pp == 0){
+		regerror("out of memory");
+		return 0;
+	}
+	freep = pp->firstinst;
+	classp = pp->class;
+	errors = 0;
+
+	if(setjmp(regkaboom))
+		goto out;
+
+	/* go compile the sucker */
+	lexdone = 0;
+	exprp = s;
+	nclass = 0;
+	nbra = 0;
+	atorp = atorstack;
+	andp = andstack;
+	subidp = subidstack;
+	lastwasand = FALSE;
+	cursubid = 0;
+
+	/* Start with a low priority operator to prime parser */
+	pushator(START-1);
+	while((token = lex(literal, dot_type)) != END){
+		if((token&0300) == OPERATOR)
+			operator(token);
+		else
+			operand(token);
+	}
+
+	/* Close with a low priority operator */
+	evaluntil(START);
+
+	/* Force END */
+	operand(END);
+	evaluntil(START);
+#ifdef DEBUG
+	dumpstack();
+#endif
+	if(nbra)
+		rcerror("unmatched left paren");
+	--andp;	/* points to first and only operand */
+	pp->startinst = andp->first;
+#ifdef DEBUG
+	dump(pp);
+#endif
+	pp = optimize(pp);
+#ifdef DEBUG
+	print("start: %d\n", andp->first-pp->firstinst);
+	dump(pp);
+#endif
+out:
+	if(errors){
+		free(pp);
+		pp = 0;
+	}
+	return pp;
+}
+
+extern	Reprog*
+regcomp(char *s)
+{
+	return regcomp1(s, 0, ANY);
+}
+
+extern	Reprog*
+regcomplit(char *s)
+{
+	return regcomp1(s, 1, ANY);
+}
+
+extern	Reprog*
+regcompnl(char *s)
+{
+	return regcomp1(s, 0, ANYNL);
+}
blob - /dev/null
blob + a6728b0e0850f6d5a5288294992e68cce0814e53 (mode 644)
--- /dev/null
+++ src/libregexp/regcomp.h
@@ -0,0 +1,74 @@
+/*
+ *  substitution list
+ */
+#define uchar __reuchar
+typedef unsigned char uchar;
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+#define NSUBEXP 32
+typedef struct Resublist	Resublist;
+struct	Resublist
+{
+	Resub	m[NSUBEXP];
+};
+
+/* max character classes per program */
+extern Reprog	RePrOg;
+#define	NCLASS	(sizeof(RePrOg.class)/sizeof(Reclass))
+
+/* max rune ranges per character class */
+#define NCCRUNE	(sizeof(Reclass)/sizeof(Rune))
+
+/*
+ * Actions and Tokens (Reinst types)
+ *
+ *	02xx are operators, value == precedence
+ *	03xx are tokens, i.e. operands for operators
+ */
+#define RUNE		0177
+#define	OPERATOR	0200	/* Bitmask of all operators */
+#define	START		0200	/* Start, used for marker on stack */
+#define	RBRA		0201	/* Right bracket, ) */
+#define	LBRA		0202	/* Left bracket, ( */
+#define	OR		0203	/* Alternation, | */
+#define	CAT		0204	/* Concatentation, implicit operator */
+#define	STAR		0205	/* Closure, * */
+#define	PLUS		0206	/* a+ == aa* */
+#define	QUEST		0207	/* a? == a|nothing, i.e. 0 or 1 a's */
+#define	ANY		0300	/* Any character except newline, . */
+#define	ANYNL		0301	/* Any character including newline, . */
+#define	NOP		0302	/* No operation, internal use only */
+#define	BOL		0303	/* Beginning of line, ^ */
+#define	EOL		0304	/* End of line, $ */
+#define	CCLASS		0305	/* Character class, [] */
+#define	NCCLASS		0306	/* Negated character class, [] */
+#define	END		0377	/* Terminate: match found */
+
+/*
+ *  regexec execution lists
+ */
+#define LISTSIZE	10
+#define BIGLISTSIZE	(10*LISTSIZE)
+typedef struct Relist	Relist;
+struct Relist
+{
+	Reinst*		inst;		/* Reinstruction of the thread */
+	Resublist	se;		/* matched subexpressions in this thread */
+};
+typedef struct Reljunk	Reljunk;
+struct	Reljunk
+{
+	Relist*	relist[2];
+	Relist*	reliste[2];
+	int	starttype;
+	Rune	startchar;
+	char*	starts;
+	char*	eol;
+	Rune*	rstarts;
+	Rune*	reol;
+};
+
+extern Relist*	_renewthread(Relist*, Reinst*, Resublist*);
+extern void	_renewmatch(Resub*, int, Resublist*);
+extern Relist*	_renewemptythread(Relist*, Reinst*, char*);
+extern Relist*	_rrenewemptythread(Relist*, Reinst*, Rune*);
blob - /dev/null
blob + 2cd1e3e28c7b9d1a2ac2c4b94823e28f9a9bb12d (mode 644)
--- /dev/null
+++ src/libregexp/regerror.c
@@ -0,0 +1,14 @@
+#include "lib9.h"
+#include "regexp9.h"
+
+void
+regerror(char *s)
+{
+	char buf[132];
+
+	strcpy(buf, "regerror: ");
+	strcat(buf, s);
+	strcat(buf, "\n");
+	write(2, buf, strlen(buf));
+	exit(1);
+}
blob - /dev/null
blob + c9f1eba291bcab26f7d4017e10dc68ac4f200d7c (mode 644)
--- /dev/null
+++ src/libregexp/regexec.c
@@ -0,0 +1,219 @@
+#include "lib9.h"
+#include "regexp9.h"
+#include "regcomp.h"
+
+
+/*
+ *  return	0 if no match
+ *		>0 if a match
+ *		<0 if we ran out of _relist space
+ */
+static int
+regexec1(Reprog *progp,	/* program to run */
+	char *bol,	/* string to run machine on */
+	Resub *mp,	/* subexpression elements */
+	int ms,		/* number of elements at mp */
+	Reljunk *j
+)
+{
+	int flag=0;
+	Reinst *inst;
+	Relist *tlp;
+	char *s;
+	int i, checkstart;
+	Rune r, *rp, *ep;
+	int n;
+	Relist* tl;		/* This list, next list */
+	Relist* nl;
+	Relist* tle;		/* ends of this and next list */
+	Relist* nle;
+	int match;
+	char *p;
+
+	match = 0;
+	checkstart = j->starttype;
+	if(mp)
+		for(i=0; i<ms; i++) {
+			mp[i].s.sp = 0;
+			mp[i].e.ep = 0;
+		}
+	j->relist[0][0].inst = 0;
+	j->relist[1][0].inst = 0;
+
+	/* Execute machine once for each character, including terminal NUL */
+	s = j->starts;
+	do{
+		/* fast check for first char */
+		if(checkstart) {
+			switch(j->starttype) {
+			case RUNE:
+				p = utfrune(s, j->startchar);
+				if(p == 0)
+					return match;
+				s = p;
+				break;
+			case BOL:
+				if(s == bol)
+					break;
+				p = utfrune(s, '\n');
+				if(p == 0)
+					return match;
+				s = p;
+				break;
+			}
+		}
+		r = *(uchar*)s;
+		if(r < (Rune)Runeself)
+			n = 1;
+		else
+			n = chartorune(&r, s);
+
+		/* switch run lists */
+		tl = j->relist[flag];
+		tle = j->reliste[flag];
+		nl = j->relist[flag^=1];
+		nle = j->reliste[flag];
+		nl->inst = 0;
+
+		/* Add first instruction to current list */
+		if(match == 0)
+			_renewemptythread(tl, progp->startinst, s);
+
+		/* Execute machine until current list is empty */
+		for(tlp=tl; tlp->inst; tlp++){	/* assignment = */
+			for(inst = tlp->inst; ; inst = inst->u2.next){
+				switch(inst->type){
+				case RUNE:	/* regular character */
+					if(inst->u1.r == r){
+						if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					}
+					break;
+				case LBRA:
+					tlp->se.m[inst->u1.subid].s.sp = s;
+					continue;
+				case RBRA:
+					tlp->se.m[inst->u1.subid].e.ep = s;
+					continue;
+				case ANY:
+					if(r != '\n')
+						if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case ANYNL:
+					if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case BOL:
+					if(s == bol || *(s-1) == '\n')
+						continue;
+					break;
+				case EOL:
+					if(s == j->eol || r == 0 || r == '\n')
+						continue;
+					break;
+				case CCLASS:
+					ep = inst->u1.cp->end;
+					for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+						if(r >= rp[0] && r <= rp[1]){
+							if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+								return -1;
+							break;
+						}
+					break;
+				case NCCLASS:
+					ep = inst->u1.cp->end;
+					for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+						if(r >= rp[0] && r <= rp[1])
+							break;
+					if(rp == ep)
+						if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case OR:
+					/* evaluate right choice later */
+					if(_renewthread(tlp, inst->u1.right, &tlp->se) == tle)
+						return -1;
+					/* efficiency: advance and re-evaluate */
+					continue;
+				case END:	/* Match! */
+					match = 1;
+					tlp->se.m[0].e.ep = s;
+					if(mp != 0)
+						_renewmatch(mp, ms, &tlp->se);
+					break;
+				}
+				break;
+			}
+		}
+		if(s == j->eol)
+			break;
+		checkstart = j->starttype && nl->inst==0;
+		s += n;
+	}while(r);
+	return match;
+}
+
+static int
+regexec2(Reprog *progp,	/* program to run */
+	char *bol,	/* string to run machine on */
+	Resub *mp,	/* subexpression elements */
+	int ms,		/* number of elements at mp */
+	Reljunk *j
+)
+{
+	Relist relist0[BIGLISTSIZE], relist1[BIGLISTSIZE];
+
+	/* mark space */
+	j->relist[0] = relist0;
+	j->relist[1] = relist1;
+	j->reliste[0] = relist0 + nelem(relist0) - 2;
+	j->reliste[1] = relist1 + nelem(relist1) - 2;
+
+	return regexec1(progp, bol, mp, ms, j);
+}
+
+extern int
+regexec(Reprog *progp,	/* program to run */
+	char *bol,	/* string to run machine on */
+	Resub *mp,	/* subexpression elements */
+	int ms)		/* number of elements at mp */
+{
+	Reljunk j;
+	Relist relist0[LISTSIZE], relist1[LISTSIZE];
+	int rv;
+
+	/*
+ 	 *  use user-specified starting/ending location if specified
+	 */
+	j.starts = bol;
+	j.eol = 0;
+	if(mp && ms>0){
+		if(mp->s.sp)
+			j.starts = mp->s.sp;
+		if(mp->e.ep)
+			j.eol = mp->e.ep;
+	}
+	j.starttype = 0;
+	j.startchar = 0;
+	if(progp->startinst->type == RUNE && progp->startinst->u1.r < (Rune)Runeself) {
+		j.starttype = RUNE;
+		j.startchar = progp->startinst->u1.r;
+	}
+	if(progp->startinst->type == BOL)
+		j.starttype = BOL;
+
+	/* mark space */
+	j.relist[0] = relist0;
+	j.relist[1] = relist1;
+	j.reliste[0] = relist0 + nelem(relist0) - 2;
+	j.reliste[1] = relist1 + nelem(relist1) - 2;
+
+	rv = regexec1(progp, bol, mp, ms, &j);
+	if(rv >= 0)
+		return rv;
+	rv = regexec2(progp, bol, mp, ms, &j);
+	if(rv >= 0)
+		return rv;
+	return -1;
+}
blob - /dev/null
blob + f26035625b810c723f12371267d3fc7e9b10afe2 (mode 644)
--- /dev/null
+++ src/libregexp/regexp9.3
@@ -0,0 +1,227 @@
+.TH REGEXP9 3
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.de LR
+.if t .BR \\$1 \\$2
+.if n .RB ` \\$1 '\\$2
+..
+.de L
+.nh
+.if t .B \\$1
+.if n .RB ` \\$1 '
+..
+.SH NAME
+regcomp, regcomplit, regcompnl, regexec, regsub, regerror \- Plan 9 regular expression library
+.SH SYNOPSIS
+.B #include <regexp9.h>
+.PP
+.ta \w'\fLRegprog 'u
+.B
+Reprog	*regcomp(char *exp)
+.PP
+.B
+Reprog	*regcomplit(char *exp)
+.PP
+.B
+Reprog	*regcompnl(char *exp)
+.PP
+.nf
+.B
+int  regexec(Reprog *prog, char *string, Resub *match, int msize)
+.PP
+.nf
+.B
+void regsub(char *source, char *dest, int dlen, Resub *match, int msize)
+.PP
+.nf
+.B
+int  rregexec(Reprog *prog, Rune *string, Resub *match, int msize)
+.PP
+.nf
+.B
+void rregsub(Rune *source, Rune *dest, int dlen, Resub *match, int msize)
+.PP
+.B
+void regerror(char *msg)
+.SH DESCRIPTION
+.I Regcomp
+compiles a
+regular expression and returns
+a pointer to the generated description.
+The space is allocated by
+.IR malloc (3)
+and may be released by
+.IR free .
+Regular expressions are exactly as in
+.IR regexp9 (7).
+.PP
+.I Regcomplit
+is like
+.I regcomp
+except that all characters are treated literally.
+.I Regcompnl
+is like
+.I regcomp
+except that the
+.B .
+metacharacter matches all characters, including newlines.
+.PP
+.I Regexec
+matches a null-terminated
+.I string
+against the compiled regular expression in
+.IR prog .
+If it matches,
+.I regexec
+returns
+.B 1
+and fills in the array
+.I match
+with character pointers to the substrings of
+.I string
+that correspond to the
+parenthesized subexpressions of 
+.IR exp :
+.BI match[ i ].sp
+points to the beginning and
+.BI match[ i ].ep
+points just beyond
+the end of the
+.IR i th
+substring.
+(Subexpression
+.I i
+begins at the
+.IR i th
+left parenthesis, counting from 1.)
+Pointers in
+.B match[0]
+pick out the substring that corresponds to
+the whole regular expression.
+Unused elements of
+.I match
+are filled with zeros.
+Matches involving
+.LR * ,
+.LR + ,
+and 
+.L ?
+are extended as far as possible.
+The number of array elements in 
+.I match
+is given by
+.IR msize .
+The structure of elements of
+.I match 
+is:
+.IP
+.EX
+typedef struct {
+	union {
+	   char *sp;
+	   Rune *rsp;
+	} s;
+	union {
+	   char *ep;
+	   Rune *rep;
+	} e;
+} Resub;
+.EE
+.LP
+If
+.B match[0].s.sp
+is nonzero on entry,
+.I regexec
+starts matching at that point within
+.IR string .
+If
+.B match[0].e.ep
+is nonzero on entry,
+the last character matched is the one
+preceding that point.
+.PP
+.I Regsub
+places in
+.I dest
+a substitution instance of
+.I source
+in the context of the last
+.I regexec
+performed using
+.IR match .
+Each instance of
+.BI \e n\f1,
+where
+.I n
+is a digit, is replaced by the
+string delimited by
+.BI match[ n ].s.sp
+and
+.BI match[ n ].e.ep\f1.
+Each instance of 
+.L &
+is replaced by the string delimited by
+.B match[0].s.sp
+and
+.BR match[0].e.ep .
+The substitution will always be null terminated and
+trimmed to fit into dlen bytes.
+.PP
+.IR Regerror ,
+called whenever an error is detected in
+.IR regcomp ,
+writes the string
+.I msg
+on the standard error file and exits.
+.I Regerror
+can be replaced to perform
+special error processing.
+If the user supplied
+.I regerror
+returns rather than exits,
+.I regcomp
+will return 0. 
+.PP
+.I Rregexec
+and
+.I rregsub
+are variants of 
+.I regexec
+and
+.I regsub
+that use strings of
+.B Runes
+instead of strings of
+.BR chars .
+With these routines, the 
+.I rsp
+and
+.I rep
+fields of the
+.I match
+array elements should be used.
+.SH "SEE ALSO"
+.IR grep (1),
+.IR regexp9 (7)
+.SH DIAGNOSTICS
+.I Regcomp
+returns 
+.B 0
+for an illegal expression
+or other failure.
+.I Regexec
+returns 0
+if
+.I string
+is not matched.
+.SH HISTORY
+This particular regular expression was first written by Rob Pike for Plan 9.
+It has also appeared as part of the Inferno operating system.
+.SH BUGS
+There is no way to specify or match a NUL character; NULs terminate patterns and strings.
blob - /dev/null
blob + 14a90d0f9360c11a6227473cc89264c5d96451d7 (mode 644)
--- /dev/null
+++ src/libregexp/regexp9.7
@@ -0,0 +1,150 @@
+.TH REGEXP9 7
+.de EX
+.nf
+.ft B
+..
+.de EE
+.fi
+.ft R
+..
+.de LR
+.if t .BR \\$1 \\$2
+.if n .RB ` \\$1 '\\$2
+..
+.de L
+.nh
+.if t .B \\$1
+.if n .RB ` \\$1 '
+..
+.SH NAME
+regexp9 \- Plan 9 regular expression notation
+.SH DESCRIPTION
+This manual page describes the regular expression
+syntax used by the Plan 9 regular expression library
+.IR regexp9 (3).
+It is the form used by
+.IR egrep (1)
+before
+.I egrep
+got complicated.
+.PP
+A 
+.I "regular expression"
+specifies
+a set of strings of characters.
+A member of this set of strings is said to be
+.I matched
+by the regular expression.  In many applications
+a delimiter character, commonly
+.LR / ,
+bounds a regular expression.
+In the following specification for regular expressions
+the word `character' means any character (rune) but newline.
+.PP
+The syntax for a regular expression
+.B e0
+is
+.IP
+.EX
+e3:  literal | charclass | '.' | '^' | '$' | '(' e0 ')'
+
+e2:  e3
+  |  e2 REP
+
+REP: '*' | '+' | '?'
+
+e1:  e2
+  |  e1 e2
+
+e0:  e1
+  |  e0 '|' e1
+.EE
+.PP
+A
+.B literal
+is any non-metacharacter, or a metacharacter
+(one of
+.BR .*+?[]()|\e^$ ),
+or the delimiter
+preceded by 
+.LR \e .
+.PP
+A
+.B charclass
+is a nonempty string
+.I s
+bracketed
+.BI [ \|s\| ]
+(or
+.BI [^ s\| ]\fR);
+it matches any character in (or not in)
+.IR s .
+A negated character class never
+matches newline.
+A substring 
+.IB a - b\f1,
+with
+.I a
+and
+.I b
+in ascending
+order, stands for the inclusive
+range of
+characters between
+.I a
+and
+.IR b .
+In 
+.IR s ,
+the metacharacters
+.LR - ,
+.LR ] ,
+an initial
+.LR ^ ,
+and the regular expression delimiter
+must be preceded by a
+.LR \e ;
+other metacharacters 
+have no special meaning and
+may appear unescaped.
+.PP
+A 
+.L .
+matches any character.
+.PP
+A
+.L ^
+matches the beginning of a line;
+.L $
+matches the end of the line.
+.PP
+The 
+.B REP
+operators match zero or more
+.RB ( * ),
+one or more
+.RB ( + ),
+zero or one
+.RB ( ? ),
+instances respectively of the preceding regular expression 
+.BR e2 .
+.PP
+A concatenated regular expression,
+.BR "e1\|e2" ,
+matches a match to 
+.B e1
+followed by a match to
+.BR e2 .
+.PP
+An alternative regular expression,
+.BR "e0\||\|e1" ,
+matches either a match to
+.B e0
+or a match to
+.BR e1 .
+.PP
+A match to any part of a regular expression
+extends as far as possible without preventing
+a match to the remainder of the regular expression.
+.SH "SEE ALSO"
+.IR regexp9 (3)
blob - /dev/null
blob + e25658a35cecf85b926ed607106c792ba6e66613 (mode 644)
--- /dev/null
+++ src/libregexp/regexp9.h
@@ -0,0 +1,71 @@
+#ifndef _REGEXP9H_
+
+#define _REGEXP9H_ 1
+#include <utf.h>
+
+typedef struct Resub		Resub;
+typedef struct Reclass		Reclass;
+typedef struct Reinst		Reinst;
+typedef struct Reprog		Reprog;
+
+/*
+ *	Sub expression matches
+ */
+struct Resub{
+	union
+	{
+		char *sp;
+		Rune *rsp;
+	}s;
+	union
+	{
+		char *ep;
+		Rune *rep;
+	}e;
+};
+
+/*
+ *	character class, each pair of rune's defines a range
+ */
+struct Reclass{
+	Rune	*end;
+	Rune	spans[64];
+};
+
+/*
+ *	Machine instructions
+ */
+struct Reinst{
+	int	type;
+	union	{
+		Reclass	*cp;		/* class pointer */
+		Rune	r;		/* character */
+		int	subid;		/* sub-expression id for RBRA and LBRA */
+		Reinst	*right;		/* right child of OR */
+	}u1;
+	union {	/* regexp relies on these two being in the same union */
+		Reinst *left;		/* left child of OR */
+		Reinst *next;		/* next instruction for CAT & LBRA */
+	}u2;
+};
+
+/*
+ *	Reprogram definition
+ */
+struct Reprog{
+	Reinst	*startinst;	/* start pc */
+	Reclass	class[16];	/* .data */
+	Reinst	firstinst[5];	/* .text */
+};
+
+extern Reprog	*regcomp(char*);
+extern Reprog	*regcomplit(char*);
+extern Reprog	*regcompnl(char*);
+extern void	regerror(char*);
+extern int	regexec(Reprog*, char*, Resub*, int);
+extern void	regsub(char*, char*, int, Resub*, int);
+
+extern int	rregexec(Reprog*, Rune*, Resub*, int);
+extern void	rregsub(Rune*, Rune*, Resub*, int);
+
+#endif
blob - /dev/null
blob + 6de2c9572030569467d0ac9d7e939ebaf3866427 (mode 644)
--- /dev/null
+++ src/libregexp/regsub.c
@@ -0,0 +1,62 @@
+#include "lib9.h"
+#include "regexp9.h"
+
+/* substitute into one string using the matches from the last regexec() */
+extern	void
+regsub(char *sp,	/* source string */
+	char *dp,	/* destination string */
+	int dlen,
+	Resub *mp,	/* subexpression elements */
+	int ms)		/* number of elements pointed to by mp */
+{
+	char *ssp, *ep;
+	int i;
+
+	ep = dp+dlen-1;
+	while(*sp != '\0'){
+		if(*sp == '\\'){
+			switch(*++sp){
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				i = *sp-'0';
+				if(mp[i].s.sp != 0 && mp!=0 && ms>i)
+					for(ssp = mp[i].s.sp;
+					     ssp < mp[i].e.ep;
+					     ssp++)
+						if(dp < ep)
+							*dp++ = *ssp;
+				break;
+			case '\\':
+				if(dp < ep)
+					*dp++ = '\\';
+				break;
+			case '\0':
+				sp--;
+				break;
+			default:
+				if(dp < ep)
+					*dp++ = *sp;
+				break;
+			}
+		}else if(*sp == '&'){				
+			if(mp[0].s.sp != 0 && mp!=0 && ms>0)
+			if(mp[0].s.sp != 0)
+				for(ssp = mp[0].s.sp;
+				     ssp < mp[0].e.ep; ssp++)
+					if(dp < ep)
+						*dp++ = *ssp;
+		}else
+			if(dp < ep)
+				*dp++ = *sp;
+		sp++;
+	}
+	*dp = '\0';
+}
blob - /dev/null
blob + f4c92d66b803ee4ca301dfab3fa30035c64a6d78 (mode 644)
--- /dev/null
+++ src/libregexp/rpm.spec
@@ -0,0 +1,34 @@
+Summary: Simple regular expression library from Plan 9
+Name: libregexp9
+Version: 2.0
+Release: 1
+Group: Development/C
+Copyright: Public Domain
+Packager: Russ Cox <rsc@post.harvard.edu>
+Source: http://pdos.lcs.mit.edu/~rsc/software/libregexp9-2.0.tgz
+URL: http://pdos.lcs.mit.edu/~rsc/software/#libregexp9
+Requires: libfmt libutf
+
+%description
+Libregexp9 is a port of Plan 9's regexp library.
+It is small and simple and provides the traditional
+extended regular expressions (as opposed to the
+current extended regular expressions, which add {}
+and various \x character classes, among other 
+complications).
+
+http://plan9.bell-labs.com/magic/man2html/2/regexp
+%prep
+%setup
+
+%build
+make
+
+%install
+make install
+
+%files
+/usr/local/include/regexp9.h
+/usr/local/lib/libregexp9.a
+/usr/local/man/man3/regexp9.3
+/usr/local/man/man7/regexp9.7
blob - /dev/null
blob + f4cb006813a29dc1bbee56e0404d0df06e173bd3 (mode 644)
--- /dev/null
+++ src/libregexp/rregaux.c
@@ -0,0 +1,26 @@
+#include "lib9.h"
+#include "regexp9.h"
+#include "regcomp.h"
+
+extern Relist*
+_rrenewemptythread(Relist *lp,	/* _relist to add to */
+	Reinst *ip,		/* instruction to add */
+	Rune *rsp)		/* pointers to subexpressions */
+{
+	Relist *p;
+
+	for(p=lp; p->inst; p++){
+		if(p->inst == ip){
+			if(rsp < p->se.m[0].s.rsp) {
+				memset((void *)&p->se, 0, sizeof(p->se));
+				p->se.m[0].s.rsp = rsp;
+			}
+			return 0;
+		}
+	}
+	p->inst = ip;
+	memset((void *)&p->se, 0, sizeof(p->se));
+	p->se.m[0].s.rsp = rsp;
+	(++p)->inst = 0;
+	return p;
+}
blob - /dev/null
blob + e96c97212fefa6769a40db7e5aa4a7d6c6bbcb99 (mode 644)
--- /dev/null
+++ src/libregexp/rregexec.c
@@ -0,0 +1,213 @@
+#include "lib9.h"
+#include "regexp9.h"
+#include "regcomp.h"
+
+/*
+ *  return	0 if no match
+ *		>0 if a match
+ *		<0 if we ran out of _relist space
+ */
+static int
+rregexec1(Reprog *progp,	/* program to run */
+	Rune *bol,		/* string to run machine on */
+	Resub *mp,		/* subexpression elements */
+	int ms,			/* number of elements at mp */
+	Reljunk *j)
+{
+	int flag=0;
+	Reinst *inst;
+	Relist *tlp;
+	Rune *s;
+	int i, checkstart;
+	Rune r, *rp, *ep;
+	Relist* tl;		/* This list, next list */
+	Relist* nl;
+	Relist* tle;		/* ends of this and next list */
+	Relist* nle;
+	int match;
+
+	match = 0;
+	checkstart = j->startchar;
+	if(mp)
+		for(i=0; i<ms; i++) {
+			mp[i].s.rsp = 0;
+			mp[i].e.rep = 0;
+		}
+	j->relist[0][0].inst = 0;
+	j->relist[1][0].inst = 0;
+
+	/* Execute machine once for each character, including terminal NUL */
+	s = j->rstarts;
+	do{
+
+		/* fast check for first char */
+		if(checkstart) {
+			switch(j->starttype) {
+			case RUNE:
+				while(*s != j->startchar) {
+					if(*s == 0)
+						return match;
+					s++;
+				}
+				break;
+			case BOL:
+				if(s == bol)
+					break;
+				while(*s != '\n') {
+					if(*s == 0)
+						return match;
+					s++;
+				}
+				break;
+			}
+		}
+
+		r = *s;
+
+		/* switch run lists */
+		tl = j->relist[flag];
+		tle = j->reliste[flag];
+		nl = j->relist[flag^=1];
+		nle = j->reliste[flag];
+		nl->inst = 0;
+
+		/* Add first instruction to current list */
+		_rrenewemptythread(tl, progp->startinst, s);
+
+		/* Execute machine until current list is empty */
+		for(tlp=tl; tlp->inst; tlp++){
+			for(inst=tlp->inst; ; inst = inst->u2.next){
+				switch(inst->type){
+				case RUNE:	/* regular character */
+					if(inst->u1.r == r)
+						if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case LBRA:
+					tlp->se.m[inst->u1.subid].s.rsp = s;
+					continue;
+				case RBRA:
+					tlp->se.m[inst->u1.subid].e.rep = s;
+					continue;
+				case ANY:
+					if(r != '\n')
+						if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case ANYNL:
+					if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case BOL:
+					if(s == bol || *(s-1) == '\n')
+						continue;
+					break;
+				case EOL:
+					if(s == j->reol || r == 0 || r == '\n')
+						continue;
+					break;
+				case CCLASS:
+					ep = inst->u1.cp->end;
+					for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+						if(r >= rp[0] && r <= rp[1]){
+							if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+								return -1;
+							break;
+						}
+					break;
+				case NCCLASS:
+					ep = inst->u1.cp->end;
+					for(rp = inst->u1.cp->spans; rp < ep; rp += 2)
+						if(r >= rp[0] && r <= rp[1])
+							break;
+					if(rp == ep)
+						if(_renewthread(nl, inst->u2.next, &tlp->se)==nle)
+							return -1;
+					break;
+				case OR:
+					/* evaluate right choice later */
+					if(_renewthread(tlp, inst->u1.right, &tlp->se) == tle)
+						return -1;
+					/* efficiency: advance and re-evaluate */
+					continue;
+				case END:	/* Match! */
+					match = 1;
+					tlp->se.m[0].e.rep = s;
+					if(mp != 0)
+						_renewmatch(mp, ms, &tlp->se);
+					break;
+				}
+				break;
+			}
+		}
+		if(s == j->reol)
+			break;
+		checkstart = j->startchar && nl->inst==0;
+		s++;
+	}while(r);
+	return match;
+}
+
+static int
+rregexec2(Reprog *progp,	/* program to run */
+	Rune *bol,	/* string to run machine on */
+	Resub *mp,	/* subexpression elements */
+	int ms,		/* number of elements at mp */
+	Reljunk *j
+)
+{
+	Relist relist0[5*LISTSIZE], relist1[5*LISTSIZE];
+
+	/* mark space */
+	j->relist[0] = relist0;
+	j->relist[1] = relist1;
+	j->reliste[0] = relist0 + nelem(relist0) - 2;
+	j->reliste[1] = relist1 + nelem(relist1) - 2;
+
+	return rregexec1(progp, bol, mp, ms, j);
+}
+
+extern int
+rregexec(Reprog *progp,	/* program to run */
+	Rune *bol,	/* string to run machine on */
+	Resub *mp,	/* subexpression elements */
+	int ms)		/* number of elements at mp */
+{
+	Reljunk j;
+	Relist relist0[LISTSIZE], relist1[LISTSIZE];
+	int rv;
+
+	/*
+ 	 *  use user-specified starting/ending location if specified
+	 */
+	j.rstarts = bol;
+	j.reol = 0;
+	if(mp && ms>0){
+		if(mp->s.sp)
+			j.rstarts = mp->s.rsp;
+		if(mp->e.ep)
+			j.reol = mp->e.rep;
+	}
+	j.starttype = 0;
+	j.startchar = 0;
+	if(progp->startinst->type == RUNE && progp->startinst->u1.r < (Rune)Runeself) {
+		j.starttype = RUNE;
+		j.startchar = progp->startinst->u1.r;
+	}
+	if(progp->startinst->type == BOL)
+		j.starttype = BOL;
+
+	/* mark space */
+	j.relist[0] = relist0;
+	j.relist[1] = relist1;
+	j.reliste[0] = relist0 + nelem(relist0) - 2;
+	j.reliste[1] = relist1 + nelem(relist1) - 2;
+
+	rv = rregexec1(progp, bol, mp, ms, &j);
+	if(rv >= 0)
+		return rv;
+	rv = rregexec2(progp, bol, mp, ms, &j);
+	if(rv >= 0)
+		return rv;
+	return -1;
+}
blob - /dev/null
blob + 15f3c1741321c4f800758b68c1b79ab99f84e8c0 (mode 644)
--- /dev/null
+++ src/libregexp/rregsub.c
@@ -0,0 +1,55 @@
+#include "lib9.h"
+#include "regexp9.h"
+
+/* substitute into one string using the matches from the last regexec() */
+extern	void
+rregsub(Rune *sp,	/* source string */
+	Rune *dp,	/* destination string */
+	Resub *mp,	/* subexpression elements */
+	int ms)		/* number of elements pointed to by mp */
+{
+	Rune *ssp;
+	int i;
+
+	while(*sp != '\0'){
+		if(*sp == '\\'){
+			switch(*++sp){
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+			case '8':
+			case '9':
+				i = *sp-'0';
+				if(mp[i].s.rsp != 0 && mp!=0 && ms>i)
+					for(ssp = mp[i].s.rsp;
+					     ssp < mp[i].e.rep;
+					     ssp++)
+						*dp++ = *ssp;
+				break;
+			case '\\':
+				*dp++ = '\\';
+				break;
+			case '\0':
+				sp--;
+				break;
+			default:
+				*dp++ = *sp;
+				break;
+			}
+		}else if(*sp == '&'){				
+			if(mp[0].s.rsp != 0 && mp!=0 && ms>0)
+			if(mp[0].s.rsp != 0)
+				for(ssp = mp[0].s.rsp;
+				     ssp < mp[0].e.rep; ssp++)
+					*dp++ = *ssp;
+		}else
+			*dp++ = *sp;
+		sp++;
+	}
+	*dp = '\0';
+}
blob - /dev/null
blob + 83533ee62e389ec7df052088f0b6ee3e7f9d161d (mode 644)
--- /dev/null
+++ src/libregexp/test.c
@@ -0,0 +1,46 @@
+#include "lib9.h"
+#include <regexp9.h>
+
+struct x
+{
+	char *re;
+	char *s;
+	Reprog *p;
+};
+
+struct x t[] = {
+	{ "^[^!@]+$", "/bin/upas/aliasmail '&'", 0 },
+	{ "^local!(.*)$", "/mail/box/\\1/mbox", 0 },
+	{ "^plan9!(.*)$", "\\1", 0 },
+	{ "^helix!(.*)$", "\\1", 0 },
+	{ "^([^!]+)@([^!@]+)$", "\\2!\\1", 0 },
+	{ "^(uk\\.[^!]*)(!.*)$", "/bin/upas/uk2uk '\\1' '\\2'", 0 },
+	{ "^[^!]*\\.[^!]*!.*$", "inet!&", 0 },
+	{ "^\xE2\x98\xBA$", "smiley", 0 },
+	{ "^(coma|research|pipe|pyxis|inet|hunny|gauss)!(.*)$", "/mail/lib/qmail '\\s' 'net!\\1' '\\2'", 0 },
+	{ "^.*$", "/mail/lib/qmail '\\s' 'net!research' '&'", 0 },
+	{ 0, 0, 0 },
+};
+
+main(int ac, char **av)
+{
+	Resub rs[10];
+	char dst[128];
+	int n;
+	struct x *tp;
+
+	for(tp = t; tp->re; tp++)
+		tp->p = regcomp(tp->re);
+
+
+	for(tp = t; tp->re; tp++){
+		print("%s VIA %s", av[1], tp->re);
+		memset(rs, 0, sizeof rs);
+		if(regexec(tp->p, av[1], rs, 10)){
+			regsub(tp->s, dst, sizeof dst, rs, 10);
+			print(" sub %s -> %s", tp->s, dst);
+		}
+		print("\n");
+	}
+	exit(0);
+}
blob - /dev/null
blob + 150953e47d31de7b3948450597bdc3c19f07dd73 (mode 644)
--- /dev/null
+++ src/libregexp/test2.c
@@ -0,0 +1,20 @@
+#include "lib9.h"
+#include <regexp9.h>
+
+
+main(int ac, char **av)
+{
+	Resub rs[10];
+	Reprog *p;
+	char *s;
+	int i;
+
+	p = regcomp("[^a-z]");
+	s = "\n";
+	if(regexec(p, s, rs, 10))
+		print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep);
+	s = "0";
+	if(regexec(p, s, rs, 10))
+		print("%s %lux %lux %lux\n", s, s, rs[0].sp, rs[0].ep);
+	exit(0);
+}
blob - /dev/null
blob + ad76cd52bacef7d8ffdae7cbe96f500f6b6cb1c9 (mode 644)
--- /dev/null
+++ src/libutf/LICENSE
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
blob - /dev/null
blob + 14b8d4e7925867693d110c320d9c5a67dcd16758 (mode 644)
--- /dev/null
+++ src/libutf/Make.Darwin-PowerMacintosh
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I${PREFIX}/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libutf/Make.FreeBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + edbdc111a2a0c008975e297c7ca60e46199397a9 (mode 644)
--- /dev/null
+++ src/libutf/Make.HP-UX-9000
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS=-O -c -Ae -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 74b0252c6eae6331b48ede7fcfa1ed760609d1a3 (mode 644)
--- /dev/null
+++ src/libutf/Make.Linux-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 087ed3abab5ea1bb549989f2c6abbae4ce024922 (mode 644)
--- /dev/null
+++ src/libutf/Make.NetBSD-386
@@ -0,0 +1,7 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c -I. -I$(PREFIX)/include
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O	# default, can be overriden by Make.$(SYSNAME)
+NAN=nan64.$O
blob - /dev/null
blob + 3d45279bba28dbe69c00f89568c444ab83a4ac72 (mode 644)
--- /dev/null
+++ src/libutf/Make.OSF1-alpha
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I.
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + c5fe67b82d86c731a56c101e522e804390e5bd5a (mode 644)
--- /dev/null
+++ src/libutf/Make.SunOS-sun4u
@@ -0,0 +1,2 @@
+include Make.SunOS-sun4u-$(CC)
+NAN=nan64.$O
blob - /dev/null
blob + 829301de8649d40632eb809ae512598af11d48c5 (mode 644)
--- /dev/null
+++ src/libutf/Make.SunOS-sun4u-cc
@@ -0,0 +1,6 @@
+CC=cc
+CFLAGS+=-g -c -I. -O
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 5c41594812a4a27eb848d384cbc356d206c0a44b (mode 644)
--- /dev/null
+++ src/libutf/Make.SunOS-sun4u-gcc
@@ -0,0 +1,6 @@
+CC=gcc
+CFLAGS+=-Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -O2 -g -c
+O=o
+AR=ar
+ARFLAGS=rvc
+NAN=nan64.$O
blob - /dev/null
blob + 419a8a65d9afbe81326eecf9d2cc5c8201d373e3 (mode 644)
--- /dev/null
+++ src/libutf/Makefile
@@ -0,0 +1,112 @@
+
+# this works in gnu make
+SYSNAME:=${shell uname}
+OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
+
+# this works in bsd make
+SYSNAME!=uname
+OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
+
+# the gnu rules will mess up bsd but not vice versa,
+# hence the gnu rules come first.
+
+include Make.$(SYSNAME)-$(OBJTYPE)
+
+PREFIX=/usr/local
+
+NUKEFILES=
+
+TGZFILES=
+
+LIB=libutf.a
+VERSION=2.0
+PORTPLACE=devel/libutf
+NAME=libutf
+
+OFILES=\
+	rune.$O\
+	runestrcat.$O\
+	runestrchr.$O\
+	runestrcmp.$O\
+	runestrcpy.$O\
+	runestrdup.$O\
+	runestrlen.$O\
+	runestrecpy.$O\
+	runestrncat.$O\
+	runestrncmp.$O\
+	runestrncpy.$O\
+	runestrrchr.$O\
+	runestrstr.$O\
+	runetype.$O\
+	utfecpy.$O\
+	utflen.$O\
+	utfnlen.$O\
+	utfrrune.$O\
+	utfrune.$O\
+	utfutf.$O\
+
+HFILES=\
+	utf.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	install -c -m 0644 isalpharune.3 $(PREFIX)/man/man3/isalpharune.3
+	install -c -m 0644 utf.7 $(PREFIX)/man/man7/utf.7
+	install -c -m 0644 rune.3 $(PREFIX)/man/man3/rune.3
+	install -c -m 0644 runestrcat.3 $(PREFIX)/man/man3/runestrcat.3
+	install -c -m 0644 utf.h $(PREFIX)/include/utf.h
+	install -c -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
+$(LIB): $(OFILES)
+	$(AR) $(ARFLAGS) $(LIB) $(OFILES)
+
+NUKEFILES+=$(LIB)
+.c.$O:
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+%.$O: %.c
+	$(CC) $(CFLAGS) -I$(PREFIX)/include $*.c
+
+
+$(OFILES): $(HFILES)
+
+tgz:
+	rm -rf $(NAME)-$(VERSION)
+	mkdir $(NAME)-$(VERSION)
+	cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION)
+	tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz
+	rm -rf $(NAME)-$(VERSION)
+
+clean:
+	rm -f $(OFILES) $(LIB)
+
+nuke:
+	rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES)
+
+rpm:
+	make tgz
+	cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES
+	rpm -ba rpm.spec
+	cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm .
+	cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm .
+	scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software
+
+PORTDIR=/usr/ports/$(PORTPLACE)
+
+ports:
+	make tgz
+	rm -rf $(PORTDIR)
+	mkdir $(PORTDIR)
+	cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles
+	cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}')
+	(cd $(PORTDIR); make makesum)
+	(cd $(PORTDIR); make)
+	(cd $(PORTDIR); /usr/local/bin/portlint)
+	rm -rf $(PORTDIR)/work
+	shar `find $(PORTDIR)` > ports.shar
+	(cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz
+	scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software
+
+.phony: all clean nuke install tgz rpm ports
blob - /dev/null
blob + ad852a1f5f623e197559cea654f752b868d9a127 (mode 644)
--- /dev/null
+++ src/libutf/Makefile.BOT
@@ -0,0 +1,47 @@
+.c.$O:
+	$(CC) $(CFLAGS) -I/usr/X11R6/include -I../sam -I$(PREFIX)/include $*.c
+
+%.$O: %.c
+	$(CC) $(CFLAGS) -I/usr/X11R6/include -I../sam -I$(PREFIX)/include $*.c
+
+
+$(OFILES): $(HFILES)
+
+tgz:
+	rm -rf $(NAME)-$(VERSION)
+	mkdir $(NAME)-$(VERSION)
+	cp Makefile Make.* README LICENSE NOTICE *.[ch137] rpm.spec bundle.ports $(TGZFILES) $(NAME)-$(VERSION)
+	tar cf - $(NAME)-$(VERSION) | gzip >$(NAME)-$(VERSION).tgz
+	rm -rf $(NAME)-$(VERSION)
+
+clean:
+	rm -f $(OFILES) $(LIB)
+
+nuke:
+	rm -f $(OFILES) *.tgz *.rpm $(NUKEFILES)
+
+rpm:
+	make tgz
+	cp $(NAME)-$(VERSION).tgz /usr/src/RPM/SOURCES
+	rpm -ba rpm.spec
+	cp /usr/src/RPM/SRPMS/$(NAME)-$(VERSION)-1.src.rpm .
+	cp /usr/src/RPM/RPMS/i586/$(NAME)-$(VERSION)-1.i586.rpm .
+	scp *.rpm rsc@amsterdam.lcs.mit.edu:public_html/software
+
+PORTDIR=/usr/ports/$(PORTPLACE)
+
+ports:
+	make tgz
+	rm -rf $(PORTDIR)
+	mkdir $(PORTDIR)
+	cp $(NAME)-$(VERSION).tgz /usr/ports/distfiles
+	cat bundle.ports | (cd $(PORTDIR) && awk '$$1=="---" && $$3=="---" { ofile=$$2; next} {if(ofile) print >ofile}')
+	(cd $(PORTDIR); make makesum)
+	(cd $(PORTDIR); make)
+	(cd $(PORTDIR); /usr/local/bin/portlint)
+	rm -rf $(PORTDIR)/work
+	shar `find $(PORTDIR)` > ports.shar
+	(cd $(PORTDIR); tar cf - *) | gzip >$(NAME)-$(VERSION)-ports.tgz
+	scp *.tgz rsc@amsterdam.lcs.mit.edu:public_html/software
+
+.phony: all clean nuke install tgz rpm ports
blob - /dev/null
blob + a817fd3c602fad79918fe87b2601c35599bce965 (mode 644)
--- /dev/null
+++ src/libutf/Makefile.CMD
@@ -0,0 +1,5 @@
+
+$(TARG): $(OFILES)
+	$(CC) -o $(TARG) $(OFILES) -L$(PREFIX)/lib -lframe -ldraw -lthread -l9 -lregexp9 -lbio -lfmt -lutf -L/usr/X11R6/lib -lX11 -lm
+
+
blob - /dev/null
blob + 9ebf5606bf0dcb0f1d85b8531987061b7d5b00b3 (mode 644)
--- /dev/null
+++ src/libutf/Makefile.LIB
@@ -0,0 +1,4 @@
+$(LIB): $(OFILES)
+	$(AR) $(ARFLAGS) $(LIB) $(OFILES)
+
+NUKEFILES+=$(LIB)
blob - /dev/null
blob + 9c142d44a7be8d74bb3b2b6a32eff62b2a641fff (mode 644)
--- /dev/null
+++ src/libutf/Makefile.MID
@@ -0,0 +1,41 @@
+LIB=libutf.a
+VERSION=2.0
+PORTPLACE=devel/libutf
+NAME=libutf
+
+OFILES=\
+	rune.$O\
+	runestrcat.$O\
+	runestrchr.$O\
+	runestrcmp.$O\
+	runestrcpy.$O\
+	runestrdup.$O\
+	runestrlen.$O\
+	runestrecpy.$O\
+	runestrncat.$O\
+	runestrncmp.$O\
+	runestrncpy.$O\
+	runestrrchr.$O\
+	runestrstr.$O\
+	runetype.$O\
+	utfecpy.$O\
+	utflen.$O\
+	utfnlen.$O\
+	utfrrune.$O\
+	utfrune.$O\
+	utfutf.$O\
+
+HFILES=\
+	utf.h\
+
+all: $(LIB)
+
+install: $(LIB)
+	test -d $(PREFIX)/man/man3 || mkdir $(PREFIX)/man/man3
+	install -c -m 0644 isalpharune.3 $(PREFIX)/man/man3/isalpharune.3
+	install -c -m 0644 utf.7 $(PREFIX)/man/man7/utf.7
+	install -c -m 0644 rune.3 $(PREFIX)/man/man3/rune.3
+	install -c -m 0644 runestrcat.3 $(PREFIX)/man/man3/runestrcat.3
+	install -c -m 0644 utf.h $(PREFIX)/include/utf.h
+	install -c -m 0644 $(LIB) $(PREFIX)/lib/$(LIB)
+
blob - /dev/null
blob + f6abc8c1d978dea6e7f45e638b92fb2417741042 (mode 644)
--- /dev/null
+++ src/libutf/Makefile.TOP
@@ -0,0 +1,20 @@
+
+# this works in gnu make
+SYSNAME:=${shell uname}
+OBJTYPE:=${shell uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'}
+
+# this works in bsd make
+SYSNAME!=uname
+OBJTYPE!=uname -m | sed 's;i.86;386;; s;/.*;;; s; ;;g'
+
+# the gnu rules will mess up bsd but not vice versa,
+# hence the gnu rules come first.
+
+include Make.$(SYSNAME)-$(OBJTYPE)
+
+PREFIX=/usr/local
+
+NUKEFILES=
+
+TGZFILES=
+
blob - /dev/null
blob + ad76cd52bacef7d8ffdae7cbe96f500f6b6cb1c9 (mode 644)
--- /dev/null
+++ src/libutf/NOTICE
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
blob - /dev/null
blob + ad76cd52bacef7d8ffdae7cbe96f500f6b6cb1c9 (mode 644)
--- /dev/null
+++ src/libutf/README
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
blob - /dev/null
blob + d5ae00b62bac5da2ccadcfe6561a6dc5513f8b80 (mode 644)
--- /dev/null
+++ src/libutf/bundle.ports
@@ -0,0 +1,43 @@
+--- Makefile ---
+# New ports collection makefile for: libutf
+# Date Created:		11 Feb 2003
+# Whom:			rsc
+#
+# THIS LINE NEEDS REPLACING.  IT'S HERE TO GET BY PORTLINT
+# $FreeBSD: ports/devel/libfmt/Makefile,v 1.1 2003/02/12 00:51:22 rsc Exp $
+
+PORTNAME=	libutf
+PORTVERSION=	2.0
+CATEGORIES=	devel
+MASTER_SITES=	http://pdos.lcs.mit.edu/~rsc/software/
+EXTRACT_SUFX=	.tgz
+
+MAINTAINER=	rsc@post.harvard.edu
+
+MAN3=		rune.3 runestrcat.3 isalpharune.3
+MAN7=		utf.7
+
+USE_REINPLACE=yes
+
+.include <bsd.port.pre.mk>
+
+post-patch:
+	${REINPLACE_CMD} -e 's,$$(PREFIX),${PREFIX},g' ${WRKSRC}/Makefile
+
+.include <bsd.port.post.mk>
+--- pkg-comment ---
+UTF8 support library from Plan 9
+--- pkg-descr ---
+UTF8 support library from Plan 9.
+
+WWW: http://pdos.lcs.mit.edu/~rsc/software/#libutf
+http://plan9.bell-labs.com/magic/man2html/3/rune
+
+Russ Cox
+rsc@post.harvard.edu
+--- pkg-plist ---
+lib/libutf.a
+include/utf.h
+--- /dev/null ---
+This is just a way to make sure blank lines don't
+creep into pkg-plist.
blob - /dev/null
blob + f9f58cdeab383474bf922659265beb7134597940 (mode 644)
--- /dev/null
+++ src/libutf/isalpharune.3
@@ -0,0 +1,47 @@
+.TH ISALPHARUNE 3
+.SH NAME
+isalpharune, islowerrune, isspacerune, istitlerune, isupperrune, tolowerrune, totitlerune, toupperrune \- Unicode character classes and cases
+.SH SYNOPSIS
+.B #include <utf.h>
+.PP
+.B
+int isalpharune(Rune c)
+.PP
+.B
+int islowerrune(Rune c)
+.PP
+.B
+int isspacerune(Rune c)
+.PP
+.B
+int istitlerune(Rune c)
+.PP
+.B
+int isupperrune(Rune c)
+.PP
+.B
+Rune tolowerrune(Rune c)
+.PP
+.B
+Rune totitlerune(Rune c)
+.PP
+.B
+Rune toupperrune(Rune c)
+.SH DESCRIPTION
+These routines examine and operate on Unicode characters,
+in particular a subset of their properties as defined in the Unicode standard.
+Unicode defines some characters as alphabetic and specifies three cases:
+upper, lower, and title.
+Analogously to
+.IR ctype (3)
+for
+.SM ASCII\c
+,
+these routines
+test types and modify cases for Unicode characters.
+The names are self-explanatory.
+.PP
+The case-conversion routines return the character unchanged if it has no case.
+.SH "SEE ALSO
+.IR ctype (3) ,
+.IR "The Unicode Standard" .
blob - /dev/null
blob + e6128ae4daa3902aa0780f84cf8224454bc838c9 (mode 644)
--- /dev/null
+++ src/libutf/lib9.h
@@ -0,0 +1,17 @@
+#include <string.h>
+#include "utf.h"
+
+#define nil ((void*)0)
+
+#define uchar _fmtuchar
+#define ushort _fmtushort
+#define uint _fmtuint
+#define ulong _fmtulong
+#define vlong _fmtvlong
+#define uvlong _fmtuvlong
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
blob - /dev/null
blob + 9893a06dc9aac52241fcc22360461472f56b4cbd (mode 644)
--- /dev/null
+++ src/libutf/mkfile
@@ -0,0 +1,9 @@
+all:V: Makefile Make.FreeBSD-386 Make.Linux-386 Make.NetBSD-386 Make.HP-UX-9000 Make.OSF1-alpha \
+	Make.SunOS-sun4u Make.SunOS-sun4u-cc Make.SunOS-sun4u-gcc \
+	Make.Darwin-PowerMacintosh
+
+Makefile:D: ../libutf/Makefile.TOP Makefile.MID ../libutf/Makefile.LIB ../libutf/Makefile.BOT
+	cat $prereq >$target
+
+Make.%: ../libutf/Make.%
+	cp $prereq $target
blob - /dev/null
blob + 7412783345249a21979229b480036f9f7c5d8531 (mode 644)
--- /dev/null
+++ src/libutf/rpm.spec
@@ -0,0 +1,28 @@
+Summary: Port of Plan 9's UTF8 support functions
+Name: libutf
+Version: 2.0
+Release: 1
+Group: Development/C
+Copyright: Public Domain
+Packager: Russ Cox <rsc@post.harvard.edu>
+Source: http://pdos.lcs.mit.edu/~rsc/software/libutf-2.0.tgz
+URL: http://pdos.lcs.mit.edu/~rsc/software/#libutf
+
+%description
+Libutf is a port of Plan 9's UTF8 support functions.
+%prep
+%setup
+
+%build
+make
+
+%install
+make install
+
+%files
+/usr/local/include/utf.h
+/usr/local/lib/libutf.a
+/usr/local/man/man3/runestrcat.3
+/usr/local/man/man3/isalpharune.3
+/usr/local/man/man3/rune.3
+/usr/local/man/man7/utf.7
blob - /dev/null
blob + 7ce978aed6129fcddddd3f934d4cab541ba103f5 (mode 644)
--- /dev/null
+++ src/libutf/rune.3
@@ -0,0 +1,187 @@
+.TH RUNE 3
+.SH NAME
+runetochar, chartorune, runelen, runenlen, fullrune, utfecpy, utflen, utfnlen, utfrune, utfrrune, utfutf \- rune/UTF conversion
+.SH SYNOPSIS
+.ta \w'\fLchar*xx'u
+.B #include <utf.h>
+.PP
+.B
+int	runetochar(char *s, Rune *r)
+.PP
+.B
+int	chartorune(Rune *r, char *s)
+.PP
+.B
+int	runelen(long r)
+.PP
+.B
+int	runenlen(Rune *r, int n)
+.PP
+.B
+int	fullrune(char *s, int n)
+.PP
+.B
+char*	utfecpy(char *s1, char *es1, char *s2)
+.PP
+.B
+int	utflen(char *s)
+.PP
+.B
+int	utfnlen(char *s, long n)
+.PP
+.B
+char*	utfrune(char *s, long c)
+.PP
+.B
+char*	utfrrune(char *s, long c)
+.PP
+.B
+char*	utfutf(char *s1, char *s2)
+.SH DESCRIPTION
+These routines convert to and from a
+.SM UTF
+byte stream and runes.
+.PP
+.I Runetochar
+copies one rune at
+.I r
+to at most
+.B UTFmax
+bytes starting at
+.I s
+and returns the number of bytes copied.
+.BR UTFmax ,
+defined as
+.B 3
+in
+.BR <libc.h> ,
+is the maximum number of bytes required to represent a rune.
+.PP
+.I Chartorune
+copies at most
+.B UTFmax
+bytes starting at
+.I s
+to one rune at
+.I r
+and returns the number of bytes copied.
+If the input is not exactly in
+.SM UTF
+format,
+.I chartorune
+will convert to 0x80 and return 1.
+.PP
+.I Runelen
+returns the number of bytes
+required to convert
+.I r
+into
+.SM UTF.
+.PP
+.I Runenlen
+returns the number of bytes
+required to convert the
+.I n
+runes pointed to by
+.I r
+into
+.SM UTF.
+.PP
+.I Fullrune
+returns 1 if the string
+.I s
+of length
+.I n
+is long enough to be decoded by
+.I chartorune
+and 0 otherwise.
+This does not guarantee that the string
+contains a legal
+.SM UTF
+encoding.
+This routine is used by programs that
+obtain input a byte at
+a time and need to know when a full rune
+has arrived.
+.PP
+The following routines are analogous to the
+corresponding string routines with
+.B utf
+substituted for
+.B str
+and
+.B rune
+substituted for
+.BR chr .
+.PP
+.I Utfecpy
+copies UTF sequences until a null sequence has been copied, but writes no 
+sequences beyond
+.IR es1 .
+If any sequences are copied,
+.I s1
+is terminated by a null sequence, and a pointer to that sequence is returned.
+Otherwise, the original
+.I s1
+is returned.
+.PP
+.I Utflen
+returns the number of runes that
+are represented by the
+.SM UTF
+string
+.IR s .
+.PP
+.I Utfnlen
+returns the number of complete runes that
+are represented by the first
+.I n
+bytes of
+.SM UTF
+string
+.IR s .
+If the last few bytes of the string contain an incompletely coded rune,
+.I utfnlen
+will not count them; in this way, it differs from
+.IR utflen ,
+which includes every byte of the string.
+.PP
+.I Utfrune
+.RI ( utfrrune )
+returns a pointer to the first (last)
+occurrence of rune
+.I c
+in the
+.SM UTF
+string
+.IR s ,
+or 0 if
+.I c
+does not occur in the string.
+The NUL byte terminating a string is considered to
+be part of the string
+.IR s .
+.PP
+.I Utfutf
+returns a pointer to the first occurrence of
+the
+.SM UTF
+string
+.I s2
+as a
+.SM UTF
+substring of
+.IR s1 ,
+or 0 if there is none.
+If
+.I s2
+is the null string,
+.I utfutf
+returns
+.IR s1 .
+.SH HISTORY
+These routines were written by Rob Pike and Ken Thompson
+and first appeared in Plan 9.
+.SH SEE ALSO
+.IR utf (7),
+.IR tcs (1)
blob - /dev/null
blob + e1aaa9be9908cef3726e43ac1c14aba263c31992 (mode 644)
--- /dev/null
+++ src/libutf/rune.c
@@ -0,0 +1,177 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+enum
+{
+	Bit1	= 7,
+	Bitx	= 6,
+	Bit2	= 5,
+	Bit3	= 4,
+	Bit4	= 3,
+
+	T1	= ((1<<(Bit1+1))-1) ^ 0xFF,	/* 0000 0000 */
+	Tx	= ((1<<(Bitx+1))-1) ^ 0xFF,	/* 1000 0000 */
+	T2	= ((1<<(Bit2+1))-1) ^ 0xFF,	/* 1100 0000 */
+	T3	= ((1<<(Bit3+1))-1) ^ 0xFF,	/* 1110 0000 */
+	T4	= ((1<<(Bit4+1))-1) ^ 0xFF,	/* 1111 0000 */
+
+	Rune1	= (1<<(Bit1+0*Bitx))-1,		/* 0000 0000 0111 1111 */
+	Rune2	= (1<<(Bit2+1*Bitx))-1,		/* 0000 0111 1111 1111 */
+	Rune3	= (1<<(Bit3+2*Bitx))-1,		/* 1111 1111 1111 1111 */
+
+	Maskx	= (1<<Bitx)-1,			/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,			/* 1100 0000 */
+
+	Bad	= Runeerror,
+};
+
+int
+chartorune(Rune *rune, char *str)
+{
+	int c, c1, c2;
+	long l;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => T1
+	 */
+	c = *(uchar*)str;
+	if(c < Tx) {
+		*rune = c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	c1 = *(uchar*)(str+1) ^ Tx;
+	if(c1 & Testx)
+		goto bad;
+	if(c < T3) {
+		if(c < T2)
+			goto bad;
+		l = ((c << Bitx) | c1) & Rune2;
+		if(l <= Rune1)
+			goto bad;
+		*rune = l;
+		return 2;
+	}
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	c2 = *(uchar*)(str+2) ^ Tx;
+	if(c2 & Testx)
+		goto bad;
+	if(c < T4) {
+		l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+		if(l <= Rune2)
+			goto bad;
+		*rune = l;
+		return 3;
+	}
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+}
+
+int
+runetochar(char *str, Rune *rune)
+{
+	long c;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 */
+	c = *rune;
+	if(c <= Rune1) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	if(c <= Rune2) {
+		str[0] = T2 | (c >> 1*Bitx);
+		str[1] = Tx | (c & Maskx);
+		return 2;
+	}
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	str[0] = T3 |  (c >> 2*Bitx);
+	str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+	str[2] = Tx |  (c & Maskx);
+	return 3;
+}
+
+int
+runelen(long c)
+{
+	Rune rune;
+	char str[10];
+
+	rune = c;
+	return runetochar(str, &rune);
+}
+
+int
+runenlen(Rune *r, int nrune)
+{
+	int nb, c;
+
+	nb = 0;
+	while(nrune--) {
+		c = *r++;
+		if(c <= Rune1)
+			nb++;
+		else
+		if(c <= Rune2)
+			nb += 2;
+		else
+			nb += 3;
+	}
+	return nb;
+}
+
+int
+fullrune(char *str, int n)
+{
+	int c;
+
+	if(n > 0) {
+		c = *(uchar*)str;
+		if(c < Tx)
+			return 1;
+		if(n > 1)
+			if(c < T3 || n > 2)
+				return 1;
+	}
+	return 0;
+}
blob - /dev/null
blob + c012e59e54834ecdc151ffabc2372b2c095f79f5 (mode 644)
--- /dev/null
+++ src/libutf/runestrcat.3
@@ -0,0 +1,65 @@
+.TH RUNESTRCAT 3
+.SH NAME
+runestrcat, 
+runestrncat,
+runestrcmp,
+runestrncmp,
+runestrcpy,
+runestrncpy,
+runestrecpy,
+runestrlen,
+runestrchr,
+runestrrchr,
+runestrdup,
+runestrstr \- rune string operations
+.SH SYNOPSIS
+.B #include <utf.h>
+.PP
+.ta \w'\fLRune* \fP'u
+.B
+Rune*	runestrcat(Rune *s1, Rune *s2)
+.PP
+.B
+Rune*	runestrncat(Rune *s1, Rune *s2, long n)
+.PP
+.B
+int	runestrcmp(Rune *s1, Rune *s2)
+.PP
+.B
+int	runestrncmp(Rune *s1, Rune *s2, long n)
+.PP
+.B
+Rune*	runestrcpy(Rune *s1, Rune *s2)
+.PP
+.B
+Rune*	runestrncpy(Rune *s1, Rune *s2, long n)
+.PP
+.B
+Rune*	runestrecpy(Rune *s1, Rune *es1, Rune *s2)
+.PP
+.B
+long	runestrlen(Rune *s)
+.PP
+.B
+Rune*	runestrchr(Rune *s, Rune c)
+.PP
+.B
+Rune*	runestrrchr(Rune *s, Rune c)
+.PP
+.B
+Rune*	runestrdup(Rune *s)
+.PP
+.B
+Rune*	runestrstr(Rune *s1, Rune *s2)
+.SH DESCRIPTION
+These functions are rune string analogues of
+the corresponding functions in 
+.IR strcat (3).
+.SH HISTORY
+These routines first appeared in Plan 9.
+.SH SEE ALSO
+.IR memmove (3),
+.IR rune (3),
+.IR strcat (2)
+.SH BUGS
+The outcome of overlapping moves varies among implementations.
blob - /dev/null
blob + e1e8c9d576e3dd25642f5e91d3b8137087c44973 (mode 644)
--- /dev/null
+++ src/libutf/runestrcat.c
@@ -0,0 +1,25 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrcat(Rune *s1, Rune *s2)
+{
+
+	runestrcpy(runestrchr(s1, 0), s2);
+	return s1;
+}
blob - /dev/null
blob + 45ee673a5992b3bcb4869a14a7b215a48dbb55e6 (mode 644)
--- /dev/null
+++ src/libutf/runestrchr.c
@@ -0,0 +1,35 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrchr(Rune *s, Rune c)
+{
+	Rune c0 = c;
+	Rune c1;
+
+	if(c == 0) {
+		while(*s++)
+			;
+		return s-1;
+	}
+
+	while(c1 = *s++)
+		if(c1 == c0)
+			return s-1;
+	return 0;
+}
blob - /dev/null
blob + d14145f3828f984b49bab82b58165b80dbe9ee27 (mode 644)
--- /dev/null
+++ src/libutf/runestrcmp.c
@@ -0,0 +1,35 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+runestrcmp(Rune *s1, Rune *s2)
+{
+	Rune c1, c2;
+
+	for(;;) {
+		c1 = *s1++;
+		c2 = *s2++;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			return 0;
+	}
+}
blob - /dev/null
blob + 9d7aa026a8063fec4061ded8d2efdf2c2b41e9f7 (mode 644)
--- /dev/null
+++ src/libutf/runestrcpy.c
@@ -0,0 +1,28 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrcpy(Rune *s1, Rune *s2)
+{
+	Rune *os1;
+
+	os1 = s1;
+	while(*s1++ = *s2++)
+		;
+	return os1;
+}
blob - /dev/null
blob + 97a889c8f10ebeb156dec0c655228858cfa6d800 (mode 644)
--- /dev/null
+++ src/libutf/runestrdup.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrdup(Rune *s) 
+{  
+	Rune *ns;
+
+	ns = malloc(sizeof(Rune)*(runestrlen(s) + 1));
+	if(ns == 0)
+		return 0;
+
+	return runestrcpy(ns, s);
+}
blob - /dev/null
blob + f3e4a096b4b03889a7a0d02d0ad6a5ce5ac70e1e (mode 644)
--- /dev/null
+++ src/libutf/runestrecpy.c
@@ -0,0 +1,32 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrecpy(Rune *s1, Rune *es1, Rune *s2)
+{
+	if(s1 >= es1)
+		return s1;
+
+	while(*s1++ = *s2++){
+		if(s1 == es1){
+			*--s1 = '\0';
+			break;
+		}
+	}
+	return s1;
+}
blob - /dev/null
blob + bca3050c55a8ee5d855819584cb13c187e0059ce (mode 644)
--- /dev/null
+++ src/libutf/runestrlen.c
@@ -0,0 +1,24 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+long
+runestrlen(Rune *s)
+{
+
+	return runestrchr(s, 0) - s;
+}
blob - /dev/null
blob + 74400c30e8699a594fc09e66f273741618a1d436 (mode 644)
--- /dev/null
+++ src/libutf/runestrncat.c
@@ -0,0 +1,32 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrncat(Rune *s1, Rune *s2, long n)
+{
+	Rune *os1;
+
+	os1 = s1;
+	s1 = runestrchr(s1, 0);
+	while(*s1++ = *s2++)
+		if(--n < 0) {
+			s1[-1] = 0;
+			break;
+		}
+	return os1;
+}
blob - /dev/null
blob + dbd9da45c5e4eef46a0de125f421b7717a6b3340 (mode 644)
--- /dev/null
+++ src/libutf/runestrncmp.c
@@ -0,0 +1,37 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+runestrncmp(Rune *s1, Rune *s2, long n)
+{
+	Rune c1, c2;
+
+	while(n > 0) {
+		c1 = *s1++;
+		c2 = *s2++;
+		n--;
+		if(c1 != c2) {
+			if(c1 > c2)
+				return 1;
+			return -1;
+		}
+		if(c1 == 0)
+			break;
+	}
+	return 0;
+}
blob - /dev/null
blob + acba7bc2bd589adfa0516b50ea52ea41a3401c42 (mode 644)
--- /dev/null
+++ src/libutf/runestrncpy.c
@@ -0,0 +1,33 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrncpy(Rune *s1, Rune *s2, long n)
+{
+	int i;
+	Rune *os1;
+
+	os1 = s1;
+	for(i = 0; i < n; i++)
+		if((*s1++ = *s2++) == 0) {
+			while(++i < n)
+				*s1++ = 0;
+			return os1;
+		}
+	return os1;
+}
blob - /dev/null
blob + 1f40c5a655f6331d363a3336cbfe5a08bcc4ca71 (mode 644)
--- /dev/null
+++ src/libutf/runestrrchr.c
@@ -0,0 +1,30 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+Rune*
+runestrrchr(Rune *s, Rune c)
+{
+	Rune *r;
+
+	if(c == 0)
+		return runestrchr(s, 0);
+	r = 0;
+	while(s = runestrchr(s, c))
+		r = s++;
+	return r;
+}
blob - /dev/null
blob + 48583a3d5efb027fc825527d21f32cbcc0d6a828 (mode 644)
--- /dev/null
+++ src/libutf/runestrstr.c
@@ -0,0 +1,44 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+Rune*
+runestrstr(Rune *s1, Rune *s2)
+{
+	Rune *p, *pa, *pb;
+	int c0, c;
+
+	c0 = *s2;
+	if(c0 == 0)
+		return s1;
+	s2++;
+	for(p=runestrchr(s1, c0); p; p=runestrchr(p+1, c0)) {
+		pa = p;
+		for(pb=s2;; pb++) {
+			c = *pb;
+			if(c == 0)
+				return p;
+			if(c != *++pa)
+				break;
+		}
+	}
+	return 0;
+}
blob - /dev/null
blob + ffae30e69a05c6fc50117939f7870c570fb08401 (mode 644)
--- /dev/null
+++ src/libutf/runetype.c
@@ -0,0 +1,1152 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+/*
+ * alpha ranges -
+ *	only covers ranges not in lower||upper
+ */
+static
+Rune	__alpha2[] =
+{
+	0x00d8,	0x00f6,	/* Ø - ö */
+	0x00f8,	0x01f5,	/* ø - ǵ */
+	0x0250,	0x02a8,	/* ɐ - ʨ */
+	0x038e,	0x03a1,	/* Ύ - Ρ */
+	0x03a3,	0x03ce,	/* Σ - ώ */
+	0x03d0,	0x03d6,	/* ϐ - ϖ */
+	0x03e2,	0x03f3,	/* Ϣ - ϳ */
+	0x0490,	0x04c4,	/* Ґ - ӄ */
+	0x0561,	0x0587,	/* ա - և */
+	0x05d0,	0x05ea,	/* א - ת */
+	0x05f0,	0x05f2,	/* װ - ײ */
+	0x0621,	0x063a,	/* ء - غ */
+	0x0640,	0x064a,	/* ـ - ي */
+	0x0671,	0x06b7,	/* ٱ - ڷ */
+	0x06ba,	0x06be,	/* ں - ھ */
+	0x06c0,	0x06ce,	/* ۀ - ێ */
+	0x06d0,	0x06d3,	/* ې - ۓ */
+	0x0905,	0x0939,	/* अ - ह */
+	0x0958,	0x0961,	/* क़ - ॡ */
+	0x0985,	0x098c,	/* অ - ঌ */
+	0x098f,	0x0990,	/* এ - ঐ */
+	0x0993,	0x09a8,	/* ও - ন */
+	0x09aa,	0x09b0,	/* প - র */
+	0x09b6,	0x09b9,	/* শ - হ */
+	0x09dc,	0x09dd,	/* ড় - ঢ় */
+	0x09df,	0x09e1,	/* য় - ৡ */
+	0x09f0,	0x09f1,	/* ৰ - ৱ */
+	0x0a05,	0x0a0a,	/* ਅ - ਊ */
+	0x0a0f,	0x0a10,	/* ਏ - ਐ */
+	0x0a13,	0x0a28,	/* ਓ - ਨ */
+	0x0a2a,	0x0a30,	/* ਪ - ਰ */
+	0x0a32,	0x0a33,	/* ਲ - ਲ਼ */
+	0x0a35,	0x0a36,	/* ਵ - ਸ਼ */
+	0x0a38,	0x0a39,	/* ਸ - ਹ */
+	0x0a59,	0x0a5c,	/* ਖ਼ - ੜ */
+	0x0a85,	0x0a8b,	/* અ - ઋ */
+	0x0a8f,	0x0a91,	/* એ - ઑ */
+	0x0a93,	0x0aa8,	/* ઓ - ન */
+	0x0aaa,	0x0ab0,	/* પ - ર */
+	0x0ab2,	0x0ab3,	/* લ - ળ */
+	0x0ab5,	0x0ab9,	/* વ - હ */
+	0x0b05,	0x0b0c,	/* ଅ - ଌ */
+	0x0b0f,	0x0b10,	/* ଏ - ଐ */
+	0x0b13,	0x0b28,	/* ଓ - ନ */
+	0x0b2a,	0x0b30,	/* ପ - ର */
+	0x0b32,	0x0b33,	/* ଲ - ଳ */
+	0x0b36,	0x0b39,	/* ଶ - ହ */
+	0x0b5c,	0x0b5d,	/* ଡ଼ - ଢ଼ */
+	0x0b5f,	0x0b61,	/* ୟ - ୡ */
+	0x0b85,	0x0b8a,	/* அ - ஊ */
+	0x0b8e,	0x0b90,	/* எ - ஐ */
+	0x0b92,	0x0b95,	/* ஒ - க */
+	0x0b99,	0x0b9a,	/* ங - ச */
+	0x0b9e,	0x0b9f,	/* ஞ - ட */
+	0x0ba3,	0x0ba4,	/* ண - த */
+	0x0ba8,	0x0baa,	/* ந - ப */
+	0x0bae,	0x0bb5,	/* ம - வ */
+	0x0bb7,	0x0bb9,	/* ஷ - ஹ */
+	0x0c05,	0x0c0c,	/* అ - ఌ */
+	0x0c0e,	0x0c10,	/* ఎ - ఐ */
+	0x0c12,	0x0c28,	/* ఒ - న */
+	0x0c2a,	0x0c33,	/* ప - ళ */
+	0x0c35,	0x0c39,	/* వ - హ */
+	0x0c60,	0x0c61,	/* ౠ - ౡ */
+	0x0c85,	0x0c8c,	/* ಅ - ಌ */
+	0x0c8e,	0x0c90,	/* ಎ - ಐ */
+	0x0c92,	0x0ca8,	/* ಒ - ನ */
+	0x0caa,	0x0cb3,	/* ಪ - ಳ */
+	0x0cb5,	0x0cb9,	/* ವ - ಹ */
+	0x0ce0,	0x0ce1,	/* ೠ - ೡ */
+	0x0d05,	0x0d0c,	/* അ - ഌ */
+	0x0d0e,	0x0d10,	/* എ - ഐ */
+	0x0d12,	0x0d28,	/* ഒ - ന */
+	0x0d2a,	0x0d39,	/* പ - ഹ */
+	0x0d60,	0x0d61,	/* ൠ - ൡ */
+	0x0e01,	0x0e30,	/* ก - ะ */
+	0x0e32,	0x0e33,	/* า - ำ */
+	0x0e40,	0x0e46,	/* เ - ๆ */
+	0x0e5a,	0x0e5b,	/* ๚ - ๛ */
+	0x0e81,	0x0e82,	/* ກ - ຂ */
+	0x0e87,	0x0e88,	/* ງ - ຈ */
+	0x0e94,	0x0e97,	/* ດ - ທ */
+	0x0e99,	0x0e9f,	/* ນ - ຟ */
+	0x0ea1,	0x0ea3,	/* ມ - ຣ */
+	0x0eaa,	0x0eab,	/* ສ - ຫ */
+	0x0ead,	0x0eae,	/* ອ - ຮ */
+	0x0eb2,	0x0eb3,	/* າ - ຳ */
+	0x0ec0,	0x0ec4,	/* ເ - ໄ */
+	0x0edc,	0x0edd,	/* ໜ - ໝ */
+	0x0f18,	0x0f19,	/* ༘ - ༙ */
+	0x0f40,	0x0f47,	/* ཀ - ཇ */
+	0x0f49,	0x0f69,	/* ཉ - ཀྵ */
+	0x10d0,	0x10f6,	/* ა - ჶ */
+	0x1100,	0x1159,	/* ᄀ - ᅙ */
+	0x115f,	0x11a2,	/* ᅟ - ᆢ */
+	0x11a8,	0x11f9,	/* ᆨ - ᇹ */
+	0x1e00,	0x1e9b,	/* Ḁ - ẛ */
+	0x1f50,	0x1f57,	/* ὐ - ὗ */
+	0x1f80,	0x1fb4,	/* ᾀ - ᾴ */
+	0x1fb6,	0x1fbc,	/* ᾶ - ᾼ */
+	0x1fc2,	0x1fc4,	/* ῂ - ῄ */
+	0x1fc6,	0x1fcc,	/* ῆ - ῌ */
+	0x1fd0,	0x1fd3,	/* ῐ - ΐ */
+	0x1fd6,	0x1fdb,	/* ῖ - Ί */
+	0x1fe0,	0x1fec,	/* ῠ - Ῥ */
+	0x1ff2,	0x1ff4,	/* ῲ - ῴ */
+	0x1ff6,	0x1ffc,	/* ῶ - ῼ */
+	0x210a,	0x2113,	/* ℊ - ℓ */
+	0x2115,	0x211d,	/* ℕ - ℝ */
+	0x2120,	0x2122,	/* ℠ - ™ */
+	0x212a,	0x2131,	/* K - ℱ */
+	0x2133,	0x2138,	/* ℳ - ℸ */
+	0x3041,	0x3094,	/* ぁ - ゔ */
+	0x30a1,	0x30fa,	/* ァ - ヺ */
+	0x3105,	0x312c,	/* ㄅ - ㄬ */
+	0x3131,	0x318e,	/* ㄱ - ㆎ */
+	0x3192,	0x319f,	/* ㆒ - ㆟ */
+	0x3260,	0x327b,	/* ㉠ - ㉻ */
+	0x328a,	0x32b0,	/* ㊊ - ㊰ */
+	0x32d0,	0x32fe,	/* ㋐ - ㋾ */
+	0x3300,	0x3357,	/* ㌀ - ㍗ */
+	0x3371,	0x3376,	/* ㍱ - ㍶ */
+	0x337b,	0x3394,	/* ㍻ - ㎔ */
+	0x3399,	0x339e,	/* ㎙ - ㎞ */
+	0x33a9,	0x33ad,	/* ㎩ - ㎭ */
+	0x33b0,	0x33c1,	/* ㎰ - ㏁ */
+	0x33c3,	0x33c5,	/* ㏃ - ㏅ */
+	0x33c7,	0x33d7,	/* ㏇ - ㏗ */
+	0x33d9,	0x33dd,	/* ㏙ - ㏝ */
+	0x4e00,	0x9fff,	/* 一 - 鿿 */
+	0xac00,	0xd7a3,	/* 가 - 힣 */
+	0xf900,	0xfb06,	/* 豈 - st */
+	0xfb13,	0xfb17,	/* ﬓ - ﬗ */
+	0xfb1f,	0xfb28,	/* ײַ - ﬨ */
+	0xfb2a,	0xfb36,	/* שׁ - זּ */
+	0xfb38,	0xfb3c,	/* טּ - לּ */
+	0xfb40,	0xfb41,	/* נּ - סּ */
+	0xfb43,	0xfb44,	/* ףּ - פּ */
+	0xfb46,	0xfbb1,	/* צּ - ﮱ */
+	0xfbd3,	0xfd3d,	/* ﯓ - ﴽ */
+	0xfd50,	0xfd8f,	/* ﵐ - ﶏ */
+	0xfd92,	0xfdc7,	/* ﶒ - ﷇ */
+	0xfdf0,	0xfdf9,	/* ﷰ - ﷹ */
+	0xfe70,	0xfe72,	/* ﹰ - ﹲ */
+	0xfe76,	0xfefc,	/* ﹶ - ﻼ */
+	0xff66,	0xff6f,	/* ヲ - ッ */
+	0xff71,	0xff9d,	/* ア - ン */
+	0xffa0,	0xffbe,	/* ᅠ - ᄒ */
+	0xffc2,	0xffc7,	/* ᅡ - ᅦ */
+	0xffca,	0xffcf,	/* ᅧ - ᅬ */
+	0xffd2,	0xffd7,	/* ᅭ - ᅲ */
+	0xffda,	0xffdc,	/* ᅳ - ᅵ */
+};
+
+/*
+ * alpha singlets -
+ *	only covers ranges not in lower||upper
+ */
+static
+Rune	__alpha1[] =
+{
+	0x00aa,	/* ª */
+	0x00b5,	/* µ */
+	0x00ba,	/* º */
+	0x03da,	/* Ϛ */
+	0x03dc,	/* Ϝ */
+	0x03de,	/* Ϟ */
+	0x03e0,	/* Ϡ */
+	0x06d5,	/* ە */
+	0x09b2,	/* ল */
+	0x0a5e,	/* ਫ਼ */
+	0x0a8d,	/* ઍ */
+	0x0ae0,	/* ૠ */
+	0x0b9c,	/* ஜ */
+	0x0cde,	/* ೞ */
+	0x0e4f,	/* ๏ */
+	0x0e84,	/* ຄ */
+	0x0e8a,	/* ຊ */
+	0x0e8d,	/* ຍ */
+	0x0ea5,	/* ລ */
+	0x0ea7,	/* ວ */
+	0x0eb0,	/* ະ */
+	0x0ebd,	/* ຽ */
+	0x1fbe,	/* ι */
+	0x207f,	/* ⁿ */
+	0x20a8,	/* ₨ */
+	0x2102,	/* ℂ */
+	0x2107,	/* ℇ */
+	0x2124,	/* ℤ */
+	0x2126,	/* Ω */
+	0x2128,	/* ℨ */
+	0xfb3e,	/* מּ */
+	0xfe74,	/* ﹴ */
+};
+
+/*
+ * space ranges
+ */
+static
+Rune	__space2[] =
+{
+	0x0009,	0x000a,	/* tab and newline */
+	0x0020,	0x0020,	/* space */
+	0x00a0,	0x00a0,	/*   */
+	0x2000,	0x200b,	/*   - ​ */
+	0x2028,	0x2029,	/* 
 - 
 */
+	0x3000,	0x3000,	/*   */
+	0xfeff,	0xfeff,	/*  */
+};
+
+/*
+ * lower case ranges
+ *	3rd col is conversion excess 500
+ */
+static
+Rune	__toupper2[] =
+{
+	0x0061,	0x007a, 468,	/* a-z A-Z */
+	0x00e0,	0x00f6, 468,	/* à-ö À-Ö */
+	0x00f8,	0x00fe, 468,	/* ø-þ Ø-Þ */
+	0x0256,	0x0257, 295,	/* ɖ-ɗ Ɖ-Ɗ */
+	0x0258,	0x0259, 298,	/* ɘ-ə Ǝ-Ə */
+	0x028a,	0x028b, 283,	/* ʊ-ʋ Ʊ-Ʋ */
+	0x03ad,	0x03af, 463,	/* έ-ί Έ-Ί */
+	0x03b1,	0x03c1, 468,	/* α-ρ Α-Ρ */
+	0x03c3,	0x03cb, 468,	/* σ-ϋ Σ-Ϋ */
+	0x03cd,	0x03ce, 437,	/* ύ-ώ Ύ-Ώ */
+	0x0430,	0x044f, 468,	/* а-я А-Я */
+	0x0451,	0x045c, 420,	/* ё-ќ Ё-Ќ */
+	0x045e,	0x045f, 420,	/* ў-џ Ў-Џ */
+	0x0561,	0x0586, 452,	/* ա-ֆ Ա-Ֆ */
+	0x1f00,	0x1f07, 508,	/* ἀ-ἇ Ἀ-Ἇ */
+	0x1f10,	0x1f15, 508,	/* ἐ-ἕ Ἐ-Ἕ */
+	0x1f20,	0x1f27, 508,	/* ἠ-ἧ Ἠ-Ἧ */
+	0x1f30,	0x1f37, 508,	/* ἰ-ἷ Ἰ-Ἷ */
+	0x1f40,	0x1f45, 508,	/* ὀ-ὅ Ὀ-Ὅ */
+	0x1f60,	0x1f67, 508,	/* ὠ-ὧ Ὠ-Ὧ */
+	0x1f70,	0x1f71, 574,	/* ὰ-ά Ὰ-Ά */
+	0x1f72,	0x1f75, 586,	/* ὲ-ή Ὲ-Ή */
+	0x1f76,	0x1f77, 600,	/* ὶ-ί Ὶ-Ί */
+	0x1f78,	0x1f79, 628,	/* ὸ-ό Ὸ-Ό */
+	0x1f7a,	0x1f7b, 612,	/* ὺ-ύ Ὺ-Ύ */
+	0x1f7c,	0x1f7d, 626,	/* ὼ-ώ Ὼ-Ώ */
+	0x1f80,	0x1f87, 508,	/* ᾀ-ᾇ ᾈ-ᾏ */
+	0x1f90,	0x1f97, 508,	/* ᾐ-ᾗ ᾘ-ᾟ */
+	0x1fa0,	0x1fa7, 508,	/* ᾠ-ᾧ ᾨ-ᾯ */
+	0x1fb0,	0x1fb1, 508,	/* ᾰ-ᾱ Ᾰ-Ᾱ */
+	0x1fd0,	0x1fd1, 508,	/* ῐ-ῑ Ῐ-Ῑ */
+	0x1fe0,	0x1fe1, 508,	/* ῠ-ῡ Ῠ-Ῡ */
+	0x2170,	0x217f, 484,	/* ⅰ-ⅿ Ⅰ-Ⅿ */
+	0x24d0,	0x24e9, 474,	/* ⓐ-ⓩ Ⓐ-Ⓩ */
+	0xff41,	0xff5a, 468,	/* a-z A-Z */
+};
+
+/*
+ * lower case singlets
+ *	2nd col is conversion excess 500
+ */
+static
+Rune	__toupper1[] =
+{
+	0x00ff, 621,	/* ÿ Ÿ */
+	0x0101, 499,	/* ā Ā */
+	0x0103, 499,	/* ă Ă */
+	0x0105, 499,	/* ą Ą */
+	0x0107, 499,	/* ć Ć */
+	0x0109, 499,	/* ĉ Ĉ */
+	0x010b, 499,	/* ċ Ċ */
+	0x010d, 499,	/* č Č */
+	0x010f, 499,	/* ď Ď */
+	0x0111, 499,	/* đ Đ */
+	0x0113, 499,	/* ē Ē */
+	0x0115, 499,	/* ĕ Ĕ */
+	0x0117, 499,	/* ė Ė */
+	0x0119, 499,	/* ę Ę */
+	0x011b, 499,	/* ě Ě */
+	0x011d, 499,	/* ĝ Ĝ */
+	0x011f, 499,	/* ğ Ğ */
+	0x0121, 499,	/* ġ Ġ */
+	0x0123, 499,	/* ģ Ģ */
+	0x0125, 499,	/* ĥ Ĥ */
+	0x0127, 499,	/* ħ Ħ */
+	0x0129, 499,	/* ĩ Ĩ */
+	0x012b, 499,	/* ī Ī */
+	0x012d, 499,	/* ĭ Ĭ */
+	0x012f, 499,	/* į Į */
+	0x0131, 268,	/* ı I */
+	0x0133, 499,	/* ij IJ */
+	0x0135, 499,	/* ĵ Ĵ */
+	0x0137, 499,	/* ķ Ķ */
+	0x013a, 499,	/* ĺ Ĺ */
+	0x013c, 499,	/* ļ Ļ */
+	0x013e, 499,	/* ľ Ľ */
+	0x0140, 499,	/* ŀ Ŀ */
+	0x0142, 499,	/* ł Ł */
+	0x0144, 499,	/* ń Ń */
+	0x0146, 499,	/* ņ Ņ */
+	0x0148, 499,	/* ň Ň */
+	0x014b, 499,	/* ŋ Ŋ */
+	0x014d, 499,	/* ō Ō */
+	0x014f, 499,	/* ŏ Ŏ */
+	0x0151, 499,	/* ő Ő */
+	0x0153, 499,	/* œ Œ */
+	0x0155, 499,	/* ŕ Ŕ */
+	0x0157, 499,	/* ŗ Ŗ */
+	0x0159, 499,	/* ř Ř */
+	0x015b, 499,	/* ś Ś */
+	0x015d, 499,	/* ŝ Ŝ */
+	0x015f, 499,	/* ş Ş */
+	0x0161, 499,	/* š Š */
+	0x0163, 499,	/* ţ Ţ */
+	0x0165, 499,	/* ť Ť */
+	0x0167, 499,	/* ŧ Ŧ */
+	0x0169, 499,	/* ũ Ũ */
+	0x016b, 499,	/* ū Ū */
+	0x016d, 499,	/* ŭ Ŭ */
+	0x016f, 499,	/* ů Ů */
+	0x0171, 499,	/* ű Ű */
+	0x0173, 499,	/* ų Ų */
+	0x0175, 499,	/* ŵ Ŵ */
+	0x0177, 499,	/* ŷ Ŷ */
+	0x017a, 499,	/* ź Ź */
+	0x017c, 499,	/* ż Ż */
+	0x017e, 499,	/* ž Ž */
+	0x017f, 200,	/* ſ S */
+	0x0183, 499,	/* ƃ Ƃ */
+	0x0185, 499,	/* ƅ Ƅ */
+	0x0188, 499,	/* ƈ Ƈ */
+	0x018c, 499,	/* ƌ Ƌ */
+	0x0192, 499,	/* ƒ Ƒ */
+	0x0199, 499,	/* ƙ Ƙ */
+	0x01a1, 499,	/* ơ Ơ */
+	0x01a3, 499,	/* ƣ Ƣ */
+	0x01a5, 499,	/* ƥ Ƥ */
+	0x01a8, 499,	/* ƨ Ƨ */
+	0x01ad, 499,	/* ƭ Ƭ */
+	0x01b0, 499,	/* ư Ư */
+	0x01b4, 499,	/* ƴ Ƴ */
+	0x01b6, 499,	/* ƶ Ƶ */
+	0x01b9, 499,	/* ƹ Ƹ */
+	0x01bd, 499,	/* ƽ Ƽ */
+	0x01c5, 499,	/* Dž DŽ */
+	0x01c6, 498,	/* dž DŽ */
+	0x01c8, 499,	/* Lj LJ */
+	0x01c9, 498,	/* lj LJ */
+	0x01cb, 499,	/* Nj NJ */
+	0x01cc, 498,	/* nj NJ */
+	0x01ce, 499,	/* ǎ Ǎ */
+	0x01d0, 499,	/* ǐ Ǐ */
+	0x01d2, 499,	/* ǒ Ǒ */
+	0x01d4, 499,	/* ǔ Ǔ */
+	0x01d6, 499,	/* ǖ Ǖ */
+	0x01d8, 499,	/* ǘ Ǘ */
+	0x01da, 499,	/* ǚ Ǚ */
+	0x01dc, 499,	/* ǜ Ǜ */
+	0x01df, 499,	/* ǟ Ǟ */
+	0x01e1, 499,	/* ǡ Ǡ */
+	0x01e3, 499,	/* ǣ Ǣ */
+	0x01e5, 499,	/* ǥ Ǥ */
+	0x01e7, 499,	/* ǧ Ǧ */
+	0x01e9, 499,	/* ǩ Ǩ */
+	0x01eb, 499,	/* ǫ Ǫ */
+	0x01ed, 499,	/* ǭ Ǭ */
+	0x01ef, 499,	/* ǯ Ǯ */
+	0x01f2, 499,	/* Dz DZ */
+	0x01f3, 498,	/* dz DZ */
+	0x01f5, 499,	/* ǵ Ǵ */
+	0x01fb, 499,	/* ǻ Ǻ */
+	0x01fd, 499,	/* ǽ Ǽ */
+	0x01ff, 499,	/* ǿ Ǿ */
+	0x0201, 499,	/* ȁ Ȁ */
+	0x0203, 499,	/* ȃ Ȃ */
+	0x0205, 499,	/* ȅ Ȅ */
+	0x0207, 499,	/* ȇ Ȇ */
+	0x0209, 499,	/* ȉ Ȉ */
+	0x020b, 499,	/* ȋ Ȋ */
+	0x020d, 499,	/* ȍ Ȍ */
+	0x020f, 499,	/* ȏ Ȏ */
+	0x0211, 499,	/* ȑ Ȑ */
+	0x0213, 499,	/* ȓ Ȓ */
+	0x0215, 499,	/* ȕ Ȕ */
+	0x0217, 499,	/* ȗ Ȗ */
+	0x0253, 290,	/* ɓ Ɓ */
+	0x0254, 294,	/* ɔ Ɔ */
+	0x025b, 297,	/* ɛ Ɛ */
+	0x0260, 295,	/* ɠ Ɠ */
+	0x0263, 293,	/* ɣ Ɣ */
+	0x0268, 291,	/* ɨ Ɨ */
+	0x0269, 289,	/* ɩ Ɩ */
+	0x026f, 289,	/* ɯ Ɯ */
+	0x0272, 287,	/* ɲ Ɲ */
+	0x0283, 282,	/* ʃ Ʃ */
+	0x0288, 282,	/* ʈ Ʈ */
+	0x0292, 281,	/* ʒ Ʒ */
+	0x03ac, 462,	/* ά Ά */
+	0x03cc, 436,	/* ό Ό */
+	0x03d0, 438,	/* ϐ Β */
+	0x03d1, 443,	/* ϑ Θ */
+	0x03d5, 453,	/* ϕ Φ */
+	0x03d6, 446,	/* ϖ Π */
+	0x03e3, 499,	/* ϣ Ϣ */
+	0x03e5, 499,	/* ϥ Ϥ */
+	0x03e7, 499,	/* ϧ Ϧ */
+	0x03e9, 499,	/* ϩ Ϩ */
+	0x03eb, 499,	/* ϫ Ϫ */
+	0x03ed, 499,	/* ϭ Ϭ */
+	0x03ef, 499,	/* ϯ Ϯ */
+	0x03f0, 414,	/* ϰ Κ */
+	0x03f1, 420,	/* ϱ Ρ */
+	0x0461, 499,	/* ѡ Ѡ */
+	0x0463, 499,	/* ѣ Ѣ */
+	0x0465, 499,	/* ѥ Ѥ */
+	0x0467, 499,	/* ѧ Ѧ */
+	0x0469, 499,	/* ѩ Ѩ */
+	0x046b, 499,	/* ѫ Ѫ */
+	0x046d, 499,	/* ѭ Ѭ */
+	0x046f, 499,	/* ѯ Ѯ */
+	0x0471, 499,	/* ѱ Ѱ */
+	0x0473, 499,	/* ѳ Ѳ */
+	0x0475, 499,	/* ѵ Ѵ */
+	0x0477, 499,	/* ѷ Ѷ */
+	0x0479, 499,	/* ѹ Ѹ */
+	0x047b, 499,	/* ѻ Ѻ */
+	0x047d, 499,	/* ѽ Ѽ */
+	0x047f, 499,	/* ѿ Ѿ */
+	0x0481, 499,	/* ҁ Ҁ */
+	0x0491, 499,	/* ґ Ґ */
+	0x0493, 499,	/* ғ Ғ */
+	0x0495, 499,	/* ҕ Ҕ */
+	0x0497, 499,	/* җ Җ */
+	0x0499, 499,	/* ҙ Ҙ */
+	0x049b, 499,	/* қ Қ */
+	0x049d, 499,	/* ҝ Ҝ */
+	0x049f, 499,	/* ҟ Ҟ */
+	0x04a1, 499,	/* ҡ Ҡ */
+	0x04a3, 499,	/* ң Ң */
+	0x04a5, 499,	/* ҥ Ҥ */
+	0x04a7, 499,	/* ҧ Ҧ */
+	0x04a9, 499,	/* ҩ Ҩ */
+	0x04ab, 499,	/* ҫ Ҫ */
+	0x04ad, 499,	/* ҭ Ҭ */
+	0x04af, 499,	/* ү Ү */
+	0x04b1, 499,	/* ұ Ұ */
+	0x04b3, 499,	/* ҳ Ҳ */
+	0x04b5, 499,	/* ҵ Ҵ */
+	0x04b7, 499,	/* ҷ Ҷ */
+	0x04b9, 499,	/* ҹ Ҹ */
+	0x04bb, 499,	/* һ Һ */
+	0x04bd, 499,	/* ҽ Ҽ */
+	0x04bf, 499,	/* ҿ Ҿ */
+	0x04c2, 499,	/* ӂ Ӂ */
+	0x04c4, 499,	/* ӄ Ӄ */
+	0x04c8, 499,	/* ӈ Ӈ */
+	0x04cc, 499,	/* ӌ Ӌ */
+	0x04d1, 499,	/* ӑ Ӑ */
+	0x04d3, 499,	/* ӓ Ӓ */
+	0x04d5, 499,	/* ӕ Ӕ */
+	0x04d7, 499,	/* ӗ Ӗ */
+	0x04d9, 499,	/* ә Ә */
+	0x04db, 499,	/* ӛ Ӛ */
+	0x04dd, 499,	/* ӝ Ӝ */
+	0x04df, 499,	/* ӟ Ӟ */
+	0x04e1, 499,	/* ӡ Ӡ */
+	0x04e3, 499,	/* ӣ Ӣ */
+	0x04e5, 499,	/* ӥ Ӥ */
+	0x04e7, 499,	/* ӧ Ӧ */
+	0x04e9, 499,	/* ө Ө */
+	0x04eb, 499,	/* ӫ Ӫ */
+	0x04ef, 499,	/* ӯ Ӯ */
+	0x04f1, 499,	/* ӱ Ӱ */
+	0x04f3, 499,	/* ӳ Ӳ */
+	0x04f5, 499,	/* ӵ Ӵ */
+	0x04f9, 499,	/* ӹ Ӹ */
+	0x1e01, 499,	/* ḁ Ḁ */
+	0x1e03, 499,	/* ḃ Ḃ */
+	0x1e05, 499,	/* ḅ Ḅ */
+	0x1e07, 499,	/* ḇ Ḇ */
+	0x1e09, 499,	/* ḉ Ḉ */
+	0x1e0b, 499,	/* ḋ Ḋ */
+	0x1e0d, 499,	/* ḍ Ḍ */
+	0x1e0f, 499,	/* ḏ Ḏ */
+	0x1e11, 499,	/* ḑ Ḑ */
+	0x1e13, 499,	/* ḓ Ḓ */
+	0x1e15, 499,	/* ḕ Ḕ */
+	0x1e17, 499,	/* ḗ Ḗ */
+	0x1e19, 499,	/* ḙ Ḙ */
+	0x1e1b, 499,	/* ḛ Ḛ */
+	0x1e1d, 499,	/* ḝ Ḝ */
+	0x1e1f, 499,	/* ḟ Ḟ */
+	0x1e21, 499,	/* ḡ Ḡ */
+	0x1e23, 499,	/* ḣ Ḣ */
+	0x1e25, 499,	/* ḥ Ḥ */
+	0x1e27, 499,	/* ḧ Ḧ */
+	0x1e29, 499,	/* ḩ Ḩ */
+	0x1e2b, 499,	/* ḫ Ḫ */
+	0x1e2d, 499,	/* ḭ Ḭ */
+	0x1e2f, 499,	/* ḯ Ḯ */
+	0x1e31, 499,	/* ḱ Ḱ */
+	0x1e33, 499,	/* ḳ Ḳ */
+	0x1e35, 499,	/* ḵ Ḵ */
+	0x1e37, 499,	/* ḷ Ḷ */
+	0x1e39, 499,	/* ḹ Ḹ */
+	0x1e3b, 499,	/* ḻ Ḻ */
+	0x1e3d, 499,	/* ḽ Ḽ */
+	0x1e3f, 499,	/* ḿ Ḿ */
+	0x1e41, 499,	/* ṁ Ṁ */
+	0x1e43, 499,	/* ṃ Ṃ */
+	0x1e45, 499,	/* ṅ Ṅ */
+	0x1e47, 499,	/* ṇ Ṇ */
+	0x1e49, 499,	/* ṉ Ṉ */
+	0x1e4b, 499,	/* ṋ Ṋ */
+	0x1e4d, 499,	/* ṍ Ṍ */
+	0x1e4f, 499,	/* ṏ Ṏ */
+	0x1e51, 499,	/* ṑ Ṑ */
+	0x1e53, 499,	/* ṓ Ṓ */
+	0x1e55, 499,	/* ṕ Ṕ */
+	0x1e57, 499,	/* ṗ Ṗ */
+	0x1e59, 499,	/* ṙ Ṙ */
+	0x1e5b, 499,	/* ṛ Ṛ */
+	0x1e5d, 499,	/* ṝ Ṝ */
+	0x1e5f, 499,	/* ṟ Ṟ */
+	0x1e61, 499,	/* ṡ Ṡ */
+	0x1e63, 499,	/* ṣ Ṣ */
+	0x1e65, 499,	/* ṥ Ṥ */
+	0x1e67, 499,	/* ṧ Ṧ */
+	0x1e69, 499,	/* ṩ Ṩ */
+	0x1e6b, 499,	/* ṫ Ṫ */
+	0x1e6d, 499,	/* ṭ Ṭ */
+	0x1e6f, 499,	/* ṯ Ṯ */
+	0x1e71, 499,	/* ṱ Ṱ */
+	0x1e73, 499,	/* ṳ Ṳ */
+	0x1e75, 499,	/* ṵ Ṵ */
+	0x1e77, 499,	/* ṷ Ṷ */
+	0x1e79, 499,	/* ṹ Ṹ */
+	0x1e7b, 499,	/* ṻ Ṻ */
+	0x1e7d, 499,	/* ṽ Ṽ */
+	0x1e7f, 499,	/* ṿ Ṿ */
+	0x1e81, 499,	/* ẁ Ẁ */
+	0x1e83, 499,	/* ẃ Ẃ */
+	0x1e85, 499,	/* ẅ Ẅ */
+	0x1e87, 499,	/* ẇ Ẇ */
+	0x1e89, 499,	/* ẉ Ẉ */
+	0x1e8b, 499,	/* ẋ Ẋ */
+	0x1e8d, 499,	/* ẍ Ẍ */
+	0x1e8f, 499,	/* ẏ Ẏ */
+	0x1e91, 499,	/* ẑ Ẑ */
+	0x1e93, 499,	/* ẓ Ẓ */
+	0x1e95, 499,	/* ẕ Ẕ */
+	0x1ea1, 499,	/* ạ Ạ */
+	0x1ea3, 499,	/* ả Ả */
+	0x1ea5, 499,	/* ấ Ấ */
+	0x1ea7, 499,	/* ầ Ầ */
+	0x1ea9, 499,	/* ẩ Ẩ */
+	0x1eab, 499,	/* ẫ Ẫ */
+	0x1ead, 499,	/* ậ Ậ */
+	0x1eaf, 499,	/* ắ Ắ */
+	0x1eb1, 499,	/* ằ Ằ */
+	0x1eb3, 499,	/* ẳ Ẳ */
+	0x1eb5, 499,	/* ẵ Ẵ */
+	0x1eb7, 499,	/* ặ Ặ */
+	0x1eb9, 499,	/* ẹ Ẹ */
+	0x1ebb, 499,	/* ẻ Ẻ */
+	0x1ebd, 499,	/* ẽ Ẽ */
+	0x1ebf, 499,	/* ế Ế */
+	0x1ec1, 499,	/* ề Ề */
+	0x1ec3, 499,	/* ể Ể */
+	0x1ec5, 499,	/* ễ Ễ */
+	0x1ec7, 499,	/* ệ Ệ */
+	0x1ec9, 499,	/* ỉ Ỉ */
+	0x1ecb, 499,	/* ị Ị */
+	0x1ecd, 499,	/* ọ Ọ */
+	0x1ecf, 499,	/* ỏ Ỏ */
+	0x1ed1, 499,	/* ố Ố */
+	0x1ed3, 499,	/* ồ Ồ */
+	0x1ed5, 499,	/* ổ Ổ */
+	0x1ed7, 499,	/* ỗ Ỗ */
+	0x1ed9, 499,	/* ộ Ộ */
+	0x1edb, 499,	/* ớ Ớ */
+	0x1edd, 499,	/* ờ Ờ */
+	0x1edf, 499,	/* ở Ở */
+	0x1ee1, 499,	/* ỡ Ỡ */
+	0x1ee3, 499,	/* ợ Ợ */
+	0x1ee5, 499,	/* ụ Ụ */
+	0x1ee7, 499,	/* ủ Ủ */
+	0x1ee9, 499,	/* ứ Ứ */
+	0x1eeb, 499,	/* ừ Ừ */
+	0x1eed, 499,	/* ử Ử */
+	0x1eef, 499,	/* ữ Ữ */
+	0x1ef1, 499,	/* ự Ự */
+	0x1ef3, 499,	/* ỳ Ỳ */
+	0x1ef5, 499,	/* ỵ Ỵ */
+	0x1ef7, 499,	/* ỷ Ỷ */
+	0x1ef9, 499,	/* ỹ Ỹ */
+	0x1f51, 508,	/* ὑ Ὑ */
+	0x1f53, 508,	/* ὓ Ὓ */
+	0x1f55, 508,	/* ὕ Ὕ */
+	0x1f57, 508,	/* ὗ Ὗ */
+	0x1fb3, 509,	/* ᾳ ᾼ */
+	0x1fc3, 509,	/* ῃ ῌ */
+	0x1fe5, 507,	/* ῥ Ῥ */
+	0x1ff3, 509,	/* ῳ ῼ */
+};
+
+/*
+ * upper case ranges
+ *	3rd col is conversion excess 500
+ */
+static
+Rune	__tolower2[] =
+{
+	0x0041,	0x005a, 532,	/* A-Z a-z */
+	0x00c0,	0x00d6, 532,	/* À-Ö à-ö */
+	0x00d8,	0x00de, 532,	/* Ø-Þ ø-þ */
+	0x0189,	0x018a, 705,	/* Ɖ-Ɗ ɖ-ɗ */
+	0x018e,	0x018f, 702,	/* Ǝ-Ə ɘ-ə */
+	0x01b1,	0x01b2, 717,	/* Ʊ-Ʋ ʊ-ʋ */
+	0x0388,	0x038a, 537,	/* Έ-Ί έ-ί */
+	0x038e,	0x038f, 563,	/* Ύ-Ώ ύ-ώ */
+	0x0391,	0x03a1, 532,	/* Α-Ρ α-ρ */
+	0x03a3,	0x03ab, 532,	/* Σ-Ϋ σ-ϋ */
+	0x0401,	0x040c, 580,	/* Ё-Ќ ё-ќ */
+	0x040e,	0x040f, 580,	/* Ў-Џ ў-џ */
+	0x0410,	0x042f, 532,	/* А-Я а-я */
+	0x0531,	0x0556, 548,	/* Ա-Ֆ ա-ֆ */
+	0x10a0,	0x10c5, 548,	/* Ⴀ-Ⴥ ა-ჵ */
+	0x1f08,	0x1f0f, 492,	/* Ἀ-Ἇ ἀ-ἇ */
+	0x1f18,	0x1f1d, 492,	/* Ἐ-Ἕ ἐ-ἕ */
+	0x1f28,	0x1f2f, 492,	/* Ἠ-Ἧ ἠ-ἧ */
+	0x1f38,	0x1f3f, 492,	/* Ἰ-Ἷ ἰ-ἷ */
+	0x1f48,	0x1f4d, 492,	/* Ὀ-Ὅ ὀ-ὅ */
+	0x1f68,	0x1f6f, 492,	/* Ὠ-Ὧ ὠ-ὧ */
+	0x1f88,	0x1f8f, 492,	/* ᾈ-ᾏ ᾀ-ᾇ */
+	0x1f98,	0x1f9f, 492,	/* ᾘ-ᾟ ᾐ-ᾗ */
+	0x1fa8,	0x1faf, 492,	/* ᾨ-ᾯ ᾠ-ᾧ */
+	0x1fb8,	0x1fb9, 492,	/* Ᾰ-Ᾱ ᾰ-ᾱ */
+	0x1fba,	0x1fbb, 426,	/* Ὰ-Ά ὰ-ά */
+	0x1fc8,	0x1fcb, 414,	/* Ὲ-Ή ὲ-ή */
+	0x1fd8,	0x1fd9, 492,	/* Ῐ-Ῑ ῐ-ῑ */
+	0x1fda,	0x1fdb, 400,	/* Ὶ-Ί ὶ-ί */
+	0x1fe8,	0x1fe9, 492,	/* Ῠ-Ῡ ῠ-ῡ */
+	0x1fea,	0x1feb, 388,	/* Ὺ-Ύ ὺ-ύ */
+	0x1ff8,	0x1ff9, 372,	/* Ὸ-Ό ὸ-ό */
+	0x1ffa,	0x1ffb, 374,	/* Ὼ-Ώ ὼ-ώ */
+	0x2160,	0x216f, 516,	/* Ⅰ-Ⅿ ⅰ-ⅿ */
+	0x24b6,	0x24cf, 526,	/* Ⓐ-Ⓩ ⓐ-ⓩ */
+	0xff21,	0xff3a, 532,	/* A-Z a-z */
+};
+
+/*
+ * upper case singlets
+ *	2nd col is conversion excess 500
+ */
+static
+Rune	__tolower1[] =
+{
+	0x0100, 501,	/* Ā ā */
+	0x0102, 501,	/* Ă ă */
+	0x0104, 501,	/* Ą ą */
+	0x0106, 501,	/* Ć ć */
+	0x0108, 501,	/* Ĉ ĉ */
+	0x010a, 501,	/* Ċ ċ */
+	0x010c, 501,	/* Č č */
+	0x010e, 501,	/* Ď ď */
+	0x0110, 501,	/* Đ đ */
+	0x0112, 501,	/* Ē ē */
+	0x0114, 501,	/* Ĕ ĕ */
+	0x0116, 501,	/* Ė ė */
+	0x0118, 501,	/* Ę ę */
+	0x011a, 501,	/* Ě ě */
+	0x011c, 501,	/* Ĝ ĝ */
+	0x011e, 501,	/* Ğ ğ */
+	0x0120, 501,	/* Ġ ġ */
+	0x0122, 501,	/* Ģ ģ */
+	0x0124, 501,	/* Ĥ ĥ */
+	0x0126, 501,	/* Ħ ħ */
+	0x0128, 501,	/* Ĩ ĩ */
+	0x012a, 501,	/* Ī ī */
+	0x012c, 501,	/* Ĭ ĭ */
+	0x012e, 501,	/* Į į */
+	0x0130, 301,	/* İ i */
+	0x0132, 501,	/* IJ ij */
+	0x0134, 501,	/* Ĵ ĵ */
+	0x0136, 501,	/* Ķ ķ */
+	0x0139, 501,	/* Ĺ ĺ */
+	0x013b, 501,	/* Ļ ļ */
+	0x013d, 501,	/* Ľ ľ */
+	0x013f, 501,	/* Ŀ ŀ */
+	0x0141, 501,	/* Ł ł */
+	0x0143, 501,	/* Ń ń */
+	0x0145, 501,	/* Ņ ņ */
+	0x0147, 501,	/* Ň ň */
+	0x014a, 501,	/* Ŋ ŋ */
+	0x014c, 501,	/* Ō ō */
+	0x014e, 501,	/* Ŏ ŏ */
+	0x0150, 501,	/* Ő ő */
+	0x0152, 501,	/* Œ œ */
+	0x0154, 501,	/* Ŕ ŕ */
+	0x0156, 501,	/* Ŗ ŗ */
+	0x0158, 501,	/* Ř ř */
+	0x015a, 501,	/* Ś ś */
+	0x015c, 501,	/* Ŝ ŝ */
+	0x015e, 501,	/* Ş ş */
+	0x0160, 501,	/* Š š */
+	0x0162, 501,	/* Ţ ţ */
+	0x0164, 501,	/* Ť ť */
+	0x0166, 501,	/* Ŧ ŧ */
+	0x0168, 501,	/* Ũ ũ */
+	0x016a, 501,	/* Ū ū */
+	0x016c, 501,	/* Ŭ ŭ */
+	0x016e, 501,	/* Ů ů */
+	0x0170, 501,	/* Ű ű */
+	0x0172, 501,	/* Ų ų */
+	0x0174, 501,	/* Ŵ ŵ */
+	0x0176, 501,	/* Ŷ ŷ */
+	0x0178, 379,	/* Ÿ ÿ */
+	0x0179, 501,	/* Ź ź */
+	0x017b, 501,	/* Ż ż */
+	0x017d, 501,	/* Ž ž */
+	0x0181, 710,	/* Ɓ ɓ */
+	0x0182, 501,	/* Ƃ ƃ */
+	0x0184, 501,	/* Ƅ ƅ */
+	0x0186, 706,	/* Ɔ ɔ */
+	0x0187, 501,	/* Ƈ ƈ */
+	0x018b, 501,	/* Ƌ ƌ */
+	0x0190, 703,	/* Ɛ ɛ */
+	0x0191, 501,	/* Ƒ ƒ */
+	0x0193, 705,	/* Ɠ ɠ */
+	0x0194, 707,	/* Ɣ ɣ */
+	0x0196, 711,	/* Ɩ ɩ */
+	0x0197, 709,	/* Ɨ ɨ */
+	0x0198, 501,	/* Ƙ ƙ */
+	0x019c, 711,	/* Ɯ ɯ */
+	0x019d, 713,	/* Ɲ ɲ */
+	0x01a0, 501,	/* Ơ ơ */
+	0x01a2, 501,	/* Ƣ ƣ */
+	0x01a4, 501,	/* Ƥ ƥ */
+	0x01a7, 501,	/* Ƨ ƨ */
+	0x01a9, 718,	/* Ʃ ʃ */
+	0x01ac, 501,	/* Ƭ ƭ */
+	0x01ae, 718,	/* Ʈ ʈ */
+	0x01af, 501,	/* Ư ư */
+	0x01b3, 501,	/* Ƴ ƴ */
+	0x01b5, 501,	/* Ƶ ƶ */
+	0x01b7, 719,	/* Ʒ ʒ */
+	0x01b8, 501,	/* Ƹ ƹ */
+	0x01bc, 501,	/* Ƽ ƽ */
+	0x01c4, 502,	/* DŽ dž */
+	0x01c5, 501,	/* Dž dž */
+	0x01c7, 502,	/* LJ lj */
+	0x01c8, 501,	/* Lj lj */
+	0x01ca, 502,	/* NJ nj */
+	0x01cb, 501,	/* Nj nj */
+	0x01cd, 501,	/* Ǎ ǎ */
+	0x01cf, 501,	/* Ǐ ǐ */
+	0x01d1, 501,	/* Ǒ ǒ */
+	0x01d3, 501,	/* Ǔ ǔ */
+	0x01d5, 501,	/* Ǖ ǖ */
+	0x01d7, 501,	/* Ǘ ǘ */
+	0x01d9, 501,	/* Ǚ ǚ */
+	0x01db, 501,	/* Ǜ ǜ */
+	0x01de, 501,	/* Ǟ ǟ */
+	0x01e0, 501,	/* Ǡ ǡ */
+	0x01e2, 501,	/* Ǣ ǣ */
+	0x01e4, 501,	/* Ǥ ǥ */
+	0x01e6, 501,	/* Ǧ ǧ */
+	0x01e8, 501,	/* Ǩ ǩ */
+	0x01ea, 501,	/* Ǫ ǫ */
+	0x01ec, 501,	/* Ǭ ǭ */
+	0x01ee, 501,	/* Ǯ ǯ */
+	0x01f1, 502,	/* DZ dz */
+	0x01f2, 501,	/* Dz dz */
+	0x01f4, 501,	/* Ǵ ǵ */
+	0x01fa, 501,	/* Ǻ ǻ */
+	0x01fc, 501,	/* Ǽ ǽ */
+	0x01fe, 501,	/* Ǿ ǿ */
+	0x0200, 501,	/* Ȁ ȁ */
+	0x0202, 501,	/* Ȃ ȃ */
+	0x0204, 501,	/* Ȅ ȅ */
+	0x0206, 501,	/* Ȇ ȇ */
+	0x0208, 501,	/* Ȉ ȉ */
+	0x020a, 501,	/* Ȋ ȋ */
+	0x020c, 501,	/* Ȍ ȍ */
+	0x020e, 501,	/* Ȏ ȏ */
+	0x0210, 501,	/* Ȑ ȑ */
+	0x0212, 501,	/* Ȓ ȓ */
+	0x0214, 501,	/* Ȕ ȕ */
+	0x0216, 501,	/* Ȗ ȗ */
+	0x0386, 538,	/* Ά ά */
+	0x038c, 564,	/* Ό ό */
+	0x03e2, 501,	/* Ϣ ϣ */
+	0x03e4, 501,	/* Ϥ ϥ */
+	0x03e6, 501,	/* Ϧ ϧ */
+	0x03e8, 501,	/* Ϩ ϩ */
+	0x03ea, 501,	/* Ϫ ϫ */
+	0x03ec, 501,	/* Ϭ ϭ */
+	0x03ee, 501,	/* Ϯ ϯ */
+	0x0460, 501,	/* Ѡ ѡ */
+	0x0462, 501,	/* Ѣ ѣ */
+	0x0464, 501,	/* Ѥ ѥ */
+	0x0466, 501,	/* Ѧ ѧ */
+	0x0468, 501,	/* Ѩ ѩ */
+	0x046a, 501,	/* Ѫ ѫ */
+	0x046c, 501,	/* Ѭ ѭ */
+	0x046e, 501,	/* Ѯ ѯ */
+	0x0470, 501,	/* Ѱ ѱ */
+	0x0472, 501,	/* Ѳ ѳ */
+	0x0474, 501,	/* Ѵ ѵ */
+	0x0476, 501,	/* Ѷ ѷ */
+	0x0478, 501,	/* Ѹ ѹ */
+	0x047a, 501,	/* Ѻ ѻ */
+	0x047c, 501,	/* Ѽ ѽ */
+	0x047e, 501,	/* Ѿ ѿ */
+	0x0480, 501,	/* Ҁ ҁ */
+	0x0490, 501,	/* Ґ ґ */
+	0x0492, 501,	/* Ғ ғ */
+	0x0494, 501,	/* Ҕ ҕ */
+	0x0496, 501,	/* Җ җ */
+	0x0498, 501,	/* Ҙ ҙ */
+	0x049a, 501,	/* Қ қ */
+	0x049c, 501,	/* Ҝ ҝ */
+	0x049e, 501,	/* Ҟ ҟ */
+	0x04a0, 501,	/* Ҡ ҡ */
+	0x04a2, 501,	/* Ң ң */
+	0x04a4, 501,	/* Ҥ ҥ */
+	0x04a6, 501,	/* Ҧ ҧ */
+	0x04a8, 501,	/* Ҩ ҩ */
+	0x04aa, 501,	/* Ҫ ҫ */
+	0x04ac, 501,	/* Ҭ ҭ */
+	0x04ae, 501,	/* Ү ү */
+	0x04b0, 501,	/* Ұ ұ */
+	0x04b2, 501,	/* Ҳ ҳ */
+	0x04b4, 501,	/* Ҵ ҵ */
+	0x04b6, 501,	/* Ҷ ҷ */
+	0x04b8, 501,	/* Ҹ ҹ */
+	0x04ba, 501,	/* Һ һ */
+	0x04bc, 501,	/* Ҽ ҽ */
+	0x04be, 501,	/* Ҿ ҿ */
+	0x04c1, 501,	/* Ӂ ӂ */
+	0x04c3, 501,	/* Ӄ ӄ */
+	0x04c7, 501,	/* Ӈ ӈ */
+	0x04cb, 501,	/* Ӌ ӌ */
+	0x04d0, 501,	/* Ӑ ӑ */
+	0x04d2, 501,	/* Ӓ ӓ */
+	0x04d4, 501,	/* Ӕ ӕ */
+	0x04d6, 501,	/* Ӗ ӗ */
+	0x04d8, 501,	/* Ә ә */
+	0x04da, 501,	/* Ӛ ӛ */
+	0x04dc, 501,	/* Ӝ ӝ */
+	0x04de, 501,	/* Ӟ ӟ */
+	0x04e0, 501,	/* Ӡ ӡ */
+	0x04e2, 501,	/* Ӣ ӣ */
+	0x04e4, 501,	/* Ӥ ӥ */
+	0x04e6, 501,	/* Ӧ ӧ */
+	0x04e8, 501,	/* Ө ө */
+	0x04ea, 501,	/* Ӫ ӫ */
+	0x04ee, 501,	/* Ӯ ӯ */
+	0x04f0, 501,	/* Ӱ ӱ */
+	0x04f2, 501,	/* Ӳ ӳ */
+	0x04f4, 501,	/* Ӵ ӵ */
+	0x04f8, 501,	/* Ӹ ӹ */
+	0x1e00, 501,	/* Ḁ ḁ */
+	0x1e02, 501,	/* Ḃ ḃ */
+	0x1e04, 501,	/* Ḅ ḅ */
+	0x1e06, 501,	/* Ḇ ḇ */
+	0x1e08, 501,	/* Ḉ ḉ */
+	0x1e0a, 501,	/* Ḋ ḋ */
+	0x1e0c, 501,	/* Ḍ ḍ */
+	0x1e0e, 501,	/* Ḏ ḏ */
+	0x1e10, 501,	/* Ḑ ḑ */
+	0x1e12, 501,	/* Ḓ ḓ */
+	0x1e14, 501,	/* Ḕ ḕ */
+	0x1e16, 501,	/* Ḗ ḗ */
+	0x1e18, 501,	/* Ḙ ḙ */
+	0x1e1a, 501,	/* Ḛ ḛ */
+	0x1e1c, 501,	/* Ḝ ḝ */
+	0x1e1e, 501,	/* Ḟ ḟ */
+	0x1e20, 501,	/* Ḡ ḡ */
+	0x1e22, 501,	/* Ḣ ḣ */
+	0x1e24, 501,	/* Ḥ ḥ */
+	0x1e26, 501,	/* Ḧ ḧ */
+	0x1e28, 501,	/* Ḩ ḩ */
+	0x1e2a, 501,	/* Ḫ ḫ */
+	0x1e2c, 501,	/* Ḭ ḭ */
+	0x1e2e, 501,	/* Ḯ ḯ */
+	0x1e30, 501,	/* Ḱ ḱ */
+	0x1e32, 501,	/* Ḳ ḳ */
+	0x1e34, 501,	/* Ḵ ḵ */
+	0x1e36, 501,	/* Ḷ ḷ */
+	0x1e38, 501,	/* Ḹ ḹ */
+	0x1e3a, 501,	/* Ḻ ḻ */
+	0x1e3c, 501,	/* Ḽ ḽ */
+	0x1e3e, 501,	/* Ḿ ḿ */
+	0x1e40, 501,	/* Ṁ ṁ */
+	0x1e42, 501,	/* Ṃ ṃ */
+	0x1e44, 501,	/* Ṅ ṅ */
+	0x1e46, 501,	/* Ṇ ṇ */
+	0x1e48, 501,	/* Ṉ ṉ */
+	0x1e4a, 501,	/* Ṋ ṋ */
+	0x1e4c, 501,	/* Ṍ ṍ */
+	0x1e4e, 501,	/* Ṏ ṏ */
+	0x1e50, 501,	/* Ṑ ṑ */
+	0x1e52, 501,	/* Ṓ ṓ */
+	0x1e54, 501,	/* Ṕ ṕ */
+	0x1e56, 501,	/* Ṗ ṗ */
+	0x1e58, 501,	/* Ṙ ṙ */
+	0x1e5a, 501,	/* Ṛ ṛ */
+	0x1e5c, 501,	/* Ṝ ṝ */
+	0x1e5e, 501,	/* Ṟ ṟ */
+	0x1e60, 501,	/* Ṡ ṡ */
+	0x1e62, 501,	/* Ṣ ṣ */
+	0x1e64, 501,	/* Ṥ ṥ */
+	0x1e66, 501,	/* Ṧ ṧ */
+	0x1e68, 501,	/* Ṩ ṩ */
+	0x1e6a, 501,	/* Ṫ ṫ */
+	0x1e6c, 501,	/* Ṭ ṭ */
+	0x1e6e, 501,	/* Ṯ ṯ */
+	0x1e70, 501,	/* Ṱ ṱ */
+	0x1e72, 501,	/* Ṳ ṳ */
+	0x1e74, 501,	/* Ṵ ṵ */
+	0x1e76, 501,	/* Ṷ ṷ */
+	0x1e78, 501,	/* Ṹ ṹ */
+	0x1e7a, 501,	/* Ṻ ṻ */
+	0x1e7c, 501,	/* Ṽ ṽ */
+	0x1e7e, 501,	/* Ṿ ṿ */
+	0x1e80, 501,	/* Ẁ ẁ */
+	0x1e82, 501,	/* Ẃ ẃ */
+	0x1e84, 501,	/* Ẅ ẅ */
+	0x1e86, 501,	/* Ẇ ẇ */
+	0x1e88, 501,	/* Ẉ ẉ */
+	0x1e8a, 501,	/* Ẋ ẋ */
+	0x1e8c, 501,	/* Ẍ ẍ */
+	0x1e8e, 501,	/* Ẏ ẏ */
+	0x1e90, 501,	/* Ẑ ẑ */
+	0x1e92, 501,	/* Ẓ ẓ */
+	0x1e94, 501,	/* Ẕ ẕ */
+	0x1ea0, 501,	/* Ạ ạ */
+	0x1ea2, 501,	/* Ả ả */
+	0x1ea4, 501,	/* Ấ ấ */
+	0x1ea6, 501,	/* Ầ ầ */
+	0x1ea8, 501,	/* Ẩ ẩ */
+	0x1eaa, 501,	/* Ẫ ẫ */
+	0x1eac, 501,	/* Ậ ậ */
+	0x1eae, 501,	/* Ắ ắ */
+	0x1eb0, 501,	/* Ằ ằ */
+	0x1eb2, 501,	/* Ẳ ẳ */
+	0x1eb4, 501,	/* Ẵ ẵ */
+	0x1eb6, 501,	/* Ặ ặ */
+	0x1eb8, 501,	/* Ẹ ẹ */
+	0x1eba, 501,	/* Ẻ ẻ */
+	0x1ebc, 501,	/* Ẽ ẽ */
+	0x1ebe, 501,	/* Ế ế */
+	0x1ec0, 501,	/* Ề ề */
+	0x1ec2, 501,	/* Ể ể */
+	0x1ec4, 501,	/* Ễ ễ */
+	0x1ec6, 501,	/* Ệ ệ */
+	0x1ec8, 501,	/* Ỉ ỉ */
+	0x1eca, 501,	/* Ị ị */
+	0x1ecc, 501,	/* Ọ ọ */
+	0x1ece, 501,	/* Ỏ ỏ */
+	0x1ed0, 501,	/* Ố ố */
+	0x1ed2, 501,	/* Ồ ồ */
+	0x1ed4, 501,	/* Ổ ổ */
+	0x1ed6, 501,	/* Ỗ ỗ */
+	0x1ed8, 501,	/* Ộ ộ */
+	0x1eda, 501,	/* Ớ ớ */
+	0x1edc, 501,	/* Ờ ờ */
+	0x1ede, 501,	/* Ở ở */
+	0x1ee0, 501,	/* Ỡ ỡ */
+	0x1ee2, 501,	/* Ợ ợ */
+	0x1ee4, 501,	/* Ụ ụ */
+	0x1ee6, 501,	/* Ủ ủ */
+	0x1ee8, 501,	/* Ứ ứ */
+	0x1eea, 501,	/* Ừ ừ */
+	0x1eec, 501,	/* Ử ử */
+	0x1eee, 501,	/* Ữ ữ */
+	0x1ef0, 501,	/* Ự ự */
+	0x1ef2, 501,	/* Ỳ ỳ */
+	0x1ef4, 501,	/* Ỵ ỵ */
+	0x1ef6, 501,	/* Ỷ ỷ */
+	0x1ef8, 501,	/* Ỹ ỹ */
+	0x1f59, 492,	/* Ὑ ὑ */
+	0x1f5b, 492,	/* Ὓ ὓ */
+	0x1f5d, 492,	/* Ὕ ὕ */
+	0x1f5f, 492,	/* Ὗ ὗ */
+	0x1fbc, 491,	/* ᾼ ᾳ */
+	0x1fcc, 491,	/* ῌ ῃ */
+	0x1fec, 493,	/* Ῥ ῥ */
+	0x1ffc, 491,	/* ῼ ῳ */
+};
+
+/*
+ * title characters are those between
+ * upper and lower case. ie DZ Dz dz
+ */
+static
+Rune	__totitle1[] =
+{
+	0x01c4, 501,	/* DŽ Dž */
+	0x01c6, 499,	/* dž Dž */
+	0x01c7, 501,	/* LJ Lj */
+	0x01c9, 499,	/* lj Lj */
+	0x01ca, 501,	/* NJ Nj */
+	0x01cc, 499,	/* nj Nj */
+	0x01f1, 501,	/* DZ Dz */
+	0x01f3, 499,	/* dz Dz */
+};
+
+static
+Rune*
+bsearch(Rune c, Rune *t, int n, int ne)
+{
+	Rune *p;
+	int m;
+
+	while(n > 1) {
+		m = n/2;
+		p = t + m*ne;
+		if(c >= p[0]) {
+			t = p;
+			n = n-m;
+		} else
+			n = m;
+	}
+	if(n && c >= t[0])
+		return t;
+	return 0;
+}
+
+Rune
+tolowerrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 500;
+	p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 500;
+	return c;
+}
+
+Rune
+toupperrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return c + p[2] - 500;
+	p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 500;
+	return c;
+}
+
+Rune
+totitlerune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __totitle1, nelem(__totitle1)/2, 2);
+	if(p && c == p[0])
+		return c + p[1] - 500;
+	return c;
+}
+
+int
+islowerrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __toupper2, nelem(__toupper2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = bsearch(c, __toupper1, nelem(__toupper1)/2, 2);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+int
+isupperrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __tolower2, nelem(__tolower2)/3, 3);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = bsearch(c, __tolower1, nelem(__tolower1)/2, 2);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+int
+isalpharune(Rune c)
+{
+	Rune *p;
+
+	if(isupperrune(c) || islowerrune(c))
+		return 1;
+	p = bsearch(c, __alpha2, nelem(__alpha2)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	p = bsearch(c, __alpha1, nelem(__alpha1), 1);
+	if(p && c == p[0])
+		return 1;
+	return 0;
+}
+
+int
+istitlerune(Rune c)
+{
+	return isupperrune(c) && islowerrune(c);
+}
+
+int
+isspacerune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __space2, nelem(__space2)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}
blob - /dev/null
blob + 97b7b1e7147a5350d7d5e70db522d849595324f7 (mode 644)
--- /dev/null
+++ src/libutf/utf.7
@@ -0,0 +1,91 @@
+.TH UTF 7
+.SH NAME
+UTF, Unicode, ASCII, rune \- character set and format
+.SH DESCRIPTION
+The Plan 9 character set and representation are
+based on the Unicode Standard and on the ISO multibyte
+.SM UTF-8
+encoding (Universal Character
+Set Transformation Format, 8 bits wide).
+The Unicode Standard represents its characters in 16
+bits;
+.SM UTF-8
+represents such
+values in an 8-bit byte stream.
+Throughout this manual,
+.SM UTF-8
+is shortened to
+.SM UTF.
+.PP
+In Plan 9, a
+.I rune
+is a 16-bit quantity representing a Unicode character.
+Internally, programs may store characters as runes.
+However, any external manifestation of textual information,
+in files or at the interface between programs, uses a
+machine-independent, byte-stream encoding called
+.SM UTF.
+.PP
+.SM UTF
+is designed so the 7-bit
+.SM ASCII
+set (values hexadecimal 00 to 7F),
+appear only as themselves
+in the encoding.
+Runes with values above 7F appear as sequences of two or more
+bytes with values only from 80 to FF.
+.PP
+The
+.SM UTF
+encoding of the Unicode Standard is backward compatible with
+.SM ASCII\c
+:
+programs presented only with
+.SM ASCII
+work on Plan 9
+even if not written to deal with
+.SM UTF,
+as do
+programs that deal with uninterpreted byte streams.
+However, programs that perform semantic processing on
+.SM ASCII
+graphic
+characters must convert from
+.SM UTF
+to runes
+in order to work properly with non-\c
+.SM ASCII
+input.
+See
+.IR rune (2).
+.PP
+Letting numbers be binary,
+a rune x is converted to a multibyte
+.SM UTF
+sequence
+as follows:
+.PP
+01.   x in [00000000.0bbbbbbb] → 0bbbbbbb
+.br
+10.   x in [00000bbb.bbbbbbbb] → 110bbbbb, 10bbbbbb
+.br
+11.   x in [bbbbbbbb.bbbbbbbb] → 1110bbbb, 10bbbbbb, 10bbbbbb
+.br
+.PP
+Conversion 01 provides a one-byte sequence that spans the
+.SM ASCII
+character set in a compatible way.
+Conversions 10 and 11 represent higher-valued characters
+as sequences of two or three bytes with the high bit set.
+Plan 9 does not support the 4, 5, and 6 byte sequences proposed by X-Open.
+When there are multiple ways to encode a value, for example rune 0,
+the shortest encoding is used.
+.PP
+In the inverse mapping,
+any sequence except those described above
+is incorrect and is converted to rune hexadecimal 0080.
+.SH "SEE ALSO"
+.IR ascii (1),
+.IR tcs (1),
+.IR rune (3),
+.IR "The Unicode Standard" .
blob - /dev/null
blob + 623bfda949c012d56e415408716a85fa0ad55004 (mode 644)
--- /dev/null
+++ src/libutf/utf.h
@@ -0,0 +1,51 @@
+#ifndef _UTFH_
+#define _UTFH_ 1
+
+typedef unsigned short Rune;	/* 16 bits */
+
+enum
+{
+	UTFmax		= 3,		/* maximum bytes per rune */
+	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
+	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
+	Runeerror	= 0x80,		/* decoding error in UTF */
+};
+
+/*
+ * rune routines
+ */
+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);
+
+#endif
blob - /dev/null
blob + 4b58ae87e42b5fe5a25b3536e9539250b6742cf3 (mode 644)
--- /dev/null
+++ src/libutf/utfdef.h
@@ -0,0 +1,14 @@
+#define uchar _utfuchar
+#define ushort _utfushort
+#define uint _utfuint
+#define ulong _utfulong
+#define vlong _utfvlong
+#define uvlong _utfuvlong
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
blob - /dev/null
blob + 571593503f49aa1f94ca72a8f78aa4ba25bc01ec (mode 644)
--- /dev/null
+++ src/libutf/utfecpy.c
@@ -0,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+char*
+utfecpy(char *to, char *e, char *from)
+{
+	char *end;
+
+	if(to >= e)
+		return to;
+	end = memccpy(to, from, '\0', e - to);
+	if(end == nil){
+		end = e-1;
+		while(end>to && (*--end&0xC0)==0x80)
+			;
+		*end = '\0';
+	}else{
+		end--;
+	}
+	return end;
+}
blob - /dev/null
blob + a10a5318a9e74ac90d5c849e0366ae648a6ba3d0 (mode 644)
--- /dev/null
+++ src/libutf/utflen.c
@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utflen(char *s)
+{
+	int c;
+	long n;
+	Rune rune;
+
+	n = 0;
+	for(;;) {
+		c = *(uchar*)s;
+		if(c < Runeself) {
+			if(c == 0)
+				return n;
+			s++;
+		} else
+			s += chartorune(&rune, s);
+		n++;
+	}
+	return 0;
+}
blob - /dev/null
blob + 66d674fd249c3a6c9ee607374afb33f4adcc10b8 (mode 644)
--- /dev/null
+++ src/libutf/utfnlen.c
@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utfnlen(char *s, long m)
+{
+	int c;
+	long n;
+	Rune rune;
+	char *es;
+
+	es = s + m;
+	for(n = 0; s < es; n++) {
+		c = *(uchar*)s;
+		if(c < Runeself){
+			if(c == '\0')
+				break;
+			s++;
+			continue;
+		}
+		if(!fullrune(s, es-s))
+			break;
+		s += chartorune(&rune, s);
+	}
+	return n;
+}
blob - /dev/null
blob + 37d2a72559983334d5ccaf8df986b9f0e0e999c5 (mode 644)
--- /dev/null
+++ src/libutf/utfrrune.c
@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+char*
+utfrrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	char *s1;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strrchr(s, c);
+
+	s1 = 0;
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return s1;
+			if(c1 == c)
+				s1 = s;
+			s++;
+			continue;
+		}
+		c1 = chartorune(&r, s);
+		if(r == c)
+			s1 = s;
+		s += c1;
+	}
+	return 0;
+}
blob - /dev/null
blob + 1a2e04c9f5160ba531c096b34b4e3c1b68ec883c (mode 644)
--- /dev/null
+++ src/libutf/utfrune.c
@@ -0,0 +1,45 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+char*
+utfrune(char *s, long c)
+{
+	long c1;
+	Rune r;
+	int n;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strchr(s, c);
+
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return 0;
+			if(c1 == c)
+				return s;
+			s++;
+			continue;
+		}
+		n = chartorune(&r, s);
+		if(r == c)
+			return s;
+		s += n;
+	}
+	return 0;
+}
blob - /dev/null
blob + ea36036121e8c58d3a3dcaf8eb080f63bd4116db (mode 644)
--- /dev/null
+++ src/libutf/utfutf.c
@@ -0,0 +1,41 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include <stdarg.h>
+#include <string.h>
+#include "utf.h"
+#include "utfdef.h"
+
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+char*
+utfutf(char *s1, char *s2)
+{
+	char *p;
+	long f, n1, n2;
+	Rune r;
+
+	n1 = chartorune(&r, s2);
+	f = r;
+	if(f <= Runesync)		/* represents self */
+		return strstr(s1, s2);
+
+	n2 = strlen(s2);
+	for(p=s1; p=utfrune(p, f); p+=n1)
+		if(strncmp(p, s2, n2) == 0)
+			return p;
+	return 0;
+}