Browse Source

Plan 9 from Bell Labs 2010-07-24

David du Colombier 13 years ago
parent
commit
b84e3a16d1

+ 2 - 4
rc/bin/patch/list

@@ -12,7 +12,7 @@ builtin cd /n/sources/patch || {
 	exit no-sources
 }
 
-if(~ $1 saved sorry applied undecided){
+if(~ $1 applied saved sorry maybe){
 	pref=$1^'/'
 	shift
 }
@@ -20,14 +20,13 @@ if(~ $#* 0)
 	*=(`{
 		if(~ $pref *?*)
 			builtin cd $pref
-		ls -t | grep -v '^(saved|sorry|applied|undecided)$'
+		ls -t | grep -v '^(applied|saved|sorry|maybe)$'
 	})
 
 trunc=(sed 5q)
 if(~ $#* 1)
 	trunc=cat
 
-
 {
 for(i in $*){
 	i=$pref^$i
@@ -49,7 +48,6 @@ for(i in $*){
 		echo '	'bad patch: $status >[2=1]
 	echo
 }
-
 } >/tmp/patchtmp.$pid
 
 cat /tmp/patchtmp.$pid

+ 9 - 1
sys/man/1/jpg

@@ -1,6 +1,6 @@
 .TH JPG 1
 .SH NAME
-jpg, gif, png, ppm, bmp, yuv, ico, togif, toppm, topng, toico \- view and convert pictures
+jpg, gif, png, ppm, bmp, v210, yuv, ico, togif, toppm, topng, toico \- view and convert pictures
 .SH SYNOPSIS
 .B jpg
 [
@@ -35,6 +35,13 @@ jpg, gif, png, ppm, bmp, yuv, ico, togif, toppm, topng, toico \- view and conver
 .I file
 ]
 .br
+.B v210
+[
+.B -39cdektv
+] [
+.I file ...
+]
+.br
 .B yuv
 [
 .I file
@@ -98,6 +105,7 @@ These programs read, display, and write image files in public formats.
 .IR png ,
 .IR ppm ,
 .IR bmp ,
+.IR v210 ,
 and
 .IR yuv
 read files in the corresponding formats and, by default, display

+ 17 - 11
sys/src/9/ip/esp.c

@@ -114,7 +114,7 @@ struct Userhdr
 
 struct Esppriv
 {
-	ulong	in;
+	uvlong	in;
 	ulong	inerrors;
 };
 
@@ -613,7 +613,7 @@ espstats(Proto *esp, char *buf, int len)
 	Esppriv *upriv;
 
 	upriv = esp->priv;
-	return snprint(buf, len, "%lud %lud\n",
+	return snprint(buf, len, "%llud %lud\n",
 		upriv->in,
 		upriv->inerrors);
 }
@@ -667,9 +667,10 @@ static char *
 setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
 {
 	uchar *key;
-	int c, i, nbyte, nchar;
+	int c, nbyte, nchar;
+	uint i;
 
-	if(n < 2)
+	if(n < 2 || n > 3)
 		return "bad format";
 	for(; alg->name; alg++)
 		if(strcmp(f[1], alg->name) == 0)
@@ -677,10 +678,14 @@ setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
 	if(alg->name == nil)
 		return "unknown algorithm";
 
-	if(n != 3)
-		return "bad format";
 	nbyte = (alg->keylen + 7) >> 3;
-	nchar = strlen(f[2]);
+	if (n == 2)
+		nchar = 0;
+	else
+		nchar = strlen(f[2]);
+	if(nchar != 2 * nbyte)			/* TODO: maybe < is ok */
+		return "key not required length";
+	/* convert hex digits from ascii, in place */
 	for(i=0; i<nchar; i++) {
 		c = f[2][i];
 		if(c >= '0' && c <= '9')
@@ -690,14 +695,15 @@ setalg(Espcb *ecb, char **f, int n, Algorithm *alg)
 		else if(c >= 'A' && c <= 'F')
 			f[2][i] -= 'A'-10;
 		else
-			return "bad character in key";
+			return "non-hex character in key";
 	}
+	/* collapse hex digits into complete bytes in reverse order in key */
 	key = smalloc(nbyte);
-	for(i=0; i<nchar && i*2<nbyte; i++) {
+	for(i = 0; i < nchar && i/2 < nbyte; i++) {
 		c = f[2][nchar-i-1];
 		if(i&1)
 			c <<= 4;
-		key[i>>1] |= c;
+		key[i/2] |= c;
 	}
 
 	alg->init(ecb, alg->name, key, alg->keylen);
@@ -806,7 +812,7 @@ aesahauth(Espcb *ecb, uchar *t, int tlen, uchar *auth)
 	uchar hash[AESdlen];
 
 	memset(hash, 0, AESdlen);
-	ecb->ds = hmac_aes(t, tlen, hash, BITS2BYTES(96), (uchar*)ecb->ahstate,
+	ecb->ds = hmac_aes(t, tlen, (uchar*)ecb->ahstate, BITS2BYTES(96), hash,
 		ecb->ds);
 	r = memcmp(auth, hash, ecb->ahlen) == 0;
 	memmove(auth, hash, ecb->ahlen);

+ 20 - 18
sys/src/boot/pc/etherrhine.c

@@ -15,19 +15,15 @@
 #include "fns.h"
 #include "io.h"
 
-typedef struct QLock { int r; } QLock;
-#define qlock(i)	while(0)
-#define qunlock(i)	while(0)
 #define iprint		print
 
 #include "etherif.h"
 #include "ethermii.h"
 
 enum {
-	Ntxd = 4,
-	Nrxd = 4,
+	Ntxd = 16,
+	Nrxd = 32,
 	Nwait = 50,
-	BIGSTR = 8192,
 };
 
 typedef struct Desc Desc;
@@ -56,7 +52,7 @@ struct Ctlr {
 	Desc	*txd;		/* wants to be aligned on 16-byte boundary */
 	Desc	*rxd;
 
-	QLock	attachlck;
+//	QLock	attachlck;
 	Lock	tlock;
 };
 
@@ -251,10 +247,11 @@ attach(Ether *edev)
 	Desc *txd, *rxd, *td, *rd;
 	Mii *mi;
 	MiiPhy *phy;
-	int i, s;
+	int s;
+	uint i;
 
 	ctlr = edev->ctlr;
-	qlock(&ctlr->attachlck);
+//	qlock(&ctlr->attachlck);
 	if (ctlr->attached == 0) {
 		txd = ctlr->txd;
 		rxd = ctlr->rxd;
@@ -293,7 +290,7 @@ attach(Ether *edev)
 		splx(s);
 		ctlr->attached = 1;
 	}
-	qunlock(&ctlr->attachlck);
+//	qunlock(&ctlr->attachlck);
 }
 
 static void
@@ -301,7 +298,8 @@ txstart(Ether *edev)
 {
 	Ctlr *ctlr;
 	Desc *txd, *td;
-	int i, txused, n;
+	int txused, n;
+	uint i;
 	RingBuf *tb;
 
 	ctlr = edev->ctlr;
@@ -348,7 +346,8 @@ txcomplete(Ether *edev)
 {
 	Ctlr *ctlr;
 	Desc *txd, *td;
-	int i, txused;
+	int txused;
+	uint i;
 	ulong stat;
 
 	ctlr = edev->ctlr;
@@ -364,7 +363,7 @@ txcomplete(Ether *edev)
 	ctlr->txused = txused;
 	ctlr->txtail = i;
 
-	if (txused <= Ntxd/2)
+//	if (txused <= Ntxd/2)
 		txstart(edev);
 }
 
@@ -377,7 +376,8 @@ interrupt(Ureg *, void *arg)
 	ushort  isr, misr;
 	ulong stat;
 	Desc *rxd, *rd;
-	int i, n, size;
+	int n, size;
+	uint i;
 
 	edev = (Ether*)arg;
 	ctlr = edev->ctlr;
@@ -405,7 +405,10 @@ interrupt(Ureg *, void *arg)
 				rb->len = size;
 				memmove(rb->pkt, rd->buf, size);
 				edev->ri = NEXT(edev->ri, edev->nrb);
-			}
+			} else
+				print("etherrhine: ether%d discarding input pkt;"
+					" buffer ring too small\n",
+					edev->ctlrno);
 
 			rd->size = sizeof(Etherpkt)+4;
 			coherence();
@@ -592,9 +595,8 @@ init(Ether *edev)
 		return;
 	}
 	for (i = 0; i < NMiiPhy; ++i)
-		if (ctlr->mii.phy[i])
-			if (ctlr->mii.phy[i]->oui != 0xFFFFF)
-				ctlr->mii.curphy = ctlr->mii.phy[i];
+		if (ctlr->mii.phy[i] && ctlr->mii.phy[i]->oui != 0xFFFFF)
+			ctlr->mii.curphy = ctlr->mii.phy[i];
 	miistatus(&ctlr->mii);
 
 	iow16(ctlr, Imr, 0);

+ 16 - 12
sys/src/cmd/ip/imap4d/mbox.c

@@ -795,7 +795,12 @@ static char *stoplist[] =
 	0
 };
 
-static char *folders[100];
+enum {
+	Maxokbytes	= 4096,
+	Maxfolders	= Maxokbytes / 4,
+};
+
+static char *folders[Maxfolders];
 static char *folderbuff;
 
 static void
@@ -803,20 +808,21 @@ readokfolders(void)
 {
 	int fd, nr;
 
-	folderbuff = malloc(512);
-	if(folderbuff == nil)
-		return;
 	fd = open("imap.ok", OREAD);
-	if(fd < 0){
-Fail:
+	if(fd < 0)
+		return;
+	folderbuff = malloc(Maxokbytes);
+	if(folderbuff == nil) {
+		close(fd);
+		return;
+	}
+	nr = read(fd, folderbuff, Maxokbytes-1);	/* once is ok */
+	close(fd);
+	if(nr < 0){
 		free(folderbuff);
 		folderbuff = nil;
 		return;
 	}
-	nr = read(fd, folderbuff, 512-1);	/* once is ok */
-	close(fd);
-	if(nr < 0)
-		goto Fail;
 	folderbuff[nr] = 0;
 	tokenize(folderbuff, folders, nelem(folders));
 }
@@ -853,7 +859,5 @@ okMbox(char *path)
 	|| strcmp("imap.subscribed", name) == 0
 	|| isdotdot(name) || name[0] == '/')
 		return 0;
-
 	return 1;
-
 }

+ 3 - 2
sys/src/cmd/ip/ipconfig/main.c

@@ -1143,12 +1143,13 @@ dhcprecv(void)
 	uchar buf[8000], vopts[256], taddr[IPaddrlen];
 	Bootp *bp;
 
+	memset(buf, 0, sizeof buf);
 	alarm(1000);
 	n = read(conf.fd, buf, sizeof buf);
 	alarm(0);
 
 	if(n < 0){
-		errstr(err, sizeof err);
+		rerrstr(err, sizeof err);
 		if(strstr(err, "interrupt") == nil)
 			warning("dhcprecv: bad read: %s", err);
 		else
@@ -1611,7 +1612,7 @@ parsebootp(uchar *p, int n)
 		return nil;
 	}
 
-	if(conf.xid != nhgetl(bp->xid))
+	if(conf.xid != nhgetl(bp->xid))		/* not meant for us */
 		return nil;
 
 	if(bp->op != Bootreply) {

+ 9 - 4
sys/src/cmd/ndb/dnresolve.c

@@ -983,12 +983,18 @@ xmitquery(Query *qp, int medium, int depth, uchar *obuf, int inns, int len)
 	destck(p);
 	if (qp->ndest < 0 || qp->ndest > Maxdest)
 		dnslog("qp->ndest %d out of range", qp->ndest);
-	if (qp->ndest > qp->curdest - p)
-		qp->curdest = &qp->dest[serveraddrs(qp, qp->curdest - p, depth)];
+	if (qp->ndest > qp->curdest - p) {
+		j = serveraddrs(qp, qp->curdest - p, depth);
+		if (j < 0 || j >= Maxdest) {
+			dnslog("serveraddrs() result %d out of range", j);
+			abort();
+		}
+		qp->curdest = &qp->dest[j];
+	}
 	destck(qp->curdest);
 
 	/* no servers, punt */
-	if (qp->curdest == qp->dest)
+	if (qp->ndest == 0)
 		if (cfg.straddle && cfg.inside) {
 			/* get ips of "outside-ns-ips" */
 			p = qp->curdest = qp->dest;
@@ -1255,7 +1261,6 @@ queryns(Query *qp, int depth, uchar *ibuf, uchar *obuf, int waitsecs, int inns)
 	char buf[12];
 	uchar srcip[IPaddrlen];
 	Dest *p, *np, *dest;
-//	Dest dest[Maxdest];
 
 	/* pack request into a udp message */
 	req = rand();

+ 20 - 2
sys/src/cmd/screenlock.c

@@ -190,14 +190,25 @@ grabmouse(void*)
 	}
 }
 
+/* lay down text at `p' */
+static void
+screenstring(Point p, char *s)
+{
+	string(screen, p, screen->display->white, ZP, font, s);
+	flushimage(display, 1);
+}
+
 void
 lockscreen(void)
 {
 	enum { Nfld = 5, Fldlen = 12, Cursorlen = 2*4 + 2*2*16, };
+	char *s;
 	char buf[Nfld*Fldlen], *flds[Nfld], newcmd[128], cbuf[Cursorlen];
 	int fd, dx, dy;
 	Image *i;
+	Point p;
 	Rectangle r;
+	Tm *tm;
 
 	fd = open("/dev/screen", OREAD);
 	if(fd < 0)
@@ -211,8 +222,8 @@ lockscreen(void)
 	snprint(newcmd, sizeof newcmd, "-r %s %s %d %d",
 		flds[1], flds[2], atoi(flds[3]) - 1, atoi(flds[4]) - 1);
 	newwindow(newcmd);
-	initdraw(nil, nil, "screenlock");
-
+	if (initdraw(nil, nil, "screenlock") < 0)
+		sysfatal("initdraw failed");
 	if(display == nil)
 		error("no display");
 
@@ -224,6 +235,7 @@ lockscreen(void)
 		i = readimage(display, fd, 0);
 		if(i){
  			r = screen->r;
+			p = Pt(r.max.x / 2, r.max.y * 2 / 3); 
 			dx = (Dx(screen->r) - Dx(i->r)) / 2;
 			r.min.x += dx;
 			r.max.x -= dx;
@@ -235,6 +247,12 @@ lockscreen(void)
 			flushimage(display, 1);
 		}
 		close(fd);
+
+		/* identify the user on screen, centered */
+		tm = localtime(time(0));
+		s = smprint("user %s at %d:%2d", getuser(), tm->hour, tm->min);
+		p = subpt(p, Pt(stringsize(font, "m").x * strlen(s) / 2, 0));
+		screenstring(p, s);
 	}
 
 	/* clear the cursor */

+ 17 - 9
sys/src/libauthsrv/readnvram.c

@@ -45,9 +45,11 @@ static struct {
 	"pc", "#f/fd1disk", -1, 512,
 	"mips", "#r/nvram", 1024+900, sizeof(Nvrsafe),
 	"power", "#F/flash/flash0", 0x440000, sizeof(Nvrsafe),
+	"power", "#F/flash/flash", 0x440000, sizeof(Nvrsafe),
 	"power", "#r/nvram", 4352, sizeof(Nvrsafe),	/* OK for MTX-604e */
 	"power", "/nvram", 0, sizeof(Nvrsafe),	/* OK for Ucu */
 	"arm", "#F/flash/flash0", 0x100000, sizeof(Nvrsafe),
+	"arm", "#F/flash/flash", 0x100000, sizeof(Nvrsafe),
 	"debug", "/tmp/nvram", 0, sizeof(Nvrsafe),
 };
 
@@ -129,15 +131,19 @@ typedef struct {
 	int	safelen;
 } Nvrwhere;
 
+static char *nvrfile = nil, *cputype = nil;
+
 /* returns with *locp filled in and locp->fd open, if possible */
 static void
 findnvram(Nvrwhere *locp)
 {
-	char *cputype, *nvrfile, *nvrlen, *nvroff, *v[2];
+	char *nvrlen, *nvroff, *v[2];
 	int fd, i, safeoff, safelen;
 
-	nvrfile = getenv("nvram");
-	cputype = getenv("cputype");
+	if (nvrfile == nil)
+		nvrfile = getenv("nvram");
+	if (cputype == nil)
+		cputype = getenv("cputype");
 	if(cputype == nil)
 		cputype = strdup("mips");
 	if(strcmp(cputype, "386")==0 || strcmp(cputype, "alpha")==0) {
@@ -199,8 +205,6 @@ findnvram(Nvrwhere *locp)
 			}
 			break;
 		}
-	free(nvrfile);
-	free(cputype);
 	locp->fd = fd;
 	locp->safelen = safelen;
 	locp->safeoff = safeoff;
@@ -241,12 +245,16 @@ readnvram(Nvrsafe *safep, int flag)
 		safe = safep;
 	else {
 		memset(safep, 0, sizeof(*safep));
-		if(loc.fd < 0
-		|| seek(loc.fd, loc.safeoff, 0) < 0
-		|| read(loc.fd, buf, loc.safelen) != loc.safelen){
+		if(loc.fd < 0)
+			fprint(2, "can't open %s: %r\n", nvrfile);
+		else if (seek(loc.fd, loc.safeoff, 0) < 0)
+			fprint(2, "can't seek %s to %d: %r\n",
+				nvrfile, loc.safeoff);
+		else if (read(loc.fd, buf, loc.safelen) != loc.safelen){
 			err = 1;
 			if(flag&(NVwrite|NVwriteonerr))
-				fprint(2, "can't read nvram: %r\n");
+				fprint(2, "can't read %d bytes from %s: %r\n",
+					loc.safelen, nvrfile);
 			/* start from scratch */
 			memset(safep, 0, sizeof(*safep));
 			safe = safep;

+ 51 - 15
sys/src/libc/9sys/nsec.c

@@ -1,5 +1,6 @@
 #include <u.h>
 #include <libc.h>
+#include <tos.h>
 
 static uvlong order = 0x0001020304050607ULL;
 
@@ -15,25 +16,60 @@ be2vlong(vlong *to, uchar *f)
 		t[o[i]] = f[i];
 }
 
+static int fd = -1;
+static struct {
+	int	pid;
+	int	fd;
+} fds[64];
+
 vlong
 nsec(void)
 {
-	static int fd = -1;
 	uchar b[8];
 	vlong t;
-	int opened;
+	int pid, i, f, tries;
+
+	/*
+	 * Threaded programs may have multiple procs
+	 * with different fd tables, so we may need to open
+	 * /dev/bintime on a per-pid basis
+	 */
 
-	opened = 0;
-	if(fd < 0){
-	reopen:
-		if(opened++ || (fd = open("/dev/bintime", OREAD|OCEXEC)) < 0)
-			return 0;
-	}
-	if(pread(fd, b, sizeof b, 0) != sizeof b){
-		close(fd);
-		fd = -1;
-		goto reopen;
-	}
-	be2vlong(&t, b);
-	return t;
+	/* First, look if we've opened it for this particular pid */
+	pid = _tos->pid;
+	do{
+		f = -1;
+		for(i = 0; i < nelem(fds); i++)
+			if(fds[i].pid == pid){
+				f = fds[i].fd;
+				break;
+			}
+		tries = 0;
+		if(f < 0){
+			/* If it's not open for this pid, try the global pid */
+			if(fd >= 0)
+				f = fd;
+			else{
+				/* must open */
+				if((f = open("/dev/bintime", OREAD|OCEXEC)) < 0)
+					return 0;
+				fd = f;
+				for(i = 0; i < nelem(fds); i++)
+					if(fds[i].pid == pid || fds[i].pid == 0){
+						fds[i].pid = pid;
+						fds[i].fd = f;
+						break;
+					}
+			}
+		}
+		if(pread(f, b, sizeof b, 0) == sizeof b){
+			be2vlong(&t, b);
+			return t;
+		}
+		close(f);
+		if(i < nelem(fds))
+			fds[i].fd = -1;
+	}while(tries++ == 0);	/* retry once */
+	USED(tries);
+	return 0;
 }

+ 44 - 0
sys/src/libc/port/runetype.c

@@ -211,9 +211,14 @@ Rune	_space2[] =
 {
 	0x0009,	0x000a,	/* tab and newline */
 	0x0020,	0x0020,	/* space */
+	0x0085, 0x0085,
 	0x00a0,	0x00a0,	/*   */
+	0x1680, 0x1680,
+	0x180e, 0x180e,
 	0x2000,	0x200b,	/*   - ​ */
 	0x2028,	0x2029,	/* 
 - 
 */
+	0x202f, 0x202f,
+	0x205f, 0x205f,
 	0x3000,	0x3000,	/*   */
 	0xfeff,	0xfeff,	/*  */
 };
@@ -611,6 +616,34 @@ Rune	_toupper1[] =
 	0x1ff3, 509,	/* ῳ ῼ */
 };
 
+static Rune __isdigitr[] = {
+	0x0030, 0x0039,
+	0x0660, 0x0669,
+	0x06f0, 0x06f9,
+	0x07c0, 0x07c9,
+	0x0966, 0x096f,
+	0x09e6, 0x09ef,
+	0x0a66, 0x0a6f,
+	0x0ae6, 0x0aef,
+	0x0b66, 0x0b6f,
+	0x0be6, 0x0bef,
+	0x0c66, 0x0c6f,
+	0x0ce6, 0x0cef,
+	0x0d66, 0x0d6f,
+	0x0e50, 0x0e59,
+	0x0ed0, 0x0ed9,
+	0x0f20, 0x0f29,
+	0x1040, 0x1049,
+	0x17e0, 0x17e9,
+	0x1810, 0x1819,
+	0x1946, 0x194f,
+	0x19d0, 0x19d9,
+	0x1b50, 0x1b59,
+	0xff10, 0xff19,
+	0x104a0, 0x104a9,
+	0x1d7ce, 0x1d7ff,
+};
+
 /*
  * upper case ranges
  *	3rd col is conversion excess 500
@@ -1135,3 +1168,14 @@ isspacerune(Rune c)
 		return 1;
 	return 0;
 }
+
+int
+isdigitrune(Rune c)
+{
+	Rune *p;
+
+	p = bsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
+	if(p && c >= p[0] && c <= p[1])
+		return 1;
+	return 0;
+}

+ 2 - 2
sys/src/libmach/5db.c

@@ -451,10 +451,10 @@ armco(Opcode *o, Instr *i)		/* coprocessor instructions */
 	p = (i->w >> 5) & 0x7;
 	if(i->w&(1<<4)) {
 		op = (i->w >> 21) & 0x07;
-		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+		snprint(buf, sizeof(buf), "#%x, #%x, R%d, C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
 	} else {
 		op = (i->w >> 20) & 0x0f;
-		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x\n", cp, op, i->rd, i->rn, i->rs, p);
+		snprint(buf, sizeof(buf), "#%x, #%x, C(%d), C(%d), C(%d), #%x", cp, op, i->rd, i->rn, i->rs, p);
 	}
 	format(o->o, i, buf);
 }

+ 17 - 6
sys/src/libregexp/regcomp.c

@@ -16,6 +16,12 @@ struct Node
 	Reinst*	last;
 }Node;
 
+/* max character classes per program is nelem(reprog->class) */
+static Reprog	*reprog;
+
+/* max rune ranges per character class is nelem(classp->spans)/2 */
+#define NCCRUNE	nelem(classp->spans)
+
 #define	NSTACK	20
 static	Node	andstack[NSTACK];
 static	Node	*andp;
@@ -322,8 +328,8 @@ dump(Reprog *pp)
 static	Reclass*
 newclass(void)
 {
-	if(nclass >= NCLASS)
-		regerr2("too many character classes; limit", NCLASS+'0');
+	if(nclass >= nelem(reprog->class))
+		rcerror("too many character classes; increase Reprog.class size");
 	return &(classp[nclass++]);
 }
 
@@ -408,7 +414,7 @@ bldcclass(void)
 	}
 
 	/* parse class into a set of spans */
-	for(; ep<&r[NCCRUNE];){
+	while(ep < &r[NCCRUNE-1]){
 		if(rune == 0){
 			rcerror("malformed '[]'");
 			return 0;
@@ -432,6 +438,10 @@ bldcclass(void)
 		}
 		quoted = nextc(&rune);
 	}
+	if(ep >= &r[NCCRUNE-1]) {
+		rcerror("char class too large; increase Reclass.spans size");
+		return 0;
+	}
 
 	/* sort on span start */
 	for(p = r; p < ep; p += 2){
@@ -455,9 +465,10 @@ bldcclass(void)
 		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];
+			/* overlapping or adjacent ranges? */
+			if(p[0] <= np[1] + 1){
+				if(p[1] >= np[1])
+					np[1] = p[1];	/* coalesce */
 			} else {
 				np += 2;
 				np[0] = p[0];

+ 0 - 7
sys/src/libregexp/regcomp.h

@@ -8,13 +8,6 @@ struct	Resublist
 	Resub	m[NSUBEXP];
 };
 
-/* max character classes per program */
-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)
  *

+ 1 - 1
sys/src/libregexp/regsub.c

@@ -28,7 +28,7 @@ regsub(char *sp,	/* source string */
 			case '8':
 			case '9':
 				i = *sp-'0';
-				if(mp[i].sp != 0 && mp!=0 && ms>i)
+				if(mp!=0 && mp[i].sp != 0 && ms>i)
 					for(ssp = mp[i].sp;
 					     ssp < mp[i].ep;
 					     ssp++)