shithub: gofs

Download patch

ref: 895af3a6c0ece7ed089ee2a5356cb1933a30cca3
author: sirjofri <sirjofri@sirjofri.de>
date: Sat Dec 13 17:38:42 EST 2025

test filesystem, stone placement, filesystem wrapper script

the filesystem wrapper script is mostly to experiment with descriptive filesystem generation.

--- /dev/null
+++ b/dat.h
@@ -1,0 +1,31 @@
+typedef struct Gogame Gogame;
+typestr struct _vec Vec;
+
+/* WHITE and BLACK should be in sync in both enums */
+typedef enum {
+	GWAIT,
+	GBLACK,
+	GWHITE,
+	GFINISH,
+} Gostate;
+
+typedef enum {
+	EMPTY,
+	BLACK,
+	WHITE,
+	WASBLACK,
+	WASWHITE,
+} Gostone;
+
+struct _vec {
+	int x;
+	int y;
+};
+
+struct Gogame {
+	Gostate state;
+	Vec size;
+	Gostone *board;
+	int whitecaptures;
+	int blackcaptures;
+};
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,16 @@
+Gogame *newgame(Vec size);
+void freegame(Gogame*);
+Gostone getcurrent(Gogame*, Vec pos);
+int setstone(Gogame*, Vec pos, Gostone);
+int passround(Gogame*, Gostone);
+
+Srv *getgenfs(void);
+
+#define V(a, b) (Vec){(a), (b)}
+Vec _vec_pos_(Vec a);
+Vec _vec_neg_(Vec a);
+Vec _vec_add_(Vec a, Vec b);
+Vec _vec_sub_(Vec a, Vec b);
+int _vec_eq_(Vec a, Vec b);
+Vec _vec_asadd_(Vec *a, Vec b);
+Vec _vec_assub_(Vec *a, Vec b);
--- /dev/null
+++ b/fs.fs
@@ -1,0 +1,113 @@
+%{
+#include "dat.h"
+#include "fns.h"
+
+extern Gogame *game1;
+
+%}
+
+/game1
+r{
+	// just print the full board and captures
+	// board: bw<space>, on char per field
+	
+	char *str, *sptr;
+	Gostone stone;
+	
+	str = mallocz((game1->size.x + 1) * game1->size.y + 1, 1);
+	sptr = str;
+	
+	for (int y = 0; y < game1->size.y; y++) {
+		for (int x = 0; x < game1->size.x; x++) {
+			stone = getcurrent(game1, V(x, y));
+			switch (stone) {
+			case WHITE:
+				*sptr = 'w';
+				break;
+			case BLACK:
+				*sptr = 'b';
+				break;
+			default:
+				*sptr = '.';
+			}
+			sptr++;
+		}
+		*sptr = '\n';
+		sptr++;
+	}
+	
+	readstr(r, str);
+	free(str);
+	
+	print("state: %d\n", game1->state);
+	
+	respond(r, nil);
+r}
+w{
+	// b = black, w = white
+	// <c> <x> <y>
+	// <c> <cmd>
+	char *fields[3];
+	int x, y, n;
+	Gostone stone;
+	
+	char *input = mallocz(r->ifcall.count + 1, 1);
+	memcpy(input, r->ifcall.data, r->ifcall.count);
+	if (input[r->ifcall.count-1] == '\n')
+		input[r->ifcall.count-1] = 0;
+	
+	n = getfields(input, fields, 3, 1, " \t");
+	if (n < 2 || n > 3) {
+		free(input);
+		respond(r, "wrong input");
+		return;
+	}
+	
+	switch (fields[0][0]) {
+	case 'w':
+		stone = WHITE;
+		break;
+	case 'b':
+		stone = BLACK;
+		break;
+	default:
+		free(input);
+		respond(r, "bad input");
+		return;
+	}
+	
+	if (n == 2) {
+		switch (fields[1][0]) {
+		case 'p':
+			if (!passround(game1, stone)) {
+				responderror(r);
+			} else {
+				respond(r, nil);
+			}
+			break;
+		}
+		free(input);
+		return;
+	}
+	
+	x = atoi(fields[1]) - 1;
+	y = atoi(fields[2]) - 1;
+	
+	if (!setstone(game1, V(x, y), stone)) {
+		free(input);
+		responderror(r);
+		return;
+	}
+	
+	free(input);
+	r->ofcall.count = r->ifcall.count;
+	respond(r, nil);
+w}
+
+/game2
+r{
+	respond(r, "nothing in data r");
+r}
+w{
+	respond(r, "nothing in data w");
+w}
\ No newline at end of file
--- /dev/null
+++ b/game.c
@@ -1,0 +1,193 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.h>
+#include "dat.h"
+#include "fns.h"
+
+static void validateboard(Gogame *game);
+
+static int
+getarrpos(Gogame *game, Vec pos)
+{
+	if (pos.x < 0 || pos.x >= game->size.x)
+		goto Err;
+	if (pos.y < 0 || pos.y >= game->size.y)
+		goto Err;
+	return pos.y * game->size.x + pos.x;
+Err:
+	werrstr("invalid position (%d, %d)", pos.x, pos.y);
+	return -1;
+}
+
+Gogame*
+newgame(Vec size)
+{
+	Gogame *game;
+	
+	game = mallocz(sizeof(Gogame), 1);
+	assert(game);
+	
+	game->board = mallocz(sizeof(Gostone) * size.x * size.y, 1);
+	assert(game->board);
+	game->size = size;
+	game->state = GBLACK;
+	return game;
+}
+
+void
+freegame(Gogame *game)
+{
+	assert(game);
+	if (game->board)
+		free(game->board);
+	free(game);
+}
+
+Gostone
+getcurrent(Gogame *game, Vec pos)
+{
+	int apos;
+	assert(game && game->board);
+	
+	apos = getarrpos(game, pos);
+	if (apos < 0)
+		return -1;
+	return game->board[apos];
+}
+
+static int
+isfree(Gogame *game, Vec pos, Gostone stone, Gostone opposite)
+{
+	Gostone s;
+	int nfreedoms = 4;
+	Vec v;
+	
+	for (int i = 0; i < 4; i++) {
+		switch (i) {
+		case 0:
+			v = pos + V(1, 0);
+			break;
+		case 1:
+			v = pos + V(0, 1);
+			break;
+		case 2:
+			v = pos - V(1, 0);
+			break;
+		case 3:
+			v = pos - V(0, 1);
+			break;
+		}
+		s = getcurrent(game, v);
+		if (s == opposite) {
+			nfreedoms--;
+			continue;
+		}
+		if (!isfree(game, v, stone, opposite))
+			return 0;
+	}
+	
+	return !!nfreedoms;
+}
+
+static int
+validmove(Gogame *game, Vec pos, Gostone stone)
+{
+	Gostone opposite = EMPTY;
+	
+	if (stone == WHITE)
+		opposite = BLACK;
+	if (stone == BLACK)
+		opposite = WHITE;
+	
+	if (opposite == EMPTY) {
+		werrstr("no valid stone");
+		return 0;
+	}
+	
+	switch (getcurrent(game, pos)) {
+		case BLACK:
+		case WHITE:
+			werrstr("there's already a stone");
+			return 0;
+		case WASBLACK:
+			if (stone == WHITE)
+				break;
+			werrstr("white on ex-white");
+			return 0;
+		case WASWHITE:
+			if (stone == BLACK)
+				break;
+			werrstr("black on ex-black");
+			return 0;
+		default:
+			return 1;
+	}
+	
+	return isfree(game, pos, stone, opposite);
+}
+
+int
+setstone(Gogame *game, Vec pos, Gostone stone)
+{
+	int apos;
+	assert(game && game->board);
+	
+	if (game->state != stone) {
+		werrstr("Can't set: It's not your turn");
+		return 0;
+	}
+	
+	apos = getarrpos(game, pos);
+	if (apos < 0)
+		return 0;
+	
+	if (!validmove(game, pos, stone))
+		return 0;
+	
+	game->board[apos] = stone;
+	validateboard(game);
+	
+	switch (stone) {
+	case WHITE:
+		game->state = GBLACK;
+		break;
+	case BLACK:
+		game->state = GWHITE;
+		break;
+	}
+	
+	return 1;
+}
+
+int
+passround(Gogame *game, Gostone stone)
+{
+	assert(game && game->board);
+	
+	print("state: %d, stone: %d\n", game->state, stone);
+	
+	if (game->state != stone) {
+		werrstr("Can't pass: It's not your turn");
+		return 0;
+	}
+	
+	switch (stone) {
+	case WHITE:
+		game->state = GBLACK;
+		break;
+	case BLACK:
+		game->state = GWHITE;
+		break;
+	default:
+		werrstr("bad move");
+		return 0;
+	}
+	return 1;
+}
+
+static void
+validateboard(Gogame *game)
+{
+}
--- /dev/null
+++ b/main.c
@@ -1,0 +1,40 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "dat.h"
+#include "fns.h"
+
+Gogame *game1 = nil;
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-s srvname]\n", argv0);
+	exits("usage");
+}
+
+char *srvname = "gofs";
+char *mtpt = "/mnt/gofs";
+
+void
+main(int argc, char **argv)
+{
+	Srv *fs;
+	
+	ARGBEGIN{
+	case 's':
+		srvname = EARGF(usage());
+		break;
+	case 'm':
+		mtpt = EARGF(usage());
+		break;
+	}ARGEND;
+	
+	game1 = newgame(V(19, 19));
+	
+	fs = getgenfs();
+	postmountsrv(fs, srvname, mtpt, MREPL);
+	exits(nil);
+}
--- /dev/null
+++ b/misc.c
@@ -1,0 +1,63 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <fcall.h>
+#include <9p.h>
+#include "dat.h"
+#include "fns.h"
+
+Vec
+_vec_pos_(Vec a)
+{
+	Vec r;
+	r.x = a.x;
+	r.y = a.y;
+	return r;
+}
+
+Vec
+_vec_neg_(Vec a)
+{
+	Vec r;
+	r.x = -a.x;
+	r.y = -a.y;
+	return r;
+}
+
+Vec
+_vec_add_(Vec a, Vec b)
+{
+	a.x += b.x;
+	a.y += b.y;
+	return a;
+}
+
+Vec
+_vec_sub_(Vec a, Vec b)
+{
+	a.x -= b.x;
+	a.y -= b.y;
+	return a;
+}
+
+int
+_vec_eq_(Vec a, Vec b)
+{
+	return a.x == b.x && a.y == b.y;
+}
+
+Vec
+_vec_asadd_(Vec *a, Vec b)
+{
+	a->x += b.x;
+	a->y += b.y;
+	return *a;
+}
+
+Vec
+_vec_assub_(Vec *a, Vec b)
+{
+	a->x -= b.x;
+	a->y -= b.y;
+	return *a;
+}
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,15 @@
+</$objtype/mkfile
+
+TARG=gofs
+OFILES=\
+	main.$O\
+	game.$O\
+	misc.$O\
+	fs.$O\
+
+HFILES=dat.h fns.h
+
+</sys/src/cmd/mkone
+
+fs.c: fs.fs mkfs.awk
+	mkfs.awk fs.fs > $target
--- /dev/null
+++ b/mkfs.awk
@@ -1,0 +1,143 @@
+#!/bin/awk -f
+
+function cleanpath(path) {
+	_name = path;
+	gsub(/\//, "_", _name);
+	gsub(/ /, "_", _name);
+	return _name;
+}
+
+function getfilename(path) {
+	_name = path;
+	gsub(/\//, "", _name);
+	return _name;
+}
+
+function startread() {
+	_name = cleanpath(currentpath);
+	printf("static void\nfsread_%s(Req *r)\n{\n", _name);
+}
+
+function startwrite() {
+	_name = cleanpath(currentpath);
+	printf("static void\nfswrite_%s(Req *r)\n{\n", _name);
+}
+
+function stopfunc() {
+	printf("}\n\n");
+}
+
+(state == 0 || state == 1) && /^$/ {
+	next;
+}
+
+state == 0 && /^\%\{/ {
+	state = 3; # passthrough
+	printf("#line %d \"%s\"\n", NR, FILENAME);
+	next;
+}
+
+state == 3 && /^\%\}/ {
+	state = 0;
+	next;
+}
+
+state == 3 {
+	print;
+}
+
+state == 0 || state == 1 && /^\// {
+	currentpath = $0;
+	paths[npaths++] = currentpath;
+	state = 1; # in file
+}
+
+state == 1 && /^[rw]\{/ {
+	state = 2; # passthrough
+	printf("#line %d \"%s\"\n", NR, FILENAME);
+	if ($1 == "r{")
+		startread();
+	else
+		startwrite();
+	next;
+}
+
+state == 2 && /^[rw]\}/ {
+	state = 1;
+	stopfunc();
+}
+
+state == 2 {
+	print;
+}
+
+BEGIN{
+	print("#include <u.h>");
+	print("#include <libc.h>");
+	print("#include <fcall.h>");
+	print("#include <thread.h>");
+	print("#include <9p.h>");
+	print("");
+	print("extern char *files[];");
+	print("extern int nfiles;");
+	print("");
+}
+
+END{
+	printf("#line %d \"%s\"\n", NR, FILENAME);
+	for (i = 0; i < npaths; i++) {
+		path = cleanpath(paths[i]);
+		printf("char *F_%s = \"%s\";\n", path, path);
+	}
+	print("");
+	
+	print("static void");
+	print("fsread(Req *r)");
+	print("{");
+	print("	void *a = r->fid->file->aux;");
+	for (i = 0; i < npaths; i++) {
+		path = cleanpath(paths[i]);
+		printf("	if (a == F_%s) fsread_%s(r); else\n", path, path);
+	}
+	print("		respond(r, \"niy\");");
+	print("}");
+	print("");
+	print("static void");
+	print("fswrite(Req *r)");
+	print("{");
+	print("	void *a = r->fid->file->aux;");
+	for (i = 0; i < npaths; i++) {
+		path = cleanpath(paths[i]);
+		printf("	if (a == F_%s) fswrite_%s(r); else\n", path, path);
+	}
+	print("		respond(r, \"niy\");");
+	print("}");
+	print("");
+	print("Srv fs = {");
+	print("	.read = fsread,");
+	print("	.write = fswrite,");
+	print("};");
+	print("");
+	print("static void");
+	print("populatetree(void)");
+	print("{");
+	
+	print("	File *f;");
+	for (i = 0; i < npaths; i++) {
+		path = paths[i];
+		name = getfilename(path);
+		path = cleanpath(path);
+		printf("	f = createfile(fs.tree->root, \"%s\", \"nil\", 0666, F_%s);\n", name, path);
+		print("	USED(f);");
+	}
+	
+	print("}");
+	print("");
+	print("Srv*");
+	print("getgenfs()");
+	print("{");
+	print("	fs.tree = alloctree(nil, nil, DMDIR|0777, nil);");
+	print("	populatetree();");
+	print("	return &fs;");
+	print("}");
+}
--