summaryrefslogtreecommitdiff
path: root/emu/port/devsnarf.c
diff options
context:
space:
mode:
Diffstat (limited to 'emu/port/devsnarf.c')
-rw-r--r--emu/port/devsnarf.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/emu/port/devsnarf.c b/emu/port/devsnarf.c
new file mode 100644
index 00000000..4778c130
--- /dev/null
+++ b/emu/port/devsnarf.c
@@ -0,0 +1,161 @@
+/*
+ * host's snarf buffer
+ */
+
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+enum{
+ Qdir,
+ Qsnarf,
+
+ Maxsnarf= 100*1024
+};
+
+static
+Dirtab snarftab[]={
+ ".", {Qdir, 0, QTDIR}, 0, 0555,
+ "snarf", {Qsnarf}, 0, 0666,
+};
+
+static QLock snarflock; /* easiest to synchronise all access */
+
+static Chan*
+snarfattach(char *spec)
+{
+ return devattach('^', spec);
+}
+
+static Walkqid*
+snarfwalk(Chan *c, Chan *nc, char **name, int nname)
+{
+ return devwalk(c, nc, name, nname, snarftab, nelem(snarftab), devgen);
+}
+
+static int
+snarfstat(Chan* c, uchar *db, int n)
+{
+ return devstat(c, db, n, snarftab, nelem(snarftab), devgen);
+}
+
+static Chan*
+snarfopen(Chan* c, int omode)
+{
+ c = devopen(c, omode, snarftab, nelem(snarftab), devgen);
+ if(c->qid.path == Qsnarf){
+ if(c->mode == ORDWR || c->mode == OWRITE){
+ qlock(&snarflock);
+ free(c->aux);
+ c->aux = nil;
+ qunlock(&snarflock);
+ }
+ }
+ return c;
+}
+
+static void
+snarfclose(Chan* c)
+{
+ if((c->flag & COPEN) == 0)
+ return;
+ if(c->qid.path == Qsnarf){
+ /* this must be the last reference: no need to lock */
+ if(c->mode == ORDWR || c->mode == OWRITE){
+ if(!waserror()){
+ clipwrite(c->aux);
+ poperror();
+ }
+ }
+ free(c->aux);
+ }
+}
+
+static long
+snarfread(Chan* c, void* a, long n, vlong offset)
+{
+ void *p;
+
+ switch((ulong)c->qid.path){
+ case Qdir:
+ return devdirread(c, a, n, snarftab, nelem(snarftab), devgen);
+ case Qsnarf:
+ qlock(&snarflock);
+ if(waserror()){
+ qunlock(&snarflock);
+ nexterror();
+ }
+ if(offset == 0){
+ p = c->aux;
+ c->aux = nil;
+ free(p);
+ c->aux = clipread();
+ }
+ if(c->aux != nil)
+ n = readstr(offset, a, n, c->aux);
+ else
+ n = 0;
+ poperror();
+ qunlock(&snarflock);
+ break;
+ default:
+ n=0;
+ break;
+ }
+ return n;
+}
+
+static long
+snarfwrite(Chan* c, void* va, long n, vlong offset)
+{
+ ulong l;
+ char *p;
+
+ switch((ulong)c->qid.path){
+ case Qsnarf:
+ /* append only */
+ USED(offset); /* not */
+ qlock(&snarflock);
+ if(waserror()){
+ qunlock(&snarflock);
+ nexterror();
+ }
+ if(c->aux != nil)
+ l = strlen(c->aux);
+ else
+ l = 0;
+ if(l+n > Maxsnarf)
+ error(Etoobig);
+ c->aux = realloc(c->aux, l+n+1);
+ if((p = c->aux) == nil)
+ error(Enovmem);
+ memmove(p+l, va, n);
+ p[l+n] = 0;
+ snarftab[1].qid.vers++;
+ poperror();
+ qunlock(&snarflock);
+ break;
+ default:
+ error(Ebadusefd);
+ }
+ return n;
+}
+
+Dev snarfdevtab = {
+ '^',
+ "snarf",
+
+ devinit,
+ snarfattach,
+ snarfwalk,
+ snarfstat,
+ snarfopen,
+ devcreate,
+ snarfclose,
+ snarfread,
+ devbread,
+ snarfwrite,
+ devbwrite,
+ devremove,
+ devwstat,
+};