commit cf702fcdf9776c99c52b6ad945ea4e166a276bee
parent b1172113893fc77e2f8174c6e55bc19583d5272d
Author: Pavel Renev <an2qzavok@gmail.com>
Date: Sat, 28 Aug 2021 21:57:29 +0000
accept into files and write images
Diffstat:
M | TODO | | | 21 | ++++++++++++++++++--- |
M | fs.c | | | 178 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
M | richterm.c | | | 19 | +++++++++++++++---- |
3 files changed, 184 insertions(+), 34 deletions(-)
diff --git a/TODO b/TODO
@@ -1,8 +1,23 @@
# images
-draw them
+something in image drawing routines is broken, not handling it well when
+image's rectangle.min != ZP.
-# links
+# fs_flush
-highlight them and add 3-button menu for interacting with them
+We need to prevent server from locking up.
+See 9pqueue(2)
+
+I think I need an independent queue for every blocking file.
+
+# fix crashes
+
+when you write into files, also related to file trunkating.
+
+# simplify file handling
+
+Add Array for text to objects, and use standard arrayread/arraywrite.
+Copy array back to global text buffer on destroyfid
+
+Do the same for fonts.
diff --git a/fs.c b/fs.c
@@ -8,27 +8,33 @@
#include "array.h"
#include "richterm.h"
-File *new, *ctl, *text, *cons, *consctl, *menu;
-Object *newobj;
-File *fsroot;
-Channel *consc, *ctlc;
Array *consbuf, *ctlbuf, *menubuf;
+Channel *consc, *ctlc;
+File *fsroot;
+File *cons, *consctl, *ctl, *menu, *new, *text;
+Object *newobj;
+Reqqueue *rq;
+
-void fs_open(Req *);
-void fs_read(Req *);
-void fs_write(Req *);
-void ftree_destroy(File *);
-char * textread(Req *);
-char * textwrite(Req *);
char * arrayread(Req *);
char * arraywrite(Req *);
-char * fontread(Req *);
-char * fontwrite(Req *);
char * consread(Req *);
char * conswrite(Req *);
char * ctlread(Req *);
char * ctlwrite(Req *);
+char * fontread(Req *);
+char * fontwrite(Req *);
char * newread(Req *);
+char * textread(Req *);
+char * textwrite(Req *);
+void delayedread(Req *);
+void fs_destroyfid(Fid *);
+void fs_flush(Req *);
+void fs_open(Req *);
+void fs_read(Req *);
+void fs_write(Req *);
+void imageclose(Fid *);
+
int
initfs(char *srvname)
@@ -37,9 +43,12 @@ initfs(char *srvname)
.open = fs_open,
.read = fs_read,
.write = fs_write,
+ .flush = fs_flush,
+ .destroyfid = fs_destroyfid,
};
newobj = nil;
consbuf = nil;
+ rq = reqqueuecreate();
menubuf = arraycreate(sizeof(char), 1024, nil);
consc = chancreate(sizeof(Array *), 1024);
ctlc = chancreate(sizeof(Array *), 1024);
@@ -145,16 +154,30 @@ ctlcmd(char *buf)
return nil;
}
+
+void
+fs_destroyfid(Fid *fid)
+{
+ if (fid->file == nil) return;
+ if (fid->file->aux == nil) return;
+ if (((Faux *)fid->file->aux)->obj == nil) return;
+ if (((Faux *)fid->file->aux)->obj->fimage == nil) return;
+ if (fid->file == ((Faux *)fid->file->aux)->obj->fimage) {
+ imageclose(fid);
+ }
+}
+
void
fs_open(Req *r)
{
+ if (r->fid->omode && OTRUNC) {
+// if ((r->fid->file->aux != nil) && (((Faux *)r->fid->file->aux)->data != nil))
+// ((Faux *)r->fid->file->aux)->data->count = 0;
+ }
if (r->fid->file == new) {
newobj = objectcreate();
mkobjectftree(newobj, fsroot);
objinsertbeforelast(newobj);
-
- /* Because our newobj is created empty, there's no need
- to move text from olast around. */
}
respond(r, nil);
}
@@ -162,14 +185,7 @@ fs_open(Req *r)
void
fs_read(Req *r)
{
- Faux *aux;
- char *s;
- aux = r->fid->file->aux;
- if (aux != nil) {
- if (aux->read != nil) s = aux->read(r);
- else s = "no read";
- } else s = "fs_read: f->aux is nil";
- respond(r, s);
+ reqqueuepush(rq, r, delayedread);
}
void
@@ -188,6 +204,25 @@ fs_write(Req *r)
respond(r, s);
}
+void
+fs_flush(Req *r)
+{
+ respond(r, nil);
+}
+
+void
+delayedread(Req *r)
+{
+ Faux *aux;
+ char *s;
+ aux = r->fid->file->aux;
+ if (aux != nil) {
+ if (aux->read != nil) s = aux->read(r);
+ else s = "no read";
+ } else s = "fs_read: f->aux is nil";
+ respond(r, s);
+}
+
char *
arrayread(Req *r)
{
@@ -204,12 +239,21 @@ arrayread(Req *r)
char *
arraywrite(Req *r)
{
+ long count;
Array *data;
- data = ((Faux *)r->fid->file->aux)->data;
qlock(rich.l);
- data->count = 0;
- arraygrow(data, r->ifcall.count, r->ifcall.data);
+ data = ((Faux *)r->fid->file->aux)->data;
+ count = r->ifcall.count + r->ifcall.offset;
+ if (count > data->count) arraygrow(data, count - data->count, nil);
+ else data->count = count;
+
+// data->count = 0;
+// arraygrow(data, r->ifcall.count, r->ifcall.data);
+ qlock(data->l);
+ memcpy(data->p + r->ifcall.offset, r->ifcall.data, r->ifcall.count);
+ qunlock(data->l);
r->ofcall.count = r->ifcall.count;
+ r->fid->file->length = data->count;
qunlock(rich.l);
return nil;
}
@@ -236,6 +280,8 @@ textread(Req *r)
readbuf(r, s, n - obj->offset);
+ r->fid->file->length = objtextlen(obj);
+
qunlock(rich.text->l);
qunlock(rich.l);
return nil;
@@ -325,7 +371,7 @@ conswrite(Req *r)
Array *a;
a = arraycreate(sizeof(char), r->ifcall.count, nil);
arraygrow(a, r->ifcall.count, r->ifcall.data);
- send(insertc, &a);
+ nbsend(insertc, &a);
r->ofcall.count = r->ifcall.count;
return nil;
}
@@ -363,3 +409,81 @@ newread(Req *r)
readstr(r, newobj->id);
return nil;
}
+
+void
+imageclose(Fid *fid)
+{
+ Array *data;
+ Rectangle r;
+ char *p;
+ int compressed, m;
+ long n;
+ ulong chan;
+ Faux *aux;
+
+
+ compressed = 0;
+ aux = fid->file->aux;
+ data = aux->data;
+
+ if (aux->obj->image != nil) return;
+
+ qlock(data->l);
+ p = data->p;
+ n = data->count;
+ if (n < 10) {
+ data->count = 0;
+ aux->obj->ftext->length = 0;
+ qunlock(data->l);
+ fprint(2, "imageclose: image file too short\n");
+ return;
+ }
+ if (strncmp("compressed\n", p, 11) == 0) {
+ p += 11;
+ n -= 11;
+ compressed = 1;
+ }
+ if (n < 60) {
+ data->count = 0;
+ aux->obj->ftext->length = 0;
+ qunlock(data->l);
+ fprint(2, "imageclose: image file too short\n");
+ return;
+ }
+ if ((chan = strtochan(p)) == 0) {
+ data->count = 0;
+ aux->obj->ftext->length = 0;
+ qunlock(data->l);
+ fprint(2, "imageclose: image channel unknown: %12s\n", p);
+ return;
+ }
+ p += 12; n -= 12;
+ r.min.x = atoi(p); p += 12; n -= 12;
+ r.min.y = atoi(p); p += 12; n -= 12;
+ r.max.x = atoi(p); p += 12; n -= 12;
+ r.max.y = atoi(p); p += 12; n -= 12;
+
+ lockdisplay(display);
+ aux->obj->image = allocimage(display, r, chan, 0, DBlue);
+ if (aux->obj->image == nil) {
+ data->count = 0;
+ aux->obj->ftext->length = 0;
+ qunlock(data->l);
+ unlockdisplay(display);
+ fprint(2, "imageclose: allocimage failed: %r\n");
+ return;
+ }
+ if (compressed != 0) m = cloadimage(aux->obj->image, r, (uchar *)p, n);
+ else m = loadimage(aux->obj->image, r, (uchar *)p, n);
+ if (m != n) {
+ fprint(2, "imageclose: failed to load image\n");
+ freeimage(aux->obj->image);
+ data->count = 0;
+ aux->obj->ftext->length = 0;
+ }
+
+ unlockdisplay(display);
+ qunlock(data->l);
+
+ return;
+}
diff --git a/richterm.c b/richterm.c
@@ -649,14 +649,25 @@ drawobject(Object *obj, Point *cur)
*cur = obj->prev->nextlinept;
}
- obj->startpt = *cur;
-
obj->nextlinept = Pt(0, cur->y + obj->font->height);
+
if ((obj->prev != nil) && (cur->x != 0)) {
if (obj->nextlinept.y < obj->prev->nextlinept.y)
obj->nextlinept.y = obj->prev->nextlinept.y;
}
+ if (obj->image != nil) {
+ Rectangle r;
+ r = rectaddpt(obj->image->r,
+ subpt(addpt(*cur, rich.page.r.min), rich.page.scroll));
+ draw(screen, r, obj->image, nil, ZP);
+ cur->x += Dx(r);
+ if (cur->y + Dy(r) > obj->nextlinept.y)
+ obj->nextlinept.y = cur->y + Dy(r);
+ }
+
+ obj->startpt = *cur;
+
if (obj->next == nil) n = rich.text->count;
else n = obj->next->offset;
@@ -679,7 +690,6 @@ redraw(Object *)
obj = nil;
cur = ZP;
qlock(rich.l);
-
for (i = 0; i < rich.objects->count; i++) {
if (arrayget(rich.objects, i, &obj) == nil)
sysfatal("redraw: %r");
@@ -803,6 +813,7 @@ objsettext(Object *obj, char *data, long count)
qunlock(rich.text->l);
qlock(rich.objects->l);
+ if (obj->ftext != nil) obj->ftext->length = count;
for (obj = obj->next; obj != nil; obj = obj->next) {
obj->offset += dn;
}
@@ -875,12 +886,12 @@ ruseract(int f)
nbsend(ctlc, &a);
}
-char genbuf[1024];
char *
rusergen(int f)
{
+ static char genbuf[1024];
int i, k;
char *ps, *pe;
memset(genbuf, 0, sizeof(genbuf));