Browse Source

Plan 9 from Bell Labs 2010-07-15

David du Colombier 8 years ago
parent
commit
744915e901

+ 1 - 1
lib/glass

@@ -117,7 +117,7 @@ Hawaiian:  Hiki iaʻu ke ʻai i ke aniani; ʻaʻole nō lā au e ʻeha.
 Marquesan: E koʻana e kai i te karahi, mea ʻā, ʻaʻe hauhau.
 Navajo: Tsésǫʼ yishą́ągo bííníshghah dóó doo shił neezgai da.
 Lojban: mi kakne le nu citka le blaci .iku'i le se go'i na xrani mi
-Nórdicg: Ljœr ye caudran créneþ ý jor cẃran.
+Nórdicg: Ljœr ye caudran créneþ ý jor cẃran.
 Euro Symbol: €.
 Greek: Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα.
 Íslenska / Icelandic: Ég  get etið gler án þess að meiða mig.

+ 18 - 0
rc/bin/ape/cat

@@ -0,0 +1,18 @@
+#!/bin/rc
+
+rfork e
+
+files=()
+while(! ~ $#* 0){
+	switch($1){
+	case -
+		files=($files /fd/0)
+	case -*
+		;
+	case *
+		files=($files $1)
+	}
+	shift
+}
+
+exec /$cputype/bin/cat $files

+ 2 - 0
rc/bin/ape/egrep

@@ -0,0 +1,2 @@
+#!/bin/rc
+exec /rc/bin/ape/grep $*

+ 2 - 0
rc/bin/ape/fgrep

@@ -0,0 +1,2 @@
+#!/bin/rc
+exec /rc/bin/ape/grep $*

+ 21 - 2
rc/bin/ape/grep

@@ -1,3 +1,22 @@
 #!/bin/rc
-# the -G flag is gone!
-exec /$cputype/bin/grep $*
+
+rfork e
+
+opts=()
+files=()
+argv0=$0
+while(! ~ $#* 0){
+	switch($1){
+	case -[cefinsv]
+		opts=($opts $1)
+	case -q
+		opts=($opts -s)
+	case -*
+		echo $argv0 $1 not supported >[2=1]
+		exit 'not supported'
+	case *
+		files=($files $1)
+	}
+	shift
+}
+exec /$cputype/bin/grep $opts $files

+ 23 - 0
rc/bin/ape/ln

@@ -0,0 +1,23 @@
+#!/bin/rc
+
+argv0=$0
+force=n
+while(! ~ $#* 0 && ~ $1 -*){
+	switch($1){
+	case -f
+		force=y
+	case -s
+		;
+	case *
+		echo 'usage: ln [-s] [-f] source destination' >[2=1]
+		exit 'usage'
+	}
+	shift
+}
+
+if(~ $force n && test -e $2){
+	echo ln: $2 destination exists >[2=1]
+	exit 'usage'
+}
+
+exec cp -gux $1 $2

+ 90 - 0
sys/man/8/histogram

@@ -0,0 +1,90 @@
+.TH HISTOGRAM 8
+.SH NAME
+histogram \- draw a histogram
+.SH SYNOPSIS
+.B histogram
+[
+.B -h
+]
+[
+.B -c
+.I index
+]
+[
+.B -r
+.I minx,miny,maxx,maxy
+]
+[
+.B -s
+.I scale
+]
+[
+.B -t
+.I title
+]
+[
+.B -v
+.I maxv
+]
+.SH DESCRIPTION
+.I Histogram
+reads numbers, one per line, from its standard input
+and draws them as bars in a histogram.
+.PP
+Use
+.B -c
+to set the color
+.I index
+for the graph.
+A modulus operation on the value keeps the color index within the available range.
+.PP
+Unless
+.B -h
+.RI ( hold )
+is given,
+.I histogram
+will exit when it reaches the end-of-file.
+It will exit immediately if it is interrupted
+or if the
+.I exit
+menu option is chosen.
+.PP
+.B -r
+sets the initial window
+.I rectangle
+coordinates.
+.PP
+.B -s
+sets the
+.I scaling
+factor.
+.PP
+.B -t
+sets the
+.I title
+displayed on a line above the histogram.
+The last value read is displayed to the right of the title.
+.PP
+.B -v
+sets the maximum
+.I value
+that can be expected.
+.SH EXAMPLE
+Plot a sine wave:
+.IP
+.EX
+hoc -e 'for(i=0.0;i<20*PI;i=i+0.1) print (10+10*sin(i)), "\\n"'|
+	histogram -t 'sin(t), 0 ≤ t ≤ 20π' -v 20 -h
+.EE
+.PP
+Show the Dow Jones adjusted daily closing price back to January 1, 2000:
+.IP
+.EX
+site=http://ichart.finance.yahoo.com
+hget $site'/table.csv?s=^DJI&a=00&b=1&c=2000' |
+	awk -F, '{print $NF}' | histogram -t DJI -v 15000 -h
+.EE
+.SH SOURCE
+.B /sys/src/cmd/histogram.c
+.SH SEE ALSO
+.IR statusbar (8)

+ 2 - 0
sys/src/ape/lib/ap/stdio/vfscanf.c

@@ -293,6 +293,7 @@ static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
 	nn=0;
 	while(!isspace(c)){
 		if(c==EOF){
+			nread--;
 			if(nn==0) return 0;
 			else goto Done;
 		}
@@ -351,6 +352,7 @@ static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
 	for(;;){
 		wgetc(c, f, Done);
 		if(c==EOF){
+			nread--;
 			if(nn==0) return 0;
 			else goto Done;
 		}

+ 33 - 12
sys/src/cmd/disk/9660/boot.c

@@ -145,10 +145,15 @@ Cputbootcat(Cdimg *cd)
 	Cpadblock(cd);
 }
 
+enum {
+	Emusectsz	= 512,		/* bytes per emulated sector */
+};
+
 void
 Cupdatebootcat(Cdimg *cd)
 {
 	uvlong o;
+	int n;
 
 	if(cd->bootdirec == nil)
 		return;
@@ -156,22 +161,38 @@ Cupdatebootcat(Cdimg *cd)
 	o = Cwoffset(cd);
 	Cwseek(cd, cd->bootimageptr);
 	Cputc(cd, 0x88);
-	switch(cd->bootdirec->length){
-	default:
-		fprint(2, "warning: boot image is not 1.44MB or 2.88MB; pretending 1.44MB\n");
-	case 1440*1024:
-		Cputc(cd, 0x02);	/* 1.44MB disk */
-		break;
-	case 2880*1024:
-		Cputc(cd, 0x03);	/* 2.88MB disk */
-		break;
-	}
+
+	if(cd->flags & CDbootnoemu)
+		Cputc(cd, 0);			/* no disk emulation */
+	else
+		switch(cd->bootdirec->length){
+		default:
+			fprint(2, "warning: boot image is not 1.44MB or 2.88MB; "
+				"pretending 1.44MB\n");
+			/* fall through */
+		case 1440*1024:
+			Cputc(cd, 0x02);	/* 1.44MB disk */
+			break;
+		case 2880*1024:
+			Cputc(cd, 0x03);	/* 2.88MB disk */
+			break;
+		}
 	Cputnl(cd, 0, 2);	/* load segment */
 	Cputc(cd, 0);	/* system type */
 	Cputc(cd, 0);	/* unused */
-	Cputnl(cd, 1, 2);	/* 512-byte sector count for load */
+
+	n = 1;
+	if(cd->flags & CDbootnoemu){
+		n = (cd->bootdirec->length + Emusectsz - 1) / Emusectsz;
+		if(n > 4){
+			fprint(2, "warning: boot image too big; "
+				"will only load the first 2K\n");
+			n = 4;
+		}
+	}
+	Cputnl(cd, n, 2);	/* Emusectsz-byte sector count for load */
 	Cputnl(cd, cd->bootdirec->block, 4);	/* ptr to disk image */
-	Cwseek(cd, o);	
+	Cwseek(cd, o);
 }
 
 void

+ 1 - 1
sys/src/cmd/disk/9660/cdrdwr.c

@@ -44,7 +44,7 @@ createcd(char *file, Cdinfo info)
 	Cputisopvd(cd, info);
 	if(info.flags & CDbootable){
 		cd->bootimage = info.bootimage;
-		cd->flags |= CDbootable;
+		cd->flags |= info.flags & (CDbootable|CDbootnoemu);
 		Cputbootvol(cd);
 	}
 

+ 3 - 0
sys/src/cmd/disk/9660/dump9660.c

@@ -77,6 +77,9 @@ main(int argc, char **argv)
 	case 'a':
 		doabort = 1;
 		break;
+	case 'B':
+		info.flags |= CDbootnoemu;
+		/* fall through */
 	case 'b':
 		if(!mk9660)
 			usage();

+ 1 - 0
sys/src/cmd/disk/9660/iso9660.h

@@ -133,6 +133,7 @@ enum {	/* Cdimg->flags, Cdinfo->flags */
 	CDnew = 1<<4,
 	CDdump = 1<<5,
 	CDbootable = 1<<6,
+	CDbootnoemu = 1<<7,
 };
 
 typedef struct Tx Tx;

+ 314 - 0
sys/src/cmd/histogram.c

@@ -0,0 +1,314 @@
+#include <u.h>
+#include <libc.h>
+#include <draw.h>
+#include <bio.h>
+#include <thread.h>
+#include <mouse.h>
+#include <keyboard.h>
+
+enum {
+	STACK 	= 8*1024,
+
+	Dot	= 2,	/* height of dot */
+	Lx	= 4,	/* x offset */
+	Ly	= 4,	/* y offset */
+	Bw	= 2,	/* border width */
+};
+
+Image *neutral;
+Image *light;
+Image *dark;
+Image *txtcolor;
+
+char *title = "histogram";
+Rectangle hrect;
+Point maxvloc;
+double *data;
+double vmax = 100, scale = 1.0;
+uint nval;
+int dontdie = 0, col = 1;
+
+int colors[][3] = {
+	{ 0xFFAAAAFF,	0xFFAAAAFF,	0xBB5D5DFF },		/* Peach */
+	{ DPalebluegreen, DPalegreygreen, DPurpleblue },	/* Aqua */
+	{ DPaleyellow,	DDarkyellow,	DYellowgreen },		/* Yellow */
+	{ DPalegreen,	DMedgreen,	DDarkgreen },		/* Green */
+	{ 0x00AAFFFF,	0x00AAFFFF,	0x0088CCFF },		/* Blue */
+	{ 0xEEEEEEFF,	0xCCCCCCFF,	0x888888F },		/* Grey */
+};
+
+void
+initcolor(int i)
+{
+	neutral = allocimagemix(display, colors[i][0], DWhite);
+	light = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][1]);
+	dark  = allocimage(display, Rect(0,0,1,1), CMAP8, 1, colors[i][2]);
+	txtcolor = display->black;
+}
+
+void*
+erealloc(void *v, ulong sz)
+{
+	v = realloc(v, sz);
+	if(v == nil){
+		sysfatal("realloc: %r");
+		threadexitsall("memory");
+	}
+	return v;
+}
+
+Point
+datapoint(int x, double v)
+{
+	Point p;
+	double y;
+
+	p.x = x;
+	y = (v*scale) / vmax;
+	p.y = hrect.max.y - Dy(hrect)*y - Dot;
+	if(p.y < hrect.min.y)
+		p.y = hrect.min.y;
+	if(p.y > hrect.max.y - Dot)
+		p.y = hrect.max.y - Dot;
+	return p;
+}
+
+void
+drawdatum(int x, double prev, double v)
+{
+	Point p, q;
+
+	p = datapoint(x, v);
+	q = datapoint(x, prev);
+	if(p.y < q.y){
+		draw(screen, Rect(p.x, hrect.min.y, p.x+1, p.y), neutral,
+			nil, ZP);
+		draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), dark, nil, ZP);
+		draw(screen, Rect(p.x, q.y+Dot, p.x+1, hrect.max.y), light,
+			nil, ZP);
+	}else{
+		draw(screen, Rect(p.x, hrect.min.y, p.x+1, q.y), neutral,
+			nil, ZP);
+		draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), dark, nil, ZP);
+		draw(screen, Rect(p.x, p.y+Dot, p.x+1, hrect.max.y), light,
+			nil, ZP);
+	}
+
+}
+
+void
+updatehistogram(double v)
+{
+	char buf[32];
+
+	draw(screen, hrect, screen, nil, Pt(hrect.min.x+1, hrect.min.y));
+	if(v * scale > vmax)
+		v = vmax / scale;
+	drawdatum(hrect.max.x-1, data[0], v);
+	memmove(&data[1], &data[0], (nval-1) * sizeof data[0]);
+	data[0] = v;
+	snprint(buf, sizeof buf, "%0.9f", v);
+	stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf,
+		neutral, ZP);
+	flushimage(display, 1);
+}
+
+void
+redrawhistogram(int new)
+{
+	Point p, q;
+	Rectangle r;
+	uint onval = nval;
+	int i;
+	char buf[32];
+
+	if(new && getwindow(display, Refnone) < 0)
+		sysfatal("getwindow: %r");
+
+	r = screen->r;
+	draw(screen, r, neutral, nil, ZP);
+	p = string(screen, addpt(r.min, Pt(Lx, Ly)), txtcolor, ZP,
+		display->defaultfont, title);
+
+	p.x = r.min.x + Lx;
+	p.y += display->defaultfont->height + Ly;
+
+	q = subpt(r.max, Pt(Lx, Ly));
+	hrect = Rpt(p, q);
+
+	maxvloc = Pt(r.max.x - Lx - stringwidth(display->defaultfont,
+		"999999999"), r.min.y + Ly);
+
+	nval = abs(Dx(hrect));
+	if(nval != onval){
+		data = erealloc(data, nval * sizeof data[0]);
+		if(nval > onval)
+			memset(data+onval, 0, (nval - onval) * sizeof data[0]);
+	}
+
+	border(screen, hrect, -Bw, dark, ZP);
+	snprint(buf, sizeof buf, "%0.9f", data[0]);
+	stringbg(screen, maxvloc, txtcolor, ZP, display->defaultfont, buf,
+		neutral, ZP);
+	draw(screen, hrect, neutral, nil, ZP);
+	for(i = 1; i < nval - 1; i++)
+		drawdatum(hrect.max.x - i, data[i-1], data[i]);
+	drawdatum(hrect.min.x, data[i], data[i]);
+	flushimage(display, 1);
+}
+
+void
+reader(void *arg)
+{
+	int fd;
+	double v;
+	char *p, *f[2];
+	uchar buf[512];
+	Biobufhdr b;
+	Channel *c = arg;
+
+	threadsetname("reader");
+	fd = dup(0, -1);
+	Binits(&b, fd, OREAD, buf, sizeof buf);
+
+	while((p = Brdline(&b, '\n')) != nil) {
+		p[Blinelen(&b) - 1] = '\0';
+		if(tokenize(p, f, 1) != 1)
+			continue;
+		v = strtod(f[0], 0);
+		send(c, &v);
+	}
+	if(!dontdie)
+		threadexitsall(nil);
+}
+
+
+void
+histogram(char *rect)
+{
+	int rm;
+	double dm;
+	Channel *dc;
+	Keyboardctl *kc;
+	Mouse mm;
+	Mousectl *mc;
+	Rune km;
+	Alt a[] = {
+		/* c	v	op */
+		{nil,	&dm,	CHANRCV},	/* data from stdin */
+		{nil,	&mm,	CHANRCV},	/* mouse message */
+		{nil,	&km,	CHANRCV},	/* keyboard runes */
+		{nil,	&rm,	CHANRCV},	/* resize event */
+		{nil,	nil,	CHANEND},
+	};
+	static char *mitems[] = {
+		"exit",
+		nil
+	};
+	static Menu menu = {
+		mitems,
+		nil,
+		-1
+	};
+
+	memset(&mm, 0, sizeof mm);
+	memset(&km, 0, sizeof km);
+	dm = rm = 0;
+
+	if(newwindow(rect) < 0)
+		sysfatal("newwindow: %r");
+	if(initdraw(nil, nil, "histogram") < 0)
+		sysfatal("initdraw: %r");
+
+	initcolor(col);
+
+	mc = initmouse(nil, screen);
+	if(!mc)
+		sysfatal("initmouse: %r");
+	kc = initkeyboard(nil);
+	if(!kc)
+		sysfatal("initkeyboard: %r");
+
+	dc = chancreate(sizeof dm, 10);
+	if(!dc)
+		sysfatal("chancreate: %r");
+
+	a[0].c = dc;
+	a[1].c = mc->c;
+	a[2].c = kc->c;
+	a[3].c = mc->resizec;
+
+	proccreate(reader, a[0].c, STACK + sizeof(Biobuf));
+
+	redrawhistogram(0);
+	for(;;)
+		switch(alt(a)){
+		case 0:
+			updatehistogram(dm);
+			break;
+		case 1:
+			if(mm.buttons & 4 && menuhit(3, mc, &menu, nil) == 0)
+				goto done;
+			break;
+		case 2:
+			if(km == 0x7F)
+				goto done;
+			break;
+		case 3:
+			redrawhistogram(1);
+			break;
+		default:
+			sysfatal("shouldn't happen");
+		}
+done:
+	closekeyboard(kc);
+	closemouse(mc);
+	chanfree(a[0].c);
+	threadexitsall(nil);
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: histogram [-h] [-c index] [-r minx,miny,maxx,maxy] "
+		"[-s scale] [-t title] [-v maxv]\n");
+	exits("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	char *p, *q;
+
+	p = "-r 0,0,400,150";
+
+	ARGBEGIN{
+	case 'v':
+		vmax = strtod(EARGF(usage()), 0);
+		break;
+	case 'r':
+		p = smprint("-r %s", EARGF(usage()));
+		break;
+	case 's':
+		scale = strtod(EARGF(usage()), 0);
+		if(scale <= 0)
+			usage();
+		break;
+	case 'h':
+		dontdie = 1;
+		break;
+	case 't':
+		title = EARGF(usage());
+		break;
+	case 'c':
+		col = atoi(EARGF(usage())) % nelem(colors);
+		break;
+	default:
+		usage();
+	}ARGEND;
+
+	while((q = strchr(p, ',')) != nil)
+		*q = ' ';
+
+	histogram(p);
+}

+ 4 - 2
sys/src/cmd/ip/snoopy/aoe.c

@@ -26,13 +26,15 @@ enum{
 static Mux p_mux[] = {
 	{"aoeata",	0},
 	{"aoecmd",	1},
+	{"aoemask",	2},
+	{"aoerr",	3},
 	{0},
 };
 
 static Field p_fields[] =
 {
-	{"slot",	Fnum,	Ominor,		"shelf",	},
-	{"shelf",	Fnum,	Omajor,		"slot",	},
+	{"shelf",	Fnum,	Ominor,		"shelf", },
+	{"slot",	Fnum,	Omajor,		"slot",	},
 	{"cmd",		Fnum,	Ocmd,		"cmd",	},
 	{0}
 };

+ 122 - 0
sys/src/cmd/ip/snoopy/aoemask.c

@@ -0,0 +1,122 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include "dat.h"
+#include "protos.h"
+
+typedef struct {
+	uchar	res;
+	uchar	cmd;
+	uchar	err;
+	uchar	cnt;
+} Hdr;
+
+enum {
+	Ocmd,
+	Oerr,
+	Ocnt,
+
+	Hsize	= 4,
+};
+
+static Field p_fields[] =
+{
+	{ "cmd",	Fnum,	Ocmd,	"command", },
+	{ "err",	Fnum,	Oerr,	"error", },
+	{ "cnt",	Fnum,	Ocnt,	"count", },
+	nil
+};
+
+static Mux p_mux[] = {
+	{ "aoemd",	0 },
+	{ "aoemd",	1 },
+	nil
+};
+
+static void
+p_compile(Filter *f)
+{
+	Mux *m;
+
+	if(f->op == '='){
+		compile_cmp(aoerr.name, f, p_fields);
+		return;
+	}
+	for(m = p_mux; m->name; m++)
+		if(strcmp(f->s, m->name) == 0){
+			f->pr = m->pr;
+			f->ulv = m->val;
+			f->subop = Ocmd;
+			return;
+		}
+	sysfatal("unknown aoemask field: %s", f->s);
+}
+
+static int
+p_filter(Filter *f, Msg *m)
+{
+	Hdr *h;
+
+	if(m->pe - m->ps < Hsize)
+		return 0;
+
+	h = (Hdr*)m->ps;
+	m->ps += Hsize;
+
+	switch(f->subop){
+	case Ocmd:
+		return h->cmd == f->ulv;
+	case Oerr:
+		return h->err == f->ulv;
+	case Ocnt:
+		return h->cnt == f->ulv;
+	}
+	return 0;
+}
+
+static char *ctab[] = {
+	"read",
+	"edit",
+};
+
+static char *etab[] = {
+	"",
+	"bad",
+	"full",
+};
+
+static int
+p_seprint(Msg *m)
+{
+	char *s, *t;
+	Hdr *h;
+
+	if(m->pe - m->ps < Hsize)
+		return 0;
+
+	h = (Hdr*)m->ps;
+	m->ps += Hsize;
+
+	demux(p_mux, h->cmd, h->cmd, m, &dump);
+
+	s = "unk";
+	if(h->cmd < nelem(ctab))
+		s = ctab[h->cmd];
+	t = "unk";
+	if(h->err < nelem(etab))
+		s = etab[h->err];
+	m->p = seprint(m->p, m->e, "cmd=%d %s err=%d %s cnt=%d\n",
+		h->cmd, s, h->err, t, h->cnt);
+	return 0;
+}
+
+Proto aoemask = {
+	"aoemask",
+	p_compile,
+	p_filter,
+	p_seprint,
+	p_mux,
+	"%lud",
+	p_fields,
+	defaultframer,
+};

+ 97 - 0
sys/src/cmd/ip/snoopy/aoemd.c

@@ -0,0 +1,97 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include "dat.h"
+#include "protos.h"
+
+typedef struct {
+	uchar	res;
+	uchar	cmd;
+	uchar	ea[6];
+} Hdr;
+
+enum {
+	Ocmd,
+	Oea,
+
+	Hsize	= 8,
+};
+
+static Field p_fields[] = {
+	{"cmd",	Fnum,	Ocmd,	"command",	},
+	{"ea",	Fnum,	Oea,	"ethernet addr", },
+	nil
+};
+
+static void
+p_compile(Filter *f)
+{
+	if(f->op == '='){
+		compile_cmp(aoemd.name, f, p_fields);
+		return;
+	}
+	sysfatal("unknown aoemd field: %s", f->s);
+}
+
+static int
+p_filter(Filter *f, Msg *m)
+{
+	uchar buf[6];
+	int i;
+	Hdr *h;
+
+	if(m->pe - m->ps < Hsize)
+		return 0;
+
+	h = (Hdr*)m->ps;
+	m->ps += Hsize;
+
+	switch(f->subop){
+	case Ocmd:
+		return h->cmd == f->ulv;
+	case Oea:
+		for(i = 0; i < 6; i++)
+			buf[i] = f->ulv >> ((5 - i)*8);
+		return memcmp(buf, h->ea, 6) == 0;
+	}
+	return 0;
+}
+
+static char *ctab[] = {
+	"  ",
+	" +",
+	" -",
+};
+
+static int
+p_seprint(Msg *m)
+{
+	char *s;
+	Hdr *h;
+
+	if(m->pe - m->ps < Hsize)
+		return 0;
+
+	h = (Hdr*)m->ps;
+	m->ps += Hsize;
+
+	/* no next protocol */
+	m->pr = nil;
+
+	s = "unk";
+	if(h->cmd < nelem(ctab))
+		s = ctab[h->cmd];
+	m->p = seprint(m->p, m->e, "cmd=%d%s ea=%E\n", h->cmd, s, h->ea);
+	return 0;
+}
+
+Proto aoemd = {
+	"aoemd",
+	p_compile,
+	p_filter,
+	p_seprint,
+	nil,
+	nil,
+	p_fields,
+	defaultframer,
+};

+ 120 - 0
sys/src/cmd/ip/snoopy/aoerr.c

@@ -0,0 +1,120 @@
+#include <u.h>
+#include <libc.h>
+#include <ip.h>
+#include "dat.h"
+#include "protos.h"
+
+typedef struct {
+	uchar	cmd;
+	uchar	nea;
+} Hdr;
+
+enum {
+	Ocmd,
+	Onea,
+	Oea,
+
+	Hsize	= 2,
+};
+
+static Field p_fields[] = {
+	{"cmd",	Fnum,	Ocmd,	"command",	},
+	{"nea",	Fnum,	Onea,	"ea count",	},
+	{"ea",	Fnum,	Onea,	"ethernet addr", },
+	nil
+};
+
+static void
+p_compile(Filter *f)
+{
+	if(f->op == '='){
+		compile_cmp(aoerr.name, f, p_fields);
+		return;
+	}
+	sysfatal("unknown aoerr field: %s", f->s);
+}
+
+static int
+p_filter(Filter *f, Msg *m)
+{
+	uchar buf[6];
+	int i;
+	Hdr *h;
+
+	if(m->pe - m->ps < Hsize)
+		return 0;
+
+	h = (Hdr*)m->ps;
+	m->ps += Hsize;
+
+	switch(f->subop){
+	case Ocmd:
+		return h->cmd == f->ulv;
+	case Onea:
+		return h->nea == f->ulv;
+	case Oea:
+		if(m->pe - m->ps < 6*h->nea)
+			return 0;
+		for(i = 0; i < 6; i++)
+			buf[i] = f->ulv >> ((5 - i)*8);
+		for(i = 0; i < h->nea; i++)
+			if(memcmp(m->ps + 6*i, buf, 6) == 0)
+				return 1;
+		return 0;
+	}
+	return 0;
+}
+
+static char *ctab[] = {
+	"read",
+	"write",
+	"force",
+};
+
+static int
+p_seprint(Msg *m)
+{
+	char *s;
+	int i;
+	Hdr *h;
+
+	if(m->pe - m->ps < Hsize)
+		return 0;
+
+	h = (Hdr*)m->ps;
+	m->ps += Hsize;
+
+	/* no next protocol */
+	m->pr = nil;
+
+	s = "unk";
+	if(h->cmd < nelem(ctab))
+		s = ctab[h->cmd];
+	m->p = seprint(m->p, m->e, "cmd=%d %s nea=%d", h->cmd, s, h->nea);
+	for(i = 0;; i++){
+		if(h->nea < i)
+			break;
+		if(i == 3){
+			m->p = seprint(m->p, m->e, " ...");
+			break;
+		}
+		if(m->pe - m->ps < 6*i){
+			m->p = seprint(m->p, m->e, " *short*");
+			break;
+		}
+		m->p = seprint(m->p, m->e, " %E", m->pe + 6*i);
+	}
+	m->p = seprint(m->p, m->e, "\n");
+	return 0;
+}
+
+Proto aoerr = {
+	"aoerr",
+	p_compile,
+	p_filter,
+	p_seprint,
+	nil,
+	nil,
+	p_fields,
+	defaultframer,
+};

+ 3 - 0
sys/src/cmd/ip/snoopy/mkfile

@@ -5,6 +5,9 @@ PROTOS=\
 	aoe\
 	aoeata\
 	aoecmd\
+	aoemask\
+	aoemd\
+	aoerr\
 	arp\
 	bootp\
 	cec\

+ 2 - 0
sys/src/cmd/tcs/conv.h

@@ -9,6 +9,8 @@ void big5_in(int fd, long *notused, struct convert *out);
 void big5_out(Rune *base, int n, long *notused);
 void gb_in(int fd, long *notused, struct convert *out);
 void gb_out(Rune *base, int n, long *notused);
+void gbk_in(int fd, long *notused, struct convert *out);
+void gbk_out(Rune *base, int n, long *notused);
 void uksc_in(int fd, long *notused, struct convert *out);
 void uksc_out(Rune *base, int n, long *notused);
 void html_in(int fd, long *notused, struct convert *out);

File diff suppressed because it is too large
+ 4006 - 0
sys/src/cmd/tcs/gbk.c


+ 4 - 0
sys/src/cmd/tcs/gbk.h

@@ -0,0 +1,4 @@
+#define GBKMIN 0x8140
+#define GBKMAX 0xFE50
+
+extern long tabgbk[];

+ 2 - 0
sys/src/cmd/tcs/mkfile

@@ -5,11 +5,13 @@ OFILES=tcs.$O\
 	conv_jis.$O\
 	conv_big5.$O\
 	conv_gb.$O\
+	conv_gbk.$O\
 	conv_ksc.$O\
 	utf.$O\
 	html.$O\
 	kuten208.$O\
 	gb.$O\
+	gbk.$O\
 	ksc.$O\
 	big5.$O\
 	tune.$O

+ 2 - 0
sys/src/cmd/tcs/tcs.c

@@ -505,6 +505,8 @@ struct convert convert[] =
 	{ "euc-k", "Korean EUC: ASCII+KS C 5601 1987", Func, 0, (Fnptr)uksc_out },
 	{ "gb2312", "GB2312-80 (Chinese)", From|Func, 0, (Fnptr)gb_in },
 	{ "gb2312", "GB2312-80 (Chinese)", Func, 0, (Fnptr)gb_out },
+	{ "gbk", "GBK (Chinese)", From|Func, 0, (Fnptr)gbk_in },
+	{ "gbk", "GBK (Chinese)", Func, 0, (Fnptr)gbk_out },
 	{ "html", "HTML", From|Func, 0, (Fnptr)html_in },
 	{ "html", "HTML", Func, 0, (Fnptr)html_out },
 	{ "ibm437", "IBM Code Page 437 (US)", Table, (void*)tabcp437 },

+ 2 - 0
sys/src/libstdio/vfscanf.c

@@ -290,6 +290,7 @@ static int icvt_s(FILE *f, va_list *args, int store, int width, int type){
 	nn=0;
 	while(!isspace(c)){
 		if(c==EOF){
+			nread--;
 			if(nn==0) return 0;
 			else goto Done;
 		}
@@ -348,6 +349,7 @@ static int icvt_sq(FILE *f, va_list *args, int store, int width, int type){
 	for(;;){
 		wgetc(c, f, Done);
 		if(c==EOF){
+			nread--;
 			if(nn==0) return 0;
 			else goto Done;
 		}