Browse Source

Plan 9 from Bell Labs 2004-03-23

David du Colombier 20 years ago
parent
commit
5668ef3d18

+ 10 - 7
dist/replica/plan9.db

@@ -2974,7 +2974,7 @@ power/mkfile - 664 sys sys 948141304 46
 rc - 20000000775 sys sys 944959447 0
 rc/bin - 20000000775 sys sys 1018637942 0
 rc/bin/9fat: - 775 sys sys 1015089559 354
-rc/bin/9fs - 775 sys sys 1042305252 869
+rc/bin/9fs - 775 sys sys 1079969823 948
 rc/bin/B - 775 sys sys 945617206 645
 rc/bin/C - 775 sys sys 1045493437 788
 rc/bin/Kill - 775 sys sys 1018637942 115
@@ -3030,7 +3030,7 @@ rc/bin/mousereset - 775 sys sys 1015089542 37
 rc/bin/nroff - 775 sys sys 945617208 27
 rc/bin/patch - 20000000775 sys sys 1067803227 0
 rc/bin/patch/apply - 775 sys sys 1067804403 1234
-rc/bin/patch/create - 775 sys sys 1067804404 1129
+rc/bin/patch/create - 775 sys sys 1079969485 1126
 rc/bin/patch/diff - 775 sys sys 1067804404 466
 rc/bin/patch/list - 775 sys sys 1067804541 321
 rc/bin/patch/note - 664 sys sys 1067804405 593
@@ -4650,7 +4650,7 @@ sys/man/1/diff - 664 sys sys 969499884 2793
 sys/man/1/doc2txt - 664 sys sys 954089516 1095
 sys/man/1/doctype - 664 sys sys 944959673 849
 sys/man/1/du - 664 sys sys 1017166323 1410
-sys/man/1/echo - 664 sys sys 944959673 279
+sys/man/1/echo - 664 sys sys 1079969656 430
 sys/man/1/ed - 664 sys sys 961259286 13916
 sys/man/1/emacs - 664 sys sys 944959673 199
 sys/man/1/eqn - 664 sys sys 944959675 5655
@@ -4675,7 +4675,7 @@ sys/man/1/hoc - 664 sys sys 944959676 2357
 sys/man/1/idiff - 664 sys sys 1018386774 927
 sys/man/1/join - 664 sys sys 957920006 2562
 sys/man/1/jpg - 664 sys sys 1074280543 4758
-sys/man/1/kbmap - 664 sys sys 1079545417 841
+sys/man/1/kbmap - 664 sys sys 1079969760 845
 sys/man/1/kill - 664 sys sys 1018369246 1193
 sys/man/1/ktrace - 664 sys sys 957920006 1330
 sys/man/1/leak - 664 sys sys 1017423522 2871
@@ -4686,7 +4686,7 @@ sys/man/1/lp - 664 sys sys 1015024739 3304
 sys/man/1/ls - 664 sys sys 1079372922 2897
 sys/man/1/mail - 664 sys sys 1050078464 2158
 sys/man/1/man - 664 sys sys 1059484724 1740
-sys/man/1/marshal - 664 sys sys 1050078464 3307
+sys/man/1/marshal - 664 sys sys 1079970326 3150
 sys/man/1/mc - 664 sys sys 1045501392 508
 sys/man/1/mk - 664 sys sys 964455061 13154
 sys/man/1/mkdir - 664 sys sys 944959673 443
@@ -9560,17 +9560,20 @@ sys/src/cmd/ip/traceroute.c - 664 sys sys 1032060124 9370
 sys/src/cmd/ip/udpecho.c - 664 sys sys 1050714674 855
 sys/src/cmd/join.c - 664 sys sys 944961364 7488
 sys/src/cmd/jpg - 20000000775 sys sys 988249983 0
+sys/src/cmd/jpg/bmp.c - 664 sys sys 1079970078 4217
+sys/src/cmd/jpg/bmp.h - 664 sys sys 1079970081 975
 sys/src/cmd/jpg/close.c - 664 sys sys 944961292 1930
 sys/src/cmd/jpg/gif.c - 664 sys sys 1045505400 8844
 sys/src/cmd/jpg/ico.c - 664 sys sys 1072107030 8799
 sys/src/cmd/jpg/imagefile.h - 664 sys sys 988225303 2246
 sys/src/cmd/jpg/jpegdump.c - 664 sys sys 1018802871 7161
 sys/src/cmd/jpg/jpg.c - 664 sys sys 1014926432 7389
-sys/src/cmd/jpg/mkfile - 664 sys sys 1072107030 1014
+sys/src/cmd/jpg/mkfile - 664 sys sys 1079970080 1056
 sys/src/cmd/jpg/multichan.c - 664 sys sys 1039753047 825
 sys/src/cmd/jpg/onechan.c - 664 sys sys 1039753044 3732
 sys/src/cmd/jpg/png.c - 664 sys sys 1014926432 4655
 sys/src/cmd/jpg/ppm.c - 664 sys sys 944961292 4190
+sys/src/cmd/jpg/readbmp.c - 664 sys sys 1079970079 13697
 sys/src/cmd/jpg/readgif.c - 664 sys sys 1014926433 10306
 sys/src/cmd/jpg/readjpg.c - 664 sys sys 1032060302 33009
 sys/src/cmd/jpg/readpng.c - 664 sys sys 1068773222 6914
@@ -11171,7 +11174,7 @@ sys/src/cmd/wikifs/io.c - 664 sys sys 1018387004 11469
 sys/src/cmd/wikifs/lookup.c - 664 sys sys 1018211093 182
 sys/src/cmd/wikifs/map.c - 664 sys sys 1018211093 109
 sys/src/cmd/wikifs/mkfile - 664 sys sys 1045503591 468
-sys/src/cmd/wikifs/parse.c - 664 sys sys 1018211093 4929
+sys/src/cmd/wikifs/parse.c - 664 sys sys 1079969446 4989
 sys/src/cmd/wikifs/parsehist.c - 664 sys sys 1018211093 1906
 sys/src/cmd/wikifs/testwrite.c - 664 sys sys 1018211093 818
 sys/src/cmd/wikifs/tohtml.c - 664 sys sys 1079380577 13998

+ 10 - 0
dist/replica/plan9.log

@@ -14714,3 +14714,13 @@
 1079811022 0 c sys/src/cmd/vnc/kbds.c - 664 sys sys 1079809881 3256
 1079877634 0 c sys/src/cmd/ramfs.c - 664 sys sys 1079877660 15377
 1079919045 0 c sys/src/cmd/ndb/dn.c - 664 sys sys 1079918815 26961
+1079969469 0 c rc/bin/patch/create - 775 sys sys 1079969485 1126
+1079969469 1 c sys/src/cmd/wikifs/parse.c - 664 sys sys 1079969446 4989
+1079971270 0 c rc/bin/9fs - 775 sys sys 1079969823 948
+1079971270 1 c sys/man/1/echo - 664 sys sys 1079969656 430
+1079971270 2 c sys/man/1/kbmap - 664 sys sys 1079969760 845
+1079971270 3 c sys/man/1/marshal - 664 sys sys 1079970326 3150
+1079971270 4 a sys/src/cmd/jpg/bmp.c - 664 sys sys 1079970078 4217
+1079971270 5 a sys/src/cmd/jpg/bmp.h - 664 sys sys 1079970081 975
+1079971270 6 c sys/src/cmd/jpg/mkfile - 664 sys sys 1079970080 1056
+1079971270 7 a sys/src/cmd/jpg/readbmp.c - 664 sys sys 1079970079 13697

+ 3 - 0
rc/bin/9fs

@@ -27,6 +27,9 @@ case sourcesdump
 case sourcessnap
 	9fs sources
 	mount /srv/sources /n/sourcessnap main/snapshot
+case wiki
+	srv 'net!plan9.bell-labs.com!wiki' wiki	
+	mount /srv/wiki /mnt/wiki
 case *
 	switch($#*){
 	case 1

+ 1 - 1
rc/bin/patch/create

@@ -17,7 +17,7 @@ if(! test -d /n/sources/patch){
 
 d=/n/sources/patch/$1
 if(! mkdir $d){
-	echo mkdir $d/$1 failed >[1=2]
+	echo mkdir $d failed >[1=2]
 	exit mkdir
 }
 

+ 6 - 0
sys/man/1/echo

@@ -18,3 +18,9 @@ Option
 suppresses the newline.
 .SH SOURCE
 .B /sys/src/cmd/echo.c
+.SH DIAGNOSTICS
+If
+.I echo
+draws an error while writing to standard output, the exit status is
+.LR "write error" .
+Otherwise the exit status is empty.

+ 4 - 4
sys/man/1/kbmap

@@ -8,15 +8,15 @@ kbmap \- show a list of available keyboard maps and switch between them.
 ]
 .SH DESCRIPTION
 .I Kbmap
-shows a single column consisting of the names keyboard maps for different
+shows a single column consisting of the names of keyboard maps for different
 alphabets available on the system. With no arguments 
 .B kbmap
 will look for files in 
-.B /lib/kbmap/.
+.BR /sys/lib/kbmap .
 .PP
-Clicking the right mouse button will highlight the name and force the
+Clicking the right mouse button will highlight the entry and force the
 keyboard mapping defined in the corresponding file to become current
-one for the system.  Typing 'q' quits.
+for the system; typing 'q' quits.
 .PP
 .I Kbmap
 requires that the file

+ 0 - 9
sys/man/1/marshal

@@ -136,15 +136,6 @@ are all passed as command line options to the
 that
 .I marshal
 invokes.
-.TP
-.BI -C recipient
-specifies that a copy of the mail should also be sent to
-.I recipient
-and that
-.I recipient
-should be included in a
-.B CC:
-header line.
 .PD
 .PP
 .I Marshal

+ 210 - 0
sys/src/cmd/jpg/bmp.c

@@ -0,0 +1,210 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include "imagefile.h"
+
+int		cflag = 0;
+int		dflag = 0;
+int		eflag = 0;
+int		nineflag = 0;
+int		threeflag = 0;
+int		output = 0;
+ulong		outchan = CMAP8;
+int		defaultcolor = 1;
+Image		*image;
+
+enum{
+	Border	= 2,
+	Edge	= 5
+};
+
+char	*show(int, char*);
+
+Rawimage** readbmp(int fd, int colorspace);
+
+void
+eresized(int new)
+{
+	Rectangle r;
+
+	if(new && getwindow(display, Refnone) < 0){
+		fprint(2, "bmp: can't reattach to window\n");
+		exits("resize");
+	}
+	if(image == nil)
+		return;
+	r = insetrect(screen->clipr, Edge+Border);
+	r.max.x = r.min.x+Dx(image->r);
+	r.max.y = r.min.y+Dy(image->r);
+	border(screen, r, -Border, nil, ZP);
+	draw(screen, r, image, nil, image->r.min);
+	flushimage(display, 1);
+}
+
+void
+main(int argc, char *argv[])
+{
+	int fd, i;
+	char *err;
+
+	ARGBEGIN{
+	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */
+		threeflag++;
+		/* fall through */
+	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */
+		cflag++;
+		dflag++;
+		output++;
+		defaultcolor = 0;
+		outchan = RGB24;
+		break;
+	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */
+		cflag++;
+		dflag++;
+		output++;
+		if(defaultcolor)
+			outchan = CMAP8;
+		break;
+	case 'd':		/* suppress display of image */
+		dflag++;
+		break;
+	case 'e':		/* disable floyd-steinberg error diffusion */
+		eflag++;
+		break;
+	case 'k':		/* force black and white */
+		defaultcolor = 0;
+		outchan = GREY8;
+		break;
+	case 'v':		/* force RGBV */
+		defaultcolor = 0;
+		outchan = CMAP8;
+		break;
+	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */
+		nineflag++;
+		dflag++;
+		output++;
+		if(defaultcolor)
+			outchan = CMAP8;
+		break;
+	default:
+		fprint(2, "usage: bmp -39cdektv  [file.bmp ...]\n");
+		exits("usage");
+	}ARGEND;
+
+	err = nil;
+	if(argc == 0)
+		err = show(0, "<stdin>");
+	else{
+		for(i=0; i<argc; i++){
+			fd = open(argv[i], OREAD);
+			if(fd < 0){
+				fprint(2, "bmp: can't open %s: %r\n", argv[i]);
+				err = "open";
+			}else{
+				err = show(fd, argv[i]);
+				close(fd);
+			}
+			if((nineflag || cflag) && argc>1 && err==nil){
+				fprint(2, "bmp: exiting after one file\n");
+				break;
+			}
+		}
+	}
+	exits(err);
+}
+
+int
+init(void)
+{
+	static int inited;
+
+	if(inited == 0){
+		if(initdraw(0, 0, 0) < 0){
+			fprint(2, "bmp: initdraw failed: %r");
+			return -1;
+		}
+		einit(Ekeyboard|Emouse);
+		inited++;
+	}
+	return 1;
+}
+
+char*
+show(int fd, char *name)
+{
+	Rawimage **array, *r, *c;
+	Image *i;
+	int j, ch;
+	char buf[32];
+
+	array = readbmp(fd, CRGB);
+	if(array == nil || array[0]==nil){
+		fprint(2, "bmp: decode %s failed: %r\n", name);
+		return "decode";
+	}
+	if(!dflag){
+		if(init() < 0)
+			return "initdraw";
+		if(defaultcolor && screen->depth>8)
+			outchan = RGB24;
+	}
+	r = array[0];
+	if(outchan == CMAP8)
+		c = torgbv(r, !eflag);
+	else{
+		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0))
+			c = totruecolor(r, CY);
+		else
+			c = totruecolor(r, CRGB24);
+	}
+	if(c == nil){
+		fprint(2, "bmp: converting %s to local format failed: %r\n", name);
+		return "torgbv";
+	}
+	if(!dflag){
+		if(r->chandesc == CY)
+			i = allocimage(display, c->r, GREY8, 0, 0);
+		else
+			i = allocimage(display, c->r, outchan, 0, 0);
+		if(i == nil){
+			fprint(2, "bmp: allocimage %s failed: %r\n", name);
+			return "allocimage";
+		}
+		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){
+			fprint(2, "bmp: loadimage %s failed: %r\n", name);
+			return "loadimage";
+		}
+		image = i;
+		eresized(0);
+		if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
+			exits(nil);
+		draw(screen, screen->clipr, display->white, nil, ZP);
+		image = nil;
+		freeimage(i);
+	}
+	if(nineflag){
+		chantostr(buf, outchan);
+		print("%11s %11d %11d %11d %11d ", buf,
+			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y);
+		if(write(1, c->chans[0], c->chanlen) != c->chanlen){
+			fprint(2, "bmp: %s: write error %r\n", name);
+			return "write";
+		}
+	}else if(cflag){
+		if(writerawimage(1, c) < 0){
+			fprint(2, "bmp: %s: write error: %r\n", name);
+			return "write";
+		}
+	}
+	for(j=0; j<r->nchans; j++)
+		free(r->chans[j]);
+	free(r);
+	free(array);
+	if(c){
+		free(c->chans[0]);
+		free(c);
+	}
+	return nil;
+}

+ 37 - 0
sys/src/cmd/jpg/bmp.h

@@ -0,0 +1,37 @@
+
+#define BMP_RGB      	0
+#define BMP_RLE8     	1
+#define BMP_RLE4     	2
+#define BMP_BITFIELDS	3
+
+typedef struct {
+	uchar red;
+	uchar green;
+	uchar blue;
+	uchar alpha;
+} Rgb;
+
+typedef struct {
+        short	type;
+        long	size;
+        short	reserved1;
+        short	reserved2;
+        long	offbits;
+} Filehdr;
+
+typedef struct {
+	long	size;		/* Size of the Bitmap-file */
+	long	lReserved;	/* Reserved */
+	long	dataoff;	/* Picture data location */
+	long	hsize;		/* Header-Size */
+	long	width;		/* Picture width (pixels) */
+	long	height;		/* Picture height (pixels) */
+	short	planes;		/* Planes (must be 1) */
+	short	bpp;		/* Bits per pixel (1, 4, 8 or 24) */
+	long	compression;	/* Compression mode */
+	long	imagesize;	/* Image size (bytes) */
+	long	hres;		/* Horizontal Resolution (pels/meter) */
+	long	vres;		/* Vertical Resolution (pels/meter) */
+	long	colours;	/* Used Colours (Col-Table index) */
+	long	impcolours;	/* Important colours (Col-Table index) */
+} Infohdr;

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

@@ -10,6 +10,7 @@ TARG=jpg\
 	yuv\
 	ico\
 	toico\
+	bmp\
 
 IMFILES=\
 	torgbv.$O\
@@ -48,6 +49,7 @@ $O.toppm:	writeppm.$O multichan.$O toppm.$O
 $O.png:		$IMFILES readpng.$O png.$O
 $O.topng:	writepng.$O topng.$O
 $O.yuv:		$IMFILES readyuv.$O yuv.$O
+$O.bmp:		$IMFILES readbmp.$O bmp.$O
 
 torgbv.$O:	ycbcr.h rgbv.h
 

+ 626 - 0
sys/src/cmd/jpg/readbmp.c

@@ -0,0 +1,626 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include "imagefile.h"
+#include "bmp.h"
+
+/*
+ MS-BMP file reader
+ (c) 2003, I.P.Keller
+
+ aims to decode *all* valid bitmap formats, although some of the
+ flavours couldn't be verified due to lack of suitable test-files.
+ the following flavours are supported:
+
+	Bit/Pix	Orientation	Compression	Tested?
+	  1	top->bottom	n/a		yes
+	  1	bottom->top	n/a		yes
+	  4	top->bottom	no		yes
+	  4	bottom->top	no		yes
+	  4	top->bottom	RLE4		yes, but not with displacement
+	  8	top->bottom	no		yes
+	  8	bottom->top	no		yes
+	  8	top->bottom	RLE8		yes, but not with displacement
+	 16	top->bottom	no		no
+	 16	bottom->top	no		no
+	 16	top->bottom	BITMASK		no
+	 16	bottom->top	BITMASK		no
+	 24	top->bottom	n/a		yes
+	 24	bottom->top	n/a		yes
+	 32	top->bottom	no		no
+	 32	bottom->top	no		no
+	 32	top->bottom	BITMASK		no
+	 32	bottom->top	BITMASK		no
+
+ OS/2 1.x bmp files are recognised as well, but testing was very limited.
+
+ verifying was done with a number of test files, generated by
+ different tools. nevertheless, the tests were in no way exhaustive
+ enough to guarantee bug-free decoding. caveat emptor!
+*/
+
+static short
+r16(Biobuf*b)
+{
+	short s;
+
+	s = Bgetc(b);
+	s |= ((short)Bgetc(b)) << 8;
+	return s;
+}
+
+
+static long
+r32(Biobuf*b)
+{
+	long l;
+
+	l = Bgetc(b);
+	l |= ((long)Bgetc(b)) << 8;
+	l |= ((long)Bgetc(b)) << 16;
+	l |= ((long)Bgetc(b)) << 24;
+	return l;
+}
+
+
+/* get highest bit set */
+static int
+msb(ulong x)
+{
+	int i;
+	for(i = 32; i; i--, x <<= 1)
+		if(x & 0x80000000L)
+			return i;
+	return 0;
+}
+
+/* Load a 1-Bit encoded BMP file (uncompressed) */
+static int
+load_1T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	long ix, iy, i = 0, step_up = 0, padded_width = ((width + 31) / 32) * 32;
+	int val = 0, n;
+
+	if(height > 0) {	/* bottom-up */
+		i = (height - 1) * width;
+		step_up = -2 * width;
+	} else
+		height = -height;
+
+	for(iy = height; iy; iy--, i += step_up)
+		for(ix = 0, n = 0; ix < padded_width; ix++, n--) {
+			if(!n) {
+				val = Bgetc(b);
+				n = 8;
+			}
+			if(ix < width) {
+				buf[i] = clut[val & 0x80 ? 1 : 0];
+				i++;
+			}
+			val <<= 1;
+		}
+	return 0;
+}
+
+/* Load a 4-Bit encoded BMP file (uncompressed) */
+static int
+load_4T(Biobuf* b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	long ix, iy, i = 0, step_up = 0, skip = (4 - (((width % 8) + 1) / 2)) & 3;
+	uint valH, valL;
+
+	if(height > 0) {	/* bottom-up */
+		i = (height - 1) * width;
+		step_up = -2 * width;
+	} else
+		height = -height;
+
+	for(iy = height; iy; iy--, i += step_up) {
+		for(ix = 0; ix < width; ) {
+			valH = valL = Bgetc(b) & 0xff;
+			valH >>= 4;
+
+			buf[i] = clut[valH];
+			i++; ix++;
+
+			if(ix < width) {
+				valL &= 0xf;
+				buf[i] = clut[valL];
+				i++; ix++;
+			}
+		}
+		Bseek(b, skip, 1);
+	}
+	return 0;
+}
+
+/* Load a 4-Bit encoded BMP file (RLE4-compressed) */
+static int
+load_4C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	long ix, iy = height -1;
+	uint val, valS, skip;
+	Rgb* p;
+
+	while(iy >= 0) {
+		ix = 0;
+		while(ix < width) {
+			val = Bgetc(b);
+
+			if(0 != val) {
+				valS = (uint)Bgetc(b);
+				p = &buf[ix + iy * width];
+				while(val--) {
+					*p = clut[0xf & (valS >> 4)];
+					p++;
+					ix++;
+					if(0 < val) {
+						*p = clut[0xf & valS];
+						p++;
+						ix++;
+						val--;
+					}
+				}
+			} else {
+				/* Special modes... */
+				val = Bgetc(b);
+				switch(val) {
+					case 0:	/* End-Of-Line detected */
+						ix = width;
+						iy--;
+						break;
+					case 1:	/* End-Of-Picture detected -->> abort */
+						ix = width;
+						iy = -1;
+						break;
+					case 2:	/* Position change detected */
+						val = Bgetc(b);
+						ix += val;
+						val = Bgetc(b);
+						iy -= val;
+						break;
+
+					default:/* Transparent data sequence detected */
+						p = &buf[ix + iy * width];
+						if((1 == (val & 3)) || (2 == (val & 3)))
+							skip = 1;
+						else 
+							skip = 0;
+
+						while(val--) {
+							valS = (uint)Bgetc(b);
+							*p = clut[0xf & (valS >> 4)];
+							p++;
+							ix++;
+							if(0 < val) {
+								*p = clut[0xf & valS];
+								p++;
+								ix++;
+								val--;
+							}
+						}
+						if(skip)
+							Bgetc(b);
+						break;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/* Load a 8-Bit encoded BMP file (uncompressed) */
+static int
+load_8T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	long ix, iy, i = 0, step_up = 0, skip = (4 - (width % 4)) & 3;
+
+	if(height > 0) {	/* bottom-up */
+		i = (height - 1) * width;
+		step_up = -2 * width;
+	} else
+		height = -height;
+
+	for(iy = height; iy; iy--, i += step_up) {
+		for(ix = 0; ix < width; ix++, i++)
+			buf[i] = clut[Bgetc(b) & 0xff];
+		Bseek(b, skip, 1);
+	}
+	return 0;
+}
+
+/* Load a 8-Bit encoded BMP file (RLE8-compressed) */
+static int
+load_8C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	long ix, iy = height -1;
+	int val, valS, skip;
+	Rgb* p;
+
+	while(iy >= 0) {
+		ix = 0;
+		while(ix < width) {
+			val = Bgetc(b);
+
+			if(0 != val) {
+				valS = Bgetc(b);
+				p = &buf[ix + iy * width];
+				while(val--) {
+					*p = clut[valS];
+					p++;
+					ix++;
+				}
+			} else {
+				/* Special modes... */
+				val = Bgetc(b);
+				switch(val) {
+					case 0: /* End-Of-Line detected */
+						ix = width;
+						iy--;
+						break;
+					case 1: /* End-Of-Picture detected */
+						ix = width;
+						iy = -1;
+						break;
+					case 2: /* Position change detected */
+						val = Bgetc(b);
+						ix += val;
+						val = Bgetc(b);
+						iy -= val;
+						break;
+					default: /* Transparent (not compressed) sequence detected */
+						p = &buf[ix + iy * width];
+						if(val & 1)
+							skip = 1;
+						else 
+							skip = 0;
+
+						while(val--) {
+							valS = Bgetc(b);
+							*p = clut[valS];
+							p++;
+							ix++;
+						}
+						if(skip)
+							/* Align data stream */
+							Bgetc(b);
+						break;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+/* Load a 16-Bit encoded BMP file (uncompressed) */
+static int
+load_16(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	uchar c[2];
+	long ix, iy, i = 0, step_up = 0;
+
+	if(height > 0) {	/* bottom-up */
+		i = (height - 1) * width;
+		step_up = -2 * width;
+	} else
+		height = -height;
+
+	if(clut) {
+		unsigned mask_blue =  (unsigned)clut[0].blue +
+		                     ((unsigned)clut[0].green << 8);
+		unsigned mask_green =  (unsigned)clut[1].blue +
+		                      ((unsigned)clut[1].green << 8);
+		unsigned mask_red =  (unsigned)clut[2].blue +
+		                    ((unsigned)clut[2].green << 8);
+		int shft_blue = msb((ulong)mask_blue) - 8;
+		int shft_green = msb((ulong)mask_green) - 8;
+		int shft_red = msb((ulong)mask_red) - 8;
+
+		for(iy = height; iy; iy--, i += step_up)
+			for(ix = 0; ix < width; ix++, i++) {
+				unsigned val;
+				Bread(b, c, sizeof(c));
+				val = (unsigned)c[0] + ((unsigned)c[1] << 8);
+
+				buf[i].alpha = 0;
+				if(shft_blue >= 0)
+					buf[i].blue = (uchar)((val & mask_blue) >> shft_blue);
+				else
+					buf[i].blue = (uchar)((val & mask_blue) << -shft_blue);
+				if(shft_green >= 0)
+					buf[i].green = (uchar)((val & mask_green) >> shft_green);
+				else
+					buf[i].green = (uchar)((val & mask_green) << -shft_green);
+				if(shft_red >= 0)
+					buf[i].red = (uchar)((val & mask_red) >> shft_red);
+				else
+					buf[i].red = (uchar)((val & mask_red) << -shft_red);
+			}
+	} else
+		for(iy = height; iy; iy--, i += step_up)
+			for(ix = 0; ix < width; ix++, i++) {
+				Bread(b, c, sizeof(c));
+				buf[i].blue = (uchar)((c[0] << 3) & 0xf8);
+				buf[i].green = (uchar)(((((unsigned)c[1] << 6) +
+				                        (((unsigned)c[0]) >> 2))) & 0xf8);
+				buf[i].red = (uchar)((c[1] << 1) & 0xf8);
+			}
+	return 0;
+}
+
+/* Load a 24-Bit encoded BMP file (uncompressed) */
+static int
+load_24T(Biobuf* b, long width, long height, Rgb* buf)
+{
+	long ix, iy, i = 0, step_up = 0, skip = (4 - ((width * 3) % 4)) & 3;
+
+	if(height > 0) {	/* bottom-up */
+		i = (height - 1) * width;
+		step_up = -2 * width;
+	} else
+		height = -height;
+
+	for(iy = height; iy; iy--, i += step_up) {
+		for(ix = 0; ix < width; ix++, i++) {
+			buf[i].alpha = 0;
+			buf[i].blue = Bgetc(b);
+			buf[i].green = Bgetc(b);
+			buf[i].red = Bgetc(b);
+		}
+		Bseek(b, skip, 1);
+	}
+	return 0;
+}
+
+/* Load a 32-Bit encoded BMP file (uncompressed) */
+static int
+load_32(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut)
+{
+	uchar c[4];
+	long ix, iy, i = 0, step_up = 0;
+
+	if(height > 0) {	/* bottom-up */
+		i = (height - 1) * width;
+		step_up = -2 * width;
+	} else
+		height = -height;
+
+	if(clut) {
+		ulong mask_blue =  (ulong)clut[0].blue +
+		                          ((ulong)clut[0].green << 8) +
+		                          ((ulong)clut[0].red << 16) +
+		                          ((ulong)clut[0].alpha << 24);
+		ulong mask_green =  (ulong)clut[1].blue +
+		                           ((ulong)clut[1].green << 8) +
+		                           ((ulong)clut[1].red << 16) +
+		                           ((ulong)clut[1].alpha << 24);
+		ulong mask_red =  (ulong)clut[2].blue +
+		                         ((ulong)clut[2].green << 8) +
+		                         ((ulong)clut[2].red << 16) +
+		                         ((ulong)clut[2].alpha << 24);
+		int shft_blue = msb(mask_blue) - 8;
+		int shft_green = msb(mask_green) - 8;
+		int shft_red = msb(mask_red) - 8;
+
+		for(iy = height; iy; iy--, i += step_up)
+			for(ix = 0; ix < width; ix++, i++) {
+				ulong val;
+				Bread(b, c, sizeof(c));
+				val =  (ulong)c[0] + ((ulong)c[1] << 8) +
+				      ((ulong)c[2] << 16) + ((ulong)c[1] << 24);
+
+				buf[i].alpha = 0;
+				if(shft_blue >= 0)
+					buf[i].blue = (uchar)((val & mask_blue) >> shft_blue);
+				else
+					buf[i].blue = (uchar)((val & mask_blue) << -shft_blue);
+				if(shft_green >= 0)
+					buf[i].green = (uchar)((val & mask_green) >> shft_green);
+				else
+					buf[i].green = (uchar)((val & mask_green) << -shft_green);
+				if(shft_red >= 0)
+					buf[i].red = (uchar)((val & mask_red) >> shft_red);
+				else
+					buf[i].red = (uchar)((val & mask_red) << -shft_red);
+			}
+	} else
+		for(iy = height; iy; iy--, i += step_up)
+			for(ix = 0; ix < width; ix++, i++) {
+				Bread(b, c, nelem(c));
+				buf[i].blue = c[0];
+				buf[i].green = c[1];
+				buf[i].red = c[2];
+			}
+	return 0;
+}
+
+
+static Rgb*
+ReadBMP(Biobuf *b, int *width, int *height)
+{
+	int colours, num_coltab = 0;
+	Filehdr bmfh;
+	Infohdr bmih;
+	Rgb clut[256];
+	Rgb* buf;
+
+	bmfh.type = r16(b);
+	if(bmfh.type != 0x4d42) 	/* signature must be 'BM' */
+		sysfatal("bad magic number, not a BMP file");
+
+	bmfh.size = r32(b);
+	bmfh.reserved1 = r16(b);
+	bmfh.reserved2 = r16(b);
+	bmfh.offbits = r32(b);
+
+	memset(&bmih, 0, sizeof(bmih));
+	bmih.size = r32(b);
+
+	if(bmih.size == 0x0c) {			/* OS/2 1.x version */
+		bmih.width = r16(b);
+		bmih.height = r16(b);
+		bmih.planes = r16(b);
+		bmih.bpp = r16(b);
+		bmih.compression = BMP_RGB;
+	} else {				/* Windows */
+		bmih.width = r32(b);
+		bmih.height = r32(b);
+		bmih.planes = r16(b);
+		bmih.bpp = r16(b);
+		bmih.compression = r32(b);
+		bmih.imagesize = r32(b);
+		bmih.hres = r32(b);
+		bmih.vres = r32(b);
+		bmih.colours = r32(b);
+		bmih.impcolours = r32(b);
+	}
+
+	if(bmih.bpp < 16) {
+		/* load colour table */
+		if(bmih.impcolours)
+			num_coltab = (int)bmih.impcolours;
+		else
+			num_coltab = 1 << bmih.bpp;
+	} else if(bmih.compression == BMP_BITFIELDS &&
+	          (bmih.bpp == 16 || bmih.bpp == 32))
+		/* load bitmasks */
+		num_coltab = 3;
+
+	if(num_coltab) {
+		int i; 
+		Bseek(b, bmih.size + sizeof(Infohdr), 0);
+
+		for(i = 0; i < num_coltab; i++) {
+			clut[i].blue  = (uchar)Bgetc(b);
+			clut[i].green = (uchar)Bgetc(b);
+			clut[i].red   = (uchar)Bgetc(b);
+			clut[i].alpha = (uchar)Bgetc(b);
+		}
+	}
+
+	*width = bmih.width;
+	*height = bmih.height;
+	colours = bmih.bpp;
+
+	Bseek(b, bmfh.offbits, 0);
+
+	if ((buf = calloc(sizeof(Rgb), *width * abs(*height))) == nil)
+		sysfatal("no memory");
+
+	switch(colours) {
+		case 1:
+			load_1T(b, *width, *height, buf, clut);
+			break;
+		case 4:
+			if(bmih.compression == BMP_RLE4)
+				load_4C(b, *width, *height, buf, clut);
+			else
+				load_4T(b, *width, *height, buf, clut);
+			break;
+		case 8:
+			if(bmih.compression == BMP_RLE8)
+				load_8C(b, *width, *height, buf, clut);
+			else
+				load_8T(b, *width, *height, buf, clut);
+			break;
+		case 16:
+			load_16(b, *width, *height, buf,
+			        bmih.compression == BMP_BITFIELDS ? clut : nil);
+			break;
+		case 24:
+			load_24T(b, *width, *height, buf);
+			break;
+		case 32:
+			load_32(b, *width, *height, buf,
+			        bmih.compression == BMP_BITFIELDS ? clut : nil);
+			break;
+	}
+	return buf;
+}
+
+Rawimage**
+Breadbmp(Biobuf *bp, int colourspace)
+{
+	Rawimage *a, **array;
+	int c, width, height;
+	uchar *r, *g, *b;
+	Rgb *s, *e;
+	Rgb *bmp;
+	char ebuf[128];
+
+	a = nil;
+	bmp = nil;
+	array = nil;
+	USED(a);
+	USED(bmp);
+	if (colourspace != CRGB) {
+		errstr(ebuf, sizeof ebuf);	/* throw it away */
+		werrstr("ReadRGB: unknown colour space %d", colourspace);
+		return nil;
+	}
+
+	if ((bmp = ReadBMP(bp, &width, &height)) == nil)
+		return nil;
+
+	if ((a = calloc(sizeof(Rawimage), 1)) == nil)
+		goto Error;
+
+	for (c = 0; c  < 3; c++)
+		if ((a->chans[c] = calloc(width, height)) == nil)
+			goto Error;
+
+	if ((array = calloc(sizeof(Rawimage *), 2)) == nil)
+		goto Error;
+	array[0] = a;
+	array[1] = nil;
+
+	a->nchans = 3;
+	a->chandesc = CRGB;
+	a->chanlen = width * height;
+	a->r = Rect(0, 0, width, height);
+
+	s = bmp;
+	e = s + width * height;
+	r = a->chans[0];
+	g = a->chans[1];
+	b = a->chans[2];
+
+	do {
+		*r++ = s->red;
+		*g++ = s->green;
+		*b++ = s->blue;
+	}while(++s < e);
+
+	free(bmp);
+	return array;
+
+Error:
+	if (a)
+		for (c = 0; c < 3; c++)
+			if (a->chans[c])
+				free(a->chans[c]);
+	if (a)
+		free(a);
+	if (array)
+		free(array);
+	if (bmp)
+		free(bmp);
+	return nil;
+
+}
+
+Rawimage**
+readbmp(int fd, int colorspace)
+{
+	Rawimage * *a;
+	Biobuf b;
+
+	if (Binit(&b, fd, OREAD) < 0)
+		return nil;
+	a = Breadbmp(&b, colorspace);
+	Bterm(&b);
+	return a;
+}
+
+

+ 14 - 3
sys/src/cmd/wikifs/parse.c

@@ -211,8 +211,19 @@ wman(Wpage *wtxt)
 	return wtxt;	
 }
 
-static char *lower = "abcdefghijklmnopqrstuvwxyz";
-static char *upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+static int isheading(char *p) {
+	Rune r;
+	int hasupper=0;
+	while(*p) {
+		p+=chartorune(&r,p);
+		if(isupperrune(r))
+			hasupper=1;
+		else if(islowerrune(r))
+			return 0;
+	}
+	return hasupper;
+}
+
 Wpage*
 Brdpage(char *(*rdline)(void*,int), void *b)
 {
@@ -247,7 +258,7 @@ Brdpage(char *(*rdline)(void*,int), void *b)
 			pw = &(*pw)->next;
 			break;
 		default:
-			if(strpbrk(p, lower)==nil && strpbrk(p, upper)){
+			if(isheading(p)){
 				*pw = mkwtxt(Wheading, estrdup(p));
 				pw = &(*pw)->next;
 				continue;