shithub: oai

Download patch

ref: 0c3b7d23fead592c182b75b5bae25110d2f5ac09
parent: 785ad1d9d08166d95344f1d7f53346eb27cca31c
author: sirjofri <sirjofri@sirjofri.de>
date: Sat Feb 28 07:13:21 EST 2026

extracts tool code to separate files

--- a/mkfile
+++ b/mkfile
@@ -5,9 +5,15 @@
 OFILES=oailib.$O
 CLEANFILES=`{ls *.princ >[2]/dev/null}
 
+tools=`{ls tools/*.tool}
+
 </sys/src/cmd/mkmany
 
-oai.$O: oai_common.princ plan9.princ front.princ
+oai.$O: oai_common.princ plan9.princ front.princ ${tools:%.tool=%.cinc}
+
+%.cinc: %.tool
+	file=`{basename $prereq}
+	tools/gencode.awk <$prereq >$target
 
 %.princ: %.prompt
 	sed 's/"/\\"/g;s/^/"/g;s/$/\\n"/g' $prereq > $target
--- a/oai.c
+++ b/oai.c
@@ -17,6 +17,7 @@
 static int yolomode = 0;
 
 static char *callfunc(char*);
+static char *writetofile(char*, char*);
 
 static int
 allowed(OToolcall toolcall, int destructive)
@@ -58,213 +59,12 @@
 	return smprint("%s request aborted by user!", tc.name);
 }
 
-static char*
-list_files(OToolcall tc, void*)
-{
-	String *str;
-	int n, i, fd;
-	Dir *dirbuf;
-	char *s;
-	JSON *j, *jf;
-	
-	if (!allowed(tc, 0))
-		return abortcall(tc);
-	
-	j = jsonparse(tc.arguments);
-	jf = jsonbyname(j, "folder");
-	s = jsonstr(jf);
-	if (!(s && s[0])) {
-		fprint(2, "list_files: invalid folder!");
-		jsonfree(j);
-		return strdup("list_files: invalid folder");
-	}
-	
-	dirbuf = dirstat(s);
-	if (!(dirbuf->mode&DMDIR)) {
-		s = smprint("%s is a file, not a folder", s);
-		free(dirbuf);
-		jsonfree(j);
-		return s;
-	}
-	
-	fd = open(s, OREAD);
-	if (fd < 0)
-		return strdup("");
-	
-	jsonfree(j);
-	
-	n = dirreadall(fd, &dirbuf);
-	close(fd);
-	if (n < 0)
-		return strdup("");
-	
-	str = s_new();
-	for (i = 0; i < n; i++) {
-		str = s_append(str, dirbuf[i].name);
-		if (dirbuf[i].mode&DMDIR)
-			str = s_append(str, "/");
-		str = s_append(str, "\n");
-	}
-	free(dirbuf);
-	s = strdup(s_to_c(str));
-	s_free(str);
-	return s;
-}
+#include "tools/listfiles.cinc"
+#include "tools/readfile.cinc"
+#include "tools/man.cinc"
+#include "tools/writefile.cinc"
+#include "tools/cmd.cinc"
 
-static char* listfilesdesc = "list all files in the specified directory, similar to `ls` command. Paths are relative to the current working directory. Use `.` for the current directory.";
-static char* listfilesargs = "{"
-"	\"type\": \"object\","
-"	\"properties\": {"
-"		\"folder\": {"
-"			\"type\": \"string\","
-"			\"description\": \"relative or absolute path to the folder.\""
-"		}"
-"	},"
-"	\"required\": [ \"folder\" ]"
-"}";
-
-static char*
-read_file(OToolcall toolcall, void*)
-{
-	JSON *j, *fj;
-	char *file;
-	Biobuf *io;
-	char *s;
-	Dir *dir;
-	
-	if (!allowed(toolcall, 0))
-		return abortcall(toolcall);
-	
-	j = jsonparse(toolcall.arguments);
-	fj = jsonbyname(j, "file");
-	if (!fj) {
-		fprint(2, "no file in read_file request!\n");
-		jsonfree(j);
-		return strdup("bad request in read_file!\n");
-	}
-	
-	file = jsonstr(fj);
-	if (!(file && file[0])) {
-		fprint(2, "invalid file in read_file request!\n");
-		jsonfree(j);
-		return strdup("bad request in read_file: no file!\n");
-	}
-	
-	dir = dirstat(file);
-	if (!dir)
-		return smprint("error opening file: %r\n");
-	
-	if (dir->mode&DMDIR) {
-		s = smprint("error: file is a directory\n");
-		free(dir);
-		return s;
-	}
-	
-	io = Bopen(file, OREAD);
-	if (!io) {
-		fprint(2, "open file: %r\n");
-		return smprint("open file in read_file: %r");
-	}
-	
-	fprint(2, "read_file: %s\n", file);
-	
-	s = Brdstr(io, 0, 0);
-	jsonfree(j);
-	Bterm(io);
-	return s;
-}
-
-static char *readfiledesc = "read the contents of a specified file, similar to the `cat` unix command. Especially useful on a Plan 9 system for interaction with filesystems.";
-static char *readfileargs = "{"
-"	\"type\": \"object\","
-"	\"properties\": {"
-"		\"file\": {"
-"			\"type\": \"string\","
-"			\"description\": \"relative or absolute path to the file\""
-"		}"
-"	},"
-"	\"required\": [ \"file\" ]"
-"}";
-
-static char*
-lookman(OToolcall tc, void*)
-{
-	JSON *j, *jk;
-	char *s, *cmd;
-	
-	if (!allowed(tc, 0))
-		return abortcall(tc);
-	
-	j = jsonparse(tc.arguments);
-	jk = jsonbyname(j, "keyword");
-	s = jsonstr(jk);
-	if (!(s && s[0]))
-		return strdup("lookman: missing keyword");
-	
-	cmd = smprint("lookman '%s'", s);
-	jsonfree(j);
-	s = callfunc(cmd);
-	free(cmd);
-	return s;
-}
-
-static char *lookmandesc = "Search the man pages for the specified keyword. The result shows the name of the man page and the section number.";
-static char *lookmanargs = "{"
-"	\"type\": \"object\","
-"	\"properties\": {"
-"		\"keyword\": {"
-"			\"type\": \"string\","
-"			\"description\": \"keyword to search for in the man pages\""
-"		}"
-"	},"
-"	\"required\": [ \"keyword\" ]"
-"}";
-
-static char*
-man(OToolcall tc, void*)
-{
-	JSON *j, *js, *jn;
-	char *sec, *name;
-	char *s, *cmd;
-	
-	if (!allowed(tc, 0))
-		return abortcall(tc);
-	
-	j = jsonparse(tc.arguments);
-	js = jsonbyname(j, "section");
-	jn = jsonbyname(j, "name");
-	
-	sec = jsonstr(js);
-	name = jsonstr(jn);
-	if (!(sec && name))
-		return strdup("man: missing section or name");
-	
-	if (!(sec[0] && name[0]))
-		return strdup("man: empty section or name");
-	
-	cmd = smprint("man '%s' '%s'", sec, name);
-	jsonfree(j);
-	s = callfunc(cmd);
-	free(cmd);
-	return s;
-}
-
-static char *mandesc = "get the contents of the specified man page.";
-static char *manargs = "{"
-"	\"type\": \"object\","
-"	\"properties\": {"
-"		\"section\": {"
-"			\"type\": \"string\","
-"			\"description\": \"section number of the man page\""
-"		},"
-"		\"name\": {"
-"			\"type\": \"string\","
-"			\"description\": \"name of the section\""
-"		}"
-"	},"
-"	\"required\": [ \"section\", \"name\" ]"
-"}";
-
 OTool *tools = nil;
 
 static void
@@ -274,6 +74,29 @@
 	maketool(tools, Function, "read_file", readfiledesc, readfileargs, read_file, nil);
 	maketool(tools, Function, "search_man", lookmandesc, lookmanargs, lookman, nil);
 	maketool(tools, Function, "read_man", mandesc, manargs, man, nil);
+	maketool(tools, Function, "write_file", writefiledesc, writefileargs, writefile, nil);
+}
+
+static char*
+writetofile(char *file, char *content)
+{
+	int fd;
+	long n;
+	char *ret;
+	
+	fd = open(file, OWRITE|OTRUNC);
+	if (fd < 0)
+		fd = create(file, OWRITE|OTRUNC, 0666);
+	if (fd < 0)
+		return smprint("cannot write to file: %r");
+	
+	n = strlen(content);
+	if (write(fd, content, n) != n)
+		ret = strdup("write error: %r");
+	else
+		ret = strdup("file written successfully");
+	close(fd);
+	return ret;
 }
 
 static char*
--- /dev/null
+++ b/tools/cmd.tool
@@ -1,0 +1,22 @@
+
+
+static char *cmddesc = "call a function in the rc shell.";
+static char *cmdargs = ""
+%%json
+{
+	"type": "object",
+	"properties": {
+		"cmd": {
+			"type": "string",
+			"description": "name or path of the command"
+		},
+		"args": {
+			"type": "array",
+			"description": "command line arguments",
+			"items": { "type": "string" }
+		}
+	},
+	"required": [ "cmd", "args" ]
+}
+%/json
+;
\ No newline at end of file
--- /dev/null
+++ b/tools/gencode.awk
@@ -1,0 +1,26 @@
+#!/bin/awk -f
+
+BEGIN{
+	printf "#line 0 \"tools/%s\"\n", ENVIRON["file"]
+}
+
+$1 == "%%json" {
+	convert = 1
+	next
+}
+
+$1 == "%/json" {
+	convert = 0
+	next
+}
+
+{
+	if (!convert) {
+		print
+		next
+	}
+	gsub(/"/, "\\\"")
+	gsub(/^/, "\"")
+	gsub(/$/, "\"")
+	print
+}
--- /dev/null
+++ b/tools/listfiles.tool
@@ -1,0 +1,68 @@
+static char*
+list_files(OToolcall tc, void*)
+{
+	String *str;
+	int n, i, fd;
+	Dir *dirbuf;
+	char *s;
+	JSON *j, *jf;
+	
+	if (!allowed(tc, 0))
+		return abortcall(tc);
+	
+	j = jsonparse(tc.arguments);
+	jf = jsonbyname(j, "folder");
+	s = jsonstr(jf);
+	if (!(s && s[0])) {
+		fprint(2, "list_files: invalid folder!");
+		jsonfree(j);
+		return strdup("list_files: invalid folder");
+	}
+	
+	dirbuf = dirstat(s);
+	if (!(dirbuf->mode&DMDIR)) {
+		s = smprint("%s is a file, not a folder", s);
+		free(dirbuf);
+		jsonfree(j);
+		return s;
+	}
+	
+	fd = open(s, OREAD);
+	if (fd < 0)
+		return strdup("");
+	
+	jsonfree(j);
+	
+	n = dirreadall(fd, &dirbuf);
+	close(fd);
+	if (n < 0)
+		return strdup("");
+	
+	str = s_new();
+	for (i = 0; i < n; i++) {
+		str = s_append(str, dirbuf[i].name);
+		if (dirbuf[i].mode&DMDIR)
+			str = s_append(str, "/");
+		str = s_append(str, "\n");
+	}
+	free(dirbuf);
+	s = strdup(s_to_c(str));
+	s_free(str);
+	return s;
+}
+
+static char* listfilesdesc = "list all files in the specified directory, similar to `ls` command. Paths are relative to the current working directory. Use `.` for the current directory.";
+static char* listfilesargs = ""
+%%json
+{
+	"type": "object",
+	"properties": {
+		"folder": {
+			"type": "string",
+			"description": "relative or absolute path to the folder."
+		}
+	},
+	"required": [ "folder" ]
+}
+%/json
+;
\ No newline at end of file
--- /dev/null
+++ b/tools/man.tool
@@ -1,0 +1,86 @@
+static char*
+lookman(OToolcall tc, void*)
+{
+	JSON *j, *jk;
+	char *s, *cmd;
+	
+	if (!allowed(tc, 0))
+		return abortcall(tc);
+	
+	j = jsonparse(tc.arguments);
+	jk = jsonbyname(j, "keyword");
+	s = jsonstr(jk);
+	if (!(s && s[0]))
+		return strdup("lookman: missing keyword");
+	
+	cmd = smprint("lookman '%s'", s);
+	jsonfree(j);
+	s = callfunc(cmd);
+	free(cmd);
+	return s;
+}
+
+static char *lookmandesc = "Search the man pages for the specified keyword. The result shows the name of the man page and the section number.";
+static char *lookmanargs = ""
+%%json
+{
+	"type": "object",
+	"properties": {
+		"keyword": {
+			"type": "string",
+			"description": "keyword to search for in the man pages"
+		}
+	},
+	"required": [ "keyword" ]
+}
+%/json
+;
+
+static char*
+man(OToolcall tc, void*)
+{
+	JSON *j, *js, *jn;
+	char *sec, *name;
+	char *s, *cmd;
+	
+	if (!allowed(tc, 0))
+		return abortcall(tc);
+	
+	j = jsonparse(tc.arguments);
+	js = jsonbyname(j, "section");
+	jn = jsonbyname(j, "name");
+	
+	sec = jsonstr(js);
+	name = jsonstr(jn);
+	if (!(sec && name))
+		return strdup("man: missing section or name");
+	
+	if (!(sec[0] && name[0]))
+		return strdup("man: empty section or name");
+	
+	cmd = smprint("man '%s' '%s'", sec, name);
+	jsonfree(j);
+	s = callfunc(cmd);
+	free(cmd);
+	return s;
+}
+
+static char *mandesc = "get the contents of the specified man page.";
+static char *manargs = ""
+%%json
+{
+	"type": "object",
+	"properties": {
+		"section": {
+			"type": "string",
+			"description": "section number of the man page"
+		},
+		"name": {
+			"type": "string",
+			"description": "name of the section"
+		}
+	},
+	"required": [ "section", "name" ]
+}
+%/json
+;
\ No newline at end of file
--- /dev/null
+++ b/tools/readfile.tool
@@ -1,0 +1,66 @@
+static char*
+read_file(OToolcall toolcall, void*)
+{
+	JSON *j, *fj;
+	char *file;
+	Biobuf *io;
+	char *s;
+	Dir *dir;
+	
+	if (!allowed(toolcall, 0))
+		return abortcall(toolcall);
+	
+	j = jsonparse(toolcall.arguments);
+	fj = jsonbyname(j, "file");
+	if (!fj) {
+		fprint(2, "no file in read_file request!\n");
+		jsonfree(j);
+		return strdup("bad request in read_file!\n");
+	}
+	
+	file = jsonstr(fj);
+	if (!(file && file[0])) {
+		fprint(2, "invalid file in read_file request!\n");
+		jsonfree(j);
+		return strdup("bad request in read_file: no file!\n");
+	}
+	
+	dir = dirstat(file);
+	if (!dir)
+		return smprint("error opening file: %r\n");
+	
+	if (dir->mode&DMDIR) {
+		s = smprint("error: file is a directory\n");
+		free(dir);
+		return s;
+	}
+	
+	io = Bopen(file, OREAD);
+	if (!io) {
+		fprint(2, "open file: %r\n");
+		return smprint("open file in read_file: %r");
+	}
+	
+	fprint(2, "read_file: %s\n", file);
+	
+	s = Brdstr(io, 0, 0);
+	jsonfree(j);
+	Bterm(io);
+	return s;
+}
+
+static char *readfiledesc = "read the contents of a specified file, similar to the `cat` unix command. Especially useful on a Plan 9 system for interaction with filesystems.";
+static char *readfileargs = ""
+%%json
+{
+	"type": "object",
+	"properties": {
+		"file": {
+			"type": "string",
+			"description": "relative or absolute path to the file"
+		}
+	},
+	"required": [ "file" ]
+}
+%/json
+;
\ No newline at end of file
--- /dev/null
+++ b/tools/writefile.tool
@@ -1,0 +1,58 @@
+static char*
+writefile(OToolcall tc, void*)
+{
+	JSON *j, *jf, *jc;
+	char *file, *content;
+	char *s;
+	
+	if (!allowed(tc, 1))
+		return abortcall(tc);
+	
+	j = jsonparse(tc.arguments);
+	jf = jsonbyname(j, "file");
+	jc = jsonbyname(j, "content");
+	
+	if (!jf)
+		goto Errnofile;
+	if (!jc)
+		goto Errnocont;
+	
+	file = jsonstr(jf);
+	content = jsonstr(jc);
+	if (!file)
+		goto Errnofile;
+	if (!content)
+		goto Errnocont;
+	
+	s = writetofile(file, content);
+	jsonfree(j);
+	return s;
+
+Errnofile:
+	jsonfree(j);
+	return strdup("error: no file");
+	
+Errnocont:
+	jsonfree(j);
+	return strdup("error: no content");
+}
+
+static char *writefiledesc = "overwrite a file. If the file doesn't exist yet, create it.";
+static char *writefileargs = ""
+%%json
+{
+	"type": "object",
+	"properties": {
+		"file": {
+			"type": "string",
+			"description": "path to the file"
+		},
+		"content": {
+			"type": "string",
+			"description": "new content of the file. Existing content will be overwritten."
+		}
+	},
+	"required": [ "file", "content" ]"
+}
+%/json
+;
\ No newline at end of file
--