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) {+ next
+ }
+ gsub(/"/, "\\\"")
+ gsub(/^/, "\"")
+ gsub(/$/, "\"")
+}
--- /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
--
⑨