OK, turing.

<- leave blank

Sun Feb 17 19:16:11 EST 2019

server "myrlang.org" {
	listen on $ext_ip tls port 443
	root "/myrlang.org"
	tls {
	       certificate "/etc/http/myrlang.org.chained.crt"
	       key "/etc/http/myrlang.org.key"
	}
}


Sun Feb 17 12:45:21 EST 2019
#include <u.h>
#include <libc.h>
#include <thread.h>

enum {
	Nfileprocs = 4,
	Nblkprocs = 16,

	Blksz = 128*1024,
};

typedef struct WaitGroup {
	Rendez;
	QLock;
	Ref;
} WaitGroup;

typedef struct File {
	Dir;
	WaitGroup wg;
	Channel *errchan;
	char *src, *dst;
	int sfd, dfd;
} File;

typedef struct Blk {
	File *f;
	vlong offset;
} Blk;

int errors = 0;
int multisrc = 0;
int keepmode = 0;
int keepmtime = 0;
int keepuser = 0;
int keepgroup = 0;
int sync = 0;
int blksz = Blksz;
int fileprocs = Nfileprocs;
int blkprocs = Nblkprocs;
Dir *skipdir;

Channel *filechan; /* chan(File*) */
Channel *blkchan; /* chan(Blk*) */

void usage(void);
void *emalloc(ulong);
char *estrdup(char*);

extern int cas(long *p, long ov, long nv);
void wginit(WaitGroup*, long);
void wgadd(WaitGroup*, long);
void wgdone(WaitGroup*);
void wgwait(WaitGroup*);

char *filename(char*);
int mkdir(char*, char*, Dir*, Dir**);
int same(Dir*, Dir*);
void clone(char*, char*);
int cloneattr(int, Dir*);
void clonedir(char*, char*);
int clonefile(File*);
File *filenew(char*, char*, Dir*);
void filefree(File*);
void fileproc(void*);
vlong blklist(File*, Blk**);
void blkproc(void*);

void
usage(void)
{
	fprint(2, "usage: %s [-gux] [-b blocksize] [-p fileprocs:blockprocs] from
	...  to\n", argv0);
	fprint(2, "usage: %s -s [-gux] [-b blocksize] [-p fileprocs:blockprocs]
	from to\n", argv0);
	exits("usage");
}

void
error(char *fmt, ...)
{
	va_list arg;
	char err[ERRMAX];

	errors = 1;
	snprint(err, sizeof err, "%s: %s\n", argv0, fmt);
	va_start(arg, fmt);
	vfprint(2, err, arg);
	va_end(arg);
}

void *
emalloc(ulong n)
{
	void *p;

	p = malloc(n);
	if(p == nil)
		sysfatal("malloc: %r");
	return p;
}

char *
estrdup(char *s)
{
	char *p;

	p = strdup(s);
	if(p == nil)
		sysfatal("strdup: %r");
	return p;
}

void
wginit(WaitGroup *wg, long n)
{
	memset(wg, 0, sizeof(*wg));
	wg->l = &wg->QLock;
	if(cas(&wg->ref, 0, n) == 0)
		sysfatal("wginit: cas failed");
}

void
wgadd(WaitGroup *wg, long n)
{
	long v;

	v = wg->ref;
	while(cas(&wg->ref, v, v+n) == 0)
		v = wg->ref;
}

void
wgdone(WaitGroup *wg)
{
	if(decref(wg) == 0){
		qlock(wg);
		rwakeupall(wg);
		qunlock(wg);
	}
}

void
wgwait(WaitGroup *wg)
{
	qlock(wg);
	while(wg->ref != 0)
		rsleep(wg);
	qunlock(wg);
}

char *
filename(char *s)
{
	char *p;

	p = strrchr(s, '/');
	if(p == nil || p == s)
		return s;
	if(p[1] == 0){
		*p = 0;
		return filename(s);
	}
	return p + 1;
}

int
mkdir(char *src, char *dst, Dir *sd, Dir **dd)
{
	int fd;
	Dir d;

	USED(src);
	if(sync == 0 && sd->mode & 0400 == 0){
		error("can't clone directory: '%s' permission denied", src);
		return -1;
	}
	if(sync == 0){
		d = *sd;
		d.mode = d.mode | DMDIR | 0200;
		fd = create(dst, 0, d.mode);
	}else
		fd = open(dst, 0);
	if(fd < 0){
		error("mkdir: %r");
		return -1;
	}
	if(dd){
		*dd = dirfstat(fd);
		if(*dd == nil){
			error("can't stat: %r");
			close(fd);
			return -1;
		}
	}
	return fd;
}

int
same(Dir *a, Dir *b)
{
	if(a->type == b->type &&
		a->dev == b->dev &&
		a->qid.path == b->qid.path &&
		a->qid.type == b->qid.type &&
		a->qid.vers == b->qid.vers)
		return 1;
	return 0;
}

File *
filenew(char *src, char *dst, Dir *d)
{
	File *f;

	f = emalloc(sizeof(File));
	memmove(f, d, sizeof(Dir));
	f->uid = estrdup(d->uid);
	f->gid = estrdup(d->gid);
	f->src = estrdup(src);
	f->dst = estrdup(dst);
	f->sfd = -1;
	f->dfd = -1;
	f->errchan = chancreate(sizeof(ulong), 0);

	return f;
}

void
filefree(File *f)
{
	if(f->sfd >= 0)
		close(f->sfd);
	if(f->dfd >= 0)
		close(f->dfd);
	free(f->uid);
	free(f->gid);
	free(f->src);
	free(f->dst);
	chanfree(f->errchan);
	free(f);
}

int
cloneattr(int fd, Dir *d)
{
	Dir dd;

	if(!(keepmode || keepuser || keepgroup || keepmtime))
		return 1;
	nulldir(&dd);
	if(keepmode)
		dd.mode = d->mode & DMDIR ? d->mode|0200 : d->mode;
	if(keepmtime)
		dd.mtime = d->mtime;
	if(keepuser)
		dd.uid = d->uid;
	if(keepgroup)
		dd.gid = d->gid;
	if(dirfwstat(fd, &dd) < 0){
		error("can't wstat: %r");
		return -1;
	}
	return 1;
}

void
clone(char *src, char *dst)
{
	int fd;
	char *dn;
	Dir *sd, *dd;
	File *f;

	fd = -1;
	dn = estrdup(dst);
	dd = nil;
	sd = dirstat(src);
	if(sd == nil){
		error("can't stat: %r");
		return;
	}
	if(access(dn, AEXIST) >= 0){
		dd = dirstat(dn);
		if(dd == nil){
			error("can't stat: %r");
			goto End;
		}
	}else if(multisrc){
		if((fd = mkdir(src, dn, sd, &dd)) < 0)
			goto End;
		skipdir = dd;
	}

	/* clone a file */
	if(!(sd->mode & DMDIR)){
		if(dd && dd->mode & DMDIR)
				dn = smprint("%s/%s", dn, filename(src));
		f = filenew(src, dn, sd);
		sendp(filechan, f);
		goto End;
	}

	/* clone a directory */
	if(sync){
		skipdir = sd;
		clonedir(src, dn);
		cloneattr(fd, sd);
		free(dn);
		free(dd);
		return;
	}
	if(dd)
		dn = smprint("%s/%s", dn, filename(src));
	if(skipdir){
		if((fd = mkdir(src, dn, sd, nil)) < 0)
			goto End;
	}else{
		if((fd = mkdir(src, dn, sd, &skipdir)) < 0)
			goto End;
	}
	clonedir(src, dn);
	cloneattr(fd, sd);

End:
	close(fd);
	free(dn);
	free(sd);
	free(dd);
}

void
clonedir(char *src, char *dst)
{
	int fd;
	long n;
	char *sn, *dn;
	Dir *dirs, *d;
	File *f;

	dirs = nil;

	fd = open(src, OREAD);
	if(fd < 0){
		error("can't open: %r");
		return;
	}
	n = dirreadall(fd, &dirs);
	if(n < 0){
		error("can't read directory: %r");
		close(fd);
		return;
	}
	close(fd);

	for(d = dirs; n; n--, d++){
		if(d->mode & DMDIR && same(skipdir, d))
			continue;

		sn = smprint("%s/%s", src, d->name);
		dn = smprint("%s/%s", dst, d->name);
		if(d->mode & DMDIR){
			if((fd = mkdir(sn, dn, d, nil)) < 0)
				continue;
			clonedir(sn, dn);
			cloneattr(fd, d);
			close(fd);
		}else{
			f = filenew(sn, dn, d);
			sendp(filechan, f);
		}
		free(sn);
		free(dn);
	}
	free(dirs);
}

vlong
blklist(File *f, Blk **bp)
{
	vlong i, nblk;
	Blk *b, *p;

	if(f->length == 0)
		return 0;
	nblk = f->length / blksz;
	if(nblk == 0)
		nblk = 1;
	else if(nblk % blksz > 0)
		nblk++;

	b = p = emalloc(sizeof(Blk) * nblk);
	for(i = 0; i < nblk; i++, p++){
		p->f = f;
		p->offset = blksz * i;
	}

	*bp = b;
	return nblk;
}

int
clonefile(File *f)
{
	int ret;
	vlong n;
	Blk *blks, *b, *be;
	enum {Anext, Aerr, Aend};
	Alt alts[] = {
	[Anext] {blkchan, &b, CHANSND},
	[Aerr] {f->errchan, nil, CHANRCV},
	[Aend] {nil, nil, CHANEND},
	};

	ret = 1;
	n = blklist(f, &blks);
	if(n == 0)
		return 1;
	wginit(&f->wg, 0);
	for(b = blks, be = b + n; b != be; b++)
		switch(alt(alts)){
		case Anext:
			wgadd(&f->wg, 1);
			break;
		case Aerr:
			ret = -1;
			goto End;
		}
End:
	chanclose(f->errchan);
	wgwait(&f->wg);
	free(blks);
	return ret;
}

void
blkproc(void *)
{
	int sfd, dfd;
	long n;
	vlong off;
	char *buf;
	File *f;
	Blk *b;

	threadsetname("blkproc");

	buf = emalloc(blksz);
	for(;;){
		b = recvp(blkchan);
		if(b == nil)
			break;

		f = b->f;
		sfd = f->sfd;
		dfd = f->dfd;
		off = b->offset;
		if((n = pread(sfd, buf, blksz, off)) < 0){
			error("can't read: %r");
			sendul(f->errchan, ~0);
		}
		if(n > 0 && pwrite(dfd, buf, n, off) < n){
			error("can't write: %r");
			sendul(f->errchan, ~0);
		}

		wgdone(&f->wg);
	}
}

void
fileproc(void *v)
{
	Dir *d;
	File *f;
	WaitGroup *wg;

	threadsetname("fileproc");

	wg = v;
	for(;;){
		f = recvp(filechan);
		if(f == nil)
			break;

		if(sync && access(f->dst, AEXIST) >= 0){
			d = dirstat(f->dst);
			if(d == nil){
				error("can't stat: %r\n");
				goto End;
			}
			if(f->mtime < d->mtime)
				goto End;
			fprint(2, "syncing %s\n", f->src);
		}
		f->dfd = create(f->dst, OWRITE, f->mode);
		if(f->dfd < 0){
			error("can't create: %r");
			goto End;
		}
		f->sfd = open(f->src, OREAD);
		if(f->sfd < 0){
			error("can't open: %r");
			goto End;
		}

		if(clonefile(f) > 0)
			cloneattr(f->dfd, f);
End:
		filefree(f);
	}
	wgdone(wg);
}

void
threadmain(int argc, char *argv[])
{
	int i;
	char *dst, *p;
	WaitGroup filewg;

	ARGBEGIN{
	case 'b':
		blksz = strtol(EARGF(usage()), nil, 0);
		break;
	case 'p':
		fileprocs = strtol(EARGF(usage()), &p, 0);
		*p++ = 0;
		blkprocs = strtol(p, nil, 0);
		break;
	case 'x':
		keepmode = keepmtime = 1;
		break;
	case 'u':
		keepuser = 1;
		break;
	case 'g':
		keepgroup = 1;
		break;
	case 's':
		sync = 1;
		break;
	}ARGEND;
	if(argc < 2)
		usage();
	if(argc > 2)
		multisrc = 1;
	dst = argv[argc - 1];
	if(multisrc && sync)
		usage();

	filechan = chancreate(sizeof(File*), fileprocs);
	blkchan = chancreate(sizeof(Blk*), blkprocs);
	wginit(&filewg, fileprocs);
	for(i = 0; i < fileprocs; i++)
		proccreate(fileproc, &filewg, mainstacksize);
	for(i = 0; i < blkprocs; i++)
		proccreate(blkproc, nil, mainstacksize);

	for(i = 0; i < argc -1; i++)
		clone(argv[i], dst);
	chanclose(filechan);
	wgwait(&filewg);

	if(errors)
		threadexitsall("errors");
	threadexitsall(nil);
}


Sun Feb 17 11:24:35 EST 2019
/sys/src/games/blabs/blabs.c:822,828 - blabs.c:822,828
			undraw(d);
		for (d = dot; d != edot; d++)
			upd(d);
- draw(screen, screen->r, screen, nil, screen->r.min);
+ draw(screen, screen->r, screen, nil, addpt(screen->r.min, Pt(-3,-5)));
		flushimage(display, 1);
		now = nsec();
		if(now - then < DELAY)


Sun Feb 17 05:47:04 EST 2019
 17-May-89 12:18 Hans.Tallis@ML metabolic fascism
 Article 106 of ics.whimsey:
 >From: David A Honig <honig@BONNIE.ICS.UCI.EDU>
 Subject: Metabolic Fascism
 Lines: 144

 ------------------------------------------------------------------------
			    Metabolic Fascism
			    =================
			     by Basil Hosmer

 Every programmer has some experience with bodily abuse.  Sooner or
 later, all of us do things to ourselves we wouldn't admit to Mom.  Most
 of the time we say we're provoked by circumstances: whether it's the
 representative from your client's company -- a not pleasant man who
 looks a lot like Herman Munster, breathing heavily on your neck -- or
 some towering, unstoppable endorphin rush that threatens to rip your
 medulla out of its socket if you don't code up that monstro algorithm
 RIGHT NOW and forget about your wedding.  We generally attribute our
 protracted binges to some external force.

 This attitude bespeaks a hideous wrong-headedness among programmers.  We
 seem to get some masochistic pleasure out of responding to pressure by
 sitting in front of our machines until our fingernails are too long to
 type.  Our eyes get varicose veins.  We run fingers through our hair
 until we get split ends.  We drool.  Why?

 Because, the deluded among us would answer, we have to.  Some specter is
 chaining us to our chairs, making strangers of our families, removing us
 from the throb of humanity.  It's not a pretty job, we sigh nobly, but
 someone has to do it.  This is, as my sister used to say, pompous fudge-
 cakes.  We do it because we like it.

 In view of this, I submit a philosophy of life which has served me well
 for the past couple of years.  I call it Metabolic Fascism.

 There are several basic tenets to this philosophy, but one provides the
 foundation for the rest: You Are At War With Your Body.

 Picture a table.  A lobbyist for your brain sits on one side, a lobbyist
 for your body on the other.  They are pushing their respective interests
 as you go through your life.  In a democratic regime, one might overhear
 something like this during a normal day:

 BODY: Nothing like a good, hearty breakfast to kick-start the day.
 BRAIN: Yeah...I feel some serious creativity coming on.  It's gonna be a
	banner day for original thought.  Can we arrange a little rush
	from a relevant gland to start things off?
 BODY: Why, sure.  (Drains a mug of java...) There we go.
 BRAIN: Thanks.

 (Some eight hours later.)

 BODY: Okay, it's about time to wind things down.
 BRAIN: But...
 BODY: C'mon, it'll be better in the morning if we quit now.
 BRAIN: Aw, okay.

 (After some interval, sleep, then repeat cycle.)

 Now, this has its obvious advantages.  Brain and body maintain a working
 camaraderie, the cycle of ups and downs is never too extreme or debili-
 tating, and the productivity of the two working in tandem is fairly
 consistent and predictable.

 On the other hand, come the day when Herman Munster is breathing down
 your neck, you might HAVE to trash that comfy little system for some-
 thing a little more, well, authoritarian.  My solution is simple:
 metabolic fascism.  Not when you have to crank it out, but ALL the time.
 To wit:

 BODY: Not coffee AGAIN.
 BRAIN: You don't want it, throw it up.  But don't bother me.  Have some
	dessert.
 BODY: Lucky Strikes a la carte.  Delectable.  My lungs look like Fire-
	stones.
 BRAIN: Listen.  I'm on the verge of a universe-tilting breakthrough.  I
	don't need your sniveling.
 BODY: Are we gonna get some sleep this week?
 BRAIN: Yeah, yeah.

 (Some 14 hours later.)

 BODY: Look, man, I'm gonna die here.  I wanna go to bed.
 BRAIN: SILENCE!

 (Rains vicious blows upon the Body Lobbyist until he sinks beneath the
 table, a simpering lump of protoplasm.)

 Philistine.

 (Some 10 hours later, the Body Lobbyist has risen from beneath the
 table, wearing full body armor and a catcher's mask.)

 BODY: Sleep.  Now.

 (The Brain lobbyist produces a dreadnought Louisville Slugger, festooned
 with nails, and clubs the Body Lobbyist senseless.)

 BRAIN: Where was I?

 (Some eight hours later, the Body Lobbyist rises and leaves the room.
 The Brain Lobbyist, deep in some amphetamine-induced trance, fails to
 notice.  Several minutes later the Body Lobbyist re-enters, carrying a
 bazooka.  He liberally distributes the Brain Lobbyist about the room.)

 BODY: Sleep.  Now.

 (Perhaps 20 hours later, another Brain Lobbyist enters the room.  Repeat
 cycle.)

 There are tradeoffs to this methodology, sure.  But the advantages are
 overwhelming.

 First, it's more honest.  After all, the first time a deadline or a good
 idea rolls around, you're gonna shaft your body anyway, right?  Why not
 accustom yourself to those inevitable caffeine fests BEFORE they descend
 on your unsuspecting, pampered physiognomy?

 Second, there is no better way to accumulate a comprehensive, detailed
 knowledge of one's body than by abusing it regularly.  Whereas most
 humans can only recognize vague, ambiguous bodily states and apply
 almost meaningless words like "good," "bad," "tired" and "rested" to the
 way they feel, a metabolic fascist becomes sensitive to the most subtle
 changes in his system.  He learns to check his pulse by noting the fre-
 quency of the shaking in his hands.  He learns to check his blood
 pressure by gauging the accuracy with which he hits the reboot switch.

 To a metabolic fascist, the body is a finely-tuned machine operating
 somewhere past the ragged edge.  One pays much more attention to an
 engine about to explode than to one that is idling, and a metabolic fas-
 cist knows his body to a degree of detail that, among other humans, only
 long-distance runners and new mothers achieve.

 (Not to mention the fact that this mode of living produces a certain
 manic look about the eyes that is useful for everything from terrifying
 muggers to staring down that fossilized waitress who never, EVER, takes
 back a cheeseburger because it's too well- done.)

 The peripheral benefits are legion.  When was the last time you really
 wondered what day it was?  A genuine scratch-your-head-and-call-up-
 Sidekick kind of puzzlement?  When was the last time you were truly
 surprised that the sun decided to rise?  When was the last time you
 stared, entranced, as the sort routine you just wrote turned into little
 green soldiers that danced across your screen?  To the metabolic fascist,
 life once more becomes that fascinating, unpredictable thing most humans
 never see after they graduate from diapers.


Sat Feb 16 14:38:05 EST 2019
/v/g/m/k/c/x/nvidia-drivers # ❯❯❯ revdep-rebuild -ip ✘ 1
 * This is the new python coded version
 * Please report any bugs found using it.
 * The original revdep-rebuild script is installed as revdep-rebuild.sh
 * Please file bugs at: https://bugs.gentoo.org/
 * Collecting system binaries and libraries
 * Checking dynamic linking consistency
 * Assign files to packages
	* Warning: "media-plugins/alsa-plugins-1.1.5" ebuild not found..
	* Warning: "kde-plasma/ksysguard-5.12.3" ebuild not found..
	* Warning: "dev-util/google-perftools-2.6.3" ebuild not found..
	* Warning: "sys-libs/compiler-rt-sanitizers-6.0.0" ebuild not found..
	!!  Could not find ebuild for sys-libs/compiler-rt-sanitizers:6.0.0
	* Warning: "sys-devel/clang-6.0.0-r1" ebuild not found..
	* Warning: "x11-libs/wxGTK-3.0.2.0-r3" ebuild not found..
	* Warning: "media-plugins/gst-plugins-libav-1.12.3" ebuild not found..
	* Warning: "app-emulation/wine-vanilla-4.0" ebuild not found..
	!!  Could not find ebuild for app-emulation/wine-vanilla:4.0
	* Warning: "sys-libs/libomp-6.0.0" ebuild not found..
	* Warning: "sys-devel/llvm-5.0.1" ebuild not found..
	* Warning: "media-video/ffmpeg-3.4.1" ebuild not found..
	* Warning: "media-plugins/gst-plugins-mpeg2dec-1.12.3" ebuild not found..
	* Warning: "media-sound/mpd-0.21.3" ebuild not found..
	* Warning: "media-libs/libsdl2-2.0.7" ebuild not found..
	* Warning: "media-plugins/gst-plugins-mpg123-1.12.3" ebuild not found..
	* Warning: "sys-devel/llvm-6.0.0" ebuild not found..
	* Warning: "media-sound/mpg123-1.25.8" ebuild not found..
	* Warning: "sys-devel/clang-5.0.1" ebuild not found..
	* Warning: "media-sound/pulseaudio-12.0-r2" ebuild not found..
	* Warning: "sys-libs/compiler-rt-sanitizers-5.0.1" ebuild not found..
	!!  Could not find ebuild for sys-libs/compiler-rt-sanitizers:5.0.1
	* Warning: "media-plugins/gst-plugins-pulse-1.12.3" ebuild not found..
	* Warning: "kde-plasma/kwin-5.12.3" ebuild not found..

emerge --pretend --oneshot --complete-graph=y media-libs/smpeg:0
media-plugins/alsa-plugins:0 kde-plasma/ksysguard:5 dev-util/google-perftools:0
media-libs/gst-plugins-base:0.10 dev-python/cffi:0/1.11.5
sys-libs/compiler-rt-sanitizers media-libs/openal:0 x11-libs/libnotify:0
games-emulation/vgba:0 sys-devel/clang:6 x11-libs/wxGTK:3
media-plugins/gst-plugins-libav:1 app-emulation/wine-vanilla net-fs/btfs:0
www-client/phantomjs:0 sys-libs/libomp:0 media-libs/gegl:0.3 sys-devel/llvm:5
media-libs/sdl2-ttf:0 media-video/ffmpeg:0 media-libs/libsdl:0
media-plugins/gst-plugins-mpeg2dec:1 app-arch/snappy:0/1 media-libs/libmpeg2:0
media-libs/chromaprint:0/1 media-sound/mpd:0 media-libs/gegl:0.4
media-libs/libsdl2:0 media-libs/libmypaint:0/0 media-plugins/gst-plugins-mpg123:1
sys-devel/llvm:6 media-sound/mpg123:0 sys-devel/clang:5 media-sound/pulseaudio:0
media-libs/sdl-net:0 media-plugins/gst-plugins-ogg:0.10
sys-libs/compiler-rt-sanitizers media-libs/vapoursynth:0 sys-devel/gcc:7.3.1
media-plugins/gst-plugins-pulse:1 media-libs/libcanberra:0 media-libs/sdl-sound:0
media-libs/gstreamer:0.10 media-libs/libao:0 x11-misc/primus:0 kde-plasma/kwin:5

These are the packages that would be merged, in order:

Calculating dependencies ...  done!

emerge: there are no ebuilds to satisfy "x11-libs/wxGTK:3".

Sat Feb 16 13:58:31 EST 2019
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>

enum {
	Pathmax = 1024,

	File, Dir,
};

int recursive = 0;

char *
basename(char *s)
{
	char *p;

	if((p = strrchr(s, '/')) == 0)
		p = s;
	if(*p == '/')
		p++;
	return p;
}

void
output(struct stat *st, char *path, int type)
{
	switch(type){
	case File:
		printf("%s\n", basename(path));
		break;
	case Dir:
		if(recursive)
			printf("\n%s:\n", path);
		else
			printf("%s\n", basename(path));
		break;
	}
}

int
ls(char *path)
{
	DIR *d;
	struct dirent *e;
	struct stat st;
	char buf[Pathmax];

	if((d = opendir(path)) == NULL)
		exit(1);
	while((e = readdir(d)) != NULL){
		if(strcmp(e->d_name, ".") == 0
		|| strcmp(e->d_name, "..") == 0)
			continue;
		snprintf(buf, sizeof buf, "%s/%s", path, e->d_name);
		if(stat(buf, &st) < 0)
			exit(1);
		if(S_ISREG(st.st_mode)){
			output(&st, buf, File);
		}else if(S_ISDIR(st.st_mode)){
			output(&st, buf, Dir);
			if(recursive)
				ls(buf);
		}
	}
	closedir(d);
	return 0;
}

int
main(int argc, char *argv[])
{
	recursive = 1;

	if(argc == 1)
		ls(".");
	else
		while(--argc)
			ls(argv[argc]);
	return 0;
}


Sat Feb 16 13:56:44 EST 2019
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include "dirwalk.h"

/* ripped off from K&R 2nd ed */
void
dirwalk(char *dir, void (*fnp)(char*))
{
	char buf[1024];
	struct dirent *dp;
	DIR *dfd;
	char *fn;

	dfd = opendir(dir);
	if(dfd == NULL){
		fprintf(stderr, "dirwalk: no such directory: %s\n", dir);
		return;
	}
	while((dp = readdir(dfd)) != NULL){
		fn = dp->d_name;
		if(strcmp(fn, ".") == 0 || strcmp(fn, "..") == 0)
			continue;
		if(strlen(dir) + strlen(fn) + 2 > sizeof buf)
			fprintf(stderr, "dirwalk: filename too long: %s", buf);
		else{
			snprintf(buf, sizeof buf, "%s/%s", dir, fn);
			(*fnp)(buf);
		}
	}
	closedir(dfd);
}


Sat Feb 16 12:34:16 EST 2019
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>

int
walk(char *path)
{
	DIR *d;
	struct dirent *e;

	if((d = opendir(path)) == NULL)
		exit(1);
	while((e = readdir(d)) != NULL){
		/* if file, print it */
		/* if directory, append its name to *path and
		 * call walk on it.
		 */
	}
	closedir(d);
	return 0;
}

int
main(int argc, char *argv[])
{
	if(argc > 1)
		walk(argv[1]);
	else
		walk(".");
	return 0;
}


Sat Feb 16 08:55:04 EST 2019
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <mouse.h>
#include <keyboard.h>
#include <cursor.h>

Mousectl *mousectl;
Keyboardctl *keyboardctl;

Image *bg;
Image *black;

Point p1, p2;

ulong colors[] = {
	0x000000FF,
	0xFFFFFFFF,
	0xFF0000FF,
	0x00FF00FF,
	0x0000FFFF,
	0x00FFFFFF,
	0xFF00FFFF,
	0xFFFF00FF,
	0xFFFFAAFF,
	0xEEEE9EFF,
	0x448844FF,
	0xAAFFAAFF,
	0x88CC88FF,
	0x000055FF,
	0xAAFFFFFF,
	0x0000BBFF,
	0x008888FF,
	0x55AAAAFF,
	0x9EEEEEFF,
	0x99994CFF,
	0x000099FF,
	0x005DBBFF,
	0x4993DDFF,
	0x8888CCFF,
};

void redraw(void);

ulong
randomcol(void)
{
	return colors[nrand(nelem(colors)-1)];
}

void
mouseproc(void *)
{
	Mouse *m;
	Point p;
	enum {Amouse, Aresize, Aend};
	Alt alts[] = {
		[Amouse]{mousectl->c, &mousectl->Mouse, CHANRCV},
		[Aresize]{mousectl->resizec, nil, CHANRCV},
		[Aend]{nil, nil, CHANEND},
	};

	m = &mousectl->Mouse;
	for(;;){
		switch(alt(alts)){
		case Aresize:
			if(getwindow(display, Refnone) < 0)
				sysfatal("getwindow: %r");
			redraw();
			break;
		case Amouse:
			switch(m->buttons){
			case 1:
				p1 = m->xy;
				break;
			case 2:
				break;
			case 4:
				p2 = m->xy;
				break;
			case 0:
				break;
			}
			if(m->buttons)
				redraw();
		break;
		}
	}
}

void
keyboardproc(void *)
{
	Rune r;
	int n;
	char buf[128] = {0};

	for(;;){
		recv(keyboardctl->c, &r);
		switch(r){
		case 'q':
			threadexitsall(nil);
			break;
		case 'r':
			freeimage(bg);
			bg = allocimage(display, Rect(0,0,1,1), RGB24, 1,
			randomcol());
			redraw();
			break;
		case 'm':
			if((n = enter("prompt:", buf, sizeof(buf)-1, mousectl,
			keyboardctl, _screen)) < 0)
				sysfatal("enter: %r");
			buf[n] = 0;
			print("%s\n", buf);
			redraw();
			break;
		default:
			print("%C", r);
			break;
		}
	}
}

void
redraw(void)
{
	Point c, tl, tr, bl, br;
	Point t1, t2;

	c = addpt(screen->r.min, Pt(Dx(screen->r)/2, Dy(screen->r)/2));
	tl = screen->r.min;
	br = screen->r.max;
	tr = Pt(br.x, tl.y);
	bl = Pt(tl.x, br.y);
	t1 = p1;
	t2 = p2;
	draw(screen, screen->r, bg, nil, ZP);
	line(screen, p1, p2, Endarrow, Endarrow, 0, black, ZP);
	for(int i = 3; i < 20; i++){
		bezier(screen, tr, t1, t2, br, 0, 0, 0, black, ZP);
		bezier(screen, tl, t1, t2, bl, 0, 0, 0, black, ZP);
		t1 = subpt(t1, Pt(0, i*i));
	}
	flushimage(display, 1);
}

void
threadmain(int argc, char *argv[])
{
	ARGBEGIN{
	}ARGEND;

	srand(time(0));

	if(newwindow(nil) < 0)
		sysfatal("newwindow: %r");
	if(initdraw(nil, nil, "t") < 0)
		sysfatal("initdraw: %r");
	if((mousectl = initmouse(nil, screen)) == nil)
		sysfatal("initmouse: %r");
	if((keyboardctl = initkeyboard(nil)) == nil)
		sysfatal("initkeyboard: %r");

	black = allocimage(display, Rect(0,0,1,1), RGBA32, 1, 0x000000BF);
	bg = allocimage(display, Rect(0,0,1,1), RGB24, 1, randomcol());

	p1 = Pt(screen->r.max.x - 50, screen->r.min.y + 50);
	p2 = Pt(screen->r.max.x - 10, screen->r.min.y + 10);
	redraw();

	proccreate(mouseproc, nil, 8192);
	proccreate(keyboardproc, nil, 8192);

	threadexits(nil);
}


Fri Feb 15 19:08:23 EST 2019
iobuf.c:186,191 - iobuf.c.orig:186,197

	if(canqlock(p))
		fprint(2, "buffer not locked %Z(%lld)\n", p->dev,
		(Wideoff)p->addr);
+
+ if((p->flags & Bmod) != 0 && p->dev->type == Devro){
+ fprint(2, "attempt to modify %Z(%lld)\n", p->dev, (Wideoff)p->addr);
+ abort();
+ }
+
	if(p->flags & Bimm) {
		if(!(p->flags & Bmod))
			fprint(2, "imm and no mod %Z(%lld)\n",


Thu Feb 14 16:13:23 EST 2019
diff --git a/tutorial.txt b/tutorial.txt
index 8bc7e35..f4d1e9f 100644
--- a/tutorial.txt
+++ b/tutorial.txt
@@ -19,7 +19,7 @@ For deeper coverage, look at the [language
specification](spec.html) and the
 [library reference manual](doc/index.html).

 We assume that you are already familiar with programming, and have installed
-Myrddin on your machine already, following the instructions on the
+Myrddin on your machine, following the instructions on the
 [Environment Setup](setup.html) page.

 A Simple Program
@@ -213,7 +213,7 @@ checked against the value in sequence, and the first one that
matches has its
 body executed.  Here, 7 and 9 are not equal to 11, so their bodies are not
 executed.  However, a free name matches any value, so matching against `n`
 succeeds.  Additionally, the free name captures the value that it is being
-matched against, meaning that in the expression `std.put("got {}\n")`, the
+matched against, meaning that in the expression `std.put("got {}\n", n)`, the
 variable n evaluates to 11.

 This kind of matching can be applied to more than just integers.  If `x` was
@@ -229,7 +229,7 @@ Pattern matches can descend into the structure of almost any
type.  Structures,
 arrays, strings, unions, and even values on the other end of pointers are fair
 game.  Of these, matching on unions is likely to be the most common.

-A union is a type that has two parts: A tag, and a body.  The body is optional,
+A union is a type that has two parts: a tag, and a body.  The body is optional,
 but the tag is always present.  We could define a union type as:

	type u = union
@@ -244,8 +244,8 @@ as in:

	x = `Int 123

-Once a value is in a union, the only way to extract is by applying a
-pattern match to it.  The tag is matched on to decide which variant of the
+Once a value is in a union, the only way to extract it is by applying a
+pattern match.  The tag is matched on to decide which variant of the
 union to extract, and the body is matched using the usual rules.  For example:

 ```{runmyr umatch}
@@ -342,7 +342,7 @@ buffered wrapper around the `std.In` input stream.  This
buffered reader is
 used to efficiently read and decode whole Unicode codepoints.

 The main loop of the `wc` program matches over the result of `bio.getc`.  The
-std result type is generic, but for our purposes right now we can assume it is
+`std.result` type is generic, but for our purposes right now we can assume it is
 defined as:

	type std.result = union
@@ -585,10 +585,10 @@ put this into a bld.proj file in the same directory as
`main.myr`:
		main.myr
	;;

-There is one problem that separate bld.proj files and installed libraries does
+There is one problem that separate bld.proj files and installed libraries do
 not address.  We may want to have the binaries and libraries shipped as part of
 the same project, implying that we want to build them all together as a unit.
-To do this, we could put the two build targets into the same `bld.proj`, we
+To do this, we could put the two build targets into the same `bld.proj`,
 and add a dependency from `main` to the `stack` library, as below:

	lib stack =
@@ -852,7 +852,7 @@ be initialized by this function.
	f(a) /* illegal: used before defined */
	g(&a) /* ok: assumption that g initializes a */

-Consts are are compile time constants, and are often placed in read only
+Consts are compile time constants, and are often placed in read only
 memory by the compiler.  Consts must be initialized with an expression that is
 computable at compile time.  Generics are closely related to constants,
 although their type may contain type variables.
@@ -884,7 +884,7 @@ This is strongly discouraged, stylistically.
 Literals in Detail
 -------------------

-Many values in can be written out directly in code, as literals.  Integers,
+Many values can be written out directly in code, as literals.  Integers,
 characters, strings, arrays, structs, and slices are all examples.

 #### Ints
@@ -1008,7 +1008,7 @@ do.
		The member lookup operator.  Looks up a value from within a
		structure or pointer to structure, and evaluates to that
		value.  As a special case, it also lets you get the length
- of a slice or array using the <code>.len</code> member.  Used as:
+ of a slice or array using the <code>.len</code> member.
	</p></dd>
	<dt>x++</dt>
	<dd><p>
@@ -1105,7 +1105,7 @@ do.
	</p></dd>
	<dt>x >> y</dt>
	<dd>
- <p>The left shift operator shifts <code>x</code> right by
+ <p>The right shift operator shifts <code>x</code> right by
		<code>y</code> bits.  Shifting by more than the number
		of bits
		in <code>x</code> can lead to strange
		results.</p>

@@ -1280,7 +1280,7 @@ Myrddin has a number of types built in.  All of them are
below:

 #### Constructed Types

-You can create new types by with modifiers.  The allowable modifiers are listed
+You can create new types with modifiers.  The allowable modifiers are listed
 below:

 <dl>
@@ -1459,8 +1459,8 @@ types:
		next : list(@elt)#
	;;

-Type names live in a namespace from variable names.  This means that a variable
-may share a name with a type without conflict.
+Type names live in a namespace separate from variable names.  This means
+that a variable may share a name with a type without conflict.

 #### Struct Types

@@ -1487,7 +1487,7 @@ operator:
 The member operator also works on pointers to structs, implicitly
 dereferencing the struct.

- var sptr = &struct
+ var sptr = &s
	sptr.val = 123

 #### Union Types
@@ -1667,7 +1667,7 @@ commenting out code during development.

 Name custom iterators `by<valuetype>`.  For example, bio provides a line
 iterator and a char iterator for files.  These are named, respectively,
-`bio.byline` and `bio.byfile`.
+`bio.byline` and `bio.bychar`.

 Break these rules when it makes sense.  They are suggestions, not laws.



prev | next