wily-0.13.41/ 40755 2743 200 0 6506117541 11066 5ustar garypgradwily-0.13.41/README100644 2743 200 4106 6251153545 12045 0ustar garypgrad * The author of this software is Gary Capell. * Copyright (c) 1995, 1996 by Gary Capell. * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY. IN PARTICULAR, THE AUTHOR DOES NOT MAKE ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. Wily is an emulation of Acme. Acme was written by Rob Pike. Nearly all of the nifty ideas (but none of the source code) in Wily are taken from Acme. Read INSTALL for hints on how to build. Ignore error messages like "no libXg configuration in dir sam" If 'make' fails, try 'gmake' (GNU make). Mail wilyfans-request@jli.com to subscribe to a list discussing wily (and to find out about new releases). Please mail gary@cs.su.oz.au if you get this working and you like it, or mail wilyfans@jli.com if you have problems getting something to work. Some Wily documentation is in wily/Doc and more will soon follow. Start with wily/Doc/00README README.sam contains some info about Sam and libXg, from which a bunch of code for wily was grabbed. Wily is Unicode aware, so with the right font files it will display all sorts of international characters. See http://www.cs.su.oz.au/~matty/9term/index.html for documentation on another Unicode-aware program (using the same libraries), including some screen shots showing some of the characters available, and a bundle of (mono-space) Unicode fonts. Wily is nicest to use with a proportional font. Use wily -fn or use X defaults. Wily.ad is my application defaults file, prop.9.font and fixed.9.font are my two font files. These refer to some fonts distributed with 9term. I would be _very_ happy if someone contributed a full set of proportional Unicode fonts. wily-0.13.41/.exclude100644 2743 200 52 6253474013 12551 0ustar garypgradinclude/RCS wily/RCS libmsg/RCS libXg/RCS wily-0.13.41/tools/ 40755 2743 200 0 6373554302 12230 5ustar garypgradwily-0.13.41/tools/python/ 40755 2743 200 0 6415660304 13546 5ustar garypgradwily-0.13.41/tools/python/wilymodule.c100644 2743 200 25554 6415661377 16247 0ustar garypgrad#include "Python.h" #ifndef NDEBUG #define NDEBUG #endif #include #include #include static PyObject *ErrorObject; /* Declarations for objects of type Connection */ typedef struct { PyObject_HEAD /* XXXX Add your own stuff here */ Handle *h; } conobject; staticforward PyTypeObject Contype; static char con_list__doc__[] = "List currently open windows list() Returns list of (name, id) tuples representing currently open windows" ; static PyObject * con_list(conobject *self, PyObject *args) { char *err; char *buf; if (!PyArg_ParseTuple(args, "")) return NULL; if((err = rpc_list(self->h, &buf))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("s", buf); } static char con_win__doc__[] = "open a window win(name:string, isBackedUp:integer) Returns an integer window identifier, to be used for later operations on the window " ; static PyObject * con_win(conobject *self, PyObject *args) { char *s; Id id; char *err; int isbackedup; if (!PyArg_ParseTuple(args, "si", &s, &isbackedup)) { return NULL; } if((err = rpc_new(self->h, s, &id, (ushort)isbackedup))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("i", id); } static char con_event__doc__[] = "event() returns an event tuple (w, t, r0, r1, s), whose fields are: w: window identifier t: event type r0, r1: affected range s: string The meaning (if any) of the values of r0, r1 and s depend on the event type 't' " ; static PyObject * con_event(conobject *self, PyObject *args) { Msg m; char *err; PyObject *o; if (!PyArg_ParseTuple(args, "")) return NULL; if(rpc_event(self->h, &m)){ PyErr_SetString(ErrorObject, err); return NULL; } o = Py_BuildValue("(iills)", m.w, m.t, m.r.p0, m.r.p1, m.s); free(m.s); return o; } static char con_eventwouldblock__doc__[] = "eventwouldblock() If eventwouldblock() returns true, calling event() might have to wait. If eventwouldblock() returns false, calling event() would return immediately because an event is already queued up and waiting"; static PyObject * con_eventwouldblock(conobject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; return Py_BuildValue("b", rpc_wouldblock(self->h)); } static char con_bounce__doc__[] = "bounce(tuple) Called with an event tuple as returned by event(). Returns None" ; static PyObject * con_bounce(conobject *self, PyObject *args) { Msg m; char *err; if (!PyArg_ParseTuple(args, "(iills)", &m.w, &m.t, &m.r.p0, &m.r.p1, &m.s)) return NULL; if(rpc_bounce(self->h, &m)){ PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_attach__doc__[] = "attach(w:integer, mask:integer) 'w' is a window identifier as obtained by new() or list(). 'mask' is a bitmask of event types. Sets the mask of events to be sent to us. "; static PyObject * con_attach(conobject *self, PyObject *args) { Id id; int mask; char *err; if (!PyArg_ParseTuple(args, "ii",&id, &mask)) return NULL; if((err = rpc_attach(self->h, id, (ushort) mask))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_setname__doc__[] = "setname(w:integer, s:string) Set w's name to 's'"; static PyObject * con_setname(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "is", &id, &name)) return NULL; if ((err = rpc_setname(self->h, id, name))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_settools__doc__[] = "settools(w:integer, s:string) Set w's tools to 's' "; static PyObject * con_settools(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "is", &id, &name)) return NULL; if ((err = rpc_settools(self->h, id, name))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_gettools__doc__[] = "gettools(w:integer) : string Return the tools currently visible in w's tag"; static PyObject * con_gettools(conobject *self, PyObject *args) { char *err; char *tools; Id id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; if ((err = rpc_gettools(self->h, id, &tools))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("s", tools); } static char con_getname__doc__[] = "getname(w:integer) : string Return the name currently visible in w's tag"; static PyObject * con_getname(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "i", &id)) return NULL; if ((err = rpc_getname(self->h, id, &name))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("s", name); } static char con_read__doc__[] = "read(w:integer, from:integer, to:integer) returns a (UTF) string "; static PyObject * con_read(conobject *self, PyObject *args) { int from,to; Id id; Range r; char *buf,*err; PyObject *retval; if (!PyArg_ParseTuple(args, "iii", &id, &from, &to)) return NULL; r.p0 = from; r.p1 = to; buf = malloc(UTFmax *(r.p1 -r.p0)); if(!buf) { PyErr_NoMemory(); return NULL; } err = rpc_read(self->h, id, r, buf); if(err) { PyErr_SetString(ErrorObject, err); retval= NULL; } else { retval= Py_BuildValue("s", buf); } free(buf); return retval; } static char con_replace__doc__[] = "replace(w:integer, from:integer, to:integer, s:string) replace the text in 'w' from 'from' to 'to' with 's' "; static PyObject * con_replace(conobject *self, PyObject *args) { char *err; int p0, p1; char *replace; Id id; Range r; if (!PyArg_ParseTuple(args, "iiis",&id, &p0, &p1,&replace)) return NULL; if (p0>p1 || p1<0 || p0<0) { PyErr_SetString(ErrorObject, "range out of bounds"); return NULL; } r.p0 = p0; r.p1 = p1; if((err = rpc_replace(self->h, id, r, replace))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_run__doc__[] = "run(w:integer, s:string) has the same effect as sweeping 's' with B2 in window 'w' "; static PyObject * con_run(conobject *self, PyObject *args) { char *err; char *name; Id id; if (!PyArg_ParseTuple(args, "is",&id, &name)) return NULL; if((err = rpc_exec(self->h, id, name))) { PyErr_SetString(ErrorObject, err); return NULL; } Py_INCREF(Py_None); return Py_None; } static char con_goto__doc__[] = "goto(w:integer, from:long, to:long, s:string, flag:integer) has the same effect as sweeping 's' with B3 in window 'w', and starting any search at range(from,to), except that we only warp and select text if 'flag' is set. Returns a tuple (w:integer, from:long, to:long), which represents the window and selection that was opened. "; static PyObject * con_goto(conobject *self, PyObject *args) { char *err; char *name; Id id; Range r; long from,to; int flag; if (!PyArg_ParseTuple(args, "illsi",&id, &from, &to, &name,&flag)) return NULL; r.p0 = from; r.p1 = to; if((err = rpc_goto(self->h, &id, &r, name, flag))) { PyErr_SetString(ErrorObject, err); return NULL; } return Py_BuildValue("(ill)", id, r.p0, r.p1); } static struct PyMethodDef con_methods[] = { {"list", con_list, 1, con_list__doc__}, {"win", con_win, 1, con_win__doc__}, {"event", con_event, 1, con_event__doc__}, {"eventwouldblock", con_eventwouldblock, 1, con_eventwouldblock__doc__}, {"bounce", con_bounce, 1, con_bounce__doc__}, {"attach", con_attach, 1, con_attach__doc__}, {"setname", con_setname, 1, con_setname__doc__}, {"getname", con_getname, 1, con_getname__doc__}, {"settools", con_settools, 1, con_settools__doc__}, {"gettools", con_gettools, 1, con_gettools__doc__}, {"read", con_read, 1, con_read__doc__}, {"replace", con_replace, 1, con_replace__doc__}, {"run", con_run, 1, con_run__doc__}, {"goto", con_goto, 1, con_goto__doc__}, {NULL, NULL} /* sentinel */ }; /* ---------- */ static conobject * newconobject() { conobject *self; int fd; self = PyObject_NEW(conobject, &Contype); if (self == NULL) return NULL; /* XXXX Add your own initializers here */ /* todo - handle errors */ fd = client_connect(); if(fd<0) { PyErr_SetString(ErrorObject, "client_connect"); return NULL; } self->h = rpc_init(fd); if (!self->h) { PyErr_SetString(ErrorObject, "rpc_init"); return NULL; } return self; } static void con_dealloc(self) conobject *self; { /* XXXX Add your own cleanup code here */ PyMem_DEL(self); } static PyObject * con_getattr(self, name) conobject *self; char *name; { /* XXXX Add your own getattr code here */ return Py_FindMethod(con_methods, (PyObject *)self, name); } static char Contype__doc__[] = "Wily connection Holds the state for a connection to Wily " ; static PyTypeObject Contype = { PyObject_HEAD_INIT(&PyType_Type) 0, /*ob_size*/ "Connection", /*tp_name*/ sizeof(conobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)con_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ (getattrfunc)con_getattr, /*tp_getattr*/ (setattrfunc)0, /*tp_setattr*/ (cmpfunc)0, /*tp_compare*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (binaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ /* Space for future expansion */ 0L,0L,0L,0L, Contype__doc__ /* Documentation string */ }; /* End of code for Connection objects */ /* -------------------------------------------------------- */ static char wily_Connection__doc__[] = "Connection() Return a connection object. Uses $WILYFIFO if set" ; static PyObject * wily_Connection(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) return NULL; return (PyObject*) newconobject(); } /* List of methods defined in the module */ static struct PyMethodDef wily_methods[] = { {"Connection", wily_Connection, 1, wily_Connection__doc__}, {NULL, NULL} /* sentinel */ }; /* Initialization function for the module (*must* be called initwily) */ static char wily_module_documentation[] = "Open, manipulate, monitor Wily windows Everything is accessed through a Connection object. Windows are represented by an integer. GOTO, EXEC, DESTROY and REPLACE are event bitmask values."; void initwily() { PyObject *m, *d; /* Create the module and add the functions */ m = Py_InitModule4("wily", wily_methods, wily_module_documentation, (PyObject*)NULL,PYTHON_API_VERSION); /* Add some symbolic constants to the module */ d = PyModule_GetDict(m); ErrorObject = PyString_FromString("wily.error"); PyDict_SetItemString(d, "error", ErrorObject); /* XXXX Add constants here */ PyDict_SetItemString(d, "GOTO", Py_BuildValue("i", WEgoto)); PyDict_SetItemString(d, "EXEC", Py_BuildValue("i", WEexec)); PyDict_SetItemString(d, "DESTROY", Py_BuildValue("i", WEdestroy)); PyDict_SetItemString(d, "REPLACE", Py_BuildValue("i", WEreplace)); /* Check for errors */ if (PyErr_Occurred()) Py_FatalError("can't initialize module wily"); } wily-0.13.41/tools/python/Makefile100644 2743 200 757 6332562103 15270 0ustar garypgrad# 9term CC=gcc PYTHONINC=/n/staff/srce/usr/local/bin/python/Python-1.4/Include/ CFLAGS=-g -Wall -I. -I/usr/pgrad/gary/src/wily/include -I/usr/pgrad/gary/src/wily/sam/include -I$(PYTHONINC) -DNDEBUG XLIBS=-L/usr/pgrad/gary/obj/sun4d/wily/libmsg -l msg -lsocket -lnsl -lintl target: wilymodule.so OBJS=wilymodule.o wilymodule.so: $(OBJS) Makefile /usr/pgrad/gary/obj/sun4d/wily/libmsg/libmsg.a ld -G -o wilymodule.so wilymodule.o $(XLIBS) wilymodule.o: /usr/pgrad/gary/src/wily/include/msg.h wily-0.13.41/tools/python/config.h100644 2743 200 4365 6130454417 15271 0ustar garypgrad/* config.h. Generated automatically by configure. */ /* config.h.in. Generated automatically from configure.in by autoheader. */ #define HAVE_ULONG 1 #define HAVE_USHORT 1 #define HAVE_UINT 1 /* #undef HAVE_UCHAR */ #define HAVE_CADDR_T 1 /* Define this if your sprintf returns char * instead of int */ #define BROKEN_SPRINTF 1 /* Define to empty if the keyword does not work. */ /* #undef const */ /* Define if you don't have vprintf but do have _doprnt. */ /* #undef HAVE_DOPRNT */ /* Define if you have that is POSIX.1 compatible. */ #define HAVE_SYS_WAIT_H 1 /* Define if you have the vprintf function. */ #define HAVE_VPRINTF 1 /* Define if you need to in order for stat and other things to work. */ /* #undef _POSIX_SOURCE */ /* Define as the return type of signal handlers (int or void). */ #define RETSIGTYPE void /* Define to `unsigned' if doesn't define. */ /* #undef size_t */ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* Define if you have the memmove function. */ #define HAVE_MEMMOVE 1 /* Define if you have the realpath function. */ #define HAVE_REALPATH 1 /* Define if you have the remove function. */ #define HAVE_REMOVE 1 /* Define if you have the strerror function. */ #define HAVE_STRERROR 1 /* Define if you have the header file. */ #define HAVE_DIRENT_H 1 /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ #define HAVE_LIMITS_H 1 /* Define if you have the header file. */ #define HAVE_MALLOC_H 1 /* Define if you have the header file. */ /* #undef HAVE_NDIR_H */ /* Define if you have the header file. */ #define HAVE_STDARG_H 1 /* Define if you have the header file. */ /* #undef HAVE_SYS_DIR_H */ /* Define if you have the header file. */ /* #undef HAVE_SYS_NDIR_H */ /* Define if you have the header file. */ #define HAVE_SYS_SELECT_H 1 /* Define if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define if you have the header file. */ #define HAVE_UNISTD_H 1 wily-0.13.41/tools/python/Makefile.in100644 2743 200 747 6332562220 15674 0ustar garypgradCC=gcc PYTHONINC=/n/staff/srce/usr/local/bin/python/Python-1.4/Include/ CFLAGS=-g -Wall -I. -I/usr/pgrad/gary/src/wily/include -I/usr/pgrad/gary/src/wily/sam/include -I$(PYTHONINC) -DNDEBUG XLIBS=-L/usr/pgrad/gary/obj/sun4d/wily/libmsg -l msg -lsocket -lnsl -lintl target: wilymodule.so OBJS=wilymodule.o wilymodule.so: $(OBJS) Makefile /usr/pgrad/gary/obj/sun4d/wily/libmsg/libmsg.a ld -G -o wilymodule.so wilymodule.o $(XLIBS) wilymodule.o: /usr/pgrad/gary/src/wily/include/msg.h wily-0.13.41/tools/python/testwily.py100755 2743 200 2045 6244064522 16105 0ustar garypgrad#!/usr/local/bin/python -u # -u == unbuffered output import wily print 'get connection' c = wily.Connection() print 'get window "fish"' w = c.win('fish', 1) print 'new window', w print 'get list of windows' print 'listing', c.list() print 'change name from "fish" to "newname"' c.setname(w, 'newname') print 'insert some text' c.replace(w, 0, 0, 'pack my box with five dozen liquor jugs') print 'search for the text "box"' w2,f,t = c.goto(w, 0, 0, 'box', 0) print 'found at', w2, f, t print 'replace "box" with "crate"' c.replace(w, f, t, 'crate') print 'search for the whole window' w2,f,t = c.goto(w, 0, 0, ':,', 0) print 'whole file is', w2, f, t print 'replace the whole window with another phrase' c.replace(w, f, t, 'the quick brown fox jumped over the lazy dog') print 'read the range [10,15) from the window' #s = c.read(w, 10, 15) # print 'read ', s print 'attach to the window, grab EXEC messages only' c.attach(w, wily.EXEC) print 'print the next ten events' for j in range(10): print 'waiting' print 'got', c.event() print 'done' wily-0.13.41/tools/README100644 2743 200 425 6332560363 13165 0ustar garypgradA bunch of programs that use wily for their user interface, and tools to create such programs. old stuff pre wily-0.11 quanstro tools from erik quanstrom python python interface for wily messages win simple terminal wpnews wily/python news reader wily-0.13.41/tools/old/ 40755 2743 200 0 6141343277 13006 5ustar garypgradwily-0.13.41/tools/old/edit/ 40755 2743 200 0 6141130621 13716 5ustar garypgradwily-0.13.41/tools/old/edit/c.c100644 2743 200 3641 6041414441 14411 0ustar garypgrad/* * c.c - this handles the c, i, a and d commands. */ #include "range.h" Bool debug = false; static Rune *rarg0, *rarg1; /* * Convert the supplied arg into Runes which can be inserted into the * new tmp file at appropriate points. */ static void argtorune(char *utfarg) { int len = strlen(utfarg); /* XXX - this is a guess - I'm assuming that n bytes of UTF won't take more than n Runes to store, but I'm allocing more here out of paranoia. */ rarg0 = salloc(len*(sizeof(Rune)+1)); for (rarg1 = rarg0; len--; rarg1++) if (*(uchar *)utfarg < Runeself) *rarg1 = *utfarg++; else utfarg += chartorune(rarg1, utfarg); return; } /* * change functions are simple - we're given the text to be * changed in, *r0 and *r1, and we change the two pairs of * pointers to what is to be written to the file, or to null, * if the given range isn't to be written. */ static int fn_c(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r0 = rarg0; *r1 = rarg1; *r2 = *r3 = 0; return 1; } static int fn_i(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r2 = *r0; *r3 = *r1; *r0 = rarg0; *r1 = rarg1; return 1; } static int fn_a(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r2 = rarg0; *r3 = rarg1; return 1; } static int fn_d(Rune **r0, Rune **r1, Rune **r2, Rune **r3) { *r0 = *r1 = *r2 = *r3 = 0; return 1; } int main(int argc, char *argv[]) { char *p; size_t len; Subrange *r; int (*fn)(Rune **r0, Rune **r1, Rune **r2, Rune **r3); p = strrchr(argv[0], '/'); p = p? p+1 : argv[0]; switch (*p) { case 'c' : fn = fn_c; break; case 'i' : fn = fn_i; break; case 'd' : fn = fn_d; break; case 'a' : fn = fn_a; break; default: fprintf(stderr,"Uknown program name!\n"); exit(1); } if (*p != 'd') { if (argc < 2) { fprintf(stderr,"%c: need text argument\n", *p); exit(1); } argtorune(argv[1]); } read_info(0); /* don't reverse ranges */ do_changes(fn); list_changes(); exit(0); } wily-0.13.41/tools/old/edit/change.c100644 2743 200 5221 6041414441 15410 0ustar garypgrad/* * routines for making changes to the temporary file. Actually, * the changes are made to a new temporary file. */ #include "range.h" static Subrange *changes; /* list of changes that we've made */ static Subrange *last; static FILE *tmpfp; static char newtmpfile[FILENAME_MAX+1]; static ulong copyfile(ulong p0, ulong p1, FILE *fp); static ulong save_change(ulong p0, Rune *r0, Rune *r1, Rune *r2, Rune *r3, FILE *fp); static void add_change(ulong p0, ulong p1, ulong q0, ulong q1) { Subrange *r; r = salloc(sizeof(*r)); r->p0 = p0; r->p1 = p1; r->q0 = q0; r->q1 = q1; r->next = 0; if (changes) { last->next = r; last = r; } else changes = last = r; return; } void do_changes(int (*changed)(Rune **r0, Rune **r1, Rune **r2, Rune **r3)) { ulong origpos = 0, pos = 0, len, newpos; Subrange *r; if (tmpfp == 0) { tmpnam(newtmpfile); if ((tmpfp = fopen(newtmpfile,"w")) == 0) { perror(newtmpfile); exit(1); } Finit(&runefile, tmpfilename); } /* for each range, copy the unchanged part of the file between the last range and this one, then pass the range to the fn, and if it's changed the text. write the two returned strings to the file */ while (r = next_range()) { Rune *r0, *r1, *r2, *r3; if (origpos < r->p0) { pos += copyfile(origpos, r->p0, tmpfp); origpos = r->p1; } r0 = runefile.getcbuf + r->p0; r1 = runefile.getcbuf + r->p1; if ((*changed)(&r0, &r1, &r2, &r3)) { modified = 1; newpos = save_change(pos,r0, r1, r2, r3, tmpfp); add_change(r->p0, r->p1, pos, newpos); pos = newpos; } } /* copy anything left after the last range */ if (origpos < runefile.nrunes) copyfile(origpos, runefile.nrunes, tmpfp); fclose(tmpfp); if (modified) { remove(tmpfilename); strcpy(tmpfilename, newtmpfile); } return; } /* * copy a section of file, unchanged. */ static ulong copyfile(ulong p0, ulong p1, FILE *fp) { fwrite(runefile.getcbuf + p0, p1-p0, RUNESIZE, fp); return (p1 - p0); } /* * a section of the file has been changed. write the changed * section to the file. */ static ulong save_change(ulong p0, Rune *r0, Rune *r1, Rune *r2, Rune *r3, FILE *fp) { ulong len; if (r0) { len = r1 - r0; if (len) fwrite(r0, len , RUNESIZE, fp); p0 += len; } if (r2) { len = r3 - r2; if (len) fwrite(r2, len , RUNESIZE, fp); p0 += len; } return p0; } void write_info(void) { printf("%s\n%s\n%s\n%d\n%d\n", origfile, origaddr, tmpfilename, modified, base); } /* * produce file info and a list of the changes */ void list_changes(void) { Subrange *r = changes; write_info(); for (; r; r = r->next) printf("#%lu,#%lu #%lu,#%lu\n", r->p0, r->p1, r->q0, r->q1); return; } wily-0.13.41/tools/old/edit/change.h100644 2743 200 0 6041414441 15323 0ustar garypgradwily-0.13.41/tools/old/edit/e.c100644 2743 200 5314 6041414441 14412 0ustar garypgrad/* * e.c - set up editing file for wily. * some parts of this are swiped straight from gary's win.c. */ #include #include #include #include #include #include #include #include "libmsg.h" int towily, fromwily; /* file descriptors */ static char tmpfilename[FILENAME_MAX+1]; static ulong tmpp0, tmpp1; Msg m; Bool debug = false; Bool frommessage = true; static int gottext = 0; /* The lines that we asked for have arrived. */ void handleread(Msg *m) { char *s, *t; int len; FILE *fp; Rune r; tmpnam(tmpfilename); tmpp0 = m->p[0]; tmpp1 = m->p[1]; s = m->s[0]; t = s + strlen(s); if ((fp = fopen(tmpfilename,"w")) == 0) { perror(tmpfilename); exit(1); } while (s < t) { if (*(uchar *)s < (ulong)Runeself) r = *s++; else s += chartorune(&r, s); if (fwrite(&r, sizeof(r), 1, fp) != 1) { perror(tmpfilename); remove(tmpfilename); exit(1); } } fclose(fp); gottext = 1; return; } /* Handle all the messages coming from wily. */ void domsg(Msg *m) { switch(m->mtype) { case 'R': handleread(m); break; default: /* ignore whatever we don't specifically handle */ if(debug) { printf("message received and ignored: "); msg_print(m); } break; } } /* Open fifos to wily. */ void connect_wily(char *file, char *addr) { char envbuf[300]; msg_init(&m); towily = fromwily = get_connect(file); if(towily<0) { perror("connect failed\n"); exit(1); } DPRINT("in %d, out %d\n", fromwily, towily); wm_read(towily, true, 0, 0, addr); } static void rcv_text(void) { char buf[BUFSIZ]; int nread; while (gottext == 0) { nread = read(fromwily,buf,BUFSIZ); if (nread <= 0) { perror("e read"); exit(1); } if (empty_msg_buf(buf, nread, &m, domsg)) fprintf(stderr,"error from empty_msg_buf\n"); } } int main(int argc, char**argv) { char buf[BUFSIZ]; extern char *optarg; extern int optind; char *file, *addr; int c; while ((c = getopt(argc, argv, "d")) != EOF){ switch(c){ case 'd': debug = true; break; case '?': fprintf(stderr, "%s [-d] [prog...]\n", argv[0]); exit(1); } } if(debug) setbuf(stdout,0); file = argv[optind]; if (!file || !*file) { fprintf(stderr,"%s: no file!\n", argv[0]); exit(1); } if (addr = strchr(file, ':')) *addr++ = 0; else { /* XXX - really, we'd like to be able to ask wily what dot is, and read that explicitly, because doing a read of "." on file /path/name, if it's not already open, causes an eventual pane_openpath() which opens /path/. - daft, isn't it? */ addr = "."; } connect_wily(file, addr); rcv_text(); printf("%s\n%s\n%s\n0\n%d\n#0,#%d\n", file, addr, tmpfilename, tmpp0, tmpp1 - tmpp0); return 0; } wily-0.13.41/tools/old/edit/q.c100644 2743 200 4331 6041414441 14424 0ustar garypgrad#include "range.h" int towily, fromwily; /* file descriptors */ Msg m; Bool debug = false; Bool frommessage = true; /* * load the relevant section of the file, convert it to UTF, and supply * the length of the resulting UTF string. */ static char * load_data(ulong p0, ulong p1, int *len) { ulong length = p1 - p0; size_t sz; static FILE *fp; Rune r; char *s; int n; /* XXX We make a guess about how much space the UTF version of the text will require... */ sz = length * (sizeof(Rune)+1); s = utffile = srealloc(utffile, sz); if (!fp && (fp = fopen(tmpfilename,"r")) == 0) { perror(tmpfilename); exit(1); } fseek(fp, p0 * sizeof(Rune), SEEK_SET); for (n = 0; n < length; n++) { fread(&r, sizeof(Rune), 1, fp); if ((uchar)r < Runeself) *s++ = r; else s += runetochar(s, &r); } *s = 0; *len = s - utffile; DPRINT("Read %d bytes\n",*len); return utffile; } static void send_data(void) { Subrange *r; char *buf; int len; if (!modified) { DPRINT("Not modified - not making changes\n"); return; } while (r = next_range()) { r->p0 += base; r->p1 += base; buf = load_data(r->q0, r->q1, &len); DPRINT("Removing old data\n"); wm_delete(towily, true, r->p0, r->p1); DPRINT("Inserting new data\n"); wm_insert(towily, true, r->p0, len, buf); } return; } /* Open fifos to wily. */ void connect_wily(char *file, char *addr) { char envbuf[300]; msg_init(&m); DPRINT("Connecting to wily\n"); towily = fromwily = get_connect(file); if(towily<0) { perror("connect failed\n"); exit(1); } DPRINT("in %d, out %d\n", fromwily, towily); DPRINT("Selecting given address\n"); wm_goto(towily, true, 0, 0, addr); } int main(int argc, char**argv) { char buf[BUFSIZ]; extern char *optarg; extern int optind; char *file, *addr; int c; while ((c = getopt(argc, argv, "d")) != EOF){ switch(c){ case 'd': debug = true; break; case '?': fprintf(stderr, "%s [-d] [prog...]\n", argv[0]); exit(1); } } if(debug) setbuf(stdout,0); read_info(1); /* reverse and coalese ranges */ if (!modified) { DPRINT("Not changed - just removing file\n"); remove(tmpfilename); return 0; } connect_wily(origfile, origaddr); send_data(); remove(tmpfilename); return 0; } wily-0.13.41/tools/old/edit/range.c100644 2743 200 5077 6041414441 15270 0ustar garypgrad#include #include #include "range.h" static Subrange *ranges, *range_ptr; static Subrange *shrink_ranges(int rev, Subrange *res); /* * This defines the number of Runes we're willing to have * in a single message to wily. */ #define MAXCHG 4000 /* * Functions for handling the ranges. Returns a subrange with * the min and max range of the whole set of ranges. Returns * 0 if no ranges were read. * Accepts either single ranges (from e, x) or pairs or ranges (from c). * Attempts to allow you to chain instances of c/i/a/d, but that's not * working properly yet. */ Subrange * read_ranges(int rev) { int nranges = 0; static Subrange res; Subrange *r, *l; ulong p0, p1, q0, q1; char buf[FILENAME_MAX+1]; while (fgets(buf, FILENAME_MAX, stdin)) { int npairs = sscanf(buf,"#%lu,#%lu #%lu,#%lu\n", &p0, &p1, &q0, &q1); switch (npairs) { default: return shrink_ranges(rev, nranges? &res : 0); case 4: if (nranges) { if (q0 < res.q0) res.q0 = q0; if (q1 > res.q1) res.q1 = q1; } else { res.q0 = q0; res.q1 = q1; } /* FALLTHROUGH */ case 2: if (nranges) { if (p0 < res.p0) res.p0 = p0; if (p1 > res.p1) res.p1 = p1; } else { res.p0 = p0; res.p1 = p1; } break; } r = salloc(sizeof(*r)); if (rev) { r->p0 = p0; r->p1 = p1; r->q0 = q0; r->q1 = q1; } else { if (npairs == 4) { r->p0 = q0; r->p1 = q1; } else { r->p0 = p0; r->p1 = p1; } } r->next = 0; if (nranges++) { l->next = r; l = r; } else l = ranges = r; } return shrink_ranges(rev, nranges? &res : 0); } Subrange * next_range(void) { Subrange *res = range_ptr; if (range_ptr) range_ptr = range_ptr->next; return res; } /* * If rev==0, then just return the min/max subrange that we've been given * (this is old, should just return a worked/failed flag). * If rev==1, then we're in "q", and will be sending the changes back to * wily. Reads the list of ranges, attempts to coalese them into single * updates, and reverses the order. */ static Subrange * shrink_ranges(int rev, Subrange *res) { Subrange *newranges = 0, *r0, *r1; range_ptr = ranges; if (rev == 0) return res; r0 = next_range(); while (r0) { while ((r1 = next_range()) && (r1->q1 - r0->q0) < MAXCHG) { /* can fit this change into the current message */ r0->p1 = r1->p1; r0->q1 = r1->q1; free(r1); } /* message is now too big to fit next range in. */ r0->next = newranges; newranges = r0; r0 = r1; } range_ptr = ranges = newranges; return res; } wily-0.13.41/tools/old/edit/range.h100644 2743 200 1365 6041414441 15271 0ustar garypgrad#ifndef WILY_EDIT_H #define WILY_EDIT_H #include #include #include #include #include #include #include "sam.h" typedef struct Subrange Subrange; struct Subrange { ulong p0, p1, q0, q1; /* p is wily ref, q is new file ref */ struct Subrange *next; }; Subrange *read_ranges(int rev); Subrange *next_range(void); void do_changes(int (*changed)(Rune **r0, Rune **r1, Rune **r2, Rune **r3)); void write_info(void); void list_changes(void); extern char origfile[FILENAME_MAX+1], origaddr[FILENAME_MAX+1]; extern char tmpfilename[FILENAME_MAX+1]; extern Subrange *minmax; extern ulong base; extern char *utffile; extern int modified; extern File runefile; #endif /* ! WILY_EDIT_H */ wily-0.13.41/tools/old/edit/regexp.c100644 2743 200 36651 6041414441 15510 0ustar garypgrad/* Copyright (c) 1992 AT&T - All rights reserved. */ #include "sam.h" Rangeset sel; String lastregexp; /* * Machine Information */ struct Inst { long type; /* < 0x10000 ==> literal, otherwise action */ union { int rsid; int rsubid; int class; struct Inst *rother; struct Inst *rright; } r; union{ struct Inst *lleft; struct Inst *lnext; } l; }; #define sid r.rsid #define subid r.rsubid #define rclass r.class #define other r.rother #define right r.rright #define left l.lleft #define next l.lnext #define NPROG 1024 Inst program[NPROG]; Inst *progp; Inst *startinst; /* First inst. of program; might not be program[0] */ Inst *bstartinst; /* same for backwards machine */ typedef struct Ilist Ilist; struct Ilist { Inst *inst; /* Instruction of the thread */ Rangeset se; Posn startp; /* first char of match */ }; #define NLIST 128 Ilist *tl, *nl; /* This list, next list */ Ilist list[2][NLIST]; static Rangeset sempty; /* * Actions and Tokens * * 0x100xx are operators, value == precedence * 0x200xx are tokens, i.e. operands for operators */ #define OPERATOR 0x10000 /* Bitmask of all operators */ #define START 0x10000 /* Start, used for marker on stack */ #define RBRA 0x10001 /* Right bracket, ) */ #define LBRA 0x10002 /* Left bracket, ( */ #define OR 0x10003 /* Alternation, | */ #define CAT 0x10004 /* Concatentation, implicit operator */ #define STAR 0x10005 /* Closure, * */ #define PLUS 0x10006 /* a+ == aa* */ #define QUEST 0x10007 /* a? == a|nothing, i.e. 0 or 1 a's */ #define ANY 0x20000 /* Any character but newline, . */ #define NOP 0x20001 /* No operation, internal use only */ #define BOL 0x20002 /* Beginning of line, ^ */ #define EOL 0x20003 /* End of line, $ */ #define CCLASS 0x20004 /* Character class, [] */ #define NCCLASS 0x20005 /* Negated character class, [^] */ #define END 0x20077 /* Terminate: match found */ #define ISATOR 0x10000 #define ISAND 0x20000 /* * Parser Information */ typedef struct Node Node; struct Node { Inst *first; Inst *last; }; #define NSTACK 20 Node andstack[NSTACK]; Node *andp; int atorstack[NSTACK]; int *atorp; int lastwasand; /* Last token was operand */ int cursubid; int subidstack[NSTACK]; int *subidp; int backwards; int nbra; Rune *exprp; /* pointer to next character in source expression */ #define DCLASS 10 /* allocation increment */ int nclass; /* number active */ int Nclass; /* high water mark */ Rune **class; int negateclass; void addinst(Ilist *l, Inst *inst, Rangeset *sep); void newmatch(Rangeset*); void bnewmatch(Rangeset*); void pushand(Inst*, Inst*); void pushator(int); Node *popand(int); int popator(void); void startlex(Rune*); int lex(void); void operator(int); void operand(int); void evaluntil(int); void optimize(Inst*); void bldcclass(void); void regerror(Err e) { Strzero(&lastregexp); error(e); } void regerror_c(Err e, int c) { Strzero(&lastregexp); error_c(e, c); } Inst * newinst(int t) { if(progp >= &program[NPROG]) regerror(Etoolong); progp->type = t; progp->left = 0; progp->right = 0; return progp++; } Inst * realcompile(Rune *s) { int token; startlex(s); atorp = atorstack; andp = andstack; subidp = subidstack; cursubid = 0; lastwasand = FALSE; /* Start with a low priority operator to prime parser */ pushator(START-1); while((token=lex()) != END){ if((token&ISATOR) == OPERATOR) operator(token); else operand(token); } /* Close with a low priority operator */ evaluntil(START); /* Force END */ operand(END); evaluntil(START); if(nbra) regerror(Eleftpar); --andp; /* points to first and only operand */ return andp->first; } void compile(String *s) { int i; Inst *oprogp; if(Strcmp(s, &lastregexp)==0) return; for(i=0; is); optimize(program); oprogp = progp; backwards = TRUE; bstartinst = realcompile(s->s); optimize(oprogp); Strduplstr(&lastregexp, s); } void operand(int t) { Inst *i; if(lastwasand) operator(CAT); /* catenate is implicit */ i = newinst(t); if(t == CCLASS){ if(negateclass) i->type = NCCLASS; /* UGH */ i->rclass = nclass-1; /* UGH */ } pushand(i, i); lastwasand = TRUE; } void operator(int t) { if(t==RBRA && --nbra<0) regerror(Erightpar); if(t==LBRA){ /* * if(++cursubid >= NSUBEXP) * regerror(Esubexp); */ cursubid++; /* silently ignored */ nbra++; if(lastwasand) operator(CAT); }else evaluntil(t); if(t!=RBRA) pushator(t); lastwasand = FALSE; if(t==STAR || t==QUEST || t==PLUS || t==RBRA) lastwasand = TRUE; /* these look like operands */ } void cant(char *s) { char buf[100]; sprint(buf, "regexp: can't happen: %s", s); panic(buf); } void pushand(Inst *f, Inst *l) { if(andp >= &andstack[NSTACK]) cant("operand stack overflow"); andp->first = f; andp->last = l; andp++; } void pushator(int t) { if(atorp >= &atorstack[NSTACK]) cant("operator stack overflow"); *atorp++=t; if(cursubid >= NSUBEXP) *subidp++= -1; else *subidp++=cursubid; } Node * popand(int op) { if(andp <= &andstack[0]) if(op) regerror_c(Emissop, op); else regerror(Ebadregexp); return --andp; } int popator(void) { if(atorp <= &atorstack[0]) cant("operator stack underflow"); --subidp; return *--atorp; } void evaluntil(int pri) { Node *op1, *op2, *t; Inst *inst1, *inst2; while(pri==RBRA || atorp[-1]>=pri){ switch(popator()){ case LBRA: op1 = popand('('); inst2 = newinst(RBRA); inst2->subid = *subidp; op1->last->next = inst2; inst1 = newinst(LBRA); inst1->subid = *subidp; inst1->next = op1->first; pushand(inst1, inst2); return; /* must have been RBRA */ default: panic("unknown regexp operator"); break; case OR: op2 = popand('|'); op1 = popand('|'); inst2 = newinst(NOP); op2->last->next = inst2; op1->last->next = inst2; inst1 = newinst(OR); inst1->right = op1->first; inst1->left = op2->first; pushand(inst1, inst2); break; case CAT: op2 = popand(0); op1 = popand(0); if(backwards && op2->first->type!=END) t = op1, op1 = op2, op2 = t; op1->last->next = op2->first; pushand(op1->first, op2->last); break; case STAR: op2 = popand('*'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(inst1, inst1); break; case PLUS: op2 = popand('+'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(op2->first, inst1); break; case QUEST: op2 = popand('?'); inst1 = newinst(OR); inst2 = newinst(NOP); inst1->left = inst2; inst1->right = op2->first; op2->last->next = inst2; pushand(inst1, inst2); break; } } } void optimize(Inst *start) { Inst *inst, *target; for(inst=start; inst->type!=END; inst++){ target = inst->next; while(target->type == NOP) target = target->next; inst->next = target; } } #ifdef DEBUG void dumpstack(void){ Node *stk; int *ip; dprint("operators\n"); for(ip = atorstack; ipfirst->type, stk->last->type); } void dump(void){ Inst *l; l = program; do{ dprint("%d:\t0%o\t%d\t%d\n", l-program, l->type, l->left-program, l->right-program); }while(l++->type); } #endif void startlex(Rune *s) { exprp = s; nbra = 0; } int lex(void){ int c= *exprp++; switch(c){ case '\\': if(*exprp) if((c= *exprp++)=='n') c='\n'; break; case 0: c = END; --exprp; /* In case we come here again */ break; case '*': c = STAR; break; case '?': c = QUEST; break; case '+': c = PLUS; break; case '|': c = OR; break; case '.': c = ANY; break; case '(': c = LBRA; break; case ')': c = RBRA; break; case '^': c = BOL; break; case '$': c = EOL; break; case '[': c = CCLASS; bldcclass(); break; } return c; } long nextrec(void){ if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0)) regerror(Ebadclass); if(exprp[0] == '\\'){ exprp++; if(*exprp=='n'){ exprp++; return '\n'; } return *exprp++|0x10000; } return *exprp++; } void bldcclass(void) { long c1, c2, n, na; Rune *classp; classp = emalloc(DCLASS*RUNESIZE); n = 0; na = DCLASS; /* we have already seen the '[' */ if(*exprp == '^'){ classp[n++] = '\n'; /* don't match newline in negate case */ negateclass = TRUE; exprp++; }else negateclass = FALSE; while((c1 = nextrec()) != ']'){ if(c1 == '-'){ Error: free(classp); regerror(Ebadclass); } if(n+4 >= na){ /* 3 runes plus NUL */ na += DCLASS; classp = erealloc(classp, na*RUNESIZE); } if(*exprp == '-'){ exprp++; /* eat '-' */ if((c2 = nextrec()) == ']') goto Error; classp[n+0] = 0xFFFF; classp[n+1] = c1; classp[n+2] = c2; n += 3; }else classp[n++] = c1; } classp[n] = 0; if(nclass == Nclass){ Nclass += DCLASS; class = erealloc(class, Nclass*sizeof(Rune*)); } class[nclass++] = classp; } int classmatch(int classno, int c, int negate) { Rune *p; p = class[classno]; while(*p){ if(*p == 0xFFFF){ if(p[1]<=c && c<=p[2]) return !negate; p += 3; }else if(*p++ == c) return !negate; } return negate; } /* * Note optimization in addinst: * *l must be pending when addinst called; if *l has been looked * at already, the optimization is a bug. */ void addinst(Ilist *l, Inst *inst, Rangeset *sep) { Ilist *p; for(p = l; p->inst; p++){ if(p->inst==inst){ if((sep)->p[0].p1 < p->se.p[0].p1) p->se= *sep; /* this would be bug */ return; /* It's already there */ } } p->inst = inst; p->se= *sep; (p+1)->inst = 0; } int execute(File *f, Posn startp, Posn eof) { int flag = 0; Inst *inst; Ilist *tlp; Posn p = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = startinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.p[0].p1 = -1; Fgetcset(f, startp); /* Execute machine once for each character */ for(;;p++){ doloop: c = Fgetc(f); if(p>=eof || c<0){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to beginning */ if(sel.p[0].p1>=0 || eof!=INFINITY) goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, (Posn)0); p = 0; goto doloop; default: goto Return; } }else if(((wrapped && p>=startp) || sel.p[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.p[0].p1<0 && (!wrapped || p= NLIST) Overflow: error(Eoverflow); sempty.p[0].p1 = p; addinst(tl, startinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst) ; tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type==c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.p[inst->subid].p1 = p; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid>=0) tlp->se.p[inst->subid].p2 = p; inst = inst->next; goto Switchstmt; case ANY: if(c!='\n') goto Addinst; break; case BOL: if(p == 0){ Step: inst = inst->next; goto Switchstmt; } if(f->getci > 1){ if(f->getcbuf[f->getci-2]=='\n') goto Step; }else{ Rune c; if(Fchars(f, &c, p-1, p)==1 && c=='\n') goto Step; } break; case EOL: if(c == '\n') goto Step; break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.p[0].p2 = p; newmatch(&tlp->se); break; } } } Return: return sel.p[0].p1>=0; } void newmatch(Rangeset *sp) { int i; if(sel.p[0].p1<0 || sp->p[0].p1p[0].p1==sel.p[0].p1 && sp->p[0].p2>sel.p[0].p2)) for(i = 0; ip[i]; } int bexecute(File *f, Posn startp) { int flag = 0; Inst *inst; Ilist *tlp; Posn p = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = bstartinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.p[0].p1= -1; Fgetcset(f, startp); /* Execute machine once for each character, including terminal NUL */ for(;;--p){ doloop: if((c = Fbgetc(f))==-1){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to end */ if(sel.p[0].p1>=0) case 3: goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, f->nrunes); p = f->nrunes; goto doloop; default: goto Return; } }else if(((wrapped && p<=startp) || sel.p[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.p[0].p1<0 && (!wrapped || p>startp)){ /* Add first instruction to this list */ if(++ntl >= NLIST) Overflow: error(Eoverflow); /* the minus is so the optimizations in addinst work */ sempty.p[0].p1 = -p; addinst(tl, bstartinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst); tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type == c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.p[inst->subid].p1 = p; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid >= 0) tlp->se.p[inst->subid].p2 = p; inst = inst->next; goto Switchstmt; case ANY: if(c != '\n') goto Addinst; break; case BOL: if(c=='\n' || p==0){ Step: inst = inst->next; goto Switchstmt; } break; case EOL: if(f->getcingetc-1){ if(f->getcbuf[f->getci+1]=='\n') goto Step; }else if(pnrunes-1){ Rune c; if(Fchars(f, &c, p, p+1)==1 && c=='\n') goto Step; } break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.p[0].p1 = -tlp->se.p[0].p1; /* minus sign */ tlp->se.p[0].p2 = p; bnewmatch(&tlp->se); break; } } } Return: return sel.p[0].p1>=0; } void bnewmatch(Rangeset *sp) { int i; if(sel.p[0].p1<0 || sp->p[0].p1>sel.p[0].p2 || (sp->p[0].p1==sel.p[0].p2 && sp->p[0].p2p[i].p2; sel.p[i].p2 = sp->p[i].p1; } } wily-0.13.41/tools/old/edit/sam.c100644 2743 200 10540 6041414442 14764 0ustar garypgrad/* * sam.c - some stubs and interface code to tie sam's regexp.c * to some standalone programs that hack a Rune-based file * extracted from a wily window. * S. Kilbane, 21/9/95. */ #include #define SAM_CODE #include "range.h" /* the File that we're going to operate on.. */ File runefile; /* * some global stuff that should be tidied up later... */ char origfile[FILENAME_MAX+1], origaddr[FILENAME_MAX+1]; char tmpfilename[FILENAME_MAX+1]; Subrange *minmax; ulong base; char *utffile; int modified; static jmp_buf regexp_state; static char *errs[] = { "Etoolong", "Eleftpar", "Erightpar", "Emissop", "Ebadregexp", "Ebadclass", "Eoverflow" }; /* * Initialise a File to the Text given. */ void Finit(File *f, char *filename) { /* load the file in. */ struct stat st; FILE *fp; ulong p0 = 0, p1; if (stat(filename,&st)) { perror(filename); exit(1); } p1 = st.st_size / RUNESIZE; if ((fp = fopen(filename,"r")) == 0) { perror(filename); exit(1); } f->nrunes = f->ngetc = p1; f->dot.r.p1 = 0; f->dot.r.p2 = p1; f->dot.f = f; f->getcbuf = salloc(p1*RUNESIZE); f->getci = f->getcp = 0; /* start at beginning of range */ fread(f->getcbuf, p1, RUNESIZE, fp); fclose(fp); return; } /* * stub routines */ int Fgetcload(File *f, Posn p) { return 0; } int Fbgetcload(File *f, Posn p) { return -1; } int Fbgetcset(File *f, Posn p) { f->getcp = f->getci = p; return f->ngetc = f->nrunes; } int Fgetcset(File *f, Posn p) { f->getcp = f->getci = p; return f->ngetc = f->nrunes; } long Fchars(File *f, Rune *r, Posn p0, Posn p1) { long n; if (p0 > f->nrunes) p0 = f->nrunes; if (p1 > f->nrunes) p1 = f->nrunes; if ((n = p1-p0) < 0) { fprintf(stderr, "regexp: Negative amount asked for by Fchars()"); return 0; } memcpy(r,f->getcbuf+p0, n*sizeof(Rune)); return n; } /* * compile the regexp * returns 0 for success. */ int init_regexp(char *re) { static String str; int l = strlen(re); if (str.n <= l) { str.n = ++l; l *= sizeof(Rune); str.s = srealloc(str.s,l); } if (setjmp(regexp_state)) return 0; /* error occurred */ str.s[utftotext(str.s, re, re+strlen(re))] = 0; compile(&str); return (startinst == 0); } /* * run_regexp(p0,p1) - the interface between wily and sam. * compile the regexp, and do a search from the current point. * If we find a match, set p0 and p1, and return true. Otherwise, * return false. */ int run_regexp(ulong q0, ulong q1, ulong *p0, ulong *p1) { if (setjmp(regexp_state)) return 0; /* error occurred */ if (execute(&runefile, q0, q1)) { *p0 = sel.p[0].p1; *p1 = sel.p[0].p2; return 1; } /* no match */ return 0; } void panic(char *str) { (void)fprintf(stderr,"panic:%s\n",str); exit(1); } void * emalloc(ulong len) { return salloc(len); } void * erealloc(void *ptr, ulong len) { return srealloc(ptr,len); } void samerror(Err e) { fprintf(stderr,"regexp error: %s\n",errs[e]); longjmp(regexp_state, 1); } void Strduplstr(String *s0, String *s1) { ulong n; n = s1->n * RUNESIZE; if (s0->n < s1->n) s0->s = erealloc(s0->s, n); s0->n = s1->n; memcpy(s0->s, s1->s, n); } int Strcmp(String *s0, String *s1) { Rune *i, *j; if (!s0->s || !s1->s) return 1; for (i = s0->s, j = s1->s; *i && (*i == *j); i++, j++) ; return *i != *j; } void error_c(Err e, int c) { fprintf(stderr,"regexp: %s, %c\n", errs[e], c); } void Strzero(String *s) { memset(s->s, 0, s->n*RUNESIZE); } /* * Read the information about the file from stdin. * returns 0 for success. */ void read_info(int rev) { static char ranges[FILENAME_MAX]; scanf("%s%s%s%d%lu\n",origfile,origaddr,tmpfilename, &modified,&base); DPRINT("of=%s,.=%s\n", origfile, origaddr); DPRINT("tf=%s,%s\n",tmpfilename, modified? "modified" : "unchanged"); /* this is a simple implementation - we just look at the ranges received, and take the widest area covered. */ if ((minmax = read_ranges(rev)) == 0) { fprintf(stderr,"failed to read ranges\n"); exit(1); } DPRINT("Chosen range: %lu-%lu\n",minmax->p0, minmax->p1); return; } /* * The following is copied from libtext/text.c, to prevent having * to link with the whole libtext library, and hence the libframe * library.c */ ulong utftotext(Rune *r, char *s1, char *s2) { Rune *q; char *t; if (s2 <= s1) return 0; for (t = s1, q = r; t < s2; q++) if (*(uchar *)t < Runeself) *q = *t++; else t += chartorune(q, t); return t-s1; } wily-0.13.41/tools/old/edit/sam.h100644 2743 200 4663 6041414442 14762 0ustar garypgrad/* This source file is derived from the sam.h file in the sam distribution, which is: */ /* Copyright (c) 1992 AT&T - All rights reserved. */ /* * sam and wily both define an error() function. To avoid changing * anything in regexp.c, we use a macro to rename it. This relies * on other wily functions including wily.h before sam.h. */ #ifndef WILY_H #define error(X) samerror(X) #define SAM_CODE #endif #include #include #include #include "wily.h" #define NSUBEXP 10 /* number of () matches in a regexp */ typedef long Posn; /* file position or address */ typedef struct Address Address; typedef struct File File; typedef struct Range Range; typedef struct Rangeset Rangeset; typedef struct String String; typedef struct Inst Inst; typedef enum { Etoolong, Eleftpar, Erightpar, Emissop, Ebadregexp, Ebadclass, Eoverflow } Err; struct String { int n; Rune *s; }; struct Range { Posn p1, p2; }; struct Rangeset { Range p[NSUBEXP]; }; struct Address { Range r; File *f; }; #define FALSE 0 #define TRUE 1 #define RUNESIZE (sizeof(Rune)) #define NGETC 128 /* Shouldn't actually be used */ #define INFINITY 0x7FFFFFFFL /* * In the original sam.h, the File structure is that which manages * all the caches and buffers of the file being edited. We're not * concerned with any of that - we just want to make the contents * of a Text look like a File to sam. */ struct File { Text *t; /* the Text that we'll search */ Posn nrunes; /* total length of file */ Address dot; /* current position */ Rune *getcbuf; /* pointer to t->text */ int ngetc; /* must be ==nrunes */ int getci; /* index into getcbuf */ Posn getcp; /* must ==getci */ }; #define Fgetc(f) ((--(f)->ngetc<0)? Fgetcload(f, (f)->getcp) : (f)->getcbuf[(f)->getcp++, (f)->getci++]) #define Fbgetc(f) (((f)->getci<=0)? Fbgetcload(f, (f)->getcp) : (f)->getcbuf[--(f)->getcp, --(f)->getci]) int Fbgetcload(File*, Posn); int Fbgetcset(File*, Posn); long Fchars(File*, Rune*, Posn, Posn); int Fgetcload(File*, Posn); int Fgetcset(File*, Posn); int bexecute(File*, Posn); void compile(String*); int execute(File*, Posn, Posn); void nextmatch(File*, String*, Posn, int); void *emalloc(ulong); void *erealloc(void*, ulong); void error_c(Err, int); void panic(char*); void Strduplstr(String *, String *); int Strcmp(String *, String *); void Strzero(String *); void error(Err); /* really samerror() */ extern Rangeset sel; extern Inst *startinst; wily-0.13.41/tools/old/edit/x.c100644 2743 200 3230 6041414442 14431 0ustar garypgrad/* * x.c - this is actually the source for x, y, g and v. There's not a lot * of point having separate programs... */ #include "range.h" Bool debug = false; static const char *fmt = "#%lu,#%lu\n"; void fn_x(ulong p0, ulong p1) { ulong q0, q1; while (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) { printf(fmt,q0,q1); p0 = q1; } } void fn_y(ulong p0, ulong p1) { ulong q0, q1; while (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) { if (p0 < q0) printf(fmt,p0,q0); p0 = q1; } if (p0 < p1) printf(fmt,p0,p1); } void fn_g(ulong p0, ulong p1) { ulong q0, q1; if (p0 < p1 && run_regexp(p0, p1, &q0, &q1)) printf(fmt,p0,p1); } void fn_v(ulong p0, ulong p1) { ulong q0, q1; if (p0 < p1 && run_regexp(p0, p1, &q0, &q1)==0) printf(fmt,p0,p1); } int main(int argc, char *argv[]) { char *p, *re; size_t len; Subrange *r; void (*fn)(ulong p0, ulong p1); /* This isn't wonderful: assume that the regexp is delimited by // */ if (argc < 2 || *(re = argv[1]) != '/' || (len = strlen(re)) < 2) { fprintf(stderr,"Usage: x /regexp/\n"); exit(1); } if (re[--len] == '/') re[len] = 0; re++; /* skip / */ if (len == 0) { fprintf(stderr,"null regexp\n"); exit(1); } if (init_regexp(re)) { fprintf(stderr,"Invalid regexp\n"); exit(1); } p = strrchr(argv[0], '/'); p = p? p+1 : argv[0]; switch (*p) { case 'x' : fn = fn_x; break; case 'y' : fn = fn_y; break; case 'g' : fn = fn_g; break; case 'v' : fn = fn_v; break; default: fprintf(stderr,"Uknown program name!\n"); exit(1); } read_info(0); /* Don't reverse ranges */ Finit(&runefile, tmpfilename); write_info(); while (r = next_range()) (*fn)(r->p0, r->p1); exit(0); } wily-0.13.41/tools/old/edit/patch100644 2743 200 6311 6041414442 15043 0ustar garypgrad*** text.c.orig Tue Sep 26 18:34:30 1995 --- text.c Tue Sep 26 17:40:49 1995 *************** *** 79,93 **** void doread(Text *t, char *addr) { ! ulong p0,p1; char *buf; int n; assert(t && t->xfd && t->datatype == Tpanetext); ! /* todo - stop cheating */ ! p0 = atoi(addr+1); ! p1 = t->length; n = p1 - p0 +1; assert(n>0); buf = salloc(2*n); --- 79,99 ---- void doread(Text *t, char *addr) { ! ulong p0,p1, t0, t1; char *buf; int n; assert(t && t->xfd && t->datatype == Tpanetext); ! if (!addr) ! return; ! t0 = t->p0; ! t1 = t->p1; ! /* addr is assumed to *not* have a preceding ":" here */ ! if (text_addr2sel(t, addr, &p0, &p1)) ! return; ! t->p0 = t0; ! t->p1 = t1; n = p1 - p0 +1; assert(n>0); buf = salloc(2*n); *************** *** 279,285 **** if (addr[0] == '.' && addr[1] == '\0') { *pp0 = t->p0; *pp1 = t->p1; ! return 0; /* todo - ask bill what should really be returned */ } n = atoi(addr); --- 285,291 ---- if (addr[0] == '.' && addr[1] == '\0') { *pp0 = t->p0; *pp1 = t->p1; ! return 1; /* smk - need to have this recognise '.' */ } n = atoi(addr); *************** *** 307,332 **** return 1; } ! /* PRE: 't' is the body of some pane, 'addr' is some string to search for. ! * 'addr' may be null. ! * POST: 't' is visible, the next occurrence of 'addr' is highlighted, ! * if it exists. */ ! void ! text_goaddr(Text *t, char *addr) { - ulong p0, p1; char *addr2; ! Pane *pane; - pane = (Pane*)t->data; - assert(pane_isgood(pane) && pane->text ==t); - - pane_raise(pane); - - if(!addr) - return; - /* * Find the second addr in the pair. Some complexity here: * (1) If the first addr is a regexp, must first find its end -- but watch --- 313,330 ---- return 1; } ! ! /* ! * given a Text and a string containing an address, return ! * the (p0,p1) that the address defines. */ ! ! int ! text_addr2sel(Text *t, char *addr, ulong *pp0, ulong *pp1) { char *addr2; ! ulong p0, p1; /* * Find the second addr in the pair. Some complexity here: * (1) If the first addr is a regexp, must first find its end -- but watch *************** *** 352,358 **** if (*addr == '\0') p0 = 0; else if (!findend(t, addr, &p0, &p1)) ! return; if (addr2) { ulong p2, pjunk; --- 350,356 ---- if (*addr == '\0') p0 = 0; else if (!findend(t, addr, &p0, &p1)) ! return 1; if (addr2) { ulong p2, pjunk; *************** *** 364,371 **** --- 362,397 ---- p1 = p2; } } + *pp0 = p0; + *pp1 = p1; + return 0; + } + + /* PRE: 't' is the body of some pane, 'addr' is some string to search for. + * 'addr' may be null. + * POST: 't' is visible, the next occurrence of 'addr' is highlighted, + * if it exists. + */ + void + text_goaddr(Text *t, char *addr) + { + ulong p0, p1; + char *addr2; + Pane *pane; + + pane = (Pane*)t->data; + assert(pane_isgood(pane) && pane->text ==t); + + pane_raise(pane); + + if(!addr) + return; + + if (text_addr2sel(t, addr, &p0, &p1)) + return; if (p1 < p0) return; + last_selection = t; textshow(t, p0+1, 1); texthighlight(t, p0, p1, F&~D); textwarp(t, (p0+p1)/2); wily-0.13.41/tools/old/edit/Makefile100644 2743 200 1140 6041414442 15454 0ustar garypgradTARGETS=e q x c LDFLAGS=-L../libmsg -L../libXg LDLIBS=-lmsg -lXg -lsocket -lnsl CPPFLAGS += -I../include -I../wily CFLAGS += -g ROBJS = range.o sam.o regexp.o COBJS = $(ROBJS) change.o all: $(TARGETS) q: q.o $(COBJS) $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) q.o $(COBJS) $(LDFLAGS) $(LDLIBS) c: c.o $(COBJS) $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) c.o $(COBJS) $(LDFLAGS) $(LDLIBS) $(RM) d i a ln c d ln c i ln c a x: x.o $(COBJS) $(CC) -o $@ $(CFLAGS) $(CPPFLAGS) x.o $(COBJS) $(LDFLAGS) $(LDLIBS) $(RM) y g v ln x y ln x g ln x v clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGETS) g v y i a d wily-0.13.41/tools/old/edit/README100644 2743 200 2677 6041414442 14714 0ustar garypgradThis is far from complete, but I've had so little time to work on it this week, and wily's had so many releases, that I thought I may as well give others a chance to play with it. Besides, I was getting fed up with applying that patch to text.c. This includes regexp.c, but again, it's unchanged from the original. The sam.[ch] here are different from those in wily itself. This works on my machine with the pipeline: e file | x /regexp/ | c word | q but I haven't played with many combinations yet. As long as the text.c patch goes in, then it will be easier to test it, rather than trying to keep up with wily revisions. Couple of major points: - e asks wily for "." by default, if no address is given. During the resolution of this, wily attempts to open "/path/." where e has asked for "." in /path/name. This is kind of weird, and is part of the context rules. I'm not sure what to do about it. - "q" isn't really necessary, if we take acme's stance, and say that you can only have one of c,i,a,d in the pipeline. Seems a little mean to me, since they don't supply s. I've tried to arrange things so that you can pipe c,i,d,a into each other, but that's not working yet. Or we could just give up (combinations of i and a are ok, c and d don't make a lot of sense in combination), add s, and dump q. Which will probably for the best anyway. - I haven't done anything about arranging things so that Wily allows Undoing, yet. Haven't even looked into it. Steve wily-0.13.41/tools/old/reader/ 40755 2743 200 0 6141130621 14233 5ustar garypgradwily-0.13.41/tools/old/reader/README100644 2743 200 12667 6052326245 15256 0ustar garypgradFirst bash at a mail reader. There are two pieces of code here: First off, you've got the generalised reader/viewer thingy. This is intended to be used as the basis for a newsreader too, but I obviously haven't got that far yet. It's mostly either implemented or hooks, depending on which part you look at. It supports windows of articles and lists of subjects, and there can be lots of either type. However, I've only ever run it with one list window, so I've no idea if the code'll work if you try multiple articles. It has hooks for saving internal copies of window contents, but I don't use them at the moment (I can't be bothered to work out what to do if someone does a sweeping delete of half the contents of a list window). Makefile getmsg.c Gets messages from wily. Used to be ridiculously complicated, before libmsg took over msg queueing (thank you, gary). headers.h proto.h reader.c The generic reader thingy. Unpleasant. reader.h utils.c Coupla handy things. Then you've got the mail-specific stuff. This currently cheats for sending messages. For example, it uses the From: line, and just feeds articles into sendmail without caring what they look like. mail.c Main mail program. mail.h Definitions. Hack MTU to be something that accepts a complete article on stdin, including headers. mbox.c Mailbox handling routines. These are actually swiped from a 9term-like mail reader I wrote about a year ago, and never finished. I *think* they're ok at updating your mailbox, but, well, they might not be. Handle with care. mbox.h solaris.c The mbox routines assume that the whole mail file is accessible as a single string. This uses malloc/fread to do this. It used to use mmap(), but that's buggy over NFS. includepatches Changes to the libmsg prototypes. libmsgpatches Some additions to the msg library: - rpc_settag() and rpc_setname() added. - rpc_new() gets a "isreal" argument. wilypatches Hacks to wily, against 0.9.5. Looking through them, they do: - Add a "Dot" builtin, that toggles display of .* files. By default, they're not shown. B2 on Dot and Get to show them. - Adds support for rpc_goto() to wily. - Adds (very basic) support for rpc_settag() to wily. - Doesn't complain about virtual windows, or attempt to back them up. winpatches Just changes win to say its window isn't real. USAGE Invoke with "mreader [-ma] mailboxname". The "-ma" option allows you to have multiple article windows open at once. By default, it only has the one article window open, because it's easier to find where the article window is, once you've positioned it. Unfortunately, this means that you don't get to see the article you're replying to. To fix this, there's a "multiart" command, which toggles this value from within the reader. First window to appear is the list window. It shows all the articles from the given mailfile, one per line. The line contains the From and Subject fields, but it's currently chopped to make things look nicer. You open an article by B3'ing on its subject line. What else? Commands supported: exit exit without doing anything to the mailfile. quit save any changes to the mailfile before quitting. delete delete the selected article. "selected" means the article which has dot in its subject line. This means you can click on the subject line with either B1 or B3, and then click on delete. Of course, if you click on delete within an article window, that article is the one that is deleted. Delete doesn't actually do anything except mark the article for deletion, and puts a "D" before at the start of the subject line. undelete reverses delete. comp compose a new message. You get a blank article window with From, To and Subject fields. Don't delete them. reply Reply to the article (article is selected in the same fashion, i.e. B1/B3 list window, or just the article that the reply cmd was executed in). The To field is filled in from the From field. You can use "inc" or "incall" to include the text of the article you're replying to. abort junk a comp/reply article without sending it. deliver post a complete comp/reply article (well, feed it to sendmail). savefile sets the name of the file that "save" writes to. save appends the current message into the savefile. Creates the file if it doesn't exist. multiart toggles the "only one article window at once" flag. This is handy for viewing several articles or reading one article while replying to another. inc [n] Includes a message into the current position of the current message. It's supposed to accept a message number, too, but I haven't tried that. incall Same as inc, but will include the headers of the message, too. Bugs Vast numbers of them... Currently needs to have at least *something* in your mailbox, otherwise it exits. At the moment, it's one-shot - it never rescans your mailbox to see if more mail has arrived (except when writing changes back on "quit"; it *has* to then....). This means you still need another mail notification program. I recommend Faces. :-) The preferred means of reading the mailbox is with mmap(), but under Solaris 2.3, that's buggy for NFS-mounted directories, so right now it compiles with a malloc-and-fread method instead. Unlike most windows, it current has the tools *before* the window label. This is because of the broken tags problem. Right now, I'm cheating, and inserting the tools at the start of the tag, instead of the end - that seems to work... wily-0.13.41/tools/old/reader/getmsg.c100644 2743 200 457 6052054010 15746 0ustar garypgrad/* * getmsg.c - handle message reception from wily. */ #include "headers.h" rdWin * getActiveWin(void) { rdWin *w; Msg *m; Id id; if ((m = mq_next(wilyq, 0)) == 0) return 0; id = msg_id(m); for (w = windows; w; w = w->next) if (id == w->id) { w->m = m; return w; } return 0; } wily-0.13.41/tools/old/reader/headers.h100644 2743 200 432 6053054374 16107 0ustar garypgrad#ifndef RD_HEADERS_H #define RD_HEADERS_H #include #include #include #include #include #include #include #include #include #include "reader.h" #include "proto.h" #endif /* RD_HEADERS_H */ wily-0.13.41/tools/old/reader/mail.c100644 2743 200 24762 6052057466 15471 0ustar garypgrad/* * some notes on how this is arranged. * call readerInit(title, msgs, 0, 1, 0) to create things. * call readerMainLoop(). * callbacks: * user_listSelection(w,n); * open new article win with getArtWin(title,text,0,0); * user_cmdExec(w,builtin,cp0,cp1,cmd,p0,p1,arg); */ #include "headers.h" #include "mbox.h" #include "mail.h" static void build_msg_list(); mWin *allocMWin(int kind, int num); void freeMWin(mWin *w); mWin *findMWin(void *ptr); int artDisplayed(rdWin *w, int n); void mDelete(rdWin *w, int n, char *arg); void mUndelete(rdWin *w, int n, char *arg); void mComp(rdWin *w, int n, char *arg); void mExit(rdWin *w, int n, char *arg); void mQuit(rdWin *w, int n, char *arg); void mReply(rdWin *w, int n, char *arg); void mAbort(rdWin *w, int n, char *arg); void mDeliver(rdWin *w, int n, char *arg); void mSavefile(rdWin *w, int n, char *arg); void mSave(rdWin *w, int n, char *arg); void dodeliver(rdWin *w, char *filename); void mMultiart(rdWin *w, int n, char *arg); void mIncludeall(rdWin *w, int n, char *arg); void mInclude(rdWin *w, int n, char *arg); void doinclude(rdWin *w, int n, char *arg, int all); mMbox *mbox; static char mboxname[FILENAME_MAX]; mWin *mwindows; mWin *listwin; static char **msgs; static char *savefile; static int multiart = 0; int main(int argc, char *argv[]) { mWin *mw; int ma = 0; printf("kill %d\n",getpid()); fflush(stdout); if (argc >=2 && strcmp(argv[1], "-ma")==0) { ma = 1; argc--; argv++; } multiart = ma; if (argc >= 2) strcpy(mboxname, argv[1]); else sprintf(mboxname,"/var/mail/%s", getenv("USER")); if ((mbox = read_mbox((const char *)mboxname, 0)) == 0) { perror(mboxname); exit(1); } mw = listwin = allocMWin(mMsgList, 0); build_msg_list(); if (readerInit(0, (char *)mw, mboxname, msgs, 0, ma, 0)) exit(1); readerMainLoop(); printf("Finished\n"); exit(0); } mWin * allocMWin(int kind, int num) { mWin *w = salloc(sizeof(*w)); mWin **p = &mwindows; w->kind = kind; w->msg = (kind == mDispArt || kind == mCompArt)? num : -1; w->mbox = mbox; w->next = 0; while (*p) p = &((*p)->next); *p = w; return w; } void freeMWin(mWin *w) { mWin **p = &mwindows; while (*p != w) p = &((*p)->next); *p = w->next; free(w); } mWin * findMWin(void *ptr) { mWin *mw = mwindows; while (mw && (mWin *)ptr != mw) mw = mw->next; return mw; } static void chkhdr(mString *s, int *len, char **rest) { int l; *rest = ""; /* default */ if (s == 0) { *len = 0; return; } l = s->s1 - s->s0; if (l > 20) { l = 20; *rest = "..."; } else if (l > 0) l--; /* skip newline */ *len = l; } static void build_msg_list(void) { int n; mMsg *m; ulong l; int lfrom, ldate, lsubject; char *rfrom, *rdate, *rsubject; mString *from; mString *date; mString *subject; int dc; if (msgs) for (n = 0; msgs[n]; n++) free(msgs[n]); msgs = (char **)srealloc(msgs, (mbox->nmsgs+1) * sizeof(char *)); for (n = 0; n < mbox->nmsgs; n++) { m = mbox->msgs[n]; dc = m->deleted? 'D' : ' '; from = m->from; date = m->date; subject = m->subject; chkhdr(from, &lfrom, &rfrom); chkhdr(date, &ldate, &rdate); chkhdr(subject, &lsubject, &rsubject); l = lfrom + ldate + lsubject + 10; msgs[n] = salloc(l); sprintf(msgs[n],"%c%d %.*s%s %.*s%s", dc, n+1, lfrom, from->s0, rfrom, lsubject, subject->s0, rsubject); } msgs[n] = 0; return; } void user_listSelection(rdWin *w, int n) { static char title[300]; mMsg *m = mbox->msgs[n]; mString *from = m->from; mString *body = &m->whole; static char *text; static size_t textlen; size_t len; mWin *mw; if (artDisplayed(w, n)) return; mw = allocMWin(mDispArt,n); sprintf(title," Mail/%d/%.*s ",n+1, from->s1 - from->s0, from->s0); title[50] = 0; /* XXX - to make sure it's not too long. */ len = body->s1 - body->s0; if (len >= textlen) { textlen = len + 1; text = srealloc(text, textlen); } memcpy(text, body->s0, len); text[len] = 0; getArtWin(n, mw, title, text, 0, 0); } int artDisplayed(rdWin *w, int n) { mWin *mw; for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) if ((w = userpWin(mw))) { rdGotoWin(w); return 1; } return 0; } static struct mCmd mcmds[] = { { "quit", MCANY, mQuit }, { "exit", MCANY, mExit }, { "reply", MCNOTCOMP, mReply }, { "delete", MCNOTCOMP, mDelete }, { "undelete", MCMSGLIST, mUndelete }, { "comp", MCMSGLIST, mComp }, { "abort", MCCOMPART, mAbort }, { "deliver", MCCOMPART, mDeliver }, { "savefile", MCANY, mSavefile }, { "save", MCANY, mSave }, { "multiart", MCANY, mMultiart}, { "inc", MCCOMPART, mInclude}, { "incall", MCCOMPART, mIncludeall}, { 0, 0, 0 } }; void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, int n, char *arg) { int c; printf("user_cmdList(w,%s,%lu,%lu, msg %d, %s)\n", cmd, p0, p1, n+1, arg); fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { printf("%s reflected\n",cmd); fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ if ((mcmds[c].context & MCMSGLIST) == 0) { fprintf(stderr,"%s: only valid within the message list\n", cmd); return; } (*mcmds[c].fn)(w, n, arg); return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; mWin *mw; unsigned short context; printf("user_cmdArt(w, %s, %lu, %lu, %s)\n", cmd, p0, p1, arg); fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { printf("%s reflected\n",cmd); fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((mw = findMWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } context = (mw->kind == mDispArt)? MCDISPART : MCCOMPART; if ((mcmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } (*mcmds[c].fn)(w, mw->msg, arg); return; } void mDelete(rdWin *w, int n, char *arg) { mWin *mw; rdWin *ow; if ((mw = findMWin(w->userp)) == 0) return; if (mw->mbox->msgs[n]->deleted) return; mw->mbox->msgs[n]->deleted = 1; mw->mbox->ndel++; if (mw->kind != mDispArt) /* might be the msg list */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) break; if (mw) { if ((ow = userpWin(mw))) /* this msg is displayed; remove the pane */ closeWin(ow); freeMWin(mw); } build_msg_list(); changeItems(userpWin(listwin), msgs, 0); return; } void mUndelete(rdWin *w, int n, char *arg) { mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; if (!mw->mbox->msgs[n]->deleted) return; mw->mbox->msgs[n]->deleted = 0; mw->mbox->ndel--; build_msg_list(); changeItems(userpWin(listwin), msgs, 0); return; } void mReply(rdWin *w, int n, char *arg) { mWin *mw = allocMWin(mCompArt, n); char *title = "Reply abort deliver "; static char body[300]; /* XXX */ mString *from = mbox->msgs[n]->from; mString *subject = mbox->msgs[n]->subject; int lfrom, lsubject; char *me = getenv("USER"); char *re = "Re: "; if (!me || !*me) me = ""; lfrom = (from->s1 - from->s0); /* include newline */ lsubject = (subject->s1 - subject->s0); if (lsubject > 4 && strncmp(subject->s0, re, 4)==0) re = ""; sprintf(body,"From: %s\nTo: %.*sSubject: %s%.*s\n", me, lfrom, from->s0, re, lsubject, subject->s0); getArtWin(n, mw, title, body, 0, 0); return; } void mAbort(rdWin *w, int n, char *arg) { mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; fprintf(stderr,"Message aborted\n"); closeWin(w); freeMWin(mw); return; } void mDeliver(rdWin *w, int n, char *arg) { mWin *mw; char *filename = tmpnam((char *)0); if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; fprintf(stderr,"Attempting to deliver message"); rdBodyToFile(w, filename); dodeliver(w,filename); return; } void mQuit(rdWin *w, int n, char *arg) { update_mbox(mbox); mExit(w, n, arg); } void mExit(rdWin *w, int n, char *arg) { mWin *mw; rdWin *rw; /* close msg windows first */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mCompArt || mw->kind == mDispArt) if ((rw = userpWin(mw))) closeWin(rw); for (mw = mwindows; mw; mw = mw->next) if (mw->kind != mCompArt && mw->kind != mDispArt) if ((rw = userpWin(mw))) closeWin(rw); exit(0); /* not actually needed - reader will exit for us */ } void mComp(rdWin *w, int n, char *arg) { mWin *mw = allocMWin(mCompArt, n); char *title = "Compose abort deliver "; static char body[300]; /* XXX */ char *me = getenv("USER"); if (!me || !*me) me = ""; sprintf(body,"From: %s\nTo: \nSubject: \n\n", me); getArtWin(n, mw, title, body, 0, 0); return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; sprintf(cmd,"%s < %s", MTU, filename); printf("command: '%s'\n",cmd); fflush(stdout); system(cmd); closeWin(w); freeMWin(mw); return; } void mSavefile(rdWin *w, int n, char *arg) { if (savefile) free(savefile); savefile = sstrdup(arg); } void mSave(rdWin *w, int n, char *arg) { FILE *fp; mWin *mw; mMsg *m; mString *text; size_t len; if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); return; } if ((mw = findMWin(w->userp)) == 0) return; m = mw->mbox->msgs[n]; text = &m->whole; len = text->s1 - text->s0; if (fwrite(text->s0, (size_t)1, len, fp) != len) perror("fwrite"); fputc('\n',fp); printf("Written message %d to %s\n", n, savefile); fflush(stdout); fclose(fp); } void mMultiart(rdWin *w, int n, char *arg) { multiart = !multiart; rdSetMulti(0, multiart); } void mInclude(rdWin *w, int n, char *arg) { doinclude(w,n,arg,0); } void mIncludeall(rdWin *w, int n, char *arg) { doinclude(w,n,arg,1); } void doinclude(rdWin *w, int n, char *arg, int all) { mWin *mw; rdWin *ow; int msgnum; /* message we're going to include */ mMsg *m; mString *s; size_t len; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; msgnum = mw->msg; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) == 0) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum--; } } if (msgnum >= mw->mbox->nmsgs) { fprintf(stderr,"Only %d messages\n", mw->mbox->nmsgs); return; } m = mw->mbox->msgs[msgnum]; s = all? &(m->whole) : &(m->body); len = s->s1 - s->s0; rdInclude(w, s->s0, len); } wily-0.13.41/tools/old/reader/mail.h100644 2743 200 2272 6052054013 15427 0ustar garypgrad/* * stuff needed for the mail client. * smk */ #include "headers.h" #include "mbox.h" typedef struct _mWin mWin; /* * We know of several different kinds of window: mailbox lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind; /* what kind of window it is */ int msg; /* message number, if mDispArt, or mCompArt */ mMbox *mbox; /* the message box we're associated with */ struct _mWin *next; }; /* * These are the commands that the mailer recognises, and the * contexts that they are valid. */ #define MCMSGLIST 01 #define MCDISPART 02 #define MCCOMPART 04 #define MCNOTCOMP (MCMSGLIST|MCDISPART) #define MCANY (MCMSGLIST|MCDISPART|MCCOMPART) struct mCmd { char *cmd; unsigned short context; void (*fn)(rdWin *, int, char *); /* pane, msg num, arg */ }; /* * The following must be the pathname of a program capable * of taking a complete message on stdin, with no arguments, * and delivering it. */ #define MTU "/usr/lib/sendmail -t" wily-0.13.41/tools/old/reader/mbox.c100644 2743 200 15520 6052054015 15467 0ustar garypgrad/* * mbox.c */ #include "headers.h" #include "mbox.h" #include #include #define COPYSIZE 8192 #define INCR 10 static mMbox *currmbox; /* current mbox being processed */ static mMsg *msg; /* current message */ static int nhdrs; /* number of current headers read so far. */ static int ahdrs; /* number of allocated hhdrs */ static mHdr **hdrs; /* current list */ static char *readhdrs(char *ptr); static void mkhdr(char *s0, char *s1); static void checkhide(mHdr *h); static void newmsg(char *s0); static char *readmsg(char *ptr); static int same(mString a, mString b); static int strsame(char *s, mString b); static void fillmsg(mMsg *msg); static void fillhdr(char *name, mMsg *msg, mString **ptr); static ulong getlength(void); static char *findend(char *ptr); /* * readhdrs(ptr) - read the headers in a message, looking for * the terminating newline. Returns pointer to first char in body. */ static char * readhdrs(char *ptr) { char *nptr = ptr; /* invariant is that nptr pts to first char of next header. when it doesn't (nptr==\n), we've reached the blank line at then end of the hdrs */ while (*nptr != '\n') { if ((nptr = strchr(nptr,'\n')) == 0) panic("No newlines in readhrds()"); if (nptr[1]==' ' || nptr[1]=='\t') { /* multi-line hdr */ nptr++; continue; } else { mkhdr(ptr, ++nptr); ptr = nptr; continue; } } return ++nptr; /* skip blank line */ } /* * mkhdr(s0,s1) - add a new header to the current list. */ static void mkhdr(char *s0, char *s1) { size_t l; char *c = strchr(s0, ':'); mHdr *h; if (c == 0) panic("no colon in hdr"); if (nhdrs >= ahdrs) { ahdrs += INCR; l = ahdrs * sizeof(*hdrs); hdrs = (mHdr **)(hdrs? realloc(hdrs,l) : malloc(l)); if (hdrs == 0) panic("resizing hdr list"); } h = hdrs[nhdrs++] = (mHdr *)malloc(sizeof(*h)); if (h == 0) panic("adding new hdr"); h->name.s0 = s0; h->name.s1 = c++; while (*c == ' ' || *c == '\t') c++; h->value.s0 = c; h->value.s1 = s1; checkhide(h); } static void checkhide(mHdr *h) { /* none are hidden, for now. */ h->hide = 0; } static void newmsg(char *s0) { size_t n; if (currmbox->nmsgs >= currmbox->amsgs) { currmbox->amsgs += INCR; n = currmbox->amsgs*sizeof(*currmbox->msgs); currmbox->msgs = (mMsg **)(currmbox->msgs? realloc(currmbox->msgs,n) : malloc(n)); if (currmbox->msgs == 0) panic("newmsg msg"); } msg = currmbox->msgs[currmbox->nmsgs++] = (mMsg *)malloc(sizeof(*msg)); if (msg == 0) panic("adding new msg"); memset(msg,0,sizeof(*msg)); msg->whole.s0 = s0; if ((hdrs = (mHdr **)malloc((ahdrs = INCR)*sizeof(*hdrs)))==0) panic("newmsg hdrs"); nhdrs = 0; } /* * readmsg(ptr) - read a complete message. Assumes we're already pointing * to the F of the "From " */ static char * readmsg(char *ptr) { char *nptr; ulong contentlength; newmsg(ptr); /* resets nhdrs and hdrs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.s0 = nptr; if ((contentlength = getlength()) == 0) nptr = findend(nptr); else nptr += contentlength; msg->whole.s1 = msg->body.s1 = nptr; fillmsg(msg); /* update from,date,subject fields */ return nptr+1; } static int same(mString a, mString b) { if ((a.s1 - a.s0) != (b.s1 - b.s0)) return 0; return (strncmp(a.s0,b.s0,a.s1-a.s0) == 0); } static int strsame(char *s, mString b) { mString a; a.s0 = s; a.s1 = s + strlen(s); return same(a,b); } static void fillmsg(mMsg *msg) { fillhdr("From",msg,&msg->from); fillhdr("Date",msg,&msg->date); fillhdr("Subject",msg,&msg->subject); } static void fillhdr(char *name, mMsg *msg, mString **ptr) { int x; static mString empty; for (x = 0; x < msg->nhdrs; x++) if (strsame(name,msg->hdrs[x]->name)) { *ptr = &(msg->hdrs[x]->value); return; } /* Sigh. This sort of thing is very irritating. */ empty.s0 = empty.s1 = msg->whole.s1; *ptr = ∅ (void)fprintf(stderr,"Message does not have a '%s' header\n",name); } static ulong getlength(void) { int x; ulong l; for (x = 0; x < nhdrs; x++) if (strsame("Content-Length",hdrs[x]->name)) goto found; return 0; found: /* use sscanf magic to skip whitespace, and stop at end */ if (sscanf(hdrs[x]->value.s0,"%lu",&l) != 1 || l==0) return 0; if ((msg->body.s0+l+1) == currmbox->mbox_end) return l; /* spot on */ if ((msg->body.s0+l+5) >= currmbox->mbox_end) return 0; /* too long */ if (strncmp("\nFrom ",(msg->body.s0+l),6) == 0) return l; else return 0; } static char * findend(char *ptr) { for (; ptr+5 <= currmbox->mbox_end && strncmp("\nFrom ",ptr,6); ptr++) if ((ptr = strchr(ptr,'\n')) == 0) panic("findend"); if (ptr+5 > currmbox->mbox_end) return currmbox->mbox_end-1; else return ptr; } mMbox * read_mbox(const char *filename, int readonly) { char *ptr; extern int load_mbox(mMbox *); if ((currmbox = (mMbox *)malloc(sizeof(*currmbox))) == 0) return 0; memset(currmbox,0,sizeof(*currmbox)); currmbox->readonly = readonly; if ((currmbox->name = strdup(filename)) == 0) goto panic2; if (load_mbox(currmbox)) goto panic1; for (ptr = currmbox->mbox_start; ptr < currmbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) goto panic1; return currmbox; panic1: free(currmbox->name); panic2: free(currmbox); return 0; } /* * update_mbox(mbox) - write any changes back to the file. */ int update_mbox(mMbox *mbox) { static char lockname[FILENAME_MAX+1], newname[FILENAME_MAX+1]; int ntries, maxtries = 10; int fd, fd2; int x; struct stat st; int r = 0; int l; mMsg *m; if (mbox->readonly || mbox->ndel == 0) return 0; (void)sprintf(lockname,"%s.lock",mbox->name); (void)sprintf(newname,"%s.new",mbox->name); for (ntries = 0; ntries < maxtries; ntries++) { if (link(mbox->name,lockname) == 0) goto locked; sleep(1); } locked: if (stat(mbox->name,&st) == -1) goto broken; if (st.st_size < mbox->size) { fprintf(stderr,"Mail file corrupted - no changes made\n"); goto broken; } if ((fd = open(newname,O_RDWR|O_CREAT|O_TRUNC)) < 0 || fchmod(fd,st.st_mode) == -1) goto broken; for (x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) continue; l = m->whole.s1 - m->whole.s0 + 1; if (write(fd,m->whole.s0,l) != l || write(fd,"\n",1) != 1) { fprintf(stderr,"write truncated, changes aborted\n"); goto broken; } } if (st.st_size > mbox->size) { static char buf[COPYSIZE]; if ((fd2 = open(mbox->name,O_RDONLY)) < 0 || lseek(fd2,mbox->size,SEEK_SET) == -1) { fprintf(stderr,"Can't open mbox for update!\n"); goto broken; } while ((l = read(fd2,buf,COPYSIZE)) > 0) if (write(fd,buf,l) != l) { fprintf(stderr,"Can't copy updated mbox\n"); close(fd2); goto broken; } close(fd2); } rename(newname,mbox->name); goto unlock; broken: r = 1; if (fd >= 0) close(fd); unlink(newname); unlock: unlink(lockname); return r; } wily-0.13.41/tools/old/reader/mbox.h100644 2743 200 3327 6052054016 15457 0ustar garypgrad/* * mbox.h - definitions for mailbox-handling library. */ #ifndef MBOX_H #define MBOX_H #include typedef struct mstring mString; typedef struct mhdr mHdr; typedef struct mmsg mMsg; typedef struct mhdrline mHdrLine; typedef struct mmbox mMbox; struct mstring { /* can include several \n characters */ char *s0; /* first char in string */ char *s1; /* char after last newline */ }; struct mhdr { /* includes ws if hdr is multiple lines */ mString name; /* s1 points to colon */ mString value; /* s0 pts to first non-ws, s1 to after \n */ int hide; /* don't display if true */ }; /* name,s0,value.s2 gives whole header */ struct mmsg { int nhdrs; /* number of headers */ mHdr **hdrs; /* headers themselves */ mString *from; /* points to value fields from mHdrs */ mString *date; mString *subject; mString whole; /* All of the message (headers and body) */ mString body; /* All of the body (not including first blank line) */ int deleted; /* marked for deletion */ int read; /* if has been read */ ulong pos; /* origin in window, if it's been read before. */ }; struct mhdrline { char *s0,*s1; /* buffer containing accumulated text */ ulong p0, p1; /* positions in hdrw for this piece of text */ }; struct mmbox { char *mbox_start; /* area of memory that the mailbox is */ char *mbox_end; /* loaded into */ int nmsgs; /* number of messages */ int amsgs; /* size of msgs array */ mMsg **msgs; /* the messages themselves */ int ndel; /* number of deleted messages */ int readonly; time_t mtime; /* time it was last modified */ off_t size; /* how big it was, last time we checked */ char *name; /* the filename */ }; mMbox *read_mbox(const char *filename, int readonly); #endif /* ! MBOX_H */ wily-0.13.41/tools/old/reader/proto.h100644 2743 200 2041 6052054017 15646 0ustar garypgradvoid queueMsg(rdWin *w); void freeMsgq(rdWin *w); rdWin *getActiveWin(void); int changeItems(rdWin *w, char **items, int savecontents); void user_listSelection(rdWin *w, int n); void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, int n, char *arg); void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg); char *sstrdup(char *str); int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents); int getListWin(int user, void *userp, char *title, char **items, int savecontents); int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents); int readerMainLoop(void); int itemNumber(rdWin *w, ulong p0, ulong p1, void **ptr); void highlightItem(rdWin *w, int n, void *ptr); void winReflectCmd(rdWin *w, char *cmd, char *arg); void closeWin(rdWin *w); void freeWin(rdWin *w); void msg_handler(rdWin *w); void rdGotoWin(rdWin *w); rdWin *userpWin(void *ptr); ulong atoul(char *str); void rdSetMulti(int list, int art); void rdInclude(rdWin *w, char *str, size_t len); wily-0.13.41/tools/old/reader/Makefile.in100600 2743 200 1123 6053052447 16375 0ustar garypgradsrcdir=@srcdir@ VPATH=@srcdir@ OBJECTS= getmsg.o mail.o reader.o mbox.o solaris.o utils.o TARGET=mreader CC=@CC@ CFLAGS=-I../include -I.. -I$(srcdir)/../include @X_CFLAGS@ MYLIBS=../libmsg/libmsg.a ../libXg/libXg.a all: $(TARGET) $(TARGET): $(OBJECTS) $(MYLIBS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(LIBS) @X_LIBS@ -lXt @X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@ purify: $(OBJECTS) purify -userpath='.:../libtext:../libframe:../libXg' $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(LIBS) $(OBJECTS): ../include/libmsg.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGET) wily-0.13.41/tools/old/reader/reader.c100644 2743 200 33153 6052054021 15763 0ustar garypgrad/* * reader.c - functions for handling news/article reader windows. */ #include "headers.h" Bool debug = true; Bool frommessage = true; /* * These determine whether we'll have one list and one article window, * that gets overwritten each time we change group/mailbox/article, * or whether we just spawn a new one. */ int rdMultiList = 0; int rdMultiArt = 0; /* * The windows currently active. */ rdWin *windows = 0; static rdWin *Listwin = 0; static rdWin *Artwin = 0; /* * General wily comms stuff. */ Mqueue realwilyq; Mqueue *wilyq = &realwilyq; Fd wilyfd; /* * default contents of tags */ char *rdListTagStr = " delete undelete comp reply quit exit "; char *rdArtTagStr = " delete reply save inc "; static rdWin *allocWin(rdWinType kind, const char *title); static int connectWin(rdWin *w, char *filename); static rdWin *getWin(int user, void *userp, rdWinType kind, char *title, char *filename); static void clearWin(rdWin *w); static void freeItems(rdWin *w); static int loadItems(rdWin *w, char **items, int savecontents); static int initWin(int user, void *userp, rdWin *w, char *title, char *filename); static void anyEvent(rdWin *w); static void winDelete(rdWin *w, int which, ulong p0, ulong p1); static void winInsert(rdWin *w, int which, ulong p, char *str); static void updateBody(rdWin *w, ulong p0, ulong p1, char *str); static void winGoto(rdWin *w, ulong p0, char *str); static void winExec(rdWin *w, char *cmd, char *arg); static void DelWin(rdWin *w, char *arg); static int rdBuiltin(rdWin *w, char *cmd, char *str); static void addrEvent(rdWin *w); static void bodyEvent(rdWin *w); static size_t countlines(char *str, size_t len); static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf); /* * allocWin(kind, title) - create a new, blank window of a given kind. */ static rdWin * allocWin(rdWinType kind, const char *title) { rdWin *w = salloc(sizeof(*w)); w->title = sstrdup((char *)title); w->wintype = kind; w->id = -1; w->m = 0; if (kind == rdList) w->items = 0; else w->body = 0; w->taglen = w->bodylen = 0; w->next = windows; windows = w; return w; } /* * connectWin(w, filename) - connect to wily, to create a new window. * If filename is true, then we get wily to open the given file. Otherwise, * we ask for a new, blank window. * Returns 0 for success. */ static int connectWin(rdWin *w, char *filename) { int fd; if (filename == 0) filename = "New"; if (rpc_new(wilyq, &w->id, filename, false) < 0) { freeWin(w); return -1; } return 0; } /* * getWin(user, userp, kind, title, filename) - grab a window of the appropriate type. */ static rdWin * getWin(int user, void *userp, rdWinType kind, char *title, char *filename) { rdWin *w; if ((!Listwin || kind == rdList && rdMultiList) || (!Artwin || kind == rdArticle && rdMultiArt)) { /* we can create a new window */ w = allocWin(kind, title); if (connectWin(w,filename)) return 0; if (kind == rdList) Listwin = w; else Artwin = w; } else { /* have to reuse the existing window */ w = (kind == rdList)? Listwin : Artwin; clearWin(w); } initWin(user, userp, w, title, filename); return w; } /* * clearWin(w) - erase the tag and body of a window */ static void clearWin(rdWin *w) { if (w->taglen) (void) rpc_settag(wilyq, w->id, ""); w->taglen = 0; if (w->bodylen) { (void) rpc_delete(wilyq, w->id, 0, w->bodylen); w->bodylen = 0; if (w->wintype == rdList) freeItems(w); } } /* * discard all the items in the window's list */ static void freeItems(rdWin *w) { rdItem *i, *j; for (i = w->items; i; i = j) { j = i->next; free(i); } w->items = 0; } /* * loadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items, int savecontents) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; if (savecontents) { for (len = 0, n = 0; items[n]; n++) len += strlen(items[n]) + seplen; w->body = buf = salloc(len); } while (*items) { i = salloc(sizeof(*i)); i->next = 0; i->p0 = p0; len = strlen(*items); if (j) j->next = i; else w->items = i; j = i; if (rpc_insert(wilyq, w->id, p0, *items)) { freeItems(w); return -1; } p0 += len; if (rpc_insert(wilyq, w->id, p0, sep)) { freeItems(w); return -1; } i->p1 = (p0 += seplen); items++; } w->bodylen = p0; return 0; } /* * changeItems(w, items, savecontents) - update the contents of a list window. */ int changeItems(rdWin *w, char **items, int savecontents) { if (w->wintype != rdList) return 1; freeItems(w); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) return 1; w->bodylen = 0; } return loadItems(w, items, savecontents); } /* * initWin(user, userp, w, title, filename) - initialise the window's tag, label, etc. */ static int initWin(int user, void *userp, rdWin *w, char *title, char *filename) { char tag[300]; /* XXX guess */ char *tagstr = w->wintype == rdArticle? rdArtTagStr : rdListTagStr; if (rpc_setname(wilyq, w->id, title)) return 1; sprintf(tag,"%s", tagstr); /* XXX at the moment, we don't include the title */ if (rpc_settag(wilyq, w->id, tag)) return 1; w->taglen = strlen(tag); w->user = user; w->userp = userp; return 0; } /* * getArtWin(title, text, filename, savecontents) - get an article window, and load it with * either the given text, or from the given file. */ int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents) { rdWin *w = getWin(user, userp, rdArticle, title, filename); if (w == 0) return 1; if (text) { int l = strlen(text); w->bodylen = l; if (rpc_insert(wilyq, w->id, 0, text)) return 1; if (savecontents) { w->body = salloc(l); strcpy(w->body, text); } } return 0; } /* * get a List window, and load it with the items in the array (which * must be null-terminated). */ int getListWin(int user, void *userp, char *title, char **items, int savecontents) { rdWin *w = getWin(user, userp, rdList, title, (char *)0); if (w == 0) return 1; return loadItems(w, items, savecontents); } /* * readerInit(title, items, ml, ma) - start things off by creating * a list window. Tell the reader whether we'll want one or more of * the list and article windows. */ int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents) { rdMultiList = ml; rdMultiArt = ma; if ((wilyfd = get_connect()) < 0) return 1; mq_init(wilyq, wilyfd); return getListWin(user, userp, title, items, savecontents); } /* * readerMainLoop() - get messages from wily, and act upon them. */ int readerMainLoop(void) { rdWin *w; Msg *m; int istag; while (windows) { if ((w = getActiveWin()) == 0) { fprintf(stderr,"No message available\n"); return 1; } m = w->m; switch (m->mtype) { char *cmd, *arg; ulong p0, p1; case EMexec: decode_exec_e(m, &cmd, &arg); winExec(w, cmd, arg); break; case EMgoto: decode_goto_e(m, &p0, &arg); winGoto(w, p0, arg); break; case EMinsert: istag = IsBody; decode_insert_e(m, &p0, &arg); winInsert(w, istag, p0, arg); break; case EMdelete: istag = IsBody; decode_delete_e(m, &p0, &p1); winDelete(w, istag, p0, p1); break; default: fprintf(stderr,"Unknown msg type!\n"); exit(1); } } return 1; } /* * text has been deleted */ static void winDelete(rdWin *w, int which, ulong p0, ulong p1) { rdItem *i; ulong l = p1 - p0; if (which == IsTag) { w->taglen -= l; return; } if (w->wintype == rdArticle) { w->bodylen -= l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p0 && p1 <= i->p1) break; if (!i) return; i->p1 -= l; for (i = i->next; i; i = i->next) { i->p0 -= l; i->p1 -= l; } updateBody(w, p0, p1, (char *)0); return; } /* * text has been inserted */ static void winInsert(rdWin *w, int which, ulong p, char *str) { rdItem *i; int l = strlen(str); if (which == IsTag) { w->taglen += l; return; } if (w->wintype == rdArticle) { w->bodylen += l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p && p <= i->p1) break; if (!i) return; i->p1 += l; for (i = i->next; i; i = i->next) { i->p0 += l; i->p1 += l; } updateBody(w, p, (ulong)l, str); return; } /* * updateBody(w,p0,p1,str) - insert p1 chars of str at p0, or remove the text * between p0 and p1. * XXX - this is *utterly* revolting, and horrendously slow. But it's quick * and simple, and will do for now. */ static void updateBody(rdWin *w, ulong p0, ulong p1, char *str) { char *newbuf; ulong newlen; if (w->body == 0) return; if (str) newlen = w->bodylen + p1; else newlen = w->bodylen - (p1 - p0); newbuf = salloc(newlen); strncpy(newbuf, w->body, p0); if (str) { strncpy(newbuf + p0, str, p1); strcpy(newbuf + p0 + p1, w->body + p0); } else { strcpy(newbuf + p0, w->body + p1); } free(w->body); w->body = newbuf; w->bodylen = newlen; } int itemNumber(rdWin *w, ulong p0, ulong p1, void **ptr) { int n; rdItem *i; if (w->wintype != rdList) return -1; for (n = 0, i = w->items; i; i = i->next, n++) if (i->p0 <= p0 && p1 <= i->p1) { *ptr = (void *)i; return n; } return -1; /* sigh */ } void highlightItem(rdWin *w, int n, void *ptr) { static char addr[80]; /* XXX - overkill */ rdItem *i = (rdItem *)ptr; if (i == 0) for (i = w->items; n--; i = i->next); sprintf(addr,"#%lu,#%lu", i->p0, i->p1); (void)rpc_goto(wilyq, w->id, addr); } /* * A B3 event has occured. */ static void winGoto(rdWin *w, ulong p0, char *str) { /* If this is a list, then it counts as a selection. Otherwise, we just reflect it back to wily as a normal B3 event. */ if (w->wintype == rdList) { int n; rdItem *i; fprintf(stderr,"Hit at (%lu)\n",p0); if ((n = itemNumber(w, p0, p0, (void **)&i)) == -1) return; /* sigh */ fprintf(stderr,"Is item %d expands to (%lu,%lu)\n",n, i->p0, i->p1); highlightItem(w, n, i); user_listSelection(w,n); return; } else (void)rpc_goto(wilyq, w->id, str); return; } /* * A B2(B1) command has been invoked. */ static void winExec(rdWin *w, char *cmd, char *arg) { ulong p0, p1; /* * Lots of options here: * - B2 with "|<>" - reflect back to wily. * - B2 cmd recognised by the reader routines - Del is about it. Execute * them ourselves. * - B2 not recognised by the reader routines - pass them onto the user, * after first getting the position of the argument within the body, if * necessary. * - B2B1 recognised by the reader routines - none spring to mind, but * I might add some. Execute them ourselves. * - B2B1 not recognised - pass onto user. */ if (!*cmd || strstr(cmd,"|<>")) { winReflectCmd(w,cmd, arg); return; } if (rdBuiltin(w,cmd,arg) == 0) return; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; if (w->wintype == rdList) { rdItem *i; int n; if ((n = itemNumber(w, p0, p1, (void *)&i)) != -1) { highlightItem(w, n, i); p0 = i->p0; p1 = i->p1; user_cmdList(w,cmd,p0,p1,n,arg); return; } } user_cmdArt(w, cmd, p0, p1, arg); return; } void winReflectCmd(rdWin *w, char *cmd, char *arg) { (void)rpc_exec(wilyq, w->id,cmd,arg); } /* * delete this particular window from the list. */ static void DelWin(rdWin *w, char *arg) { closeWin(w); } void closeWin(rdWin *w) { /* get wily to close the pane */ (void)rpc_exec(wilyq, w->id, "Del", ""); /* free up resources */ free(w->title); free(w->body); if (w->wintype == rdList) freeItems(w); /* XXX - currently leak the stateinfo stuff */ freeWin(w); return; } void freeWin(rdWin *w) { rdWin **wp = &windows; /* remove from the window chain */ while ((*wp) != w) wp = &((*wp)->next); *wp = w->next; if (w == Artwin) Artwin = 0; if (w == Listwin) Listwin = 0; if (windows == 0) exit(0); return; } static struct { char *cmd; void (*fn)(rdWin *, char *); } builtins[] = { { "Del", DelWin }, { 0, 0 } }; /* * check for builtin commands understood by the reader routines. */ static int rdBuiltin(rdWin *w, char *cmd, char *str) { int i; for (i = 0; builtins[i].cmd; i++) if (strcmp(builtins[i].cmd, cmd) == 0) { (*builtins[i].fn)(w, str); return 0; } return 1; } /* * "redisplay" a window that's already open. */ void rdGotoWin(rdWin *w) { (void)rpc_goto(wilyq, w->id, "."); } rdWin * userpWin(void *ptr) { rdWin *w = windows; while (w && w->userp != ptr) w = w->next; return w; } /* * Some routines which attempt to extract the body of a window, * and store it in a file. if p0==p1==0, assume all the body is wanted. */ void rdBodyToFile(rdWin *w, char *filename) { FILE *fp; char *buf = salloc(w->bodylen+1); if (rpc_read(wilyq, w->id, 0, w->bodylen, buf)) return; if ((fp = fopen(filename, "w"))) { (void)fprintf(fp,"%s",buf); fclose(fp); } free(buf); return; } /* * change current settings for multi-list and multi-art windows. */ void rdSetMulti(int list, int art) { rdMultiList = list; rdMultiArt = art; } void rdInclude(rdWin *w, char *str, size_t len) { size_t nlines = countlines(str, len); char *buf; char *prefix = "> "; size_t nlen, plen = strlen(prefix); ulong p0, p1; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; nlen = len + nlines*plen + 1; buf = salloc(nlen); prefixlines(str, len, prefix, plen, buf); rpc_insert(wilyq, w->id, p1, buf); w->bodylen += nlen; free(buf); } static size_t countlines(char *str, size_t len) { size_t nlines = 0; while (len--) if (*str++ == '\n') nlines++; return nlines; } static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf) { while (len) { strncpy(buf,prefix,plen); buf += plen; while (len-- && (*buf++ = *str++) != '\n') ; } *buf = 0; } wily-0.13.41/tools/old/reader/reader.h100644 2743 200 2220 6052054022 15740 0ustar garypgrad/* * reader.h - declarations for a mail/news reader toolkit for wily. */ /* * We support two kinds of window - a list (mailboxes, newsgroups, subject lines) * and an article display. There can be more than one instance of each. */ typedef enum _rdWinType { rdList, rdArticle } rdWinType; /* * This makes the messages clearer */ enum { IsTag = 0, IsBody = 1 }; typedef struct _rdWin rdWin; typedef struct _rdItem rdItem; typedef struct _Msgq Msgq; extern int rdMultiList; extern int rdMultiArt; struct _rdItem { ulong p0, p1; /* address of this item in the window. */ struct _rdItem *next; /* next item in the list */ }; struct _rdWin { rdWinType wintype; int user; /* user info */ void *userp; /* ditto */ Id id; struct _rdWin *next; /* list storage */ char *title; /* what we think the title of this window is */ ulong taglen; /* length of tag, in characters */ ulong bodylen; /* length of body, in characters */ Msg *m; /* message from wily */ char *body; /* UTF text of an article window */ rdItem *items; /* The items in a list */ }; extern rdWin *windows; extern Mqueue *wilyq; wily-0.13.41/tools/old/reader/utils.c100644 2743 200 452 6052054024 15620 0ustar garypgrad/* * general utilities... */ #include "headers.h" char * sstrdup(char *str) { char *s = salloc(strlen(str)+1); strcpy(s,str); return s; } void panic(const char *msg) { fprintf(stderr,"%s\n", msg); exit(1); } ulong atoul(char *str) { return strtoul((const char *)str, (char **)0, 10); } wily-0.13.41/tools/old/reader/solaris.c100644 2743 200 2775 6052054023 16165 0ustar garypgrad/* * solaris.c - the system-dependent routines for Solaris 2. */ #include "headers.h" #include "mbox.h" #include #include #include /* * load_mbox(mbox) - open the named file, and make it available * as a block of memory between mbox_start and mbox_end. */ #ifdef USE_MMAP int load_mbox(mMbox *mbox) { mode_t mode = mbox->readonly? O_RDONLY : O_RDWR; int fd = open(mbox->name,mode); caddr_t addr; size_t len; int prot, flags; off_t off; struct stat st; if (fd < 0) return 1; if (fstat(fd,&st) == -1) return 1; len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; addr = 0; prot = PROT_READ; off = 0; flags = MAP_SHARED; if ((mbox->mbox_start = mmap(addr,len,prot,flags,fd,off)) == MAP_FAILED) return 1; close(fd); mbox->mbox_end = mbox->mbox_start + len; return 0; } #else /* USE_MMAP */ int load_mbox(mMbox *mbox) { const char *mode = mbox->readonly? "r" : "r+"; FILE *fp = fopen(mbox->name,mode); char *addr = 0; size_t len; struct stat st; if (fp == 0) goto broken; if (stat(mbox->name,&st) == -1) goto broken; len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; if ((addr = malloc(len+1)) == 0) goto broken; addr[len] = 0; /* handy for debugging */ if (fread(addr, (size_t)1, len, fp) != len) goto broken; fclose(fp); mbox->mbox_start = addr; mbox->mbox_end = mbox->mbox_start + len; return 0; broken: if (addr) free(addr); fclose(fp); return 1; } #endif /* USE_MMAP */ wily-0.13.41/tools/old/sh/ 40755 2743 200 0 6141130621 13403 5ustar garypgradwily-0.13.41/tools/old/sh/README100600 2743 200 541 6050056651 14341 0ustar garypgradwcmd prog [args] connect to wily, set $WILYFD to be the file descriptor, then run 'prog' rpc type [args] packs its arguments up in the wily message format (currently headed by a length field, and separated by nulls) and sends the message out on WILYFD, waits for the response (printing and discarding events), and prints the response on stdout. wily-0.13.41/tools/old/sh/wcmd.c100600 2743 200 711 6047136440 14557 0ustar garypgrad#include #include #include #include #include #include void main(int argc, char **argv) { int fd; char buf[1024]; /* connect to wily */ fd = get_connect(); if(fd<0) { perror("get_connect"); exit(1); } /* make it file descriptor 3 */ sprintf(buf,"WILYFD=%d", fd); if(putenv(buf)){ perror("putenv"); exit(1); } /* start up the other program */ argv++; execvp(argv[0],argv); } wily-0.13.41/tools/old/sh/Makefile.in100644 2743 200 1036 6057224332 15556 0ustar garypgradsrcdir=@srcdir@ VPATH=@srcdir@ OBJECTS= wcmd.o rpc.o TARGETS=wcmd rpc CC=@CC@ RANLIB=@RANLIB@ CFLAGS=@CFLAGS@ -I../include -I.. -I$(srcdir)/../include @X_CFLAGS@ MYLIBS=../libmsg/libmsg.a ../libXg/libXg.a all: $(TARGETS) $(TARGETS): $(MYLIBS) wcmd: wcmd.o $(CC) $(LDFLAGS) -o wcmd wcmd.o $(MYLIBS) $(LIBS) @X_EXTRA_LIBS@ rpc: rpc.o $(CC) $(LDFLAGS) -o rpc rpc.o $(MYLIBS) $(LIBS) @X_EXTRA_LIBS@ $(OBJECTS): ../include/libmsg.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGETS) install: $(TARGET) cp $(TARGET) ../$(TARGET).$(SYS) wily-0.13.41/tools/old/sh/rpc.c100600 2743 200 1443 6047143655 14442 0ustar garypgrad#include #include #include #include #include #include int main(int argc, char **argv) { int fd; char *fdenv; char *type; Mtype mt; int t; Mqueue q; Msg *m; fdenv = getenv("WILYFD"); if(!fdenv) { fprintf(stderr,"$WILYFD must be set\n"); exit(1); } fd = atoi(fdenv); if(argc<2){ fprintf(stderr,"usage: %s message-type [args]", argv[0]); exit(1); } type = argv[1]; t = name2type(type); if(t<0) { fprintf(stderr,"couldn't recognise [%s] as a type of wily message\n", type); exit(1); } mt =t ; mq_init(&q, fd); fd_send_array(fd, mt, argv+2, argc-2); while( (m= mq_next(&q, 0)) ) { msg_print(m); if(m->mtype == mt || m->mtype == Merror || m->mtype == Mok) break; msg_free(m); free(m); } return 0; } wily-0.13.41/tools/old/wilytoys/ 40755 2743 200 0 6141343277 14711 5ustar garypgradwily-0.13.41/tools/old/wilytoys/Makefile100644 2743 200 404 6121344152 16413 0ustar garypgradW = /home/steve/src/9/orig/wily-0.9.8 CFLAGS = -Xc -g CPPFLAGS = -I$W -I$W/include -I$W/libXg LDFLAGS = -L$W/libXg -L$W/libmsg LDLIBS = -lmsg -lXg -lnsl -lsocket PROGS = bold wcat all: $(PROGS) install: cp $(PROGS) $(HOME)/bin/Wily nuke: $(RM) $(PROGS) wily-0.13.41/tools/old/wilytoys/bold.c100644 2743 200 2400 6121340060 16047 0ustar garypgrad#include #include #include #include #include /* * XXX - current assumes that we won't be in mid-sequence when EOF is reached. */ #define MAGICBOLD 0x4000 #define MAGICITALIC 0x4100 #define MAGICITALICBOLD 0x4200 static long charset = MAGICITALIC; static void boldchar(int c, int overstrike) { char str[4], *s = str; Rune r = c + charset; switch (runetochar(s, &r)) { case 3: putchar(*s++); case 2: putchar(*s++); case 1: putchar(*s++); } } int main(int argc, char *argv[]) { int i = 0, b = 0,c; int state = 0; int outchar; int os = 0; while ((c = getopt(argc, argv, "ib")) != EOF) { switch (c) { case 'b': b++; break; case 'i': i++; break; default: exit(1); } } charset = b&&i? MAGICITALICBOLD : b? MAGICBOLD : MAGICITALIC; while ((c = getchar()) != EOF) { switch (state) { case 0: if (c == '_') state++; else putchar(c); break; case 1: if (c == 0x8) /* backspace */ state++; else { putchar('_'); putchar(c); state = 0; } break; case 2: boldchar(c,0); state = 0; break; default: fprintf(stderr,"We're screwed!\n"); exit(1); } } if (state) fprintf(stderr,"File was truncated!\n"); return 0; } wily-0.13.41/tools/old/wilytoys/wcat.c100644 2743 200 1566 6121340060 16101 0ustar garypgrad#include #include #include #include #include #include #include void e(char *s) { perror(s); exit(1); } int main(int argc, char *argv[]) { char cwd[BUFSIZ+1], filename[BUFSIZ]; char *file; int isreal; Fd fd; Mqueue q[1]; Id id; int r; ulong len = 0; if (argc > 1) { file = argv[1]; isreal = 1; if (*file == '/') strcpy(filename, file); else { if (getcwd(cwd,BUFSIZ) == 0) e("getcwd"); sprintf(filename,"%s/%s", cwd, file); } } else { isreal = 0; sprintf(filename,"+stdin-%d",getpid()); } if ((fd = get_connect()) < 0) e("get_connect"); mq_init(q,fd); if (rpc_new(q, &id, filename, isreal)) e("rpc_new"); if (isreal) return 0; while ((r = fread(cwd, 1, BUFSIZ, stdin))) { cwd[r] = 0; if (rpc_insert(q, id, len, cwd)) e("rpc_insert"); len += r; } return 0; } wily-0.13.41/tools/old/wilytoys/fetchurl100755 2743 200 1005 6121340135 16530 0ustar garypgrad#!/usr/local/bin/expect -f # Download an HTML file in a simplistic fashion. # Usage: fetchurl hostname filename # (parse the URL yourself...) set hostname [lindex $argv 0] set filename [lindex $argv 1] log_user 0 spawn telnet $hostname http expect { "Connected" { expect "Escape character is '^]'." send "GET $filename\n" expect "GET $filename\r\n" log_user 1 interact -o "\r" {} "Connection closed by foreign host." {} exit 0 } timeout { send_user "Could not connect to $hostname\n" exit 1 } } wily-0.13.41/tools/old/wilytoys/html-ascii.pl100644 2743 200 14674 6121340135 17415 0ustar garypgrad# Routines for HTML to ASCII. # (fixed width font, no font changes for size, bold, etc) with a little # BUGS AND MISSING FEATURES # font tags (e.g. CODE, EM) cause an extra whitespace # e.g. foo, -> foo , # Jim Davis July 15 1994 # modified 3 Aug 94 to support MENU and DIR require "tformat.pl" || die "Could not load tformat.pl: $@\nStopped"; # Can be set by command line arg if (! defined($columns_per_line)) { $columns_per_line = 72;} if (! defined($flush_last_page)) { $flush_last_page = 1;} # amount to add to indentation $indent_left = 5; $indent_right = 5; # ignore contents inside HEAD. $ignore_text = 0; # Set variables in tformat $left_margin = 1; $right_margin = $columns_per_line; $bottom_margin = 0; ## Routines called by html.pl $Begin{"HEAD"} = "begin_head"; $End{"HEAD"} = "end_head"; sub begin_head { local ($element, $tag) = @_; $ignore_text = 1;} sub end_head { local ($element) = @_; $ignore_text = 0;} $Begin{"BODY"} = "begin_document"; sub begin_document { local ($element, $tag) = @_; &start_page();} $End{"BODY"} = "end_document"; sub end_document { local ($element) = @_; &fresh_line();} ## Headers $Begin{"H1"} = "begin_header"; $End{"H1"} = "end_header"; $Begin{"H2"} = "begin_header"; $End{"H2"} = "end_header"; $Begin{"H3"} = "begin_header"; $End{"H3"} = "end_header"; $Begin{"H4"} = "begin_header"; $End{"H4"} = "end_header"; $Skip_Before{"H1"} = 1; $Skip_After{"H1"} = 1; $Skip_Before{"H2"} = 1; $Skip_After{"H2"} = 1; $Skip_Before{"H3"} = 1; $Skip_After{"H3"} = 0; sub begin_header { local ($element, $tag) = @_; &skip_n_lines ($Skip_Before{$element}, 5);} sub end_header { local ($element) = @_; &skip_n_lines ($Skip_After{$element});} $Begin{"BR"} = "line_break"; sub line_break { local ($element, $tag) = @_; &fresh_line();} $Begin{"P"} = "begin_paragraph"; # if fewer than this many lines left on page, start new page $widow_cutoff = 5; sub begin_paragraph { local ($element, $tag) = @_; &skip_n_lines (1, $widow_cutoff);} $Begin{"BLOCKQUOTE"} = "begin_blockquote"; $End{"BLOCKQUOTE"} = "end_blockquote"; sub begin_blockquote { local ($element, $tag) = @_; $left_margin += $indent_left; $right_margin = $columns_per_line - $indent_right; &skip_n_lines (1);} sub end_blockquote { local ($element) = @_; $left_margin -= $indent_left; $right_margin = $columns_per_line; &skip_n_lines (1);} $Begin{"PRE"} = "begin_pre"; $End{"PRE"} = "end_pre"; sub begin_pre { local ($element, $tag) = @_; $whitespace_significant = 1;} sub end_pre { local ($element) = @_; $whitespace_significant = 0;} $Begin{"INPUT"} = "form_input"; sub form_input { local ($element, $tag, *attributes) = @_; if ($attributes{"value"} ne "") { &print_word_wrap($attributes{"value"});}} $Begin{"HR"} = "horizontal_rule"; sub horizontal_rule { local ($element, $tag) = @_; &fresh_line (); &print_n_chars ($right_margin - $left_margin, "-");} # Add code for IMG (use ALT attribute) # Ignore I, B, EM, TT, CODE (no font changes) ## List environments $Begin{"UL"} = "begin_itemize"; $End{"UL"} = "end_list_env"; $Begin{"OL"} = "begin_enumerated"; $End{"OL"} = "end_list_env"; $Begin{"MENU"} = "begin_menu"; $End{"MENU"} = "end_list_env"; $Begin{"DIR"} = "begin_dir"; $End{"DIR"} = "end_list_env"; $Begin{"LI"} = "begin_list_item"; # application-specific initialization routine sub html_begin_doc { @list_stack = (); $list_type = "bullet"; $list_counter = 0;} sub push_list_env { push (@list_stack, join (":", $list_type, $list_counter));} sub pop_list_env { ($list_type, $list_counter) = split (":", pop (@list_stack)); $left_margin -= $indent_left;} sub begin_itemize { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_menu { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_dir { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_enumerated { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "enumerated"; $list_counter = 1;} sub end_list_env { local ($element) = @_; &pop_list_env(); # &fresh_line(); } sub begin_list_item { local ($element, $tag) = @_; $left_margin -= 2; &fresh_line(); &print_word_wrap("$list_counter "); if ($list_type eq "enumerated") {$list_counter++;} $left_margin += 2;} $Begin{"DL"} = "begin_dl"; sub begin_dl { local ($element, $tag) = @_; &skip_n_lines(1,5);} $Begin{"DT"} = "begin_defined_term"; $Begin{"DD"} = "begin_defined_definition"; $End{"DD"} = "end_defined_definition"; sub begin_defined_term { local ($element, $tag) = @_; &fresh_line();} sub begin_defined_definition { local ($element, $tag) = @_; $left_margin += $indent_left; &fresh_line();} sub end_defined_definition { local ($element) = @_; $left_margin -= $indent_left; &fresh_line();} $Begin{"META"} = "begin_meta"; # a META tag sets a value in the assoc array %Variable # i.e. sers $Variable{author} to "Rushdie" sub begin_meta { local ($element, $tag, *attributes) = @_; local ($variable, $value); $variable = $attributes{name}; $value = $attributes{content}; $Variable{$variable} = $value;} $Begin{"IMG"} = "begin_img"; sub begin_img { local ($element, $tag, *attributes) = @_; &print_word_wrap (($attributes{"alt"} ne "") ? $attributes{"alt"} : "[IMAGE]");} # URLs $Begin{"A"} = "begin_a"; sub begin_a { local ($element, $tag, *attributes) = @_; local ($href, $k); $href = $attributes{href}; $k = $main'wily_url++; $main'wily_urls{$k} = $href; &print_word_wrap ("[_u$k]["); } $End{"A"} = "end_a"; sub end_a { &print_word_wrap("]"); } # Content and whitespace. sub html_content { local ($string) = @_; unless ($ignore_text) { &print_word_wrap ($string);}} sub html_whitespace { local ($string) = @_; if (! $whitespace_significant) { die "Internal error, called html_whitespace when whitespace was not significant";} local ($i); for ($i = 0; $i < length ($string); $i++) { &print_whitespace (substr($string,$i,1));}} # called by tformat. Do nothing. sub do_footer { } sub do_header { } 1; wily-0.13.41/tools/old/wilytoys/html2wily100755 2743 200 3066 6121340135 16660 0ustar garypgrad#!/usr/local/bin/perl -I/home/steve/bin/Wily # Program to generate ASCII text for HTML # Created by James R. Davis, July 15 1994 # Split a URL into its component parts sub split_url { local($method, $host, $port, $path); $_ = $_[0]; /^((http|ftp|news|mailto|gopher|telnet):)?(\/\/([^\/:]+)(:([0-9]+))?)?(.*)/; $method = $2; $host = $4; $port = $6; $path = $7; return ($method, $host, $port, $path); } # Convert a hyperlink URL into a FQU, if necessary. sub fqu { local($partial) = @_; local($full); local($pmethod, $phost, $pport, $ppath) = &split_url($partial); $pmethod = $basemethod if $pmethod eq ""; $phost = $basehost if $phost eq ""; $pport = $baseport if $pport eq ""; if ($pport eq "80") { $pport = ""; } else { $pport = ":" . $pport; } if ($phost eq $basehost) { if ($ppath !~ /^\//) { $ppath = $basepath . '/' . $ppath; } } $full = $pmethod . "://" . $phost . $pport . $ppath; return $full; } # get directory where this file is. {$0 =~ /^(.*)\/.*$/; $my_dir = $1; if ($my_dir !~ ?^/?) {$my_dir = $ENV{PWD} . "/" . $my_dir;} if ($my_dir =~ ?/$?) {chop ($my_dir);}} push(@INC, $my_dir); # Parse command line arguments. $file = shift; $baseurl = shift; ($basemethod, $basehost, $baseport, $basepath) = &split_url($baseurl); $baseport = "80" if $baseport eq ""; require "parse-html.pl" || die "Could not load parse-html.pl"; require "html-ascii.pl" || die "Could not load html-ascii.pl"; %wily_urls = (); $wily_url = 1; &parse_html ($file); foreach $k (keys %wily_urls) { $u = &fqu($wily_urls{$k}); print "[_u$k] [http $u]\n"; } wily-0.13.41/tools/old/wilytoys/http100755 2743 200 740 6121340135 15660 0ustar garypgrad#!/bin/rc # http - get an HTTP URL, retrieve the file, convert it into something that looks # vaguely nice, and send it to a Wily window. # Usage: http http://site/path/name.html url = $1 tmpfile = /tmp/http$pid switch ($url) { case http:* eval `{echo $url | sed -e 's!http://\([^/]*\)\(.*\)!host=(\1);file=(\2)!'} case * echo Only http URLs supported >[1=2] exit 1 } if (~ $file ()) file = /; fetchurl $host $file > $tmpfile html2wily $tmpfile $url | wcat rm $tmpfile wily-0.13.41/tools/old/wilytoys/parse-html.pl100644 2743 200 21450 6121340136 17426 0ustar garypgrad# HTML parser # Jim Davis, July 15 1994 # This is an HTML parser not an SGML parser. It does not parse a DTD, # The DTD is implicit in the code, and specific to HTML. # The processing of the HTML can be customized by the user by # 1) Defining routines to be called for various tags (see Begin and End arrays) # 2) Defining routines html_content and html_whitespace # This is not a validating parser. It does not check the content model # eg you can use DT outside a DL and it won't know. It is too liberal in # what tags are allowed to minimize what other tags. # Bugs - can't parse the prolog or whatever you call it # # # # %html; # ]> # modified 3 Aug to add a bunch of HTML 2.0 tags # modified 3 Sept to print HTML stack to STDERR not STDOUT, to add new # routines html_begin_doc and html_end_doc for application specific cleanup # and to break parse_html into two pieces. # modified 30 Sept 94. parse_attributes now handles tag attributes that # don't have values. thanks to Bill Simpson-Young # for the code. # modified 17 Apr 95 to support FORMS tags. $debug = 0; $whitespace_significant = 0; # global variables: # $line_buffer is line buffer # $line_count is input line number. $line_buffer = ""; $line_count = 0; sub parse_html { local ($file) = @_; open (HTML, $file) || die "Could not open $file: $!\nStopped"; &parse_html_stream (); close (HTML);} # Global input HTML is the handle to the stream of HTML sub parse_html_stream { local ($token, $new); ## initialization @stack=(); $line_count = 0; $line_buffer = ""; ## application specific initialization &html_begin_doc(); main: while (1) { # if whitespace does not matter, trim any leading space. if (! $whitespace_significant) { $line_buffer =~ s/^\s+//;} # now dispatch on the type of token if ($line_buffer =~ /^(\s+)/) { $token = $1; $line_buffer = $'; &html_whitespace ($token);} # This will lose if there is more than one comment on the line! elsif ($line_buffer =~ /^(\)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\]*\>)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\<\/[^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_etag ($token);} elsif ($line_buffer =~ /^(\<[^!\/][^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_tag ($token);} elsif ($line_buffer =~ /^([^\s<]+)/) { $token = $1; $line_buffer = $'; $token = &substitute_entities($token); &html_content ($token); } else { # No valid token in buffer. Maybe it's empty, or maybe there's an # incomplete tag. So get some more data. $new = ; if (! defined ($new)) {last main;} # if we're trying to find a match for a tag, then get rid of embedded newline # this is, I think, a kludge if ($line_buffer =~ /^\ -1) { print STDERR "Stack not empty at end of document\n"; &print_html_stack();} } sub html_tag { local ($tag) = @_; local ($element) = &tag_element ($tag); local (%attributes) = &tag_attributes ($tag); # the tag might minimize (be an implicit end) for the previous tag local ($prev_element); while (&Minimizes(&stack_top_element(), $element)) { $prev_element = &stack_pop_element (); if ($debug) { print STDERR "MINIMIZING $prev_element with $element on $line_count\n";} &html_end ($prev_element, 0);} push (@stack, $tag); &html_begin ($element, $tag, *attributes); if (&Empty($element)) { pop(@stack); &html_end ($element, 0);} } sub html_etag { local ($tag) = @_; local ($element) = &tag_element ($tag); # pop stack until find matching tag. This is probably a bad idea, # or at least too general. local ( $prev_element) = &stack_pop_element(); until ($prev_element eq $element) { if ($debug) { print STDERR "MINIMIZING $prev_element with /$element on $line_count \n";} &html_end ($prev_element, 0); if ($#stack == -1) { print STDERR "No match found for /$element. You will lose\n"; last;} $prev_element = &stack_pop_element();} &html_end ($element, 1); } # For each element, the names of elements which minimize it. # This is of course totally HTML dependent and probably I have it wrong too $Minimize{"DT"} = "DT:DD"; $Minimize{"DD"} = "DT"; $Minimize{"LI"} = "LI"; $Minimize{"P"} = "P:DT:LI:H1:H2:H3:H4:BLOCKQUOTE:UL:OL:DL"; # Does element E2 minimize E1? sub Minimizes { local ($e1, $e2) = @_; local ($value) = 0; foreach $elt (split (":", $Minimize{$e1})) { if ($elt eq $e2) {$value = 1;}} $value;} $Empty{"BASE"} = 1; $Empty{"BR"} = 1; $Empty{"HR"} = 1; $Empty{"IMG"} = 1; $Empty{"ISINDEX"} = 1; $Empty{"LINK"} = 1; $Empty{"META"} = 1; $Empty{"NEXTID"} = 1; $Empty{"INPUT"} = 1; # Empty tags have no content and hence no end tags sub Empty { local ($element) = @_; $Empty{$element};} sub print_html_stack { print STDERR "\n ==\n"; foreach $elt (reverse @stack) {print STDERR " $elt\n";} print STDERR " ==========\n";} # The element on top of stack, if any. sub stack_top_element { if ($#stack >= 0) { &tag_element ($stack[$#stack]);}} sub stack_pop_element { &tag_element (pop (@stack));} # The element from the tag, normalized. sub tag_element { local ($tag) = @_; $tag =~ /<\/?([^\s>]+)/; local ($element) = $1; $element =~ tr/a-z/A-Z/; $element;} # associative array of the attributes of a tag. sub tag_attributes { local ($tag) = @_; $tag =~ /^<[A-Za-z]+ +(.*)>$/; &parse_attributes($1);} # string should be something like # KEY="value" KEY2="longer value" KEY3="tags o doom" # output is an associative array (like a lisp property list) # attributes names are not case sensitive, do I downcase them # Maybe (probably) I should substitute for entities when parsing attributes. sub parse_attributes { local ($string) = @_; local (%attributes); local ($name, $val); get: while (1) { if ($string =~ /^ *([A-Za-z]+)=\"([^\"]*)\"/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val; } elsif ($string =~ /^ *([A-Za-z]+)=(\S*)/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} elsif ($string =~ /^ *([A-Za-z]+)/) { $name = $1; $val = ""; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} else {last;}} %attributes;} sub substitute_entities { local ($string) = @_; $string =~ s/&/&/g; $string =~ s/<//g; $string =~ s/"/\"/g; $string;} @HTML_elements = ( "A", "ADDRESS", "B", "BASE", "BLINK", # Netscape addition :-( "BLOCKQUOTE", "BODY", "BR", "CITE", "CENTER", # Netscape addition :-( "CODE", "DD", "DIR", "DFN", "DL", "DT", "EM", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HR", "HTML", "I", "ISINDEX", "IMG", "INPUT", "KBD", "LI", "LINK", "MENU", "META", "NEXTID", "OL", "OPTION", "P", "PRE", "SAMP", "SELECT", "STRIKE", "STRONG", "TITLE", "TEXTAREA", "TT", "UL", "VAR", ); sub define_element { local ($element) = @_; $Begin{$element} = "Noop"; $End{$element} = "Noop";} foreach $element (@HTML_elements) {&define_element($element);} # do nothing sub Noop { local ($element, $xxx) = @_; } # called when a tag begins. Dispatches using Begin sub html_begin { local ($element, $tag, *attributes) = @_; local ($routine) = $Begin{$element}; if ($routine eq "") { print STDERR "Unknown HTML element $element ($tag) on line $line_count\n";} else {eval "&$routine;"}} # called when a tag ends. Explicit is 0 if tag end is because of minimization # not that you should care. sub html_end { local ($element, $explicit) = @_; local ($routine) = $End{$element}; if ($routine eq "") { print STDERR "Unknown HTML element \"$element\" (END $explicit) on line $line_count\n";} else {eval "&$routine(\"$element\", $explicit)";}} sub html_content { local ($word) = @_; } sub html_whitespace { local ($whitespace) = @_;} sub html_comment { local ($tag) = @_;} # redefine these for application-specific initialization and cleanup sub html_begin_doc {} sub html_end_doc {} # return a "true value" when loaded by perl. 1; wily-0.13.41/tools/old/wilytoys/man100755 2743 200 210 6121340325 15445 0ustar garypgrad#!/bin/rc { if (~ $1 *.[0-9]*) { nroff -man $* } else { PAGER='cat' exec /usr/bin/man $* } } | bold | perl -pe 's/\010.//g;' | wcat wily-0.13.41/tools/old/wilytoys/make100755 2743 200 260 6121340364 15617 0ustar garypgrad#!/bin/rc # script to make errors from the C compiler look like addresses # to Wily. exec /usr/ccs/bin/make $* >[2=1] | perl -pe '$| = 1; s/"([^"]*)", line ([0-9]+)/\1:\2/;' wily-0.13.41/tools/old/wilytoys/diff100755 2743 200 307 6121340364 15614 0ustar garypgrad#!/bin/rc # script to make line numbers from diff look like addresses # to Wily. f1 = $1 f2 = $2 exec /usr/bin/diff $* | perl -pe '$| = 1; s!^(([0-9]+)(.)([0-9]+).*)!\1 '^$f1^':\2 \3 '^$f2^':\4!;' wily-0.13.41/tools/old/wilytoys/tformat.pl100644 2743 200 6142 6121340556 17015 0ustar garypgrad# Simple text formatter # Jim Davis 17 July 94 # current page, line, and column numbers. $page = 1; $line = 1; $column = 1; $left_margin = 1; $right_margin = 72; # lines on page before footer. or 0 if no limit. $bottom_margin = 58; # add newlines to make page be full length? $fill_page_length = 1; sub print_word_wrap { local ($word) = @_; if (($column + ($whitespace_significant ? 0 : 1) + length ($word) ) > ($right_margin + 1)) { &fresh_line();} if ($column > $left_margin && !$whitespace_significant) { print " "; $column++;} print $word; $column += length ($word);} sub print_whitespace { local ($char) = @_; if ($char eq " ") { $column++; print " ";} elsif ($char eq "\t") { &get_to_column (&tab_column($column));} elsif ($char eq "\n") { &new_line();} else { die "Unknown whitespace character \"$char\"\nStopped";} } sub tab_column { local ($c) = @_; (int (($c-1) / 8) + 1) * 8 + 1;} sub fresh_line { if ($column > $left_margin) {&new_line();} while ($column < $left_margin) { print " "; $column++;}} sub finish_page { # Add extra newlines to finish page. # You might not want to do this on the last page. if ($fill_page_length) { while ($line < $bottom_margin) {&cr();}} &do_footer (); $line = 1; $column = 1;} sub start_page { if ($page != 1) { &do_header ();}} sub print_n_chars { local ($n, $char) = @_; local ($i); for ($i = 1; $i <= $n; $i++) {print $char;} $column += $n;} # need one NL to end current line, and then N to get N blank lines. sub skip_n_lines { local ($n, $room_left) = @_; if ($bottom_margin > 0 && $line + $room_left >= $bottom_margin) { &finish_page(); &start_page();} else { local ($i); for ($i = 0; $i <= $n; $i++) {&new_line();}}} sub new_line { if ($bottom_margin > 0 && $line >= $bottom_margin) { &finish_page(); &start_page();} else {&cr();} &print_n_chars ($left_margin - 1, " ");} # used in footer and header where we don't respect the bottom margin. sub print_blank_lines { local ($n) = @_; local ($i); for ($i = 0; $i < $n; $i++) {&cr();}} sub cr { print "\n"; $line++; $column = 1;} # left, center, and right tabbed items sub print_lcr_line { local ($left, $center, $right) = @_; &print_tab_left (1, $left); &print_tab_center (($right_margin - $left_margin) / 2, $center); &print_tab_right ($right_margin, $right); &cr();} sub print_tab_left { local ($tab_column, $string) = @_; &get_to_column ($tab_column); print $string; $column += length ($string); } sub print_tab_center { local ($tab_column, $string) = @_; &get_to_column ($tab_column - (length($string) / 2)); print $string; $column += length ($string); } sub print_tab_right { local ($tab_column, $string) = @_; &get_to_column ($tab_column - length($string)); print $string; $column += length ($string); } sub get_to_column { local ($goal_column) = @_; if ($column > $goal_column) {print " "; $column++;} else { while ($column < $goal_column) { print " "; $column++;}}} wily-0.13.41/tools/old/wilytoys/fixed.9.font100644 2743 200 3621 6121341011 17124 0ustar garypgrad17 14 0x0000 0x00FF lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.41/tools/old/wilytoys/prop.9.font100644 2743 200 3612 6121341011 17005 0ustar garypgrad16 13 0x0000 0x00FF lubs14 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.41/tools/old/wilytoys/smk.9.font100644 2743 200 3733 6121341011 16623 0ustar garypgrad16 13 0x0000 0x00FF wilynormal 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4000 0x40FF wilybold 0x4100 0x41FF wilyitalic 0x4200 0x42FF wilybolditalic 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.41/tools/old/wilytoys/fonts.alias100644 2743 200 536 6121342526 17130 0ustar garypgradwilynormal "-adobe-new century schoolbook-medium-r-normal--12-120-75-75-p-70-iso8859-1" wilybold "-adobe-new century schoolbook-bold-r-normal--12-120-75-75-p-70-iso8859-1" wilyitalic "-adobe-new century schoolbook-medium-i-normal--12-120-75-75-p-70-iso8859-1" wilybolditalic "-adobe-new century schoolbook-bold-i-normal--12-120-75-75-p-70-iso8859-1" wily-0.13.41/tools/old/wilytoys/README100644 2743 200 11015 6121344112 15667 0ustar garypgradThese files are a few toys that I thought I would share with other people. They're not at all polished, and one of them was only just finished today, but hey - that's life on the edge. What is here: - working wcat to shove files into wily. - filter to convert man pages into something pretty and readable. - some scripts to view HTML web pages with wily. - a couple of useful wily wrapper scripts. What you need: - perl. 4.036 is what I use, but you might get away with v5. - Expect, if you want to be able to download web pages. Actually, there are plain perl scripts around on the net to do this, but I couldn't get the damn things to work on my machine, and I was in a hurry. I recommend trying one of the existing perl things (get_url, etc.) before installing Expect, if you haven't already got it. - the fonts from Matty's 9term distribution (if you want pretty man pages). - wily 0.98. - luck. Major Credit where credit is due: - The Perl scripts used for converting HTML files into something vaguely readable is by James R. Davis. I grabbed it from the web, and made a few minor changes to make it function as a wily browser, but the proper work's all James'. To build wcat: - Fiddle with the Makefile, so that it can find your wily distribution. - make all. If you want, you might want to bodge ./make, and put it somewhere where wily can find it. I use it to mangle the output of Sun's ANSI compiler into wily-style file:line references. There isn't a lot of point including it here, except that perl allows you to see each error message as it appears, with minimal buffering. there's also a "diff" script which does much the same thing. Well, I like it... The Makefile also builds "bold". We'll come back to that shortly. Man page viewer: This is an horrendous cheat, as suggested by either myself or gary/matty a while ago in the list (I forget who). Basically, it uses the large Unicode character set to have normal, italic and bold versions of the same characters within your set, and just displays the appropriate one according to the output of nroff/man. This required a little bit of setting up and munging around with fonts. These are my notes which I scrawled at the time that I got this going: Unpacked matty's font distribution. ran mkfontdir in the bdf directory. Selected a font I liked using xfontsel(1). Created bdf/fonts.alias, containing the alias "wilynormal" for this preferred font. Put wilynormal as the first font in smk.9.font (which I'd copied from prop.9.font). Add the font directory to the X server's font path with xset fp+ /home/steve/lib/fonts/bdf Changed bin/acme to have smk.9.font and fixed.9.font args. Checked all was ok by viewing src/9/hacked/9term/utf.test I've included my font files and the fonts.alias file so that you can see what I've done. Note that the extra character sets appear in the 0x4000-odd range, and that this is hard-coded into the source for "bold.c". The man page viewer ("man") takes standard man arguments, and passes the output of normal man through bold, to get the pretty fonts, and then into wcat to display the file in wily. It doesn't get everything right, but it's good enough for what I use it for. You can also B2B1 on filename.1 files to view them directly. HTML web browser: This has three parts. The first is fetchurl, a quick Expect script that will grab the output of a telnet connection to some web server. Use a proper perl program to do this if you can get one. For starters, mine only handles http URLs. The second part is the driver, http. This takes as an argument a normal URL, e.g. "http http://www.w3.org". It uses fetchurl to grab the file, and then passes it to the final part, html2wily. Html2wily does the clever bit of generating readable ASCII out of the HTML. The bit I've added is to support URLs within the file: given a URL such as Some Text, you end up with this: [_u1][Some Text]. At the bottom of the file, you see: [_u1][http http://www.foo.com/file.html]. The idea is that you can B3 on the _u1 to move between the highlighted text and the URL that goes with it. If you decide to follow the URL, you double-click beside the [ or ], to select the whole command, and B2 it. The process then begins again. Incidentally, there are a few broken bits in this, especially where partial URLs are converted into full ones, but that's life. This thing took about 2 hours to write, this morning. Hope this of some use... Steve Kilbane, 12 March 1996. wily-0.13.41/tools/old/wilytoys/reader/ 40755 2743 200 0 6125634422 16150 5ustar garypgradwily-0.13.41/tools/old/wilytoys/reader/README100644 2743 200 6205 6057267633 17142 0ustar garypgradUSAGE Invoke with "mreader [-ma] mailboxname". The "-ma" option allows you to have multiple article windows open at once. By default, it only has the one article window open, because it's easier to find where the article window is, once you've positioned it. Unfortunately, this means that you don't get to see the article you're replying to. To fix this, there's a "multiart" command, which toggles this value from within the reader. First window to appear is the list window. It shows all the articles from the given mailfile, one per line. The line contains the From and Subject fields, but it's currently chopped to make things look nicer. You open an article by B3'ing on its subject line. What else? Commands supported: exit exit without doing anything to the mailfile. quit save any changes to the mailfile before quitting. delete delete the selected article. "selected" means the article which has dot in its subject line. This means you can click on the subject line with either B1 or B3, and then click on delete. If you sweep more than one subject line, then all the affected articles are deleted. Of course, if you click on delete within an article window, that article is the one that is deleted. Delete doesn't actually do anything except mark the article for deletion, and puts a "D" before at the start of the subject line. undelete reverses delete. comp compose a new message. You get a blank article window with From, To and Subject fields. Don't delete them. reply Reply to the article (article is selected in the same fashion, i.e. B1/B3 list window, or just the article that the reply cmd was executed in). The To field is filled in from the From field. You can use "inc" or "incall" to include the text of the article you're replying to. abort junk a comp/reply article without sending it. deliver post a complete comp/reply article (well, feed it to sendmail). savefile sets the name of the file that "save" writes to. save appends the current message into the savefile. Creates the file if it doesn't exist. You can also sweep several articles in the list window, then click on save (also in the list window), and it'll save all of them. multiart toggles the "only one article window at once" flag. This is handy for viewing several articles or reading one article while replying to another. allheaders toggles whether all header fields are displayed. By default, a particular set are suppressed (the set is in the array hidden_hdrs[] in mail.c). inc [n] Includes a message into the current position of the current message. If you specify a message number, it'll include that message. incall Same as inc, but will include the headers of the message, too. commit Write changes back to the mailbox, but don't actually quit. rescan Load any new mail that has arrived. Doesn't write any changes done so far, though. Bugs Probably vast numbers of them... Unlike most windows, it current has the tools *before* the window label. This is because of the broken tags problem. Right now, I'm cheating, and inserting the tools at the start of the tag, instead of the end - that seems to work... wily-0.13.41/tools/old/wilytoys/reader/getmsg.c100644 2743 200 606 6057267612 17670 0ustar garypgrad/* * getmsg.c - handle message reception from wily. */ #include "headers.h" rdWin * getActiveWin(void) { rdWin *w; Msg *m; Id id; while ((m = mq_next(wilyq, 0)) == 0) { if (rdAlarmEvent) { dorescan(); rdAlarmEvent = false; continue; } return 0; } id = msg_id(m); for (w = windows; w; w = w->next) if (id == w->id) { w->m = m; return w; } return 0; } wily-0.13.41/tools/old/wilytoys/reader/headers.h100644 2743 200 606 6057267614 20024 0ustar garypgrad#ifndef RD_HEADERS_H #define RD_HEADERS_H #include #include #include #include #include #include #include #ifdef __STDC__ char *strdup(char *); #endif #include #include #include #include #include "reader.h" #include "proto.h" #include "membuf.h" #endif /* RD_HEADERS_H */ wily-0.13.41/tools/old/wilytoys/reader/mail.c100644 2743 200 32604 6057267616 17373 0ustar garypgrad#include "headers.h" #include "mbox.h" #include "mail.h" static void build_msg_list(); static char *getarttext(mMsg *m); mWin *allocMWin(int kind, int num); void freeMWin(mWin *w); mWin *findMWin(void *ptr); int artDisplayed(rdWin *w, int n); void mDelete(rdWin *w, int first, int last, char *arg); void mUndelete(rdWin *w, int first, int last, char *arg); void mComp(rdWin *w, int first, int last, char *arg); void mExit(rdWin *w, int first, int last, char *arg); void mQuit(rdWin *w, int first, int last, char *arg); void mReply(rdWin *w, int first, int last, char *arg); void mAbort(rdWin *w, int first, int last, char *arg); void mDeliver(rdWin *w, int first, int last, char *arg); void mSavefile(rdWin *w, int first, int last, char *arg); void mSave(rdWin *w, int first, int last, char *arg); void dodeliver(rdWin *w, char *filename); void mMultiart(rdWin *w, int first, int last, char *arg); void mAllheaders(rdWin *w, int first, int last, char *arg); void mIncludeall(rdWin *w, int first, int last, char *arg); void mInclude(rdWin *w, int first, int last, char *arg); void doinclude(rdWin *w, int first, int last, char *arg, int all); void mCommit(rdWin *w, int first, int last, char *arg); void mRescan(rdWin *w, int first, int last, char *arg); mMbox *mbox; static char mboxname[MAXPATHLEN]; mWin *mwindows; mWin *listwin; static char **msgs; static char *savefile; static int multiart = 0; static int show_all_headers = 0; /* * These are headers that we'd rather not see when the message gets displayed. */ static char *hidden_hdrs[] = { "Content-Length", "Content-Transfer-Encoding", "Content-Type", "In-Reply-To", "Message-Id", "Mime-Version", "Original-Sender", "Received", "Sender", "Status", "X-Lines", "X-Mailer", "X-Newsreader" }; static int nhidden_hdrs = sizeof(hidden_hdrs)/sizeof(hidden_hdrs[0]); int main(int argc, char *argv[]) { mWin *mw; int ma = 0; int mustexist = 0; int timer = RESCAN_TIME; fflush(stdout); if (argc >=2 && strcmp(argv[1], "-ma")==0) { ma = 1; argc--; argv++; } multiart = ma; if (argc >= 2) { mustexist = 1; strcpy(mboxname, argv[1]); timer = 0; /* don't rescan named mboxes */ } else { char *u = getenv("USER"); if (!u || !*u) { fprintf(stderr,"Need $USER to find mailbox name\n"); exit(1); } sprintf(mboxname,"%s/%s", SPOOLDIR, u); } savefile = getenv(SAVEFILE_ENV); if (!savefile || !*savefile) { char s[MAXPATHLEN]; char *h; if ((h = getenv("HOME")) == 0 || !*h) savefile = sstrdup("mbox"); /* what planet are we on? */ else { sprintf(s,"%s/mbox",h); savefile = sstrdup(s); } } else savefile = sstrdup(savefile); set_hdr_filter(nhidden_hdrs, hidden_hdrs); if ((mbox = read_mbox((const char *)mboxname, 0, mustexist)) == 0) { perror(mboxname); exit(1); } mw = listwin = allocMWin(mMsgList, 0); build_msg_list(); if (readerInit(0, (char *)mw, mboxname, msgs, 0, ma, 0)) exit(1); rdSetRescanTimer(timer); readerMainLoop(); exit(0); } mWin * allocMWin(int kind, int num) { mWin *w = salloc(sizeof(*w)); mWin **p = &mwindows; w->kind = kind; w->msg = (kind == mDispArt || kind == mCompArt)? num : -1; w->mbox = mbox; w->next = 0; while (*p) p = &((*p)->next); *p = w; return w; } void freeMWin(mWin *w) { mWin **p = &mwindows; while (*p != w) p = &((*p)->next); *p = w->next; free(w); } mWin * findMWin(void *ptr) { mWin *mw = mwindows; while (mw && (mWin *)ptr != mw) mw = mw->next; return mw; } static void chkhdr(mString *s, int *len, char **rest) { int l; *rest = ""; /* default */ if (s == 0) { *len = 0; return; } l = s->s1 - s->s0; if (l > 20) { l = 20; *rest = "..."; } else if (l > 0) l--; /* skip newline */ *len = l; } static void build_msg_list(void) { int n; mMsg *m; ulong l; int lfrom, ldate, lsubject; char *rfrom, *rdate, *rsubject; mString *from; mString *date; mString *subject; int dc; if (msgs) for (n = 0; msgs[n]; n++) free(msgs[n]); msgs = (char **)srealloc(msgs, (mbox->nmsgs+1) * sizeof(char *)); for (n = 0; n < mbox->nmsgs; n++) { m = mbox->msgs[n]; dc = m->deleted? 'D' : ' '; from = m->from; date = m->date; subject = m->subject; chkhdr(from, &lfrom, &rfrom); chkhdr(date, &ldate, &rdate); chkhdr(subject, &lsubject, &rsubject); l = lfrom + ldate + lsubject + 10; msgs[n] = salloc(l); sprintf(msgs[n],"%c%d %.*s%s %.*s%s", dc, n+1, lfrom, from->s0, rfrom, lsubject, subject->s0, rsubject); } msgs[n] = 0; return; } void user_listSelection(rdWin *w, rdItemRange range) { static char title[300]; /* XXX standard silly guess */ int n = range.first; mMsg *m = mbox->msgs[n]; mString *from = m->from; mWin *mw; char *text; if (artDisplayed(w, n)) return; mw = allocMWin(mDispArt,n); sprintf(title," %s/%d", mbox->name, n+1); title[50] = 0; /* XXX - to make sure it's not too long. */ text = getarttext(m); getArtWin(n, mw, title, text, 0, 0, 0); } static char * getarttext(mMsg *m) { static char *text; static size_t textlen; size_t len; mString *body; body = &m->whole; len = body->s1 - body->s0; if (len >= textlen) { textlen = len + 1; text = srealloc(text, textlen); } if (show_all_headers) { memcpy(text, body->s0, len); text[len] = 0; } else { char *p = text; int n, l; mHdr *h; for (n = 0; n < m->nhdrs; n++) { h = m->hdrs[n]; if (h->hide) continue; l = h->value.s1 - h->name.s0; memcpy(p, h->name.s0, l); p += l; } *p++ = '\n'; /* make sure there's a separating line */ body = &m->body; len = body->s1 - body->s0; memcpy(p, body->s0, len); p[len] = 0; } return text; } int artDisplayed(rdWin *w, int n) { mWin *mw; for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) if ((w = userpWin(mw))) { rdGotoWin(w); return 1; } return 0; } static struct mCmd mcmds[] = { { "quit", MCANY, MNOARG, mQuit }, { "exit", MCANY, MNOARG, mExit }, { "reply", MCNOTCOMP, MARG, mReply }, { "delete", MCNOTCOMP, MARG, mDelete }, { "undelete", MCMSGLIST, MARG, mUndelete }, { "comp", MCMSGLIST, MNOARG, mComp }, { "abort", MCCOMPART, MARG, mAbort }, { "deliver", MCCOMPART, MARG, mDeliver }, { "savefile", MCANY, MARG, mSavefile }, { "save", MCANY, MARG, mSave }, { "multiart", MCANY, MARG, mMultiart}, { "allheaders", MCANY, MARG, mAllheaders}, { "inc", MCCOMPART, MARG, mInclude}, { "incall", MCCOMPART, MARG, mIncludeall}, { "commit", MCANY, MNOARG, mCommit }, { "rescan", MCANY, MNOARG, mRescan }, { 0, 0, 0 } }; void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange r, char *arg) { int c; fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ if ((mcmds[c].context & MCMSGLIST) == 0) { fprintf(stderr,"%s: only valid within the message list\n", cmd); return; } /* check we've been given an appropriate argument */ if (mcmds[c].req == MARG && r.first == -1) { fprintf(stderr,"%s: needs a message\n", cmd); return; } (*mcmds[c].fn)(w, r.first, r.last, arg); return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; mWin *mw; unsigned short context; fflush(stdout); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((mw = findMWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } context = (mw->kind == mDispArt)? MCDISPART : MCCOMPART; if ((mcmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } (*mcmds[c].fn)(w, mw->msg, mw->msg, arg); return; } void mDelete(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *ow; int n, i; rdWin *lp = userpWin(listwin); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) return; if (mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 1; *msgs[n] = 'D'; rdChangeItem(lp, n, msgs[n]); mw->mbox->ndel++; if (mw->kind != mDispArt) /* might be the msg list */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) break; if (mw) { if ((ow = userpWin(mw))) /* this msg is displayed; remove the pane */ closeWin(ow); freeMWin(mw); } } return; } void mUndelete(rdWin *w, int first, int last, char *arg) { mWin *mw; int n, i; rdWin *lp = userpWin(listwin); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) return; if (!mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 0; mw->mbox->ndel--; *msgs[n] = ' '; rdChangeItem(lp, n, msgs[n]); } return; } void mReply(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Reply abort deliver "; static char body[300]; /* XXX */ mString *from = mbox->msgs[n]->from; mString *subject = mbox->msgs[n]->subject; int lfrom, lsubject; char *me = getenv("USER"); char *re = "Re: "; if (!me || !*me) me = ""; lfrom = (from->s1 - from->s0); /* include newline */ lsubject = (subject->s1 - subject->s0); if (lsubject > 4 && strncmp(subject->s0, re, 4)==0) re = ""; sprintf(body,"From: %s\nTo: %.*sSubject: %s%.*s\n", me, lfrom, from->s0, re, lsubject, subject->s0); if (getArtWin(n, mw, title, body, 0, 0, 1)) return; /* XXX - should clear up */ return; } void mAbort(rdWin *w, int first, int last, char *arg) { mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; fprintf(stderr,"Message aborted\n"); closeWin(w); freeMWin(mw); return; } void mDeliver(rdWin *w, int first, int last, char *arg) { mWin *mw; char *filename = tmpnam((char *)0); if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; rdBodyToFile(w, filename); dodeliver(w,filename); return; } void mQuit(rdWin *w, int first, int last, char *arg) { update_mbox(mbox); mExit(w, first, last, arg); } void mExit(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *rw; /* close msg windows first */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mCompArt || mw->kind == mDispArt) if ((rw = userpWin(mw))) closeWin(rw); for (mw = mwindows; mw; mw = mw->next) if (mw->kind != mCompArt && mw->kind != mDispArt) if ((rw = userpWin(mw))) closeWin(rw); exit(0); /* not actually needed - reader will exit for us */ } void mComp(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Compose abort deliver "; static char body[300]; /* XXX */ char *me = getenv("USER"); if (!me || !*me) me = ""; sprintf(body,"From: %s\nTo: \nSubject: \n\n", me); if (getArtWin(n, mw, title, body, 0, 0, 1)) return; /* XXX - should clear up */ return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ mWin *mw; if ((mw = findMWin(w->userp)) == 0) return; sprintf(cmd,"%s < %s", MTU, filename); fflush(stdout); system(cmd); closeWin(w); freeMWin(mw); return; } void mSavefile(rdWin *w, int first, int last, char *arg) { if (savefile) free(savefile); savefile = sstrdup(arg); } void mSave(rdWin *w, int first, int last, char *arg) { FILE *fp; mWin *mw; mMsg *m; mString *text; size_t len; int n; if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); return; } if ((mw = findMWin(w->userp)) == 0) return; for (n = first; n <= last; n++) { m = mw->mbox->msgs[n]; text = &m->whole; len = text->s1 - text->s0; if (fwrite(text->s0, (size_t)1, len, fp) != len) perror("fwrite"); fputc('\n',fp); printf("Written message %d to %s\n", n+1, savefile); /* count from 1 */ } fflush(stdout); fclose(fp); } void mMultiart(rdWin *w, int first, int last, char *arg) { multiart = !multiart; rdSetMulti(0, multiart); } void mAllheaders(rdWin *w, int first, int last, char *arg) { show_all_headers = !show_all_headers; } void mInclude(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,0); } void mIncludeall(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,1); } void doinclude(rdWin *w, int first, int last, char *arg, int all) { mWin *mw; rdWin *ow; int msgnum; /* message we're going to include */ mMsg *m; mString *s; size_t len; int n; if ((mw = findMWin(w->userp)) == 0) return; if (mw->kind != mCompArt) return; msgnum = mw->msg; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) == 0) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum--; } } if (msgnum >= mw->mbox->nmsgs) { fprintf(stderr,"Only %d messages\n", mw->mbox->nmsgs); return; } m = mw->mbox->msgs[msgnum]; s = all? &(m->whole) : &(m->body); len = s->s1 - s->s0; rdInclude(w, s->s0, len); } void mCommit(rdWin *w, int first, int last, char *arg) { update_mbox(mbox); build_msg_list(); changeItems(userpWin(listwin), msgs, 0); } void dorescan(void) { mRescan((rdWin *)0, 0, 0, (char *)0); } void mRescan(rdWin *w, int first, int last, char *arg) { rdWin *lp = userpWin(listwin); int n = mbox->nmsgs; extend_mbox(mbox); if (n >= mbox->nmsgs) return; build_msg_list(); while (n < mbox->nmsgs) rdAddItem(lp, msgs[n++]); } wily-0.13.41/tools/old/wilytoys/reader/mail.h100644 2743 200 3231 6057267617 17353 0ustar garypgrad/* * stuff needed for the mail client. * smk */ #include "headers.h" #include "mbox.h" typedef struct _mWin mWin; /* * We know of several different kinds of window: mailbox lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind; /* what kind of window it is */ int msg; /* message number, if mDispArt, or mCompArt */ mMbox *mbox; /* the message box we're associated with */ struct _mWin *next; }; /* * These are the commands that the mailer recognises, and the * contexts that they are valid. */ #define MCMSGLIST 01 #define MCDISPART 02 #define MCCOMPART 04 #define MCNOTCOMP (MCMSGLIST|MCDISPART) #define MCANY (MCMSGLIST|MCDISPART|MCCOMPART) #define MNOARG 00 #define MARG 01 struct mCmd { char *cmd; unsigned short context; unsigned short req; void (*fn)(rdWin *, int, int, char *); /* pane, first msg, last msg, arg */ }; /* * The following must be the pathname of a program capable * of taking a complete message on stdin, with no arguments, * and delivering it. */ #define MTU "/usr/lib/sendmail -t" /* * Where do you keep your mail? Don't currently support anything other * than directly-accessible mail files.... */ #define SPOOLDIR "/var/mail" /* * How long we wait before rescanning. */ #define RESCAN_TIME 60 /* * Environment variable and default filename for savefile's * default parameter. */ #define SAVEFILE_ENV "SAVEFILE" #define SAVEFILE_DEF "mbox" /* in $HOME, if possible */ wily-0.13.41/tools/old/wilytoys/reader/mbox.c100644 2743 200 20732 6057267620 17410 0ustar garypgrad/* * mbox.c */ #include "headers.h" #include "mbox.h" #include #include #define COPYSIZE 8192 #define INCR 10 static mMbox *currmbox; /* current mbox being processed */ static mMsg *msg; /* current message */ static int nhdrs; /* number of current headers read so far. */ static int ahdrs; /* number of allocated hhdrs */ static mHdr **hdrs; /* current list */ static char **hiddenhdrs; /* names of header fields we don't want to see */ static int nhiddenhdrs; extern int load_mbox(mMbox *, int); static char *readhdrs(char *ptr); static void mkhdr(char *s0, char *s1); static void checkhide(mHdr *h); static int freehdrlist(int n, char **h); static void newmsg(char *s0); static char *readmsg(char *ptr); static int same(mString a, mString b); static int strsame(char *s, mString b); static void fillmsg(mMsg *msg); static void fillhdr(char *name, mMsg *msg, mString **ptr); static ulong getlength(void); static char *findend(char *ptr); static void freemsg(mMbox *mbox, int n); /* * readhdrs(ptr) - read the headers in a message, looking for * the terminating newline. Returns pointer to first char in body. */ static char * readhdrs(char *ptr) { char *nptr = ptr; /* invariant is that nptr pts to first char of next header. when it doesn't (nptr==\n), we've reached the blank line at then end of the hdrs */ while (*nptr != '\n') { if ((nptr = strchr(nptr,'\n')) == 0) panic("No newlines in readhrds()"); if (nptr[1]==' ' || nptr[1]=='\t') { /* multi-line hdr */ nptr++; continue; } else { mkhdr(ptr, ++nptr); ptr = nptr; continue; } } return ++nptr; /* skip blank line */ } /* * mkhdr(s0,s1) - add a new header to the current list. */ static void mkhdr(char *s0, char *s1) { size_t l; char *c = strchr(s0, ':'); mHdr *h; if (c == 0) panic("no colon in hdr"); if (nhdrs >= ahdrs) { ahdrs += INCR; l = ahdrs * sizeof(*hdrs); hdrs = (mHdr **)(hdrs? realloc(hdrs,l) : malloc(l)); if (hdrs == 0) panic("resizing hdr list"); } h = hdrs[nhdrs++] = (mHdr *)malloc(sizeof(*h)); if (h == 0) panic("adding new hdr"); h->name.s0 = s0; h->name.s1 = c++; while (*c == ' ' || *c == '\t') c++; h->value.s0 = c; h->value.s1 = s1; checkhide(h); } static void checkhide(mHdr *h) { int n; int l = h->name.s1 - h->name.s0; for (n = 0; n < nhiddenhdrs; n++) if (strncmp(hiddenhdrs[n], h->name.s0, l) == 0) { h->hide = 1; return; } h->hide = 0; /* default to showing header */ } int set_hdr_filter(int nhdrs, char **hdrs) { int n; (void)freehdrlist(nhiddenhdrs, hiddenhdrs); /* clear out existing list */ if ((hiddenhdrs = (char **)realloc((void *)hiddenhdrs, (nhdrs+1)*sizeof(char *))) == 0) return 1; for (n = 0; n < nhdrs; n++) if ((hiddenhdrs[n] = strdup(hdrs[n])) == 0) return freehdrlist(n, hiddenhdrs); hiddenhdrs[n] = 0; nhiddenhdrs = n; return 0; } static int freehdrlist(int n, char **h) { while (n--) free (*h++); return 1; } static void newmsg(char *s0) { size_t n; if (currmbox->nmsgs >= currmbox->amsgs) { currmbox->amsgs += INCR; n = currmbox->amsgs*sizeof(*currmbox->msgs); currmbox->msgs = (mMsg **)(currmbox->msgs? realloc(currmbox->msgs,n) : malloc(n)); if (currmbox->msgs == 0) panic("newmsg msg"); } msg = currmbox->msgs[currmbox->nmsgs++] = (mMsg *)malloc(sizeof(*msg)); if (msg == 0) panic("adding new msg"); memset(msg,0,sizeof(*msg)); msg->whole.s0 = s0; if ((hdrs = (mHdr **)malloc((ahdrs = INCR)*sizeof(*hdrs)))==0) panic("newmsg hdrs"); nhdrs = 0; } /* * readmsg(ptr) - read a complete message. Assumes we're already pointing * to the F of the "From " */ static char * readmsg(char *ptr) { char *nptr; ulong contentlength; newmsg(ptr); /* resets nhdrs and hdrs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.s0 = nptr; if ((contentlength = getlength()) == 0) nptr = findend(nptr); else nptr += contentlength; msg->whole.s1 = msg->body.s1 = nptr; fillmsg(msg); /* update from,date,subject fields */ mb_split(ptr, ++nptr); return nptr; } static int same(mString a, mString b) { if ((a.s1 - a.s0) != (b.s1 - b.s0)) return 0; return (strncmp(a.s0,b.s0,a.s1-a.s0) == 0); } static int strsame(char *s, mString b) { mString a; a.s0 = s; a.s1 = s + strlen(s); return same(a,b); } static void fillmsg(mMsg *msg) { fillhdr("From",msg,&msg->from); fillhdr("Date",msg,&msg->date); fillhdr("Subject",msg,&msg->subject); } static void fillhdr(char *name, mMsg *msg, mString **ptr) { int x; static mString empty; for (x = 0; x < msg->nhdrs; x++) if (strsame(name,msg->hdrs[x]->name)) { *ptr = &(msg->hdrs[x]->value); return; } /* Sigh. This sort of thing is very irritating. */ empty.s0 = empty.s1 = msg->whole.s1; *ptr = ∅ (void)fprintf(stderr,"Message does not have a '%s' header\n",name); } static ulong getlength(void) { int x; ulong l; for (x = 0; x < nhdrs; x++) if (strsame("Content-Length",hdrs[x]->name)) goto found; return 0; found: /* use sscanf magic to skip whitespace, and stop at end */ if (sscanf(hdrs[x]->value.s0,"%lu",&l) != 1 || l==0) return 0; if ((msg->body.s0+l+1) == currmbox->mbox_end) return l; /* spot on */ if ((msg->body.s0+l+5) >= currmbox->mbox_end) return 0; /* too long */ if (strncmp("\nFrom ",(msg->body.s0+l),6) == 0) return l; else return 0; } static char * findend(char *ptr) { for (; ptr+5 <= currmbox->mbox_end && strncmp("\nFrom ",ptr,6); ptr++) if ((ptr = strchr(ptr,'\n')) == 0) panic("findend"); if (ptr+5 > currmbox->mbox_end) return currmbox->mbox_end-1; else return ptr; } mMbox * read_mbox(const char *filename, int readonly, int mustexist) { char *ptr; extern int empty_mbox(mMbox *box, const char *filename, int mustexist); if ((currmbox = (mMbox *)malloc(sizeof(*currmbox))) == 0) return 0; memset(currmbox,0,sizeof(*currmbox)); currmbox->readonly = readonly; if ((currmbox->name = strdup(filename)) == 0) goto panic2; if (load_mbox(currmbox, 0) && empty_mbox(currmbox, filename, mustexist)) goto panic1; for (ptr = currmbox->mbox_start; ptr < currmbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) goto panic1; return currmbox; panic1: free(currmbox->name); panic2: free(currmbox); return 0; } int extend_mbox(mMbox *mbox) { char *ptr; if (load_mbox(mbox,1)) return 1; for (ptr = mbox->mbox_start; ptr < mbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) return 1; return 0; } /* * update_mbox(mbox) - write any changes back to the file. */ int update_mbox(mMbox *mbox) { static char lockname[MAXPATHLEN+1], newname[MAXPATHLEN+1]; int ntries, maxtries = 10; int fd, fd2; int x; struct stat st; int r = 0; int l; mMsg *m; if (mbox->readonly || mbox->ndel == 0) return 0; (void)sprintf(lockname,"%s.lock",mbox->name); (void)sprintf(newname,"%s.new",mbox->name); for (ntries = 0; ntries < maxtries; ntries++) { if (link(mbox->name,lockname) == 0) goto locked; sleep(1); } locked: if (stat(mbox->name,&st) == -1) goto broken; if (st.st_size < mbox->size) { fprintf(stderr,"Mail file corrupted - no changes made\n"); goto broken; } if ((fd = open(newname,O_RDWR|O_CREAT|O_TRUNC)) < 0 || fchmod(fd,st.st_mode) == -1) goto broken; for (x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) continue; l = m->whole.s1 - m->whole.s0 + 1; if (write(fd,m->whole.s0,l) != l || write(fd,"\n",1) != 1) { fprintf(stderr,"write truncated, changes aborted\n"); goto broken; } } if (st.st_size > mbox->size) { static char buf[COPYSIZE]; if ((fd2 = open(mbox->name,O_RDONLY)) < 0 || lseek(fd2,mbox->size,SEEK_SET) == -1) { fprintf(stderr,"Can't open mbox for update!\n"); goto broken; } while ((l = read(fd2,buf,COPYSIZE)) > 0) if (write(fd,buf,l) != l) { fprintf(stderr,"Can't copy updated mbox\n"); close(fd2); goto broken; } close(fd2); } rename(newname,mbox->name); stat(mbox->name, &st); mbox->mtime = st.st_mtime; mbox->size = st.st_size; goto unlock; broken: r = 1; if (fd >= 0) close(fd); unlink(newname); unlock: unlink(lockname); /* now update the list of messages in the mbox */ for (l = x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) freemsg(mbox,x); else mbox->msgs[l++] = m; } mbox->nmsgs = l; mbox->ndel = 0; return r; } static void freemsg(mMbox *mbox, int n) { mMsg *m = mbox->msgs[n]; int h; mbox->msgs[n] = 0; for (h = 0; h < m->nhdrs; h++) free(m->hdrs[h]); free(m->hdrs); mb_free(m->whole.s0); free(m); } wily-0.13.41/tools/old/wilytoys/reader/mbox.h100644 2743 200 3460 6057267621 17375 0ustar garypgrad/* * mbox.h - definitions for mailbox-handling library. */ #ifndef MBOX_H #define MBOX_H #include typedef struct mstring mString; typedef struct mhdr mHdr; typedef struct mmsg mMsg; typedef struct mhdrline mHdrLine; typedef struct mmbox mMbox; struct mstring { /* can include several \n characters */ char *s0; /* first char in string */ char *s1; /* char after last newline */ }; struct mhdr { /* includes ws if hdr is multiple lines */ mString name; /* s1 points to colon */ mString value; /* s0 pts to first non-ws, s1 to after \n */ int hide; /* don't display if true */ }; /* name,s0,value.s2 gives whole header */ struct mmsg { int nhdrs; /* number of headers */ mHdr **hdrs; /* headers themselves */ mString *from; /* points to value fields from mHdrs */ mString *date; mString *subject; mString whole; /* All of the message (headers and body) */ mString body; /* All of the body (not including first blank line) */ int deleted; /* marked for deletion */ int read; /* if has been read */ ulong pos; /* origin in window, if it's been read before. */ }; struct mhdrline { char *s0,*s1; /* buffer containing accumulated text */ ulong p0, p1; /* positions in hdrw for this piece of text */ }; struct mmbox { char *mbox_start; /* area of memory that the mailbox is */ char *mbox_end; /* loaded into */ int nmsgs; /* number of messages */ int amsgs; /* size of msgs array */ mMsg **msgs; /* the messages themselves */ int ndel; /* number of deleted messages */ int readonly; time_t mtime; /* time it was last modified */ off_t size; /* how big it was, last time we checked */ char *name; /* the filename */ }; mMbox *read_mbox(const char *filename, int readonly, int mustexist); int extend_mbox(mMbox *mbox); int set_hdr_filter(int nhdrs, char **hdrs); #endif /* ! MBOX_H */ wily-0.13.41/tools/old/wilytoys/reader/proto.h100644 2743 200 2353 6057267623 17575 0ustar garypgradvoid queueMsg(rdWin *w); void freeMsgq(rdWin *w); rdWin *getActiveWin(void); int changeItems(rdWin *w, char **items, int savecontents); void user_listSelection(rdWin *w, rdItemRange r); void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange items, char *arg); void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg); char *sstrdup(char *str); int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents, int protect); int getListWin(int user, void *userp, char *title, char **items, int savecontents); int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents); int readerMainLoop(void); rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1); void highlightItem(rdWin *w, rdItemRange r); void winReflectCmd(rdWin *w, char *cmd, char *arg); void closeWin(rdWin *w); void freeWin(rdWin *w); void msg_handler(rdWin *w); void rdGotoWin(rdWin *w); rdWin *userpWin(void *ptr); ulong atoul(char *str); void rdSetMulti(int list, int art); void rdInclude(rdWin *w, char *str, size_t len); void rdSetRescanTimer(int secs); void dorescan(void); int rdDelItem(rdWin *w, int item); int rdAddItem(rdWin *w, char *text); int rdChangeItem(rdWin *w, int item, char *text); wily-0.13.41/tools/old/wilytoys/reader/Makefile100600 2743 200 1254 6056644002 17675 0ustar garypgradW = /home/steve/src/9/orig/wily-0.9.5 O = /home/steve/src/9/orig/orig-0.9.5 CFLAGS = -Xc -g -DUSE_SELECT CPPFLAGS = -I. -I$W/include -I$W LDFLAGS = -L$W/libmsg -L$W/libXg LDLIBS = -lmsg -lXg -lnsl -lsocket PATCHES = includepatches libmsgpatches wilypatches winpatches PROGS = mreader browser OBJS = getmsg.o mail.o reader.o membuf.o mbox.o solaris.o utils.o all: $(PROGS) mreader: $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) clean: $(RM) *.o core nuke: $(RM) *.o core $(PROGS) cleanpatches: $(RM) $(PATCHES) patches: $(PATCHES) includepatches: makepatch include > $@ libmsgpatches: makepatch libmsg > $@ wilypatches: makepatch wily > $@ winpatches: makepatch win > $@ wily-0.13.41/tools/old/wilytoys/reader/reader.c100644 2743 200 41034 6057267625 17710 0ustar garypgrad/* * reader.c - functions for handling news/article reader windows. */ #include "headers.h" Bool debug = false; Bool frommessage = true; /* * These determine whether we'll have one list and one article window, * that gets overwritten each time we change group/mailbox/article, * or whether we just spawn a new one. */ int rdMultiList = 0; int rdMultiArt = 0; /* * The windows currently active. */ rdWin *windows = 0; static rdWin *Listwin = 0; static rdWin *Artwin = 0; /* * General wily comms stuff. */ Mqueue realwilyq; Mqueue *wilyq = &realwilyq; Fd wilyfd; /* * Amount of time we wait before causing a rescan event, in seconds. * If zero, then we don't rescan. */ static int rdRescanTimer = 0; Bool rdAlarmEvent = false; static void (*old_alarm_handler)(int) = 0; /* * default contents of tags */ char *rdListTagStr = " delete undelete comp reply quit exit "; char *rdArtTagStr = " delete reply save inc "; static rdWin *allocWin(rdWinType kind, const char *title); static int connectWin(rdWin *w, char *filename); static rdWin *getWin(int user, void *userp, rdWinType kind, char *title, char *filename, int protect); static void clearWin(rdWin *w); static void freeItems(rdWin *w); static int loadItems(rdWin *w, char **items, int savecontents); static int initWin(int user, void *userp, rdWin *w, char *title, char *filename, int protect); static void anyEvent(rdWin *w); static void winDelete(rdWin *w, int which, ulong p0, ulong p1); static void winInsert(rdWin *w, int which, ulong p, char *str); static void updateBody(rdWin *w, ulong p0, ulong p1, char *str); static void winGoto(rdWin *w, ulong p0, char *str); static void winExec(rdWin *w, char *cmd, char *arg); static void DelWin(rdWin *w, char *arg); static int rdBuiltin(rdWin *w, char *cmd, char *str); static void addrEvent(rdWin *w); static void bodyEvent(rdWin *w); static size_t countlines(char *str, size_t len); static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf); static void alarm_handler(int signal); static void set_sig(void); static void updateItems(rdWin *w, rdItem *i, int len); /* * allocWin(kind, title) - create a new, blank window of a given kind. */ static rdWin * allocWin(rdWinType kind, const char *title) { rdWin *w = salloc(sizeof(*w)); w->title = sstrdup((char *)title); w->wintype = kind; w->id = -1; w->m = 0; w->items = 0; w->body = 0; w->protect = 0; w->taglen = w->bodylen = 0; w->next = windows; windows = w; return w; } /* * connectWin(w, filename) - connect to wily, to create a new window. * If filename is true, then we get wily to open the given file. Otherwise, * we ask for a new, blank window. * Returns 0 for success. */ static int connectWin(rdWin *w, char *filename) { int fd; if (filename == 0) filename = "New"; if (rpc_new(wilyq, &w->id, filename, false) < 0) { freeWin(w); return -1; } return 0; } /* * getWin(user, userp, kind, title, filename, protect) - grab a window of the appropriate type. */ static rdWin * getWin(int user, void *userp, rdWinType kind, char *title, char *filename, int protect) { rdWin *w; if ((kind == rdList && (!Listwin || rdMultiList)) || (kind == rdArticle && (!Artwin || Artwin->protect || protect || rdMultiArt))) { /* we can create a new window */ w = allocWin(kind, title); if (connectWin(w,filename)) return 0; if (kind == rdList) Listwin = w; else if (!protect) Artwin = w; } else { /* have to reuse the existing window */ w = (kind == rdList)? Listwin : Artwin; clearWin(w); } initWin(user, userp, w, title, filename, protect); return w; } /* * clearWin(w) - erase the tag and body of a window */ static void clearWin(rdWin *w) { if (w->taglen) (void) rpc_settag(wilyq, w->id, ""); w->taglen = 0; w->protect = 0; if (w->bodylen) { (void) rpc_delete(wilyq, w->id, 0, w->bodylen); w->bodylen = 0; if (w->wintype == rdList) freeItems(w); } } /* * discard all the items in the window's list */ static void freeItems(rdWin *w) { rdItem *i, *j; for (i = w->items; i; i = j) { j = i->next; free(i); } w->items = 0; } /* * loadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items, int savecontents) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; if (savecontents) { for (len = 0, n = 0; items[n]; n++) len += strlen(items[n]) + seplen; w->body = buf = salloc(len); } while (*items) { i = salloc(sizeof(*i)); i->next = 0; i->p0 = p0; len = strlen(*items); if (j) j->next = i; else w->items = i; j = i; if (rpc_insert(wilyq, w->id, p0, *items)) { freeItems(w); return -1; } p0 += len; if (rpc_insert(wilyq, w->id, p0, sep)) { freeItems(w); return -1; } i->p1 = (p0 += seplen); items++; } w->bodylen = p0; return 0; } /* * changeItems(w, items, savecontents) - update the contents of a list window. */ int changeItems(rdWin *w, char **items, int savecontents) { if (w->wintype != rdList) return 1; freeItems(w); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) return 1; w->bodylen = 0; } return loadItems(w, items, savecontents); } /* * initWin(user, userp, w, title, filename, protect) - initialise the window's tag, label, etc. */ static int initWin(int user, void *userp, rdWin *w, char *title, char *filename, int protect) { char tag[300]; /* XXX guess */ char *tagstr = w->wintype == rdArticle? rdArtTagStr : rdListTagStr; if (rpc_setname(wilyq, w->id, title)) return 1; sprintf(tag,"%s", tagstr); /* XXX at the moment, we don't include the title */ if (rpc_settag(wilyq, w->id, tag)) return 1; w->taglen = strlen(tag); w->user = user; w->userp = userp; w->protect = protect; return 0; } /* * getArtWin(title, text, filename, savecontents, protect) - get an article window, and load it with * either the given text, or from the given file. */ int getArtWin(int user, void *userp, char *title, char *text, char *filename, int savecontents, int protect) { rdWin *w = getWin(user, userp, rdArticle, title, filename, protect); if (w == 0) return 1; if (text) { int l = strlen(text); w->bodylen = l; if (rpc_insert(wilyq, w->id, 0, text)) return 1; if (savecontents) { w->body = salloc(l); strcpy(w->body, text); } } return 0; } /* * get a List window, and load it with the items in the array (which * must be null-terminated). */ int getListWin(int user, void *userp, char *title, char **items, int savecontents) { rdWin *w = getWin(user, userp, rdList, title, (char *)0, 0); if (w == 0) return 1; return loadItems(w, items, savecontents); } /* * readerInit(title, items, ml, ma) - start things off by creating * a list window. Tell the reader whether we'll want one or more of * the list and article windows. */ int readerInit(int user, char *userp, char *title, char **items, int ml, int ma, int savecontents) { rdMultiList = ml; rdMultiArt = ma; if ((wilyfd = get_connect()) < 0) return 1; mq_init(wilyq, wilyfd); return getListWin(user, userp, title, items, savecontents); } /* * readerMainLoop() - get messages from wily, and act upon them. */ int readerMainLoop(void) { rdWin *w; Msg *m; int istag; while (windows) { if ((w = getActiveWin()) == 0) { fprintf(stderr,"No message available\n"); return 1; } m = w->m; switch (m->mtype) { char *cmd, *arg; ulong p0, p1; case EMexec: decode_exec_e(m, &cmd, &arg); winExec(w, cmd, arg); break; case EMgoto: decode_goto_e(m, &p0, &arg); winGoto(w, p0, arg); break; case EMinsert: istag = IsBody; decode_insert_e(m, &p0, &arg); winInsert(w, istag, p0, arg); break; case EMdelete: istag = IsBody; decode_delete_e(m, &p0, &p1); winDelete(w, istag, p0, p1); break; default: fprintf(stderr,"Unknown msg type!\n"); exit(1); } } return 1; } /* * delete item n from the list */ int rdDelItem(rdWin *w, int item) { rdItem **pi; rdItem *i; int len; if (w->wintype != rdList || item < 0) return 1; for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) return 1; /* not found */ i = *pi; len = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) < 0) return 1; *pi = i->next; free(i); updateItems(w, *pi, -len); return 0; } /* * add a new item to the end of the list */ int rdAddItem(rdWin *w, char *text) { rdItem **pi; rdItem *i; int len = (int)strlen(text); char *sep = "\n"; if (w->wintype != rdList || !text || !*text) return 1; i = salloc(sizeof(*i)); for (pi = &w->items; *pi; pi = &((*pi)->next)); *pi = i; i->p0 = w->bodylen; i->p1 = i->p0 + len; i->next = 0; if (rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p1++, sep)) return 1; len += strlen(sep); w->bodylen += len; return 0; } /* * change the text of an item */ int rdChangeItem(rdWin *w, int item, char *text) { rdItem **pi; rdItem *i; int len, oldlen, newlen = strlen(text); char *sep = "\n"; if (w->wintype != rdList || !text || !*text) return 1; for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) return 1; i = *pi; oldlen = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) || rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p0 + newlen, sep)) return 1; newlen += strlen(sep); i->p1 = i->p0 + newlen; len = newlen - oldlen; updateItems(w, i->next, len); return 0; } static void updateItems(rdWin *w, rdItem *i, int len) { w->bodylen += len; while (i) { i->p0 += len; i->p1 += len; i = i->next; } } /* * text has been deleted */ static void winDelete(rdWin *w, int which, ulong p0, ulong p1) { rdItem *i; ulong l = p1 - p0; if (which == IsTag) { w->taglen -= l; return; } if (w->wintype == rdArticle) { w->bodylen -= l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p0 && p1 <= i->p1) break; if (!i) return; i->p1 -= l; for (i = i->next; i; i = i->next) { i->p0 -= l; i->p1 -= l; } updateBody(w, p0, p1, (char *)0); return; } /* * text has been inserted */ static void winInsert(rdWin *w, int which, ulong p, char *str) { rdItem *i; int l = strlen(str); if (which == IsTag) { w->taglen += l; return; } if (w->wintype == rdArticle) { w->bodylen += l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p && p <= i->p1) break; if (!i) return; i->p1 += l; for (i = i->next; i; i = i->next) { i->p0 += l; i->p1 += l; } updateBody(w, p, (ulong)l, str); return; } /* * updateBody(w,p0,p1,str) - insert p1 chars of str at p0, or remove the text * between p0 and p1. * XXX - this is *utterly* revolting, and horrendously slow. But it's quick * and simple, and will do for now. */ static void updateBody(rdWin *w, ulong p0, ulong p1, char *str) { char *newbuf; ulong newlen; if (w->body == 0) return; if (str) newlen = w->bodylen + p1; else newlen = w->bodylen - (p1 - p0); newbuf = salloc(newlen); strncpy(newbuf, w->body, p0); if (str) { strncpy(newbuf + p0, str, p1); strcpy(newbuf + p0 + p1, w->body + p0); } else { strcpy(newbuf + p0, w->body + p1); } free(w->body); w->body = newbuf; w->bodylen = newlen; } rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1) { int n; rdItem *i; rdItemRange r; r.first = r.last = -1; r.i0 = r.i1 = 0; if (w->wintype != rdList || p1 < p0) return r; for (n = 0, i = w->items; i; i = i->next, n++) { if (i->p0 <= p0 && p0 <= i->p1) { r.first = r.last = n; r.i0 = r.i1 = i; } if (i->p0 <= p1 && p1 <= i->p1) { r.last = n; r.i1 = i; return r; } } return r; /* sigh */ } void highlightItem(rdWin *w, rdItemRange r) { static char addr[80]; /* XXX - overkill */ rdItem *i; ulong p0, p1; int n; if (!r.i0 || !r.i1) { for (i = w->items, n = 0; n <= r.last; n++, i = i->next) { if (n == r.first) p0 = i->p0; if (n == r.last) p1 = i->p1; } } else { p0 = r.i0->p0; p1 = r.i1->p1; } sprintf(addr,"#%lu,#%lu", p0, p1); (void)rpc_goto(wilyq, w->id, addr); } /* * A B3 event has occured. */ static void winGoto(rdWin *w, ulong p0, char *str) { /* If this is a list, then it counts as a selection. Otherwise, we just reflect it back to wily as a normal B3 event. */ if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p0); if (r.first == -1) return; /* sigh */ highlightItem(w, r); user_listSelection(w,r); return; } else (void)rpc_goto(wilyq, w->id, str); return; } /* * A B2(B1) command has been invoked. */ static void winExec(rdWin *w, char *cmd, char *arg) { ulong p0, p1; /* * Lots of options here: * - B2 with "|<>" - reflect back to wily. * - B2 cmd recognised by the reader routines - Del is about it. Execute * them ourselves. * - B2 not recognised by the reader routines - pass them onto the user, * after first getting the position of the argument within the body, if * necessary. * - B2B1 recognised by the reader routines - none spring to mind, but * I might add some. Execute them ourselves. * - B2B1 not recognised - pass onto user. */ if (!*cmd || strstr(cmd,"|<>")) { winReflectCmd(w,cmd, arg); return; } if (rdBuiltin(w,cmd,arg) == 0) return; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p1); if (r.first == -1) { p0 = p1 = 0; } else { highlightItem(w, r); p0 = r.i0->p0; p1 = r.i1->p1; } user_cmdList(w,cmd,p0,p1,r,arg); return; } user_cmdArt(w, cmd, p0, p1, arg); return; } void winReflectCmd(rdWin *w, char *cmd, char *arg) { (void)rpc_exec(wilyq, w->id,cmd,arg); } /* * delete this particular window from the list. */ static void DelWin(rdWin *w, char *arg) { closeWin(w); } void closeWin(rdWin *w) { /* get wily to close the pane */ (void)rpc_exec(wilyq, w->id, "Del", ""); /* free up resources */ free(w->title); free(w->body); if (w->wintype == rdList) freeItems(w); /* XXX - currently leak the stateinfo stuff */ freeWin(w); return; } void freeWin(rdWin *w) { rdWin **wp = &windows; /* remove from the window chain */ while ((*wp) != w) wp = &((*wp)->next); *wp = w->next; if (w == Artwin) Artwin = 0; if (w == Listwin) Listwin = 0; if (windows == 0) exit(0); return; } static struct { char *cmd; void (*fn)(rdWin *, char *); } builtins[] = { { "Del", DelWin }, { 0, 0 } }; /* * check for builtin commands understood by the reader routines. */ static int rdBuiltin(rdWin *w, char *cmd, char *str) { int i; for (i = 0; builtins[i].cmd; i++) if (strcmp(builtins[i].cmd, cmd) == 0) { (*builtins[i].fn)(w, str); return 0; } return 1; } /* * "redisplay" a window that's already open. */ void rdGotoWin(rdWin *w) { (void)rpc_goto(wilyq, w->id, "."); } rdWin * userpWin(void *ptr) { rdWin *w = windows; while (w && w->userp != ptr) w = w->next; return w; } /* * Some routines which attempt to extract the body of a window, * and store it in a file. if p0==p1==0, assume all the body is wanted. */ void rdBodyToFile(rdWin *w, char *filename) { FILE *fp; char *buf = salloc(w->bodylen+1); if (rpc_read(wilyq, w->id, 0, w->bodylen, buf)) return; if ((fp = fopen(filename, "w"))) { (void)fprintf(fp,"%s",buf); fclose(fp); } free(buf); return; } /* * change current settings for multi-list and multi-art windows. */ void rdSetMulti(int list, int art) { rdMultiList = list; rdMultiArt = art; } static void alarm_handler(int signal) { if (signal != SIGALRM) return; set_sig(); rdAlarmEvent = true; if (old_alarm_handler != SIG_DFL && old_alarm_handler != SIG_IGN) (*old_alarm_handler)(signal); alarm(rdRescanTimer); } static void set_sig(void) { (void)signal(SIGALRM, alarm_handler); } void rdSetRescanTimer(int secs) { rdRescanTimer = secs; if (old_alarm_handler == 0) { if ((old_alarm_handler = signal(SIGALRM, alarm_handler)) == SIG_ERR) { perror("signal"); rdRescanTimer = 0; return; } } alarm(rdRescanTimer); } void rdInclude(rdWin *w, char *str, size_t len) { size_t nlines = countlines(str, len); char *buf; char *prefix = "> "; size_t nlen, plen = strlen(prefix); ulong p0, p1; if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) return; nlen = len + nlines*plen + 1; buf = salloc(nlen); prefixlines(str, len, prefix, plen, buf); rpc_insert(wilyq, w->id, p1, buf); w->bodylen += nlen; free(buf); } static size_t countlines(char *str, size_t len) { size_t nlines = 0; while (len--) if (*str++ == '\n') nlines++; return nlines; } static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf) { while (len) { strncpy(buf,prefix,plen); buf += plen; while (len-- && (*buf++ = *str++) != '\n') ; } *buf = 0; } wily-0.13.41/tools/old/wilytoys/reader/reader.h100644 2743 200 2540 6057267626 17675 0ustar garypgrad/* * reader.h - declarations for a mail/news reader toolkit for wily. */ /* * We support two kinds of window - a list (mailboxes, newsgroups, subject lines) * and an article display. There can be more than one instance of each. */ typedef enum _rdWinType { rdList, rdArticle } rdWinType; /* * This makes the messages clearer */ enum { IsTag = 0, IsBody = 1 }; typedef struct _rdWin rdWin; typedef struct _rdItem rdItem; typedef struct _rdItemRange rdItemRange; typedef struct _Msgq Msgq; extern int rdMultiList; extern int rdMultiArt; struct _rdItem { ulong p0, p1; /* address of this item in the window. */ struct _rdItem *next; /* next item in the list */ }; struct _rdItemRange { int first, last; /* inclusive */ rdItem *i0, *i1; }; struct _rdWin { rdWinType wintype; int user; /* user info */ void *userp; /* ditto */ Id id; struct _rdWin *next; /* list storage */ char *title; /* what we think the title of this window is */ ulong taglen; /* length of tag, in characters */ ulong bodylen; /* length of body, in characters */ Msg *m; /* message from wily */ char *body; /* UTF text of an article window */ rdItem *items; /* The items in a list */ int protect; /* The user is writing to this window */ }; extern rdWin *windows; extern Mqueue *wilyq; extern Bool rdAlarmEvent; wily-0.13.41/tools/old/wilytoys/reader/utils.c100644 2743 200 452 6057267631 17542 0ustar garypgrad/* * general utilities... */ #include "headers.h" char * sstrdup(char *str) { char *s = salloc(strlen(str)+1); strcpy(s,str); return s; } void panic(const char *msg) { fprintf(stderr,"%s\n", msg); exit(1); } ulong atoul(char *str) { return strtoul((const char *)str, (char **)0, 10); } wily-0.13.41/tools/old/wilytoys/reader/Credits100644 2743 200 223 6057270733 17547 0ustar garypgradBjorn Helgaas change of FILENAME_MAX to MAXPATHLEN arnold@infographix.infographix.com (Arnold Robbins) Various suggestions. wily-0.13.41/tools/old/wilytoys/reader/solaris.c100644 2743 200 3640 6057267630 20077 0ustar garypgrad/* * solaris.c - the system-dependent routines for Solaris 2. */ #include "headers.h" #include "mbox.h" #include #include /* * load_mbox(mbox,rescan) - open the named file, and make it available * as a block of memory between mbox_start and mbox_end. If rescan * is true, we've already the mbox, and we want to see if there're more * messages in the file. */ int load_mbox(mMbox *mbox, int rescan) { const char *mode = mbox->readonly? "r" : "r+"; FILE *fp = fopen(mbox->name,mode); char *addr = 0; size_t len; struct stat st; if (fp == 0) goto broken; if (stat(mbox->name,&st) == -1) goto broken; if (rescan) { if (st.st_size < mbox->size) { fprintf(stderr,"%s corrupt\n", mbox->name); goto broken; } if (st.st_mtime == mbox->mtime) { fclose(fp); mbox->mbox_start = mbox->mbox_end = 0; return 0; } len = (size_t)(st.st_size - mbox->size); fseek(fp, mbox->size, SEEK_SET); } else len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; if ((addr = mb_alloc(len+1)) == 0) goto broken; addr[len] = 0; /* handy for debugging */ if (fread(addr, (size_t)1, len, fp) != len) goto broken; fclose(fp); mbox->mbox_start = addr; mbox->mbox_end = mbox->mbox_start + len; return 0; broken: if (addr) free(addr); fclose(fp); return 1; } /* we failed to load the mbox. Check that it exists, if we need it to. */ int empty_mbox(mMbox *box, const char *filename, int mustexist) { int readable = !access(filename, R_OK); int exists = !access(filename, F_OK); if (readable || (exists && !readable) || (mustexist && !exists)) { fprintf(stderr,"%s not %s\n",filename, readable? "read" : exists? "readable" : "found"); return 1; } /* file doesn't exist, but that's ok - it doesn't need to in this case, so create an empty mbox */ box->size = 0; box->mbox_start = box->mbox_end = 0; /* XXX - likely to flush out some bugs */ return 0; } wily-0.13.41/tools/old/wilytoys/reader/membuf.c100644 2743 200 5237 6056645342 17701 0ustar garypgrad/* * memory.c - custom memory handler for mail messages. * XXX - This handler does *not* return buffers aligned for * anything larger than a byte! */ #include "headers.h" #include #define MINBUF 512 /* limit for splitting */ static membuf *busy, *freed; static void *find_free(size_t len); /* * allocate a new buffer. */ void *mb_alloc(size_t len) { void *ptr; membuf *m; assert(len); if ((ptr = find_free(len))) return ptr; m = salloc(sizeof(*m)); m->len = len; m->start = salloc(len); m->end = m->start + len; m->next = busy; busy = m; return m->start; } /* * grab an existing buffer from the free list, if there is one * large enough. */ static void * find_free(size_t len) { membuf **pm = &freed; membuf **smallest = 0; membuf *m, *nm; for (;*pm; pm = &((*pm)->next)) if ((*pm)->len >= len && (!smallest || (*pm)->len < (*smallest)->len)) smallest = pm; if (smallest == 0) return 0; /* no buffer big enough */ m = *smallest; /* found one - big enough to split? */ if (m->len > len+MINBUF) { /* yep */ nm = salloc(sizeof(*nm)); nm->len = len; nm->start = m->start; nm->len = len; nm->end = (m->start += len); m->len -= len; nm->next = busy; busy = nm; return nm->start; } /* nope - remove this one from the free queue, and return it */ *smallest = m->next; m->next = busy; busy = m; return m->start; } /* * A previously allocated buffer contains more than one mail message. * break the buffer into two, at the point indicated. */ void mb_split(void *old, void *new) { membuf *m, *nm; size_t len; assert(old); assert(new); assert (old < new); len = (char *)new - (char *)old; for (m = busy; m; m = m->next) if (m->start == old) break; assert(m); assert(m->len >= len); if (m->len == len) return; nm = salloc(sizeof(*nm)); nm->len = m->len - len; nm->end = m->end; m->end = nm->start = new; nm->len = m->len - len; m->len = len; nm->next = m->next; m->next = nm; } /* * discard the memory buffer, by placing it on the free list. */ void mb_free(void *ptr) { membuf **m; membuf *p; assert(ptr); for (m = &busy; *m; m = &((*m)->next)) if ((*m)->start == ptr) break; assert(*m); p = *m; *m = p->next; /* remove from the busy list */ /* search the free list for an adjacent buffer. If we find one, combine the two. */ for (m = &freed; *m; m = &((*m)->next)) { if ((*m)->end == p->start) { (*m)->end = p->end; (*m)->len += p->len; free(p); return; } if ((*m)->start == p->end) { (*m)->start = p->start; (*m)->len += p->len; free(p); return; } } /* didn't find one - just append the new buffer onto the free list. */ *m = p; p->next = 0; return; } wily-0.13.41/tools/old/wilytoys/reader/membuf.h100644 2743 200 444 6056645162 17661 0ustar garypgrad/* * memory.h - defs for message memory handling. */ typedef struct _membuf membuf; struct _membuf { char *start, *end; /* end points to first byte after buffer */ size_t len; struct _membuf *next; }; void *mb_alloc(size_t); void mb_free(void *); void mb_split(void *old, void *new); wily-0.13.41/tools/old/wilytoys/reader/CHANGES100644 2743 200 1675 6057270433 17253 0ustar garypgrad0.1 -> 0.2 ======== Filters out most common garbage headers (toggle this with allheaders). Can delete/undelete/save multiple messages, by sweeping them. [Un]delete is a lot less effort on the screen updates. Commit now writes changes back to the mailbox, without quitting. Doesn't read in new mail, though. Rescan reads in any new mail that has arrived. Doesn't write any current changes, though. Rescans your mailbox for new mail automatically. Does this every 60 seconds, by default. You have to hack mail.h to change this... If you're running it in non-multiart mode (default), then it tries to avoid trashing your composition windows when you pull up a message window. savefile has a default parameter: $SAVEFILE if set, or $HOME/mbox otherwise. Sets the title of article windows to just mailboxname/msgnum, because the From: lines are too long. Uses MAXPATHLEN instead of FILENAME_MAX, because FILENAME_MAX is way too small on some machines. wily-0.13.41/tools/old/wilytoys/reader2/ 40755 2743 200 0 6125634422 16232 5ustar garypgradwily-0.13.41/tools/old/wilytoys/reader2/mail.c100444 2743 200 46775 6120766350 17457 0ustar garypgrad#include "mailheaders.h" static void build_msg_list(); static char *getarttext(mMsg *m); mWin *allocMWin(int kind, int num); void freeMWin(mWin *w); mWin *findMWin(void *ptr); int artDisplayed(int n); void mDelete(rdWin *w, int first, int last, char *arg); void mUndelete(rdWin *w, int first, int last, char *arg); void mComp(rdWin *w, int first, int last, char *arg); void mExit(rdWin *w, int first, int last, char *arg); void mQuit(rdWin *w, int first, int last, char *arg); void mReply(rdWin *w, int first, int last, char *arg); void mAbort(rdWin *w, int first, int last, char *arg); void mDeliver(rdWin *w, int first, int last, char *arg); void mSavefile(rdWin *w, int first, int last, char *arg); void mSave(rdWin *w, int first, int last, char *arg); void dodeliver(rdWin *w, char *filename); void mAllheaders(rdWin *w, int first, int last, char *arg); void mIncludeall(rdWin *w, int first, int last, char *arg); void mInclude(rdWin *w, int first, int last, char *arg); void doinclude(rdWin *w, int first, int last, char *arg, int all); void mCommit(rdWin *w, int first, int last, char *arg); void mRescan(rdWin *w, int first, int last, char *arg); void mNext(rdWin *w, int first, int last, char *arg); void mPrev(rdWin *w, int first, int last, char *arg); static void chkhdr(mString *s, int *len, int max, char **rest); mMbox *mbox; static char mboxname[MAXPATHLEN]; mWin *mwindows; mWin *listwin; rdWin *rdlistwin; static char **msgs; static char *savefile; static int multiart = 0; static int show_all_headers = 0; static int whichfrom = WHICHFROM; static char *list_tools = " delete undelete comp reply quit exit commit rescan savefile "; static char *art_tools = " next prev delete reply save inc "; static char *comp_tools = " deliver abort inc incall "; static char *version = "X-Mailer: Wilymail 0.4\n"; /* * These are headers that we'd rather not see when the message gets displayed. */ static char *hidden_hdrs[] = { "Content-Length", "Content-Transfer-Encoding", "Content-Type", "In-Reply-To", "Message-Id", "Mime-Version", "Original-Sender", "Received", "Sender", "Status", "X-Lines", "X-Mailer", "X-Newsreader" }; static int nhidden_hdrs = sizeof(hidden_hdrs)/sizeof(hidden_hdrs[0]); int main(int argc, char *argv[]) { mWin *mw; int ma = 0; int mustexist = 0; int timer = RESCAN_TIME; if (readerInit()) { fprintf(stderr,"readerInit() failed\n"); exit(1); } if ((rdlistwin = readerLoading(0, (void *)0, 0, "Wilymail")) == 0) { fprintf(stderr,"No list window\n"); exit(1); } fflush(stdout); if (argc >=2 && strcmp(argv[1], "-ma")==0) { ma = 1; argc--; argv++; } multiart = ma; if (argc >= 2) { mustexist = 1; strcpy(mboxname, argv[1]); timer = 0; /* don't rescan named mboxes */ } else { char *u = getenv("USER"); if (!u || !*u) { fprintf(stderr,"Need $USER to find mailbox name\n"); exit(1); } sprintf(mboxname,"%s/%s", SPOOLDIR, u); } assert(mboxname); DPRINT("mailbox name is..."); DPRINT(mboxname); savefile = getenv(SAVEFILE_ENV); if (!savefile || !*savefile) { char s[MAXPATHLEN]; char *h; if ((h = getenv("HOME")) == 0 || !*h) savefile = sstrdup("mbox"); /* what planet are we on? */ else { sprintf(s,"%s/mbox",h); savefile = sstrdup(s); } } else savefile = sstrdup(savefile); assert(savefile); DPRINT("savefile is..."); DPRINT(savefile); set_hdr_filter(nhidden_hdrs, hidden_hdrs); if ((mbox = read_mbox((const char *)mboxname, 0, mustexist)) == 0) { DPRINT("Failed to read mailbox"); perror(mboxname); exit(1); } mw = listwin = allocMWin(mMsgList, 0); assert(mw); build_msg_list(); if (setWinUser(rdlistwin, 0, (void *)mw) || setWinTitle(rdlistwin, mboxname) || setWinTools(rdlistwin, list_tools) || setWinList(rdlistwin, msgs)) { DPRINT("Failed to initialise reader"); exit(1); } rdSetRescanTimer(timer); readerMainLoop(); DPRINT("readerMainLoop() returned"); exit(0); } mWin * allocMWin(int kind, int num) { mWin *w = salloc(sizeof(*w)); mWin **p = &mwindows; assert(kind == mMsgList || kind == mDispArt || kind == mCompArt); assert(num >= -1); w->kind = kind; w->msg = (kind == mDispArt || kind == mCompArt)? num : -1; w->mbox = mbox; w->next = 0; while (*p) p = &((*p)->next); *p = w; return w; } void freeMWin(mWin *w) { mWin **p = &mwindows; assert(w); while (*p != w) p = &((*p)->next); *p = w->next; free(w); } mWin * findMWin(void *ptr) { mWin *mw = mwindows; assert(ptr); while (mw && (mWin *)ptr != mw) mw = mw->next; return mw; } static void chkhdr(mString *s, int *len, int max, char **rest) { int l; assert(len); assert(rest); *rest = ""; /* default */ if (s == 0) { *len = 0; return; } assert(s->s0 && s->s1); l = s->s1 - s->s0; if (l > max) { l = max; *rest = "..."; } else if (l > 0) l--; /* skip newline */ *len = l; } static void parsefrom(mString *s, char **from, int *len, char **rest) { char *email, *name, *str; int max; *rest = ""; *from = ""; *len = 0; if (s == 0) return; parseaddr(s->s0, s->s1-s->s0, &email, &name); str = (whichfrom == FROMEMAIL)? email : name; max = (whichfrom == FROMEMAIL)? MAXEMAIL : MAXFULLNAME; if (str == 0) return; *from = str; if ((*len = strlen(str)) > max) { *len = max; *rest = "..."; } return; } static void build_msg_list(void) { int n; mMsg *m; ulong l; int lfrom, ldate, lsubject; char *fromstr, *rfrom, *rdate, *rsubject; mString *from; mString *date; mString *subject; int dc; assert(mbox); assert(mbox->nmsgs >= 0); if (msgs) for (n = 0; msgs[n]; n++) free(msgs[n]); msgs = (char **)srealloc(msgs, (mbox->nmsgs+1) * sizeof(char *)); for (n = 0; n < mbox->nmsgs; n++) { m = mbox->msgs[n]; assert(m); dc = m->deleted? 'D' : ' '; from = m->from; date = m->date; subject = m->subject; parsefrom(from, &fromstr, &lfrom, &rfrom); chkhdr(date, &ldate, MAXDATE, &rdate); chkhdr(subject, &lsubject, MAXSUBJECT, &rsubject); l = lfrom + ldate + lsubject + 10; msgs[n] = salloc(l); sprintf(msgs[n],"%c%d %.*s%s %.*s%s", dc, n+1, lfrom, fromstr, rfrom, lsubject, subject->s0, rsubject); } msgs[n] = 0; return; } void user_listSelection(rdWin *w, rdItemRange range) { static char title[300]; /* XXX standard silly guess */ int n = range.first; mMsg *m = mbox->msgs[n]; mString *from = m->from; mWin *mw; char *text; assert(w); /* XXX not sure if this is right */ DPRINT("User selected an article"); if (artDisplayed(n)) { DPRINT("Article is already displayed"); return; } DPRINT("Displaying article"); if (w && w->wintype == rdList) w = 0; mw = allocMWin(mDispArt,n); sprintf(title," %s/%d", mbox->name, n+1); title[50] = 0; /* XXX - to make sure it's not too long. */ text = getarttext(m); assert(text); getArtWin(n, mw, title, art_tools, text, w); } static char * getarttext(mMsg *m) { static char *text; static size_t textlen; size_t len; mString *body; assert(m); body = &m->whole; len = body->s1 - body->s0; if (len >= textlen) { textlen = len + 1; text = srealloc(text, textlen); } if (show_all_headers) { memcpy(text, body->s0, len); text[len] = 0; } else { char *p = text; int n, l; mHdr *h; for (n = 0; n < m->nhdrs; n++) { h = m->hdrs[n]; if (h->hide) continue; l = h->value.s1 - h->name.s0; memcpy(p, h->name.s0, l); p += l; } *p++ = '\n'; /* make sure there's a separating line */ body = &m->body; len = body->s1 - body->s0; memcpy(p, body->s0, len); p[len] = 0; } return text; } int artDisplayed(int n) { rdWin *w; mWin *mw; assert(n >= 0); for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) if ((w = userpWin(mw))) { rdGotoWin(w); return 1; } return 0; } static struct mCmd mcmds[] = { { "quit", MCANY, MNOARG, mQuit }, { "exit", MCANY, MNOARG, mExit }, { "reply", MCNOTCOMP, MARG, mReply }, { "delete", MCNOTCOMP, MARG, mDelete }, { "undelete", MCMSGLIST, MARG, mUndelete }, { "comp", MCMSGLIST, MNOARG, mComp }, { "abort", MCCOMPART, MARG, mAbort }, { "deliver", MCCOMPART, MARG, mDeliver }, { "savefile", MCANY, MARG, mSavefile }, { "save", MCANY, MARG, mSave }, { "allheaders", MCANY, MARG, mAllheaders}, { "inc", MCCOMPART, MARG, mInclude}, { "incall", MCCOMPART, MARG, mIncludeall}, { "commit", MCANY, MNOARG, mCommit }, { "rescan", MCANY, MNOARG, mRescan }, { "next", MCANY, MNOARG, mNext }, { "prev", MCANY, MNOARG, mPrev }, { 0, 0, 0, 0 } }; void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange r, char *arg) { int c; assert(w); assert(cmd); DPRINT("User entered a command in a list window..."); DPRINT(cmd); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { DPRINT("Command is not recognised - reflecting"); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ if ((mcmds[c].context & MCMSGLIST) == 0) { fprintf(stderr,"%s: only valid within the message list\n", cmd); return; } /* check we've been given an appropriate argument */ if (mcmds[c].req == MARG && r.first == -1) { fprintf(stderr,"%s: needs a message\n", cmd); return; } DPRINT("Calling chosen function..."); (*mcmds[c].fn)(w, r.first, r.last, arg); DPRINT("Function complete"); return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; mWin *mw; unsigned short context; assert(w); assert(cmd); DPRINT("User entered a command in an article window..."); DPRINT(cmd); for (c = 0; mcmds[c].cmd; c++) if (strcmp(cmd, mcmds[c].cmd) == 0) break; if (mcmds[c].cmd == 0) { DPRINT("Command not recognised - reflecting"); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((mw = findMWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } context = (mw->kind == mDispArt)? MCDISPART : MCCOMPART; if ((mcmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } DPRINT("Calling selected function..."); (*mcmds[c].fn)(w, mw->msg, mw->msg, arg); DPRINT("Called function complete"); return; } void mDelete(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *ow; int n, i; rdWin *lp = userpWin(listwin); assert(w); assert(lp); assert(first >= 0 && last >= 0 && first <= last); DPRINT("Deleting articles"); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) { DPRINT("No mWin found for rdWin - aborting deletion"); return; } if (mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 1; *msgs[n] = 'D'; rdChangeItem(lp, n, msgs[n]); mw->mbox->ndel++; if (mw->kind != mDispArt) /* might be the msg list */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mDispArt && mw->msg == n) break; if (mw) { if ((ow = userpWin(mw))) { /* this msg is displayed; remove the pane */ DPRINT("Article has open window - closing"); closeWin(ow); } DPRINT("Article has allocated mWin - freeing"); freeMWin(mw); } } DPRINT("Articles deleted"); return; } void user_delWin(rdWin *w) { assert(w); DPRINT("Reader window was closed - freeing mWin"); freeMWin(findMWin(w->userp)); } void mUndelete(rdWin *w, int first, int last, char *arg) { mWin *mw; int n, i; rdWin *lp = userpWin(listwin); assert(w); assert(lp); DPRINT("Undeleting articles"); for (i = first; i <= last; i++) { n = i; if ((mw = findMWin(w->userp)) == 0) { DPRINT("nWin not found for window - aborting"); return; } if (!mw->mbox->msgs[n]->deleted) continue; mw->mbox->msgs[n]->deleted = 0; mw->mbox->ndel--; *msgs[n] = ' '; rdChangeItem(lp, n, msgs[n]); } DPRINT("Articles undeleted"); return; } void mReply(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Reply abort deliver "; static char body[300]; /* XXX */ mString *from = mbox->msgs[n]->from; mString *subject = mbox->msgs[n]->subject; int lfrom, lsubject; char *me = getenv("USER"); char *re = "Re: "; assert(w); assert(mw); assert(from); assert(subject); DPRINT("Replying to an article"); if (!me || !*me) { DPRINT("$USER is not valid - fill in from address yourself!"); me = ""; } lfrom = (from->s1 - from->s0); /* include newline */ lsubject = (subject->s1 - subject->s0); if (lsubject > 4 && strncmp(subject->s0, re, 4)==0) re = ""; sprintf(body,"From: %s\nTo: %.*sSubject: %s%.*s%s\n", me, lfrom, from->s0, re, lsubject, subject->s0, version); if (getArtWin(n, mw, title, comp_tools, body, 0)) { DPRINT("Could not get Reply window - leaving a mess in memory"); return; /* XXX - should clear up */ } DPRINT("Reply window ready"); return; } void mAbort(rdWin *w, int first, int last, char *arg) { mWin *mw; assert(w); assert(w->userp); DPRINT("Aborting reply/comp"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Can't find associated window - aborting abort"); return; } if (mw->kind != mCompArt) { DPRINT("Abort isn't applied to a composition window - ignoring"); return; } fprintf(stderr,"Message aborted\n"); closeWin(w); freeMWin(mw); DPRINT("Abort done"); return; } void mDeliver(rdWin *w, int first, int last, char *arg) { mWin *mw; char *filename = tmpnam((char *)0); assert(w); assert(w->userp); assert(filename); DPRINT("Delivering message"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Couldn't find associated composition window - aborting"); return; } if (mw->kind != mCompArt) { DPRINT("Deliver not applied to composition window - ignored"); return; } rdBodyToFile(w, filename); dodeliver(w,filename); DPRINT("Deliver done"); return; } void mQuit(rdWin *w, int first, int last, char *arg) { DPRINT("Quitting - first flushing mbox changes"); update_mbox(mbox); mExit(w, first, last, arg); } void mExit(rdWin *w, int first, int last, char *arg) { mWin *mw; rdWin *rw; DPRINT("Exiting - closing msg windows"); /* close msg windows first */ for (mw = mwindows; mw; mw = mw->next) if (mw->kind == mCompArt || mw->kind == mDispArt) { if ((rw = userpWin(mw))) closeWin(rw); else { DPRINT("Could not find rdWin for mWin while closing"); } } DPRINT("Closing list windows"); for (mw = mwindows; mw; mw = mw->next) if (mw->kind != mCompArt && mw->kind != mDispArt) { if ((rw = userpWin(mw))) closeWin(rw); else { DPRINT("Could not find rdWin for mWin while closing"); } } DPRINT("Managed to close everything without dying..."); exit(0); /* not actually needed - reader will exit for us */ } void mComp(rdWin *w, int first, int last, char *arg) { int n = first; /* last ignored */ mWin *mw = allocMWin(mCompArt, n); char *title = "Compose abort deliver "; static char body[300]; /* XXX */ char *me = getenv("USER"); assert(mw); DPRINT("Composing new article"); if (!me || !*me) { DPRINT("$USER isn't set - fill in From: field yourself!"); me = ""; } sprintf(body,"From: %s\nTo: \nSubject: \n%s\n", me, version); if (getArtWin(n, mw, title, comp_tools, body, 0)) { DPRINT("Couldn't get new composition window"); return; /* XXX - should clear up */ } DPRINT("Composition window open"); return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ mWin *mw; assert(w); assert(w->userp); assert(MTU && *MTU); assert(filename); DPRINT("Attempting to deliver an article"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Could not find mWin for this window - aborting"); return; } sprintf(cmd,"%s < %s", MTU, filename); DPRINT("Delivery command is...."); DPRINT(cmd); fflush(stdout); system(cmd); closeWin(w); freeMWin(mw); DPRINT("Seems to have delivered"); return; } void mSavefile(rdWin *w, int first, int last, char *arg) { assert(arg); if (savefile) { DPRINT("Savefile used to be...."); DPRINT(savefile); free(savefile); } savefile = sstrdup(arg); assert(savefile); DPRINT("Savefile now set to..."); DPRINT(savefile); } void mSave(rdWin *w, int first, int last, char *arg) { FILE *fp; mWin *mw; mMsg *m; mString *text; size_t len; int n; assert(w); assert(w->userp); assert(first >= 0); assert(first <= last); assert(last <= mbox->nmsgs); DPRINT("Saving articles"); if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); DPRINT("Could not open savefile - article not saved"); return; } if ((mw = findMWin(w->userp)) == 0) { DPRINT("could not find mWin for indicated rdWin - not saved"); return; } for (n = first; n <= last; n++) { m = mw->mbox->msgs[n]; assert(m); text = &m->whole; assert(text->s1 && text->s0); len = text->s1 - text->s0; if (fwrite(text->s0, (size_t)1, len, fp) != len) { DPRINT("Failed to write the file"); perror("fwrite"); } fputc('\n',fp); printf("Written message %d to %s\n", n+1, savefile); /* count from 1 */ } fflush(stdout); fclose(fp); } void mAllheaders(rdWin *w, int first, int last, char *arg) { show_all_headers = !show_all_headers; DPRINT(show_all_headers? "All headers now on" : "All headers now off"); } void mInclude(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,0); } void mIncludeall(rdWin *w, int first, int last, char *arg) { doinclude(w,first,last,arg,1); } void doinclude(rdWin *w, int first, int last, char *arg, int all) { mWin *mw; rdWin *ow; int msgnum; /* message we're going to include */ mMsg *m; mString *s; size_t len; int n; assert(w); assert(w->userp); assert(arg); DPRINT("Including article text"); if ((mw = findMWin(w->userp)) == 0) { DPRINT("Could not find mWin for rdWin - aborting"); return; } if (mw->kind != mCompArt) { DPRINT("Not a composition window - include ignored"); return; } msgnum = mw->msg; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) < 1) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum--; } } if (msgnum < 0 || msgnum >= mw->mbox->nmsgs) { fprintf(stderr,"Invalid msg number (1-%d)\n", mw->mbox->nmsgs); return; } m = mw->mbox->msgs[msgnum]; assert(m); s = all? &(m->whole) : &(m->body); assert(s && s->s0 && s->s1); len = s->s1 - s->s0; rdInclude(w, s->s0, len); DPRINT("Done include"); } void mCommit(rdWin *w, int first, int last, char *arg) { DPRINT("Doing commit - flushing any mailbox changes"); update_mbox(mbox); DPRINT("Commit - rebuilding message list"); build_msg_list(); DPRINT("Commit - redrawing message list"); setWinList(userpWin(listwin), msgs); DPRINT("Commit complete"); } void dorescan(void) { mRescan((rdWin *)0, 0, 0, (char *)0); } void mRescan(rdWin *w, int first, int last, char *arg) { rdWin *lp = userpWin(listwin); int n = mbox->nmsgs; assert(lp); DPRINT("Rescanning mailbox"); extend_mbox(mbox); if (n >= mbox->nmsgs) { DPRINT("No new messages (might be less, though...)"); return; } DPRINT("Rebuilding msg list"); build_msg_list(); DPRINT("Adding new messages to screen"); while (n < mbox->nmsgs) rdAddItem(lp, msgs[n++]); DPRINT("Rescan complete"); } static int nextArt(rdWin *w, int *num, int next, int first) { mWin *mw; int max = mbox->nmsgs-1; int n; assert(w); assert(w->userp); assert(num); mw = findMWin(w->userp); assert(mw); n = (mw->kind == mDispArt)? mw->msg : first; *num = n + (next? 1 : -1); return !((next && n < max) || (!next && n > 0)); } void mNext(rdWin *w, int first, int last, char *arg) { rdItemRange r; if (nextArt(w, &r.first, 1, first)) return; r.i0 = r.i1 = 0; user_listSelection(w, r); } void mPrev(rdWin *w, int first, int last, char *arg) { rdItemRange r; if (nextArt(w, &r.first, 0, first)) return; r.i0 = r.i1 = 0; user_listSelection(w, r); } wily-0.13.41/tools/old/wilytoys/reader2/getmsg.c100444 2743 200 1063 6120766350 17760 0ustar garypgrad/* * getmsg.c - handle message reception from wily. */ #include "headers.h" rdWin * getActiveWin(void) { rdWin *w; Msg *m; Id id; DPRINT("Waiting for next wily message"); while ((m = mq_next(wilyq, 0)) == 0) { if (rdAlarmEvent) { DPRINT("A rescan alarm occurred"); dorescan(); rdAlarmEvent = false; continue; } DPRINT("No message received from wily"); return 0; } id = msg_id(m); for (w = windows; w; w = w->next) if (id == w->id) { w->m = m; return w; } DPRINT("No window found matching message's Id"); return 0; } wily-0.13.41/tools/old/wilytoys/reader2/headers.h100444 2743 200 1307 6120766350 20113 0ustar garypgrad#ifndef RD_HEADERS_H #define RD_HEADERS_H #include #include #include #include #include #include #include #include #include #ifdef __STDC__ char *strdup(char *); #endif #include #include #include #include #include "reader.h" #include "proto.h" #ifdef DEBUG #define DPRINT(X) (void)fprintf(stderr,"%s:%d:%s\n",__FILE__,__LINE__,X) #else #define DPRINT(X) #endif #define MAXFROMLINE 512 #define MAXDATE 24 #define MAXEMAIL 40 #define MAXFULLNAME 40 #define MAXSUBJECT 40 #define FROMEMAIL 0 #define FROMNAME 1 #define WHICHFROM FROMNAME #endif /* RD_HEADERS_H */ wily-0.13.41/tools/old/wilytoys/reader2/mail.h100444 2743 200 3317 6120766350 17425 0ustar garypgrad/* * stuff needed for the mail client. * smk */ #ifndef MAIL_H #define MAIL_H #include "headers.h" #include "mbox.h" typedef struct _mWin mWin; /* * We know of several different kinds of window: mailbox lists, * message lists, displayed articles and messages being composed. */ enum { mMboxList, /* list of mailboxes */ mMsgList, /* list of msgs in a mailbox */ mDispArt, /* a displayed article within a mailbox */ mCompArt /* a new article being composed */ }; struct _mWin { int kind; /* what kind of window it is */ int msg; /* message number, if mDispArt, or mCompArt */ mMbox *mbox; /* the message box we're associated with */ struct _mWin *next; }; /* * These are the commands that the mailer recognises, and the * contexts that they are valid. */ #define MCMSGLIST 01 #define MCDISPART 02 #define MCCOMPART 04 #define MCNOTCOMP (MCMSGLIST|MCDISPART) #define MCANY (MCMSGLIST|MCDISPART|MCCOMPART) #define MNOARG 00 #define MARG 01 struct mCmd { char *cmd; unsigned short context; unsigned short req; void (*fn)(rdWin *, int, int, char *); /* pane, first msg, last msg, arg */ }; /* * The following must be the pathname of a program capable * of taking a complete message on stdin, with no arguments, * and delivering it. */ #define MTU "/usr/lib/sendmail -t" /* * Where do you keep your mail? Don't currently support anything other * than directly-accessible mail files.... */ #define SPOOLDIR "/var/mail" /* * How long we wait before rescanning. */ #define RESCAN_TIME 60 /* * Environment variable and default filename for savefile's * default parameter. */ #define SAVEFILE_ENV "SAVEFILE" #define SAVEFILE_DEF "mbox" /* in $HOME, if possible */ #endif /* ! MAIL_H */ wily-0.13.41/tools/old/wilytoys/reader2/mbox.c100444 2743 200 24774 6120766351 17476 0ustar garypgrad/* * mbox.c */ #include "mailheaders.h" #include #include #define COPYSIZE 8192 #define INCR 10 static mMbox *currmbox; /* current mbox being processed */ static mMsg *msg; /* current message */ static int nhdrs; /* number of current headers read so far. */ static int ahdrs; /* number of allocated hhdrs */ static mHdr **hdrs; /* current list */ static char **hiddenhdrs; /* names of header fields we don't want to see */ static int nhiddenhdrs; extern int load_mbox(mMbox *, int); static char *readhdrs(char *ptr); static void mkhdr(char *s0, char *s1); static void checkhide(mHdr *h); static int freehdrlist(int n, char **h); static void newmsg(char *s0); static char *readmsg(char *ptr); static int same(mString a, mString b); static int strsame(char *s, mString b); static void fillmsg(mMsg *msg); static void fillhdr(char *name, mMsg *msg, mString **ptr); static ulong getlength(void); static char *findend(char *ptr); static void freemsg(mMbox *mbox, int n); /* * readhdrs(ptr) - read the headers in a message, looking for * the terminating newline. Returns pointer to first char in body. */ static char * readhdrs(char *ptr) { char *nptr = ptr; assert(nptr); /* invariant is that nptr pts to first char of next header. when it doesn't (nptr==\n), we've reached the blank line at then end of the hdrs */ while (*nptr != '\n') { if ((nptr = strchr(nptr,'\n')) == 0) panic("No newlines in readhrds()"); if (nptr[1]==' ' || nptr[1]=='\t') { /* multi-line hdr */ nptr++; continue; } else { mkhdr(ptr, ++nptr); ptr = nptr; continue; } } assert(*nptr == '\n'); assert(nptr[1]); return ++nptr; /* skip blank line */ } /* * mkhdr(s0,s1) - add a new header to the current list. */ static void mkhdr(char *s0, char *s1) { size_t l; char *c = strchr(s0, ':'); mHdr *h; assert(s0); assert(s1); assert(c); if (c == 0) panic("no colon in hdr"); if (nhdrs >= ahdrs) { ahdrs += INCR; l = ahdrs * sizeof(*hdrs); hdrs = (mHdr **)(hdrs? realloc(hdrs,l) : malloc(l)); if (hdrs == 0) panic("resizing hdr list"); } h = hdrs[nhdrs++] = (mHdr *)malloc(sizeof(*h)); if (h == 0) panic("adding new hdr"); h->name.s0 = s0; h->name.s1 = c++; while (*c == ' ' || *c == '\t') c++; h->value.s0 = c; h->value.s1 = s1; checkhide(h); } static void checkhide(mHdr *h) { int n; int l; assert(h); assert(h->name.s0 && h->name.s1); l = h->name.s1 - h->name.s0; for (n = 0; n < nhiddenhdrs; n++) if (strncmp(hiddenhdrs[n], h->name.s0, l) == 0) { h->hide = 1; return; } h->hide = 0; /* default to showing header */ } int set_hdr_filter(int nhdrs, char **hdrs) { int n; assert(nhdrs >= 0); assert(hdrs); (void)freehdrlist(nhiddenhdrs, hiddenhdrs); /* clear out existing list */ if ((hiddenhdrs = (char **)realloc((void *)hiddenhdrs, (nhdrs+1)*sizeof(char *))) == 0) { DPRINT("Failed to allocate new hidden hdr list"); return 1; } for (n = 0; n < nhdrs; n++) { assert(hdrs[n]); if ((hiddenhdrs[n] = strdup(hdrs[n])) == 0) { DPRINT("Failed to copy hidden hdr item"); return freehdrlist(n, hiddenhdrs); } } hiddenhdrs[n] = 0; nhiddenhdrs = n; return 0; } static int freehdrlist(int n, char **h) { while (n--) free (*h++); return 1; } static void newmsg(char *s0) { size_t n; assert(s0); DPRINT("Adding new message"); if (currmbox->nmsgs >= currmbox->amsgs) { currmbox->amsgs += INCR; n = currmbox->amsgs*sizeof(*currmbox->msgs); currmbox->msgs = (mMsg **)(currmbox->msgs? realloc(currmbox->msgs,n) : malloc(n)); if (currmbox->msgs == 0) panic("newmsg msg"); } msg = currmbox->msgs[currmbox->nmsgs++] = (mMsg *)malloc(sizeof(*msg)); if (msg == 0) panic("adding new msg"); memset(msg,0,sizeof(*msg)); msg->whole.s0 = s0; if ((hdrs = (mHdr **)malloc((ahdrs = INCR)*sizeof(*hdrs)))==0) panic("newmsg hdrs"); nhdrs = 0; } /* * readmsg(ptr) - read a complete message. Assumes we're already pointing * to the F of the "From " */ static char * readmsg(char *ptr) { char *nptr; ulong contentlength; assert(ptr); assert(strncmp(ptr,"From ",5) == 0); newmsg(ptr); /* resets nhdrs and hdrs, too */ if ((nptr = strchr(ptr,'\n')) == 0) /* skip From line */ panic("From line broken"); nptr = readhdrs(nptr+1); assert(nptr); assert(hdrs); msg->nhdrs = nhdrs; msg->hdrs = hdrs; msg->body.s0 = nptr; if ((contentlength = getlength()) == 0) nptr = findend(nptr); else nptr += contentlength; assert(nptr); msg->whole.s1 = msg->body.s1 = nptr; fillmsg(msg); /* update from,date,subject fields */ mb_split(ptr, ++nptr); return nptr; } static int same(mString a, mString b) { assert(a.s0 && a.s1 && b.s0 && b.s1); if ((a.s1 - a.s0) != (b.s1 - b.s0)) return 0; return (strncmp(a.s0,b.s0,a.s1-a.s0) == 0); } static int strsame(char *s, mString b) { mString a; assert(s && b.s0 && b.s1); a.s0 = s; a.s1 = s + strlen(s); return same(a,b); } static void fillmsg(mMsg *msg) { assert(msg); fillhdr("From",msg,&msg->from); fillhdr("Date",msg,&msg->date); fillhdr("Subject",msg,&msg->subject); } static void fillhdr(char *name, mMsg *msg, mString **ptr) { int x; static mString empty; assert(name); assert(msg); assert(ptr); for (x = 0; x < msg->nhdrs; x++) if (strsame(name,msg->hdrs[x]->name)) { *ptr = &(msg->hdrs[x]->value); assert((*ptr)->s0 && (*ptr)->s1); return; } /* Sigh. This sort of thing is very irritating. */ empty.s0 = empty.s1 = msg->whole.s1; *ptr = ∅ /* (void)fprintf(stderr,"Message does not have a '%s' header\n",name); */ } static ulong getlength(void) { int x; ulong l; for (x = 0; x < nhdrs; x++) if (strsame("Content-Length",hdrs[x]->name)) goto found; return 0; found: /* use sscanf magic to skip whitespace, and stop at end */ if (sscanf(hdrs[x]->value.s0,"%lu",&l) != 1 || l==0) return 0; if ((msg->body.s0+l+1) == currmbox->mbox_end) return l; /* spot on */ if ((msg->body.s0+l+5) >= currmbox->mbox_end) { DPRINT("WARNING: Content-Length: field points to past end of box"); return 0; /* too long */ } if (strncmp("\nFrom ",(msg->body.s0+l),6) == 0) return l; else { DPRINT("WARNING: Content-Length field doesn't find start of next msg"); return 0; } } static char * findend(char *ptr) { assert(ptr); for (; ptr+5 <= currmbox->mbox_end && strncmp("\nFrom ",ptr,6); ptr++) if ((ptr = strchr(ptr,'\n')) == 0) panic("findend"); if (ptr+5 > currmbox->mbox_end) return currmbox->mbox_end-1; else return ptr; } mMbox * read_mbox(const char *filename, int readonly, int mustexist) { char *ptr; extern int empty_mbox(mMbox *box, const char *filename, int mustexist); assert(filename); DPRINT("Reading file called..."); DPRINT(filename); DPRINT(readonly? "(readonly mode)" : "(writable)"); DPRINT(mustexist? "(must exist)" : "(normal mbox)"); if ((currmbox = (mMbox *)malloc(sizeof(*currmbox))) == 0) { DPRINT("Could not allocate mbox structure"); return 0; } memset(currmbox,0,sizeof(*currmbox)); currmbox->readonly = readonly; if ((currmbox->name = strdup((char *)filename)) == 0) { DPRINT("Could not copy filename"); goto panic2; } if (load_mbox(currmbox, 0) && empty_mbox(currmbox, filename, mustexist)) { DPRINT("mbox failed to load"); goto panic1; } for (ptr = currmbox->mbox_start; ptr < currmbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) { DPRINT("Failed to read a message - aborting mbox read"); goto panic1; } DPRINT("mbox read successfully"); return currmbox; panic1: free(currmbox->name); panic2: free(currmbox); return 0; } int extend_mbox(mMbox *mbox) { char *ptr; assert(mbox); DPRINT("Extending mbox"); if (load_mbox(mbox,1)) { DPRINT("Failed to read mbox"); return 1; } for (ptr = mbox->mbox_start; ptr < mbox->mbox_end; ) if ((ptr = readmsg(ptr)) == 0) { DPRINT("Failed to read message"); return 1; } DPRINT("mbox extended ok"); return 0; } /* * update_mbox(mbox) - write any changes back to the file. */ int update_mbox(mMbox *mbox) { static char lockname[MAXPATHLEN+1], newname[MAXPATHLEN+1]; int ntries, maxtries = 10; int fd, fd2; int x; struct stat st; int r = 0; int l; mMsg *m; assert(mbox); assert(mbox->name); assert(strlen(mbox->name)+5 < MAXPATHLEN); DPRINT("Updating mbox"); if (mbox->readonly || mbox->ndel == 0) { DPRINT(mbox->readonly? "mbox is readonly - not written" : "No changes"); return 0; } (void)sprintf(lockname,"%s.lock",mbox->name); (void)sprintf(newname,"%s.new",mbox->name); for (ntries = 0; ntries < maxtries; ntries++) { if (link(mbox->name,lockname) == 0) goto locked; DPRINT("Could not get lock - sleeping"); sleep(1); } (void)fprintf(stderr,"Could not get lockfile %s - skipping update\n", lockname); return 1; locked: DPRINT("Mailbox now locked"); if (stat(mbox->name,&st) == -1) { DPRINT("mailbox has vanished"); goto broken; } if (st.st_size < mbox->size) { fprintf(stderr,"Mail file corrupted - no changes made\n"); goto broken; } if ((fd = open(newname,O_RDWR|O_CREAT|O_TRUNC,st.st_mode)) < 0) { DPRINT("Could not open or fchmod new file..."); DPRINT(newname); goto broken; } DPRINT("Writing messages to new file"); for (x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) continue; l = m->whole.s1 - m->whole.s0 + 1; if (write(fd,m->whole.s0,l) != l || write(fd,"\n",1) != 1) { fprintf(stderr,"write truncated, changes aborted\n"); goto broken; } } DPRINT("Messages written"); if (st.st_size > mbox->size) { static char buf[COPYSIZE]; DPRINT("mbox has grown since last read - copying new msgs"); if ((fd2 = open(mbox->name,O_RDONLY)) < 0 || lseek(fd2,mbox->size,SEEK_SET) == -1) { fprintf(stderr,"Can't open mbox for update!\n"); goto broken; } while ((l = read(fd2,buf,COPYSIZE)) > 0) if (write(fd,buf,l) != l) { fprintf(stderr,"Can't copy updated mbox\n"); close(fd2); goto broken; } close(fd2); DPRINT("New msgs copied"); } DPRINT("Replacing old mbox with new mbox"); assert(rename(newname,mbox->name) == 0); assert(stat(mbox->name, &st) == 0); mbox->mtime = st.st_mtime; mbox->size = st.st_size; goto unlock; broken: r = 1; if (fd >= 0) close(fd); unlink(newname); unlock: DPRINT("Unlocking mbox"); unlink(lockname); /* now update the list of messages in the mbox */ for (l = x = 0; x < mbox->nmsgs; x++) { m = mbox->msgs[x]; if (m->deleted) freemsg(mbox,x); else mbox->msgs[l++] = m; } mbox->nmsgs = l; mbox->ndel = 0; DPRINT("Update complete"); return r; } static void freemsg(mMbox *mbox, int n) { mMsg *m = mbox->msgs[n]; int h; mbox->msgs[n] = 0; for (h = 0; h < m->nhdrs; h++) free(m->hdrs[h]); free(m->hdrs); mb_free(m->whole.s0); free(m); } wily-0.13.41/tools/old/wilytoys/reader2/mbox.h100444 2743 200 3460 6120766351 17450 0ustar garypgrad/* * mbox.h - definitions for mailbox-handling library. */ #ifndef MBOX_H #define MBOX_H #include typedef struct mstring mString; typedef struct mhdr mHdr; typedef struct mmsg mMsg; typedef struct mhdrline mHdrLine; typedef struct mmbox mMbox; struct mstring { /* can include several \n characters */ char *s0; /* first char in string */ char *s1; /* char after last newline */ }; struct mhdr { /* includes ws if hdr is multiple lines */ mString name; /* s1 points to colon */ mString value; /* s0 pts to first non-ws, s1 to after \n */ int hide; /* don't display if true */ }; /* name,s0,value.s2 gives whole header */ struct mmsg { int nhdrs; /* number of headers */ mHdr **hdrs; /* headers themselves */ mString *from; /* points to value fields from mHdrs */ mString *date; mString *subject; mString whole; /* All of the message (headers and body) */ mString body; /* All of the body (not including first blank line) */ int deleted; /* marked for deletion */ int read; /* if has been read */ ulong pos; /* origin in window, if it's been read before. */ }; struct mhdrline { char *s0,*s1; /* buffer containing accumulated text */ ulong p0, p1; /* positions in hdrw for this piece of text */ }; struct mmbox { char *mbox_start; /* area of memory that the mailbox is */ char *mbox_end; /* loaded into */ int nmsgs; /* number of messages */ int amsgs; /* size of msgs array */ mMsg **msgs; /* the messages themselves */ int ndel; /* number of deleted messages */ int readonly; time_t mtime; /* time it was last modified */ off_t size; /* how big it was, last time we checked */ char *name; /* the filename */ }; mMbox *read_mbox(const char *filename, int readonly, int mustexist); int extend_mbox(mMbox *mbox); int set_hdr_filter(int nhdrs, char **hdrs); #endif /* ! MBOX_H */ wily-0.13.41/tools/old/wilytoys/reader2/README100444 2743 200 20677 6120766351 17243 0ustar garypgradThe mail and news reader software is for wily 0.98. I haven't got around to converting them to use the 1.0 beta, because I *use* them, and Gary thinks the beta isn't ready for daily use yet. MAIL READER USAGE Invoke with "mreader mailboxname". The "-ma" option of the previous version is still there, but it doesn't do anything. This is explained below. First window to appear is the list window. It shows all the articles from the given mailfile, one per line. The line contains the From and Subject fields, but it might be chopped to make things look nicer. You open an article by B3'ing on its subject line. What else? Commands supported: exit exit without doing anything to the mailfile. quit save any changes to the mailfile before quitting. delete delete the selected article. "selected" means the article which has dot in its subject line. This means you can click on the subject line with either B1 or B3, and then click on delete. If you sweep more than one subject line, then all the affected articles are deleted. Of course, if you click on delete within an article window, that article is the one that is deleted. Delete doesn't actually do anything except mark the article for deletion, and puts a "D" before at the start of the subject line. undelete reverses delete. comp compose a new message. You get a blank article window with From, To and Subject fields. Don't delete them. reply Reply to the article (I recommend that you only use this from within a particular article). The To field is filled in from the From field. You can use "inc" or "incall" to include the text of the article you're replying to. abort junk a comp/reply article without sending it. deliver post a complete comp/reply article (well, feed it to your mail agent). next Display the next message in the current window. prev Display the previous message in the current window. savefile sets the name of the file that "save" writes to. save appends the current message into the savefile. Creates the file if it doesn't exist. You can also sweep several articles in the list window, then click on save (in the list window), and it'll save all of them. allheaders toggles whether all header fields are displayed. By default, a particular set are suppressed (the set is in the array hidden_hdrs[] in mail.c). inc [n] Includes a message body into the current position of the current message. If you specify a message number, it'll include that message. incall Same as inc, but will include the headers of the message, too. commit Write changes back to the mailbox, but don't actually quit. rescan Load any new mail that has arrived. Doesn't write any changes done so far, though. Window Control The "multiart" mode in the last version didn't really work too well. I've adopted a compromise that fits with the way I read mail, and which may not work for you. Here's what happens: - When you B3 on an article's entry in the list, a window is opened for the article, unless there's already a window open and displaying that article, in which case you warp to it. - next and prev operate only in article windows, and replace the current window's contents with the next/previous message - composition articles (comp, reply) are always created from scratch, and exist until you explicitly close them with one of deliver, abort, quit, exit or Del. Configuration headers.h contains a few defines that you can twiddle - the maximum length of the sender and subject details can be set here, and you can also define whether the list shows the sender's email address or full name. The parsing of From lines is fairly broken, but it'll do for now. mail.c contains the hidden_hdrs[] array, which you can alter if you don't like the default set of displayed headers. mail.h defines MTU, which is your mail transfer utility. This has to be capable of accepting a fully-formed message on stdin, without needing to be told destination addresses on the command line. It also defines the directory where your mail files are, and the number of seconds it waits before rescanning the mailbox for changes. You can also set the name of the environmental variable you use to specify the default file to save messages to. Bugs Probably vast numbers of them... Ones I know about are.: Unlike most wily windows, it current has the tools *before* the window label. This is because of the broken tags problem. Right now, I'm cheating, and inserting the tools at the start of the tag, instead of the end - that seems to work... In one case, I have seen the mailer *LOSE* incoming mail. I use Faces to announce incoming mail, but a commit after the mail arrived didn't display it. I haven't been able to reproduce this, but be warned... If you have '.' in the message body, it's not escaped before the body is sent to sendmail, so that terminates the message. If you delete windows, view a deleted message, and then do a commit, the article window remains open. Since we're renaming the mailbox, instead of overwriting it, it's losing its original mode/group. Searching actions are not reflected back to wily correctly at the moment, so B3'ing within any of the reader windows won't work. Instead, select some text and B2B1 on Look. Next and Prev don't change the highlighting of the selected article in the list window. I couldn't get wily to do this without warping the cursor to the new highlighting, and that's *really* irritating, so I opted for the more comfortable, broken approach. Wily doesn't maintain the edit history when the window is owned by a client. NEWS READER USAGE Started with "nreader". This is an NNTP-only reader, I'm afraid. Those of you with local spool disks and no NNTP reader will have to hash up some scripts to browse the spool directory. It uses $NNTPSERVER to determine the server host name, and by default this is "news". I rely on the server supporting the XHDR extension. Innd does, and so does the "reference" implementation. The reader currently uses .testnewsrc, rather than .newsrc, because you might not want to blow away your news readership just because you want to try out some new software. The reader doesn't add or remove groups, or handle subscribing, etc. It just updates which articles you've read. The reader gives some feedback as it first queries the server for new article counts, and then displays a list of groups and articles. B3'ing on a group displays a list of articles, just like in the mail reader. B3'ing on an article's subject line brings up the article. Window control is mostly the same, except: - next/prev will walk off the end of one group, and onto the next. In addition to updating the article displayed in the current window, it also updates the list of articles in the group window. If you've got more than one list window open on the group, it might update the wrong one. Sorry. - catchup marks all articles in the group as read, and then moves to the next group. Closes all displayed-article windows for that group too. - There are followup and follrep commands as well as reply, and there's a post command instead of "comp". Behaviour is basically obvious, and follrep posts a followup and emails a reply at the same time. - there are markread and markunread commands, if this is important to you. - quit updates your .testnewsrc, but exit doesn't. It doesn't checkpoint the .testnewsrc at any point, right now. Configuration You can change the From display stuff, in headers.h. There isn't a list of restricted headers here, though. news.h needs your mailer defining again. FROMENV is the name of the environment variable which contains your full, real, email address. This is a bit of an abuse hole, but I can't be bothered to work out what it should be (it's a real pain getting *mine* from my surroundings...). LOADDISP is handy for feedback. If you've got an enormous amount of groups to check, this helps you stop panicking. If non-zero, then for every LOADDISP groups the server is queried about, the group's name is displayed in the main window. (note: unsubscribed groups are ignored in this count). Bugs Well, I've only just started using the newsreader, so it's bound to be bad. Really needs killfile support. Doesn't understand cross-posting concepts at all, so you read the same article twice. Sorry. I've managed to kill wily with "estart failed" at one point - probably out of fds... If you open article x, hit next a few times, and then reply, followup, etc, if you do "inc", you get article x, not the one you want to reply to. wily-0.13.41/tools/old/wilytoys/reader2/Makefile100600 2743 200 2052 6120766771 17766 0ustar garypgradW = /home/steve/src/9/orig/wily-0.9.8 O = /home/steve/src/9/orig/orig-0.9.8 # CC = /opt/CenterLine/bin/proof cc CFLAGS = -Xc -g -DUSE_SELECT #-DDEBUG CPPFLAGS = -I. -I$W/include -I$W LDFLAGS = -L$W/libmsg -L$W/libXg LDLIBS = -lmsg -lXg -lnsl -lsocket PATCHES = includepatches libmsgpatches wilypatches winpatches # You might not have all of the PROGs listed here - don't worry about # it - they're not ready yet, and it just means that I've forgotten to # strip them from the Makefile before shipping... PROGS = mreader nreader COBJS = getmsg.o reader.o utils.o addr.o MOBJS = mail.o membuf.o mbox.o solaris.o NOBJS = news.o nntp.o newsrc.o post.o all: $(PROGS) mreader: $(COBJS) $(MOBJS) $(LINK.c) -o $@ $(COBJS) $(MOBJS) $(LDLIBS) nreader: $(COBJS) $(NOBJS) $(LINK.c) -o $@ $(COBJS) $(NOBJS) $(LDLIBS) clean: $(RM) *.o core nuke: $(RM) *.o core $(PROGS) cleanpatches: $(RM) $(PATCHES) patches: $(PATCHES) includepatches: makepatch include > $@ libmsgpatches: makepatch libmsg > $@ wilypatches: makepatch wily > $@ winpatches: makepatch win > $@ wily-0.13.41/tools/old/wilytoys/reader2/membuf.c100444 2743 200 5261 6120766351 17752 0ustar garypgrad/* * membuf.c - custom memory handler for mail messages. * XXX - This handler does *not* return buffers aligned for * anything larger than a byte! */ #include "mailheaders.h" #include #define MINBUF 512 /* limit for splitting */ static membuf *busy, *freed; static void *find_free(size_t len); /* * allocate a new buffer. */ void *mb_alloc(size_t len) { void *ptr; membuf *m; assert(len); if ((ptr = find_free(len))) return ptr; m = salloc(sizeof(*m)); m->len = len; m->start = salloc(len); m->end = m->start + len; m->next = busy; busy = m; return m->start; } /* * grab an existing buffer from the free list, if there is one * large enough. */ static void * find_free(size_t len) { membuf **pm = &freed; membuf **smallest = 0; membuf *m, *nm; assert(len); for (;*pm; pm = &((*pm)->next)) if ((*pm)->len >= len && (!smallest || (*pm)->len < (*smallest)->len)) smallest = pm; if (smallest == 0) return 0; /* no buffer big enough */ m = *smallest; /* found one - big enough to split? */ if (m->len > len+MINBUF) { /* yep */ nm = salloc(sizeof(*nm)); nm->len = len; nm->start = m->start; nm->len = len; nm->end = (m->start += len); m->len -= len; nm->next = busy; busy = nm; return nm->start; } /* nope - remove this one from the free queue, and return it */ *smallest = m->next; m->next = busy; busy = m; return m->start; } /* * A previously allocated buffer contains more than one mail message. * break the buffer into two, at the point indicated. */ void mb_split(void *old, void *new) { membuf *m, *nm; size_t len; assert(old); assert(new); assert (old < new); len = (char *)new - (char *)old; for (m = busy; m; m = m->next) if (m->start == old) break; assert(m); assert(m->len >= len); if (m->len == len) return; nm = salloc(sizeof(*nm)); nm->len = m->len - len; nm->end = m->end; m->end = nm->start = new; nm->len = m->len - len; m->len = len; nm->next = m->next; m->next = nm; } /* * discard the memory buffer, by placing it on the free list. */ void mb_free(void *ptr) { membuf **m; membuf *p; assert(ptr); for (m = &busy; *m; m = &((*m)->next)) if ((*m)->start == ptr) break; assert(*m); p = *m; *m = p->next; /* remove from the busy list */ /* search the free list for an adjacent buffer. If we find one, combine the two. */ for (m = &freed; *m; m = &((*m)->next)) { if ((*m)->end == p->start) { (*m)->end = p->end; (*m)->len += p->len; free(p); return; } if ((*m)->start == p->end) { (*m)->start = p->start; (*m)->len += p->len; free(p); return; } } /* didn't find one - just append the new buffer onto the free list. */ *m = p; p->next = 0; return; } wily-0.13.41/tools/old/wilytoys/reader2/membuf.h100444 2743 200 537 6120766351 17740 0ustar garypgrad/* * memory.h - defs for message memory handling. */ #ifndef MEMBUF_H #define MEMBUF_H typedef struct _membuf membuf; struct _membuf { char *start, *end; /* end points to first byte after buffer */ size_t len; struct _membuf *next; }; void *mb_alloc(size_t); void mb_free(void *); void mb_split(void *old, void *new); #endif /* !MEMBUF_H */ wily-0.13.41/tools/old/wilytoys/reader2/news.c100444 2743 200 41041 6120766352 17470 0ustar garypgrad/* * Simplistic driver for an NNTP news client for wily. */ #include "newsheaders.h" #define MAXFROMLEN MAXEMAIL #define MAXSUBJLEN MAXSUBJECT static int getGroupInfo(void); static void countUnread(nGroup *g); static int getGroupListItems(void); static int groupItems(nGroup *g); static void freeGroupItems(nGroup *g); static int getLen(char *str, unsigned int max); static void selectGroup(nWin *nw, rdWin *rdw, int item); static void selectArticle(nWin *nw, rdWin *rdw, int item); static void markread(nArticle *a, int read); static void nQuit(rdWin *w, nGroup *g, int first, int last, char *arg); static void nExit(rdWin *w, nGroup *g, int first, int last, char *arg); static void nNext(rdWin *w, nGroup *g, int first, int last, char *arg); static void nPrev(rdWin *w, nGroup *g, int first, int last, char *arg); static void nArtMarkRead(rdWin *w, nGroup *g, int first, int last, char *arg); static void nArtMarkUnread(rdWin *w, nGroup *g, int first, int last, char *arg); static void nCatchup(rdWin *w, nGroup *g, int first, int last, char *arg); static void markartsread(nGroup *g, int first, int last, int read); static int nextGroup(rdWin *w, int next, int *num); static nGroup *itemToGroup(int item); static void displayGroupList(nGroup *g, nWin *newnw, rdWin *newrdw); static void displayArticle(rdWin *w, nGroup *g, int i); static char **grouplistitems; static nGroup **grpptrs; static nGroup *groups; static int ngroups; static nWin *listwin; static rdWin *rdlistwin; static nWin *nwindows; static int whichfrom = WHICHFROM; static char *grouplist_tools = " next quit post exit "; static char *artlist_tools = " next prev catchup post "; static char *artdisp_tools = " next prev followup reply follrep save "; static struct nCmd ncmds[] = { { "quit", NCANY, NNOARG, nQuit }, { "exit", NCANY, NNOARG, nExit }, { "next", NCDISPART, NNOARG, nNext }, { "prev", NCDISPART, NNOARG, nPrev }, { "markread", NCMSGLIST, NNOARG, nArtMarkRead }, { "markunread", NCMSGLIST, NNOARG, nArtMarkUnread }, { "catchup", NCMSGLIST, NNOARG, nCatchup }, { "reply", NCDISPART, NNOARG, nReply }, { "post", NCANY, NNOARG, nPost }, { "followup", NCDISPART, NNOARG, nFollowUp }, { "follrep", NCDISPART, NNOARG, nFollRep }, { "savefile", NCANY, NARG, nSavefile }, { "save", NCDISPART, NNOARG, nSave }, { "deliver", NCCOMPART, NNOARG, nDeliver }, { "abort", NCCOMPART, NNOARG, nAbort }, { "inc", NCCOMPART, NNOARG, nInclude }, { "incall", NCCOMPART, NNOARG, nIncludeall }, { 0, 0, 0, 0 }, }; int main(int argc, char *argv[]) { nWin *nw; if (readerInit() || (rdlistwin = readerLoading(0,(void *)0, 0, "News")) == 0) { fprintf(stderr,"Could not initialise reader\n"); exit(1); } if ((groups = read_newsrc()) == 0) { fprintf(stderr,"Couldn't read .newsrc\n"); return 1; } unlock_newsrc(); if (nntpConnect()) { fprintf(stderr,"Could not connect to news server\n"); return 1; } if (getGroupInfo()) { fprintf(stderr,"Could not get group information\n"); return 1; } if (getGroupListItems()) return 1; DPRINT("Initialising news reader"); nw = listwin = allocNWin(nGroupList,0,0); if (setWinUser(rdlistwin, 0, (void *)nw) || setWinTitle(rdlistwin, "News") || setWinTools(rdlistwin, grouplist_tools) || setWinList(rdlistwin, grouplistitems)) { DPRINT("Could not start up main list window"); exit(1); } DPRINT("Entering main loop"); readerMainLoop(); DPRINT("Main loop exited!"); nntpQuit(); return 0; } /* * Find out how many articles there are in each group that we haven't read. */ static int getGroupInfo(void) { nGroup *g; int x = 0; (void)rdAddItem(rdlistwin, "Scanning..."); for (g = groups; g; g = g->next) { if (!g->issub || nntpSetGroup(g) || g->last==0 || (g->last < g->first)) g->first = g->last = g->nunread = 0; else countUnread(g); if (LOADDISP && g->issub && x-- == 0) { (void)rdChangeItem(rdlistwin, 0, g->name); x = LOADDISP; } } fputc('\n',stderr); return 0; } static void countUnread(nGroup *g) { int f, l, p0 = 0, p1 = 0, p2 = 0; nRange *r; assert(g); f = g->first; l = g->last; for (r = g->read; r; r = r->next) if (f <= r->n0 && r->n1 <= l) p1 += r->n1 - r->n0 + 1; else if (r->n0 <= f && f <= r->n1) p0 = r->n1 - f + 1; else if (r->n0 <= l && l <= r->n1) p2 = l - r->n0 + 1; g->nunread = (l - f + 1) - (p0 + p1 + p2); if (g->nunread < 0) g->nunread = 0; } /* * create the list of strings that we display in a group's subject list window. */ static int groupItems(nGroup *g) { int n, i; nArticle *a; assert(g); if (g->items) { freeGroupItems(g); g->items = 0; } if ((n = g->nunread) == 0) return 0; g->items = salloc((n+1) * sizeof(g->items[0])); g->artptrs = salloc((n+1) * sizeof(g->artptrs[0])); for (a = g->arts, i = 0; a && i < n; a = a->next) { int l, froml, subjl; char *from, *email, *name; if (a->read) continue; g->artptrs[i] = a; parseaddr(a->from, strlen(a->from), &email, &name); from = (whichfrom == FROMEMAIL)? email : name; froml = getLen(from, MAXFROMLEN); subjl = getLen(a->subj, MAXSUBJLEN); l = 10 + froml + subjl; g->items[i] = salloc(l); sprintf(g->items[i],"%c%-5d %.*s %.*s", a->read? 'R' : ' ', a->num, froml, from, subjl, a->subj); i++; } g->items[i] = 0; g->artptrs[i] = 0; return 0; } /* * Convert between item numbers in an artlist and article numbers. */ static int itemToArtnum(nGroup *g, int item) { assert(g && g->artptrs && g->artptrs[item]); return g->artptrs[item]->num; } int artnumToItem(nGroup *g, int artnum) { int item; assert(g && g->artptrs); for (item = 0; g->artptrs[item]; item++) if (g->artptrs[item]->num == artnum) return item; return -1; } /* * Get the listing of all groups */ static int getGroupListItems(void) { nGroup *g; int n; for (ngroups = 0, g = groups; g; g = g->next) if (g->nunread) ngroups++; n = ngroups + 1; grouplistitems = salloc(n * sizeof(*grouplistitems)); grpptrs = salloc(n * sizeof(*grpptrs)); for (n = 0, g = groups; g; g = g->next) { if (g->nunread == 0) continue; grouplistitems[n] = salloc(strlen(g->name) + 30); sprintf(grouplistitems[n],"%s %d articles", g->name, g->nunread); grpptrs[n] = g; n++; } grouplistitems[n] = 0; grpptrs[n] = 0; return 0; } static void freeGroupItems(nGroup *g) { int i; assert(g); if (g->items == 0) for (i = 0; g->items[i]; i++) free(g->items[i]); free(g->items); free(g->artptrs); g->items = 0; g->artptrs = 0; } static int getLen(char *str, unsigned int max) { int l; assert(str); l = strlen(str); return l < max? l : max; } void dorescan(void) { return; } void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg) { int c; nWin *nw; unsigned short context; fflush(stdout); assert(w); assert(cmd); assert(arg); for (c = 0; ncmds[c].cmd; c++) if (strcmp(cmd, ncmds[c].cmd) == 0) break; if (ncmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in this window */ if ((nw = findNWin(w->userp)) == 0) { fprintf(stderr,"%s: invalid window argument\n",cmd); return; } switch (nw->kind) { case nGroupList: context = NCGRPLIST; break; case nArtList: context = NCMSGLIST; break; default: case nDispArt: context = NCDISPART; break; case nCompArt: context = NCCOMPART; break; } if ((ncmds[c].context & context) == 0) { fprintf(stderr,"%s: not valid in that window\n", cmd); return; } DPRINT("executing command..."); DPRINT(cmd); (*ncmds[c].fn)(w, nw->group, nw->artnum, nw->artnum, arg); DPRINT("Command complete"); return; } void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange r, char *arg) { int c; unsigned short context; nWin *nw; assert(w); assert(cmd); assert(arg); nw = findNWin(w->userp); fflush(stdout); for (c = 0; ncmds[c].cmd; c++) if (strcmp(cmd, ncmds[c].cmd) == 0) break; if (ncmds[c].cmd == 0) { fflush(stdout); winReflectCmd(w,cmd,arg); return; } /* check that the command is valid in a list like this */ context = (nw->kind == nGroupList)? NCGRPLIST : NCMSGLIST; if ((ncmds[c].context & context) == 0) { fprintf(stderr,"%s: only valid within list windows\n", cmd); return; } /* check we've been given an appropriate argument */ if (ncmds[c].req == NARG && r.first == -1) { fprintf(stderr,"%s: needs a message\n", cmd); return; } DPRINT("Calling command..."); DPRINT(cmd); (*ncmds[c].fn)(w, nw->group, r.first, r.last, arg); DPRINT("Command complete"); return; } void user_listSelection(rdWin *w, rdItemRange r) { nWin *nw; int item = r.first; assert(w); assert(nw = findNWin(w->userp)); switch (nw->kind) { case nGroupList: selectGroup(nw, w, item); break; case nArtList: selectArticle(nw, w, item); break; default: /* Shouldn't reach here */ assert(false); } return; } void user_delWin(rdWin *w) { nWin *nw; nArticle *a; assert(w); nw = findNWin(w->userp); assert(nw); /* * XXX We *dont't* free the group and article information. Instead, * we burn memory, assuming that swap space is cheaper than * downloading the info each time. I'm probably going to hell * for this. * * switch (nw->kind) { * case nArtList: * freeGroupItems(nw->group); * break; * case nDispArt: * for (a = nw->group->arts; a; a = a->next) * if (a->num == nw->artnum) { * free(a->body); * a->body = 0; * a->bodylen = 0; * break; * } * break; * } */ freeNWin(nw); } /* * canWarp(isart, g, artnum, nw, rdw) - search for an open rdWin that * contains displayed article g/artnum (is isart) or artlist of group g. * If we find one, return true, and set nw/rdw. Otherwise, return false. */ static int canWarp(int isart, nGroup *g, int artnum, nWin **nw, rdWin **rdw) { nWin *nwin; rdWin *rdwin; for (nwin = nwindows; nwin; nwin = nwin->next) if ((nwin->kind == nArtList || nwin->kind == nDispArt) && nwin->group == g && (isart == 0 || nwin->artnum == artnum)) if ((rdwin = userpWin(nwin))) { *nw = nwin; *rdw = rdwin; return 1; } *nw = 0; *rdw = 0; return 0; } static nGroup * itemToGroup(int item) { assert(item >= 0 && item <= ngroups); assert(grpptrs && grpptrs[item]); return grpptrs[item]; } static void selectGroup(nWin *nw, rdWin *rdw, int item) { nGroup *g; nWin *newnw; rdWin *newrdw; assert(g = itemToGroup(item)); if (canWarp(0, g, 0, &newnw, &newrdw)) { warpToWin(newrdw); return; } displayGroupList(g,newnw, newrdw); return; } static void displayGroupList(nGroup *g, nWin *newnw, rdWin *newrdw) { if (newnw == 0) assert(newnw = allocNWin(nArtList, g, 0)); if (newrdw == 0) assert(newrdw = getBlankListWin(0,(void *)newnw)); newnw->group = g; setWinTitle(newrdw, g->name); setWinTools(newrdw, artlist_tools); if (g->items == 0) { if (nntpGroupHdrs(g)) { DPRINT("Could not get group headers"); return; } if (groupItems(g)) { DPRINT("Could not get group items"); return; } } setWinList(newrdw, g->items); return; } static void selectArticle(nWin *nw, rdWin *rdw, int item) { nGroup *g; int artnum; nWin *newnw; rdWin *newrdw; nArticle *a; assert(nw && nw->kind == nArtList); g = nw->group; artnum = itemToArtnum(g, item); if (canWarp(1, g, artnum, &newnw, &newrdw)) { warpToWin(newrdw); return; } assert(newnw = allocNWin(nDispArt, g, artnum)); assert(newrdw = getBlankArtWin(item, (void *)newnw)); displayArticle(newrdw, g, item); return; } static void markread(nArticle *a, int read) { nGroup *g = a->group; int i; nWin *nw; rdWin *w; assert(a); g = a->group; if (a->read == read) return; a->read = read; if (read) newsrcMarkRead(g, a->num); else newsrcMarkUnread(g, a->num); i = artnumToItem(g, a->num); assert(i >= 0); g->items[i][0] = read? 'R' : ' '; for (nw = nwindows; nw; nw = nw->next) if (nw->kind == nArtList && nw->group == g) break; if (nw == 0) { DPRINT("No window found to mark article as read in"); return; /* user might have closed the window */ } w = userpWin(nw); assert(w); rdChangeItem(w, i, g->items[i]); } nWin * allocNWin(int kind, nGroup *g, int num) { nWin *n = salloc(sizeof(*n)); nWin **p = &nwindows; n->kind = kind; n->group = g; n->artnum = num; n->isrep = n->ispost = 0; n->next = 0; while (*p) p = &((*p)->next); *p = n; return n; } void freeNWin(nWin *w) { nWin **p = &nwindows; assert(w); while (*p != w) { assert (*p); p = &((*p)->next); } *p = w->next; free(w); } nWin * findNWin(void *ptr) { nWin *nw = nwindows; assert(ptr); while (nw && (nWin *)ptr != nw) nw = nw->next; return nw; } static void nQuit(rdWin *w, nGroup *g, int first, int last, char *arg) { DPRINT("Quitting"); update_newsrc(groups); nExit(w, g, first, last, arg); } static void nExit(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw; rdWin *rw; assert(w); assert(arg); unlock_newsrc(); /* close msg windows first */ for (nw = nwindows; nw; nw = nw->next) if (nw->kind == nCompArt || nw->kind == nDispArt) if ((rw = userpWin(nw))) closeWin(rw); for (nw = nwindows; nw; nw = nw->next) if (nw->kind != nCompArt && nw->kind != nDispArt) if ((rw = userpWin(nw))) closeWin(rw); exit(0); /* not actually needed - reader will exit for us */ } static int groupNum(nGroup *grp) { int n; for (n = 0; n < ngroups; n++) if (grpptrs[n] == grp) return n; assert(false); /* shouldn't run off the end */ } /* * Scan the list of groups for one which had some unread articles in it. */ static nGroup * findUnreadGroup(nGroup *grp, int fwd) { int n = groupNum(grp); if ((fwd && n >= ngroups-1) || (!fwd && !n)) return 0; /* out of groups */ n += fwd? 1 : -1; assert(n >= 0 && n < ngroups); assert(grpptrs[n]); return grpptrs[n]; } /* * XXX - this function deals with numbers that refer to an article's position * in the list window (0-n), not article numbers (xxx-yyy). */ static int nextArt(rdWin *w, nGroup **ng, int *num, int next) { nWin *artwin, *gwin; rdWin *rwin; nGroup *g = *ng, *nextgroup; int max, item; assert(w); assert(artwin = findNWin(w->userp)); max = g->nunread; item = artwin->itemnum; if ((next && item >= max-1) || (!next && !item)) { /* walking off one end of this newsgroup onto another (in either direction) */ nextgroup = findUnreadGroup(g, next); if (nextgroup == 0) return -1; (void)canWarp(0, g, 0, &gwin, &rwin); /* locate the group window */ displayGroupList(nextgroup, gwin, rwin); artwin->group = nextgroup; /* item number of article is first(last) in group */ if (next) item = 0; else item = nextgroup->nunread - 1; *ng = nextgroup; } else { /* still within this group - move to next article */ item += next? 1 : -1; } *num = item; return 0; } /* * displayArticle(w,g,i) - display article which is item i in group g, in * window w. */ static void displayArticle(rdWin *w, nGroup *g, int i) { nArticle *a; int artnum; nWin *nw; static char title[200]; /* XXX standard guess */ assert(w); assert(g); assert(nw = findNWin(w->userp)); artnum = itemToArtnum(g,i); a = g->artptrs[i]; if (a->body == 0) if (nntpGetArticle(a)) { DPRINT("Could not retrieve article"); return; } sprintf(title,"%s/%d", g->name, artnum); setWinTitle(w, title); setWinTools(w, artdisp_tools); setWinArt(w, a->body); nw->itemnum = i; markread(a, 1); return; } void nNext(rdWin *w, nGroup *g, int first, int last, char *arg) { assert(w); if (nextArt(w, &g, &first, 1)) { DPRINT("No more to select"); return; } displayArticle(w,g,first); } void nPrev(rdWin *w, nGroup *g, int first, int last, char *arg) { assert(w); if (nextArt(w, &g, &first, 0)) { DPRINT("No more to select"); return; } displayArticle(w,g,first); } void nArtMarkRead(rdWin *w, nGroup *g, int first, int last, char *arg) { markartsread(g, first, last, 1); } void nArtMarkUnread(rdWin *w, nGroup *g, int first, int last, char *arg) { markartsread(g, first, last, 0); } void nCatchup(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw, *t; rdWin *rdw; nGroup *nextgroup; assert(g); markartsread(g, 0, g->nunread-1, 1); /* Close any articles displayed from this group */ for (nw = nwindows; nw; nw = t) { t = nw->next; if (nw->kind == nDispArt && nw->group == g) if ((rdw = userpWin(nw)) != 0) { closeWin(rdw); freeNWin(nw); } } /* Move onto next group, if there is one. */ if ((nextgroup = findUnreadGroup(g, 1)) == 0) return; displayGroupList(nextgroup, findNWin(w->userp), w); return; } static void markartsread(nGroup *g, int first, int last, int read) { int i; nArticle *a; assert(g); assert(0 <= first && first <= last); assert(read == 0 || read == 1); for (i = first; i <= last; i++) { DPRINT("Marking article as (un)read"); if (g->artptrs[i]) markread(g->artptrs[i], read); } return; } wily-0.13.41/tools/old/wilytoys/reader2/utils.c100444 2743 200 530 6120766352 17612 0ustar garypgrad/* * general utilities... */ #include "headers.h" char * sstrdup(char *str) { char *s; assert(str); s = salloc(strlen(str)+1); strcpy(s,str); return s; } void panic(const char *msg) { assert(msg); fprintf(stderr,"%s\n", msg); exit(1); } ulong atoul(char *str) { assert(str); return strtoul((const char *)str, (char **)0, 10); } wily-0.13.41/tools/old/wilytoys/reader2/news.h100444 2743 200 6775 6120766352 17474 0ustar garypgrad/* * news.h - definitions of newsgroups and news articles. This is a simplistic * view - we ignore concepts like cross-posting. :-} */ #ifndef NEWS_H #define NEWS_H typedef struct _nGroup nGroup; typedef struct _nArticle nArticle; typedef struct _nWin nWin; typedef struct _nRange nRange; typedef struct _nString nString; /* * Kinds of window we understand. */ enum { nGroupList, /* list of newsgroups */ nArtList, /* list of articles within a group */ nDispArt, /* a displayed article, within a group */ nCompArt /* a new article being composed */ }; struct _nString { char *s0, *s1; }; struct _nRange { int n0, n1; struct _nRange *next; }; struct _nWin { int kind; /* what kind of window it is */ nGroup *group; /* null for nGroupList */ struct _nWin *gwin; /* For articles, this is the userp of the group list window */ int artnum; /* valid for nDispArt and nCompArt */ int itemnum; /* 0 - (n-1), where n==number of items in list */ int isrep; /* true if nCompArt and replying by email */ int ispost; /* true if nCompArt and following up */ struct _nWin *next; }; struct _nGroup { char *name; /* newsgroup name */ int first, last; /* range of articles in this group */ int nunread; /* number of articles left in this group to be read */ nArticle *arts; /* actual articles - null until fetched */ nArticle **artptrs; /* art ptrs, in sync with items */ char **items; /* list of items we pass to the window */ nRange *read; /* list of articles that we've read, from the .newsrc */ int canpost; /* true if posting is allowed to this group */ int issub; /* true if we're subscribed to this group */ struct _nGroup *next; }; /* * In the following structure, if nString.s0 == nString.s1 == 0, then * we haven't downloaded the relevant section yet. */ struct _nArticle { int num; /* article number within group */ int visible; /* true if the article is currently in a window */ nGroup *group; /* group this article is from */ int read; /* true if we've read it */ char *body; /* whole body of article */ int bodylen; /* length of body */ char *from; /* sender - points into hdr */ char *subj; /* subject - points into hdr */ struct _nArticle *next; }; /* * These are the commands that the news reader recognises, and the * contexts that they are valid. */ #define NCMSGLIST 0x1 #define NCDISPART 0x2 #define NCCOMPART 0x4 #define NCGRPLIST 0x8 #define NCNOTCOMP (NCMSGLIST|NCDISPART|NCGRPLIST) #define NCANY (NCMSGLIST|NCDISPART|NCCOMPART|NCGRPLIST) #define NNOARG 0x0 #define NARG 0x1 struct nCmd { char *cmd; unsigned short context; unsigned short req; void (*fn)(rdWin *, nGroup *, int, int, char *); /* pane, first msg, last msg, arg */ }; /* * MTU is your mailer program. It must be capable of reading a complete * mail message, with headers, on stdin. No arguments are added to the * command. */ #define MTU "/usr/lib/sendmail -t" /* * FROMENV gives the name of the environment variable to use to * obtain your real email address - it'll place this in the From: field * of mail messages and news articles. */ #define FROMENV "WILYFROM" /* * LOADDISP determines how much feedback you get when the * newsreader is initialising. It'll display the name of every * LOADDISPth group it asks the server about, unless it's * 0, in which case you don't get any feedback at all. */ #define LOADDISP 5 nWin *allocNWin(int kind, nGroup *g, int num); void freeNWin(nWin *w); nWin *findNWin(void *ptr); int artnumToItem(nGroup *g, int artnum); #endif /* !NEWS_H */ wily-0.13.41/tools/old/wilytoys/reader2/nntp.h100444 2743 200 1134 6120766352 17457 0ustar garypgrad/* * Declarations of NNTP stuff. Pity there isn't a standard header file for this.... */ #ifndef NNTP_H #define NNTP_H /* * Numeric responses from the server. */ typedef enum { nnServerOkPost = 200, nnServerOkNoPost = 201, nnListFollows = 215, nnGroupSel = 211, nnXhdrOk = 221, nnSendArticle = 340, nnPostedOk = 240, nnPostFailed = 441 } nnServerResp; int nntpConnect(void); nGroup *nntpListGroups(void); void nntpQuit(void); int nntpSetGroup(nGroup *g); int nntpGroupHdrs(nGroup *g); int nntpGetArticle(nArticle *a); int nntpPost(char *filename); #endif /* !NNTP_H */ wily-0.13.41/tools/old/wilytoys/reader2/nntp.c100444 2743 200 27152 6120766353 17503 0ustar garypgrad/* * NNTP client code. */ #include "newsheaders.h" #include #include #include #include #include #include #define NNTPMAXRESP 512 #define NNTPMAXPARAMS 256 #define GetChar() ((nntpBufPtr < nntpBufLen)? nntpBuf[nntpBufPtr++] : nntpFillBuf()) static void nntpErr(int quit, char *msg); static int iptoaddr(char *host, char **addr, size_t *len); static int gethost(char **addr, size_t *len); static int getport(void); static int getServerResp(void); static int nntpFillBuf(void); static char *getLine(int *len); static int getServerLine(void); static int splitServerLine(void); static int getLongText(void); static int sendCommand(const char *cmd, ...); static nGroup *getGroupLine(char **str); static int getFromHdrs(nGroup *g); static int doXhdr(nGroup *g, char *arg); static char *nextXhdr(char *s, int *n, char **t); static int getSubjHdrs(nGroup *g); static int haveRead(nGroup *g, int num); static int nextArtLine(FILE *fp, char **lineptr); /* * Messages sent to the server. */ static const char *articleComm = "ARTICLE", *bodyComm = "BODY", *headComm = "HEAD", *statComm = "STAT", *groupComm = "GROUP", *listComm = "LIST", *newgroupsComm = "NEWGROUPS", *newnewsComm = "NEWNEWS", *nextComm = "NEXT", *postComm = "POST", *quitComm = "QUIT", *xhdrComm = "XHDR"; /* * NNTP server status */ static nGroup *currgrp; static nArticle *currartp; static int currartnum; static int canpost; /* * connection to NNTP server. */ static int nntpfd; /* * Response information */ static char nntpBuf[BUFSIZ]; static int nntpBufLen; static int nntpBufPtr; static char nntpRespLine[NNTPMAXRESP+1]; static char *nntpRespWords[NNTPMAXPARAMS]; static char *nntpText; static int nntpRespLen; static int nntpRespNParams; static int nntpStatus; static int nntpTextMax; static int nntpTextLen; /* * Display an NNTP error message. */ static void nntpErr(int quit, char *msg) { int n; fprintf(stderr,"NNTP server error: %s\n", msg); for (n = 0; n < nntpRespNParams; n++) fprintf(stderr,"%s ", nntpRespWords[n]); fputc('\n',stderr); if (quit) exit(1); } /* * Functions to connect to the NNTP server. */ static int iptoaddr(char *host, char **addr, size_t *len) { unsigned long l = inet_addr((const char *)host); if (l == (unsigned long)-1) { perror("bad NNTP address"); return -1; } *addr = (char *)&l; *len = sizeof(l); return 0; } static int gethost(char **addr, size_t *len) { static struct hostent *hp; char *host = getenv("NNTPSERVER"); if (!host || !*host) { DPRINT("NNTPSERVER not set - using 'news'"); host = "news"; /* desparate guess */ } if ((hp = gethostbyname(host)) == 0) { DPRINT("Could not get host address"); if (isdigit(*host)) { DPRINT("Treating hostname as IP address"); return iptoaddr(host, addr, len); /* assume a.b.c.d */ } perror(host); return 1; } assert(hp); *addr = hp->h_addr; *len = hp->h_length; return 0; } static int getport(void) { struct servent *sp; char *srv = "nntp"; if ((sp = getservbyname(srv, "tcp")) == 0) { perror("getservbyname"); exit(1); } else return sp->s_port; } int nntpConnect() { int s; struct sockaddr_in saddr; char *haddr; size_t h_len; int port; if (gethost(&haddr, &h_len)) return -1; memcpy((char *)&saddr.sin_addr, haddr, h_len); if ((port = getport()) == -1) return -1; saddr.sin_port = htons((short)port); if ((s = socket( AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket: %m\n"); return -1; } saddr.sin_family = AF_INET; if (connect (s, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) { perror("connect: %m\n"); return -1; } nntpfd = s; if (getServerResp()) return -1; if (nntpStatus == nnServerOkPost || nntpStatus == nnServerOkNoPost) canpost = nntpStatus == nnServerOkPost; else nntpErr(1,"Failed to connect"); /* doesn't return */ return 0; } /* * Get a response from the server. */ static int getServerResp(void) { nntpRespLen = nntpRespNParams = nntpTextLen = 0; if (getServerLine()) { DPRINT("Could not read line from server"); return 1; } if (splitServerLine()) { DPRINT("Could not split line from server"); return 1; } return 0; } static int nntpFillBuf(void) { int r; nntpBufLen = nntpBufPtr = 0; do { r = read(nntpfd, nntpBuf, BUFSIZ); } while (r < 0 && r == EINTR); if (r == 0) { DPRINT("EOF from nntp server"); return EOF; } if (r < 0) { perror("NNTP read"); exit(1); } nntpBufLen = r; nntpBufPtr = 1; return *nntpBuf; } static char * getLine(int *len) { static char *str; static int max; int l = 0, c = 0, cr = 0; while ((c = GetChar()) != EOF) { if (l >= max) { max = l + NNTPMAXRESP; str = srealloc(str, max); } str[l++] = c; if (c == '\r') cr = 1; else if (cr && c == '\n') { str[--l] = 0; str[l-1] = '\n'; *len = l; return str; } else cr = 0; } return 0; } static int getServerLine(void) { int l; char *s = getLine(&l); if (!s || !*s) return 1; s[--l] = 0; /* chop newline */ if (l >= NNTPMAXRESP) { DPRINT("NNTP line chopped"); } l = l < NNTPMAXRESP? l : NNTPMAXRESP; strncpy(nntpRespLine,s,l); nntpRespLine[l] = 0; nntpRespLen = l; return 0; } static int splitServerLine(void) { char *s = nntpRespLine; assert(s); do { nntpRespWords[nntpRespNParams++] = s; if ((s = strchr(s,' '))) *s++ = 0; } while (s); nntpStatus = atoi(nntpRespWords[0]); assert(nntpStatus); return 0; } static int getLongText(void) { int l; char *s; nntpTextLen = 0; while ((s = getLine(&l))) { if (*s == '.' && s[1] == '\n') return 0; if (nntpTextLen + l > nntpTextMax) { nntpTextMax = nntpTextLen + l + BUFSIZ; nntpText = srealloc(nntpText, nntpTextMax); } strcpy(nntpText + nntpTextLen, s); nntpTextLen += l; } nntpErr(1,"EOF in middle of textual response!"); } /* * Send a command to the NNTP server. */ static int sendCommand(const char *cmd, ...) { static char cmdbuf[512]; int l = 0; char *s; va_list alist; va_start(alist, cmd); strcpy(cmdbuf,cmd); l = strlen(cmd); while ((s = va_arg(alist, char *))) { cmdbuf[l++] = ' '; /* XXX - doesn't check limit of string length */ strcpy(cmdbuf+l, s); l += strlen(s); } va_end(alist); cmdbuf[l++] = '\r'; cmdbuf[l++] = '\n'; if (write(nntpfd, cmdbuf, l) != l) { perror("write"); exit(1); } return 0; } /* * Get a listing of all the groups that the server supports. */ nGroup * nntpListGroups(void) { nGroup *groups = 0, *g; char *s; if (sendCommand(listComm, (char *)0)) return 0; if (getServerResp()) return 0; if (nntpStatus != nnListFollows) nntpErr(1,"Could not get newsgroup list"); if (getLongText()) return 0; for (s = nntpText; s; ) { if ((g = getGroupLine(&s))) { g->next = groups; groups = g; } else break; } return groups; } static nGroup * getGroupLine(char **str) { char *last, *first, *p; nGroup *g; assert(str); if ((last = strchr(*str,' ')) == 0) return 0; *last++ = 0; if ((first = strchr(last,' ')) == 0) return 0; *first++ = 0; if ((p = strchr(first,' ')) == 0) return 0; *p++ = 0; g = salloc(sizeof(*g)); g->name = sstrdup(*str); g->first = atoi(first); g->last = atoi(last); g->canpost = (*p == 'y' || *p == 'Y'); /* Y probably isn't valid but.... */ g->arts = 0; g->read = 0; g->next = 0; if ((*str = strchr(p,'\n'))) (*str)++; return g; } void nntpQuit(void) { (void)sendCommand(quitComm,(char *)0); (void)getServerResp(); close(nntpfd); return; } /* * Select a particular group, and also retrieve the info about that group. */ int nntpSetGroup(nGroup *g) { assert(g); if (sendCommand(groupComm,g->name,0)) return 1; if (getServerResp()) return 1; if (nntpStatus == nnGroupSel) { currgrp = g; currartp = 0; /* not defined yet */ currartnum = g->first = atoi(nntpRespWords[2]); g->last = atoi(nntpRespWords[3]); return 0; } nntpErr(0,"Could not select group"); return 1; } /* * Fill in the From and Subject fields for a group's articles. */ int nntpGroupHdrs(nGroup *g) { assert(g); if (g->nunread == 0) return 0; if (g != currgrp && nntpSetGroup(g)) return 1; if (getFromHdrs(g)) return 1; if (getSubjHdrs(g)) return 1; return 0; } static int getFromHdrs(nGroup *g) { char *s; nArticle **ap = &g->arts; nArticle *a; char *from; int num; assert(g); ap = &g->arts; if (doXhdr(g, "from")) return 1; *ap = 0; for (s = nextXhdr(nntpText, &num, &from); s; s = nextXhdr(s, &num, &from)) { a = salloc(sizeof(*a)); a->num = num; a->visible = 0; a->group = g; a->read = haveRead(g, a->num); a->body = 0; a->from = from; a->subj = 0; a->next = 0; *ap = a; ap = &a->next; } return 0; } static int doXhdr(nGroup *g, char *arg) { static char range[80]; /* XXX - more guesses */ sprintf(range,"%d-%d", g->first, g->last); if (sendCommand(xhdrComm,arg,range,0)) return 1; if (getServerResp()) return 1; if (nntpStatus != nnXhdrOk) return 1; if (getLongText()) return 1; return 0; } static char * nextXhdr(char *s, int *n, char **t) { char *text, *num = s; if (s >= nntpText + nntpTextLen) return 0; if ((text = strchr(s, ' ')) == 0) return 0; *text++ = 0; if ((s = strchr(text,'\n')) == 0) return 0; *s++ = 0; *n = atoi(num); *t = sstrdup(text); return s; } static int getSubjHdrs(nGroup *g) { int num; char *s, *subj; nArticle *a = g->arts; assert(g); a = g->arts; if (a == 0) return 0; if (doXhdr(g, "subject")) return 1; for (s = nextXhdr(nntpText, &num, &subj); s; s = nextXhdr(s, &num, &subj)) { if (num < a->num) continue; /* new article appeared from nowhere */ while (a && a->num < num) a = a->next; /* article has been cancelled */ if (a == 0) return 0; a->subj = subj; a = a->next; } return 0; } /* * Read the text for an article. */ int nntpGetArticle(nArticle *a) { static char arg[80]; /* XXX */ assert(a); if (a->body) return 0; /* already fetched */ if (a->group != currgrp && nntpSetGroup(a->group)) return 1; sprintf(arg,"%d", a->num); if (sendCommand(articleComm, arg, 0)) return 1; if (getServerResp()) return 1; if (getLongText()) return 1; a->body = sstrdup(nntpText); a->bodylen = nntpTextLen; return 0; } static int haveRead(nGroup *g, int num) { nRange *r; assert(g); for (r = g->read; r ; r = r->next) if (r->n0 <= num && num <= r->n1) return 1; return 0; } /* * Post an article to the server */ int nntpCanPost(void) { return canpost; } int nntpPost(char *filename) { FILE *fp; char *line; int len; assert(filename); assert(canpost); if ((fp = fopen(filename,"r")) == 0) { (void)fprintf(stderr,"Cannot read %s to post!\n", filename); return 1; } if (sendCommand(postComm,0)) goto broken; if (getServerResp()) goto broken; if (nntpStatus != nnSendArticle) { nntpErr(0,"Server refused article"); goto broken; } while ((len = nextArtLine(fp, &line)) > 0) if (write(nntpfd, line, len) != len) { perror("write"); goto broken; } if (len < 0) goto broken; (void)fclose(fp); if (write(nntpfd, ".\r\n",3) != 3) { perror("write"); return 1; } if (getServerResp()) return 1; if (nntpStatus == nnPostedOk) { DPRINT("Article posted"); } else { nntpErr(0,"Article not posted"); } return 0; broken: (void)fclose(fp); return 1; } static int nextArtLine(FILE *fp, char **lineptr) { static char text[NNTPMAXRESP+1]; int len = 0; int c; *lineptr = text; while ((c = fgetc(fp)) != EOF) { text[len++] = c; if (c == '\n') { text[len-1] = '\r'; text[len++] = '\n'; text[len] = 0; break; } if (len == NNTPMAXRESP-1) { /* line has got too long to put the \r\n sequence in - sent it now. */ text[len] = 0; return len; } } if (len == 3 && text[0] == '.') { len++; strcpy(text,"..\r\n"); } return len; } wily-0.13.41/tools/old/wilytoys/reader2/Credits100644 2743 200 223 6057270733 17631 0ustar garypgradBjorn Helgaas change of FILENAME_MAX to MAXPATHLEN arnold@infographix.infographix.com (Arnold Robbins) Various suggestions. wily-0.13.41/tools/old/wilytoys/reader2/newsrc.c100444 2743 200 13300 6120766352 20012 0ustar garypgrad/* * newsrc.c - loading, parsing and updating the list of newsgoups/articles * that have been read. */ #include "newsheaders.h" static void init_filenames(void); static FILE *lock_newsrc(void); static nGroup *newsrcLine(FILE *fp); static char *newsrcGroup(FILE *fp); static nRange *newsrcRanges(FILE *fp); static nRange *newsrcRange(FILE *fp, int *end); static void newsrcCompress(nGroup *g); static char newsrcname[MAXPATHLEN+1]; static char newsrctmp[MAXPATHLEN+1]; static char newsrcold[MAXPATHLEN+1]; static char lockname[MAXPATHLEN+1]; static int newsrcline; static void init_filenames(void) { char *h = getenv("HOME"); if (!h || !*h) { fprintf(stderr,"$HOME is not set\n"); exit(1); /* XXX- should really get pwdent */ } sprintf(newsrcname,"%s/%s", h, NEWSRC); sprintf(newsrctmp,"%s/%s.tmp", h, NEWSRC); sprintf(newsrcold,"%s/%s.old", h, NEWSRC); sprintf(lockname,"%s/%s", h, LOCKFILE); DPRINT("newsrc is..."); DPRINT(newsrcname); DPRINT("lockfile is..."); DPRINT(lockname); return; } static FILE * lock_newsrc(void) { FILE *fp; DPRINT("Locking .newsrc..."); if (link(newsrcname, lockname)) { perror(".newsrc link"); fprintf(stderr,"Could not lock %s with link to %s\n", newsrcname, lockname); return 0; } DPRINT("Newsrc locked - opening"); if ((fp = fopen(newsrcname,"r")) == 0) { DPRINT("could not open newsrc"); unlock_newsrc(); } atexit(unlock_newsrc); return fp; } void unlock_newsrc(void) { DPRINT("Unlocking newsrc"); remove(lockname); DPRINT("Newsrc unlocked"); } nGroup * read_newsrc(void) { FILE *fp; nGroup *groups = 0, *g; nGroup **p; DPRINT("Reading newsrc"); newsrcline = 1; init_filenames(); if ((fp = lock_newsrc()) == 0) { DPRINT("Could not lock newsrc"); return 0; } for (p = &groups; (g = newsrcLine(fp)); p = &g->next) *p = g; DPRINT("Closing newsrc"); fclose(fp); return groups; } static nGroup * newsrcLine(FILE *fp) { nGroup *g = salloc(sizeof(*g)); int c; memset(g,0,sizeof(*g)); if ((g->name = newsrcGroup(fp)) == 0) goto broken; switch ((c = fgetc(fp))) { case SUBSEP: g->issub = 1; break; case NOSUBSEP: g->issub = 0; break; default: DPRINT("Don't recognise group name delimiter in line"); goto broken; } g->read = newsrcRanges(fp); newsrcline++; return g; broken: if (g->name) free(g->name); free(g); return 0; } static char * newsrcGroup(FILE *fp) { int c, l = 0; static char str[MAXPATHLEN+1]; while ((c = fgetc(fp)) != SUBSEP && c != NOSUBSEP) { if (c == EOF || l == MAXPATHLEN) { if (l) fprintf(stderr,"%s corrupt: line %d\n", newsrcname, newsrcline); return 0; } str[l++] = c; } assert(l); ungetc(c, fp); str[l] = 0; return sstrdup(str); } static nRange * newsrcRanges(FILE *fp) { nRange *ranges = 0, *r; nRange **p; int c, end = 0; while (isspace((c = fgetc(fp))) && c!='\n') ; if (c == '\n') return 0; ungetc(c,fp); for (p = &ranges; r = newsrcRange(fp, &end); p = &r->next) { *p = r; if (end) break; } assert(ranges); return ranges; } static nRange * newsrcRange(FILE *fp, int *end) { nRange *r = salloc(sizeof(*r)); int c, l; static char num[80]; /* XXX wild guess */ r->next = 0; for (l = 0; isdigit((c = fgetc(fp))); num[l++] = c) ; num[l] = 0; r->n0 = r->n1 = atoi(num); if (c == '-') { for (l = 0; isdigit((c = fgetc(fp))); num[l++] = c) ; num[l] = 0; r->n1= atoi(num); } if (c != RANGESEP && c != '\n') while ((c = fgetc(fp)) != EOF && c != '\n'); if (c != RANGESEP) *end = 1; return r; } int update_newsrc(nGroup *groups) { nGroup *g; nRange *r; FILE *fp; assert(groups); DPRINT("Updating newsrc"); newsrcCompress(groups); if ((fp = fopen(newsrctmp,"w")) == 0) { perror(newsrctmp); return 1; } for (g = groups; g; g = g->next) { char *s = ""; char *fmt = g->read? "%s%c " : "%s%c"; fprintf(fp, fmt, g->name, g->issub? SUBSEP : NOSUBSEP); for (r = g->read; r; r= r->next, s = ",") if (r->n0 == r->n1) fprintf(fp, "%s%d",s,r->n0); else fprintf(fp,"%s%d-%d",s,r->n0, r->n1); fputc('\n',fp); } if (fclose(fp)) { perror(newsrctmp); remove(newsrctmp); return 1; } if (rename(newsrcname, newsrcold) || rename(newsrctmp, newsrcname)) { perror("renaming .newsrc"); return 1; } DPRINT("Newsrc updated"); return 0; } /* * Some routines for handling the list of ranges of read articles. */ void newsrcMarkRead(nGroup *g, int i) { nRange **p; nRange *r; assert(g); for (p = &g->read; *p && (*p)->n0 < i; p = &((*p)->next)) ; /* have now reached the end of the list, the range containing i, or the range that comes after i. */ if (!*p || i < (*p)->n0) { /* does insert at end, insert at start, or insert before a range */ r = salloc(sizeof(*r)); r->n0 = r->n1 = i; r->next = *p; *p = r; return; } /* only remaining case is that the current range already contains i */ assert(*p); assert((*p)->n0 <= i && i <= (*p)->n1); return; } void newsrcMarkUnread(nGroup *g, int i) { nRange **p; nRange *r, *n; assert(g); for (p = &g->read; *p && (*p)->n0 < i; p = &((*p)->next)) { r = *p; if (r->n0 == i && i == r->n1) { *p = r->next; free(r); return; } else if (r->n0 == i) { r->n0++; return; } else if (r->n1 == i) { r->n1--; return; } else if (r->n0 < i && i < r->n1) { n = salloc(sizeof(*n)); n->n1 = r->n1; n->n0 = i + 1; n->next = r->next; r->n1 = i - 1; r->next = n; return; } } /* i isn't in any of the items in the list */ return; } /* * compress the list, by combining adjacent ranges */ static void newsrcCompress(nGroup *g) { nRange *r, *n; assert(g); for (; g; g = g->next) for (r = g->read; r; r = r->next) for (n = r->next; n && n->n0 <= r->n1 + 1; n = r->next) { r->n1 = n->n1; r->next = n->next; free(n); } return; } wily-0.13.41/tools/old/wilytoys/reader2/solaris.c100444 2743 200 4260 6120766353 20153 0ustar garypgrad/* * solaris.c - the system-dependent routines for Solaris 2. */ #include "mailheaders.h" #include #include /* * load_mbox(mbox,rescan) - open the named file, and make it available * as a block of memory between mbox_start and mbox_end. If rescan * is true, we've already the mbox, and we want to see if there're more * messages in the file. */ int load_mbox(mMbox *mbox, int rescan) { const char *mode = mbox->readonly? "r" : "r+"; FILE *fp = fopen(mbox->name,mode); char *addr = 0; size_t len; struct stat st; if (fp == 0) { DPRINT("Could not open file"); goto broken; } if (stat(mbox->name,&st) == -1) { DPRINT("Could not stat file"); goto broken; } if (rescan) { if (st.st_size < mbox->size) { fprintf(stderr,"%s corrupt\n", mbox->name); goto broken; } if (st.st_mtime == mbox->mtime) { DPRINT("file hasn't changed"); fclose(fp); mbox->mbox_start = mbox->mbox_end = 0; return 0; } len = (size_t)(st.st_size - mbox->size); if (fseek(fp, mbox->size, SEEK_SET) == -1) { DPRINT("Could not seek to start of new messages"); } } else len = (size_t)st.st_size; mbox->size = st.st_size; mbox->mtime = st.st_mtime; if ((addr = mb_alloc(len+1)) == 0) { DPRINT("Could not allocate space for new messages"); goto broken; } addr[len] = 0; /* handy for debugging */ if (fread(addr, (size_t)1, len, fp) != len) { DPRINT("Could not read new messages"); goto broken; } fclose(fp); mbox->mbox_start = addr; mbox->mbox_end = mbox->mbox_start + len; return 0; broken: if (addr) free(addr); fclose(fp); return 1; } /* we failed to load the mbox. Check that it exists, if we need it to. */ int empty_mbox(mMbox *box, const char *filename, int mustexist) { int readable = !access(filename, R_OK); int exists = !access(filename, F_OK); if (readable || (exists && !readable) || (mustexist && !exists)) { fprintf(stderr,"%s not %s\n",filename, readable? "read" : exists? "readable" : "found"); return 1; } /* file doesn't exist, but that's ok - it doesn't need to in this case, so create an empty mbox */ box->size = 0; box->mbox_start = box->mbox_end = 0; /* XXX - likely to flush out some bugs */ return 0; } wily-0.13.41/tools/old/wilytoys/reader2/newsrc.h100444 2743 200 571 6120766353 17766 0ustar garypgrad/* * newsrc.h - handling the list of newsgroups/articles that we've read. */ #define SUBSEP ':' #define NOSUBSEP '!' #define RANGESEP ',' #define NEWSRC ".testnewsrc" #define LOCKFILE ".testnewsrc.lock" nGroup *read_newsrc(void); void unlock_newsrc(void); int update_newsrc(nGroup *groups); void newsrcMarkRead(nGroup *g, int i); void newsrcMarkUnread(nGroup *g, int i); wily-0.13.41/tools/old/wilytoys/reader2/proto.h100444 2743 200 3265 6120766354 17654 0ustar garypgrad#ifndef PROTO_H #define PROTO_H /* getmsg.c */ rdWin *getActiveWin(void); /* reader.c */ void closeWin(rdWin *w); void freeWin(rdWin *w); rdWin *getArtWin(int user, void *userp, char *title, char *tools, char *text, rdWin *oldwin); rdWin *getListWin(int user, void *userp, char *title, char *tools, rdWin *oldwin, char **items); void highlightItem(rdWin *w, rdItemRange r); void warpToWin(rdWin *w); rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1); int rdAddItem(rdWin *w, char *text); int rdChangeItem(rdWin *w, int item, char *text); int rdDelItem(rdWin *w, int item); void rdGotoWin(rdWin *w); void rdInclude(rdWin *w, char *str, size_t len); void rdSetMulti(int list, int art); void rdSetRescanTimer(int secs); rdWin *readerLoading(int user, void *userp, int isart, char *title); int readerInit(); int readerMainLoop(void); rdWin *userpWin(void *ptr); void winReflectCmd(rdWin *w, char *cmd, char *arg); rdWin *getBlankListWin(int user, void *userp); rdWin *getBlankArtWin(int user, void *userp); int setWinUser(rdWin *w, int user, void *userp); int setWinTitle(rdWin *w, char *title); int setWinTools(rdWin *w, char *tools); int setWinList(rdWin *w, char **items); int setWinArt(rdWin *w, char *art); /* reader clients: mail.c, news.c */ void user_cmdArt(rdWin *w, char *cmd, ulong p0, ulong p1, char *arg); void user_cmdList(rdWin *w, char *cmd, ulong p0, ulong p1, rdItemRange items, char *arg); void user_listSelection(rdWin *w, rdItemRange r); void user_delWin(rdWin *w); #ifdef WILYMAIL_H /* mail.c */ void dorescan(void); #endif /* utils.c */ ulong atoul(char *str); char *sstrdup(char *str); /* addr.c */ void parseaddr(char *addr, int len, char **email, char **name); #endif /* !PROTO_H */ wily-0.13.41/tools/old/wilytoys/reader2/CHANGES100644 2743 200 6252 6120766245 17333 0ustar garypgrad0.3 - 0.4 ======= Newsreader has been significantly improved, to the point where I actually use it for reading news. It's got a long way to go, but I can actually bear to use it, so it can't be all that bad. Both readers give feedback when they're loading - makes it slightly less stressful watching the newsreader load, anyway. Addresses are "parsed", for want of a better word, to give name or email address in the message lists. 0.2 - 0.3 ======= *BUG WARNING* In at least one case, I've noticed that this appears to have lost mail in a race condition. Faces announced that new mail had arrived, I did a commit, and nothing new appeared. :-( I'm not aware of this happening more than once, but how do you tell? I recommend using a .forward file or some similar mechanism to keep a separate copy of your mail, so that you've got a day or so's backlog in case someone claims something went missing. I don't know how to reproduce this, so I've got no idea how to fix it. Right now, I'm not too worried - no one else has appeared to send me anything which has vanished, and the message I did lose was from my boss. :-) Added lots more assertions and a DEBUG option for the Makefile, which produces lots of gibberish. Added "next" and "prev" commands, for advancing through the mailbox. This occasioned a change in how it determines which window to display a message in. The rule is: - if you next/prev in an article window, you'll re-use that window, and get the next/previous article according to the number of the article in that window. - if you next/prev in the list window, you'll get a new window, and it'll give you the next/previous article according to the line currently selected in the list. (BUG: doesn't change *which* item in the list is currently selected; this is because that causes a cursor warp, too). - If you B3 on a subject line, you get a new window for the article indicated. A News reader is included. This should read groups and articles ok, and allows you to post articles or reply via email. It works, but the behaviour of "next" and "prev" is broken. Right now, it uses .testnewsrc instead of .newsrc, because it's too broken for daily use. When posting a mail message, changes the tag to "Sending...", so you know something is happening. 0.1 -> 0.2 ======== Filters out most common garbage headers (toggle this with allheaders). Can delete/undelete/save multiple messages, by sweeping them. [Un]delete is a lot less effort on the screen updates. Commit now writes changes back to the mailbox, without quitting. Doesn't read in new mail, though. Rescan reads in any new mail that has arrived. Doesn't write any current changes, though. Rescans your mailbox for new mail automatically. Does this every 60 seconds, by default. You have to hack mail.h to change this... If you're running it in non-multiart mode (default), then it tries to avoid trashing your composition windows when you pull up a message window. savefile has a default parameter: $SAVEFILE if set, or $HOME/mbox otherwise. Sets the title of article windows to just mailboxname/msgnum, because the From: lines are too long. Uses MAXPATHLEN instead of FILENAME_MAX, because FILENAME_MAX is way too small on some machines. wily-0.13.41/tools/old/wilytoys/reader2/reader.c100444 2743 200 45633 6120766354 17773 0ustar garypgrad/* * reader.c - functions for handling news/article reader windows. */ #include "headers.h" Bool debug = false; Bool frommessage = true; /* * The windows currently active. */ rdWin *windows = 0; /* * General wily comms stuff. */ Mqueue realwilyq; Mqueue *wilyq = &realwilyq; Fd wilyfd; /* * Amount of time we wait before causing a rescan event, in seconds. * If zero, then we don't rescan. */ static int rdRescanTimer = 0; Bool rdAlarmEvent = false; static void (*old_alarm_handler)(int) = 0; /* * default contents of tags */ char *rdListTagStr = " "; char *rdArtTagStr = " "; static rdWin *allocWin(rdWinType kind, const char *title); static int connectWin(rdWin *w, char *filename); static rdWin *getWin(int user, void *userp, rdWinType kind); static void clearWin(rdWin *w); static void freeItems(rdWin *w); static int initWin(int user, void *userp, rdWin *w, char *title, char *tools); static void anyEvent(rdWin *w); static void winDelete(rdWin *w, int which, ulong p0, ulong p1); static void winInsert(rdWin *w, int which, ulong p, char *str); static void updateBody(rdWin *w, ulong p0, ulong p1, char *str); static void winGoto(rdWin *w, ulong p0, char *str); static void winExec(rdWin *w, char *cmd, char *arg); static void DelWin(rdWin *w, char *arg); static int rdBuiltin(rdWin *w, char *cmd, char *str); static void addrEvent(rdWin *w); static void bodyEvent(rdWin *w); static size_t countlines(char *str, size_t len); static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf); static void alarm_handler(int signal); static void set_sig(void); static void updateItems(rdWin *w, rdItem *i, int len); /* * allocWin(kind, title) - create a new, blank window of a given kind. */ static rdWin * allocWin(rdWinType kind, const char *title) { rdWin *w = salloc(sizeof(*w)); assert(title); w->title = sstrdup((char *)title); w->wintype = kind; w->id = -1; w->m = 0; w->items = 0; w->body = 0; w->taglen = w->bodylen = 0; w->next = windows; windows = w; return w; } /* * connectWin(w, filename) - connect to wily, to create a new window. * If filename is true, then we get wily to open the given file. Otherwise, * we ask for a new, blank window. * Returns 0 for success. */ static int connectWin(rdWin *w, char *filename) { int fd; assert(w); if (filename == 0) filename = "New"; if (rpc_new(wilyq, &w->id, filename, false) < 0) { DPRINT("Could not get new window from wily"); freeWin(w); return -1; } return 0; } /* * setWinUser(w, user, userp) - change the user info for this window. */ int setWinUser(rdWin *w, int user, void *userp) { assert(w); w->user = user; w->userp = userp; return 0; } /* * randomTitle() - generate a one-off string to be the title for * this window, until we're given one by the user program. * XXX this is a static string, which is copied when it's written * into the window structure. */ static char * randomTitle(void) { int pid = getpid(); static int num; static char title[30]; /* XXX - usual guess */ sprintf(title,"+rdwin%d-%d", pid, num++); return title; } /* * setWinTitle(w, title) - set the title of a window. */ int setWinTitle(rdWin *w, char *title) { assert(w); assert(title); if (rpc_setname(wilyq, w->id, title)) { DPRINT("Wily couldn't set window title"); return 1; } if (w->title) free(w->title); assert(w->title = sstrdup(title)); return 0; } /* * setWinTools(w, tools) - set the tools for a window. */ int setWinTools(rdWin *w, char *tools) { assert(w); assert(tools); if (rpc_settag(wilyq, w->id, tools)) { DPRINT("wily couldn't set window tools"); return 1; } w->taglen = strlen(tools); return 0; } /* * getBlankArtWin(user, userp) - grab an article window. */ rdWin * getBlankArtWin(int user, void *userp) { return getWin(user, userp, rdArticle); } /* * getBlankListWin(user, userp) - grab a list window. */ rdWin * getBlankListWin(int user, void *userp) { return getWin(user, userp, rdList); } /* * getWin(user, userp, kind) - create a new window. */ rdWin * getWin(int user, void *userp, rdWinType kind) { rdWin *w; char *title; assert(title = randomTitle()); assert(w = allocWin(kind, title)); if (connectWin(w,title)) return 0; w->user = user; w->userp = userp; return w; } /* * discard all the items in the window's list */ static void freeItems(rdWin *w) { rdItem *i, *j; assert(w); for (i = w->items; i; i = j) { j = i->next; free(i); } w->items = 0; } /* * loadItems(w, items) - load an array of items into the list, and into the window. */ static int loadItems(rdWin *w, char **items) { rdItem *i, *j = 0; char *sep = "\n"; ulong p0 = 0; ulong len, seplen = strlen(sep); char *buf = 0; int n; assert(w); assert(items); while (*items) { i = salloc(sizeof(*i)); i->next = 0; i->p0 = p0; len = strlen(*items); if (j) j->next = i; else w->items = i; j = i; if (rpc_insert(wilyq, w->id, p0, *items)) { DPRINT("Failed to insert list item into wily"); freeItems(w); return -1; } p0 += len; if (rpc_insert(wilyq, w->id, p0, sep)) { DPRINT("Failed to insert list separator into wily"); freeItems(w); return -1; } i->p1 = (p0 += seplen); items++; } w->bodylen = p0; return 0; } /* * setWinList(w, items) - update the contents of a list window. */ int setWinList(rdWin *w, char **items) { assert(w); assert(items); if (w->wintype != rdList) { DPRINT("setWinList() called for non-list window"); return 1; } freeItems(w); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) { DPRINT("Could not delete list body"); return 1; } w->bodylen = 0; } return loadItems(w, items); } /* * setWinArt(w,art) - replace the contents of article window w with text art. */ int setWinArt(rdWin *w, char *art) { assert(w); assert(art); assert(w->wintype == rdArticle); if (w->bodylen) { if (rpc_delete(wilyq, w->id, 0, w->bodylen)) { DPRINT("Failed to delete existing contents of window"); return 1; } } w->bodylen = strlen(art); if (rpc_insert(wilyq, w->id, 0, art)) { DPRINT("Failed to insert new body into window"); return 1; } return 0; } /* * getArtWin(title, text, filename) - get an article window, and load it with * either the given text, or from the given file. */ rdWin * getArtWin(int user, void *userp, char *title, char *tools, char *text, rdWin *oldwin) { rdWin *w; if (oldwin) { w = oldwin; setWinUser(w, user, userp); } else assert(w = getBlankArtWin(user, userp)); if (title && setWinTitle(w, title)) return 0; if (tools && setWinTools(w, tools)) return 0; if (text && setWinArt(w, text)) return 0; return w; } /* * get a List window, and load it with the items in the array (which * must be null-terminated). */ rdWin * getListWin(int user, void *userp, char *title, char *tools, rdWin *oldwin, char **items) { rdWin *w; if (oldwin) { w = oldwin; setWinUser(w, user, userp); } else assert(w = getBlankListWin(user, userp)); if (title && setWinTitle(w, title)) return 0; if (tools && setWinTools(w, tools)) return 0; if (items && setWinList(w, items)) return 0; return w; } /* * readerLoading(user, userp, int isart, title) - create a window of the * desired type and title that indicates that the program has started and is * working at something... */ rdWin * readerLoading(int user, void *userp, int isart, char *title) { rdWin *w; assert(title); assert(w = isart? getBlankArtWin(user, userp) : getBlankListWin(user, userp)); assert(setWinTitle(w,title)==0 && setWinTools(w,"Working...")==0); return w; } /* * readerInit() - general initialisation. */ int readerInit(void) { if ((wilyfd = get_connect()) < 0) { DPRINT("Could not connect to wily"); return 1; } mq_init(wilyq, wilyfd); return 0; } /* * readerMainLoop() - get messages from wily, and act upon them. */ int readerMainLoop(void) { rdWin *w; Msg *m; int istag; while (windows) { if ((w = getActiveWin()) == 0) { fprintf(stderr,"No message available\n"); return 1; } m = w->m; assert(m); switch (m->mtype) { char *cmd, *arg; ulong p0, p1; case EMexec: decode_exec_e(m, &cmd, &arg); winExec(w, cmd, arg); break; case EMgoto: decode_goto_e(m, &p0, &arg); winGoto(w, p0, arg); break; case EMinsert: istag = IsBody; decode_insert_e(m, &p0, &arg); winInsert(w, istag, p0, arg); break; case EMdelete: istag = IsBody; decode_delete_e(m, &p0, &p1); winDelete(w, istag, p0, p1); break; default: fprintf(stderr,"Unknown msg type!\n"); exit(1); } } return 1; } /* * delete item n from the list */ int rdDelItem(rdWin *w, int item) { rdItem **pi; rdItem *i; int len; assert(w); if (w->wintype != rdList || item < 0) { DPRINT("Invalid window or item for delete"); return 1; } for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) { DPRINT("Could not find item to delete it"); return 1; /* not found */ } i = *pi; len = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) < 0) { DPRINT("Could not delete item from list"); return 1; } *pi = i->next; free(i); updateItems(w, *pi, -len); return 0; } /* * add a new item to the end of the list */ int rdAddItem(rdWin *w, char *text) { rdItem **pi; rdItem *i; int len; char *sep = "\n"; assert(w); assert(text); len = (int)strlen(text); if (w->wintype != rdList || !text || !*text) { DPRINT("addItem() call for non-list window"); return 1; } i = salloc(sizeof(*i)); for (pi = &w->items; *pi; pi = &((*pi)->next)); *pi = i; i->p0 = w->bodylen; i->p1 = i->p0 + len; i->next = 0; if (rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p1++, sep)) { DPRINT("Could not insert item into window"); return 1; } len += strlen(sep); w->bodylen += len; return 0; } /* * change the text of an item */ int rdChangeItem(rdWin *w, int item, char *text) { rdItem **pi; rdItem *i; int len, oldlen, newlen; char *sep = "\n"; assert(w); assert(text); newlen = strlen(text); if (w->wintype != rdList || !text || !*text) { DPRINT("changeItem() called for non-list window"); return 1; } for (pi = &w->items; *pi && item; pi = &((*pi)->next)) item--; if (item) { DPRINT("item not found"); return 1; } i = *pi; oldlen = i->p1 - i->p0; if (rpc_delete(wilyq, w->id, i->p0, i->p1) || rpc_insert(wilyq, w->id, i->p0, text) || rpc_insert(wilyq, w->id, i->p0 + newlen, sep)) { DPRINT("Updates to wily window failed"); return 1; } newlen += strlen(sep); i->p1 = i->p0 + newlen; len = newlen - oldlen; updateItems(w, i->next, len); return 0; } static void updateItems(rdWin *w, rdItem *i, int len) { assert(w); w->bodylen += len; while (i) { i->p0 += len; i->p1 += len; i = i->next; } } /* * text has been deleted */ static void winDelete(rdWin *w, int which, ulong p0, ulong p1) { rdItem *i; ulong l = p1 - p0; assert(w); assert(p0 <= p1); if (which == IsTag) { w->taglen -= l; return; } if (w->wintype == rdArticle) { w->bodylen -= l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p0 && p1 <= i->p1) break; if (!i) return; i->p1 -= l; for (i = i->next; i; i = i->next) { i->p0 -= l; i->p1 -= l; } updateBody(w, p0, p1, (char *)0); return; } /* * text has been inserted */ static void winInsert(rdWin *w, int which, ulong p, char *str) { rdItem *i; int l; assert(w); assert(str); l = strlen(str); if (which == IsTag) { w->taglen += l; return; } if (w->wintype == rdArticle) { w->bodylen += l; return; } for (i = w->items; i; i = i->next) if (i->p0 <= p && p <= i->p1) break; if (!i) return; i->p1 += l; for (i = i->next; i; i = i->next) { i->p0 += l; i->p1 += l; } updateBody(w, p, (ulong)l, str); return; } /* * updateBody(w,p0,p1,str) - insert p1 chars of str at p0, or remove the text * between p0 and p1. * XXX - this is *utterly* revolting, and horrendously slow. But it's quick * and simple, and will do for now. */ static void updateBody(rdWin *w, ulong p0, ulong p1, char *str) { char *newbuf; ulong newlen; assert(w); if (w->body == 0) return; if (str) newlen = w->bodylen + p1; else newlen = w->bodylen - (p1 - p0); newbuf = salloc(newlen); strncpy(newbuf, w->body, p0); if (str) { strncpy(newbuf + p0, str, p1); strcpy(newbuf + p0 + p1, w->body + p0); } else { strcpy(newbuf + p0, w->body + p1); } free(w->body); w->body = newbuf; w->bodylen = newlen; } rdItemRange itemNumber(rdWin *w, ulong p0, ulong p1) { int n; rdItem *i; rdItemRange r; assert(w); r.first = r.last = -1; r.i0 = r.i1 = 0; if (w->wintype != rdList || p1 < p0) { DPRINT("itemNumber asked for in non-list window"); return r; } for (n = 0, i = w->items; i; i = i->next, n++) { if (i->p0 <= p0 && p0 <= i->p1) { r.first = r.last = n; r.i0 = r.i1 = i; } if (i->p0 <= p1 && p1 <= i->p1) { r.last = n; r.i1 = i; return r; } } DPRINT("Can't find item in list window"); return r; /* sigh */ } /* * Move the cursor to a particular window. */ void warpToWin(rdWin *w) { assert(w); /* XXX not implemented yet. */ } void highlightItem(rdWin *w, rdItemRange r) { static char addr[80]; /* XXX - overkill */ rdItem *i; ulong p0, p1; int n; assert(w); if (!r.i0 || !r.i1) { for (i = w->items, n = 0; n <= r.last; n++, i = i->next) { if (n == r.first) p0 = i->p0; if (n == r.last) p1 = i->p1; } } else { p0 = r.i0->p0; p1 = r.i1->p1; } sprintf(addr,"#%lu,#%lu", p0, p1); if (rpc_goto(wilyq, w->id, addr)) { DPRINT("highlighting failed"); } } /* * A B3 event has occured. */ static void winGoto(rdWin *w, ulong p0, char *str) { /* If this is a list, then it counts as a selection. Otherwise, we just reflect it back to wily as a normal B3 event. */ assert(w); assert(str); if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p0); if (r.first == -1) { DPRINT("Goto occurred outside range of items"); return; /* sigh */ } highlightItem(w, r); user_listSelection(w,r); return; } else { if (rpc_goto(wilyq, w->id, str)) { DPRINT("could not send goto to wily"); } } return; } /* * A B2(B1) command has been invoked. */ static void winExec(rdWin *w, char *cmd, char *arg) { ulong p0, p1; /* * Lots of options here: * - B2 with "|<>" - reflect back to wily. * - B2 cmd recognised by the reader routines - Del is about it. Execute * them ourselves. * - B2 not recognised by the reader routines - pass them onto the user, * after first getting the position of the argument within the body, if * necessary. * - B2B1 recognised by the reader routines - none spring to mind, but * I might add some. Execute them ourselves. * - B2B1 not recognised - pass onto user. */ assert(w); assert(cmd); assert(arg); DPRINT("Command received..."); DPRINT(cmd); if (!*cmd || strstr(cmd,"|<>")) { DPRINT("Reflecting command"); winReflectCmd(w,cmd, arg); return; } if (rdBuiltin(w,cmd,arg) == 0) { DPRINT("command is reader builtin - handled"); return; } if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) { DPRINT("could not get address of dot"); return; } if (w->wintype == rdList) { rdItemRange r = itemNumber(w, p0, p1); if (r.first == -1) { p0 = p1 = 0; } else { highlightItem(w, r); p0 = r.i0->p0; p1 = r.i1->p1; } user_cmdList(w,cmd,p0,p1,r,arg); return; } user_cmdArt(w, cmd, p0, p1, arg); return; } void winReflectCmd(rdWin *w, char *cmd, char *arg) { if (rpc_exec(wilyq, w->id,cmd,arg)) { DPRINT("could not reflect command to wily"); } } /* * delete this particular window from the list. */ static void DelWin(rdWin *w, char *arg) { assert(w); user_delWin(w); closeWin(w); } void closeWin(rdWin *w) { assert(w); /* get wily to close the pane */ if (rpc_exec(wilyq, w->id, "Del", "")) { DPRINT("Could not close window"); } /* free up resources */ free(w->title); free(w->body); if (w->wintype == rdList) freeItems(w); /* XXX - currently leak the stateinfo stuff */ freeWin(w); return; } void freeWin(rdWin *w) { rdWin **wp = &windows; assert(w); /* remove from the window chain */ while ((*wp) != w) wp = &((*wp)->next); *wp = w->next; if (windows == 0) { DPRINT("All windows have been closed - exiting"); exit(0); } return; } static struct { char *cmd; void (*fn)(rdWin *, char *); } builtins[] = { { "Del", DelWin }, { 0, 0 } }; /* * check for builtin commands understood by the reader routines. */ static int rdBuiltin(rdWin *w, char *cmd, char *str) { int i; assert(w); assert(cmd); for (i = 0; builtins[i].cmd; i++) if (strcmp(builtins[i].cmd, cmd) == 0) { (*builtins[i].fn)(w, str); return 0; } return 1; } /* * "redisplay" a window that's already open. */ void rdGotoWin(rdWin *w) { if (rpc_goto(wilyq, w->id, ".")) { DPRINT("Could not redisplay open window"); } } rdWin * userpWin(void *ptr) { rdWin *w = windows; while (w && w->userp != ptr) w = w->next; return w; } /* * Some routines which attempt to extract the body of a window, * and store it in a file. if p0==p1==0, assume all the body is wanted. */ void rdBodyToFile(rdWin *w, char *filename) { FILE *fp; char *buf; assert(w); assert(filename); buf = salloc(w->bodylen+1); if (rpc_settag(wilyq, w->id, "Sending... ")) { DPRINT("Could not change tag"); return; } if (rpc_read(wilyq, w->id, 0, w->bodylen, buf)) { DPRINT("Could not retrieve body text"); return; } if ((fp = fopen(filename, "w"))) { (void)fprintf(fp,"%s",buf); fclose(fp); } else { DPRINT("Could not write body text to a file"); } free(buf); return; } static void alarm_handler(int signal) { if (signal != SIGALRM) { DPRINT("non-alarm signal received!"); return; } set_sig(); rdAlarmEvent = true; if (old_alarm_handler != SIG_DFL && old_alarm_handler != SIG_IGN) { DPRINT("Passing alarm onto previous handler"); (*old_alarm_handler)(signal); } alarm(rdRescanTimer); } static void set_sig(void) { (void)signal(SIGALRM, alarm_handler); } void rdSetRescanTimer(int secs) { rdRescanTimer = secs; if (old_alarm_handler == 0) { if ((old_alarm_handler = signal(SIGALRM, alarm_handler)) == SIG_ERR) { perror("signal"); rdRescanTimer = 0; return; } } alarm(rdRescanTimer); } void rdInclude(rdWin *w, char *str, size_t len) { size_t nlines; char *buf; char *prefix = "> "; size_t nlen, plen = strlen(prefix); ulong p0, p1; assert(w); assert(str); nlines = countlines(str, len); if (rpc_addr(wilyq, w->id, ".", &p0, &p1)) { DPRINT("Could not get address of dot"); return; } nlen = len + nlines*plen + 1; buf = salloc(nlen); prefixlines(str, len, prefix, plen, buf); if (rpc_insert(wilyq, w->id, p1, buf)) { DPRINT("Could not insert included text"); } w->bodylen += nlen; free(buf); } static size_t countlines(char *str, size_t len) { size_t nlines = 0; assert(str); while (len--) if (*str++ == '\n') nlines++; return nlines; } static void prefixlines(char *str, size_t len, char *prefix, size_t plen, char *buf) { assert(str && prefix); while (len) { strncpy(buf,prefix,plen); buf += plen; while (len-- && (*buf++ = *str++) != '\n') ; } *buf = 0; } wily-0.13.41/tools/old/wilytoys/reader2/mailheaders.h100444 2743 200 215 6120766353 20736 0ustar garypgrad#ifndef WILYMAIL_H #define WILYMAIL_H #include "headers.h" #include "mbox.h" #include "mail.h" #include "membuf.h" #endif /* WILYMAIL_H */ wily-0.13.41/tools/old/wilytoys/reader2/newsheaders.h100444 2743 200 237 6120766353 20774 0ustar garypgrad#ifndef WILYNEWS_H #define WILYNEWS_H #include "headers.h" #include "news.h" #include "newsrc.h" #include "nntp.h" #include "post.h" #endif /* WILYNEWS_H */ wily-0.13.41/tools/old/wilytoys/reader2/reader.h100444 2743 200 2633 6120766354 17751 0ustar garypgrad/* * reader.h - declarations for a mail/news reader toolkit for wily. */ #ifndef READER_H #define READER_H /* * We support two kinds of window - a list (mailboxes, newsgroups, subject lines) * and an article display. There can be more than one instance of each. */ typedef enum _rdWinType { rdList, rdArticle } rdWinType; /* * This makes the messages clearer */ enum { IsTag = 0, IsBody = 1 }; typedef struct _rdWin rdWin; typedef struct _rdItem rdItem; typedef struct _rdItemRange rdItemRange; typedef struct _Msgq Msgq; extern int rdMultiList; extern int rdMultiArt; struct _rdItem { ulong p0, p1; /* address of this item in the window. */ struct _rdItem *next; /* next item in the list */ }; struct _rdItemRange { int first, last; /* inclusive */ rdItem *i0, *i1; }; struct _rdWin { rdWinType wintype; int user; /* user info */ void *userp; /* ditto */ Id id; struct _rdWin *next; /* list storage */ char *title; /* what we think the title of this window is */ ulong taglen; /* length of tag, in characters */ ulong bodylen; /* length of body, in characters */ Msg *m; /* message from wily */ char *body; /* UTF text of an article window */ rdItem *items; /* The items in a list */ int protect; /* The user is writing to this window */ }; extern rdWin *windows; extern Mqueue *wilyq; extern Bool rdAlarmEvent; #endif /* !READER_H */ wily-0.13.41/tools/old/wilytoys/reader2/post.c100444 2743 200 17107 6120766355 17512 0ustar garypgrad/* * This file handles posting of new articles, follow-ups to * existing ones, and emailed replies. It's ripped pretty * much as-is from the mailer. */ #include "newsheaders.h" static void genpost(rdWin *w, nGroup *g, int num, char *to, char *ng, char *subj); static char *getNewsGroups(char *text); static char *version = "X-NewsReader: wilynews 0.1\n"; static char *post_tools = " deliver abort inc "; static char *rep_tools = " deliver abort inc "; static char *savefile; static int getWinNum(rdWin *w, nGroup *g, int first, char *arg) { int n; nWin *nw; assert(w); assert(g); nw = findNWin(w->userp); assert(nw); if (nw->kind == nDispArt) return artnumToItem(g,nw->artnum); else if (arg && *arg && (n = atoi(arg)) && (n = artnumToItem(g,n)) != -1) return n; else return first; } void nReply(rdWin *w, nGroup *g, int first, int last, char *arg) { int num; nArticle *a; char *from; DPRINT("Replying to an article"); num = getWinNum(w,g,first,arg); assert(num >= 0); a = g->artptrs[num]; assert(a); from = a->from; genpost(w, g, num, from, (char *)0, a->subj); return; } void nFollowUp(rdWin *w, nGroup *g, int first, int last, char *arg) { int num; nArticle *a; char *groups; DPRINT("Following up an article"); if (nntpCanPost() == 0) { fprintf(stderr,"Posting not allowed to this server\n"); return; } num = getWinNum(w,g,first,arg); assert(num >= 0); a = g->artptrs[num]; assert(a); if ((groups = getNewsGroups(a->body)) == 0) { DPRINT("Could not get list of groups for article"); groups = "junk"; } genpost(w, g, num, (char *)0, groups, a->subj); return; } void nFollRep(rdWin *w, nGroup *g, int first, int last, char *arg) { int num; nArticle *a; char *groups; DPRINT("Following up and replying to an article"); if (nntpCanPost() == 0) { fprintf(stderr,"Posting not allowed to this server\n"); return; } num = getWinNum(w,g,first,arg); assert(num >= 0); a = g->artptrs[num]; assert(a); if ((groups = getNewsGroups(a->body)) == 0) { DPRINT("Could not get list of groups for article"); groups = "junk"; } genpost(w, g, num, a->from, groups, a->subj); return; } void nPost(rdWin *w, nGroup *g, int first, int last, char *arg) { DPRINT("Posting an article"); if (nntpCanPost() == 0) { fprintf(stderr,"Posting not allowed to this server\n"); return; } genpost(w,g,first, (char *)0, "", (char *)0); return; } static void genpost(rdWin *w, nGroup *g, int num, char *to, char *newsgroups, char *subj) { nWin *nw, *rnw; static char body[300]; /* XXX */ char *me = getenv(FROMENV); char *re = subj? "Re: " : ""; char *tohdr = to? "\nTo: " : ""; char *nghdr = newsgroups? "\nNewsgroups: " : ""; char *title = newsgroups? "Post" : "Reply"; char *tools = newsgroups? post_tools : rep_tools; assert(w); nw = findNWin(w->userp); assert(nw); rnw = allocNWin(nCompArt, g, num); assert(rnw); rnw->isrep = (to != 0); rnw->ispost = (newsgroups != 0); if (!me) me = getenv("USER"); if (!me || !*me) { DPRINT("$WILYFROM and $USER are not valid - fill in from address yourself!"); me = ""; } if (!subj || !*subj || strncmp(subj, "Re: ", 4)==0) re = ""; sprintf(body,"From: %s%s%s%s%s\nSubject: %s%s\n%s\n", me, tohdr, to? to : "", nghdr, newsgroups? newsgroups : "", re, subj? subj : "", version); if (getArtWin(num, rnw, title, tools, body, 0)) { DPRINT("Could not get Reply window - leaving a mess in memory"); return; /* XXX - should clear up */ } DPRINT("Reply window ready"); return; } void nAbort(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw; assert(w); assert(w->userp); DPRINT("Aborting reply/comp"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Can't find associated window - aborting abort"); return; } if (nw->kind != nCompArt) { DPRINT("Abort isn't applied to a composition window - ignoring"); return; } fprintf(stderr,"Message aborted\n"); closeWin(w); freeNWin(nw); DPRINT("Abort done"); return; } void nDeliver(rdWin *w, nGroup *g, int first, int last, char *arg) { nWin *nw; char *filename = tmpnam((char *)0); assert(w); assert(w->userp); assert(filename); DPRINT("Delivering message"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Couldn't find associated composition window - aborting"); return; } if (nw->kind != nCompArt) { DPRINT("Deliver not applied to composition window - ignored"); return; } rdBodyToFile(w, filename); if (nw->isrep) dodeliver(w,filename); if (nw->ispost) nntpPost(filename); (void)remove(filename); DPRINT("Deliver done"); closeWin(w); freeNWin(nw); return; } void dodeliver(rdWin *w, char *filename) { static char cmd[100]; /* XXX another guess */ nWin *nw; assert(w); assert(w->userp); assert(MTU && *MTU); assert(filename); DPRINT("Attempting to deliver an article"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Could not find nWin for this window - aborting"); return; } sprintf(cmd,"%s < %s", MTU, filename); DPRINT("Delivery command is...."); DPRINT(cmd); fflush(stdout); system(cmd); DPRINT("Seems to have delivered"); return; } void nSavefile(rdWin *w, nGroup *g, int first, int last, char *arg) { assert(arg); if (savefile) { DPRINT("Savefile used to be...."); DPRINT(savefile); free(savefile); } savefile = sstrdup(arg); assert(savefile); DPRINT("Savefile now set to..."); DPRINT(savefile); } void nSave(rdWin *w, nGroup *g, int first, int last, char *arg) { FILE *fp; nWin *nw; nArticle *a; int n; assert(w); assert(w->userp); assert(first >= 0); assert(first <= last); nw = findNWin(w->userp); assert(nw); assert(last <= g->nunread); DPRINT("Saving articles"); if (savefile == 0) { fprintf(stderr,"No savefile yet: 'savefile filename'\n"); return; } if ((fp = fopen(savefile,"a")) == 0) { perror(savefile); DPRINT("Could not open savefile - article not saved"); return; } for (n = first; n <= last; n++) { a = g->artptrs[n]; assert(a); (void)fprintf(fp,"%s\n", a->body); printf("Written message %d to %s\n", n+1, savefile); /* count from 1 */ } fflush(stdout); fclose(fp); } void nInclude(rdWin *w, nGroup *g, int first, int last, char *arg) { doinclude(w,g,first,last,arg,0); } void nIncludeall(rdWin *w, nGroup *g, int first, int last, char *arg) { doinclude(w,g,first,last,arg,1); } void doinclude(rdWin *w, nGroup *g, int first, int last, char *arg, int all) { nWin *nw; rdWin *ow; int msgnum; /* message we're going to include */ nArticle *a; char *s; int n; assert(w); assert(w->userp); assert(arg); DPRINT("Including article text"); if ((nw = findNWin(w->userp)) == 0) { DPRINT("Could not find nWin for rdWin - aborting"); return; } if (nw->kind != nCompArt) { DPRINT("Not a composition window - include ignored"); return; } msgnum = nw->artnum; /* default value */ if (*arg) { if ((msgnum = atoi(arg)) < 1) { fprintf(stderr,"'%s' is an invalid message number\n", arg); return; } else { msgnum = artnumToItem(g, msgnum); } } if (msgnum < 0 || msgnum >= g->nunread) { fprintf(stderr,"Invalid msg number (%d-%d)\n", g->first, g->last); return; } a = g->artptrs[msgnum]; assert(a); s = all? a->body : a->body; /* XXX should have one option skip headers */ assert(s); rdInclude(w, s, strlen(s)); DPRINT("Done include"); } static char * getNewsGroups(char *text) { static char *buff; char *s, *t, *ng = "\nNewsgroups: "; size_t len = strlen(ng); if (buff) free(buff); if ((s = strstr(text, ng))) s += len; else if (strncmp(text, ng+1, len-1) == 0) s = text + len - 1; else return 0; if ((t = strchr(s, '\n')) == 0) return 0; len = t - s + 1; buff = salloc(len); strncpy(buff, s, len); buff[len-1] = 0; return buff; } wily-0.13.41/tools/old/wilytoys/reader2/post.h100444 2743 200 1534 6120766355 17474 0ustar garypgrad#ifndef WILYPOST_H #define WILYPOST_H void nReply(rdWin *w, nGroup *g, int first, int last, char *arg); void nPost(rdWin *w, nGroup *g, int first, int last, char *arg); void nFollowUp(rdWin *w, nGroup *g, int first, int last, char *arg); void nFollRep(rdWin *w, nGroup *g, int first, int last, char *arg); void nAbort(rdWin *w, nGroup *g, int first, int last, char *arg); void nDeliver(rdWin *w, nGroup *g, int first, int last, char *arg); void nSavefile(rdWin *w, nGroup *g, int first, int last, char *arg); void nSave(rdWin *w, nGroup *g, int first, int last, char *arg); void dodeliver(rdWin *w, char *filename); void nIncludeall(rdWin *w, nGroup *g, int first, int last, char *arg); void nInclude(rdWin *w, nGroup *g, int first, int last, char *arg); void doinclude(rdWin *w, nGroup *g, int first, int last, char *arg, int all); #endif /* !WILYPOST_H */ wily-0.13.41/tools/old/wilytoys/reader2/addr.c100444 2743 200 5645 6120766355 17423 0ustar garypgrad/* * addr.c - parse email addresses into something more readable. * smk 6/3/96. */ #include "headers.h" #include static char *trimws(char *str); static void whatsleft(char *copy, char *found, char *foundend, char **rest); static int angle(char *copy, char **es, char **ee); static int paren(char *copy, char **ns, char **ne); static int quotes(char *copy, char **ns, char **ne); static int findchars(char *copy, char **s, char **e, char c1, char c2); static int at(char *copy, char **es, char **ee); /* * parseaddr(addr, len, email, name) - parses addr into an email address and a full * name, based rather vaguely on RFC822: * if <...> found * use it for email address * use what's left as name * else if () or "" found * use it for name * use what's left as email * else if @ found * use it for email address * use what's left as name * else * use everything as both email address and name. */ void parseaddr(char *addr, int len, char **email, char **name) { static char copy[MAXFROMLINE+1]; char *cp, *e, *n, *z; assert(addr && *addr && email && name); strncpy(copy, addr, len); copy[len] = 0; cp = trimws(copy); assert(*cp); if (angle(cp, &e, &z)) whatsleft(cp,e,z, &n); else if (paren(cp, &n, &z)) whatsleft(cp,n,z,&e); else if (quotes(cp, &n, &z)) whatsleft(cp,n,z,&e); else if (at(cp, &e, &z)) whatsleft(cp,e,z,&n); else e = n = copy; *email = trimws(e); *name = trimws(n); return; } static char * trimws(char *str) { char *s; assert(str); while (isspace(*str)) str++; s = str + strlen(str) - 1; while (str < s && isspace(*s)) *s-- = 0; return str; } /* * found points to the located item. foundend points to the character * after the end of the item (where we'd put the null char). * If we find any alphanumeric data between copy and found, * we assume that it's the other part of the address string. * Otherwise, we take any alphanumeric data after foundend. */ static void whatsleft(char *copy, char *found, char *foundend, char **rest) { char *s; assert(copy <= found); for (s = copy; s < found; s++) if (isalnum(*s)) { *rest = s; *(found - 1) = *foundend = 0; return; } for (s = foundend; *s; s++) if (isalnum(*s)) { *rest = s; *foundend = 0; return; } *rest = found; *foundend = 0; return; } static int angle(char *copy, char **es, char **ee) { return findchars(copy,es,ee,'<', '>'); } static int paren(char *copy, char **ns, char **ne) { return findchars(copy,ns,ne,'(', ')'); } static int quotes(char *copy, char **ns, char **ne) { return findchars(copy,ns,ne,'"', '"'); } static int findchars(char *copy, char **s, char **e, char c1, char c2) { return (*s = strchr(copy,c1)) && *++(*s) && (*e = strchr(*s,c2)); } static int at(char *copy, char **es, char **ee) { char *a; if ((a = strchr(copy,'@')) == 0) return 0; for (*es = a; copy < *es && !isspace(**es); --*es); for (*ee = a; **ee && !isspace(**ee); (*ee)++); return 1; } wily-0.13.41/tools/old/wilytoys/toys/ 40755 2743 200 0 6133221322 15672 5ustar garypgradwily-0.13.41/tools/old/wilytoys/toys/Makefile100644 2743 200 404 6121344152 17411 0ustar garypgradW = /home/steve/src/9/orig/wily-0.9.8 CFLAGS = -Xc -g CPPFLAGS = -I$W -I$W/include -I$W/libXg LDFLAGS = -L$W/libXg -L$W/libmsg LDLIBS = -lmsg -lXg -lnsl -lsocket PROGS = bold wcat all: $(PROGS) install: cp $(PROGS) $(HOME)/bin/Wily nuke: $(RM) $(PROGS) wily-0.13.41/tools/old/wilytoys/toys/bold.c100644 2743 200 2400 6121340060 17045 0ustar garypgrad#include #include #include #include #include /* * XXX - current assumes that we won't be in mid-sequence when EOF is reached. */ #define MAGICBOLD 0x4000 #define MAGICITALIC 0x4100 #define MAGICITALICBOLD 0x4200 static long charset = MAGICITALIC; static void boldchar(int c, int overstrike) { char str[4], *s = str; Rune r = c + charset; switch (runetochar(s, &r)) { case 3: putchar(*s++); case 2: putchar(*s++); case 1: putchar(*s++); } } int main(int argc, char *argv[]) { int i = 0, b = 0,c; int state = 0; int outchar; int os = 0; while ((c = getopt(argc, argv, "ib")) != EOF) { switch (c) { case 'b': b++; break; case 'i': i++; break; default: exit(1); } } charset = b&&i? MAGICITALICBOLD : b? MAGICBOLD : MAGICITALIC; while ((c = getchar()) != EOF) { switch (state) { case 0: if (c == '_') state++; else putchar(c); break; case 1: if (c == 0x8) /* backspace */ state++; else { putchar('_'); putchar(c); state = 0; } break; case 2: boldchar(c,0); state = 0; break; default: fprintf(stderr,"We're screwed!\n"); exit(1); } } if (state) fprintf(stderr,"File was truncated!\n"); return 0; } wily-0.13.41/tools/old/wilytoys/toys/wcat.c100644 2743 200 1566 6121340060 17077 0ustar garypgrad#include #include #include #include #include #include #include void e(char *s) { perror(s); exit(1); } int main(int argc, char *argv[]) { char cwd[BUFSIZ+1], filename[BUFSIZ]; char *file; int isreal; Fd fd; Mqueue q[1]; Id id; int r; ulong len = 0; if (argc > 1) { file = argv[1]; isreal = 1; if (*file == '/') strcpy(filename, file); else { if (getcwd(cwd,BUFSIZ) == 0) e("getcwd"); sprintf(filename,"%s/%s", cwd, file); } } else { isreal = 0; sprintf(filename,"+stdin-%d",getpid()); } if ((fd = get_connect()) < 0) e("get_connect"); mq_init(q,fd); if (rpc_new(q, &id, filename, isreal)) e("rpc_new"); if (isreal) return 0; while ((r = fread(cwd, 1, BUFSIZ, stdin))) { cwd[r] = 0; if (rpc_insert(q, id, len, cwd)) e("rpc_insert"); len += r; } return 0; } wily-0.13.41/tools/old/wilytoys/toys/fetchurl100755 2743 200 1005 6121340135 17526 0ustar garypgrad#!/usr/local/bin/expect -f # Download an HTML file in a simplistic fashion. # Usage: fetchurl hostname filename # (parse the URL yourself...) set hostname [lindex $argv 0] set filename [lindex $argv 1] log_user 0 spawn telnet $hostname http expect { "Connected" { expect "Escape character is '^]'." send "GET $filename\n" expect "GET $filename\r\n" log_user 1 interact -o "\r" {} "Connection closed by foreign host." {} exit 0 } timeout { send_user "Could not connect to $hostname\n" exit 1 } } wily-0.13.41/tools/old/wilytoys/toys/html-ascii.pl100644 2743 200 14674 6121340135 20413 0ustar garypgrad# Routines for HTML to ASCII. # (fixed width font, no font changes for size, bold, etc) with a little # BUGS AND MISSING FEATURES # font tags (e.g. CODE, EM) cause an extra whitespace # e.g. foo, -> foo , # Jim Davis July 15 1994 # modified 3 Aug 94 to support MENU and DIR require "tformat.pl" || die "Could not load tformat.pl: $@\nStopped"; # Can be set by command line arg if (! defined($columns_per_line)) { $columns_per_line = 72;} if (! defined($flush_last_page)) { $flush_last_page = 1;} # amount to add to indentation $indent_left = 5; $indent_right = 5; # ignore contents inside HEAD. $ignore_text = 0; # Set variables in tformat $left_margin = 1; $right_margin = $columns_per_line; $bottom_margin = 0; ## Routines called by html.pl $Begin{"HEAD"} = "begin_head"; $End{"HEAD"} = "end_head"; sub begin_head { local ($element, $tag) = @_; $ignore_text = 1;} sub end_head { local ($element) = @_; $ignore_text = 0;} $Begin{"BODY"} = "begin_document"; sub begin_document { local ($element, $tag) = @_; &start_page();} $End{"BODY"} = "end_document"; sub end_document { local ($element) = @_; &fresh_line();} ## Headers $Begin{"H1"} = "begin_header"; $End{"H1"} = "end_header"; $Begin{"H2"} = "begin_header"; $End{"H2"} = "end_header"; $Begin{"H3"} = "begin_header"; $End{"H3"} = "end_header"; $Begin{"H4"} = "begin_header"; $End{"H4"} = "end_header"; $Skip_Before{"H1"} = 1; $Skip_After{"H1"} = 1; $Skip_Before{"H2"} = 1; $Skip_After{"H2"} = 1; $Skip_Before{"H3"} = 1; $Skip_After{"H3"} = 0; sub begin_header { local ($element, $tag) = @_; &skip_n_lines ($Skip_Before{$element}, 5);} sub end_header { local ($element) = @_; &skip_n_lines ($Skip_After{$element});} $Begin{"BR"} = "line_break"; sub line_break { local ($element, $tag) = @_; &fresh_line();} $Begin{"P"} = "begin_paragraph"; # if fewer than this many lines left on page, start new page $widow_cutoff = 5; sub begin_paragraph { local ($element, $tag) = @_; &skip_n_lines (1, $widow_cutoff);} $Begin{"BLOCKQUOTE"} = "begin_blockquote"; $End{"BLOCKQUOTE"} = "end_blockquote"; sub begin_blockquote { local ($element, $tag) = @_; $left_margin += $indent_left; $right_margin = $columns_per_line - $indent_right; &skip_n_lines (1);} sub end_blockquote { local ($element) = @_; $left_margin -= $indent_left; $right_margin = $columns_per_line; &skip_n_lines (1);} $Begin{"PRE"} = "begin_pre"; $End{"PRE"} = "end_pre"; sub begin_pre { local ($element, $tag) = @_; $whitespace_significant = 1;} sub end_pre { local ($element) = @_; $whitespace_significant = 0;} $Begin{"INPUT"} = "form_input"; sub form_input { local ($element, $tag, *attributes) = @_; if ($attributes{"value"} ne "") { &print_word_wrap($attributes{"value"});}} $Begin{"HR"} = "horizontal_rule"; sub horizontal_rule { local ($element, $tag) = @_; &fresh_line (); &print_n_chars ($right_margin - $left_margin, "-");} # Add code for IMG (use ALT attribute) # Ignore I, B, EM, TT, CODE (no font changes) ## List environments $Begin{"UL"} = "begin_itemize"; $End{"UL"} = "end_list_env"; $Begin{"OL"} = "begin_enumerated"; $End{"OL"} = "end_list_env"; $Begin{"MENU"} = "begin_menu"; $End{"MENU"} = "end_list_env"; $Begin{"DIR"} = "begin_dir"; $End{"DIR"} = "end_list_env"; $Begin{"LI"} = "begin_list_item"; # application-specific initialization routine sub html_begin_doc { @list_stack = (); $list_type = "bullet"; $list_counter = 0;} sub push_list_env { push (@list_stack, join (":", $list_type, $list_counter));} sub pop_list_env { ($list_type, $list_counter) = split (":", pop (@list_stack)); $left_margin -= $indent_left;} sub begin_itemize { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_menu { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_dir { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "bullet"; $list_counter = "*";} sub begin_enumerated { local ($element, $tag) = @_; &push_list_env(); $left_margin += $indent_left; $list_type = "enumerated"; $list_counter = 1;} sub end_list_env { local ($element) = @_; &pop_list_env(); # &fresh_line(); } sub begin_list_item { local ($element, $tag) = @_; $left_margin -= 2; &fresh_line(); &print_word_wrap("$list_counter "); if ($list_type eq "enumerated") {$list_counter++;} $left_margin += 2;} $Begin{"DL"} = "begin_dl"; sub begin_dl { local ($element, $tag) = @_; &skip_n_lines(1,5);} $Begin{"DT"} = "begin_defined_term"; $Begin{"DD"} = "begin_defined_definition"; $End{"DD"} = "end_defined_definition"; sub begin_defined_term { local ($element, $tag) = @_; &fresh_line();} sub begin_defined_definition { local ($element, $tag) = @_; $left_margin += $indent_left; &fresh_line();} sub end_defined_definition { local ($element) = @_; $left_margin -= $indent_left; &fresh_line();} $Begin{"META"} = "begin_meta"; # a META tag sets a value in the assoc array %Variable # i.e. sers $Variable{author} to "Rushdie" sub begin_meta { local ($element, $tag, *attributes) = @_; local ($variable, $value); $variable = $attributes{name}; $value = $attributes{content}; $Variable{$variable} = $value;} $Begin{"IMG"} = "begin_img"; sub begin_img { local ($element, $tag, *attributes) = @_; &print_word_wrap (($attributes{"alt"} ne "") ? $attributes{"alt"} : "[IMAGE]");} # URLs $Begin{"A"} = "begin_a"; sub begin_a { local ($element, $tag, *attributes) = @_; local ($href, $k); $href = $attributes{href}; $k = $main'wily_url++; $main'wily_urls{$k} = $href; &print_word_wrap ("[_u$k]["); } $End{"A"} = "end_a"; sub end_a { &print_word_wrap("]"); } # Content and whitespace. sub html_content { local ($string) = @_; unless ($ignore_text) { &print_word_wrap ($string);}} sub html_whitespace { local ($string) = @_; if (! $whitespace_significant) { die "Internal error, called html_whitespace when whitespace was not significant";} local ($i); for ($i = 0; $i < length ($string); $i++) { &print_whitespace (substr($string,$i,1));}} # called by tformat. Do nothing. sub do_footer { } sub do_header { } 1; wily-0.13.41/tools/old/wilytoys/toys/html2wily100755 2743 200 3066 6121340135 17656 0ustar garypgrad#!/usr/local/bin/perl -I/home/steve/bin/Wily # Program to generate ASCII text for HTML # Created by James R. Davis, July 15 1994 # Split a URL into its component parts sub split_url { local($method, $host, $port, $path); $_ = $_[0]; /^((http|ftp|news|mailto|gopher|telnet):)?(\/\/([^\/:]+)(:([0-9]+))?)?(.*)/; $method = $2; $host = $4; $port = $6; $path = $7; return ($method, $host, $port, $path); } # Convert a hyperlink URL into a FQU, if necessary. sub fqu { local($partial) = @_; local($full); local($pmethod, $phost, $pport, $ppath) = &split_url($partial); $pmethod = $basemethod if $pmethod eq ""; $phost = $basehost if $phost eq ""; $pport = $baseport if $pport eq ""; if ($pport eq "80") { $pport = ""; } else { $pport = ":" . $pport; } if ($phost eq $basehost) { if ($ppath !~ /^\//) { $ppath = $basepath . '/' . $ppath; } } $full = $pmethod . "://" . $phost . $pport . $ppath; return $full; } # get directory where this file is. {$0 =~ /^(.*)\/.*$/; $my_dir = $1; if ($my_dir !~ ?^/?) {$my_dir = $ENV{PWD} . "/" . $my_dir;} if ($my_dir =~ ?/$?) {chop ($my_dir);}} push(@INC, $my_dir); # Parse command line arguments. $file = shift; $baseurl = shift; ($basemethod, $basehost, $baseport, $basepath) = &split_url($baseurl); $baseport = "80" if $baseport eq ""; require "parse-html.pl" || die "Could not load parse-html.pl"; require "html-ascii.pl" || die "Could not load html-ascii.pl"; %wily_urls = (); $wily_url = 1; &parse_html ($file); foreach $k (keys %wily_urls) { $u = &fqu($wily_urls{$k}); print "[_u$k] [http $u]\n"; } wily-0.13.41/tools/old/wilytoys/toys/http100755 2743 200 740 6121340135 16656 0ustar garypgrad#!/bin/rc # http - get an HTTP URL, retrieve the file, convert it into something that looks # vaguely nice, and send it to a Wily window. # Usage: http http://site/path/name.html url = $1 tmpfile = /tmp/http$pid switch ($url) { case http:* eval `{echo $url | sed -e 's!http://\([^/]*\)\(.*\)!host=(\1);file=(\2)!'} case * echo Only http URLs supported >[1=2] exit 1 } if (~ $file ()) file = /; fetchurl $host $file > $tmpfile html2wily $tmpfile $url | wcat rm $tmpfile wily-0.13.41/tools/old/wilytoys/toys/parse-html.pl100644 2743 200 21450 6121340136 20424 0ustar garypgrad# HTML parser # Jim Davis, July 15 1994 # This is an HTML parser not an SGML parser. It does not parse a DTD, # The DTD is implicit in the code, and specific to HTML. # The processing of the HTML can be customized by the user by # 1) Defining routines to be called for various tags (see Begin and End arrays) # 2) Defining routines html_content and html_whitespace # This is not a validating parser. It does not check the content model # eg you can use DT outside a DL and it won't know. It is too liberal in # what tags are allowed to minimize what other tags. # Bugs - can't parse the prolog or whatever you call it # # # # %html; # ]> # modified 3 Aug to add a bunch of HTML 2.0 tags # modified 3 Sept to print HTML stack to STDERR not STDOUT, to add new # routines html_begin_doc and html_end_doc for application specific cleanup # and to break parse_html into two pieces. # modified 30 Sept 94. parse_attributes now handles tag attributes that # don't have values. thanks to Bill Simpson-Young # for the code. # modified 17 Apr 95 to support FORMS tags. $debug = 0; $whitespace_significant = 0; # global variables: # $line_buffer is line buffer # $line_count is input line number. $line_buffer = ""; $line_count = 0; sub parse_html { local ($file) = @_; open (HTML, $file) || die "Could not open $file: $!\nStopped"; &parse_html_stream (); close (HTML);} # Global input HTML is the handle to the stream of HTML sub parse_html_stream { local ($token, $new); ## initialization @stack=(); $line_count = 0; $line_buffer = ""; ## application specific initialization &html_begin_doc(); main: while (1) { # if whitespace does not matter, trim any leading space. if (! $whitespace_significant) { $line_buffer =~ s/^\s+//;} # now dispatch on the type of token if ($line_buffer =~ /^(\s+)/) { $token = $1; $line_buffer = $'; &html_whitespace ($token);} # This will lose if there is more than one comment on the line! elsif ($line_buffer =~ /^(\)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\]*\>)/) { $token = $1; $line_buffer = $'; &html_comment ($token);} elsif ($line_buffer =~ /^(\<\/[^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_etag ($token);} elsif ($line_buffer =~ /^(\<[^!\/][^\>]*\>)/) { $token = $1; $line_buffer = $'; &html_tag ($token);} elsif ($line_buffer =~ /^([^\s<]+)/) { $token = $1; $line_buffer = $'; $token = &substitute_entities($token); &html_content ($token); } else { # No valid token in buffer. Maybe it's empty, or maybe there's an # incomplete tag. So get some more data. $new = ; if (! defined ($new)) {last main;} # if we're trying to find a match for a tag, then get rid of embedded newline # this is, I think, a kludge if ($line_buffer =~ /^\ -1) { print STDERR "Stack not empty at end of document\n"; &print_html_stack();} } sub html_tag { local ($tag) = @_; local ($element) = &tag_element ($tag); local (%attributes) = &tag_attributes ($tag); # the tag might minimize (be an implicit end) for the previous tag local ($prev_element); while (&Minimizes(&stack_top_element(), $element)) { $prev_element = &stack_pop_element (); if ($debug) { print STDERR "MINIMIZING $prev_element with $element on $line_count\n";} &html_end ($prev_element, 0);} push (@stack, $tag); &html_begin ($element, $tag, *attributes); if (&Empty($element)) { pop(@stack); &html_end ($element, 0);} } sub html_etag { local ($tag) = @_; local ($element) = &tag_element ($tag); # pop stack until find matching tag. This is probably a bad idea, # or at least too general. local ( $prev_element) = &stack_pop_element(); until ($prev_element eq $element) { if ($debug) { print STDERR "MINIMIZING $prev_element with /$element on $line_count \n";} &html_end ($prev_element, 0); if ($#stack == -1) { print STDERR "No match found for /$element. You will lose\n"; last;} $prev_element = &stack_pop_element();} &html_end ($element, 1); } # For each element, the names of elements which minimize it. # This is of course totally HTML dependent and probably I have it wrong too $Minimize{"DT"} = "DT:DD"; $Minimize{"DD"} = "DT"; $Minimize{"LI"} = "LI"; $Minimize{"P"} = "P:DT:LI:H1:H2:H3:H4:BLOCKQUOTE:UL:OL:DL"; # Does element E2 minimize E1? sub Minimizes { local ($e1, $e2) = @_; local ($value) = 0; foreach $elt (split (":", $Minimize{$e1})) { if ($elt eq $e2) {$value = 1;}} $value;} $Empty{"BASE"} = 1; $Empty{"BR"} = 1; $Empty{"HR"} = 1; $Empty{"IMG"} = 1; $Empty{"ISINDEX"} = 1; $Empty{"LINK"} = 1; $Empty{"META"} = 1; $Empty{"NEXTID"} = 1; $Empty{"INPUT"} = 1; # Empty tags have no content and hence no end tags sub Empty { local ($element) = @_; $Empty{$element};} sub print_html_stack { print STDERR "\n ==\n"; foreach $elt (reverse @stack) {print STDERR " $elt\n";} print STDERR " ==========\n";} # The element on top of stack, if any. sub stack_top_element { if ($#stack >= 0) { &tag_element ($stack[$#stack]);}} sub stack_pop_element { &tag_element (pop (@stack));} # The element from the tag, normalized. sub tag_element { local ($tag) = @_; $tag =~ /<\/?([^\s>]+)/; local ($element) = $1; $element =~ tr/a-z/A-Z/; $element;} # associative array of the attributes of a tag. sub tag_attributes { local ($tag) = @_; $tag =~ /^<[A-Za-z]+ +(.*)>$/; &parse_attributes($1);} # string should be something like # KEY="value" KEY2="longer value" KEY3="tags o doom" # output is an associative array (like a lisp property list) # attributes names are not case sensitive, do I downcase them # Maybe (probably) I should substitute for entities when parsing attributes. sub parse_attributes { local ($string) = @_; local (%attributes); local ($name, $val); get: while (1) { if ($string =~ /^ *([A-Za-z]+)=\"([^\"]*)\"/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val; } elsif ($string =~ /^ *([A-Za-z]+)=(\S*)/) { $name = $1; $val = $2; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} elsif ($string =~ /^ *([A-Za-z]+)/) { $name = $1; $val = ""; $string = $'; $name =~ tr/A-Z/a-z/; $attributes{$name} = $val;} else {last;}} %attributes;} sub substitute_entities { local ($string) = @_; $string =~ s/&/&/g; $string =~ s/<//g; $string =~ s/"/\"/g; $string;} @HTML_elements = ( "A", "ADDRESS", "B", "BASE", "BLINK", # Netscape addition :-( "BLOCKQUOTE", "BODY", "BR", "CITE", "CENTER", # Netscape addition :-( "CODE", "DD", "DIR", "DFN", "DL", "DT", "EM", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HEAD", "HR", "HTML", "I", "ISINDEX", "IMG", "INPUT", "KBD", "LI", "LINK", "MENU", "META", "NEXTID", "OL", "OPTION", "P", "PRE", "SAMP", "SELECT", "STRIKE", "STRONG", "TITLE", "TEXTAREA", "TT", "UL", "VAR", ); sub define_element { local ($element) = @_; $Begin{$element} = "Noop"; $End{$element} = "Noop";} foreach $element (@HTML_elements) {&define_element($element);} # do nothing sub Noop { local ($element, $xxx) = @_; } # called when a tag begins. Dispatches using Begin sub html_begin { local ($element, $tag, *attributes) = @_; local ($routine) = $Begin{$element}; if ($routine eq "") { print STDERR "Unknown HTML element $element ($tag) on line $line_count\n";} else {eval "&$routine;"}} # called when a tag ends. Explicit is 0 if tag end is because of minimization # not that you should care. sub html_end { local ($element, $explicit) = @_; local ($routine) = $End{$element}; if ($routine eq "") { print STDERR "Unknown HTML element \"$element\" (END $explicit) on line $line_count\n";} else {eval "&$routine(\"$element\", $explicit)";}} sub html_content { local ($word) = @_; } sub html_whitespace { local ($whitespace) = @_;} sub html_comment { local ($tag) = @_;} # redefine these for application-specific initialization and cleanup sub html_begin_doc {} sub html_end_doc {} # return a "true value" when loaded by perl. 1; wily-0.13.41/tools/old/wilytoys/toys/man100755 2743 200 210 6121340325 16443 0ustar garypgrad#!/bin/rc { if (~ $1 *.[0-9]*) { nroff -man $* } else { PAGER='cat' exec /usr/bin/man $* } } | bold | perl -pe 's/\010.//g;' | wcat wily-0.13.41/tools/old/wilytoys/toys/make100755 2743 200 260 6121340364 16615 0ustar garypgrad#!/bin/rc # script to make errors from the C compiler look like addresses # to Wily. exec /usr/ccs/bin/make $* >[2=1] | perl -pe '$| = 1; s/"([^"]*)", line ([0-9]+)/\1:\2/;' wily-0.13.41/tools/old/wilytoys/toys/diff100755 2743 200 307 6121340364 16612 0ustar garypgrad#!/bin/rc # script to make line numbers from diff look like addresses # to Wily. f1 = $1 f2 = $2 exec /usr/bin/diff $* | perl -pe '$| = 1; s!^(([0-9]+)(.)([0-9]+).*)!\1 '^$f1^':\2 \3 '^$f2^':\4!;' wily-0.13.41/tools/old/wilytoys/toys/tformat.pl100644 2743 200 6142 6121340556 20013 0ustar garypgrad# Simple text formatter # Jim Davis 17 July 94 # current page, line, and column numbers. $page = 1; $line = 1; $column = 1; $left_margin = 1; $right_margin = 72; # lines on page before footer. or 0 if no limit. $bottom_margin = 58; # add newlines to make page be full length? $fill_page_length = 1; sub print_word_wrap { local ($word) = @_; if (($column + ($whitespace_significant ? 0 : 1) + length ($word) ) > ($right_margin + 1)) { &fresh_line();} if ($column > $left_margin && !$whitespace_significant) { print " "; $column++;} print $word; $column += length ($word);} sub print_whitespace { local ($char) = @_; if ($char eq " ") { $column++; print " ";} elsif ($char eq "\t") { &get_to_column (&tab_column($column));} elsif ($char eq "\n") { &new_line();} else { die "Unknown whitespace character \"$char\"\nStopped";} } sub tab_column { local ($c) = @_; (int (($c-1) / 8) + 1) * 8 + 1;} sub fresh_line { if ($column > $left_margin) {&new_line();} while ($column < $left_margin) { print " "; $column++;}} sub finish_page { # Add extra newlines to finish page. # You might not want to do this on the last page. if ($fill_page_length) { while ($line < $bottom_margin) {&cr();}} &do_footer (); $line = 1; $column = 1;} sub start_page { if ($page != 1) { &do_header ();}} sub print_n_chars { local ($n, $char) = @_; local ($i); for ($i = 1; $i <= $n; $i++) {print $char;} $column += $n;} # need one NL to end current line, and then N to get N blank lines. sub skip_n_lines { local ($n, $room_left) = @_; if ($bottom_margin > 0 && $line + $room_left >= $bottom_margin) { &finish_page(); &start_page();} else { local ($i); for ($i = 0; $i <= $n; $i++) {&new_line();}}} sub new_line { if ($bottom_margin > 0 && $line >= $bottom_margin) { &finish_page(); &start_page();} else {&cr();} &print_n_chars ($left_margin - 1, " ");} # used in footer and header where we don't respect the bottom margin. sub print_blank_lines { local ($n) = @_; local ($i); for ($i = 0; $i < $n; $i++) {&cr();}} sub cr { print "\n"; $line++; $column = 1;} # left, center, and right tabbed items sub print_lcr_line { local ($left, $center, $right) = @_; &print_tab_left (1, $left); &print_tab_center (($right_margin - $left_margin) / 2, $center); &print_tab_right ($right_margin, $right); &cr();} sub print_tab_left { local ($tab_column, $string) = @_; &get_to_column ($tab_column); print $string; $column += length ($string); } sub print_tab_center { local ($tab_column, $string) = @_; &get_to_column ($tab_column - (length($string) / 2)); print $string; $column += length ($string); } sub print_tab_right { local ($tab_column, $string) = @_; &get_to_column ($tab_column - length($string)); print $string; $column += length ($string); } sub get_to_column { local ($goal_column) = @_; if ($column > $goal_column) {print " "; $column++;} else { while ($column < $goal_column) { print " "; $column++;}}} wily-0.13.41/tools/old/wilytoys/toys/fixed.9.font100644 2743 200 3621 6121341011 20122 0ustar garypgrad17 14 0x0000 0x00FF lucm.latin1.9 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.41/tools/old/wilytoys/toys/prop.9.font100644 2743 200 3612 6121341011 20003 0ustar garypgrad16 13 0x0000 0x00FF lubs14 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.41/tools/old/wilytoys/toys/smk.9.font100644 2743 200 3733 6121341011 17621 0ustar garypgrad16 13 0x0000 0x00FF wilynormal 0x0100 0x017E lucm.latineur.9 0x0180 0x01F0 matty.latinext.9 0x0250 0x02E9 lucm.ipa.9 0x0300 0x0308 matty.gendiacritics.9 0x0370 0x0372 matty.greekpunc.9 0x0386 0x03F5 lucm.greek.9 0x0400 0x0475 misc.cyrillic.9 0x2000 0x2044 lucm.genpunc.9 0x2070 0x208E lucm.supsub.9 0x20A0 0x20AA lucm.currency.9 0x2100 0x2138 matty.letterlike.9 0x2190 0x21EA misc.arrows 0x2200 0x227F matty.math1 0x2280 0x22F1 matty.math2 0x2300 0x232C matty.tech 0x2500 0x257F matty.chart 0x2580 0x2595 matty.blocks 0x25a0 0x25ee matty.geometric 0x2600 0x266F misc.ding 0x3000 0x303f jis.jis3000.16 0x3041 0x309e jis.hiragana.16 0x30a1 0x30fe jis.katakana.16 0x4000 0x40FF wilybold 0x4100 0x41FF wilyitalic 0x4200 0x42FF wilybolditalic 0x4e00 0x4fff jis.jis4e00.16 0x5000 0x51ff jis.jis5000.16 0x5200 0x53ff jis.jis5200.16 0x5400 0x55ff jis.jis5400.16 0x5600 0x57ff jis.jis5600.16 0x5800 0x59ff jis.jis5800.16 0x5a00 0x5bff jis.jis5a00.16 0x5c00 0x5dff jis.jis5c00.16 0x5e00 0x5fff jis.jis5e00.16 0x6000 0x61ff jis.jis6000.16 0x6200 0x63ff jis.jis6200.16 0x6400 0x65ff jis.jis6400.16 0x6600 0x67ff jis.jis6600.16 0x6800 0x69ff jis.jis6800.16 0x6a00 0x6bff jis.jis6a00.16 0x6c00 0x6dff jis.jis6c00.16 0x6e00 0x6fff jis.jis6e00.16 0x7000 0x71ff jis.jis7000.16 0x7200 0x73ff jis.jis7200.16 0x7400 0x75ff jis.jis7400.16 0x7600 0x77ff jis.jis7600.16 0x7800 0x79ff jis.jis7800.16 0x7a00 0x7bff jis.jis7a00.16 0x7c00 0x7dff jis.jis7c00.16 0x7e00 0x7fff jis.jis7e00.16 0x8000 0x81ff jis.jis8000.16 0x8200 0x83ff jis.jis8200.16 0x8400 0x85ff jis.jis8400.16 0x8600 0x87ff jis.jis8600.16 0x8800 0x89ff jis.jis8800.16 0x8a00 0x8bff jis.jis8a00.16 0x8c00 0x8dff jis.jis8c00.16 0x8e00 0x8fff jis.jis8e00.16 0x9000 0x91ff jis.jis9000.16 0x9200 0x93ff jis.jis9200.16 0x9400 0x95ff jis.jis9400.16 0x9600 0x97ff jis.jis9600.16 0x9800 0x99ff jis.jis9800.16 0x9a00 0x9bff jis.jis9a00.16 0x9c00 0x9dff jis.jis9c00.16 0x9e00 0x9fff jis.jis9e00.16 0xe000 0xe05f matty.tengwar.9 0xfee0 0xff5e lucm.latin1.9 0xfffd 0xfffd pelm.fffd.9 wily-0.13.41/tools/old/wilytoys/toys/fonts.alias100644 2743 200 536 6121342526 20126 0ustar garypgradwilynormal "-adobe-new century schoolbook-medium-r-normal--12-120-75-75-p-70-iso8859-1" wilybold "-adobe-new century schoolbook-bold-r-normal--12-120-75-75-p-70-iso8859-1" wilyitalic "-adobe-new century schoolbook-medium-i-normal--12-120-75-75-p-70-iso8859-1" wilybolditalic "-adobe-new century schoolbook-bold-i-normal--12-120-75-75-p-70-iso8859-1" wily-0.13.41/tools/old/wilytoys/toys/README100644 2743 200 11015 6121344112 16665 0ustar garypgradThese files are a few toys that I thought I would share with other people. They're not at all polished, and one of them was only just finished today, but hey - that's life on the edge. What is here: - working wcat to shove files into wily. - filter to convert man pages into something pretty and readable. - some scripts to view HTML web pages with wily. - a couple of useful wily wrapper scripts. What you need: - perl. 4.036 is what I use, but you might get away with v5. - Expect, if you want to be able to download web pages. Actually, there are plain perl scripts around on the net to do this, but I couldn't get the damn things to work on my machine, and I was in a hurry. I recommend trying one of the existing perl things (get_url, etc.) before installing Expect, if you haven't already got it. - the fonts from Matty's 9term distribution (if you want pretty man pages). - wily 0.98. - luck. Major Credit where credit is due: - The Perl scripts used for converting HTML files into something vaguely readable is by James R. Davis. I grabbed it from the web, and made a few minor changes to make it function as a wily browser, but the proper work's all James'. To build wcat: - Fiddle with the Makefile, so that it can find your wily distribution. - make all. If you want, you might want to bodge ./make, and put it somewhere where wily can find it. I use it to mangle the output of Sun's ANSI compiler into wily-style file:line references. There isn't a lot of point including it here, except that perl allows you to see each error message as it appears, with minimal buffering. there's also a "diff" script which does much the same thing. Well, I like it... The Makefile also builds "bold". We'll come back to that shortly. Man page viewer: This is an horrendous cheat, as suggested by either myself or gary/matty a while ago in the list (I forget who). Basically, it uses the large Unicode character set to have normal, italic and bold versions of the same characters within your set, and just displays the appropriate one according to the output of nroff/man. This required a little bit of setting up and munging around with fonts. These are my notes which I scrawled at the time that I got this going: Unpacked matty's font distribution. ran mkfontdir in the bdf directory. Selected a font I liked using xfontsel(1). Created bdf/fonts.alias, containing the alias "wilynormal" for this preferred font. Put wilynormal as the first font in smk.9.font (which I'd copied from prop.9.font). Add the font directory to the X server's font path with xset fp+ /home/steve/lib/fonts/bdf Changed bin/acme to have smk.9.font and fixed.9.font args. Checked all was ok by viewing src/9/hacked/9term/utf.test I've included my font files and the fonts.alias file so that you can see what I've done. Note that the extra character sets appear in the 0x4000-odd range, and that this is hard-coded into the source for "bold.c". The man page viewer ("man") takes standard man arguments, and passes the output of normal man through bold, to get the pretty fonts, and then into wcat to display the file in wily. It doesn't get everything right, but it's good enough for what I use it for. You can also B2B1 on filename.1 files to view them directly. HTML web browser: This has three parts. The first is fetchurl, a quick Expect script that will grab the output of a telnet connection to some web server. Use a proper perl program to do this if you can get one. For starters, mine only handles http URLs. The second part is the driver, http. This takes as an argument a normal URL, e.g. "http http://www.w3.org". It uses fetchurl to grab the file, and then passes it to the final part, html2wily. Html2wily does the clever bit of generating readable ASCII out of the HTML. The bit I've added is to support URLs within the file: given a URL such as Some Text, you end up with this: [_u1][Some Text]. At the bottom of the file, you see: [_u1][http http://www.foo.com/file.html]. The idea is that you can B3 on the _u1 to move between the highlighted text and the URL that goes with it. If you decide to follow the URL, you double-click beside the [ or ], to select the whole command, and B2 it. The process then begins again. Incidentally, there are a few broken bits in this, especially where partial URLs are converted into full ones, but that's life. This thing took about 2 hours to write, this morning. Hope this of some use... Steve Kilbane, 12 March 1996. wily-0.13.41/tools/quanstro/ 40755 2743 200 0 6141227423 14076 5ustar garypgradwily-0.13.41/tools/quanstro/Makefile100644 2743 200 542 6141227422 15613 0ustar garypgradW = $(HOME)/src/plan9/wily/wily-0.11.1 CPPFLAGS = -I$W -I$W/include -I$W/libXg -I$W/sam/include LDFLAGS = -L$W/sam/libXg -L$W/libmsg LDLIBS = -lmsg -lXg # gmake CFLAGS = -g -Wall -ansi CFLAGS = -g -Wall -ansi $(CPPFLAGS) $(LDLIBS) CC=gcc PROGS = wcat windows wreplace wattach wread all: $(PROGS) install: cp $(PROGS) $(binpath) clean: rm $(PROGS) wily-0.13.41/tools/quanstro/wattach.c100644 2743 200 2724 6141227422 15776 0ustar garypgrad#include #include #include #include #include #include #include volatile Bool control_c = false; void catch(int sig){ signal(sig, catch); control_c = true; } void exits(const char*whine){ if (*whine){ fprintf(stderr, "%s\n", whine); exit(1); } exit(0); } const char* decode(Msg* m){ switch(m->t){ default: return "unknown message type"; case WEexec: if (!strcmp(m->s, "Del")){ exit(1);} printf("exec %5.5d %s\n", m->w, m->s); break; case WEgoto: printf("goto %5.5d {%lu,%lu} %s\n", m->w, m->r.p0, m->r.p1, m->s); break; case WEdestroy: printf("dest %5.5d \n", m->w); break; case WEreplace: printf("repl %5.5d {%lu,%lu} %s\n", m->w, m->r.p0, m->r.p1, m->s); break; } fflush(stdout); return 0; } void main(int c, char**v){ Msg m; int fd; Handle *h; Id id; char* r; const char* s; c--; v++; if (c != 1){ exits("usage: wattach "); } id = strtoul(*v, &r, 0); if (*r){ exits("doesn't look integerish"); } signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ exits("can't open wilyfifo"); } h = rpc_init(fd); s = rpc_attach(h, id, WEexec | WEgoto | WEreplace | WEdestroy); if (s){ exits(s); } while (0 == rpc_event(h,&m)){ decode(&m); free(m.s); if (control_c){ break; } } /* rpc_detach(h, id);*/ rpc_freehandle(h); exit(control_c ? 0 : -1); } wily-0.13.41/tools/quanstro/wcat.c100644 2743 200 4637 6141227422 15306 0ustar garypgrad#include #include #include #include #include #include #include volatile Bool control_c = false; enum { BLOCK = 8 * 1024 }; void e(const char *s) { perror(s); exit(1); } void catch(int sig){ signal(sig, catch); control_c = true; } Bool map_file(const char* file, Handle* q, const char* title){ char* p; char filename[PATH_MAX+1]; char cwd[PATH_MAX+1]; Id id; if (!title){ if (*file == '/'){ strcpy(filename, file); } else { p = getcwd(cwd, PATH_MAX); if (!p){ fprintf(stderr, "can't get cwd()"); return false; } } } else { sprintf(filename, "+%s", title); } sprintf(filename,"%s/%s", cwd, file); if (rpc_new(q, filename, &id)){ fprintf(stderr, "rpc_new(q, %s, 0, id) fails\n", filename); return false; } fprintf(stderr, "%d\n", id); return true; } Bool map_stream(int fd, Handle* q, const char* title){ char block[BLOCK]; char winname[50]; Id id; ulong len; long r; Range R; const char* s; if (!title){ sprintf(winname,"+stdin-%d",getpid()); } else { sprintf(winname, "+%s", title); } if (rpc_new(q, winname, &id)){ fprintf(stderr, "rpc_new(q, %s, 0, id) fails\n", winname); return false; } fprintf(stderr, "%d\n", id); R.p0 = 0; R.p1 = 0; for (len = 0; (r = read(fd, block, BLOCK))>0; len += r){ block[r] = 0; s = rpc_replace(q, id, R, block); if (s){ fprintf(stderr, "rpc_replace(q,%d,{%lu,%lu}, ) fails with %s\n", id, len, len, s); return false; } s = rpc_goto(q, &id, &R, (char*)":$", false); if (s){ fprintf(stderr, "rpc_goto(q,%d,{%lu,%lu}, ':$') fails with %s\n", id, R.p0, R.p0, s); return false; } } return true; } void main(int c, char**v){ int fd; Handle *h; Bool taetig; Bool status; char* title; signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ e("can't open wilyfifo"); } h = rpc_init(fd); status = true; taetig = false; title = 0; for (v++; *v; v++){ if (0 == strcmp(*v, "-t")){ v++; if (*v){ title = *v; } continue; } taetig = true; if (0 == strcmp(*v, "-")){ status |= map_stream(0, h, title); } else { status |= map_file(*v, h, title); } if (control_c){ goto out; } } if (!taetig){ status |= map_stream(0, h, title); } out: status |= control_c; rpc_freehandle(h); if (status){ exit(0); } exit(1); } wily-0.13.41/tools/quanstro/windows.c100644 2743 200 1204 6141227423 16026 0ustar garypgrad#include #include #include #include #include #include #include volatile Bool control_c = false; void e(const char *s) { perror(s); exit(1); } void catch(int sig){ signal(sig, catch); control_c = true; } void main(int c, char**v){ int fd; Handle *h; Bool status; char *p; signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ e("can't open wilyfifo"); } h = rpc_init(fd); status = true; rpc_list(h, &p); printf("%s", p); free(p); rpc_freehandle(h); exit(!status); } wily-0.13.41/tools/quanstro/wread.c100644 2743 200 2646 6141227423 15451 0ustar garypgrad#include #include #include #include #include #include #include volatile Bool control_c = false; enum { BLOCK = 8 * 1024 }; void exits(const char*whine){ if (*whine){ fprintf(stderr, "%s\n", whine); exit(1); } exit(0); } void catch(int sig){ signal(sig, catch); control_c = true; } const char* read_buf(Handle *h, long id, long len){ Range R; long p; char buf[UTFmax * BLOCK]; const char* s; int delta; for(p = 0; p + BLOCK <= len; p += BLOCK){ R.p0 = p; R.p1 = p + BLOCK-1; s = rpc_read(h, id, R, buf); if (s){ return s; } delta=strlen(&buf[BLOCK-1]); write(1, buf, BLOCK+delta); } R.p0 = p; R.p1 = len; s = rpc_read(h, id, R, buf); if (s){ return s; } delta=strlen(&buf[len-p]); write(1, buf, R.p1 - R.p0 + delta); /* wrong! */ return 0; } void main(int c, char**v){ int fd; Handle *h; Bool status; const char* s; Range R; long id; char* r; c--; v++; if (c != 1){ exits("usage: wread "); } id = strtoul(*v, &r, 0); if (*r){ exits("doesn't look integerish"); } signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ exits("can't open wilyfifo"); } h = rpc_init(fd); s=rpc_goto(h, (Id*)&id, &R, (char*)":$", false); if (s){ exits(s); } read_buf(h, id, R.p1); rpc_freehandle(h); exit(!status); } wily-0.13.41/tools/quanstro/wreplace.c100644 2743 200 4026 6141227423 16143 0ustar garypgrad#include #include #include #include #include #include #include volatile Bool control_c = false; enum { BLOCK = 8 * 1024 }; void e(const char *s) { perror(s); exit(1); } void catch(int sig){ signal(sig, catch); control_c = true; } Bool map_stream(int fd, Handle* h, long id, const char* range){ char block[BLOCK]; ulong len; long r; const char*s; Range R; s=rpc_goto(h, (Id*)&id, &R, (char*)range, true); if (s){ fprintf(stderr, "rpc_goto -> %s\n", s); return false; } fprintf(stderr, "%ld\n", id); for (len = 0; (r = read(fd, block, BLOCK))>0; len += r){ block[r] = 0; if (rpc_replace(h, id, R, block)){ fprintf(stderr, "rpc_insert(q,%ld,%ld,%ld, ) fails\n", id, len, len); return 0; } R.p0 = R.p1 = len; } return 0; } long getLong(const char* s){ char* r; ulong l; l = strtoul(s,&r,0); if (*r){ e("want long integer"); } return l; } void main(int c, char**v){ int fd; int f; Handle* h; Bool taetig; Bool status; long id; const char* range; signal(SIGHUP, catch); signal(SIGINT, catch); signal(SIGQUIT, catch); signal(SIGTERM, catch); fd = client_connect(); if (-1 == fd){ e("can't open wilyfifo"); } h = rpc_init(fd); status = true; taetig = false; for (v++; *v; v++){ id = -1; range = ":,"; if (0 == strcmp(*v, "-i")){ v++; if (*v){ id = getLong(*v++); } } if (0 == strcmp(*v, "-r")){ v++; if (*v){ range = *v++; } } if (-1 == id){ e("missing id"); } if (!*v){ break; } taetig = true; if (0 == strcmp(*v, "-")){ status |= map_stream(0, h, id, range); } else { f = open(*v, 0, 0666); if (-1 == f){ fprintf(stderr, "can't open file %s\n", *v); } else { status |= map_stream(f, h, id, range); close(f); } } if (control_c){ goto out; } } if (!taetig){ if (-1 == id){ e("missing id"); } status |= map_stream(0, h, id, range); } out: status |= control_c; rpc_freehandle(h); if (status){ exit(0); } exit(1); } wily-0.13.41/tools/win/ 40755 2743 200 0 6352450210 13013 5ustar garypgradwily-0.13.41/tools/win/README100644 2743 200 2010 6250475275 14000 0ustar garypgradThis is a collection of tools for wily. It should be unpacked in the base wily directory (i.e., in the same directory as libmsg). It includes a pseudo-terminal based terminal emulator, commands to search for and replace text, a manual page interface, and a tags interface. See INSTALL for instructions on compiling and installing. Please send bug reports to the author at alan@oldp.nmsu.edu. Copyright (c) 1996 by Alan Watson (alan@oldp.nmsu.edu). Written by Alan Watson. Not derived from licensed software. Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions: 1. The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it. 2. The origin of this software must not be misrepresented, either by explicit claim or by omission. 3. Altered versions must be plainly marked as such, and must not be misrepresented as being the original software. wily-0.13.41/tools/win/INSTALL100644 2743 200 16446 6250475275 14213 0ustar garypgradBasic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. wily-0.13.41/tools/win/configure100755 2743 200 75445 6347424747 15102 0ustar garypgrad#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated automatically using autoconf version 2.4 # Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc. # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. # Defaults: ac_help= ac_default_prefix=/usr/local # Any additions from configure.in: # Initialize some variables set by options. # The variables have the same names as the options, with # dashes changed to underlines. build=NONE cache_file=./config.cache exec_prefix=NONE host=NONE no_create= nonopt=NONE no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= target=NONE verbose= x_includes=NONE x_libraries=NONE # Initialize some other variables. subdirs= ac_prev= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval "$ac_prev=\$ac_option" ac_prev= continue fi case "$ac_option" in -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; *) ac_optarg= ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case "$ac_option" in -build | --build | --buil | --bui | --bu | --b) ac_prev=build ;; -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*) build="$ac_optarg" ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file="$ac_optarg" ;; -disable-* | --disable-*) ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` eval "enable_${ac_feature}=no" ;; -enable-* | --enable-*) ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } fi ac_feature=`echo $ac_feature| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "enable_${ac_feature}='$ac_optarg'" ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix="$ac_optarg" ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he) # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat << EOF Usage: configure [options] [host] Options: [defaults in brackets after descriptions] Configuration: --cache-file=FILE cache test results in FILE --help print this message --no-create do not create output files --quiet, --silent do not print \`checking...' messages --version print the version of autoconf that created configure Directory and file names: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=PREFIX install architecture-dependent files in PREFIX [same as prefix] --srcdir=DIR find the sources in DIR [configure dir or ..] --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names Host type: --build=BUILD configure for building on BUILD [BUILD=HOST] --host=HOST configure for HOST [guessed] --target=TARGET configure for TARGET [TARGET=HOST] Features and packages: --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR --enable and --with options recognized:$ac_help EOF exit 0 ;; -host | --host | --hos | --ho) ac_prev=host ;; -host=* | --host=* | --hos=* | --ho=*) host="$ac_optarg" ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix="$ac_optarg" ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix="$ac_optarg" ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix="$ac_optarg" ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name="$ac_optarg" ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site="$ac_optarg" ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir="$ac_optarg" ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target="$ac_optarg" ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers) echo "configure generated by autoconf version 2.4" exit 0 ;; -with-* | --with-*) ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` case "$ac_option" in *=*) ;; *) ac_optarg=yes ;; esac eval "with_${ac_package}='$ac_optarg'" ;; -without-* | --without-*) ac_package=`echo $ac_option|sed -e 's/-*without-//'` # Reject names that are not valid shell variable names. if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } fi ac_package=`echo $ac_package| sed 's/-/_/g'` eval "with_${ac_package}=no" ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes="$ac_optarg" ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries="$ac_optarg" ;; -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } ;; *) if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then echo "configure: warning: $ac_option: invalid host type" 1>&2 fi if test "x$nonopt" != xNONE; then { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } fi nonopt="$ac_option" ;; esac done if test -n "$ac_prev"; then { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } fi trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 # File descriptor usage: # 0 standard input # 1 file creation # 2 errors and warnings # 3 some systems may open it to /dev/tty # 4 used on the Kubota Titan # 6 checking for... messages and results # 5 compiler messages saved in config.log if test "$silent" = yes; then exec 6>/dev/null else exec 6>&1 fi exec 5>./config.log echo "\ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. " 1>&5 # Strip out --no-create and --no-recursion so they do not pile up. # Also quote any args containing shell metacharacters. ac_configure_args= for ac_arg do case "$ac_arg" in -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c) ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) ac_configure_args="$ac_configure_args '$ac_arg'" ;; *) ac_configure_args="$ac_configure_args $ac_arg" ;; esac done # NLS nuisances. # Only set LANG and LC_ALL to C if already set. # These must not be set unconditionally because not all systems understand # e.g. LANG=C (notably SCO). if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi if test "${LANG+set}" = set; then LANG=C; export LANG; fi # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -rf conftest* confdefs.h # AIX cpp loses on an empty file, so make sure it contains at least a newline. echo > confdefs.h # A filename unique to this package, relative to the directory that # configure is in, which we can look for to find out if srcdir is correct. ac_unique_file=../../wily/wily.c # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then its parent. ac_prog=$0 ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. srcdir=$ac_confdir if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } else { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } fi fi srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` # Prefer explicitly selected file to automatically selected ones. if test -z "$CONFIG_SITE"; then if test "x$prefix" != xNONE; then CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" else CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi fi for ac_site_file in $CONFIG_SITE; do if test -r "$ac_site_file"; then echo "loading site script $ac_site_file" . "$ac_site_file" fi done if test -r "$cache_file"; then echo "loading cache $cache_file" . $cache_file else echo "creating cache $cache_file" > $cache_file fi ac_ext=c # CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. ac_cpp='$CPP $CPPFLAGS' ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5 2>&5' ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5 2>&5' if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then ac_n= ac_c=' ' ac_t=' ' else ac_n=-n ac_c= ac_t= fi else ac_n= ac_c='\c' ac_t= fi ac_aux_dir= for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do if test -f $ac_dir/install-sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f $ac_dir/install.sh; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break fi done if test -z "$ac_aux_dir"; then { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } fi ac_config_guess=$ac_aux_dir/config.guess ac_config_sub=$ac_aux_dir/config.sub ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # ./install, which can be erroneously created by make from ./install.sh. echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 if test -z "$INSTALL"; then if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do # Account for people who put trailing slashes in PATH elements. case "$ac_dir/" in /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. for ac_prog in ginstall installbsd scoinst install; do if test -f $ac_dir/$ac_prog; then if test $ac_prog = install && grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. # OSF/1 installbsd also uses dspmsg, but is usable. : else ac_cv_path_install="$ac_dir/$ac_prog -c" break 2 fi fi done ;; esac done IFS="$ac_save_ifs" # As a last resort, use the slow shell script. test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh" fi INSTALL="$ac_cv_path_install" fi echo "$ac_t""$INSTALL" 1>&6 # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_prog_CC="gcc" break fi done IFS="$ac_save_ifs" test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc" fi fi CC="$ac_cv_prog_CC" if test -n "$CC"; then echo "$ac_t""$CC" 1>&6 else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.c <&5 | egrep yes >/dev/null 2>&1; then ac_cv_prog_gcc=yes else ac_cv_prog_gcc=no fi fi echo "$ac_t""$ac_cv_prog_gcc" 1>&6 if test $ac_cv_prog_gcc = yes; then GCC=yes if test "${CFLAGS+set}" != set; then echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_prog_gcc_g'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then ac_cv_prog_gcc_g=yes else ac_cv_prog_gcc_g=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_prog_gcc_g" 1>&6 if test $ac_cv_prog_gcc_g = yes; then CFLAGS="-g -O" else CFLAGS="-O" fi fi else GCC= test "${CFLAGS+set}" = set || CFLAGS="-g" fi echo $ac_n "checking for working const""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <j = 5; } { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ const int foo = 10; } ; return 0; } EOF if eval $ac_compile; then rm -rf conftest* ac_cv_c_const=yes else rm -rf conftest* ac_cv_c_const=no fi rm -f conftest* fi echo "$ac_t""$ac_cv_c_const" 1>&6 if test $ac_cv_c_const = no; then cat >> confdefs.h <<\EOF #define const EOF fi for ac_prog in rc RC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_path_RC'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else case "$RC" in /*) ac_cv_path_RC="$RC" # Let the user override the test with a path. ;; *) IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" for ac_dir in $PATH; do test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$ac_word; then ac_cv_path_RC="$ac_dir/$ac_word" break fi done IFS="$ac_save_ifs" ;; esac fi RC="$ac_cv_path_RC" if test -n "$RC"; then echo "$ac_t""$RC" 1>&6 else echo "$ac_t""no" 1>&6 fi test -n "$RC" && break done echo $ac_n "checking for -lnsl""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_nsl'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lnsl $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo nsl | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi echo $ac_n "checking for -lsocket""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_lib_socket'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" LIBS="-lsocket $LIBS" cat > conftest.$ac_ext <&6 ac_tr_lib=HAVE_LIB`echo socket | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi for ac_func in _getpty do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < /* Override any gcc2 internal prototype to avoid an error. */ char $ac_func(); int main() { return 0; } int t() { /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined (__stub_$ac_func) || defined (__stub___$ac_func) choke me #else $ac_func(); #endif ; return 0; } EOF if eval $ac_link; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else rm -rf conftest* eval "ac_cv_func_$ac_func=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_func=HAVE_`echo $ac_func | tr '[a-z]' '[A-Z]'` cat >> confdefs.h <&6 fi done echo $ac_n "checking for /dev/ptmx""... $ac_c" 1>&6 if /bin/test -e /dev/ptmx ; then echo "$ac_t""yes" 1>&6 cat >> confdefs.h <<\EOF #define HAVE_DEV_PTMX 1 EOF else echo "$ac_t""no" 1>&6 fi echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else # This must be in double quotes, not single quotes, because CPP may get # substituted into the Makefile and "${CC-cc}" will confuse make. CPP="${CC-cc} -E" # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext < Syntax Error EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then : else echo "$ac_err" >&5 rm -rf conftest* CPP=/lib/cpp fi rm -f conftest* fi rm -f conftest* ac_cv_prog_CPP="$CPP" fi CPP="$ac_cv_prog_CPP" else ac_cv_prog_CPP="$CPP" fi echo "$ac_t""$CPP" 1>&6 for ac_hdr in sys/ptem.h do ac_safe=`echo "$ac_hdr" | tr './\055' '___'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext < EOF eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" ac_err=`grep -v '^ *+' conftest.out` if test -z "$ac_err"; then rm -rf conftest* eval "ac_cv_header_$ac_safe=yes" else echo "$ac_err" >&5 rm -rf conftest* eval "ac_cv_header_$ac_safe=no" fi rm -f conftest* fi if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then echo "$ac_t""yes" 1>&6 ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'` cat >> confdefs.h <&6 fi done trap '' 1 2 15 cat > confcache <<\EOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # EOF # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. (set) 2>&1 | sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=\${\1='\2'}/p" \ >> confcache if cmp -s $cache_file confcache; then : else if test -w $cache_file; then echo "updating cache $cache_file" cat confcache > $cache_file else echo "not updating unwritable cache $cache_file" fi fi rm -f confcache trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Any assignment to VPATH causes Sun make to only execute # the first set of double-colon rules, so remove it if not needed. # If there is a colon in the path, we need to keep it. if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' fi trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. cat > conftest.defs <<\EOF s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%-D\1=\2%g s%[ `~#$^&*(){}\\|;'"<>?]%\\&%g s%\[%\\&%g s%\]%\\&%g s%\$%$$%g EOF DEFS=`sed -f conftest.defs confdefs.h | tr '\012' ' '` rm -f conftest.defs # Without the "./", some shells look in PATH for config.status. : ${CONFIG_STATUS=./config.status} echo creating $CONFIG_STATUS rm -f $CONFIG_STATUS cat > $CONFIG_STATUS </dev/null | sed 1q`: # # $0 $ac_configure_args # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" for ac_option do case "\$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "$CONFIG_STATUS generated by autoconf version 2.4" exit 0 ;; -help | --help | --hel | --he | --h) echo "\$ac_cs_usage"; exit 0 ;; *) echo "\$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=$srcdir ac_given_INSTALL="$INSTALL" trap 'rm -fr `echo "Makefile" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 # Protect against being on the right side of a sed subst in config.status. sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g; s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF $ac_vpsub $extrasub s%@CFLAGS@%$CFLAGS%g s%@CPPFLAGS@%$CPPFLAGS%g s%@CXXFLAGS@%$CXXFLAGS%g s%@DEFS@%$DEFS%g s%@LDFLAGS@%$LDFLAGS%g s%@LIBS@%$LIBS%g s%@exec_prefix@%$exec_prefix%g s%@prefix@%$prefix%g s%@program_transform_name@%$program_transform_name%g s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g s%@INSTALL_DATA@%$INSTALL_DATA%g s%@CC@%$CC%g s%@RC@%$RC%g s%@CPP@%$CPP%g CEOF EOF cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust relative srcdir, etc. for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done rm -f conftest.subs exit 0 EOF chmod +x $CONFIG_STATUS rm -fr confdefs* $ac_clean_files test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 wily-0.13.41/tools/win/configure.in100644 2743 200 673 6347424706 15426 0ustar garypgradAC_INIT(../../wily/wily.c) dnl Checks for programs. AC_PROG_INSTALL AC_PROG_CC AC_C_CONST AC_PATH_PROGS(RC, rc RC) dnl Checks for libraries. AC_CHECK_LIB(nsl, gethostbyname) AC_CHECK_LIB(socket, connect) dnl Checks for pty stuff AC_CHECK_FUNCS(_getpty) AC_MSG_CHECKING(for /dev/ptmx) if /bin/test -e /dev/ptmx ; then AC_MSG_RESULT(yes) AC_DEFINE(HAVE_DEV_PTMX) else AC_MSG_RESULT(no) fi AC_CHECK_HEADERS(sys/ptem.h) AC_OUTPUT(Makefile) wily-0.13.41/tools/win/Makefile.in100644 2743 200 3434 6250475275 15200 0ustar garypgradSHELL = /bin/sh srcdir = @srcdir@ VPATH = @srcdir@ prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = $(exec_prefix)/bin mandir = $(prefix)/man INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ CC = @CC@ CFLAGS = @CFLAGS@ -I.. -I$(srcdir)/../include -I$(srcdir)/../sam/include DEFS = @DEFS@ LIBS = @LIBS@ ../libmsg/libmsg.a ../sam/libXg/libXg.a LDFLAGS = @LDFLAGS@ RC = @RC@ SRCS = win.c wgoto.c wreplace.c Tag.rc mktags.rc Man.rc BINS = win wgoto wreplace Tag mktags Man MANS = win.1 wgoto.1 wreplace.1 Tag.1 mktags.1 Man.1 DISTFILES = \ README INSTALL \ configure configure.in Makefile.in install-sh mkinstalldirs \ $(SRCS) $(MANS) .SUFFIXES : .SUFFIXES : .c .rc .c : $(CC) $(CFLAGS) $(DEFS) $(LDFLAGS) -o $* $*.c $(LIBS) .rc : ( echo '#!' $(RC) ; cat $*.rc; ) >$* ; \ chmod a+x $* all : $(BINS) install : all installdirs for BIN in $(BINS) ; do \ $(INSTALL) $$BIN $(bindir)/$$BIN ; \ done for MAN in $(MANS) ; do \ $(INSTALL_DATA) $$MAN $(mandir)/man1/$$MAN ; \ done installdirs : mkinstalldirs $(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1 clean : rm -f $(BINS) distclean : clean rm -f Makefile config.cache config.status config.log SCCSFILES = $(SRCS) $(MANS) SCCSDIR = SCCS admin : -test -d $(SCCSDIR) && rm -rfi $(SCCSDIR) mkdir $(SCCSDIR) for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ admin -i $$FILE $(SCCSDIR)/s.$$FILE ; \ done rm -i $(SCCSFILES) get : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get $(SCCSDIR)/s.$$FILE ; \ done edit : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get -e $(SCCSDIR)/s.$$FILE ; \ done delta : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ delta -y '' $(SCCSDIR)/s.$$FILE ; \ done dist : ./mkdist $(DISTFILES) wily-0.13.41/tools/win/install-sh100755 2743 200 11243 6250475275 15154 0ustar garypgrad#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 wily-0.13.41/tools/win/mkinstalldirs100755 2743 200 1211 6250475275 15730 0ustar garypgrad#!/bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1994-03-25 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" || errstatus=$? fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here wily-0.13.41/tools/win/win.c100644 2743 200 32532 6250475275 14115 0ustar garypgrad#include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif #include #include #include #include #if HAVE_SYS_PTEM_H #include #endif int shellpid; int master; int slave; char *slavename; const int ttymode = 0600; #define ctrl(c) (c & 0x1f) const char intchar = ctrl('c'); const char eofchar = ctrl('d'); int wilyfifo; Handle *handle; Id id; Bool shelloutput = false; ulong length; ulong outputpoint; void error(const char *, ...); char *getshell(void); char *flatlist(char **); void execshell(char **); void sigexit(int); void sigchld(int); void forkshell(char **); void ipcinit(char *); void ipcloop(void); ulong getlength(void); char *gettagname(char *); void handleshelloutput(void); Bool isbuiltin(char *); void handleWEexec(Msg *); void handleshellinput(Msg *); void handleWEreplace(Msg *); void handlemsg(void); void openmaster(void); void openslave(void); void setslaveattr(void); #define stringize2(x) #x #define stringize(x) stringize2(x) #if defined(__GNUC__) #define here " at " __FILE__ ":" stringize(__LINE__) " in " __FUNCTION__ "()" #else #define here " at " __FILE__ ":" stringize(__LINE__) #endif #define PROGRAMNAME "win" #define VERSIONNAME "%R%.%L% of %D%" char programname[] = PROGRAMNAME; char versioninfo[] = PROGRAMNAME " " VERSIONNAME; char usageinfo[] = "usage: " PROGRAMNAME " [-v] [-t tagname] [command [argument ...]]"; char whatinfo[] = "@(#)" PROGRAMNAME " " VERSIONNAME; void main(int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; char *tagname; /* parse arguments */ tagname = 0; opterr = 0; while ((c = getopt(argc, argv, "vt:")) != -1) { switch (c) { case 'v': fprintf(stderr, "%s\n", versioninfo); exit(0); case 't': tagname = optarg; break; default: fprintf(stderr, "%s\n", usageinfo); exit(1); break; } } /* determine tag name */ if (tagname == 0) if (argv[optind] != 0) tagname = gettagname(argv[optind]); else tagname = "+win"; /* open pty and fork shell */ forkshell(&argv[optind]); /* handle ipc */ ipcinit(tagname); outputpoint = length = getlength(); ipcloop(); } /* * error(fmt, ...): * * Print "win: ", message, and a newline to stderr. */ void error(const char *fmt, ...) { va_list ap; fprintf(stderr, "win: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } /* * getshell(): * * Return the name of the shell. * * Return value is a pointer to malloc()-ed storage. */ char * getshell(void) { char *path, *shell; path = getenv("SHELL"); if (path == 0) path = "/bin/sh"; shell = malloc(strlen(path) + 1); if (shell == 0) { error("malloc() failed" here); exit(1); } strcpy(shell, path); return shell; } /* * flatlist(v): * * Return a space-separated flattened representation of the * string list v. * * Return value is a pointer to malloc()-ed storage. */ char * flatlist(char **v) { char *s; size_t len; size_t i; len = strlen(v[0]); for (i = 1; v[i] != 0; ++i) { ++len; len += strlen(v[i]); } s = malloc(len + 1); if (s == 0) { error("malloc() failed" here); exit(1); } s[0] = 0; strcat(s, v[0]); for (i = 1; v[i] != 0; ++i) { strcat(s, " "); strcat(s, v[i]); } return s; } /* * execshell(argv): * * Exec a shell to execute the command in argv. * The shell should understand -i and -c. */ void execshell(char **argv) { char *arg0, *arg1, *arg2; arg0 = getshell(); if (*argv == 0) { arg1 = "-i"; arg2 = 0; } else { arg1 = "-c"; arg2 = flatlist(argv); } execl(arg0, arg0, arg1, arg2, 0); error("execl(%s, ...) failed" here, arg0); exit(1); } /* * sigexit(sig) * * Signal handler that simply exits. */ void sigexit(int sig) { exit(0); } /* * sigchld(sig) * * Signal handler that exits if the shell has exited. */ void sigchld(int sig) { signal(sig, sigchld); if (wait(0) == shellpid) exit(0); } /* * forkshell(argv): * * Open the master pty; fork. * In the master: set signal handlers. * In the child: set signal handlers; close the master pty; * start a new process group; open the slave pty; make the slave * the controlling terminal (if open() did not already); set the * attributes of the slave; put "TERM=win" into the environment; * exec the shell. */ void forkshell(char **argv) { openmaster(); switch (shellpid = fork()) { case -1: error("fork() failed" here); exit(1); case 0: signal(SIGCHLD, SIG_DFL); signal(SIGINT, SIG_DFL); signal(SIGQUIT, SIG_DFL); signal(SIGTSTP, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); close(master); if (setsid() < 0) { error("setsid() failed" here); exit(1); } openslave(); setslaveattr(); #if defined(TIOCSCTTY) /* e.g., on Digital UNIX */ ioctl(slave, TIOCSCTTY, (void *) 0); #endif if(dup2(slave, 0) < 0 || dup2(slave, 1) < 0 || dup2(slave, 2) < 0) { error("dup2() failed" here); exit(1); } close(slave); putenv("TERM=win"); execshell(argv); default: signal(SIGHUP, sigexit); signal(SIGINT, sigexit); signal(SIGQUIT, sigexit); signal(SIGTERM, sigexit); signal(SIGCHLD, sigchld); } } /* * ipcinit(tagname): * * Initialize IPC to wily. */ void ipcinit(char *tagname) { char *msg; wilyfifo = client_connect(); if (wilyfifo < 0) { error("client_connect() failed" here); exit(1); } handle = rpc_init(wilyfifo); msg = rpc_new(handle, tagname, &id, 0); if (msg != 0) { error("rpc_new() failed" here ": %s", msg); exit(1); } msg = rpc_attach(handle, id, WEexec|WEreplace|WEdestroy); if (msg != 0) { error("rpc_attach() failed" here ": %s", msg); exit(1); } } /* * ipcloop(): * * Handle IPC with wily. */ void ipcloop(void) { fd_set readfds; int nready; for (;;) { while (!rpc_wouldblock(handle)) handlemsg(); FD_ZERO(&readfds); FD_SET(wilyfifo, &readfds); FD_SET(master, &readfds); nready = select(FD_SETSIZE, &readfds, 0, 0, 0); if (nready < 0) { error("select() failed" here); exit(1); } if (FD_ISSET(master, &readfds)) handleshelloutput(); else if (FD_ISSET(wilyfifo, &readfds)) handlemsg(); else { error("select() returned in error" here); exit(1); } } } /* * getlength(): * * Return the length of the body being handled in Runes. */ ulong getlength(void) { Range r; char *msg; msg = rpc_goto(handle, &id, &r, strdup(":,"), 0); if (msg != 0) { error("rpc_goto() failed " here ": %s", msg); exit(1); } return r.p1; } /* * gettagname(shorttagname): * * Return the tag name to use. * * Return value is a pointer to malloc()-ed storage. */ char * gettagname(char *shorttagname) { char *tagname; tagname = malloc(strlen(shorttagname) + 2); if (tagname == 0) { error("malloc() failed" here); exit(1); } sprintf(tagname, "+%s", shorttagname); return tagname; } /* * handleshelloutput(): * * Read output from the shell and pass it to wily. */ void handleshelloutput(void) { char buf[BUFSIZ + 1]; int nread; char *msg; nread = read(master, buf, BUFSIZ); if (nread < 0) { error("read() failed in shellinput()" here); exit(1); } if (nread == 0) exit(0); buf[nread] = '\0'; msg = rpc_replace(handle, id, range(outputpoint, outputpoint), buf); if (msg != 0) { error("rpc_replace() failed" here ": %s", msg); exit(1); } shelloutput = true; } /* * isbuiltin(s): * * Check to see if a command is a builtin command. * * Return true if it is, otherwise false. */ Bool isbuiltin(char *cmd) { char *whitespace = " \t\v\n"; char *first; first = cmd + strspn(cmd, whitespace); return *first == '|' || *first == '<' || *first == '>' || isupper(*first); } /* * handleexec(m): * * Handle a WEexec message m. */ void handleWEexec(Msg *m) { size_t nbytes; int addnewline; char *cmd; char *msg; if (isbuiltin(m->s)) { rpc_bounce(handle, m); return; } nbytes = strlen(m->s); if (nbytes == 0) return; addnewline = (m->s[nbytes - 1] != '\n'); cmd = malloc(nbytes + addnewline + 1); if (cmd == 0) { error("malloc() failed" here); exit(1); } strcpy(cmd, m->s); if (addnewline) strcat(cmd, "\n"); msg = rpc_replace(handle, id, range(length, length), cmd); if (msg != 0) { error("rpc_replace() failed " here ": %s", msg); exit(1); } free(cmd); } /* * handleshellinput(m): * * Send everything from the output point to the last newline * or ctrl-d in the message m to the shell, and adjust the * output point. */ void handleshellinput(Msg *m) { char *lastnewline, *lastintchar, *lasteofchar, *last; ulong lastpoint; char *buf; size_t len; lastnewline = strrchr(m->s, '\n'); lastintchar = strrchr(m->s, intchar); lasteofchar = strrchr(m->s, eofchar); last = lastnewline; if (lastintchar != 0 && (last == 0 || last < lastintchar)) last = lastintchar; if (lasteofchar != 0 && (last == 0 || last < lasteofchar)) last = lasteofchar; *last = '\0'; lastpoint = m->r.p0 + utflen(m->s) + 1; buf = malloc(UTFmax * (lastpoint - outputpoint + 1)); if (buf == 0) { error("malloc() failed" here); exit(1); } rpc_read(handle, id, range(outputpoint, lastpoint), buf); len = strlen(buf); if (write(master, buf, len) != len) { error("write() failed" here); exit(1); } free(buf); outputpoint = lastpoint; } /* * handleWEreplace(m): * * Handle a WEreplace message m. */ void handleWEreplace(Msg *m) { length = length - RLEN(m->r) + utflen(m->s); if (shelloutput) { shelloutput = false; outputpoint = m->r.p0 - RLEN(m->r) + utflen(m->s); #if 0 { /* * This doesn't work. It's an idea for implementing scrolling * on output. What we need is msg.c to execute view_show() * but not view_select() or view_warp(). However, making that * modification would case view_show() to happen even if you * are not setting dot. What we need to do is separate the * functions show, select, and warp. */ char *msg; char buf[100]; Range r; sprintf(buf, ":#%lu", outputpoint); msg = rpc_goto(handle, &id, &r, strdup(buf), 0); if (msg != 0) { error("rpc_goto() failed " here ": %s", msg); exit(1); } } #endif } else { if (outputpoint > m->r.p0) outputpoint = outputpoint - RLEN(m->r) + utflen(m->s); if (m->r.p0 + utflen(m->s) > outputpoint && (strchr(m->s, '\n') || strchr(m->s, intchar) || strchr(m->s, eofchar))) handleshellinput(m); } } /* * handlemsg(): * * Handle a message from wily. */ void handlemsg(void) { Msg m; if (rpc_event(handle, &m) != 0) { error("rpc_event() failed" here); exit(1); } switch (m.t) { case WEdestroy: exit(0); case WEexec: handleWEexec(&m); break; case WEreplace: handleWEreplace(&m); break; default: error("unexpected message type" here); } } /* * openmaster(): * * Open the master end of a pty; determine the name of * the slave end but do not open it. */ void openmaster(void) { #if HAVE__GETPTY /* e.g., on IRIX */ { extern char *_getpty(); slavename = _getpty(&master, O_RDWR, ttymode, 0); if (slavename == 0) { error("_getpty() failed" here); exit(1); } } #elif HAVE_DEV_PTMX /* e.g., on Digital UNIX or Solaris */ { extern char *ptsname(); extern int grantpt(); extern int unlockpt(); master = open("/dev/ptmx", O_RDWR); if (master < 0) { error("open() failed" here); exit(1); } if (grantpt(master) < 0) { error("grantpt() failed" here); exit(1); } if (unlockpt(master) < 0) { error("unlockpt() failed" here); exit(1); } fchmod(master, ttymode); slavename = ptsname(master); if (slavename == 0) { error("ptsname() failed" here); exit(1); } } #else /* e.g., on BSD */ { static char name[]= "/dev/ptyXX"; char *c1, *c2; master = -1; c1 = "pqrstuvwxyzABCDE"; do { c2 = "0123456789abcdef"; do { sprintf(name, "/dev/pty%c%c", *c1, *c2); master = open(name, O_RDWR); } while (master < 0 && *++c2 != 0); } while (master < 0 && *++c1 != 0); if (master < 0) { error("unable to open master pty" here); exit(1); } fchmod(master, ttymode); sprintf(name, "/dev/tty%c%c", *c1, *c2); slavename = name; } #endif } /* * openslave(): * * Open the slave pty. */ void openslave(void) { slave = open(slavename, O_RDWR); if (slave < 0) { error("open() failed" here); exit(1); } fchmod(slave, ttymode); #if HAVE_SYS_PTEM_H /* e.g., on Solaris */ ioctl(slave, I_PUSH, "ptem"); ioctl(slave, I_PUSH, "ldterm"); #endif } /* * setslaveattr() * * Set the slave attributes. */ void setslaveattr(void) { struct termios attr; int i; #if defined(TIOCSETD) && defined(TERMIODISC) /* e.g., on Ultrix */ { /* use termios line discipline */ int ldisc = TERMIODISC; ioctl(slave, TIOCSETD, (void *) &ldisc); } #endif if (tcgetattr(slave, &attr) < 0) { error("tcgetattr() failed" here); exit(1); } attr.c_iflag = 0; attr.c_oflag = ~OPOST; attr.c_lflag = ISIG | ICANON; for (i = 0; i < sizeof(attr.c_cc) / sizeof(*attr.c_cc); ++i) attr.c_cc[i] = 0; attr.c_cc[VINTR] = intchar; attr.c_cc[VEOF] = eofchar; if (tcsetattr(slave, TCSANOW, &attr) < 0) { error("tcsetattr() failed" here); exit(1); } } wily-0.13.41/tools/win/wgoto.c100644 2743 200 3545 6250475275 14441 0ustar garypgrad#include #include #include #include #include #include int wilyfd; Handle *handle; Id id; void error(const char *, ...); char *getfilename(char *); char *readfd(int); #define STRINGIZE2(x) #x #define STRINGIZE(x) STRINGIZE2(x) #ifdef __GNUC__ #define here " at " __FILE__ ":" STRINGIZE(__LINE__) " in " __FUNCTION__ "()" #else #define here " at " __FILE__ ":" STRINGIZE(__LINE__) #endif #define PROGRAMNAME "wgoto" #define VERSIONNAME "%R%.%L% of %D%" char programname[] = PROGRAMNAME; char versioninfo[] = PROGRAMNAME " " VERSIONNAME; char usageinfo[] = "usage: " PROGRAMNAME " [-v] address"; char whatinfo[] = "@(#)" PROGRAMNAME " " VERSIONNAME; void main(int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; char *msg; char *address; Range r; /* parse arguments */ opterr = 0; while ((c = getopt(argc, argv, "v")) != -1) { switch (c) { case 'v': fprintf(stderr, "%s\n", versioninfo); exit(0); default: fprintf(stderr, "%s\n", usageinfo); exit(1); break; } } if (argv[optind] == 0 || argv[optind + 1] != 0) { fprintf(stderr, "%s\n", usageinfo); exit(1); } address = argv[optind]; /* open connection */ wilyfd = client_connect(); if (wilyfd < 0) { error("client_connect() failed" here); exit(1); } handle = rpc_init(wilyfd); /* get address */ msg = rpc_goto(handle, &id, &r, strdup(address), 1); if (msg != 0) { error("rpc_goto() failed" here ": %s", msg); exit(1); } if (r.p0 > r.p1) { error("unable to find %s", address); exit(1); } exit(0); } /* * error(fmt, ...): * * Print program name, ": ", message, and a newline to stderr. */ void error(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", programname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } wily-0.13.41/tools/win/wreplace.c100644 2743 200 6752 6250475275 15107 0ustar garypgrad#include #include #include #include #include #include int wilyfd; Handle *handle; Id id; void error(const char *, ...); char *getfilename(char *); char *readfd(int); #define STRINGIZE2(x) #x #define STRINGIZE(x) STRINGIZE2(x) #ifdef __GNUC__ #define here " at " __FILE__ ":" STRINGIZE(__LINE__) " in " __FUNCTION__ "()" #else #define here " at " __FILE__ ":" STRINGIZE(__LINE__) #endif #define PROGRAMNAME "wreplace" #define VERSIONNAME "%R%.%L% of %D%" char programname[] = PROGRAMNAME; char versioninfo[] = PROGRAMNAME " " VERSIONNAME; char usageinfo[] = "usage: " PROGRAMNAME " [-v] [-c] [-b] address"; char whatinfo[] = "@(#)" PROGRAMNAME " " VERSIONNAME; void main(int argc, char **argv) { int c; extern char *optarg; extern int optind; extern int opterr; char *msg; char *address; char *filename; Range r; Bool create, backup; /* parse arguments */ opterr = 0; create = false; backup = false; while ((c = getopt(argc, argv, "vcb")) != -1) { switch (c) { case 'v': fprintf(stderr, "%s\n", versioninfo); exit(0); case 'c': create = true; break; case 'b': backup = true; break; default: fprintf(stderr, "%s\n", usageinfo); exit(1); break; } } if (argv[optind] == 0 || argv[optind + 1] != 0) { fprintf(stderr, "%s\n", usageinfo); exit(1); } address = argv[optind]; /* open connection */ wilyfd = client_connect(); if (wilyfd < 0) { error("client_connect() failed" here); exit(1); } handle = rpc_init(wilyfd); /* create window if requested */ if (create) { filename = getfilename(address); msg = rpc_new(handle, filename, &id, backup); if (msg != 0) { error("rpc_new() failed" here ": %s", msg); exit(1); } } /* get address */ msg = rpc_goto(handle, &id, &r, strdup(address), 1); if (msg != 0) { error("rpc_goto() failed" here ": %s", msg); exit(1); } if (r.p0 > r.p1) { error("unable to find %s", address); exit(1); } /* do replacement */ msg = rpc_replace(handle, id, r, readfd(0)); if (msg != 0) { error("rpc_replace() failed " here ": %s", msg); exit(1); } exit(0); } /* * error(fmt, ...): * * Print program name, ": ", message, and a newline to stderr. */ void error(const char *fmt, ...) { va_list ap; fprintf(stderr, "%s: ", programname); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); } /* * getfilename(address): * * Return the filename part of an address or 0 * if there is none. * * Returned value is a pointer to malloc()-ed storage. */ char * getfilename(char *address) { char *colon; char *filename; size_t len; colon = strchr(address, ':'); if (colon == 0) len = strlen(address); else len = colon - address; filename = malloc(len + 1); if (filename == 0) { error("malloc() failed" here); exit(1); } memcpy(filename, address, len); filename[len] = 0; return filename; } /* * readfd(fd): * * Read from a fd into a malloc()-ed string. */ char * readfd(int fd) { char *buf; size_t bufsize, buflen; const size_t bufquantum = BUFSIZ; ssize_t nread; buflen = 0; bufsize = 0; buf = 0; do { if (buflen + 1 >= bufsize) { bufsize += bufquantum; buf = realloc(buf, bufsize); if (buf == 0) { error("realloc() failed" here); exit(1); } } nread = read(fd, buf + buflen, bufsize - buflen - 1); if (nread < 0) { error("read() failed" here); exit(1); } buflen += nread; } while (nread != 0); buf[buflen] = 0; return buf; } wily-0.13.41/tools/win/Tag.rc100644 2743 200 772 6250475275 14156 0ustar garypgradif ( ! ~ $#* 1 ) { echo >[1=2] usage: Tag [-v] name exit 1 } if ( ~ $1 -v ) { # @(#) Tag %R%.%L% of %D% echo Tag %R%.%L% of %D% exit 0 } if ( ! test -f Tags ) { echo >[1=2] Tag: no Tags file exit 1 } name = $1 ifs = ' ' tags = `{ egrep '^'^$name^' ' Tags | sed 's/[^ ]* //' } switch ( $#tags ) { case 0 echo >[1=2] Tag: no tag for $name exit 1 case 1 wgoto $tags exit case * echo >[1=2] Tag: multiple tags for $name: wgoto '+Errors:$' for (tag in $tags) { echo >[1=2] $tag } exit 1 } wily-0.13.41/tools/win/mktags.rc100644 2743 200 1755 6250475275 14753 0ustar garypgradif ( ~ $#* 0 ) { echo >[1=2] 'usage: mktags [-v] file ...' exit 1 } if ( ~ $1 -v ) { # @(#) mktags %R%.%L% of %D% echo mktags %R%.%L% of %D% exit 0 } tab = ' ' nawk >Tags ' BEGIN { status = 0; } END { exit(status); } function error(msg) { system("echo 1>&2 " msg); } function checkname(name) { if (file[name] != "") { error(sprintf("mktags: %s is defined in %s and %s", name, file[name], FILENAME)); status = 1; } file[name] = FILENAME; } /^[a-zA-Z_][a-zA-Z_0-9]*\(/ { name = $0; sub("\\(.*", "", name); ere = $0; sub("\\(.*", "\\(", ere); sub("^", "^", ere); checkname(name); printf("%s %s:/%s/\n", name, FILENAME, ere); next; } /^#[ ]*define[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*\(/ { name = $0; sub("#[ ]*define[ ][ ]*", "", name); sub("\\(.*", "", name); ere = $0; sub("\\(.*", "\\(", ere); sub("^", "^", ere); checkname(name); printf("%s %s:/%s/\n", name, FILENAME, ere); next; } ' $* exit wily-0.13.41/tools/win/Man.rc100644 2743 200 371 6250475275 14151 0ustar garypgradif ( ! ~ $#* 1 ) { echo >[1=2] 'usage: Man [-v] [options] title ...' exit 1 } if ( ~ $1 -v ) { # @(#) Man %R%.%L% of %D% echo Man %R%.%L% of %D% exit 0 } name = `{ echo $*($#*) } man $* >[2=1] | col -bx | wreplace -c '+Man '^$name^':,' exit wily-0.13.41/tools/win/win.1100644 2743 200 10057 6250475275 14031 0ustar garypgrad.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) win %R%.%L% of %D% .TH win 1 "%R%.%L% of %D%" .SH NAME win \- Terminal emulator .SH SYNOPSIS .B win .RB [ \-v ] .RB [ -t .IB name ] .RI [ command .RI [ argument .IR ... ]] .I address .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I win prints its version number and date and exits. .TP .BI \-t name If the .B \-t option is present, win uses .I +name as the final part of the tag name of its window. .SH DESCRIPTION .I win must be able to connect to a running .IR wily (1). .I win attaches to a window. If the .B \-t option is present, the final part of the tag name is .IR name . If .I command is present, the final part of the tag name is .IR +command . Otherwise, the final part of the tag name is .IR +win . The first part of the tag name is the current working directory. .PP win runs a program in a child process. The child process is the leader of a process group and is connected to .I win by a pseudo-terminal. If .I command is specified, the child process runs .Ds $SHELL -c 'command argument ...' .De otherwise it runs .Ds $SHELL -i .De If SHELL is not found in the environment, .I /bin/sh is used. .PP TERM=win is placed in the environment of the running program. .PP Output from the running command appears in the window. The point after the last output from the running command is known as the output point. Further output from the running command appears just before the output point. The output point is initially at the end of the window. .PP Normal wily editing commands work in the window. When a newline, interrupt character, or end-of-file character is created after the output point, the text between the output point and the last newline, interrupt character, or end-of-file character in the window (inclusive) is passed to the running program as input. .PP The interrupt character is control-C and the end-of-file character is control-D. The pseudo-terminal initially is configured so that these are recognized with their normal meanings. .PP The B2 commands beginning with the |, <, or > characters or an upper case letter are executed normally by wily. Other B2 are first terminated with a newline, if they are not already, and are then appended to the buffer (and thereafter passed to the running program). .SH RETURNS .I win returns zero if it is able to successfully create the child process, otherwise it returns non-zero. .SH EXAMPLES Run a terminal emulator within wily .Ds win .De .PP Run FTP within wily .Ds win ftp .De .PP Run rlogin within wily .Ds win -t host.domain rlogin -8 host.domain .De .SH SEE ALSO .IR wily (1) .IR Tag (1) .IR Man (1) .SH BUGS .I win doesn't follow changes to the terminal attributes. In particular, there is no way to stop echoing or to change its concept of the interrupt and eof characters. .PP .I rlogin seems to need -8 and, annoyingly, sets echo and onlcr. The latter can be fixed in your .rcrc: .Ds if ( ~ $TERM win ) { stty -echo -onlcr } .De .PP .I win doesn't follow changes to the terminal attributes. In particular, there is no way to stop echoing or to change its concept of the interrupt and eof characters. .PP WEdestroy messages aren't yet passed by wily. Thus, Del and Delcol can delete the window yet leave win running. .PP There is a race condition; the user can press newline and then delete text before win has a chance to read it. .SH AUTHOR .I win was originally written by Gary Capell (gary@cs.su.oz.au). Alan Watson (alan@oldp.nmsu.edu) rewrote it and added support for arguments, pseudo-terminals instead of pipes, and execution of certain B2 commands by wily. The pseudo-terminal support in 9term, written by Matty Farrow (matty@cs.su.oz.au), was a great help. wily-0.13.41/tools/win/wgoto.1100644 2743 200 2246 6250475275 14354 0ustar garypgrad.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) wgoto %R%.%L% of %D% .TH wgoto 1 "%R%.%L% of %D%" .SH NAME wgoto \- Search for and move to an address .SH SYNOPSIS .B wgoto .RB [ \-v ] .I address .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I wgoto prints its version number and date and exits. .SH DESCRIPTION .I wgoto must be able to connect to a running .IR wily (1). .PP .I wgoto searches for .IR address . which must be a .IR wily (1) address. If the search is successful, dot is set. .SH RETURNS .I wgoto returns zero if it was able to find the address, otherwise it returns non-zero. .SH EXAMPLES Find the superuser entry in /etc/passwd: .Ds wgoto '/etc/passwd:/^root:/' .De .SH SEE ALSO .IR wily (1) .IR wreplace (1) .IR Tag (1) .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.41/tools/win/wreplace.1100644 2743 200 2765 6250475275 15025 0ustar garypgrad.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) wreplace %R%.%L% of %D% .TH wreplace 1 "%R%.%L% of %D%" .SH NAME wreplace \- Replace an address with the contents of stdin. .SH SYNOPSIS .B Goto .RB [ \-v ] .RB [ \-c ] .RB [ \-b ] .I address .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I Goto prints its version number and date and exits. .TP .B \-c If the .B \-c option is present, .I wreplace creates the window if necessary. .TP .B \-b If the .B \-b option is present, .I wreplace sets the backup flag on any windows it creates. .TP .B \-d .SH DESCRIPTION .I wreplace must be able to connect to a running .IR wily (1). .PP .I wreplace searches for .IR address and replaces it with the contents of the standard input. .I address must be a valid wily address. .SH RETURNS .I Goto returns zero if it was able to execute the remote goto command, otherwise it returns non-zero. No indication of the success or the failure of the actual search is given. .SH EXAMPLES .PP Create a manifest file: .Ds ls | wreplace -c -b MANIFEST:, .De .SH SEE ALSO .IR wily (1) .IR wgoto (1) .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.41/tools/win/Tag.1100644 2743 200 3320 6250475275 13722 0ustar garypgrad.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) Tag %R%.%L% of %D% .TH Tag 1 "%R%.%L% of %D%" .SH NAME Tag \- Search for and move to a tagged location .SH SYNOPSIS .B Tag .RB [ \-v ] .I name .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I Tag prints its version number and date and exits. .SH DESCRIPTION .I Tag must be able to connect to a running .I wily (1). .PP .I Tag looks for a tag entry corresponding to .I name in the file .I Tags in the current directory. Each line in the .I Tags file is a tag entry consisting of a name, then a space, then a wily address. If .I Tag finds a unique entry corresponding to .I name , it executes a .I wgoto command to search for and move to the address. If .I Tag finds more than one entry corresponding to .I name , it prints the addresses to the .I +Errors window and executes a .I Goto command to move to the .I +Errors window. The correct address can then be selected. .SH RETURNS .I Tag returns zero if it was able to find a unique tag entry and execute the .I wgoto command successfully, otherwise it returns non-zero. No indication of the success or the failure of the actual search is given. .SH EXAMPLES Find the tag entry corresponding to main .DS Tag main .De .SH FILES .I Tags .SH SEE ALSO .IR wily (1), .IR mktags (1) .IR wgoto (1), .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.41/tools/win/mktags.1100644 2743 200 2773 6250475275 14510 0ustar garypgrad.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) mktags %R%.%L% of %D% .TH mktags 1 "%R%.%L% of %D%" .SH NAME mktags \- Create a tag file .SH SYNOPSIS .B mktags .RB [ \-v ] .IB file [ ... ] .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I mktags prints its version number and date and exits. .SH DESCRIPTION .I mktags creates a tag file called .I Tags file suitable for used by .IR Tag (1). Each line in the tags file is a tag entry consisting of a name, then a space, then a .IR wily (1) address. .PP .I mktags recognizes certain C constructions by matching extended regular expressions. In the following, \et represents the tab character and parentheses enclose the name .TP Function definitions ^([a-zA-Z_][a-zA-Z_0-9]*)\e( .TP Function-like macro definitions ^#[\ \et]*define[\ \et][\ \et]*([a\-zA\-Z_][a\-zA\-Z_0\-9]*)\e( .SH RETURNS .I mktags returns zero if it executes successfully, otherwise it returns non-zero. .SH EXAMPLES Make tags from all of the C source files in the current directory .DS mktags *.c *.h .De .SH FILES .I Tags .SH SEE ALSO .IR wily (1) .IR Tag (1) .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.41/tools/win/Man.1100644 2743 200 2154 6250475275 13726 0ustar garypgrad.\" Dd distance to space vertically before a "display" .\" These are what n/troff use for interparagraph distance .\"------- .if t .nr Dd .4v .if n .nr Dd 1v .\"------- .\" Ds begin a display, indented .5 inches from the surrounding text. .\" .\" Note that uses of Ds and De may NOT be nested. .\"------- .de Ds .sp \\n(Ddu .RS \\$1 .nf .. .\"------- .\" De end a display (no trailing vertical spacing) .\"------- .de De .fi .RE .in .. .\" @(#) Man %R%.%L% of %D% .TH Man 1 "%R%.%L% of %D%" .SH NAME Man \- Displays reference pages .SH SYNOPSIS .B Man .RB [ \-v ] .I title ... .SH OPTIONS .TP .B \-v If the .B \-v option is present, .I Man prints its version number and date and exits. .PP Any .IR man (1) options are allowed. .SH DESCRIPTION .I Man must be able to connect to a running .I wily (1). .PP Man executes a .I man (1) command with the specified options and titles and displays the result in a window. The name of the window is .IR "+Man\ title" , where title is the last title specified. .SH EXAMPLES Display the man page for make .DS Man make .De .SH SEE ALSO .IR wily (1), .SH AUTHOR Alan Watson (alan@oldp.nmsu.edu) wily-0.13.41/tools/win/config.log100644 2743 200 177 6347424754 15067 0ustar garypgradThis file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. wily-0.13.41/tools/win/Makefile100644 2743 200 3632 6347424760 14573 0ustar garypgrad# Generated automatically from Makefile.in by configure. SHELL = /bin/sh srcdir = . prefix = /usr/local exec_prefix = ${prefix} bindir = $(exec_prefix)/bin mandir = $(prefix)/man INSTALL = ./install-sh -c INSTALL_DATA = ${INSTALL} -m 644 CC = gcc CFLAGS = -g -O -I.. -I$(srcdir)/../include -I$(srcdir)/../sam/include DEFS = -DHAVE_LIBNSL=1 -DHAVE_LIBSOCKET=1 -DHAVE_DEV_PTMX=1 -DHAVE_SYS_PTEM_H=1 LIBS = -lsocket -lnsl ../libmsg/libmsg.a ../sam/libXg/libXg.a LDFLAGS = RC = /usr/pgrad/gary/bin/sun4d/rc SRCS = win.c wgoto.c wreplace.c Tag.rc mktags.rc Man.rc BINS = win wgoto wreplace Tag mktags Man MANS = win.1 wgoto.1 wreplace.1 Tag.1 mktags.1 Man.1 DISTFILES = \ README INSTALL \ configure configure.in Makefile.in install-sh mkinstalldirs \ $(SRCS) $(MANS) .SUFFIXES : .SUFFIXES : .c .rc .c : $(CC) $(CFLAGS) $(DEFS) $(LDFLAGS) -o $* $*.c $(LIBS) .rc : ( echo '#!' $(RC) ; cat $*.rc; ) >$* ; \ chmod a+x $* all : $(BINS) install : all installdirs for BIN in $(BINS) ; do \ $(INSTALL) $$BIN $(bindir)/$$BIN ; \ done for MAN in $(MANS) ; do \ $(INSTALL_DATA) $$MAN $(mandir)/man1/$$MAN ; \ done installdirs : mkinstalldirs $(srcdir)/mkinstalldirs $(bindir) $(mandir)/man1 clean : rm -f $(BINS) distclean : clean rm -f Makefile config.cache config.status config.log SCCSFILES = $(SRCS) $(MANS) SCCSDIR = SCCS admin : -test -d $(SCCSDIR) && rm -rfi $(SCCSDIR) mkdir $(SCCSDIR) for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ admin -i $$FILE $(SCCSDIR)/s.$$FILE ; \ done rm -i $(SCCSFILES) get : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get $(SCCSDIR)/s.$$FILE ; \ done edit : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ get -e $(SCCSDIR)/s.$$FILE ; \ done delta : for FILE in $(SCCSFILES) ; do \ echo $$FILE: ; \ delta -y '' $(SCCSDIR)/s.$$FILE ; \ done dist : ./mkdist $(DISTFILES) wily-0.13.41/tools/win/config.cache100644 2743 200 2774 6347424757 15401 0ustar garypgrad# This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs. It is not useful on other systems. # If it contains results you don't want to keep, you may remove or edit it. # # By default, configure uses ./config.cache as the cache file, # creating it if it does not exist already. You can give configure # the --cache-file=FILE option to use a different cache file; that is # what configure does when it calls configure scripts in # subdirectories, so they share the cache. # Giving --cache-file=/dev/null disables caching, for debugging configure. # config.status only pays attention to the cache file if you give it the # --recheck option to rerun configure. # ac_cv_c_const=${ac_cv_c_const='yes'} ac_cv_func__getpty=${ac_cv_func__getpty='no'} ac_cv_header_sys_ptem_h=${ac_cv_header_sys_ptem_h='yes'} ac_cv_lib_nsl=${ac_cv_lib_nsl='yes'} ac_cv_lib_nsl_gethostbyname=${ac_cv_lib_nsl_gethostbyname='yes'} ac_cv_lib_socket=${ac_cv_lib_socket='yes'} ac_cv_lib_socket_connect=${ac_cv_lib_socket_connect='yes'} ac_cv_path_RC=${ac_cv_path_RC='/usr/pgrad/gary/bin/sun4d/rc'} ac_cv_path_install=${ac_cv_path_install='./install-sh -c'} ac_cv_prog_CC=${ac_cv_prog_CC='gcc'} ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'} ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross='no'} ac_cv_prog_cc_g=${ac_cv_prog_cc_g='yes'} ac_cv_prog_cc_works=${ac_cv_prog_cc_works='yes'} ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'} ac_cv_prog_gcc_g=${ac_cv_prog_gcc_g='yes'} wily-0.13.41/tools/win/config.status100755 2743 200 6575 6347424760 15661 0ustar garypgrad#! /bin/sh # Generated automatically by configure. # Run this file to recreate the current configuration. # This directory was configured as follows, # on host pgrad: # # ./configure # # Compiler output produced by configure, useful for debugging # configure, is in ./config.log if it exists. ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]" for ac_option do case "$ac_option" in -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) echo "running ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion" exec ${CONFIG_SHELL-/bin/sh} ./configure --no-create --no-recursion ;; -version | --version | --versio | --versi | --vers | --ver | --ve | --v) echo "./config.status generated by autoconf version 2.4" exit 0 ;; -help | --help | --hel | --he | --h) echo "$ac_cs_usage"; exit 0 ;; *) echo "$ac_cs_usage"; exit 1 ;; esac done ac_given_srcdir=. ac_given_INSTALL="./install-sh -c" trap 'rm -fr Makefile conftest*; exit 1' 1 2 15 # Protect against being on the right side of a sed subst in config.status. sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g; s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF /^[ ]*VPATH[ ]*=[^:]*$/d s%@CFLAGS@%-g -O%g s%@CPPFLAGS@%%g s%@CXXFLAGS@%%g s%@DEFS@% -DHAVE_LIBNSL=1 -DHAVE_LIBSOCKET=1 -DHAVE_DEV_PTMX=1 -DHAVE_SYS_PTEM_H=1 %g s%@LDFLAGS@%%g s%@LIBS@%-lsocket -lnsl %g s%@exec_prefix@%${prefix}%g s%@prefix@%/usr/local%g s%@program_transform_name@%s,x,x,%g s%@INSTALL_PROGRAM@%${INSTALL}%g s%@INSTALL_DATA@%${INSTALL} -m 644%g s%@CC@%gcc%g s%@RC@%/usr/pgrad/gary/bin/sun4d/rc%g s%@CPP@%gcc -E%g CEOF CONFIG_FILES=${CONFIG_FILES-"Makefile"} for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then # Support "outfile[:infile]", defaulting infile="outfile.in". case "$ac_file" in *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'` ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; *) ac_file_in="${ac_file}.in" ;; esac # Adjust relative srcdir, etc. for subdirectories. # Remove last slash and all that follows it. Not all systems have dirname. ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then # The file is in a subdirectory. test ! -d "$ac_dir" && mkdir "$ac_dir" ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" # A "../" for each directory in $ac_dir_suffix. ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` else ac_dir_suffix= ac_dots= fi case "$ac_given_srcdir" in .) srcdir=. if test -z "$ac_dots"; then top_srcdir=. else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; *) # Relative path. srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" top_srcdir="$ac_dots$ac_given_srcdir" ;; esac case "$ac_given_INSTALL" in [/$]*) INSTALL="$ac_given_INSTALL" ;; *) INSTALL="$ac_dots$ac_given_INSTALL" ;; esac echo creating "$ac_file" rm -f "$ac_file" configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." case "$ac_file" in *Makefile*) ac_comsub="1i\\ # $configure_input" ;; *) ac_comsub= ;; esac sed -e "$ac_comsub s%@configure_input@%$configure_input%g s%@srcdir@%$srcdir%g s%@top_srcdir@%$top_srcdir%g s%@INSTALL@%$INSTALL%g " -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file fi; done rm -f conftest.subs exit 0 wily-0.13.41/tools/win/confdefs.h100644 2743 200 1 6327321132 14761 0ustar garypgrad wily-0.13.41/tools/shell/ 40755 2743 200 0 6373553446 13347 5ustar garypgradwily-0.13.41/tools/shell/README100644 2743 200 1006 6373554177 14323 0ustar garypgradSome simple C programs to use as wrappers around shell scripts to interact with Wily. Having to know window id's is pretty cumbersome, I know, and I'm open to suggestions on how to improve things. Wins print list of 'filename winid' lines to stdout Wexec cmd id Execute cmd (as if selected with b2), in context of id Wgoto path id Goto 'path' (as if selected with b3), in context of id # NB this is *guaranteed* _not_ to compile "out of the box", you'll need a Makefile that isn't stupid, like the current one. wily-0.13.41/tools/shell/Wins.c100644 2743 200 1100 6373550464 14515 0ustar garypgrad#include #include #include #include #include static void ehandle(char*msg) { fprintf(stderr, "%s\n", msg); exit(1); } int main(int argc, char**argv) { int fd; Handle *handle; char *wins; char *errstr; /* Obtain file descriptor */ fd = client_connect(); if (fd<0) { ehandle("client_connect"); } /* Obtain handle */ handle = rpc_init(fd); assert(handle != 0); /* Grab the list */ errstr = rpc_list(handle, &wins); if(errstr) { ehandle(errstr); } /* Print it */ printf("%s\n", wins); return 0; } wily-0.13.41/tools/shell/Makefile100644 2743 200 674 6373553445 15072 0ustar garypgrad# 9term CC=gcc WILY=$(h)/src/wily BINDIR=$(h)/obj/sun4d/wily CFLAGS=-g -Wall -I. -I$(WILY)/include -I$(WILY)/sam/include -I$(BINDIR) LIBS=-L$(BINDIR)/libmsg -lmsg -lsocket -lnsl -lintl TARGETS= Wgoto Wexec Wins OBJECTS=$(TARGETS:%=%.o) $(TARGETS): Wins: Wins.o gcc -o Wins Wins.o $(LIBS) Wexec: Wexec.o gcc -o Wexec Wexec.o $(LIBS) Wgoto: Wgoto.o gcc -o Wgoto Wgoto.o $(LIBS) clean: - rm $(OBJECTS) nuke: - rm $(OBJECTS) $(TARGETS) wily-0.13.41/tools/shell/Wexec.c100644 2743 200 1250 6373551764 14662 0ustar garypgrad#include #include #include #include #include static void ehandle(char*msg) { fprintf(stderr, "%s\n", msg); exit(1); } int main(int argc, char**argv) { int fd; Handle *handle; char *cmd; char *idstr; Id id; char *errstr; if( argc != 3 ) { ehandle("usage: Wexec cmd id"); } cmd = argv[1]; idstr = argv[2]; id = atoi(idstr); /* Obtain file descriptor */ fd = client_connect(); if (fd<0) { ehandle("client_connect"); } /* Obtain handle */ handle = rpc_init(fd); assert(handle != 0); /* send the command */ errstr = rpc_exec (handle, id, cmd); if(errstr) { ehandle(errstr); } return 0; } wily-0.13.41/tools/shell/Wgoto.c100644 2743 200 1476 6373552746 14721 0ustar garypgrad#include #include #include #include #include static void ehandle(char*msg) { fprintf(stderr, "%s\n", msg); exit(1); } int main(int argc, char**argv) { int fd; Handle *handle; char *path; char *idstr; Id id; char *errstr; ushort selectit; Range rangefound; if( argc != 3 ) { ehandle("usage: Wexec path id"); } path = argv[1]; idstr = argv[2]; id = atoi(idstr); /* Obtain file descriptor */ fd = client_connect(); if (fd<0) { ehandle("client_connect"); } /* Obtain handle */ handle = rpc_init(fd); assert(handle != 0); /* send the command */ selectit = 1; errstr = rpc_goto (handle, &id, &rangefound, path, selectit); if(errstr) { ehandle(errstr); } else { printf("%d %lu, %lu\n", id, rangefound.p0, rangefound.p1); } return 0; } wily-0.13.41/tools/tcl/ 40755 2743 200 0 6242205552 13005 5ustar garypgradwily-0.13.41/tools/tcl/Makefile100644 2743 200 772 6242205545 14532 0ustar garypgrad# # $Header: /u/cvs/wtcl/Makefile,v 1.2 1996/11/12 23:33:55 cvs Exp $ # CC=gcc W=$(TMPDIR)/wily-0.13.19/ WINC=-I$W -I$W/include -I$W/libXg -I$W/sam/include INC=-I/usr/local/include $(WINC) WLD=-L$W/sam/libXg -L$W/libmsg -lmsg -lXg CFLAGS=-Wall $(INC) LDFLAGS=-L/usr/local/lib -ltk -ltcl -lX11 -lm $(WLD) T=wtcl wtk S=wtcl.c wtk.c wily.c O=$(S:.c=.o) all : $T wtcl : wtcl.o wily.o $(CC) -o $@ wtcl.o wily.o $(LDFLAGS) wtk : wtk.o wily.o $(CC) -o $@ wtk.o wily.o $(LDFLAGS) clean : rm -f $T $O core wily-0.13.41/tools/tcl/README100644 2743 200 3330 6242205545 13763 0ustar garypgradthis is a package of tools for communicating with wily using the Tcl library. the file wily.c defines a thin veneer round wily's libmsg. this compiles with wily-0.13.1[89] with tclversion 7.4. the files wtcl.c and wtk.c compile against wily.c to give a tclsh alike with wily support called wtcl, and a wish alike with wily support called wtk. the only addition to standard tcl/tk is the ``wily'' command. this has several subcommands wily init connects to wily. should be called before any other wily command wily isconnected checks that we can still talk to wily. returns boolean. wily list returns a list of window ids (integers). wily name returns the name of the window with given id. wily new opens a new window with given filename. wily attach offer to collect events for window with given id. we collect _all_ events. wily setname set the name of window with given id to the given new name. wily settools appends the given tools to the tools for window with given id. wily read returns the text between points and in window . wily replace replaces the text between points and in window id with . wily exec just as if had been b2'd in window . wily goto as if string had been b3'd in windows . if is true then we jump to and select the result. wily length the length of the text in window wily wouldblock return boolean. true if there is no event in queue. false if there is. wily event returns a string describing the event. wily bounce return the last event received back to wily. wily-0.13.41/tools/tcl/wattach100755 2743 200 431 6242205546 14444 0ustar garypgrad#!wtcl # # $Header: /u/cvs/wtcl/wattach,v 1.1.1.1 1996/11/12 21:28:10 cvs Exp $ # wily init wily attach $argv while {1} { set event [wily event] if [string match [lindex $event 0] WMexec] { if [string match [lindex $event 2] Del] { wily bounce exit } } puts $event } wily-0.13.41/tools/tcl/wily.c100644 2743 200 23770 6242205547 14267 0ustar garypgrad/* $Header: /u/cvs/wtcl/wily.c,v 1.2 1996/11/12 23:33:58 cvs Exp $ */ #include #include #include #include #include /* * dispatcher within Wily() routine */ typedef struct WCmd WCmd ; struct WCmd { char *name ; int (*proc)(Tcl_Interp*, int, char**) ; } ; /* * the handle to wily. should be 0 if not connected */ static Handle *h ; /* * the last event fetched by rpc_event() used * by bounce -- we can only bounce if we haveevent */ static Bool haveevent = false ; static Msg m ; static Bool iscon( void ) { if(h == 0 || rpc_isconnected(h) == false) { h = 0 ; return false ; } return true ; } /* * check args etc for Wily() sub command. * check that argc == argswanted. * if id != 0 then check that we have an id * and return it as *id. * check we are connected to wily. * if anything fails then set the result string */ static int chk( Tcl_Interp *interp, int argc, char **argv, int argswanted, char *usage, Id *id ) { int n ; if(argc != argswanted) { Tcl_SetResult(interp, usage, TCL_STATIC) ; return TCL_ERROR ; } if(iscon() == false) { Tcl_SetResult(interp, "not connected", TCL_STATIC) ; return TCL_ERROR ; } if(id != 0) { if(Tcl_GetInt(interp, argv[1], &n) != TCL_OK) { Tcl_SetResult(interp, "arg doesn't look like id", TCL_STATIC) ; return TCL_ERROR ; } *id = n ; } return TCL_OK ; } static int wrpc_init( Tcl_Interp *interp, int argc, char **argv ) { int fd ; if(argc != 1) { Tcl_SetResult(interp, "init requires no arguments", TCL_STATIC) ; return TCL_ERROR ; } fd = client_connect() ; if(fd < 0) { Tcl_SetResult(interp, "can't connect", TCL_STATIC) ; return TCL_ERROR ; } h = rpc_init(fd) ; if(h == 0) { Tcl_SetResult(interp, "can't init", TCL_STATIC) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_isconnected( Tcl_Interp *interp, int argc, char **argv ) { if(argc != 1) { Tcl_AppendResult(interp, "isconnected requires no arguments", TCL_STATIC) ; return TCL_ERROR ; } if(iscon() == false) { Tcl_SetResult(interp, "0", TCL_STATIC) ; h = 0 ; } else Tcl_SetResult(interp, "1", TCL_STATIC) ; return TCL_OK ; } static int wrpc_list( Tcl_Interp *interp, int argc, char **argv ) { char *p ; char *emsg ; char *t ; char *s ; if(chk(interp, argc, argv, 1, "list requires no arguments", 0) != TCL_OK) return TCL_ERROR ; emsg = rpc_list(h, &p) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } /* * we trust p to be in a reasonable condition */ t = strtok(p, "\n") ; while(t != 0 && (s = strchr(t, '\t')) != 0) { s++ ; Tcl_AppendElement(interp, s) ; t = strtok(0, "\n") ; } free(p) ; return TCL_OK ; } static int wrpc_name( Tcl_Interp *interp, int argc, char **argv ) { char *p ; char *emsg ; char *t ; char *s ; if(chk(interp, argc, argv, 2, "name requires id", 0) != TCL_OK) return TCL_ERROR ; emsg = rpc_list(h, &p) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } /* * we trust p to be in a reasonable condition */ t = strtok(p, "\n") ; while(t != 0 && (s = strchr(t, '\t')) != 0) { *s++ = '\0' ; if(strcmp(argv[1], s) == 0) { Tcl_SetResult(interp, t, TCL_VOLATILE) ; free(p) ; return TCL_OK ; } t = strtok(0, "\n") ; } Tcl_SetResult(interp, "id not found", TCL_STATIC) ; free(p) ; return TCL_ERROR ; } static int wrpc_new( Tcl_Interp *interp, int argc, char **argv ) { char *emsg ; Id id ; if(chk(interp, argc, argv, 2, "new needs filename", 0) != TCL_OK) return TCL_ERROR ; emsg = rpc_new(h, argv[1], &id) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } sprintf(interp->result, "%ld", (long)id) ; return TCL_OK ; } static int wrpc_attach( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 2, "attach needs id", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_attach(h, id, WEexec | WEgoto | WEdestroy | WEreplace) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_setname( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 3, "setname needs id and new name", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_setname(h, id, argv[2]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_settools( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 3, "settools needs id and new text", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_settools(h, id, argv[2]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_read( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; char *p ; int n ; if(chk(interp, argc, argv, 4, "read needs id, begin and end", &id) != TCL_OK) return TCL_ERROR ; r.p0 = Tcl_GetInt(interp, argv[2], &n) != TCL_OK ? -1 : n ; r.p1 = Tcl_GetInt(interp, argv[3], &n) != TCL_OK ? -1 : n ; if(r.p0 < 0 || r.p1 < 0 || r.p0 > r.p1) { Tcl_SetResult(interp, "strange numbers", TCL_STATIC) ; return TCL_ERROR ; } p = malloc(UTFmax * RLEN(r)) ; if(p == 0) { Tcl_SetResult(interp, "malloc fails", TCL_STATIC) ; return TCL_ERROR ; } emsg = rpc_read(h, id, r, p) ; if(emsg != 0) { free(p) ; Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } /* * let tcl reclaim the string */ Tcl_SetResult(interp, p, TCL_DYNAMIC) ; return TCL_OK ; } static int wrpc_replace( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; int n ; if(chk(interp, argc, argv, 5, "replace needs id, begin, end and new text", &id) != TCL_OK) return TCL_ERROR ; r.p0 = Tcl_GetInt(interp, argv[2], &n) != TCL_OK ? -1 : n ; r.p1 = Tcl_GetInt(interp, argv[3], &n) != TCL_OK ? -1 : n ; if(r.p0 < 0 || r.p1 < 0 || r.p0 > r.p1) { Tcl_SetResult(interp, "strange numbers", TCL_STATIC) ; return TCL_ERROR ; } emsg = rpc_replace(h, id, r, argv[4]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_exec( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; if(chk(interp, argc, argv, 3, "exec needs id and command", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_exec(h, id, argv[2]) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_goto( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; int b ; if(chk(interp, argc, argv, 4, "goto needs id, string and flag", &id) != TCL_OK) return TCL_ERROR ; if(Tcl_GetBoolean(interp, argv[3], &b) != TCL_OK) b = 0 ; emsg = rpc_goto(h, &id, &r, argv[2], b != 0 ? true : false) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } sprintf(interp->result, "%ld %ld %ld", (long)id, (long)r.p0, (long)r.p1) ; return TCL_OK ; } static int wrpc_length( Tcl_Interp *interp, int argc, char **argv ) { Id id ; char *emsg ; Range r ; if(chk(interp, argc, argv, 2, "length needs id", &id) != TCL_OK) return TCL_ERROR ; emsg = rpc_goto(h, &id, &r, ":$", false) ; if(emsg != 0) { Tcl_SetResult(interp, emsg, TCL_VOLATILE) ; return TCL_ERROR ; } sprintf(interp->result, "%ld", (long)r.p0) ; return TCL_OK ; } static int wrpc_wouldblock( Tcl_Interp *interp, int argc, char **argv ) { if(chk(interp, argc, argv, 1, "wouldblock needs no args", 0) != TCL_OK) return TCL_ERROR ; Tcl_SetResult(interp, rpc_wouldblock(h) == false ? "1" : "0", TCL_STATIC) ; return TCL_OK ; } static int wrpc_event( Tcl_Interp *interp, int argc, char **argv ) { if(chk(interp, argc, argv, 1, "event needs no args", 0) != TCL_OK) return TCL_ERROR ; if(rpc_event(h, &m) == -1) { Tcl_SetResult(interp, "event fails", TCL_STATIC) ; return TCL_ERROR ; } haveevent = true ; switch(m.t) { case WEexec: sprintf(interp->result, "WMexec\t%ld\t%s", (long)m.w, m.s) ; break ; case WEgoto: sprintf(interp->result, "WMgoto\t%ld\t%ld\t%ld\t%s", (long)m.w, m.r.p0, m.r.p1, m.s) ; break ; case WEdestroy: sprintf(interp->result, "WMdestory\t%ld", (long)m.w) ; break ; case WEreplace: sprintf(interp->result, "WMreplace\t%ld\t%ld\t%ld\t%s", (long)m.w, m.r.p0, m.r.p1, m.s) ; break ; default: Tcl_SetResult(interp, "unknown message type", TCL_STATIC) ; return TCL_ERROR ; } return TCL_OK ; } static int wrpc_bounce( Tcl_Interp *interp, int argc, char **argv ) { if(chk(interp, argc, argv, 1, "bounce needs no args", 0) != TCL_OK) return TCL_ERROR ; if(haveevent != true) { Tcl_SetResult(interp, "nothing to bounce", TCL_STATIC) ; return TCL_ERROR ; } if(rpc_bounce(h, &m) != 0) { Tcl_SetResult(interp, "rpc_bounce fails", TCL_STATIC) ; return TCL_ERROR ; } return TCL_OK ; } static WCmd cmds[] = { "init", wrpc_init, "isconnected", wrpc_isconnected, "list", wrpc_list, "new", wrpc_new, "attach", wrpc_attach, "setname", wrpc_setname, "name", wrpc_name, "settools", wrpc_settools, "read", wrpc_read, "replace", wrpc_replace, "exec", wrpc_exec, "goto", wrpc_goto, "length", wrpc_length, "wouldblock", wrpc_wouldblock, "event", wrpc_event, "bounce", wrpc_bounce, } ; static int Wily( ClientData clientdata, Tcl_Interp *interp, int argc, char **argv ) { WCmd *p ; if(argc > 1) for(p = cmds ; p < cmds + sizeof cmds / sizeof cmds[0] ; p++) if(strcmp(argv[1], p->name) == 0) return (*p->proc)(interp, argc - 1, argv + 1) ; Tcl_AppendResult(interp, "usage: ", argv[0], ": ", (char*)0) ; for(p = cmds ; p < cmds + sizeof cmds / sizeof cmds[0] ; p++) Tcl_AppendResult(interp, "[", p->name, "] ", (char*)0) ; return TCL_ERROR ; } extern int Wily_Init( Tcl_Interp *interp ) { Tcl_CreateCommand(interp, "wily", Wily, (ClientData)0, (Tcl_CmdDeleteProc*)0) ; return TCL_OK ; } wily-0.13.41/tools/tcl/wlist100755 2743 200 233 6242205550 14146 0ustar garypgrad#!wtcl # # $Header: /u/cvs/wtcl/wlist,v 1.2 1996/11/12 23:34:00 cvs Exp $ # wily init foreach i [wily list] { set name [wily name $i] puts "$i\t$name" } wily-0.13.41/tools/tcl/wname100755 2743 200 313 6242205550 14112 0ustar garypgrad#!wtcl # # $Header: /u/cvs/wtcl/wname,v 1.1.1.1 1996/11/12 21:28:10 cvs Exp $ # wily init if [expr $argc != 2] { puts "usage: $argv0 " exit 1 } wily name [lindex $argv 0] [lindex $argv 1] wily-0.13.41/tools/tcl/wnew100755 2743 200 303 6242205550 13762 0ustar garypgrad#!wtcl # # $Header: /u/cvs/wtcl/wnew,v 1.1.1.1 1996/11/12 21:28:09 cvs Exp $ # wily init set wd [pwd] foreach i "$argv" { if [regexp "^/" $i] { wily new $i } else { wily new "$wd/$i" } } wily-0.13.41/tools/tcl/wtcl.c100644 2743 200 714 6242205551 14200 0ustar garypgrad/* $Header: /u/cvs/wtcl/wtcl.c,v 1.1.1.1 1996/11/12 21:28:09 cvs Exp $ */ #include #include "wtcl.h" extern int Tcl_AppInit( Tcl_Interp *interp ) { if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR ; if(Wily_Init(interp) == TCL_ERROR) return TCL_ERROR ; Tcl_SetVar(interp, "tcl_rcFileName", "~/.wtcl", TCL_GLOBAL_ONLY) ; return TCL_OK ; } extern int main( int argc, char **argv ) { Tcl_Main(argc, argv, Tcl_AppInit) ; return 0 ; } wily-0.13.41/tools/tcl/wtcl.h100644 2743 200 157 6242205551 14206 0ustar garypgrad/* $Header: /u/cvs/wtcl/wtcl.h,v 1.1.1.1 1996/11/12 21:28:09 cvs Exp $ */ extern int Wily_Init(Tcl_Interp*) ; wily-0.13.41/tools/tcl/wtk.c100644 2743 200 1022 6242205551 14045 0ustar garypgrad/* $Header: /u/cvs/wtcl/wtk.c,v 1.1.1.1 1996/11/12 21:28:10 cvs Exp $ */ #include #include #include "wtcl.h" extern int Tcl_AppInit( Tcl_Interp *interp ) { if(Tcl_Init(interp) == TCL_ERROR) return TCL_ERROR ; if(Tk_Init(interp) == TCL_ERROR) return TCL_ERROR ; if(Wily_Init(interp) == TCL_ERROR) return TCL_ERROR ; Tcl_SetVar(interp, "tcl_rcFileName", "~/.wtk", TCL_GLOBAL_ONLY) ; return TCL_OK ; } extern int main( int argc, char **argv ) { Tk_Main(argc, argv, Tcl_AppInit) ; return 0 ; } wily-0.13.41/tools/tcl/wtktest100755 2743 200 521 6242205552 14513 0ustar garypgrad#!wtk # # $Header: /u/cvs/wtcl/wtktest,v 1.1 1996/11/12 23:34:01 cvs Exp $ # wily init proc cmd {name} { set id [lindex [wily list] 0] wily exec $id $name } button .quit -text Quit -command {cmd Quit} button .putall -text Putall -command {cmd Putall} button .font -text Font -command {cmd Font } pack .quit .putall .font -side left wily-0.13.41/tools/tcl/wtools100755 2743 200 315 6242205552 14336 0ustar garypgrad#!wtcl # # $Header: /u/cvs/wtcl/wtools,v 1.2 1996/11/12 23:34:03 cvs Exp $ # wily init if [expr $argc != 2] { puts "usage: $argv0 " exit 1 } wily settools [lindex $argv 0] [lindex $argv 1] wily-0.13.41/wily/ 40755 2743 200 0 6541667676 12074 5ustar garypgradwily-0.13.41/wily/mouse.c100644 2743 200 10520 6521547347 13471 0ustar garypgrad/******************************************* * Handle mouse actions *******************************************/ #include "wily.h" #include "view.h" #include static void b2 (View *, Range, Bool); static void dobutton (View *, Mouse *); static void doscroll (View *, Mouse *); static void action (View *, Mouse *, Range, ulong); /* PRE: a mouse button is down * POST: no mouse buttons down, we've probably done something. */ void domouse(View *v, Mouse *m) { assert(m->buttons); if ( POINTINSCROLL(m->xy, v) ) { if(v->scroll) doscroll(v,m); else dobutton(v, m); } else { ulong oldbuttons = m->buttons; Range r = vselect(v, m); action(v, m, r, oldbuttons); } } /****************************************************** static functions ******************************************************/ static void dobutton(View *v, Mouse *orig) { Mouse m; Tile *tile = view_tile(v); assert(ISTAG(v)); assert(orig->buttons); if(tile == wily) /* can't move the main window this way */ return; /* swap cursor, follow mouse until button state changes */ cursorswitch(&boxcursor); do { m = emouse(); } while(m.buttons == orig->buttons); cursorswitch(cursor); /* aborted by pressing a different button? */ if(m.buttons) return; if (distance(m.xy, orig->xy) < SMALLDISTANCE) { tile_grow(tile, orig->buttons); cursorset(buttonpos(tile)); } else tile_move(tile, m.xy); } /* * Some builtins should always be applied to the window where * you clicked button 2. */ static char *locals[] = {"Look", "Put", "Get", "Undo", "Redo", 0}; static Bool islocal(char *s) { char **ptr; for (ptr =locals; *ptr; ptr++) if (!strncmp(s, *ptr, strlen(*ptr))) return true; return false; } /* clicked button 2 in 'v' selecting 'r'. 'ischord' is true * if we also clicked button 1. */ static void b2(View *v, Range r, Bool ischord) { char *cmd,*arg; View *ls = last_selection; r = view_expand(v, r, notcommand); if(!RLEN(r)) return; cmd = text_duputf(v->t, r); if(ischord && ls && RLEN(ls->sel) < 200) { Range rarg; rarg = view_expand(ls, ls->sel, notfilename); arg = text_duputf(ls->t, rarg); /* use arg for context-- with some exceptions */ if(!islocal(cmd)) v = ls; } else arg = 0; if (!data_sendexec(view_data(v),cmd, arg)) run(v, cmd, arg); free(cmd); if(arg) free(arg); } /* * Currently mouse is like 'm', originally we had 'oldbuttons'. When * we're finished, v's display should be correct, and no mouse buttons * should be down. */ static void action(View *v, Mouse *m, Range r, ulong oldbuttons) { /* mouse button state has changed, possibly do something */ assert(m->buttons != oldbuttons); if (oldbuttons&LEFT) { enum {Cancut = 1, Canpaste = 2} state = Cancut | Canpaste; while(m->buttons) { if(m->buttons&MIDDLE) { if (state&Cancut) { view_cut(v, v->sel); state = Canpaste; } } else if ( m->buttons&RIGHT) { if (state&Canpaste) { view_paste(v); state = Cancut; } } *m = emouse(); } } else if (oldbuttons & MIDDLE) { if(m->buttons) { if(m->buttons&LEFT) /* chord */ b2(v,r,true); while (m->buttons) /* wait for button up */ *m = emouse(); } else { b2(v,r,false); } } else { assert((oldbuttons&RIGHT)); if(m->buttons) /* cancelled a b3 */ while (m->buttons) *m = emouse(); else b3(v, r); } } /* PRE: 'e' a mouse event in 'v', but not in v's frame, so probably in * the scrollbar. 'v' is a body frame. * POST: we've tracked the mouse until all the buttons are down, * and have scrolled if we should have. */ static void doscroll(View *v, Mouse *m ) { ulong buttons; ulong timer; ulong type; int delay = DOUBLECLICK / SCROLLTIME; Bool firstmouse; Event e; assert(ptinrect(m->xy, v->r)); assert(v->scroll); buttons = m->buttons; assert(buttons); type = Emouse; firstmouse = true; e.mouse = *m; m = &e.mouse; /* start waiting for timer events */ timer = etimer(0, SCROLLTIME); do { assert(type== timer || type == Emouse); if(type==Emouse) { if (firstmouse) { firstmouse = false; view_scroll(v, m); } } else { if(delay) delay--; else view_scroll(v, m); } type = eread(Emouse|timer,&e); } while (!(type ==Emouse && m->buttons != buttons)); estoptimer(timer); /* stop the timer */ /* wait for buttons up */ while (m->buttons) eread(Emouse, &e); } wily-0.13.41/wily/wily.c100644 2743 200 7544 6541445407 13315 0ustar garypgrad/******************************************* * main(), parse arguments *******************************************/ #include "wily.h" #include "tile.h" static int ncolumns = 2; int tagheight; Tile *wily=0; /* encloses the whole application */ char *wilytools = "Kill | Newcol Quit Putall wily-0.13.41 Dotfiles Font "; /* version */ char *filetools = "Del Look ."; char *dirtools = "Del Look .."; char *columntools = "Delcol New Cut Paste Snarf Anchor Split | "; void _allocerror(char*s){ fprintf(stderr,"%s\n", s); abort(); } /* Add 'cmd' to the visible list of running processes. */ void addrunning(char *cmd){ tag_addrunning(view_text(wily->tag), cmd); } /* Remove 'cmd' from the visible list of running processes.*/ void rmrunning(char *cmd){ tag_rmtool(view_text(wily->tag), cmd); } /* Initialize info about what bits of text get added to various tags. * Reads $WILYTOOLS or $HOME/.wilytools for regexp/tool pairs, * uses $WMAINTAG, $WCOLTAG $WFILETAG, $WDIRTAG * as the tools for the wily tag, column tag, file tags and directory tags * respectively. */ static void tools_init(void){ char*s, t[200]; if ((s = getenv("WILYTOOLS"))) tag_init(s); else { Path p; sprintf(p, "%s/%s", getenv("HOME"), ".wilytools"); tag_init(p); } if ((s=getenv("WCOLTAG"))) columntools = strdup(s); if ((s=getenv("WMAINTAG"))) { strcpy(t, wilytools); strcat(t, s); wilytools = strdup(t); } if ((s=getenv("WFILETAG"))) filetools = strdup(s); if ((s=getenv("WDIRTAG"))) dirtools = strdup(s); } static void usage(void) { fprintf(stderr,"wily [-c ncolumns] [-a tabsize] [-e command] [file1 ...]\n"); exit(1); } static void args(int argc,char **argv, char **envp) { extern char *optarg; extern int optind; int c; char *cmd = 0; tabsize = 4; /* default */ /* init libXg */ xtbinit((Errfunc)error, "Wily", &argc, argv, 0); tagheight = font->height + 2*INSET; while ((c = getopt(argc, argv, "c:a:e:")) != EOF) { switch (c) { case 'c': ncolumns = atoi(optarg); break; case 'a': tabsize = atoi(optarg); break; case 'e': cmd = optarg; break; default: usage(); break; } } scroll_init(); einit(Ekeyboard | Emouse); cursorswitch(cursor); wily_init(); ex_init(); if (optindtag, cmd, 0); } /* Initialise the base tile, with some columns */ void wily_init(void) { Text *t; int j; t = text_alloc(0, false); text_replaceutf(t, nr, wilytools); wily = tile_new(V, 0, screen.r.max.y, 0, 0, t, 0); tile_reshaped(wily); last_selection = 0; view_setlastselection( wily->tag); for(j=0; j< ncolumns; j++) col_new(wily->tag, 0); } /* Reshape the base tile */ void ereshaped(Rectangle r) { if(!wily) return; /* not initialised yet */ wily->cmax = r.max.x; wily->max = r.max.y; tile_reshaped(wily); } /* Main event loop */ static void mainloop(void) { ulong type; Event e; Bool mouseaction=true; Point lastp={0,0}; View *v=0; while ((type = eread(~0, &e))) { switch(type){ case Ekeyboard: if(mouseaction) { /* 'v' is a cache of the view we are pointing at, * (we use point to type). We update this only * when we start typing after moving the pointer. */ v = point2view(lastp); mouseaction=false; } if(v) dokeyboard(v, e.kbdc); break; case Emouse: lastp = e.mouse.xy; mouseaction=true; if(e.mouse.buttons && (v = point2view(e.mouse.xy))) domouse(v, &e.mouse); break; default: dofd(type, e.n, (char*)e.data); break; } } } int main(int argc,char **argv, char **envp) { if (!getcwd(wilydir,MAXPATH)) fatal("couldn't find out what directory this is"); add_slash(wilydir); env_init(envp); tools_init(); args(argc,argv, envp); mainloop(); return 0; } wily-0.13.41/wily/path.c100644 2743 200 4245 6355671430 13260 0ustar garypgrad/******************************************* * Expand abbreviations for pathnames *******************************************/ #include "wily.h" #include static char* gettilde(const char*s); /* * Expand 'orig' into 'dest', using 'expansion'. * Expansion must take a char*, and return a static char*, * i.e. one we don't have to free (and can't keep). */ static void expand(char*dest, char*orig, char*(*expansion)(const char*)){ Path key; char *val; char *slash; assert(orig[0]=='$' || orig[0]=='~'); strcpy(key,orig+1); if( (slash=strchr(key,'/')) ) { *slash = 0; } val = (*expansion)(key); if(slash) *slash = '/'; if(val){ sprintf(dest, "%s%s", val, slash? slash: ""); } else { strcpy(dest, orig); } } /* Convert a 'label' to a 'path'. Paths are always absolute. */ void label2path(char*path, char*label) { if(!label){ strcpy(path,wilydir); return; } switch(label[0]) { case '$': expand(path, label, getenv); break; case '~': expand(path, label, gettilde); break; case '/': strcpy(path, label); break; default: sprintf(path, "%s%s", wilydir, label); break; } labelclean(path); } /********************************************************* static functions *********************************************************/ /* Clean up 'label' by removing components with '.' or '..' */ void labelclean(char*label) { char *slash, *from, *to, c; char *back; slash = strchr(label,'/'); if(slash) { from = to = slash+1; } else { return; } while (from[0] != '\0') { assert(to[-1] == '/'); switch(from[0]){ case '/': /* ignore "//" */ from++; continue; case '.': switch(from[1]){ case '\0': case '/': /* Ignore "./" */ from++; continue; case '.': if (from[2] == '\0' || from[2] == '/') { from += 2; to[-1] = '\0'; back = strrchr(label, '/'); if(back){ to = back+1; } else { to[-1] ='/'; } continue; } } default: do { c = (*to++ = *from++); } while (c != '\0' && c != '/'); from--; } } *to='\0'; } static char* gettilde(const char*s) { struct passwd *pw; pw = strlen(s) ? getpwnam(s) : getpwuid(getuid()); return pw ? pw->pw_dir : 0; } wily-0.13.41/wily/data.c100644 2743 200 5524 6337255414 13236 0ustar garypgrad/******************************************* * Data methods *******************************************/ #include "wily.h" #include "data.h" #include Data *dataroot; Text* data_body(Data*d) { return d->t; } Text* data_tag(Data*d){ return d->tag; } /* Return the names in directory 'd', or 0 */ char** data_names(Data*d){ return d ? d->names : 0; } /* Return true if 'd' should have its resize box filled in */ Bool data_isdirty(Data *d) { return d && NEEDSBACKUP(d); } /* Write all dirty windows. Return 0 for success. */ int data_putall(void) { Data *d; int retval = 0; for(d=dataroot; d; d=d->next) if(NEEDSBACKUP(d)) if (data_put(d,0)) retval = -1; return retval; } /* Backup all dirty files. Return 0 unless we failed to backup something. */ int data_backupall(void) { Data *d; int retval= 0; for(d = dataroot; d; d = d->next) { if (data_backup(d)) { retval = 1; } } return retval; } /* * Write the contents of 'd' to 'path'. * Return 0 if we've successfully written 'd' to its label. */ int data_put(Data *d, char *label) { int fd; Stat buf; Path path; Bool statfailed, writefailed; if(!label) label = d->label; label2path(path, label); statfailed = stat(path, &buf); if((fd = open(path,O_RDWR|O_CREAT|O_TRUNC, 0666))<0){ diag(path, "couldn't open \"%s\" for write", path); return -1; } writefailed = text_write_range(d->t, text_all(d->t), fd); close(fd); if(writefailed) { diag(path, "write failed: \"%s\"", path); return -1; } if (!strcmp(d->label,label) || !statcmp(&buf, &d->stat)) { if(!d->names) { tag_rmtool(d->tag, "Put"); undo_mark(d->t); } return 0; } return -1; } void data_listremove(Data *d) { Data **ptr; for(ptr = &dataroot; *ptr != d; ptr = &((*ptr)->next)) ; *ptr = d->next; } /* Delete 'd' if we can do so without permanently losing * data, and return 0. If there's a problem, return 1. */ int data_del(Data*d) { if(data_backup(d)) return 1; data_senddestroy(d); data_listremove(d); dirnames_free(d->names); if(d->backupto) free(d->backupto); free(d); return 0; } /* Backup 'd' if necessary. Return 0 for success. */ int data_backup(Data *d) { Path fname; if (!NEEDSBACKUP(d)) return 0; if( (backup_name(d->backupto, fname)) ) return -1; if(text_write(d->t, fname)) return -1; errno = 0; diag(fname, "backup %s %s", mybasename(fname), d->backupto); return 0; } /* Record that in emergencies, 'd' should be saved, noting * that it is a copy of 'bfile' */ void data_setbackup(Data *d, char*bfile) { if(d->backupto) free(d->backupto); if(bfile && !strstr(bfile, "+Errors")) { d->backupto = strdup(bfile); text_setneedsbackup(d->t, true); } else { d->backupto = 0; text_setneedsbackup(d->t, false); }; } Data * data_findid(Id id) { Data *d; for(d=dataroot; d; d=d->next) if(d->id==id) break; return d; } wily-0.13.41/wily/view.h100644 2743 200 2467 6401466046 13304 0ustar garypgrad/* * Both tags and bodies use a View as a display widget. The difference * between them is that bodies have scrollbars, whereas tags don't (but * tags automatically grow as required). A View uses a Text to keep * track of the text that is currently not on screen, and a Frame to * display text. A view keeps track of the visible area, the selected * area, and the place where we began typing (if we're in the middle of * typing). * * The View controls all aspects of viewing and selecting text, but has * no knowledge of how we store all the text. * If a view is not visible, v->r.max.y == v->r.min.y, and it's frame * will have been frcleared, i.e. not usable */ struct View { Rectangle r; /* of whole view */ Text *t; Frame f; Range visible, sel; /* visible, selected area */ ulong anchor; /* where we most recently started typing */ Scroll *scroll; /* 0 for tag */ Tile *tile; View *next; /* list of views displaying same Data */ Bool selecting; /* we're busy dragging out a selection */ Bool autoindent; /* autoindent in this view? */ }; #define ISTAG(v) ((v) && !(v)->scroll) #define ISBODY(v) ( (v) && (v)->scroll) #define ISVISIBLE(v) ( (v)->f.b!=0 ) /* Return true if 'p' is contained in 'v's scrollbar */ #define POINTINSCROLL(p,v) ( (p).x < (v)->r.min.x + SCROLLWIDTH + INSET ) wily-0.13.41/wily/text.c100644 2743 200 14476 6332626025 13332 0ustar garypgrad/* We use a simple buffer-gap. This is not too good for working * with large files if we're simultaneously working at both ends of * the file, because everytime we make a change, we have to move * the gap to the position of the change. * * If we wanted to handle large files efficiently we should * probably use multiple gaps, or multiple separate buffers. * What we have is probably sufficient for most cases, though. * * If we wanted to worry about our memory footprint, instead * of keeping the whole file in memory as Runes, we could copy * it to a (or many) auxiliary files and convert to Runes on demand. * This would also help with latency of opening big files. It would * also be much more complex. Virtual memory is our friend. */ #include "wily.h" #include "text.h" #include static void setgap(Text *t, ulong p, int n); #ifndef NDEBUG static Rune * findnull(Rune*start, Rune*end) { Rune *p; for(p=start; pgap.p1 >= t->gap.p0); assert(t->gap.p1 <= t->alloced); assert(t->length <= t->alloced); assert(!(p=findnull(t->text, t->text + t->gap.p0))); assert(!(p=findnull(t->text + t->gap.p1, t->text + t->alloced))); assert( TEXT_ISTAG(t) || t->data); /* if we're not a tag, we have data */ #endif return true; } /* Read the contents of 't' from 'fd', which should have 'len' bytes. * Return 0 for success, -1 for failure */ int text_read(Text *t, int fd, int len) { int desired, nread; char buf[BUFFERSIZE]; extern int utftotext_unconverted; int offset; /* Ensure we have enough rune space. Do it one * block to avoid fragmentation */ desired = len*sizeof(Rune) + GAPSIZE; if (t->alloced < desired) { t->alloced = desired; free(t->text); t->text = salloc(t->alloced * sizeof(Rune)); } t->length = 0; t->pos = 0; offset = 0; while(len > 0) { desired = MIN(len, BUFFERSIZE - offset); nread = read(fd, buf + offset, desired); if(nread<=0) return -1; t->length += utftotext(t->text+t->length, buf, buf + nread +offset); len -= nread; /* * If there were bytes at the end of the buffer that * weren't a complete rune, copy them back to the * start of the buffer for the next time. */ if ( (offset = utftotext_unconverted)) { memcpy(buf, buf + desired - offset, offset); } } t->gap = range(t->length, t->alloced); undo_reset(t); undo_start(t); close(fd); viewlist_refresh(t->v); return 0; } /** * Convert the runes in [r0, r1) to UTF and write to 'fd'. * Return 0 for success. **/ static int utfwrite(Rune *r0, Rune *r1, int fd) { char buf[BUFFERSIZE+UTFmax]; Rune *p; char *t; int nwrite, nwritten; assert(r1 >= r0); assert(fd >= 0); p = r0; while(p < r1) { t = buf; while(p 0; nwrite -= nwritten, t += nwritten) { nwritten = write(fd, t, nwrite); if (nwritten <= 0) return -1; } } return 0; } void gaptranslate (Range r, Range gap, Range *before, Range *after) { Range NULLRANGE = {0,0}; /* Before the gap */ *before = (r.p0 < gap.p0) ? range(r.p0, MIN(r.p1, gap.p0)) : NULLRANGE; /* After the gap */ *after = (r.p1 > gap.p0) ? range (MAX(gap.p1, r.p0 + RLEN(gap)), r.p1 + RLEN(gap)) : NULLRANGE; } /* Write section 'r' of 't' to 'fd'. Return 0 for success */ int text_write_range(Text*t, Range r, int fd) { Range b, a; /* before, after the gap */ gaptranslate(r, t->gap, &b, &a); return utfwrite(t->text + b.p0, t->text + b.p1, fd) || utfwrite(t->text + a.p0, t->text + a.p1, fd); } /* Fill 'buf' with (legal) range 'logical'. */ void text_copy(Text *t, Range r, Rune *buf) { Range b,a; /* before and after the gap */ ulong bsize; assert(text_invariants(t)); assert((r.p1 >= r.p0) && (r.p1 <= t->length)); gaptranslate(r, t->gap, &b, &a); bsize = RLEN(b); memcpy(buf, t->text +b.p0, bsize*sizeof(Rune)); buf += bsize; memcpy(buf, t->text + a.p0, RLEN(a)*sizeof(Rune)); } Text * text_alloc(Data *d, Bool isbody) { Text *t; t = NEW(Text); t->alloced = 0; t->text = 0; t->length = 0; t->pos = 0; t->gap = nr; t->data = d; t->isbody = isbody; t->v = 0; /* to be assigned later */ t->did = t->undone = t->mark = 0; t->undoing = NoUndo; t->needsbackup = false; return t; } /* Replace data in range 'r' of 't' with 's'. Update displays. * Return the range of the inserted text. */ Range text_replace(Text *t, Range r, Rstring s) { ulong rlen = RLEN(r); ulong rslen = RSLEN(s); int delta = rslen - rlen; assert(ROK(r) && RSOK(s) && r.p1 <= t->length); assert(text_invariants(t)); assert(!findnull(s.r0, s.r1)); if(!(RLEN(r) || RSLEN(s))) return r; undo_record(t, r, s); if(t->gap.p0 != r.p0 || RLEN(t->gap) < delta) setgap(t, r.p0, delta); memcpy(t->text + t->gap.p0, s.r0, rslen*sizeof(Rune)); t->gap.p1 += rlen; t->gap.p0 += rslen; t->length += delta; /* invalidate cache? */ viewlist_replace(t->v, r, s); if(t->data){ if(TEXT_ISTAG(t)) tag_modified(t, r.p0); else data_sendreplace(t->data, r, s); } r.p1 = r.p0 + rslen; assert(text_invariants(t)); return r; } /* Clean up any resources which t uses. */ void text_free(Text *t) { undo_free(t); if(t->text) free(t->text); } /************* static functions *********************/ static void movegap(Text *t, ulong p) { assert(text_invariants(t)); /* move the gap to 'p' */ if (p < t->gap.p0) { memmove(t->text + p + RLEN(t->gap), t->text + p, (t->gap.p0 - p)*sizeof(Rune)); t->gap.p1 -= t->gap.p0 - p; t->gap.p0 = p; } else if (p > t->gap.p0) { memmove (t->text + t->gap.p0, t->text + t->gap.p1, (p - t->gap.p0)*sizeof(Rune)); t->gap.p1 = p + RLEN(t->gap); t->gap.p0 = p; } assert(text_invariants(t)); } /* Move the gap for 't' to 'p', ensure we can grow by at least 'n' */ static void setgap(Text *t, ulong p, int n) { int extra; assert(text_invariants(t)); movegap(t,p); assert(text_invariants(t)); extra = n - RLEN(t->gap); if (extra <= 0) return; /* Expand the gap */ extra += GAPSIZE; t->alloced += extra; t->text = srealloc(t->text, t->alloced * sizeof(Rune) ); /* Add this to the gap */ memmove ( t->text + t->gap.p1 + extra, t->text + t->gap.p1, (t->alloced - extra - t->gap.p1)*sizeof(Rune) ); t->gap.p1 += extra; assert(text_invariants(t)); } wily-0.13.41/wily/wily.h100644 2743 200 2133 6401466061 13301 0ustar garypgrad/******************************************* * Includes a bunch of header files *******************************************/ #ifndef WILY_H #define WILY_H #include #include #include #include #include #include #define IMPLIES(a,b) (!(a)||(b)) #include #include #include "const.h" typedef struct stat Stat; typedef char Path[MAXPATH]; typedef Rune RPath[MAXPATH]; typedef struct View View; /* see view.h */ typedef struct Scroll Scroll; /* see scroll.c */ typedef struct Text Text; /* see text.h */ typedef struct Data Data; /* see data.h */ typedef struct Undo Undo; /* see undo.c */ typedef struct Tile Tile; /* see tile.h */ typedef struct Rstring Rstring; typedef struct Mbuf Mbuf; struct Mbuf { char *buf; /* alloced initially, never freed */ int alloced; int n; }; struct Rstring { Rune *r0, *r1; }; /* elements of the Rstring are >= r0 and < r1 */ #define RSLEN(r) ((r).r1 -(r).r0) #define RSOK(r) ((r).r1 >= (r).r0) #define RSFREE(r) free((r).r0) /* GLOBALS */ #include "global.h" #include "proto.h" #endif wily-0.13.41/wily/grow.c100644 2743 200 3703 6332624741 13276 0ustar garypgrad/******************************************* * grow tiles by different amounts *******************************************/ #include "tile.h" /************************************************************ Tile growth functions: Modify tile->min, tile->max, possibly min and max for tile's siblings. After these functions, every visible tile will have the _size_ which we want, but the tiles may not abutt, and may not fit into tile->up. We rely on list_reshaped to tidy these things up. ************************************************************/ /* grow tile a little */ static void gsome(Tile*tile) { tile->min -= tile->base*2; tile->max += tile->base*2; } /* grow tile lots */ static void gmost(Tile*tile) { Tile *t, *up = tile->up; int space = 0; /* space either above or below 'tile' */ for (t = up->down; t; t=t->right) { if (t != tile) { space += t->base; t->max = t->min + t->base; } else { t->min = space + up->cmin; space = 0; /* start counting space _above_ tile */ } } tile->max = up->cmax - space; } /* grow tile way lots */ static void gall(Tile *tile) { Tile *t, *up = tile->up; for (t = up->down; t; t=t->right) { if (t != tile) t->ishidden = true; } tile->min = up->cmin; tile->max = up->cmax; } /************************************************************ End of Tile growth functions: ************************************************************/ /* Grow 'tile' by some amount */ void tile_grow(Tile *tile, int buttons) { assert(list_invariant(tile->up)); list_unhide(tile->up); /* Adjust the placement of tile, and possibly tile's siblings. Don't worry too much about placing them. Relies on list_reshaped to do the placement and redisplay. */ switch (buttons) { case 1: gsome(tile); break; case 2: gmost(tile); break; case 4: gall(tile); break; default: gsome(tile); break; } list_reshaped(tile->up, tile); assert(list_invariant(tile->up)); } wily-0.13.41/wily/point.c100644 2743 200 2763 6332625154 13455 0ustar garypgrad/******************************************* * geometry stuff for tiles and views *******************************************/ #include "tile.h" #include "view.h" /* Set 'cmin' and 'cmax' for any child of 'list' */ void setcminmax(Tile *list, int*cmin, int*cmax) { if(list) { *cmin = (list->ori == V)? list->tag->r.max.y + tagheight:list->min; *cmax = list->max; } else { *cmin = 0; *cmax = screen.r.max.x; } } /* Return the Rectangle to enclose 't' */ Rectangle rectangle(Tile*t) { if(t->ori==H) { return Rect(t->min, t->up->tag->r.max.y, t->max, t->up->max); } else if (t->up) { return Rect(t->up->min, t->min, t->up->max, t->max); } else { return Rect(0, t->min, t->cmax, t->max); } } /* Return a point somewhere in the middle of 'tile's button */ Point buttonpos(Tile*tile) { return add(tile->tag->r.min, Pt(SCROLLWIDTH/2, SCROLLWIDTH/2)); } /* Return the tile containing p (or 0) */ Tile* point2tile(Tile *tile, Point p) { int pos; Tile *t; assert(tile); if(tile->body || ptinrect(p, tile->tag->r)) return tile; pos = tile->ori==V ? p.x : p.y ; for (t =tile ->down; t; t=t->right) { if (!tile_hidden(t) && pos < t->max && pos >= t->min) break; } if (t && !tile_hidden(t) && pos > t->min) return point2tile(t,p); return tile; } /* Return the view containing p (or 0) */ View * point2view(Point p) { Tile *t; View *v; t = point2tile(wily, p); if (ptinrect(p, t->tag->r)) v= t->tag; else v = t->body; assert(IMPLIES(v, ptinrect(p, v->r))); return v; } wily-0.13.41/wily/sam.h100644 2743 200 4631 6332624322 13101 0ustar garypgrad/******************************************* * Utility declarations for regexp.c *******************************************/ /* This source file is derived from the sam.h file in the sam distribution, which is: */ /* Copyright (c) 1992 AT&T - All rights reserved. */ /* * sam and wily both define an error() function. To avoid changing * anything in regexp.c, we use a macro to rename it. This relies * on other wily functions including wily.h before sam.h. */ #ifndef WILY_H #define error(X) samerror(X) #define SAM_CODE #endif #define emalloc salloc #define erealloc srealloc #include #include #include #include "wily.h" #include "text.h" #define NSUBEXP 10 /* number of () matches in a regexp */ typedef long Posn; /* file position or address */ typedef struct Address Address; typedef struct File File; typedef struct samRange samRange; typedef struct samRangeset samRangeset; typedef struct String String; typedef struct Inst Inst; typedef enum { Etoolong, Eleftpar, Erightpar, Emissop, Ebadregexp, Ebadclass, Eoverflow } Err; struct String { int n; Rune *s; }; struct samRange { Posn p1, w2; }; struct samRangeset { samRange w[NSUBEXP]; }; struct Address { samRange r; File *f; }; #ifdef TRUE #undef TRUE #endif #ifdef FALSE #undef FALSE #endif enum { FALSE=0, TRUE = 1, RUNESIZE = (sizeof(Rune)), INFINITY = 0x7FFFFFFFL }; /* * In the original sam.h, the File structure is that which manages * all the caches and buffers of the file being edited. We're not * concerned with any of that - we just want to make the contents * of a View look like a File to sam. */ struct File { Text *t; /* the Text that we'll search */ Posn nrunes; /* total length of file */ Address dot; /* current position */ }; #define Fgetc(f) (Tgetc(f->t)) #define Fbgetc(f) (Tbgetc(f->t)) #define Fgetcload(f,p) Tgetcload((f)->t, (p)) #define Fbgetcload(f,p) Tbgetcload((f)->t, (p)) #define Fgetcset(f,p) Tgetcset((f)->t, (p)) #define Fbgetcset(f,p) Tbgetcset((f)->t, (p)) #define Fchars(f,r,p0,p1) Tchars((f)->t, (r),(p0),(p1)) int bexecute(File*, Posn); void compile(String*); int execute(File*, Posn, Posn); void nextmatch(File*, String*, Posn, int); void error_c(Err, int); void panic(char*); void Strduplstr(String *, String *); int Strcmp(String *, String *); void Strzero(String *); void error(Err); /* really samerror() */ extern samRangeset sel; extern Inst *startinst; wily-0.13.41/wily/proto.h100644 2743 200 17456 6422322652 13516 0ustar garypgrad/******************************************* * Declarations of major functions and macros *******************************************/ #ifndef SAM_CODE void error(char *, ...); #endif void fatal(char*,...); /* builtins.c */ Bool builtin (View *, char *, char*); /* click.c */ Range text_doubleclick (Text *, ulong); Range text_expand (Text *, Range, char *); ulong text_startofword (Text *, ulong); /* col.c */ Tile* tile_col (Tile*); void col_new (View*v, char *arg); void col_del (Tile*); /* data.c */ Text* data_body (Data*); Text* data_tag (Data*); char** data_names (Data*d); Bool data_isdirty (Data *d); int data_putall (void); int data_backupall (void); int data_put (Data *d, char *path); int data_del (Data*); int data_backup (Data *d); /* env.c */ void env_init (char **); void pathcontract (char*, char *); /* event.c */ void event_wellknown (int); int event_outputstart (int , int , char*, char*, View *); void keytab_init (void); void dofd (ulong, int, char*); void kill_all (char *s); void kill_list (void); /* exec.c */ void ex_init (void); void run (View *, char *, char *); /* file.c */ View * data_open (char*, Bool); int data_get (Data *d, char *); /* include.c */ View* openinclude (View *v, Range r); /* keyboard.c */ void dokeyboard (View *, Rune); void view_pagedown (View *, Bool ); void view_linesdown (View *v, int n, Bool down); /* label.c */ void data_addcontext (Data*, char*, char*); void data_getlabel (Data*, char*); void data_setlabel (Data*, char *); View * data_find (char*); /* line.c */ int text_linenumber (Text *t, ulong ); Bool text_findline (Text *, Range *, ulong); Range text_lastline (Text *); ulong text_nl (Text *, ulong, int); ulong text_startOfLine (Text *, ulong); /* mouse.c */ void domouse (View*, Mouse*); /* msg.c */ void mbuf_init (Mbuf*); void mbuf_clear (Mbuf*); int partialmsg (Mbuf *, int , int , char*); Bool data_sendreplace (Data *,Range r, Rstring ); Bool data_sendgoto (Data *,Range r, char *); Bool data_sendexec (Data *,char*, char *); void data_fdstop (int ); /* path.c */ void labelclean (char*); void label2path (char*,char*); void envexpand (char*, char*); View* openlabel (char*,Bool); /* place.c */ Tile* findcol (char*); void placedcol (char*, Tile*); /* point.c */ Point buttonpos (Tile*tile); /* sam.c */ Bool text_regexp (Text *, Rstring , Range*, Bool ); Bool text_utfregexp (Text *, char*, Range*, Bool ); long Tchars (Text *, Rune *, ulong, ulong); /* scroll.c */ void scroll_update (Scroll *); void scroll_init (void); Scroll * scroll_alloc (Bitmap *, Rectangle); void scroll_setrects (Scroll*, Bitmap *, Rectangle); void scroll_set (Scroll *, ulong , ulong , ulong ); /* search.c */ Bool text_look (Text*, Range*, Range); Bool text_findliteralutf (Text*, Range*, char*); Bool text_findwordutf (Text*, Range*, char*); Bool text_findliteral (Text*, Range*, Rstring); Bool text_findword (Text*, Range*, Rstring); Bool text_search (Text*, Range*, char *, Range); /* select.c */ Range vselect (View *, Mouse *); /* tag.c */ void tag_set (Text *, char*s); void tag_rmtool (Text *, char *); void tag_addtool (Text *, char *); void tag_modified (Text *, ulong); void tag_reset (Text *); void tag_setlabel (Text *, char *); void tag_settools (Text *, char *); char* tag_gettools (Text *); void tag_addrunning (Text *t, char *cmd); /* tagmatch.c */ void tag_init (char *filename); char* tag_match (char*label); /* text.c */ int text_read (Text *, int fd, int len); int text_write_range (Text *, Range, int); void text_copy (Text *, Range, Rune *); Text* text_alloc (Data *, Bool); Range text_replace (Text *, Range, Rstring); void text_free (Text *); /* text2.c */ void text_allread (Text*t); Data* text_data (Text*); View* text_view (Text*t); ulong text_length (Text*); Bool text_needsbackup (Text*); View* text_body (Text*); void text_setneedsbackup(Text*t, Bool b); Bool text_badrange (Text *t, Range r); void text_addview (Text*, View*); int text_rmview (Text*, View*); int text_write (Text *, char *fname); int text_fd (Text*, Range); Rstring text_autoindent (Text *t, ulong p); int back_height (Text *t, ulong, Font *, int, int); Range text_all (Text*t); void text_fillbutton (Text*t, Fcode f); ulong text_ncopy (Text *, Rune*, ulong , ulong ); Range text_replaceutf (Text*, Range, char*); char* text_duputf (Text*, Range); int text_copyutf (Text *, Range, char *); Bool text_refreshdir (Text*t); void text_formatdir (Text *t, char**); /* tile.c */ Bool tile_hidden (Tile*tile); View* tile_body (Tile*tile); void ereshaped (Rectangle); void tile_del (Tile *); void tile_grow (Tile *, int ); void tile_move (Tile *, Point); void tile_setfont (Tile*, char*); void tile_show (Tile *); View* tile_tag (Tile*); void wily_init (void); /* undo.c */ void undo_record (Text*, Range, Rstring); Range undo_undo (Text*, Bool); Range undo_redo (Text*, Bool); void undo_free (Text*); void undo_reset (Text*); void undo_start (Text*); void undo_break (Text*); void undo_mark (Text*); Bool undo_atmark (Text*); /* util.c */ void dirnametrunc (char*); void addcontext (char*, char*, char*); void olabel (char*out, char*label); int statcmp (Stat*a, Stat*b); Bool isdir (char*path); int backup_name (char *orig, char *back); char * columnate (int, int, Font *, char **); void noutput (char *context, char *base, int n); void add_slash (char*); int distance (Point , Point ); Bool frame_isfull (Frame*); void frgetmouse (void); char* mybasename (char*f); Range paste (Text *, Range); Rstring rstring (Rune*r0, Rune*r1); char* select_get (void); void select_put (char*); void snarf (Text *, Range); int stripnulls (char *buf, int len); ulong texttoutf (char *, Rune *, Rune *); ulong utftotext (Rune *, char *, char *); int diag (char*,char*, ...); void cleanup_and_abort (int); void cleanup_and_die (int); Rstring utf2rstring (char*utf); /* vgeom.c */ void filled (View*, Range ); void extend_selection (View*, Range ); void view_fillbutton (View*v, Fcode f); void fill (View*); void view_setscroll (View*); int snapheight (View*v, int h); void view_reshaped (View*, Rectangle); int view_lastlinepos (View*v); int view_stripwhitespace (View*v); /* view.c */ void view_getdot (View *v, char*buf, Bool isLine); void view_paste (View*v); Range view_expand (View *v, Range r, char *s); View* view_new (Font *, Bool, Text *, Tile *); int view_delete (View *v); Bool view_invariants (View*v); Data* view_data (View*); View* view_body (View*); Tile* view_win (View*); Tile* view_tile (View*); Text* view_text (View*); Range view_getsel (View*); int view_height (View*); void view_cut (View*, Range r); void view_append (View*, char *, int); void view_pipe (View*, Bool *, char *, int); void view_setfont (View*, char*arg); void view_border (View*, Bool); void view_select (View*, Range); void view_warp (View*, Range); void view_setlastselection(View *v); void viewlist_refresh (View*); void viewlist_replace (View*, Range, Rstring); /* vsearch.c */ void b3 (View*, Range r); void view_look (View*, char*); Bool view_goto (View**, Range *r, char *s); /* vshow.c */ void view_show (View*, Range); void view_scroll (View *, Mouse *); void view_hscroll (View*v, Bool left); /* wily.c */ void addrunning (char *cmd); void rmrunning (char *cmd); /* win.c */ int win_del (Tile*); Tile* tile_win (Tile*); void win_clone (Tile*); void win_anchor (Tile*, char *); void win_new (char*, Text*, Text*); #define RECTOK(r) (Dx(r)>=0 && Dy(r) >= 0) #define cls(r) bitblt(&screen, (r).min, &screen, (r), Zero) #define SETSIZE(buf, n, desired) {if(nsize==0) tile_paint(Tile*t, Rect r) { view_paint(tag, r); if (t->type == TILE_WIN) { view_paint(t->contents.body, r2); } else { tileSetPaint(t->contents.children, r2); } } /** TileSet contains a list of tiles, which might be arranged * horizontally (e.g. columns within main wily win) * or vertically (e.g. windows within a column). **/ struct TileSet { Tile **tile; int ntiles, maxtiles; int totalSize; Rectangle r; Bool isHorizontal; } #define TILESIZE(tile) ((tile)->max - (tile)->min) #define LISTSIZE(list) ((list)->cmax - (list)->cmin) #define ISWIN(tile) ( (tile)->type== TILE_WIN ) extern int tagheight; /* height of a tag */ extern Tile *wily; wily-0.13.41/wily/sam.c100644 2743 200 6671 6252763254 13113 0ustar garypgrad/* sam.c - some stubs and interface code to tie sam's regexp.c * to the rest of wily. * S. Kilbane, 13/9/95. */ #include #define SAM_CODE #include "sam.h" static jmp_buf regexp_state; static char *errs[] = { "Etoolong", "Eleftpar", "Erightpar", "Emissop", "Ebadregexp", "Ebadclass", "Eoverflow" }; /* * Initialise a File to the Text given. */ void Finit(File *f, Text*t, Range *r) { f->t = t; f->nrunes = t->length; f->dot.r.p1 = r->p0; f->dot.r.w2 = r->p1; f->dot.f = f; return; } /* * stub routines */ static int do_compile(String *s) { compile(s); return (startinst == 0); } void panic(char *str) { (void)fprintf(stderr,"panic:%s\n",str); exit(1); } void samerror(Err e) { fprintf(stderr, "regexp error: %s\n",errs[e]); longjmp(regexp_state, 1); } void Strduplstr(String *s0, String *s1) { ulong n; n = s1->n; if (s0->n < s1->n) s0->s = srealloc(s0->s, n*RUNESIZE); s0->n = s1->n; memcpy(s0->s, s1->s, n); } int Strcmp(String *s0, String *s1) { Rune *i, *j; if (!s0->s || !s1->s) return 1; for (i = s0->s, j = s1->s; *i && (*i == *j); i++, j++) ; return *i != *j; } void error_c(Err e, int c) { fprintf(stderr, "regexp: %s, %c\n", errs[e], c); longjmp(regexp_state, 1); } void Strzero(String *s) { memset(s->s, 0, s->n*RUNESIZE); } /* * Seems to work, so now I need to sort out the handling of * ranges. I think it should search from the current p1, * wrap around, and continue to before p0. Should probably * play with ACME a bit, and see how that goes... */ /* * text_regexp(t,re,r,fwd) - the interface between wily and sam. * compile the regexp, and do a search from the current point. * If we find a match, set r, and return true. Otherwise, * return false. */ static Bool text_strregexp(Text *t, String str, Range *r, Bool fwd) { File f; Bool found; ulong q0, q1; /* We run into all sorts of setjmp/longjmp madness * if text_strregexp somehow calls itself. * Let's make sure that doesn't happen. * For this same reason, can't use diag anywhere * in sam.c or regexp.c, fprintf(stderr,...) instead. */ static Bool active = false; assert(!active); active = true; if (setjmp(regexp_state)) { found = false; goto out; } found =false; if (do_compile(&str)) { fprintf(stderr, "regexp: compilation failed\n"); goto out; } q0 = r->p0; q1 = r->p1; Finit(&f, t, r); /* first, try after current posn to end of file. */ found = fwd? execute(&f, q1, t->length) : bexecute(&f,q0); if (found) { r->p0 = sel.w[0].p1; r->p1 = sel.w[0].w2; goto out; } /* No good. wrap, and try from start of file. */ found = fwd? execute(&f,0,t->length) : bexecute(&f,t->length); if (found) { r->p0 = sel.w[0].p1; r->p1 = sel.w[0].w2; } out: active = false; return found; } Bool text_utfregexp(Text *t, char *re, Range *r, Bool fwd) { static String str; int l = (1+strlen(re))*sizeof(Rune); if (str.n <= l) { str.n = l; str.s = srealloc(str.s, str.n); } str.s[utftotext(str.s, re, re+strlen(re))] = 0; return text_strregexp(t, str, r, fwd); } Bool text_regexp(Text *t, Rstring re, Range *r, Bool fwd) { static String str; int l = (1+RSLEN(re))*sizeof(Rune); if (str.n <= l) { str.n = l; str.s = srealloc(str.s, str.n); } memcpy(str.s, re.r0, RSLEN(re)*sizeof(Rune)); str.s[RSLEN(re)] = 0; return text_strregexp(t, str, r, fwd); } long Tchars(Text *t, Rune *buf, ulong p0, ulong p1) { Range r; r = range( p0, MIN(p1, t->length)); text_copy(t, r, buf); return RLEN(r); } wily-0.13.41/wily/regexp.c100644 2743 200 36642 6332624545 13644 0ustar garypgrad/******************************************* * Rune regular expression library--stolen from Sam *******************************************/ /* Copyright (c) 1992 AT&T - All rights reserved. */ #include "sam.h" #define emalloc salloc #define erealloc srealloc samRangeset sel; String lastregexp; /* * Machine Information */ struct Inst { long type; /* < 0x10000 ==> literal, otherwise action */ union { int rsid; int rsubid; int class; struct Inst *rother; struct Inst *rright; } r; union{ struct Inst *lleft; struct Inst *lnext; } l; }; #define sid r.rsid #define subid r.rsubid #define rclass r.class #define other r.rother #define right r.rright #define left l.lleft #define next l.lnext #define NPROG 1024 Inst program[NPROG]; Inst *progp; Inst *startinst; /* First inst. of program; might not be program[0] */ Inst *bstartinst; /* same for backwards machine */ typedef struct Ilist Ilist; struct Ilist { Inst *inst; /* Instruction of the thread */ samRangeset se; Posn startp; /* first char of match */ }; #define NLIST 128 Ilist *tl, *nl; /* This list, next list */ Ilist list[2][NLIST]; static samRangeset sempty; /* * Actions and Tokens * * 0x100xx are operators, value == precedence * 0x200xx are tokens, i.e. operands for operators */ enum { OPERATOR = 0x10000, /* Bitmask of all operators */ START = 0x10000, /* Start, used for marker on stack */ RBRA = 0x10001, /* Right bracket, ) */ LBRA = 0x10002, /* Left bracket, ( */ OR = 0x10003, /* Alternation, | */ CAT = 0x10004, /* Concatentation, implicit operator */ STAR = 0x10005, /* Closure, * */ PLUS = 0x10006, /* a+ == aa* */ QUEST = 0x10007, /* a? == a|nothing, i.e. 0 or 1 a's */ ANY = 0x20000, /* Any character but newline, . */ NOP = 0x20001, /* No operation, internal use only */ BOL = 0x20002, /* Beginning of line, ^ */ EOL = 0x20003, /* End of line, $ */ CCLASS = 0x20004, /* Character class, [] */ NCCLASS = 0x20005, /* Negated character class, [^] */ END = 0x20077, /* Terminate: match found */ ISATOR = 0x10000, ISAND = 0x20000 }; /* * Parser Information */ typedef struct Node Node; struct Node { Inst *first; Inst *last; }; #define NSTACK 20 Node andstack[NSTACK]; Node *andp; int atorstack[NSTACK]; int *atorp; int lastwasand; /* Last token was operand */ int cursubid; int subidstack[NSTACK]; int *subidp; int backwards; int nbra; Rune *exprp; /* pointer to next character in source expression */ #define DCLASS 10 /* allocation increment */ int nclass; /* number active */ int Nclass; /* high water mark */ Rune **class; int negateclass; void addinst(Ilist *l, Inst *inst, samRangeset *sep); void newmatch(samRangeset*); void bnewmatch(samRangeset*); void pushand(Inst*, Inst*); void pushator(int); Node *popand(int); int popator(void); void startlex(Rune*); int lex(void); void operator(int); void operand(int); void evaluntil(int); void optimize(Inst*); void bldcclass(void); void regerror(Err e) { Strzero(&lastregexp); error(e); } void regerror_c(Err e, int c) { Strzero(&lastregexp); error_c(e, c); } Inst * newinst(int v) { if(progp >= &program[NPROG]) regerror(Etoolong); progp->type = v; progp->left = 0; progp->right = 0; return progp++; } Inst * realcompile(Rune *s) { int token; startlex(s); atorp = atorstack; andp = andstack; subidp = subidstack; cursubid = 0; lastwasand = FALSE; /* Start with a low priority operator to prime parser */ pushator(START-1); while((token=lex()) != END){ if((token&ISATOR) == OPERATOR) operator(token); else operand(token); } /* Close with a low priority operator */ evaluntil(START); /* Force END */ operand(END); evaluntil(START); if(nbra) regerror(Eleftpar); --andp; /* points to first and only operand */ return andp->first; } void compile(String *s) { int i; Inst *oprogp; if(Strcmp(s, &lastregexp)==0) return; for(i=0; is); optimize(program); oprogp = progp; backwards = TRUE; bstartinst = realcompile(s->s); optimize(oprogp); Strduplstr(&lastregexp, s); } void operand(int v) { Inst *i; if(lastwasand) operator(CAT); /* catenate is implicit */ i = newinst(v); if(v == CCLASS){ if(negateclass) i->type = NCCLASS; /* UGH */ i->rclass = nclass-1; /* UGH */ } pushand(i, i); lastwasand = TRUE; } void operator(int v) { if(v==RBRA && --nbra<0) regerror(Erightpar); if(v==LBRA){ /* * if(++cursubid >= NSUBEXP) * regerror(Esubexp); */ cursubid++; /* silently ignored */ nbra++; if(lastwasand) operator(CAT); }else evaluntil(v); if(v!=RBRA) pushator(v); lastwasand = FALSE; if(v==STAR || v==QUEST || v==PLUS || v==RBRA) lastwasand = TRUE; /* these look like operands */ } void cant(char *s) { char buf[100]; sprint(buf, "regexp: can't happen: %s", s); panic(buf); } void pushand(Inst *f, Inst *l) { if(andp >= &andstack[NSTACK]) cant("operand stack overflow"); andp->first = f; andp->last = l; andp++; } void pushator(int v) { if(atorp >= &atorstack[NSTACK]) cant("operator stack overflow"); *atorp++=v; if(cursubid >= NSUBEXP) *subidp++= -1; else *subidp++=cursubid; } Node * popand(int op) { if(andp <= &andstack[0]) if(op) regerror_c(Emissop, op); else regerror(Ebadregexp); return --andp; } int popator(void) { if(atorp <= &atorstack[0]) cant("operator stack underflow"); --subidp; return *--atorp; } void evaluntil(int pri) { Node *op1, *op2, *v; Inst *inst1, *inst2; while(pri==RBRA || atorp[-1]>=pri){ switch(popator()){ case LBRA: op1 = popand('('); inst2 = newinst(RBRA); inst2->subid = *subidp; op1->last->next = inst2; inst1 = newinst(LBRA); inst1->subid = *subidp; inst1->next = op1->first; pushand(inst1, inst2); return; /* must have been RBRA */ default: panic("unknown regexp operator"); break; case OR: op2 = popand('|'); op1 = popand('|'); inst2 = newinst(NOP); op2->last->next = inst2; op1->last->next = inst2; inst1 = newinst(OR); inst1->right = op1->first; inst1->left = op2->first; pushand(inst1, inst2); break; case CAT: op2 = popand(0); op1 = popand(0); if(backwards && op2->first->type!=END) v = op1, op1 = op2, op2 = v; op1->last->next = op2->first; pushand(op1->first, op2->last); break; case STAR: op2 = popand('*'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(inst1, inst1); break; case PLUS: op2 = popand('+'); inst1 = newinst(OR); op2->last->next = inst1; inst1->right = op2->first; pushand(op2->first, inst1); break; case QUEST: op2 = popand('?'); inst1 = newinst(OR); inst2 = newinst(NOP); inst1->left = inst2; inst1->right = op2->first; op2->last->next = inst2; pushand(inst1, inst2); break; } } } void optimize(Inst *start) { Inst *inst, *target; for(inst=start; inst->type!=END; inst++){ target = inst->next; while(target->type == NOP) target = target->next; inst->next = target; } } #ifdef DEBUG void dumpstack(void){ Node *stk; int *ip; dprint("operators\n"); for(ip = atorstack; ipfirst->type, stk->last->type); } void dump(void){ Inst *l; l = program; do{ dprint("%d:\t0%o\v%d\v%d\n", l-program, l->type, l->left-program, l->right-program); }while(l++->type); } #endif void startlex(Rune *s) { exprp = s; nbra = 0; } int lex(void){ int c= *exprp++; switch(c){ case '\\': if(*exprp) if((c= *exprp++)=='n') c='\n'; break; case 0: c = END; --exprp; /* In case we come here again */ break; case '*': c = STAR; break; case '?': c = QUEST; break; case '+': c = PLUS; break; case '|': c = OR; break; case '.': c = ANY; break; case '(': c = LBRA; break; case ')': c = RBRA; break; case '^': c = BOL; break; case '$': c = EOL; break; case '[': c = CCLASS; bldcclass(); break; } return c; } long nextrec(void){ if(exprp[0]==0 || (exprp[0]=='\\' && exprp[1]==0)) regerror(Ebadclass); if(exprp[0] == '\\'){ exprp++; if(*exprp=='n'){ exprp++; return '\n'; } return *exprp++|0x10000; } return *exprp++; } void bldcclass(void) { long c1, c2, n, na; Rune *classp; classp = emalloc(DCLASS*RUNESIZE); n = 0; na = DCLASS; /* we have already seen the '[' */ if(*exprp == '^'){ classp[n++] = '\n'; /* don'v match newline in negate case */ negateclass = TRUE; exprp++; }else negateclass = FALSE; while((c1 = nextrec()) != ']'){ if(c1 == '-'){ Error: free(classp); regerror(Ebadclass); } if(n+4 >= na){ /* 3 runes plus NUL */ na += DCLASS; classp = erealloc(classp, na*RUNESIZE); } if(*exprp == '-'){ exprp++; /* eat '-' */ if((c2 = nextrec()) == ']') goto Error; classp[n+0] = 0xFFFF; classp[n+1] = c1; classp[n+2] = c2; n += 3; }else classp[n++] = c1; } classp[n] = 0; if(nclass == Nclass){ Nclass += DCLASS; class = erealloc(class, Nclass*sizeof(Rune*)); } class[nclass++] = classp; } int classmatch(int classno, int c, int negate) { Rune *w; w = class[classno]; while(*w){ if(*w == 0xFFFF){ if(w[1]<=c && c<=w[2]) return !negate; w += 3; }else if(*w++ == c) return !negate; } return negate; } /* * Note optimization in addinst: * *l must be pending when addinst called; if *l has been looked * at already, the optimization is a bug. */ void addinst(Ilist *l, Inst *inst, samRangeset *sep) { Ilist *w; for(w = l; w->inst; w++){ if(w->inst==inst){ if((sep)->w[0].p1 < w->se.w[0].p1) w->se= *sep; /* this would be bug */ return; /* It's already there */ } } w->inst = inst; w->se= *sep; (w+1)->inst = 0; } int execute(File *f, Posn startp, Posn eof) { int flag = 0; Inst *inst; Ilist *tlp; Posn w = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = startinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.w[0].p1 = -1; Fgetcset(f, startp); /* Execute machine once for each character */ for(;;w++){ doloop: c = Fgetc(f); if(w>=eof || c<0){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to beginning */ if(sel.w[0].p1>=0 || eof!=INFINITY) goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, (Posn)0); w = 0; goto doloop; default: goto Return; } }else if(((wrapped && w>=startp) || sel.w[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.w[0].p1<0 && (!wrapped || w= NLIST) Overflow: error(Eoverflow); sempty.w[0].p1 = w; addinst(tl, startinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst) ; tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type==c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.w[inst->subid].p1 = w; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid>=0) tlp->se.w[inst->subid].w2 = w; inst = inst->next; goto Switchstmt; case ANY: if(c!='\n') goto Addinst; break; case BOL: if(w == 0){ Step: inst = inst->next; goto Switchstmt; } { Rune c2; if(Fchars(f, &c2, w-1, w)==1 && c2=='\n') goto Step; } break; case EOL: if(c == '\n') goto Step; break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.w[0].w2 = w; newmatch(&tlp->se); break; } } } Return: return sel.w[0].p1>=0; } void newmatch(samRangeset *sp) { int i; if(sel.w[0].p1<0 || sp->w[0].p1w[0].p1==sel.w[0].p1 && sp->w[0].w2>sel.w[0].w2)) for(i = 0; iw[i]; } int bexecute(File *f, Posn startp) { int flag = 0; Inst *inst; Ilist *tlp; Posn w = startp; int nnl = 0, ntl; int c; int wrapped = 0; int startchar = bstartinst->typetype : 0; list[0][0].inst = list[1][0].inst = 0; sel.w[0].p1= -1; Fgetcset(f, startp); /* Execute machine once for each character, including terminal NUL */ for(;;--w){ doloop: if((c = Fbgetc(f))==-1){ switch(wrapped++){ case 0: /* let loop run one more click */ case 2: break; case 1: /* expired; wrap to end */ if(sel.w[0].p1>=0) case 3: goto Return; list[0][0].inst = list[1][0].inst = 0; Fgetcset(f, f->nrunes); w = f->nrunes; goto doloop; default: goto Return; } }else if(((wrapped && w<=startp) || sel.w[0].p1>0) && nnl==0) break; /* fast check for first char */ if(startchar && nnl==0 && c!=startchar) continue; tl = list[flag]; nl = list[flag^=1]; nl->inst = 0; ntl = nnl; nnl = 0; if(sel.w[0].p1<0 && (!wrapped || w>startp)){ /* Add first instruction to this list */ if(++ntl >= NLIST) Overflow: error(Eoverflow); /* the minus is so the optimizations in addinst work */ sempty.w[0].p1 = -w; addinst(tl, bstartinst, &sempty); } /* Execute machine until this list is empty */ for(tlp = tl; (inst = tlp->inst); tlp++){ /* assignment = */ Switchstmt: switch(inst->type){ default: /* regular character */ if(inst->type == c){ Addinst: if(++nnl >= NLIST) goto Overflow; addinst(nl, inst->next, &tlp->se); } break; case LBRA: if(inst->subid>=0) tlp->se.w[inst->subid].p1 = w; inst = inst->next; goto Switchstmt; case RBRA: if(inst->subid >= 0) tlp->se.w[inst->subid].w2 = w; inst = inst->next; goto Switchstmt; case ANY: if(c != '\n') goto Addinst; break; case BOL: if(c=='\n' || w==0){ Step: inst = inst->next; goto Switchstmt; } break; case EOL: if(wnrunes-1){ Rune c2; if(Fchars(f, &c2, w, w+1)==1 && c2=='\n') goto Step; } break; case CCLASS: if(c>=0 && classmatch(inst->rclass, c, 0)) goto Addinst; break; case NCCLASS: if(c>=0 && classmatch(inst->rclass, c, 1)) goto Addinst; break; case OR: /* evaluate right choice later */ if(++ntl >= NLIST) goto Overflow; addinst(tlp, inst->right, &tlp->se); /* efficiency: advance and re-evaluate */ inst = inst->left; goto Switchstmt; case END: /* Match! */ tlp->se.w[0].p1 = -tlp->se.w[0].p1; /* minus sign */ tlp->se.w[0].w2 = w; bnewmatch(&tlp->se); break; } } } Return: return sel.w[0].p1>=0; } void bnewmatch(samRangeset *sp) { int i; if(sel.w[0].p1<0 || sp->w[0].p1>sel.w[0].w2 || (sp->w[0].p1==sel.w[0].w2 && sp->w[0].w2w[i].w2; sel.w[i].w2 = sp->w[i].p1; } } wily-0.13.41/wily/text.h100644 2743 200 2717 6332626025 13312 0ustar garypgrad/* * The Text is the non-visible counterpart to the View. It maintains * the internal data structure of the whole file, but has no knowledge * about how to display things. The Text is also responsible for * maintaining Undo information. * * There may be one or more Views of a particular piece of text. */ struct Text { Rune *text; /* where we store stuff */ ulong alloced,length; Range gap; /* buffer gap */ Data *data; /* 0 for wilytag or columntag */ Bool isbody; View *v; /* list of views of this text */ Bool needsbackup; /* this text can become dirty */ ulong pos; /* position for regexp search engine */ Undo *did,*undone, *mark; enum {NoUndo, StartUndo, MoreUndo} undoing; }; #define TEXT_ISTAG(t) ( !(t)->isbody ) /* A set of macros to traverse all the runes within a text, * useful for searching. * * To traverse forwards * Tgetcset(text, pos) sets a starting position * Tgetc(text) returns the next rune (or -1) * To traverse backwards, use Tbgetcset(t,p), Tbgetc(t) */ #define Tgetcset(t,p) ((t)->pos = (p)) #define Tgetc(t) ( \ ((t)->pos < (t)->gap.p0) ? \ ((t)->text[(t)->pos++] ) : \ (((t)->pos < (t)->length) ? \ (t)->text[(t)->pos++ + RLEN((t)->gap)] : \ -1)) #define Tbgetc(tp) ( ((tp)->pos > (tp)->gap.p0) ? \ (tp)->text[--(tp)->pos + RLEN((tp)->gap)] : \ ( (tp)->pos ? (tp)->text[--(tp)->pos] : -1) ) #define Tbgetcset(t,p) ( (t)->pos = (p)) /* TODO - a builtin literal search could be quite a bit quicker */ wily-0.13.41/wily/tag.c100644 2743 200 7303 6332625350 13070 0ustar garypgrad/******************************************* * Maintain and monitor tags *******************************************/ #include "wily.h" #include "view.h" #include "text.h" #include #include /* The tag for a window contains: a label then whitespace, then some * system-maintained tools, then a pipe symbol, then user stuff. */ static char * whitespace_regexp = "[ \t\n]+"; static Range tag_findtool(Text *, char*); static Bool wily_modifying_tag = false; /************************************************ Gettools and Settools only used by the messaging interface. It's still up in the air what exactly they should do. TODO - ensure space before/after "|" separator. ************************************************/ char* tag_gettools(Text*t){ Range r; r = nr; if(text_utfregexp(t, "\\|.*", &r, true)) { r.p0++; return text_duputf(t, r); } else { return ""; } } void tag_settools(Text*t, char*s) { Range r = nr; ulong len; if(text_utfregexp(t, "\\|.*", &r, true)) { r.p0++; } else { len = text_length(t); r = range(len,len); } text_replaceutf(t,r,s); } void tag_set(Text*t, char*s) { assert(TEXT_ISTAG(t)); wily_modifying_tag = true; text_replaceutf(t, text_all(t), s); wily_modifying_tag = false; } void tag_setlabel(Text *t, char *s) { Range r; Path buf; ulong l; wily_modifying_tag = true; /* find first whitespace_regexp */ r = range(0,0); if(! text_utfregexp(t, whitespace_regexp, &r, true)) { l = text_length(t); r = range(l,l); } r.p0 = 0; sprintf(buf, "%s ", s); text_replaceutf(t, r, buf); wily_modifying_tag = false; } /* Remove 's' from the tool section of tag 't', if it exists there. */ void tag_rmtool(Text *t, char *s) { Range r; wily_modifying_tag = true; r = tag_findtool(t, s); if(RLEN(r)) text_replace(t, r, rstring(0,0)); if(STRSAME(s,"Put")) text_fillbutton(t, Zero); wily_modifying_tag = false; } /* Replace 'r' in 't' with 's' and a trailing space */ static void place_tool(Text*t, Range r, char*s) { Path tmp; sprintf(tmp, "%s ", s); text_replaceutf(t,r,tmp); } /* * Add a string to represent a running command to 't'. * * Almost the same as tag_addtool, the difference being * that tag_addrunning will create duplicates, e.g. the * tag could read "xterm xterm " */ void tag_addrunning(Text *t, char *cmd) { Range r; r = tag_findtool(t,cmd); r.p0 = r.p1; /* don't replace */ place_tool(t,r,cmd); } /* Add 's' to the tool section of tag 't', unless it's there already. */ void tag_addtool(Text *t, char *s) { Range r; wily_modifying_tag = true; r = tag_findtool(t,s); if(!RLEN(r)) place_tool(t,r,s); if(STRSAME(s,"Put")) text_fillbutton(t, F); wily_modifying_tag = false; } /* If 's' is in the system tools section of t, return the range * containing 's' and all the immediately following whitespace. * Otherwise return a 0-length range where the next tool * should be inserted. */ static Range tag_findtool(Text*t, char*s) { Range pos, endpos; ulong l; endpos = pos = nr; if(text_findliteralutf(t, &endpos, "|")) { endpos.p1 = endpos.p0; } else { l = text_length(t); endpos = range(l,l); } if(text_findwordutf(t, &pos, s) && pos.p0 < endpos.p0) return pos; return endpos; } /* * 't' has been modified in some fashion. 'p' is the index of the * most recently modified character. */ void tag_modified(Text*t, ulong p) { Range r; Path buf; int n; assert(t->data && TEXT_ISTAG(t)); if( wily_modifying_tag) return; /* find first whitespace_regexp */ r = nr; if(text_utfregexp(t, whitespace_regexp, &r, true)) { if(p>r.p0) return; r.p1 = r.p0; r.p0 = 0; } else { r = text_all(t); } n = text_copyutf(t, r, buf); buf[n] = 0; data_setlabel(text_data(t), buf); } wily-0.13.41/wily/tile.h100644 2743 200 4217 6541710150 13253 0ustar garypgrad#include "wily.h" typedef enum Ori { H, V } Ori; /* Windows and Wily itself have V orientation, * columns have H orientation */ struct Tile { View *tag; /* every tile has a tag */ View *body; /* window tiles also have a body */ int min,max; /* starting and ending location */ int base; /* Minimum size of tile. */ Ori ori; /* orientation of _our_ min and max */ Bool ishidden; /* is this tile currently hidden? */ Tile *up, *down; /* parent, child */ Tile *left, *right; /* siblings */ int cmin, cmax; /* start and end locations of children */ }; #define TILESIZE(tile) ((tile)->max - (tile)->min) #define LISTSIZE(list) ((list)->cmax - (list)->cmin) #define ISWIN(tile) ( (tile)->body!= 0 ) /* loop over every visible child in the halfopen range [start,end) */ #define FOR_EACH_VISIBLE(start,end)\ for(t=(start); t!=(end);t=t->right)\ if (!t->ishidden) #define FOR_EACH_TILE(start,end)\ for(t=(start); t!=(end);t=t->right) extern int tagheight; /* height of a tag */ extern Tile *wily; Bool tile_invariant(Tile *tile); Bool list_invariant(Tile *list); View * point2view(Point pt); void tile_reshaped(Tile *t); Tile* point2tile(Tile *tile, Point p); void list_unhide(Tile*list); Tile* last_visible_body(Tile*start, Tile*end); void list_reshaped(Tile *l, Tile *t); Tile* newparent(Tile*tile, Point p); Tile* point2tile(Tile *tile, Point p); View * point2view(Point p); void list_unhide(Tile*list); void findplace(Tile*list, int *min, int *max); void list_slide(Tile *t) ; Tile* biggest_visible(Tile*start, Tile*end); Tile* last_visible_body(Tile*start, Tile*end); Tile* last_visible(Tile*start, Tile*end); int list_size(Tile *start, Tile *end); int list_basesize(Tile*start, Tile*end); Tile* list_find(Tile*parent, int n); Tile* next_visible(Tile*t); void setcminmax(Tile *list, int*cmin, int*cmax); void moveto(Tile*t, int pos); Rectangle rectangle(Tile*t); int adjust_sizes_in_range(Tile*start, Tile*end, int available); Tile* tile_new(Ori, int, int, int, Tile*, Text *, Text*); int tile_minsize(Tile*t); void list_add(Tile *list, Tile *tile); Bool list_oksizes(Tile*list); Bool list_contains(Tile*start, Tile*end, Tile *want); wily-0.13.41/wily/adjust.c100644 2743 200 5701 6541710226 13606 0ustar garypgrad/***************************************************************** Collection of functions to reduce the size of a tile. Each reduces the tile's size, and return the amount of savings. They appear in order of severity. *****************************************************************/ #include "tile.h" /* If t's body contains any blank lines, get rid of them */ static int stripwhitespace(Tile *t, int excess) { int saving,size; if (!t->body ) return 0; size = TILESIZE(t); /* Possibly we've already mangled this tile, so it can no longer * properly contain its body and tag */ if(size < view_height(t->body) + view_height(t->tag)) return 0; if((saving = view_stripwhitespace(t->body))) { assert(saving < size); saving = MIN(saving, excess); t->max -= saving; assert(TILESIZE(t) >= t->base); } return saving; } /* Halve the amount by which t's size exceeds t->base */ static int halve(Tile*t, int excess) { int saving,size = TILESIZE(t); int extra = size - t->base; if(extra > 0) { saving = MIN(extra/2, excess); t->max -= saving; return size - TILESIZE(t); } return 0; } /* Shrink 't' down to t->base */ static int shrink(Tile *t, int excess) { int saving = MIN(TILESIZE(t) - t->base, excess); t->max -= saving; return saving; } /* Hide 't': => size = 0 */ static int hide(Tile *t, int excess) { assert(TILESIZE(t) == t->base); /* we've already done 'shrink' */ t->ishidden = true; return t->base; } typedef int (*SizeAdjust)(Tile*, int); SizeAdjust method [] = { stripwhitespace, halve, shrink, hide, 0 }; /***************************************************************** End of Collection of functions to reduce the size of a tile. *****************************************************************/ /* * Adjust the sizes of the tiles in [start,end) so that they add to * <= 'available'. * Return the total size. */ int adjust_sizes_in_range(Tile*start, Tile*end, int available) { Tile *t; int size,saving,excess; int now; int j; SizeAdjust m; /* method to adjust the size of a tile */ assert(available >= 0); size = list_size(start,end); for(j=0; (m=method[j]); j++) { FOR_EACH_VISIBLE(start,end){ assert(size == (now = list_size(start, end))); excess = MAX(size - available, 0); saving = (*m)(t, excess); assert(t->ishidden || (TILESIZE(t) >= t->base)); size -= saving; /* check our math */ assert(size == (now = list_size(start, end))); if (size <= available) { /* C doesn't have labelled break. So sue me. */ goto out; } } } out: /* check our math */ assert(size == (now = list_size(start, end))); assert (size <= available); /* Even if we had to hide everything */ /* If we've taken too much, return some size to the last visible tile */ if(sizemax += available - size; size = available; now = list_size(start,end); assert( size == now); } assert( size <= available); assert (size >= 0); return size; } wily-0.13.41/wily/global.c100600 2743 200 1043 6541666633 13553 0ustar garypgrad#include "wily.h" Bool show_dot_files = false; Bool autoindent_enabled = true; /* cwd for wily process */ Path wilydir; /* widget with most recent b1 click */ View * last_selection; /* "stop" characters for various text expansions. * heuristic guesses only. */ char *notfilename = "!\"#%&'()*;<=>?@`[\\]^{|}"; char *notinclude = "!#%&'()*;=?@`[\\]^{|}"; char *notdoubleclick= "!\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~"; char *notcommand= "!\"#%&'()*;:=?@`[\\]^{}"; char *notaddress= "!\"%&'()+;<=>?@`[]{|}"; char *whitespace = " \t\v\n"; wily-0.13.41/wily/win.c100644 2743 200 2726 6422322537 13117 0ustar garypgrad/******************************************* * add and delete windows *******************************************/ #include "tile.h" static void win_place(Tile *col, Text *tag, Text *body); /* Free the resources tied up by 'win'. Return 0 for success. */ int win_del(Tile *w) { if(!w) return 0; assert(ISWIN(w)); /* make sure we can delete the body */ if(view_delete(w->body)){ return -1; } /* delete the tag, and the tile */ view_delete(w->tag); tile_del(w); return 0; } /* Return the window associated with 'tile', or 0. */ Tile* tile_win(Tile*tile) { return (tile && tile->body) ? tile : 0; } /* clone 'win' */ void win_clone(Tile *win) { Text *tag, *body; assert(ISWIN(w)); tag = view_text(win->tag); body = view_text(win->body); win_place(win->up, tag, body); } /* Create a window to represent 'path' */ void win_new(char*path, Text*tag, Text*body) { Tile * col; col = findcol(path); win_place(col, tag, body); } /* Add some text to w's tag representing the current selection */ void win_anchor(Tile*w, char *arg) { char buf[80]; assert(ISWIN(w)); view_getdot(w->body, buf, arg!=0); tag_addtool(view_text(w->tag), buf); } /** Create and place a new window with the given 'tag' and 'body' * text, in the given 'col'umn **/ static void win_place(Tile *col, Text *tag, Text *body) { Tile *win; int max, min; findplace(col, &min, &max); win = tile_new(V, min, max, tagheight, col, tag, body); list_add(col, win); assert(ISWIN(win)); } wily-0.13.41/wily/NOTES100644 2743 200 3021 6332627526 12764 0ustar garypgradCoding conventions Everything before the first blank line in each file is a comment about that whole file. Functions manipulating a Fish structure are called fish_functionName() TEXT.C buffer gap implementation: The buffer is represented as a contiguous array of Runes, with a "gap". To insert or delete text, we move the gap to the required position, then add text into the gap or expand the gap. Anywhere else which needs to access the buffer has to get to it through text_copy or text_replace. SEARCH.C handles literal search, double-click and other expansion, line counting, ... For efficiency, grabs text from the buffer into a buffer and works from the buffer. SAM.C wrapper to support regexp.c from the program sam. Uses the buffering code in search.c. The buffering is optimised to go in one direction or the other, and regexp.c uses the internal structure of that buffer :-( VIEW.C Glue to connect frames, which actually display stuff, and text buffers. Must cope with the fact that sometimes views have zero height (if they're squeezed out by the other views), and sometimes views change size (by adding text to a tag). If a view has been squeezed, then it has zero height, its frame has been frclear'ed, and you should not attempt to update the frame. NAMES A file name may be: 1. a short file name, for typing or for window labels 2. a unique identifier for a file 3. a name which the file system understands We should distinguish between these usages and meanings. A file name is possibly not the best thing for 2. wily-0.13.41/wily/cursor.c100644 2743 200 2224 6332625624 13633 0ustar garypgrad/******************************************* * Cursor bitmaps *******************************************/ /* Copyright (c) 1992 AT&T - All rights reserved. */ #include #include #include Cursor boxcursor = { {-7, -7}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00} }; Cursor fatarrow = { { -1, -1 }, { 0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c, 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04, 0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40, }, { 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0, 0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8, 0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8, 0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00, }, }; Cursor *cursor=&fatarrow; /* Cursor *cursor=0; thin cursor */ wily-0.13.41/wily/vgeom.c100644 2743 200 10140 6415674655 13461 0ustar garypgrad/******************************************* * view size and reshaping *******************************************/ #include "wily.h" #include "view.h" static Rectangle snap(View*v, Rectangle r); static Rectangle resizebox(Rectangle r); static void rfill(Rectangle r, Fcode f); static void button_set(View *v); static void setrects(View*v, Rectangle r); void view_fillbutton(View*v, Fcode f){ rfill(resizebox(v->r), f); } /* PRE: v->visible.p0 is correct. The text which is currently displayed in the frame is correct, but there might not be enough. POST: The frame is displaying everything it should, and v->visible.p1 is set. */ void fill(View *v) { Frame *f = &v->f; ulong p; /* text position of last visible rune */ Rune buf[FILLCHUNK]; int n; Text *t = v->t; /* view_invariants may not hold at this point */ if(!f->b) return; /* Add runes until we exhaust the text or fill the frame */ p = v->visible.p0 + f->nchars; while (!frame_isfull(f) && (n = text_ncopy(t, buf, p, FILLCHUNK)) ) { frinsert(f, buf, buf+n, f->nchars); p += n; } v->visible.p1 = v->visible.p0 + f->nchars; if(v->scroll) scroll_set(v->scroll, v->visible.p0, f->nchars, text_length(v->t) ); else button_set(v); /* Ensure that if v->sel is in the visible area, it is selected */ frselectp(f, F&~D); f->p0 = clip(v->sel.p0 - v->visible.p0, 0, f->nchars); f->p1 = clip(v->sel.p1 - v->visible.p0, 0, f->nchars); frselectp(f, F&~D); assert(view_invariants(v)); } int snapheight(View*v, int h) { int lines; int fh = v->f.font->height; int brdr = 2*INSET; if (v->scroll) { lines = (h - brdr) / fh; if (lines == 0) return 0; else return h; } else return brdr + fh; } /* Try to redraw 'v' inside 'r' */ void view_reshaped(View*v, Rectangle r) { Frame *f; assert(view_invariants(v)); r = snap(v,r); setrects(v, r); if (ISVISIBLE(v)) { if(text_refreshdir(v->t)){ v->visible.p0 = v->sel.p0 = v->sel.p1 = 0; frdelete(&v->f, 0, v->f.nchars); } fill(v); /* Clean up any trailing junk. */ f = &v->f; /* Last line. */ r.max = r.min = frptofchar(f, f->nchars + 1); r.max.x = f->r.max.x; r.max.y += f->font->height; if (r.min.x != r.max.x) cls(r); /* Below last line. */ r.min.x = f->r.min.x; r.min.y = r.max.y; r.max.y = v->r.max.y; if (r.min.y != r.max.y) cls(r); view_border(v, v == last_selection); } } /* Return point just after the last line in 'v' */ int view_lastlinepos(View*v) { Frame *f = &v->f; Point p = frptofchar(f, f->nchars); int y = p.y + f->font->height; return MIN(y, f->r.max.y); } /* Return the amount by which 'v' could be squeezed */ int view_stripwhitespace(View*v) { Frame *f; int blanklines; if(v && ISVISIBLE(v)) { f = &v->f; assert(Dy(v->r) >= f->maxlines * f->font->height); blanklines = f->maxlines - f->nlines; if(blanklines > 0) { return blanklines * f->font->height; } } return 0; } static Rectangle snap(View*v, Rectangle r) { r.max.y = r.min.y + snapheight(v, Dy(r)); return r; } /* Fill 'r' according to 'f' */ static void rfill(Rectangle r, Fcode f) { r = inset(r,2); bitblt(&screen, r.min, &screen, r, f); } static Rectangle resizebox(Rectangle r) { r = inset(r, INSET); r.max.x = r.min.x + SCROLLWIDTH; return r; } static void button_set(View *v) { Rectangle r; assert(ISTAG(v)); /* we're a tag */ r = resizebox(v->r); border(&screen, r, 1, F); if(data_isdirty(view_data(tile_body(v->tile)))) rfill(r, F); } /* Set the rectangles for 'v', v's frame and v's scrollbar. * Assumes that 'r' is already correct. * If we can be displayed, set up the frame and scrollbar. */ static void setrects(View*v, Rectangle r) { Frame *f = &v->f; Font *ft = f->font; Rectangle scrollr, framer; Bitmap *b; assert(Dx(r) >= MINWIDTH); /* Or our tile is bizarre */ scrollr = inset(r, INSET); scrollr.max.x = scrollr.min.x + SCROLLWIDTH; framer = inset(r, INSET); framer.min.x += SCROLLWIDTH; framer.min.x += INSET; /* If 'r' is too small, we're hidden: use null bitmap */ b = Dy(r) < tagheight ? 0 : &screen; v->r = r; scroll_setrects(v->scroll, b, scrollr); frclear(f); frinit(f, framer, ft, b); } wily-0.13.41/wily/builtins.c100644 2743 200 13505 6541665505 14177 0ustar garypgrad/******************************************* * Builtin functions *******************************************/ #include "wily.h" #include "view.h" #include #include /* Each of these functions takes a View used as the context * of the command, and an argument. The argument may be null. */ /* * If given arguments, Kill all the external processes matching * the arguments. * * If given no arguments, generate a list of possible 'Kill' commands. */ static void builtin_kill(View*v, char*s) { if (s) kill_all(s); else kill_list(); } /***************************************************** Dotfiles, Font, Indent Toggle operations. These probably _should_ all act similarly, but right now they don't. todo. *****************************************************/ static void dotfiles(View *v, char *arg) { show_dot_files = !show_dot_files; } static void builtin_font(View *v, char *arg) { tile_setfont(view_tile(v), arg); } static void builtin_autoindent(View *v, char *arg) { View *body; if ((body = view_body(v))) { body->autoindent = ! body->autoindent; } else { autoindent_enabled = !autoindent_enabled; } } /***************************************************** Undo, redo. If called with an argument, they each go 'all the way'. *****************************************************/ static void undo_ops(View *v, char*arg, Range (*undofn)(Text*, Bool)) { Range r; if(!(v = view_body(v))) return; r = (*undofn)(v->t, (Bool)arg); if ROK(r) { view_show(v, r); view_select(v, r); } } static void undo(View *v, char *arg){undo_ops(v, arg, undo_undo);} static void redo(View *v, char *arg) {undo_ops(v, arg, undo_redo);} /***************************************************** Get, Put. If called with an argument, they each go 'all the way'. *****************************************************/ /* Read or write the window associated with 'v', possibly using 'arg' */ static void getorput(View*v, char*arg, int(*fn)(Data*,char*)) { Data *d; Path dest; char *s; if (!(d = view_data(v))) return; if (arg && strlen(arg)) { data_addcontext(d, dest, arg); s = dest; } else { s = 0; } (*fn)(d, s); } static void put(View *v, char *arg) {getorput(v, arg, data_put);} static void get(View *v, char *arg) {getorput(v, arg, data_get);} /***************************************************** Quit/Putall ignore the context. *****************************************************/ static void putall(View *v, char *arg) { data_putall(); } static void quit(View *v, char *arg) { cleanup_and_die(0); } /***************************************************** Del, Delcol delete the window or column 'v' belongs to. *****************************************************/ static void del(View *v, char *arg) { win_del(view_win(v)); } static void delcol(View*v, char *arg) { col_del(tile_col(v->tile)); } /***************************************************** Cut/Snarf/Paste all act on last_selection *****************************************************/ static void cut(View *v, char *arg) { if((v=last_selection)) view_cut(v, v->sel); } static void builtin_snarf(View *v, char *arg) { if((v=last_selection)) snarf(v->t, v->sel); } static void builtin_paste(View *v, char *arg) { if((v=last_selection)) view_paste(v); } /***************************************************** Anchor, Split act on either the window of the current context, or the last selection. *****************************************************/ static void anchor(View *v, char *arg) { Tile *win; if ( (win=view_win(v)) || (win=view_win(last_selection)) ) { win_anchor(win, arg); } } /* If 'v' or 'last_selection' are in a window, split that window */ static void split(View *v, char *arg) { Tile *win; if( (win = view_win(v)) || (win = view_win(last_selection)) ) { win_clone(win); } } /***************************************************** Clear, Look act on the body of the current context. *****************************************************/ static void clear(View *v, char *arg) { View *body; if ((body = view_body(v))) text_replace(body->t, text_all(body->t), rstring(0,0)); } /* Look for 'arg' or the current selection in the body of 'v', * select and show the found thing if you find it. */ static void look(View *v, char *arg) { if((v=view_body(v))) view_look(v, arg); } /***************************************************** New window, possibly called 'arg'. Try to use a window for context. *****************************************************/ static void new(View *v, char *arg) { Path label; if(!arg) arg = "New"; /* If 'v' isn't part of a window, maybe last_selection is */ if(!view_win(v)) v = last_selection; data_addcontext(view_data(v), label, arg); if(!data_find(label)) data_open(label, true); } typedef struct Cmd Cmd; struct Cmd { char *name; void (*cmd)(View *, char *); }; /* _Must_ be kept in sorted order, we use bsearch on it */ static Cmd builtins[] = { {"Anchor", anchor}, {"Clear", clear}, {"Cut", cut}, {"Del", del}, {"Delcol", delcol}, {"Dotfiles", dotfiles}, {"Font", builtin_font}, {"Get", get}, {"Indent", builtin_autoindent}, {"Kill", builtin_kill}, {"Look", look}, {"New", new}, {"Newcol", col_new}, {"Paste", builtin_paste}, {"Put", put}, {"Putall", putall}, {"Quit", quit}, {"Redo", redo}, {"Snarf", builtin_snarf}, {"Split", split}, {"Undo", undo}, }; static int cmd_compare(Cmd *a,Cmd *b) { return strcmp(a->name, b->name); } /* * PRE: 'v' is the context, 'cmd' the command. * POST: return true if we recognise the builtin, false otherwise. */ Bool builtin(View *v, char *cmd, char *arg) { Cmd key, *c; assert(v); assert(cmd[0] && !isspace(cmd[0])); key.name = cmd; c = bsearch( &key, builtins, sizeof(builtins)/sizeof(Cmd), sizeof(Cmd), (int (*)(const void *,const void*))cmd_compare); if (c) (*c->cmd)(v, arg); return (Bool) c; } wily-0.13.41/wily/select.c100644 2743 200 14310 6374250275 13616 0ustar garypgrad/******************************************* * drag out a selection, scrolling as you go *******************************************/ #include "wily.h" #include "view.h" #include "text.h" static void frselectf2(Frame *f, Point p0, Point p1, Fcode c); static void dclick(View *, ulong, ulong *, ulong *); typedef void (*SelFn)(Frame*, Point, Point, Fcode); #define BASE(v) ((v)->visible.p0) /* Return a-b, or 0 */ static ulong usub (ulong a, ulong b) { return a>b? a-b : 0; } /* PRE: 'v' shows the region [p0,p1] selected with 'fn' * POST: 'v' shows the region [p0, q] selected with 'fn' */ static void update(View *v, SelFn fn, ulong p0, ulong p1, ulong q) { Frame *f = &v->f; Point pt0, pt1, qt; pt0 = frptofchar(f, usub(p0, BASE(v))); pt1 = frptofchar(f, usub(p1, BASE(v))); qt = frptofchar(f, usub(q, BASE(v))); if(p0 == p1) (*fn)(f, pt0, pt1, F&~D); if(p1 < q) (*fn)(f, pt1, qt, F&~D); else (*fn)(f, qt, pt1, F&~D); if(p0 == q) (*fn)(f, pt0, qt, F&~D); } /* Toggle the region p0,p1 in 'v' with 'fn' */ static void toggle(View *v, SelFn fn, ulong p0, ulong p1) { Frame *f = &v->f; Point pt0,pt1; pt0 = frptofchar(f, usub(MIN(p0,p1), BASE(v))); pt1 = frptofchar(f, usub(MAX(p0,p1), BASE(v))); (*fn)(f, pt0, pt1, F&~D); } /* PRE: The region [p0,p1] in 'v' is indicated with 'fn' * POST: We've scrolled towards 'pt', but the region is still indicated. */ static void move(View *v, SelFn fn, Point pt, ulong p0, ulong p1) { Rectangle r = v->f.r; assert(!ptinrect(pt, r)); /* If we moved off the left or right edge of a view with a * scrollbar, or if we're trying to scroll past the top or bottom * of the text, don't do anything. This avoids a flicker. It also * avoids scrolling down when the bottom of the text is already * visible. * * The "right" way to fix the flickering * may be to fix the selection so we don't * have to turn it off, then back on. This would avoid a * flicker while scrolling as well. I'm not entirely sure * why we need toggle(). * * If the flickering is fixed, we will still need to check that * we aren't scrolling down unnecessarily when the bottom of * the text is visible. That check can appear in a more * appropriate context, however. */ if (v->scroll && ((pt.y >= r.min.y && pt.y <= r.max.y) || (pt.y < r.min.y && v->visible.p0 == 0) || (pt.y > r.max.y && v->visible.p1 == view_text(v)->length))) return; toggle(v,fn,p0,p1); v->f.p0 = v->f.p1 = 0; if (v->scroll) { if (pt.y < r.min.y) view_linesdown(v, 2, false); else if (pt.y > r.max.y) view_linesdown(v, 2, true); } else { if (pt.x < r.min.x) view_hscroll(v, true); else if (pt.x > r.max.x) view_hscroll(v, false); } toggle(v,fn,p0,p1); } /* PRE: nothing is selected in 'v', our initial desired selection is [p0,p1] * POST: 'v' indicates a selection (using Selfn 'fn'), we return the selected * range. */ static Range follow(View *v, ulong oldq, ulong p0, ulong p1, Bool selecting, Mouse *m) { ulong buttons = m->buttons; Frame *f = &v->f; ulong q; Event e; ulong type, timer=0; SelFn fn; fn = selecting? frselectf : frselectf2; toggle(v, fn, p0, p1); v->selecting = true; *m= emouse(); type = 0; while(m->buttons == buttons){ q = frcharofpt(f, m->xy) +v->visible.p0; /* We only autoscroll while affecting the selection, not for b2 or b3 */ if (selecting) { /* We want the timer going iff we're outside the rectangle */ if (ptinrect(m->xy, f->r)) { if (timer){ estoptimer(timer); timer=0; } } else { /* We do a move on timer events, or the first mouse event */ if(timer == type || timer == 0) move(v, fn, m->xy, p0, p1); if (timer==0) timer = etimer(0, SCROLLTIME); } } if(q != oldq && p1 != q){ update(v, fn, p0, p1, q); oldq = p1 = q; } if((type = eread(Emouse|timer,&e))==Emouse) *m= e.mouse; } v->selecting = false; if(timer) estoptimer(timer); return range(MIN(p0,p1), MAX(p0,p1)); } /* Drag out a selection, starting with 'm' (mouse down), * until the mouse buttons change. Return the selected range. */ Range vselect(View *v, Mouse *m) { Frame *f = &v->f; Bool selecting; /* affects selection */ ulong orig, p0, p1; Range sel; orig = p0 = p1 = frcharofpt(f, m->xy) + BASE(v); selecting = m->buttons&LEFT; if (selecting) { frselectp(f, F&~D); /*remove old highlighted bit */ view_setlastselection(v); dclick(v, m->msec, &p0, &p1); } sel = follow(v, orig, p0, p1, selecting, m); if(selecting) { v->sel = sel; v->anchor = sel.p1; f->p0 = pclipr(sel.p0, v->visible) - BASE(v); f->p1 = pclipr(sel.p1, v->visible) - BASE(v); } else { frselectf2(f, frptofchar(f, sel.p0 -BASE(v) ), frptofchar(f, sel.p1 -BASE(v)), F&~D); } assert(view_invariants(v)); return sel; } /* it is assumed p0<=p1 and both were generated by frptofchar() */ static void frselectf2(Frame *f, Point p0, Point p1, Fcode c) { int n; int ht; if(p0.x == f->left) p0.x = f->r.min.x; if(p1.x == f->left) p1.x = f->r.min.x; ht = f->font->height; n = (p1.y-p0.y)/ht; /* p0.y += ht - 1; p1.y = p0.y + 1; */ p1.y = p0.y + ht; /* p0.y = (p0.y + p1.y) >> 1; */ p0.y = p1.y - 2; if(f->b == 0) berror("frselect2 b==0"); if(p0.y == f->r.max.y) return; if(n == 0){ if(p0.x == p1.x) if(p0.x == f->r.min.x) p1.x++; else p0.x--; bitblt(f->b, p0, f->b, Rpt(p0, p1), c); /* bitblt(f->b, p0, f->d, Rpt(p0, p1), c); */ }else{ if(p0.x >= f->r.max.x) p0.x = f->r.max.x-1; bitblt(f->b, p0, f->b, Rect(p0.x, p0.y, f->r.max.x, p1.y), c); while (--n > 0) { p0.y += ht; p1.y += ht; bitblt(f->b, Pt(f->r.min.x, p0.y), f->b, Rect(f->r.min.x, p0.y, f->r.max.x, p1.y), c); } p0.y += ht; p1.y += ht; bitblt(f->b, Pt(f->r.min.x, p0.y), f->b, Rect(f->r.min.x, p0.y, p1.x, p1.y), c); } } /* Check for double-click. If 'click' happened not long after 'lastclick', * set '*p0' and '*p1' appropriately. Update 'lastclick'. */ static void dclick(View *v, ulong click, ulong *p0, ulong *p1) { Range sel; static ulong lastclick; /* check for double click */ if( (v->sel.p0 == *p0 ) && (click < lastclick + DOUBLECLICK )) { sel = text_doubleclick(v->t, *p0); *p0 = sel.p0; *p1 = sel.p1; lastclick = 0; } else { lastclick = click; } } wily-0.13.41/wily/Makefile.in100644 2743 200 3076 6352452056 14224 0ustar garypgradSHELL=/bin/sh srcdir=@srcdir@ VPATH=@srcdir@ prefix = @prefix@ LIBS=@LIBS@ exec_prefix = @exec_prefix@ # Directory in which to install scripts. bindir = $(exec_prefix)/bin CC=@CC@ RANLIB=@RANLIB@ INCLUDES= -I.. -I$(srcdir)/../include @X_CFLAGS@ OPTS=-DNDEBUG CFLAGS= @CFLAGS@ $(OPTS) $(INCLUDES) TARGET=wily OBJECTS= env.o include.o label.o file.o msg.o data.o line.o\ vgeom.o vsearch.o vshow.o \ tagmatch.o place.o event.o exec.o dir.o \ point.o global.o cursor.o scroll.o path.o keyboard.o \ wily.o tag.o view.o grow.o adjust.o win.o list.o col.o\ undo.o builtins.o util.o select.o\ mouse.o regexp.o text2.o \ sam.o text.o click.o tile.o search.o MYLIBS=../libmsg/libmsg.a ../libframe/libframe.a ../libXg/libXg.a XLIBS=$(LIBS) @X_LIBS@ -lXt @X_PRE_LIBS@ -lX11 @X_EXTRA_LIBS@ all: $(TARGET) $(TARGET): $(OBJECTS) $(MYLIBS) $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(XLIBS) pure: $(OBJECTS) $(MYLIBS) purify $(CC) $(LDFLAGS) -o $(TARGET) $(OBJECTS) $(MYLIBS) $(XLIBS) $(OBJECTS): wily.h const.h proto.h ../include/msg.h builtins.o keyboard.o mouse.o tag.o text.o text2.o tile.o view.o: view.h keyboard.o search.o tag.o text.o text2.o undo.o view.o line.o click.o : text.h tile.o grow.o adjust.o win.o col.o list.o: tile.h point.o: tile.h view.h sam.o regexp.o: sam.h file.o msg.o data.o label.o : data.h adjust.o builtins.o keyboard.o mouse.o point.o select.o tag.o text2.o tile.o vgeom.o view.o vsearch.o vshow.o : view.h clean: rm -f *.o core *pure* nuke: clean rm -f $(TARGET) dist: nuke cp -r `ls |grep -v RCS` ../dist/wily install: $(TARGET) cp $(TARGET) $(bindir) wily-0.13.41/wily/view.c100644 2743 200 16444 6541445251 13317 0ustar garypgrad/******************************************* * View methods *******************************************/ #include "wily.h" #include "view.h" #include static Rectangle nullrect = { {0,0}, {0,0}}; /* Store string representation of 'dot' for 'v' into 'buf'. * if 'isLine', we want a line address, otherwise we want * a character address. */ void view_getdot(View *v, char*buf, Bool isLine) { if(isLine) { sprintf(buf, " :%d,.", text_linenumber(v->t, v->sel.p0)); } else { /* character address */ sprintf(buf, " :#%lu,.", v->sel.p0); } } Range view_expand(View *v, Range r, char *s) { if(RLEN(r)) return r; if (RLEN(v->sel) && v->sel.p0 <= r.p0 && v->sel.p1 >= r.p1) return v->sel; else return text_expand(v->t, r, s); } /***************************************** Allocate, deallocate, invariants *****************************************/ /* Allocate and return a new View. Doesn't attempt to draw it. */ View* view_new(Font *f, Bool istag, Text *text, Tile *tile) { View*v = NEW(View); Bitmap*b = 0; ulong length; ulong sel; length = text_length(text); v->r = nullrect; frinit(&v->f, nullrect, f, b); v->visible = range(0,0); sel = istag? length : 0; v->sel = range(sel, sel); v->anchor = length; v->t = text; v->next = 0; v->selecting = false; v->autoindent = autoindent_enabled; text_addview(text, v); v->tile = tile; v->scroll = istag? 0 : scroll_alloc(b, nullrect); assert(view_invariants(v)); return v; } /* Delete v and free its resources. Return 0 for success */ int view_delete(View *v){ if (text_rmview(v->t, v)) return -1; if(v==last_selection) view_setlastselection(0); frclear(&v->f); if(v->scroll) free(v->scroll); return 0; } Bool view_invariants(View*v) { Range r; ulong length; if(!v->f.b) return true; /* all bets are off if we're not visible */ length = text_length(v->t); /* The selection and visible region are sane */ assert(ROK(v->sel)); assert(ROK(v->visible)); assert(v->sel.p1 <= length); assert(v->visible.p1 <= length); /* We're either displaying at least one line, or we're quite hidden */ assert(RLEN(v->visible)==v->f.nchars); assert(v->f.nchars <= length); /* View height == integral number of lines assert(Dy(v->r) == 2*INSET + v->f.maxlines * v->f.font->height); */ if(!v->selecting) { /* The visible part of the View selection == the frame selection */ r = rclip(v->sel, v->visible); assert( (r.p0 - v->visible.p0) == v->f.p0); assert( (r.p1 - v->visible.p0) == v->f.p1); } return true; } /***************************************** Simple data hiding stuff *****************************************/ /* Return the 'Data' associated with 'v', or 0. */ Data* view_data(View *v) { return v ? text_data(v->t): 0; } /* Body associated with 'v' */ View* view_body(View*v) { if(!v) return 0; return ISBODY(v) ? v : tile_body(v->tile); } /* The window 'v' is a part of, or 0. */ Tile* view_win(View*v) { return v? tile_win(v->tile) : 0; } /* The tile 'v' is part of, or 0. */ Tile* view_tile(View*v) { return v? v->tile : 0; } Text* view_text(View*v) { return v? v->t : 0; } Range view_getsel(View*v) { return v->sel; } int view_height(View*v) { return (v && v->f.b) ? Dy(v->r) : 0; } void view_paste(View*v){ undo_break(v->t); view_select(v, paste(v->t, v->sel)); view_show(v, v->sel); } /* * Copy the range to the snarf buffer (unless it's empty). * Delete the text, update the View */ void view_cut(View*v, Range r) { if(RLEN(r)){ snarf(v->t, r); undo_break(v->t); text_replace(v->t, r, rstring(0,0)); } view_show(v, range(r.p0, r.p0)); } void view_append(View *v, char *s, int n) { Text *t; ulong len; Range end; t = v->t; len = text_length(t); end = range(len,len); s[n] = 0; text_replaceutf(v->t, end, s); } /* Append 'n' bytes at 's' to 'v'. If 'first' time, we replace * the selection, otherwise we append to the selection */ void view_pipe(View *v, Bool *first, char *s, int n) { ulong p0 = v->sel.p0; Range r; if (*first) { r = v->sel; *first = false; } else { r = range(v->sel.p1, v->sel.p1); } s[n]=0; /* bug - assuming no nulls in 's' */ text_replaceutf(v->t, r, s); r = range(p0, v->sel.p1); view_select(v, r); } /* * Change v's font. If 'arg' is not null, use it, otherwise * toggle between Fonts 'fixed' and 'font' */ void view_setfont(View *v, char*arg) { frfont(&v->f, (v->f.font==font)? fixed: font); if(ISVISIBLE(v)) view_reshaped(v, v->r); } /* * Perform the actual drawing of the border that indicates the * view is the last_selection. */ void view_border(View *v, Bool set) { Rectangle r; assert(v); r = v->r; r.min.x += SCROLLWIDTH + 4; if (tile_hidden(view_tile(v))) return; if (set) border(&screen, r, SELECTEDBORDER, F); else { border(&screen, r, SELECTEDBORDER, 0); border(&screen, v->r, 1, F); } } /* Indicate visually that 'v' is the 'last_selection' */ void view_setlastselection(View *v) { if (v == last_selection) return; if (last_selection) view_border(last_selection, false); if (v) view_border(v, true); last_selection = v; } /* Set the selection in 'v' to 'r'. Indicate on screen if necessary */ void view_select(View*v, Range r) { assert(ROK(r)); assert(view_invariants(v)); frselectp(&v->f, F&~D); v->sel = r; r = rclip(v->sel, v->visible); v->f.p0 = r.p0 - v->visible.p0; v->f.p1 = r.p1 - v->visible.p0; frselectp(&v->f, F&~D); assert(view_invariants(v)); } /* Warp the cursor to selection 'r' in 'v'. * PRE: 'v' is visible. Some of 'r' is visible. */ void view_warp (View *v, Range r) { Point pt; assert(view_invariants(v)); assert(ROK(r)); assert(RINTERSECT(r, v->visible)); assert(r.p1 <= text_length(v->t)); assert(ISVISIBLE(v)); pt = frptofchar(&v->f, r.p0 - v->visible.p0); pt.y += v->f.font->height/2; /* middle of char */ cursorset(pt); } /* * Replace Range 'r' with 's' in 'v'. We've already changed the underlying * text buffer, we now just have to change the display, and update * v->visible and v->sel. */ static void view_replace(View *v, Range r, Rstring s) { Range q = intersect(r, v->visible); /* visible part of change */ int len; Bool visible = ISVISIBLE(v); /* view_invariants don't hold at present because * v->t->length has changed but v->sel hasn't */ assert(ROK(r)); assert (RSOK(s)); assert(RLEN(r) || RSLEN(s)); /* or we wouldn't get here */ assert(r.p0 <= text_length(v->t)); /* even if we're deleting text, this will hold */ if(visible && q.p1 >= q.p0) { /* some of the replaced text is visible */ Frame *f = &v->f; q.p0 -= v->visible.p0; q.p1 -= v->visible.p0; if(RLEN(q)) frdelete(f, q.p0 , q.p1); if(RSLEN(s)) frinsert(f, s.r0, s.r1, q.p0); } /* adjust our counters */ len = RSLEN(s); v->visible.p0 = ladjust(v->visible.p0, r,len); v->visible.p1 = radjust(v->visible.p1, r,len); v->sel.p0 = radjust(v->sel.p0, r,len); v->sel.p1 = radjust(v->sel.p1, r,len); v->anchor= ladjust(v->anchor, r,len); if(visible) fill(v); assert(view_invariants(v)); } /* Refresh v because its text has changed arbitrarily. */ static void view_refresh(View*v) { if(ISVISIBLE(v)) { v->sel = range(v->visible.p0, v->visible.p0); frdelete(&v->f, 0, v->f.nchars); fill(v); } } void viewlist_refresh(View*v) { for(;v; v = v->next) view_refresh(v); } void viewlist_replace(View*v, Range r, Rstring s) { for(;v; v = v->next) view_replace(v, r, s); } wily-0.13.41/wily/.wily.prcs_aux100644 2743 200 251 6352450046 14734 0ustar garypgrad;; This file is automatically generated, editing may cause PRCS to do ;; REALLY bad things. (Created-By-Prcs-Version 1 2 0) (wily/text.h 1487 862661653 d/23_text.h 1.3) wily-0.13.41/wily/util.c100644 2743 200 17773 6373540077 13335 0ustar garypgrad/******************************************* * A few utilities *******************************************/ #include "wily.h" #include #include #include #include void dirnametrunc(char*s){ if((s=strrchr(s,'/'))) *(++s) = 0; } /* Combine 'add' with 'context', put the result in 'dest' */ void addcontext(char*dest, char*context, char*add){ char*s; if(strchr("/$~", add[0])){ strcpy(dest,add); return; } strcpy(dest, context); if(!(s = strrchr(dest, '/'))){ label2path(dest, context); if(!(s = strrchr(dest, '/'))){ s = dest + strlen(dest) -1; } } strcpy(s+1,add); labelclean(dest); } /* Set the name of the window where output from the context * of 'label' will appear. */ void olabel(char*out, char*label){ addcontext(out, label, "+Errors"); } /* Compares two stat buffers, returns 0 if they have * the same inode and device numbers. */ int statcmp(Stat*a, Stat*b) { if(a->st_ino != b->st_ino || a->st_dev != b->st_dev) return -1; else return 0; } Bool isdir(char*path) { struct stat buf; return !stat(path, &buf) && S_ISDIR(buf.st_mode); } /* * Return Rstring for utf. Either s.r0 == s.r1 == 0, * or s.r0 will need to be free */ Rstring utf2rstring(char*utf) { Rstring s; int len; if( (len = utflen(utf)) ) { s.r0 = salloc(len*sizeof(Rune)); s.r1 = s.r0 + utftotext(s.r0, utf, utf+strlen(utf)); } else s.r0 = s.r1 = 0; return s; } /* Write into 'back' the name of a file we can write to as a backup * for 'orig'. Return 0 for success. */ int backup_name(char *orig, char *back) { Path dir, guide; char *home; DIR *dirp; struct dirent *direntp; FILE *fp; int max,n; int init_guide = 0; if ( !(home=getenv("WILYBAK")) ) { if ( !(home=getenv("HOME")) ) { return diag(0, "getenv HOME"); } sprintf(dir, "%s/.wilybak", home); } else strcpy(dir, home); /* Make sure the directory exists. Create it if necessary. */ if(access(dir, W_OK) && (mkdir(dir, 0700)) ) return diag(0, "couldn't create backup directory %s", dir); /* Find directory entry with largest number. We will be one * greater than that. */ max=0; if(!(dirp = opendir(dir))) { return diag(0, "couldn't opendir %s", dir); } rewinddir(dirp); /* Workaround for FreeBSD. */ while ((direntp = readdir(dirp))) { if ( (n=atoi(direntp->d_name)) > max) max = n; } closedir(dirp); max++; sprintf(back, "%s/%d", dir, max); /* Record what is going where */ sprintf(guide,"%s/guide", dir); if(access(guide, W_OK) < 0) init_guide = 1; fp = fopen(guide, "a+"); if(fp) { /* if this fails, don't care all that much */ if(init_guide) fprintf(fp, "diff cp rm *\n"); fprintf(fp, "%3d\t%s\n", max, orig); fclose(fp); } else { diag(guide, "couldn't update backup guide file"); } return 0; } void noutput(char *context, char *base, int n) { Path errwin; View *v; Range r; char *s; Text *t; ulong p; strcpy(errwin, context? context : wilydir); if((s = strrchr(errwin, '/'))) s++; else s = errwin +strlen(errwin); strcpy(s, "+Errors"); v = openlabel(errwin, true); base[n] = 0; t = view_text(v); p = text_length(t); r = text_replaceutf(t, range(p,p), base); r.p0 = r.p1; /* most interested in the end bit */ view_show(v, r); } /* * Given strings stored in (null-terminated) 'item', arrange them in * columns to fit neatly in a window with given 'totalwidth', 'tabwidth' * and font 'f'. Return the finished, allocated, null-terminated * string. */ char * columnate(int totalwidth, int tabwidth, Font *f, char **item) { int rows, columns, row, column; int maxwidth; int j, widest,nitems, ntabs, biggest; int *width; char *buf, *s, **c; int remaining; /* count the items */ nitems = 0; c= item; while(*c++) nitems++; if(!nitems) return strdup(""); /* width[j] - width of string j * widest - index of widest string * maxwidth - width of largest string plus a tab */ widest = 0; width = (int*)salloc(nitems*sizeof(int)); for(j=0; j< nitems; j++) { width[j] = strwidth(f, item[j]); if (width[j]>width[widest]) widest = j; } biggest = width[widest] + strwidth(f, "W"); ntabs = biggest/tabwidth; if (biggest % tabwidth) ntabs++; maxwidth = ntabs*tabwidth; columns = ((totalwidth -biggest) / maxwidth) +1; rows = nitems / columns; if (nitems % columns) rows++; s = buf = (char*)salloc(nitems*(strlen(item[widest])+4)); remaining = nitems; for(row=0; ; row++) { for(column = 0; column < columns; column++) { int current, deficit; current = column*rows + row; if (current >= nitems) break; deficit = maxwidth - width[current]; ntabs = deficit / tabwidth; if (deficit % tabwidth) ntabs++; if(column==columns-1) ntabs=0; /* no tabs for last column */ assert(ntabs < 48); strcpy(s, item[current]); s += strlen(item[current]); while(ntabs-->0) *s++ = '\t'; if (!(--remaining)) goto done; } *s++ = '\n'; } done: if(column) *s++ = '\n'; *s++='\0'; free(width); return buf; } static void cleanup(void){ data_backupall(); fifo_cleanup(); } void cleanup_and_die(int n) { cleanup(); exit(0); } void cleanup_and_abort(int n) { perror("wily: something horrible happened:"); cleanup(); abort(); } /* Send a diagnostic message to the appropriate place, * given its context. */ int diag(char *context, char *fmt, ...) { va_list args; Path msg; char *err,*s; s = msg; if ( errno && (err=strerror(errno)) ) { sprintf(msg, "diag: %s: ", err); s += strlen(s); } va_start(args,fmt); vsprintf(s, fmt, args); va_end(args); strcat(msg, "\n"); assert(strlen(msg)<1024); noutput(context, msg, strlen(msg)); return 1; } Rstring rstring(Rune*r0, Rune*r1) { Rstring s; s.r0 = r0; s.r1 = r1; return s; } char* mybasename(char*f) { char *s; s=strrchr(f,'/'); return s ? s+1 : f; } ulong texttoutf(char *s, Rune *r1, Rune *r2) { Rune *q; char *t; if (r2 <= r1) return 0; for (t = s, q = r1; q < r2; q++) t += runetochar(t, q); return t-s; } int distance(Point p1, Point p2) { return (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y); } /* Error we should be able to recover from */ void error(char *fmt, ...) { va_list args; perror("wily:"); va_start(args,fmt); vfprintf(stderr, fmt, args); va_end(args); } /* Error we cannot recover from */ void fatal(char *fmt, ...) { va_list args; perror("wily:"); va_start(args,fmt); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); cleanup_and_abort(0); } /* * dummy mouse driver for the frame library */ void frgetmouse(void) {} /* Store runes from 't' into X clipboard as UTF */ void snarf(Text *t, Range r) { char *buf; assert(t); if(RLEN(r)){ buf = text_duputf(t, r); select_put(buf); free(buf); } } /* Replace range 'r' of 't' with the snarf buffer, return * the range of the new text. */ Range paste(Text *t, Range r) { char *cbuf; Rune *rbuf; int n; Rstring s; assert(t); assert(ROK(r)); cbuf = select_get(); /* not to be freed */ rbuf = (Rune *)salloc(sizeof(Rune)*(utflen(cbuf)+1)); n = utftotext(rbuf, cbuf, cbuf+strlen(cbuf)); s.r0 = rbuf; s.r1 = rbuf + n; text_replace(t, r, s); r.p1 = r.p0 + n; free(rbuf); return r; } void add_slash(char*s) { int n; n = strlen(s); if(s[n-1] != '/'){ s[n++]='/'; s[n]='\0'; } } Bool frame_isfull(Frame*f) { return f->nlines == f->maxlines && f->lastlinefull; } Bool utfHadNulls; int utftotext_unconverted; /* bytes at the end which weren't converted */ /* Convert UTF from s1 to s2 into runes, store them at r * Returns the number of runes stored. * Sets utfHadNulls to indicate that some of the UTF contained nulls, * which are _not_ converted into null Runes. */ ulong utftotext(Rune *r, char *s1, char *s2) { Rune *q; char *v; utfHadNulls = false; if (s2 <= s1) return 0; for (v = s1, q = r; v < s2; ) { if (!(*(uchar*)v)) { utfHadNulls = true; v++; continue; } else if (*(uchar *)v < Runeself) { *q = *v++; } else { v += chartorune(q, v); } assert(*q); q++; } if (v > s2) { int length; q--; length = runelen(*q); utftotext_unconverted = s2 - (v-length); } return q-r; } wily-0.13.41/wily/keyboard.c100644 2743 200 6116 6332627543 14124 0ustar garypgrad/******************************************* * Handle keystroke events *******************************************/ #include "wily.h" #include "view.h" static void view_cursor(View *v, Rune r); static void addrune(View*v, Rune r); static void tag_cr(View *v); static void backspace(View*v); static void deleteline(View*v); static void deleteword(View*v); static void esc(View*v); void dokeyboard(View *v, Rune r) { switch(r) { case DownArrow: case UpArrow: case Home: case End: case LeftArrow: case RightArrow: view_cursor(v, r); break; case PageDown: case PageUp: view_pagedown(v,r==PageDown); break; case Ctrlh: case Backspace: backspace(v); break; case Ctrlu: deleteline(v); break; case Ctrlw: deleteword(v); break; case Esc: esc(v); break; case '\n': if(!v->scroll){tag_cr(v); break; } default: addrune(v,r); } } /****************************************************** static functions ******************************************************/ /* Handle carriage-return in 'v' * * Select text as if we hit escape, * and either search (if selected text starts with ':') * or execute the selected text. */ static void tag_cr(View*v) { char*cmd; if(!RLEN(v->sel)){ assert(v->anchor <= v->sel.p0); view_select(v, range(v->anchor, v->sel.p0)); } cmd = text_duputf(v->t, v->sel); if(cmd[0]==':'){ b3(v, v->sel); } else { if (!data_sendexec(view_data(v),cmd, 0)) run(v, cmd, 0); } free(cmd); } /* delete selection and rune before */ static void backspace(View*v){ Range del = v->sel; if(del.p0) del.p0--; view_cut(v, del); } /* delete selection and back to start of line */ static void deleteline(View*v){ Range del = v->sel; del.p0 = text_startOfLine(v->t, del.p0); view_cut(v, del); } /* delete back to start of word */ static void deleteword(View*v){ Range del = v->sel; del.p0 = text_startofword(v->t, del.p0); view_cut(v, del); } static void esc(View*v) { Range del = v->sel; if ((RLEN(del))) { /* delete selected text */ view_cut(v, del); } else { /* Select from v->anchor to v->sel.p0 */ view_select(v, range(v->anchor, v->sel.p0)); view_setlastselection(v); } } static void addrune(View*v, Rune r) { Rstring s; if ( r == '\n' && v->autoindent) { s = text_autoindent(v->t, v->sel.p0); } else { s.r0 = &r; s.r1 = &r +1; } if(RLEN(v->sel)){ snarf(v->t, v->sel); } text_replace(v->t, v->sel, s); view_show(v, v->sel); } /* * We've hit a cursor key. * * Set the selection to something relative to previous sel.p0, and * make sure the new selection is visible. */ static void view_cursor(View *v, Rune r) { ulong p; Point pt; p = v->sel.p0; switch(r) { case LeftArrow: if(p) p--; break; case RightArrow: if (p < text_length(v->t)) p++; break; case DownArrow: case UpArrow: pt = frptofchar(&v->f, p - v->visible.p0); if (r==DownArrow) pt.y += v->f.font->height; else pt.y -= v->f.font->height; p = frcharofpt(&v->f, pt) + v->visible.p0; break; case Home: p = 0; break; case End: p = text_length(v->t); break; } view_select(v, range(p,p)); view_show(v, v->sel); } wily-0.13.41/wily/text2.c100644 2743 200 16242 6332627776 13423 0ustar garypgrad/******************************************* * Convenience wrappers around Text methods *******************************************/ #include "wily.h" #include "text.h" #include "view.h" #include /**************************************************** Random garbage ****************************************************/ void text_allread (Text*t) { undo_reset(t); undo_start(t); viewlist_refresh(t->v); } /**************************************************** Simple data access ****************************************************/ Data* text_data(Text*t) { return t? t->data:0; } View* text_view(Text*t) { return t->v; } ulong text_length(Text*t) { return t->length; } Bool text_needsbackup(Text*t) { return t->needsbackup; } /**************************************************** Cooked data access ****************************************************/ /* Return body view associated with 't'. */ View* text_body(Text*t) { if(t->data) { if (TEXT_ISTAG(t)) { t = data_body(t->data); return t->v; } else { return t->v; } } else { return 0; } } /**************************************************** Simple data manipulations ****************************************************/ void text_setneedsbackup(Text*t, Bool b) { t->needsbackup = b; } Bool text_badrange(Text *t, Range r) { return r.p1 > t->length || r.p0 > r.p1; } void text_addview(Text*t, View*v) { v->next = t->v; t->v = v; } /* * Remove 'v' from list of views displaying 't'. If 'v' was the last * one, remove 't'. If 't' represents some Data, make sure we've backed * it up if necessary. Return 0 for success. */ int text_rmview(Text*t, View *v) { View**ptr; if (t->v ==v && v->next == 0) { /* this is the last view */ if (t->isbody && data_del(t->data)) return -1; } /* update the list of views of the same body */ for (ptr = &(t->v); *ptr != v; ptr = &( (*ptr)->next)) ; *ptr = v->next; if(!t->v) { /* we've deleted the last view */ text_free(t); free(t); } return 0; } /**************************************************** Write to file ****************************************************/ /* Write the contents of 't' to 'fname'. Return 0 for success. */ int text_write(Text *t, char *fname) { int fd; int retval; /* open 0666 and rely on the umask */ if((fd = open(fname,O_RDWR|O_CREAT|O_TRUNC, 0666))<0){ diag(fname, "couldn't open %s for write",fname); return 1; } retval = text_write_range(t, range(0, t->length), fd); if(retval) diag(fname, "couldn't write %s",fname); close(fd); return retval; } /*Return a file descriptor open for reading from a temporary * file which has a copy of the current selection. * * The input for the child comes from the current selection. * Put the selection into a text file and attach that text * file to the command's fdin. */ int text_fd(Text *t, Range sel) { char *file = tmpnam(0); int fd; int input; if ((fd = open(file, O_WRONLY|O_CREAT, 0600)) < 0) { perror("open temp file"); (void) unlink(file); return(-1); } /* Now for the child's end. Do it quick so we can unlink. */ if ((input = open(file, O_RDONLY)) < 0) { perror("open temp file"); (void) unlink(file); return(-1); } if (unlink(file) < 0) perror("unlink temp file"); /* no need to *do* anything about it */ /* Our buffer is the most recent selection, or if the * most recent selection is in a tag, the selection in the body * of that win. */ if (text_write_range(t, sel, fd)) { perror("write temp file"); return(-1); } if (close(fd) < 0) perror("close temp file"); return input; } /**************************************************** Auto indent ****************************************************/ enum {MAXAI=128}; /* * Return an Rstring to be inserted after position 'p', * given that autoindent is on. * The Rstring is to a *static* Rune buffer. */ /** NB *not* reentrant */ Rstring text_autoindent(Text *t, ulong p) { static Rune buf[MAXAI]; Rstring s; Range r; int i; buf[0] = '\n'; s.r0 = buf; r = range(text_startOfLine(t, p), p); if (RLEN(r) > MAXAI) r.p1 = r.p0 + MAXAI; text_copy(t, r, buf +1); i = 1; while (i <= RLEN(r) && isspace(buf[i])) i++; s.r1 = buf + i; return s; } /**************************************************** Convenience functions ****************************************************/ /* * Return the character to start displaying from, * such that the character at 'p' will be offset by * 'height', when displayed * in a window of width 'w', with Font 'f' */ int back_height(Text *t, ulong p, Font *f, int width, int height) { int c, hpos; if (p > 0) --p; for( hpos = 0; p>0 && height>0; p--) { Tgetcset(t,p); c = Tgetc(t); switch(c) { case '\t': hpos += tabsize; break; case '\n': hpos = 0; height -= f->height; break; default: hpos += charwidth(f,c); break; } if (hpos >= width) { hpos =0; height -= f->height; } } return p? p+2 : p; } Range text_all(Text*t){ Range r; r.p0 = 0; r.p1 = t->length; return r; } void text_fillbutton(Text*t, Fcode f) { View*v; for(v = t->v; v; v= v->next) view_fillbutton(v,f); } /* Try to copy 'n' Runes at 'p' from 't' into 'buf'. * Return the number of runes copied. */ ulong text_ncopy(Text *t, Rune*buf, ulong p, ulong n) { Range r; if (p >= t->length) return 0; r = range(p, MIN(p+n, t->length)); text_copy(t, r, buf); return RLEN(r); } /* Replace 'r' in 't' with 'utf', return the range of newly placed runes */ Range text_replaceutf(Text*t, Range r, char*utf) { Rstring s; s = utf2rstring(utf); r = text_replace(t, r, s); if(s.r0) free(s.r0); return r; } /* Return a newly allocated string containing the utf * representation of the given range inside 't' */ char * text_duputf(Text *t, Range r) { ulong len = RLEN(r); ulong n; char *buf; if(!len) return strdup(""); buf = salloc(len * UTFmax); n = text_copyutf(t, r, buf); buf[n] = '\0'; return buf; } /* Copy Range 'r' from 't', convert it to utf, store it * in 'buf', (which must have enough space allocated). * Returns the number of utf characters copied. */ int text_copyutf(Text*t, Range r, char *buf) { Rune *rbuf; int rlen; int n; rlen = RLEN(r); rbuf = salloc( rlen * sizeof(Rune)); text_copy(t, r, rbuf); n = texttoutf(buf, rbuf, rbuf + rlen); free(rbuf); return n; } /**************************************************** Formatting text representing a directory ****************************************************/ static void text_getdir(Text *t, char**names) { Frame *f; char *s; f = &t->v->f; s = columnate(Dx(f->r), f->maxtab, f->font, names); undo_reset(t); text_replaceutf(t, range(0, t->length), s); undo_start(t); free(s); } /* * If 't' represents a directory, and doesn't have any modified text, * reformat the directory and return true. Otherwise return false. */ Bool text_refreshdir(Text*t) { char**names; if ( t->isbody && (names = data_names(t->data)) && undo_atmark(t) && t->v) { text_getdir(t, names); return true; } else { return false; } } /* Reformat 'd' (which must hold a directory) to fit nicely * in the smallest view displaying it. */ void text_formatdir(Text *t, char**names) { if(!(t->v && names)) return; text_getdir(t,names); viewlist_refresh(t->v); } wily-0.13.41/wily/search.c100600 2743 200 11026 6333561765 13601 0ustar garypgrad/******************************************* * Search in text *******************************************/ #include "wily.h" #include "text.h" static char *endword = "[^a-zA-Z0-9][^a-zA-Z0-9|]*"; static char *startword = "[^a-zA-Z0-9]"; static char *special = ".*+?(|)\\[]^$"; static Bool findend(Text *t, Range *r, char *addr, Range dot); static Rstring word(Rstring s); static Rstring literal(Rstring s); static void strip_re_slash(char *re); /* Look for the text in 'dot'. * If found, set '*r' and return true, * otherwise return false. */ Bool text_look(Text*t, Range *r, Range dot) { RPath buf; ulong len; assert(!text_badrange(t,dot)); len = RLEN(dot); /* don't try to search for HUGE dot */ if( len > MAXPATH) return false; text_copy(t, dot, buf); return text_findliteral(t, r, rstring(buf, buf + len)); } Bool text_findliteralutf(Text*t, Range *r, char*lit) { Rstring s; Bool found; s = utf2rstring(lit); r->p0 = r->p1; found = text_findliteral(t, r, s); free(s.r0); return found; } Bool text_findwordutf(Text*t, Range *r, char*lit) { Rstring s; Bool found; s = utf2rstring(lit); found = text_findword(t, r, s); free(s.r0); return found; } /* * If we can find 's' in 't' (start looking at 'pos'), return true and * set 'pos' to the location of the start of the string. Otherwise, * return false. */ Bool text_findliteral(Text *t, Range *r, Rstring s) { Rstring s2; Bool found; s2 = literal(s); found = text_regexp(t, s2, r, 1); RSFREE(s2); return found; } Bool text_findword(Text *t, Range *r, Rstring s) { Rstring s2; Bool found; s2 = word(s); found = text_regexp(t, s2, r, 1); RSFREE(s2); r->p0++; return found; } /* If we can find 'addr', preferably someplace just after 'r', * set 'r' to the range we found, and return true, otherwise return false. * 'addr' may be any Sam-style address. */ Bool text_search(Text *t, Range *r, char *addr, Range dot) { char *addr2; /* * Find the second addr in the pair. Some complexity here: * (1) If the first addr is a regexp, must first find its end -- but watch * out for escaped "/"'s. * (2) Otherwise, just find the first comma. */ if (*addr == '/') { /* find an unescaped "/" */ for (addr2 = addr + 1; (addr2 = strchr(addr2, '/')) && addr2[-1] == '\\'; addr2++) ; /* check to see that it's followed by a comma */ if (addr2 && *++addr2 != ',') addr2 = 0; } else addr2 = strchr(addr, ','); if (addr2) *addr2++ = '\0'; if (*addr == '\0') { r->p0 = 0; } else if (!findend(t, r, addr, dot)) { return false; } if (addr2) { Range range2 = *r; if (*addr2 == '\0') r->p1 = t->length; else if (!findend(t, &range2, addr2, dot)) return false; else if ( range2.p1 < r->p0) return false; else r->p1 = range2.p1; } return true; } /* * Used to find one "end" of an addr (which might be the whole addr, but * never mind). The address passed in here is not expected to contain * commas. */ static Bool findend(Text *t, Range *r, char *addr, Range dot) { if(!strchr("/-#$.0123456789", *addr)) return false; switch(*addr){ case '/': strip_re_slash(addr); return text_utfregexp(t, addr+1, r, true); case '-': if(addr[1] != '/') return false; strip_re_slash(addr); return text_utfregexp(t, addr+2, r, 0); case '#': r->p0 = r->p1 = atol(addr + 1); return r->p0 <= t->length; case '$': if(addr[1] != '\0') return false; *r = text_lastline(t); return true; case '.': if(addr[1] != '\0') return false; *r = dot; return true; default: return text_findline(t, r, atol(addr)); } } /* * Strip trailing slash from a regexp, if present and not escaped. * WARNING: This code can reference the character * immediately preceding its argument, so use with care. */ static void strip_re_slash(char *re) { if ((re = strrchr(re, '/')) && re[1] == '\0' && re[-1] != '\\') re[0] = '\0'; } static Rstring literal(Rstring s) { Rstring s2; Rune *r; /* quote any special characters in 's' */ s2.r0 = s2.r1 = (Rune*)salloc(RSLEN(s)*2*sizeof(Rune)); for (r = s.r0; r < s.r1; r++){ if(utfrune(special, *r)) *s2.r1++ = '\\'; *s2.r1++ = *r; } return s2; } static Rstring word(Rstring s) { Rstring s2; Rune *r; int nrunes; nrunes = RSLEN(s)*2 +strlen(startword) + strlen(endword); s2.r0 = s2.r1 = (Rune*)salloc(nrunes*sizeof(Rune)); s2.r1 += utftotext(s2.r1, startword, startword + strlen(startword)); for (r = s.r0; r < s.r1; r++){ if(utfrune(special, *r)) *s2.r1++ = '\\'; *s2.r1++ = *r; } s2.r1 += utftotext(s2.r1, endword, endword + strlen(endword)); return s2; } wily-0.13.41/wily/include.c100644 2743 200 3610 6332625612 13736 0ustar garypgrad/******************************************* * Expand b3-clicks to "include" files, e.g. *******************************************/ #include "wily.h" static char * pathfind (const char *paths, const char *file); static Bool is_includebrackets(char left, char right); /* * The user has selected 'r' in 'v'. * If possible, open an appropriate include file, return a View * representing its body. * * If no include file is appropriate, return 0. */ View* openinclude(View *v, Range r) { Range expanded; Path buf, pbuf; int len; Text *t; char *s; t = view_text(v); expanded = text_expand(t, r, notinclude); len = RLEN(expanded); if( len > (MAXPATH*UTFmax) || len < 2) return false; len = text_copyutf(t, expanded, buf); if (!is_includebrackets(buf[0], buf[len-1])) return false; buf[len-1] = 0; s = pathfind(getenv("INCLUDES"), buf+1); if(!s) { sprintf(pbuf, "/usr/include/%s", buf+1); s = pbuf; } return openlabel(s, false); } /********************************************************** static functions **********************************************************/ static Bool is_includebrackets(char left, char right) { return (left == '"' && right == '"') || (left == '<' && right == '>'); } static const char * nextstr (const char *p, const char *c, int *n){ int i; if (!p || !*p) return 0; *n = i = strcspn (p, c); /* XXX - utf */ if (p[i]) i += 1; /* strspn (p+i, c); ? */ return p+i; } static char * pathfind (const char *paths, const char *file) { const char *p,*ptmp; int flen; int plen; if (!paths || !file) return 0; flen = strlen(file); p = paths; while((ptmp = nextstr(p, ":", &plen))!= 0) { int fd; char *tmp = malloc(plen+1+flen+1); if (tmp) { sprintf(tmp, "%.*s/%s", plen, p, file); if ((fd = open(tmp, 0)) < 0) { free(tmp); } else { close(fd); return tmp; } } p = ptmp; } return 0; } wily-0.13.41/wily/tagmatch.c100644 2743 200 5007 6332625257 14112 0ustar garypgrad/******************************************* * Maintain and query (regexp, tag tools) pairs *******************************************/ #include "wily.h" #include #include #include #include #include #include typedef struct Pair Pair; struct Pair { char* regex; char* tools; }; static Pair* pair; static int npairs = 0; static int maxpairs = 0; static Bool match(char *regex, char *s) { /* Make a dummy text file, search in that */ static Text *t=0; Range r; Bool retval; if(!t) t = text_alloc(0, false); r = nr; text_replaceutf(t, text_all(t), s); text_replaceutf(t, range(text_length(t),text_length(t)), "\n"); retval = text_utfregexp(t, regex, &r, true); return retval; } static void addpair(char *regex, char* tools) { Pair p; char *nl; p.regex = regex; p.tools = tools; if ((nl = strchr(p.tools, '\n'))) { *nl = 0; } if(npairs == maxpairs) { maxpairs = maxpairs? maxpairs*2 : maxpairs + 10; pair = (Pair*) srealloc(pair, maxpairs * sizeof(Pair)); } pair[npairs++] = p; } char* tag_match(char*label) { int j; static Bool inprogress; if(inprogress) { j= npairs; } else { inprogress = true; for(j=0; j0) { nread = read(fd, buf, size); if(nread <= 0) { perror(filename); free(buf); return 0; } size -= nread; } close(fd); return buf; } /* * Read 'filename', initialize 'pair' and 'npairs'. * 'filename' is made up of lines, each of which may * be blank, a comment (starts with '#'), or a pattern * toolset pair (separated by tabs) */ void tag_init(char *filename) { char *buf, *ptr, *tab; if(!(buf=readfile(filename))) return; for(ptr = strtok(buf, "\n"); ptr; ptr = strtok(0, "\n")) { /* comment or blank line */ if (ptr[0] == '#' || isspace(ptr[0])) continue; if((tab = strchr(ptr, '\t'))) { *tab++ = 0; /* strip leading whitespace */ tab += strspn(tab, whitespace); addpair(ptr, tab); } else { addpair(ptr, ""); } } /* don't free(buf) - keep the memory in the array of strings */ } wily-0.13.41/wily/env.c100600 2743 200 4350 6332624625 13100 0ustar garypgrad/******************************************* * ~ and $ expand and contract *******************************************/ #include "wily.h" #include #include #include typedef struct Abbrev Abbrev; struct Abbrev { Path env; Stat buf; }; static struct Abbrev *abbrev = 0; static int nabbrev = 0, maxabbrev = 0; static Bool foundmatch (char*dest, char*orig); static Bool contract (char*dest, char*orig); static void newenv (char *env, Stat*buf); static Abbrev* findstat (Stat*buf); void env_init(char **envp) { char *env, *ptr; Stat buf; /* Add environment variables */ while ( (env = *envp++)) { if (! (ptr = strchr(env, '=')) ) continue; *ptr ++ = 0; if (strlen(ptr)&& !stat(ptr, &buf)) newenv(env, &buf); *--ptr = '='; } } /* Copy shorter version of 'orig' into 'dest' */ void pathcontract(char*dest, char *orig) { if(orig[0]=='/' && contract(dest, orig)) { ; /* we're done */ } else { strcpy(dest,orig); } } /****************************************************** static functions ******************************************************/ static Bool foundmatch(char*dest, char*orig){ Stat buf; Abbrev *ab; if(!stat(orig,&buf) && (ab = findstat(&buf))){ sprintf(dest, "$%s", ab->env); return true; } else { return false; } } static Bool contract(char*dest, char*orig) { char*lastslash; Bool retval; if(foundmatch(dest, orig)) { return true; } else { lastslash = strrchr(orig,'/'); if(lastslash) { *lastslash = '\0'; retval = contract(dest,orig); *lastslash = '/'; if(retval) { strcat(dest, lastslash); } return retval; } else { return false; } } } static void newenv(char *env, Stat*buf) { Abbrev*new; Abbrev*old; /* "I told him we've already got one" Holy Grail */ if((old = findstat(buf))){ if(strlen(env)env)) strcpy(old->env, env); return; } if (nabbrev == maxabbrev) { maxabbrev = maxabbrev? maxabbrev*2 : maxabbrev + 2; abbrev = srealloc(abbrev, maxabbrev * sizeof(*abbrev)); } new = &abbrev[nabbrev++]; strcpy(new->env, env); new->buf = *buf; } static Abbrev* findstat(Stat*buf){ Abbrev*ab; for(ab = abbrev; ab < abbrev + nabbrev; ab++) if( !statcmp( buf, &ab->buf)) return ab; return 0; } wily-0.13.41/wily/list.c100644 2743 200 4577 6332625405 13303 0ustar garypgrad/******************************************* * Simple operations to apply to every visible tile in a list. *******************************************/ #include "tile.h" /******************************************************** Simple operations to apply to every visible tile in a list. ********************************************************/ Bool list_oksizes(Tile*list) { Tile*t; FOR_EACH_VISIBLE(list->down,0){ assert(TILESIZE(t) >= t->base); } return true; } void list_unhide(Tile*list) { Tile*t; FOR_EACH_TILE(list->down,0) { t->ishidden = false; if ( TILESIZE(t) < t->base) t->max = t->min + t->base; } } /* Slide the visible children of 't' along so that they abut one another */ void list_slide(Tile *t) { int prev = t->cmin; FOR_EACH_VISIBLE(t->down, 0) { moveto(t, prev); prev = t->max; } } /* Return the biggest visible child in the (half-open) range */ Tile* biggest_visible(Tile*start, Tile*end) { Tile *t, *big = 0; FOR_EACH_VISIBLE(start, end) { if (!big || TILESIZE(t) > TILESIZE(big)) big =t; } return big; } /* Return the last child with a visible body in the (half-open) range */ Tile* last_visible_body(Tile*start, Tile*end) { Tile *t, *last=0; FOR_EACH_VISIBLE(start, end) { if(TILESIZE(t) > t->base) last =t; } return last; } /* Return the last visible child in the (half-open) range */ Tile* last_visible(Tile*start, Tile*end) { Tile *t, *last=0; FOR_EACH_VISIBLE(start, end) { last = t; } return last; } /* The total size of the visible tiles in the (half-open) range. */ int list_size(Tile *start, Tile *end) { int size=0; Tile *t; FOR_EACH_VISIBLE(start, end) { size += TILESIZE(t); } return size; } /* Sum the base sizes of the tiles in the (half-open) range. */ int list_basesize(Tile*start, Tile*end) { int size=0; Tile *t; FOR_EACH_VISIBLE(start, end) { size += t->base; } return size; } /* Find the child of 'parent' which contains position 'n' */ Tile* list_find(Tile*parent, int n) { Tile *t; FOR_EACH_VISIBLE(parent->down, 0) { if (n < t->max && n >= t->min) break; } return t; } /* Return the next visible tile after 't' */ Tile* next_visible(Tile*t) { FOR_EACH_VISIBLE(t->right, 0) { break; } return t; } /* Return the next visible tile after 't' */ Bool list_contains(Tile*start, Tile*end, Tile *want) { Tile*t; FOR_EACH_VISIBLE(start,end) { if(t==want) return true; } return false; } wily-0.13.41/wily/const.h100644 2743 200 1771 6332624247 13457 0ustar garypgrad/******************************************* * Constant declarations *******************************************/ #include /* for MAXPATHLEN */ #ifndef DEFAULTSHELL #define DEFAULTSHELL "/bin/sh" #endif #ifndef FOPEN_MAX #define FOPEN_MAX NOFILE #endif #ifndef MAXPATH #define MAXPATH MAXPATHLEN #endif enum { /* memory */ GAPSIZE = 512, /* buffer gap */ BUFFERSIZE = 10240, /* when copying a whole file */ FILLCHUNK = 512, /* when filling a View */ /* geometry */ SCROLLWIDTH = 13, MINWIDTH = 50, /* ... of a window or column */ SELECTEDBORDER = 3, SMALLDISTANCE = 5*5, /* 5 pixels squared */ INSET = 4, /* mouse buttons */ LEFT =1, MIDDLE=2, RIGHT=4, /* keys */ Backspace = 0x7f, PageDown = 0x80, PageUp = 0x81, LeftArrow = 0x82, RightArrow = 0x83, DownArrow = 0x84, UpArrow = 0x85, Home = 0x86 , End = 0x87, NEWLINE = '\n', Ctrlh = 010, Ctrlu = 025, Ctrlw = 027, Esc = 27, /* time delays (ms) */ DOUBLECLICK = 500, SCROLLTIME = 100 }; wily-0.13.41/wily/tile.c100644 2743 200 23272 6415675227 13307 0ustar garypgrad/******************************************* * Tiling window manager *******************************************/ #include "tile.h" /* Is the tile hidden? */ Bool tile_hidden(Tile *t) { /* We are hidden, or one of our ancestors is hidden */ return t->ishidden || (t->up && tile_hidden(t->up)); } Bool tile_invariant(Tile *tile) { int size ,body,tag, diff; Tile *last; assert(tile); /* Can't have _both_ a body and and a child */ assert(!(tile->body && tile->down)); if(tile->ishidden) return true; /* Tests for non-hidden tiles */ size = TILESIZE(tile); assert( size >= tile->base); if (!tile->body) return true; /* Tests for tiles with bodies, i.e. windows */ /* * The size of the tile == the sum of the sizes of its body and * tag, except if we're the "bottom" tile, in which case the * size of the tile might be a _little_ bit bigger than that * sum. */ body = view_height(tile->body); tag = view_height(tile->tag); last = last_visible_body(tile, 0); if (tile != last) { assert(size == body + tag); } else { /* bottom tile might have a little 'slop' */ diff = size - (body + tag); assert(diff >= 0); assert (diff <= tag); } return true; } Bool list_invariant(Tile *list) { int prev; Tile *t; int diff; assert(tile_invariant(list)); /* A list is also a tile */ assert(!list->body); /* Lists don't have bodies */ for (prev = list->cmin, t= list->down; t; t=t->right) { assert(tile_invariant(t)); /* Every child is a valid tile */ if(t->ishidden) continue; /* Every visible tile abutts the previous one */ assert(t->min == prev); prev = t->max; } if(list->down) { diff = list->cmax - prev; /* slop at the bottom */ assert(diff >= 0); assert(diff <= list->down->base); } return true; } /* "Snap" the size of 't' to some "neat" value, * without increasing 't's size. */ static void quantize(Tile*t) { int tag, body,size; if (!t->body) return; /* only really makes sense for windows */ size = TILESIZE(t); tag = snapheight(t->tag, size); assert(size >= tag); /* or we should have been hidden */ body = snapheight( t->body, size -tag); t->max = t->min + tag + body; } /* Ensure 't' wil fit inside 'list'. */ static void crop(Tile*t, Tile *list) { int size = TILESIZE(t); int listsize = LISTSIZE(list); assert(t->up == list); assert (size >= 0); if(size > listsize) { t->max = t->min + listsize; size = listsize; } if (t->min < list->cmin) moveto(t, list->cmin); if (t->max > list->cmax) t->max = list->cmax; assert (t->max >= t->min); assert (t->max <= list->cmax); assert (t->min >= list->cmin); } /* 't's shape has changed. Redisplay it, and any of its children */ void tile_reshaped(Tile *t) { Rectangle r = rectangle(t); assert(!t->ishidden); /* we don't reshape hidden tiles */ cls(r); view_reshaped(t->tag, r); if(t->body) { r.min.y += view_height(t->tag); view_reshaped(t->body, r); } else { list_reshaped(t,0); } assert(tile_invariant(t)); } /* Add 'tile' to 'list' and redisplay the modified 'list' * Try to maintain 'tile's min and max, but also try to avoid hiding * other tiles. Make sure that 'tile' ends up with a reasonable amount * of space. */ void list_add(Tile *list, Tile *tile) { Tile *left; Tile *next; int max; assert(!list->ishidden); assert(!tile->ishidden); assert(list_invariant(list)); if(tile->body) { Path buf; Data *d; d = view_data(tile->body); data_getlabel(d, buf); placedcol( buf, list); } tile->up = list; crop(tile, list); if( (left = list_find(list, tile->min)) ) { /* Add 'tile' just to the right of 'left' */ left->max = tile->min; if(TILESIZE(left) < tile->base) left->ishidden = true; else quantize(left); tile->left = left; tile->right = left->right; left->right = tile; if (tile->right) tile->right->left = tile; } else { assert(!list->down); /* ...or we would have found a tile */ tile->right = tile->left = 0; list->down = tile; tile->min = list->cmin; tile->max = list->cmax; } /* Maybe expand tile->max */ next = next_visible(tile); max = next? next->min : list->cmax; tile->max = MAX(tile->max, max); tile->min = MIN(tile->max - tile->base, tile->min); list_reshaped(list, tile); } /* Adjust the position of 't', to try to make sure we don't * have to hide all of t's siblings. On the other hand, don't * move 't' _too_ much. */ static void adjust_position(Tile *t) { Tile *l = t->up; int size, available, before, after, minsize, diff, move; before = list_basesize(l->down, t); after = list_basesize(t->right, 0); size = TILESIZE(t); /* We're prepared to shrink to half our asked-for size, * or the minimum size for a tile of our type, whichever * is bigger. */ minsize = MAX(size/2, tile_minsize(t)); available = size - minsize; /* move t->min down a bit? */ diff = l->cmin + before - t->min; if (diff>0) { move= MIN(available, diff); if(move > 0) { t->min += move; available -= move; } } /* move t->min up a bit? */ diff = t->max - (l->cmax - after); if (diff>0) { move= MIN(available, diff); if(move > 0) { t->max -= move; } } } /* * Adjust the sizes of the children, redisplay them if necessary. * Avoid moving or resizing 't'. Ensure that 't' remains visible. * We can assume that all of the * tiles have the right approximate size, but that's it. */ void list_reshaped(Tile *l, Tile *tile) { Tile *t; int cmin, cmax; Tile *slop; int diff; assert(list_oksizes(l)); if (tile) { crop(tile,l); adjust_position(tile); adjust_sizes_in_range(l->down, tile, tile->min - l->cmin); adjust_sizes_in_range(tile->right, 0, l->cmax - tile->max); } else adjust_sizes_in_range(l->down, 0, LISTSIZE(l)); assert(list_oksizes(l)); assert(list_size(l->down, 0) <= LISTSIZE(l)); FOR_EACH_VISIBLE(l->down,0) { quantize(t); } diff = LISTSIZE(l) - list_size(l->down, 0); assert(diff>=0); /* Even things up a little bit */ if ((slop = last_visible_body(l->down,0)) || (slop = last_visible(l->down, 0)) ) { slop->max += diff; } list_slide(l); setcminmax(l, &cmin, &cmax); FOR_EACH_TILE(l->down,0) { t->cmin = cmin; t->cmax = cmax; if(!t->ishidden) tile_reshaped(t); } assert(list_invariant(l)); } /* * Find a good place to create a window to display 'path'. * Fill *col with the column to contain the window, * *min, *max with a suggested position within the column */ /* Change the font of 't' and t's children */ void tile_setfont(Tile *t,char* arg) { if(t->body) { view_setfont( t->body, arg); } else { FOR_EACH_TILE(t->down, 0) { tile_setfont(t, arg); } } } /* * Unlink 'tile' from its parent/child/siblings. */ void tile_unlink(Tile*tile){ /* Unlink tile */ if(tile->right) tile->right->left = tile->left; if(tile->left) { tile->left->right = tile->right; /* Give the preceding window all the space. */ tile->left->max = tile->max; } else { tile->up->down = tile->right; } list_unhide(tile->up); cls(rectangle(tile)); list_reshaped(tile->up, 0); } /* * Free up all the resources used by 'tile' */ void tile_free(Tile*tile){ /* Free tile's resources */ free(tile->body); free(tile->tag); free(tile); } /* * Unlink 'tile' from its parent/child/siblings. * Free up all the resources used by 'tile' */ void tile_del(Tile *tile) { tile_unlink(tile); tile_free(tile); } /* Find a new parent for 'tile' somewhere at point 'p' */ Tile* newparent(Tile*tile, Point p){ Tile *t = point2tile(wily, p); assert(t); while((t->ori == tile->ori) || t->body) t = t->up; return t; } void tile_move(Tile *tile, Point p){ Tile *parent; int dest; /* Make sure we'll have someplace worth moving to */ parent = point2tile(wily,p); if (parent == 0 || parent == wily) return; tile_unlink(tile); dest = (tile->ori == H) ? p.x : p.y; if (tile->min < dest && dest < tile->max) tile->min = dest; else moveto(tile, dest); parent = newparent(tile, p); list_add(parent, tile); cursorset(buttonpos(tile)); } void tile_show(Tile *tile) { if(tile->up) tile_show(tile->up); if (tile->ishidden || (TILESIZE(tile) < tile_minsize(tile))) tile_grow(tile, 1); } View* tile_body(Tile*t) { return t? t->body: 0; } View* tile_tag(Tile*t) { return t? t->tag: 0; } /* Fill in 'min' and 'max' with a subregion within 'tile' for creating a new tile */ static void tile_split(Tile *tile, int *min, int *max) { int lastline, average; *max = tile->max; average = (tile->max + tile->min)/ 2; if(tile->body) { lastline = view_lastlinepos(tile->body); assert(lastline <= tile->max); *min = MIN(average, lastline); } else { *min = average; } } /* Fill 'min' and 'max' with a good place to add a tile within 'list' */ void findplace(Tile*list, int *min, int *max) { /* Split the largest visible tile, or use all the available space. */ Tile*biggest; if ( (biggest=biggest_visible(list->down, 0)) ) { tile_split(biggest, min, max); } else { *max = list->cmax; *min = list->cmin; } } /* Change t's position, keeping its size. */ void moveto(Tile*t, int pos) { int size = TILESIZE(t); t->min = pos; t->max = t->min + size; } /* Create (but don't display) a new tile */ Tile* tile_new(Ori ori, int min, int max, int base, Tile*parent, Text *tagt, Text*bodyt) { Tile*tile = NEW(Tile); int minsize; tile->ishidden = false; tile->ori = ori; tile->min = min; tile->max = max; tile->base = base; tile->up = parent; setcminmax(parent, &tile->cmin, &tile->cmax); tile->down = tile->left = tile->right = 0; tile->tag = view_new(font, true, tagt, tile); tile->body = bodyt ? view_new(font, false, bodyt, tile): 0; minsize = tile_minsize(tile); if(TILESIZE(tile) < minsize) tile->max = tile->min + minsize; return tile; } /* The minimum comfortable viewing size for 't' */ int tile_minsize(Tile*t) { return 3 * t->base; } wily-0.13.41/wily/col.c100644 2743 200 1657 6353254412 13100 0ustar garypgrad/******************************************* * Functions on columns *******************************************/ #include "tile.h" extern char* columntools; /* Return the column enclosing 'tile', or 0 */ Tile* tile_col(Tile*tile){ if(tile && tile->ori != H) tile = tile->up; return tile; } /* Create and display a new column. */ void col_new(View*v, char *arg) { int min, max; Tile *col; Text *tagt; findplace(wily, &min, &max); tagt = text_alloc(0, false); text_replaceutf(tagt, nr, columntools); col = tile_new(H, min, max, MINWIDTH, wily, tagt, 0); list_add(wily, col); } /* Delete as many of the windows of 'tile' as possible. Return 0 * if we got them all. */ static int col_delwins(Tile*tile) { Tile *t, *next; int problem = 0; for(t = tile->down; t; t= next) { next = t->right; if (win_del(t)) problem = 1; } return problem; } void col_del(Tile*t) { if(t && !col_delwins(t)) { tile_del(t); } } wily-0.13.41/wily/dir.c100644 2743 200 3723 6373537427 13111 0ustar garypgrad/******************************************* * Read and format directories *******************************************/ #include "wily.h" #include "data.h" enum { MAXNAMES = 10240 /* initial number of names in a directory */ }; static int mycmp (const void *a, const void *d) { return strcmp(*(char**)a, *(char**)d); } /* A few OS's have file systems that know which files in a directory are dirs. */ #ifdef DT_DIR #define CHECKDIR(dp) ((dp)->d_type == DT_DIR) #else #define CHECKDIR(dp) (0) #endif /* * Read 'dirp', return null-terminated array of strings representing the * files in the directory. Both the strings and the array need to be * freed later (use dirnames_free()). * * Returns 0 on error. */ char ** dirnames (DIR *dirp, char *path) { struct stat statbuf; struct dirent *direntp; char *name; char **list; int nfiles; int maxnames = MAXNAMES; /* Read the directory into a big buffer */ rewinddir(dirp); /* Workaround for FreeBSD. */ list = (char**) salloc(maxnames * sizeof(char*)); /* temporarily chdir so we can stat */ if(chdir(path)) { diag(path, "couldn't chdir"); return 0; } nfiles = 0; while ((direntp = readdir(dirp))) { name = direntp->d_name; if( name[0] == '.' && (!show_dot_files || name[1]=='\0')) { continue; } if (!(nfiles+2 < maxnames) ) { maxnames *= 2; list = (char**) srealloc(list, maxnames * sizeof(char*)); } if (CHECKDIR(direntp) || (stat(name, &statbuf) >= 0 && S_ISDIR(statbuf.st_mode))) { Path buf; sprintf(buf, "%s/", name); list[nfiles++] = strdup(buf); } else { list[nfiles++] = strdup(name); } } /* return to wilydir */ if(chdir(wilydir)) { diag(wilydir, "couldn't chdir back to wilydir [%s]", wilydir); } closedir(dirp); qsort(list, nfiles, sizeof(char*), mycmp); list[nfiles] = 0; return list; } /* Keep consistent with dirnames() */ void dirnames_free(char**names) { char **s; if(!names) return; for(s=names; *s; s++) free(*s); free(names); } wily-0.13.41/wily/vsearch.c100644 2743 200 10660 6506117074 13772 0ustar garypgrad/******************************************* * b3-type stuff in a view *******************************************/ #include "wily.h" #include "view.h" static Bool view_literal(View**vp, Range*r, char*s); static Bool view_gotofile(View**vp, Range *r, char *s); /* If 'label' is the label of some existing file, return View for it. */ View* openlabel(char*label, Bool create) { View*v; Path contracted; pathcontract(contracted,label); if ( (v=data_find(contracted)) ) { tile_show(v->tile); return v; } else if ( (v=data_open(contracted,create)) ) return v; else return 0; } /* Look (builtin) for 'arg' in the context of 'v' */ void view_look (View *v, char *arg) { Bool found = false; ulong p; Range r; assert(ISBODY(v)); if( ! text_length(v->t)) return ; p = (v->sel.p0 + 1) % text_length(v->t); r = range(p, p); if(arg) { found = text_findliteralutf(v->t, &r, arg); } else if (RLEN(v->sel) ){ found = text_look(v->t, &r, v->sel); } else { found = false; } if(found){ view_show(v,r); view_select(v, r); view_setlastselection(v); } } /* * Search for address 's'. Use *vp for context, *r as the starting point * for searches. May create a new window, but doesn't otherwise affect * the screen. If it finds something, return true, and fill in *vp and * and *r with the location of where we found something. * * 's' may be of the form path:addr, :addr, path or a literal, searched * for in that order. * * NB modifies 's' */ Bool view_goto(View**vp, Range *r, char *s) { return view_gotofile(vp,r,s) || view_literal(vp, r,s); } /* We've clicked the 'goto' button, selecting 'r' in 'v' * If this window is under external control, just send the event, * otherwise expand the selection, and 'goto' it, in the context of 'v'. */ void b3(View *v, Range r) { char *s; View *oldv; Range expanded; Data *d; View*found; /* Try to send simply expanded version to remote process */ expanded = view_expand(v, r, notaddress); if (!RLEN(expanded)) return; /* empty click nowhere -- ignore */ s = text_duputf(v->t, expanded); d = view_data(v); oldv = v; /* Send to remote process? */ if(data_sendgoto(d,expanded, s)) goto cleanup; if (view_gotofile(&v, &expanded, s)) { /* Simple file? */ r = expanded; } else if ( (found = openinclude(v,r)) ) { v = found; r = found->sel; } else if (view_literal(&v, &expanded, s)) { /* Literal? */ r = expanded; } else { /* found nothing */ goto cleanup; } view_show(v,r); view_select(v,r); view_setlastselection(v); /* warp unless b3 in the tag jumps to the body. */ if (oldv != tile_tag(view_win(v))) view_warp(v,r); cleanup: free(s); } /* Search for literal 's' in '*vp' starting at '*r'. * If we find a match, update 'vp' and 'r' and return true, * otherwise, return false. */ static Bool view_literal(View**vp, Range*r, char*s) { View*v; Text *t; Range tmp; v = *vp; tmp = *r; /* Only makes sense if 'v' is a body or we can find a useful body */ if(!ISBODY(v)){ if ((v = view_body(v)) || (v = view_body(last_selection))) { tmp = v->sel; } else { return false; } } assert(ISBODY(v)); t = v->t; if(text_findliteralutf(t, &tmp, s)) { *vp = v; *r = tmp; return true; } return false; } /* * Search for address 'a'. Use *vp for context, *r as the starting point * for searches. May create a new window, but doesn't otherwise affect * the screen. If it finds something, update *vp and *r and return * true, otherwise return false and leave vp and r alone. * * 's' may be of the form path:addr, or path, or :addr. */ static Bool view_gotofile(View**vp, Range *r, char *a) { Path s; View *v = *vp; View *v2; char *colon; /* preserve the colon */ Path label; strcpy(s,a); /* BUG - fails horribly if 'a' is large */ colon = strchr(s, ':'); if (colon) { *colon=0; } /* look for 's' as a file or directory */ if(strlen(s)) { /* 'path' or 'path:addr' */ data_addcontext(view_data(v), label, s); if( (v2=openlabel(label, false))){ if(colon) { Range oldr = v2->sel; if(!text_search(v2->t, r, colon+1, v2->sel)) { *r = oldr; } } else { *r = v2->sel; } *vp = v2; return true; } else return false; /* bad path */ } assert(!strlen(s)); /* :addr by itself then */ if(!ISBODY(v)){ if( ! ((v = view_body(v)) || (v = view_body(last_selection))) ) return false; } *r = v->sel; if (text_search(v->t, r, colon+1, v->sel)) { *vp = v; return true; } return false; } wily-0.13.41/wily/exec.c100644 2743 200 17644 6332625531 13273 0ustar garypgrad/******************************************* * fork, setup environment, exec children *******************************************/ #include "wily.h" #include #include #include static char * historyfile; static char * shell; static int ex_run (View*, char *); static int pipe_views (char**cmd, View**vout, View**vin); static int openpipes (int*out, int *err, Bool ); static int ex_parent (int , int , char*, char*, View *, int ); static void ex_child (int , int , char *, char *, View *); static void history (char *cmd); static void childenv (char *,char*); static void childfds (int fderr, int fdout, View *vin); static void reap (void); static void signal_init (void) ; static void well_known_init(void) ; /* * Initialize whatever we need * for dealing with external processes */ void ex_init(void) { keytab_init(); well_known_init(); signal_init(); historyfile = getenv("HISTORY"); if(!historyfile) historyfile = getenv("history"); shell = getenv("SHELL"); if(!shell) shell=DEFAULTSHELL; } /* * Run 'cmd' with arg 'arg' in View 'v'. * * 'arg' may be null, 'cmd' must be nonnull. */ void run(View *v, char *cmd, char *arg) { char *buf, *buf2; char *a2; cmd += strspn(cmd, whitespace); if(!*cmd) return; /* * For builtins, we want to separate cmd and arg, * and if we're passed a pointer to 'arg', we must pass * one on to builtin, even if the arg is just whitespace. */ if(arg) { buf = salloc( strlen(cmd) + strlen(arg) + 2); sprintf(buf, "%s %s", cmd, arg); } else { buf = strdup(cmd); } buf2 = strdup(buf); /* before we scribble over buf */ cmd = strtok(buf, whitespace); assert(*cmd && !isspace(*cmd)); a2 = strtok(0, ""); if(!a2) a2 = arg; if(!builtin(v, cmd, a2)) ex_run(v, buf2); free (buf); free (buf2); } /********************************************************************* Static Functions *********************************************************************/ /* Execute 'cmd', which was selected in 'v'. * PRE: the first character of cmd is not 0 or whitespace. * Return 0 for success. */ static int ex_run(View*v, char *cmd) { View *vout, *vin; /* Views for output/input */ int pout[2]; /* pipe for stdout */ int perr[2]; /* pipe for stderr */ Path label; int pid; if(pipe_views(&cmd, &vout, &vin)) return -1; if(openpipes(pout, perr, (Bool)vout)) return -1; data_getlabel(view_data(v), label); switch(pid=fork()) { case -1: /* fork failed */ close(perr[0]); close(perr[1]); close(pout[0]); close(pout[1]); return -1; default: /* parent */ close(perr[1]); close(pout[1]); return ex_parent(perr[0], pout[0], label, cmd, vout, pid); case 0: /* child */ close(perr[0]); close(pout[0]); ex_child(perr[1], pout[1], label, cmd, vin); /* ex_child doesn't return */ assert(false); exit(1); return -1; } } /* * Update 'cmd', 'vout' and 'vin' * appropriately depending on whether 'cmd' is a piping command, * i.e. starts with | < or >. * Return 0 for success. */ static int pipe_views(char**cmd, View**vout, View**vin) { char op; View*vpipe; op = **cmd; *vout = 0; *vin = 0; if(!( op == '|' || op == '<' || op == '>')){ return 0; } /* Pipe operations are on the body of the last selection */ if(!(vpipe = view_body(last_selection))) return -1; /* Make 'cmd' now point to the command, after '|' and * optional whitespace. */ *cmd += 1 + strspn((*cmd)+1, whitespace); /* don't execute an empty command */ if (!strlen(*cmd)) return -1; if (op == '|' || op == '<') *vout = vpipe; if (op == '|' || op == '>') *vin= vpipe; return 0; } /* Open pipes for stdout and stderr. * If and only if this is a '|' or '>' operation, stdout * will be distinct from stderr. * * Return 0 for success. * * If we don't succeed, make sure * we don't leave any open file descriptors. */ static int openpipes(int*out, int *err, Bool is_pipe_operation){ if (pipe(err) < 0) { diag(0, "pipe"); return -1; } if (is_pipe_operation) { if (pipe(out) < 0) { diag(0, "pipe"); close(err[0]); close(err[1]); return -1; } } else { out[0] = err[0]; out[1] = err[1]; } return 0; } /* * Parent-side accounting for a recently started external process. * * 'fderr', 'fdout' are file descriptors for stdout and stderr * 'label' is the label of the window we started in. * 'cmd' is the command being executed * 'vout', if non-null, is the View to send stdout to. * 'pid' is the process id of the child process. * * Return 0 for success. */ static int ex_parent(int fderr, int fdout, char*label, char*cmd, View *vout, int pid) { /* fderr == fdout if and only if vout == 0 */ assert( (vout==0) == (fderr == fdout)); reap(); event_outputstart(fderr, pid, cmd, label,0); if(vout) event_outputstart(fdout, pid, cmd, label, vout); return 0; } /* * Child-side accounting for a recently started external process. * * 'fderr', 'fdout' are file descriptors for stdout and stderr * 'label' is the label of the window we started in. * 'cmd' is the command being executed * 'vin', if non-null, is the View to get stdin from. * * Does not return. * Don't use normal diag stuff -- we're a separate process. * After we've set up stderr, just fprintf(stderr,...) */ static void ex_child(int fderr, int fdout, char *label, char *cmd, View *vin) { Path dir; Path path; childfds(fderr, fdout, vin); /* become process group leader */ if(setsid()<0) perror("setsid"); label2path(path, label); strcpy(dir,path); dirnametrunc(dir); /* Executing the command without being in the right directory * would be _bad_. */ if(chdir(dir)){ Path buf; sprintf(buf, "chdir(%s)", dir); perror(buf); exit(1); } childenv(label, path); history(cmd); execl(shell, shell, "-c", cmd, 0); perror(shell); exit(1); } /* Record 'cmd' in the history file */ static void history(char *cmd) { FILE *fp; if(!historyfile) return; fp = fopen(historyfile, "a"); fprintf(fp,"%s\n", cmd); fclose(fp); } /* Add some stuff to the environment of our child */ static void childenv(char *label,char*path) { Path buf; sprintf(buf, "WILYLABEL=%s", label); (void)putenv(strdup(buf)); sprintf(buf, "WILYPATH=%s", path); (void)putenv(strdup(buf)); sprintf(buf, "w=%s", path); (void)putenv(strdup(buf)); } /* * Set up default file descriptors for a child process. * * Replace 'stderr' and 'stdout' with 'fderr' and 'fdout'. * * If 'vin' is not null, replace 'stdin' with a file descriptor * that will give the contents of the selection in 'vin', * otherwise, 'stdin' is set to '/dev/null'. */ static void childfds(int fderr, int fdout, View *vin) { int j; int fdin; /* redirect fdout and fderr */ if (dup2(fderr, 2) < 0 || dup2(fdout, 1) < 0) { perror("dup2"); exit(1); } if (vin) { /* fd open to read current selection */ fdin = text_fd(view_text(vin), view_getsel(vin)); if(fdin<0) exit(1); } else if ((fdin = open("/dev/null", O_RDONLY, 0)) < 0) { perror("open /dev/null"); fdin = 0; } if (fdin) { if (dup2(fdin, 0) < 0) { perror("input dup2"); fdin = 0; } } if (!fdin) { /* no need to panic... */ if (close(0) < 0) { /* OK, panic. */ perror("close fdin"); exit(1); } } /* Don't inherit any other open fds */ for(j=3; j 0 ) ; } /* Prepare to catch some signals */ static void signal_init(void) { /* in case external process exits */ signal(SIGPIPE, SIG_IGN); signal(SIGHUP, cleanup_and_die); signal(SIGINT, cleanup_and_die); signal(SIGTERM, cleanup_and_die); signal(SIGSEGV, cleanup_and_abort); /* signal(SIGSYS, cleanup_and_abort); */ signal(SIGILL, cleanup_and_abort); } /* Start listening to fifo in well-known location */ static void well_known_init(void) { int fd; if((fd = wilyfifolisten())<0) { diag(0, "couldn't open fifo"); } else { event_wellknown(fd); } } wily-0.13.41/wily/event.c100644 2743 200 13434 6332625633 13464 0ustar garypgrad/********************************************************* Set up and handle interactions with all the libXg events that aren't mouse,timer or keyboard. *********************************************************/ #include "wily.h" #include typedef struct Key Key; /* Different uses for a libXg event key */ typedef enum Keytype { Kfree, /* not in use */ Klisten, /* connection requests */ Kout, /* output to stderr or a window */ Kmsg /* from external connections */ } Keytype; /* Info about a libXg event key */ struct Key { Keytype t; int fd; /* file descriptor*/ ulong key; /* libXg event key */ /* * Buffer for incomplete messages. * Only in use if k->t == Kmsg. */ Mbuf buf; /* * Info about the program sending us output. * Only valid if k->t == Kout. */ int pid; Path cmd; /* shortened name of executing command */ Path olabel; /* where output should go */ /* If output should replace some View's selection ( |, > ). * Note that when we use |cmd or >cmd, we'll get TWO * event Keys, one for stderr (with k->v == 0), and * one for stdout, (with k->v set). */ View *v; Bool first; }; /* * Because libXg can only keep track of a small number of * event keys, so do we. We keep the Keys in a static array. * The Key at position 'n' in keytab has libXg event key 2^n. * * This is a bit wasteful, and a bit inefficient. Some event keys * will never be used here. Too bad. */ enum { MAXKEYS =FOPEN_MAX }; static Key keytab[MAXKEYS]; static Key* key_find(ulong key); static void outmsg(Key*k, int n, char*s); static void key_del(Key *k); static Key* key_new(ulong key, int fd, Keytype t); static Key* key_findcmd(char*cmd); static void oneword(char*s, char*l); static void output(Key*k, int n, char*s); static void ex_accept(int n, char*s); /* Initialise keytab */ void keytab_init(void) { Key *k; ulong key = 1; for(k = keytab; k < keytab + MAXKEYS; k++) { k->t = Kfree; k->key = key; key *= 2; mbuf_init(&k->buf); } } /* * Start listening for output on 'fd'. * The output is from the (long) command 'cmd', process 'pid'. * The context is associated with 'label'. * If 'v' is set, we are piping the output to this View. */ int event_outputstart(int fd, int pid, char*cmd, char*label, View *v){ ulong key; Key *k; if (!(key = estart(0, fd, 0))) { diag(0, "estart"); return -1; } k = key_new(key, fd, Kout); k->pid = pid; k->v = v; /* Every 'pipe' key has another 'stderr' key, we only * display the 'cmd' associated with the 'stderr' key. */ if(k->v) { k->first = true; } else { oneword(k->cmd, cmd); olabel(k->olabel, label); addrunning(k->cmd); } return 0; } /* Start listening for connection attempts on 'fd' */ void event_wellknown(int fd){ ulong key; if(!(key = estart(0, fd, 0))) error("estart"); key_new(key,fd, Klisten); } /* * Handle 'n' bytes of data in 's' which arrived from * libXg event key 'key'. */ void dofd(ulong key, int n, char*s) { Key *k = key_find(key); if(!n) { key_del(k); return; } switch(k->t){ case Klisten: ex_accept(n,s); break; case Kout: output(k, n, s); break; case Kmsg: outmsg(k, n, s); break; default: error("bad key type %d", k->t); break; } } /* * Kill all the external processes matching * the arguments. */ void kill_all(char*s) { Key *k = 0; const char *sep = " \t\n"; for (s = strtok(s, sep); s; s = strtok(NULL, sep)) { if ((k = key_findcmd(s))) { /* only output keys have a prog attached */ assert(k->t == Kout); if(kill(- k->pid, SIGKILL)) diag(0, "kill %s", s); } } } /* Output a list of possible 'Kill' commands. */ void kill_list(void){ Key *k; for(k = keytab; k < keytab + MAXKEYS; k++) if(k->t == Kout && !k->v) diag(0, "Kill %s", k->cmd); } /****************************************************** static functions ******************************************************/ static void outmsg(Key*k, int n, char*s) { if(partialmsg(&k->buf, k->fd, n, s)){ diag(0, "Received bad message, closing connection"); key_del(k); } } /* Free any resources that 'k' was tying up. */ static void key_del(Key *k) { close(k->fd); estop(k->key); switch(k->t) { case Kout: if(!k->v)rmrunning(k->cmd); break; case Kmsg: data_fdstop(k->fd); break; case Klisten: error("Klisten closed"); default: error("bad key type %d", k->t); } k->t = Kfree; } /* Allocate and return a new Key with the given key, fd and type */ static Key* key_new(ulong key, int fd, Keytype t) { Key *k; k = key_find(key); assert(k->t == Kfree); k->fd = fd; k->t = t; return k; } /* Find the output Key with the given 'cmd' */ static Key* key_findcmd(char*cmd) { Key *k; for(k = keytab; k < keytab + MAXKEYS; k++) if (k->t == Kout && STRSAME(cmd, k->cmd)) return k; return 0; } /* Put a one-word version of long command 'l' into 's' */ static void oneword(char*s, char*l){ strcpy(s,l); /* break at first whitespace */ if( (s = strpbrk(s, whitespace)) ) *s='\0'; } /* Copy the 'n' bytes of data in 's' to the window or output directory * corresponding to 'k' */ static void output(Key*k, int n, char*s) { if(k->v) view_pipe(k->v, &k->first, s, n); else noutput(k->olabel, s, n); } /* Accept the connection we're told about with 's' and 'n' */ static void ex_accept(int n, char*s) { int fd; ulong key; Key *k; if((fd =wily_connect(s,n))<0) { diag(0, "failed connection attempt"); return; } if (!(key= estart(0,fd,0))){ diag(0, "couldn't estart to accept connection"); close(fd); return; } k = key_new(key, fd, Kmsg); mbuf_clear(&k->buf); } /* * Find the Key info given the libXg event key. * * ASSUMPTION: integers at least 32 bit. */ static Key* key_find(ulong key) { Key *k; for(k = keytab; k < keytab + MAXKEYS; k++) if(k->key == key) return k; /* We assume key_find will always work */ assert(false); return 0; } wily-0.13.41/wily/place.c100644 2743 200 3336 6332624564 13411 0ustar garypgrad/******************************************* * Decide where to place new windows *******************************************/ #include "wily.h" #include "tile.h" enum {TSIZE=401}; static Tile* placetable[TSIZE]; /* hashed array of column tiles */ static Bool iserror(char*label); static Bool validcolumn(Tile*c); static unsigned long hashpath(char *path); static Tile * find(char *label); /* Save the window column for later lookup. */ void placedcol(char*label, Tile *c) { if (label && !iserror(label)) placetable[hashpath(label)] = c; } /* Return the column to use for a new window with label 'path' */ Tile* findcol(char*label) { Tile *c; if(!wily->down){ col_new(wily->tag,0); return wily->down; } if(iserror(label)) return last_visible(wily->down, 0); if (!(c= find(label))) { c = biggest_visible(wily->down, 0); assert(c); placedcol(label, c); } return c; } /****************************************************** static functions ******************************************************/ static Bool iserror(char*label) { static char *errors = "+Errors"; int elen = strlen(errors); int len = strlen(label); return (len >= elen && !strncmp(label + (len - elen), errors, elen)); } /* Is 'c' still a valid pointer for a visible column? */ static Bool validcolumn(Tile*c) { return list_contains(wily->down, 0, c); } /* Hash from directory name into 'placetable' */ static unsigned long hashpath(char *path) { char *s; unsigned long hash = 0; assert(path); for (s = strrchr(path, '/'); path < s; path++) hash = (hash << 5) ^ *path; return hash % TSIZE; } static Tile * find(char *label) { Tile *c; if (label) { c = placetable[hashpath(label)]; if (validcolumn(c)) return c; } return 0; } wily-0.13.41/wily/data.h100644 2743 200 3773 6332624342 13242 0ustar garypgrad/******************************************* * the stuff a window represents (file, directory, type-script...) *******************************************/ #include /* The 'Data' struct The 'label' is the name of the window, as it appears in the window. The label can start with: / meaning an absolute path name, e.g. /bin $ meaning an environment variable, e.g. $HOME ~ meaning a home-dir, e.g. ~/, ~i/ anything else is interpreted relative to the directory wily started in. If the window is a directory, the label should end with a / If we represent some file which should be backed up, 'backupto' is set to the name of the file to back up. For data objects monitored by some external process we track the file descriptor to that process, and an event mask telling us what events that process is interested in. For directories, we cache a null-terminated list of strings representing the files in the directory. This is so when the window is reshaped we can reformat the list without having to reread the directory. If this Data object doesn't represent a directory, 'names' ==0 'label' is what currently appears in the tag. 'cachedlabel' is the value of 'label' at the last successful stat/open/... We only update 'has_stat' and 'stat' when necessary. */ struct Data { Text *t; Text *tag; Data *next; Path label, cachedlabel; /* Path path; */ Bool has_stat; Stat stat; char *backupto; /* for object connected to some external process */ int fd; ushort emask; Id id; /* Unique identifier */ char **names; /* cache of names of files in this directory, or 0 */ }; /* A data object needs to be backed up if there is some backup file associated * with it, and it's Text isn't clean */ #define NEEDSBACKUP(d) (d->backupto && !undo_atmark(d->t)) void data_setbackup(Data *, char*); Data * data_findid(Id ); extern Data *dataroot; Bool data_senddestroy(Data *d); void data_listremove(Data *d); /* dir.c */ void dirnames_free(char**names); char** dirnames (DIR *dirp, char *path); wily-0.13.41/wily/msg.c100644 2743 200 16540 6332624603 13126 0ustar garypgrad/******************************************* * Handle messages from remote processes *******************************************/ #include "wily.h" #include "data.h" static char* badrange ="bad range"; static char* unknown ="unknown message type"; static char* data_attach(Data*d, int fd, ushort emask); static void data_changelabel(Data *d,char*label); static char* data_getname(Data*d); static char * data_list(void); static int msg_send(Msg*m, int fd); static void msg_new(Msg*m); static void msg_fillfd(Msg*m, int fd); static Bool msg_form_and_send(Mtype, Id, Id, Range, ushort, char *, int); static void msg_process(Msg*m, int fd); static void msg_error(Msg*m, char*s); /**************************************************************** Unpack and handle incoming messages ****************************************************************/ void mbuf_init(Mbuf*m){ m->buf = 0; m->alloced = 0; m->n = 0; } void mbuf_clear(Mbuf*m){ m->n = 0; } /* * Handle the message contained in 'buf' (which might have * part of an old message) and 's', which contains 'n' new bytes. * Send any replies back along 'fd'. * * Return 0 unless we get a badly formatted message. */ int partialmsg(Mbuf *m, int fd, int n, char*s){ char *ptr; int left; /* copy to m->buf */ SETSIZE(m->buf, m->alloced, m->n + n); memcpy(m->buf + m->n, s, n); m->n += n; /* process any whole messages */ ptr = m->buf; left = m->n; while (FULLMSG(ptr,left)) { Msg msg; int eaten = msg_bufsize(ptr); if(msg_init(&msg, ptr)){ return -1; } ptr += eaten; left -= eaten; msg_process(&msg, fd); } /* move any incomplete messages to front of buf->buf */ if (left && left != m->n) memmove(m->buf, ptr, left); m->n = left; return 0; } /* * Stop any data from sending events to 'fd', * which is probably closed. */ void data_fdstop(int fd) { Data *d; for (d=dataroot; d; d = d->next) { if(d->fd == fd){ d->fd = 0; d->emask = 0; } } } /**************************************************************** Send out messages in response to user events ****************************************************************/ /* * If someone's monitoring this window for 'replace' events, * send them one. If we fail to send the message, or don't need * to send the message, return false. */ Bool data_sendreplace(Data *d,Range r, Rstring s) { char *buf; Bool retval; if(! ( d && d->emask & WEreplace) ) return false; buf = salloc(RSLEN(s) * UTFmax); buf[texttoutf(buf, s.r0, s.r1)] = '\0'; retval = msg_form_and_send(WEreplace, 0, d->id, r, 0, buf, d->fd); free(buf); return retval; } /* see data_sendreplace */ Bool data_senddestroy(Data *d) { if(! ( d && d->emask & WEdestroy) ) return false; return msg_form_and_send(WEdestroy, 0, d->id, nr, 0, 0, d->fd); } /* see data_sendreplace */ Bool data_sendgoto(Data *d,Range r, char *s) { if(! ( d && d->emask & WEgoto) ) return false; return msg_form_and_send(WEgoto, 0, d->id, r, 0, s, d->fd); } /* see data_sendreplace */ Bool data_sendexec(Data *d,char*cmd, char *arg) { Bool retval; char *s; if(! ( d && d->emask & WEexec) ) return false; if(arg) { s = salloc( strlen(cmd) + strlen(arg) + 2); sprintf(s, "%s %s", cmd, arg); } else { s = cmd; } retval = msg_form_and_send(WEexec, 0, d->id, nr, 0, s, d->fd); if(arg) free(s); return retval; } /********************************************** Static functions **********************************************/ static char* data_attach(Data*d, int fd, ushort emask) { if(d->fd) return "This window already attached"; else { d->fd = fd; d->emask = emask; return 0; } } /* Change the d->label to 'label', update d->path. * Only called in response to a remote message. */ static void data_changelabel(Data *d,char*label) { strcpy(d->label, label); tag_setlabel(d->tag, d->label); } static char* data_getname(Data*d){ static Path buf; label2path(buf, d->label); return buf; } /* Return newline-separated list of tab-separated (winname,id) tuples */ static char * data_list(void) { static char *buf=0; static int alloced=0; int size = 0; Data *d; char *ptr; Path path; /* calculate the size of buffer required */ size =0; for(d=dataroot; d; d=d->next) { label2path(path, d->label); size += strlen(path) + 15; } if(size > alloced) { alloced = size; buf = srealloc(buf, alloced); } ptr = buf; for(d=dataroot; d; d=d->next) { label2path(path, d->label); sprintf(ptr, "%s\t%d\n", path, d->id); ptr += strlen(ptr); } return buf; } /* Return 0 for success */ static int msg_send(Msg*m, int fd) { static uchar*buf=0; static int alloced=0; ulong size = msg_size(m); SETSIZE(buf, alloced, size); msg_flatten(m, buf); return write(fd,buf,size)!=size; /* todo - handle partial writes? */ } static void msg_new(Msg*m) { View *v; Data *d; if(!(v = data_find(m->s))) v = data_open(m->s, true); d = view_data(v); if(!m->flag) data_setbackup(d,0); m->w = d->id; } static void handleattach(Msg*m, Data*d, int fd){ m->s = data_attach(d, fd, m->flag); if(m->s) m->t = WRerror; } static void handleread(Msg*m, Text *t ) { if (text_badrange(t,m->r)) { msg_error(m, badrange); } else { m->s = text_duputf(t, m->r); } } static void handlereplace(Msg*m, Text *t ) { if (text_badrange(t,m->r)) { msg_error(m, badrange); } else { text_replaceutf(t, m->r, m->s); } } static void handlegoto(Msg*m, View*v) { Bool show; Range r; show = (m->t == WEgoto) || m->flag; /* We get the search start position * either from 'm' or 'dot' in the view. */ r = m->r; if(r.p0>r.p1) r = view_getsel(v); if(view_goto(&v, &r, m->s)){ if (show) { view_show(v, r); view_select(v, r); view_warp(v, r); } m->r = r; m->w = text_data(view_text(v))->id; } else { /* indicate search failure */ m->r.p0 = -1; m->r.p1 = 0; } } static void msg_error(Msg*m, char*s){ m->s = s; m->t = WRerror; } /* Process a message which arrived on 'fd'. Modifies 'm'. */ static void msg_fillfd(Msg*m, int fd) { Data *d=0; View *v; /* WMlist or WMnew don't need to be associated with a valid window. */ switch(m->t) { case WMlist: m->s = data_list(); return; case WMnew: msg_new(m); return; default: break; } if(!(d=data_findid(m->w))) { msg_error(m, "No window with this id"); return; } v = text_view(d->t); switch(m->t) { case WMattach: handleattach(m,d,fd); break; case WMsetname: data_changelabel(d, m->s); break; case WMgetname: m->s = data_getname(d); break; case WMsettools: tag_settools(d->tag, m->s); break; case WMgettools: m->s=tag_gettools(d->tag); break; case WMread: handleread(m, d->t); break; case WEreplace: break; case WMreplace: handlereplace(m,d->t); break; case WMexec: /* fall through */ case WEexec: run(v, m->s, 0); break; case WMgoto: /* fall through */ case WEgoto: handlegoto(m,v); break; default: msg_error(m, unknown); break; } } static Bool msg_form_and_send(Mtype t, Id m, Id w, Range r, ushort flag, char *s, int fd) { Msg msg; msg.t = t; msg.m = m; msg.w = w; msg.r = r; msg.flag = flag; msg.s = s; return ! msg_send(&msg, fd); } /* Process a message which arrived on 'fd' */ static void msg_process(Msg*m, int fd) { Bool isbounce; isbounce = m->t < WEfencepost; msg_fillfd(m, fd); if(!isbounce){ if(m->t != WRerror) m->t ++; (void)msg_send(m,fd); } else if (m->t == WRerror) { diag(0, "error from bounced event %s", m->s); msg_print(m); } } wily-0.13.41/wily/vshow.c100644 2743 200 10561 6332630412 13476 0ustar garypgrad/******************************************* * view scrolling *******************************************/ #include "wily.h" #include "view.h" void view_linesdown(View *v, int n, Bool down) { Mouse m; Rectangle r; if(! (v = tile_body(view_win(v))) ) return; r = v->r; m.xy.x = r.min.x; m.xy.y = r.min.y + v->f.font->height * n; m.buttons = down? RIGHT : LEFT; view_scroll(v, &m); } void view_pagedown(View *v, Bool down) { Mouse m; Rectangle r; if(! (v = tile_body(view_win(v))) ) return; r = v->r; m.xy.x = r.min.x; m.xy.y = (r.min.y + r.max.y) /2; m.buttons = down? RIGHT : LEFT; view_scroll(v, &m); } /* Make 'n' the first rune displayed in 'v' */ static void view_set(View*v, ulong n) { ulong ndelete; assert(view_invariants(v)); assert(v->scroll); assert(n<= text_length(v->t)); if(n == v->visible.p0) return; ndelete = RCONTAINS(v->visible, n) ? n - v->visible.p0 : v->f.nchars; v->visible.p0 = n; if (ISVISIBLE(v)) { frdelete(&v->f, 0, ndelete); fill(v); } assert(view_invariants(v)); } static Bool tag_isfull(Frame*f) { Point pt = frptofchar(f, f->nchars); Point max = f->r.max; return max.x - pt.x < 30; } /* Try to get a tag to show as much as possible of 'r' */ static void tag_show(View*v, Range r) { Frame *f = &v->f; assert(ISTAG(v)); assert(r.p1 <= text_length(v->t)); /* If we're seeing all of r, * or if all that we're seeing is in r, we're happy */ if(RISSUBSET(r, v->visible) || RISSUBSET( v->visible,r)) goto done; /* Otherwise, it must be the case that EITHER * there's some of 'r' invisible off to the right or the left */ assert(r.p1 > v->visible.p1 || r.p0 < v->visible.p0); if (r.p1 > v->visible.p1) { /* remove stuff until we can see r.p1 */ while(r.p1 > v->visible.p1) { frdelete(f, 0, f->nchars); v->visible.p0 += 5; fill(v); } assert(r.p1 <= v->visible.p1); } else { /* add stuff until we can see r.p0 */ frdelete(f, 0, f->nchars); v->visible.p0 = r.p0; fill(v); assert(r.p0 >= v->visible.p0); } done: while (!tag_isfull(f) && v->visible.p0) { frdelete(f, 0, f->nchars); v->visible.p0--; fill(v); } } /* Make sure 'v' is showing at least some of 'r' */ void view_show(View *v, Range r) { assert(view_invariants(v)); assert(ROK(r)); assert(r.p1 <= text_length(v->t)); if (v->scroll) { tile_show(v->tile); } assert(ISVISIBLE(v)); if(!v->scroll) { tag_show(v,r); return; } if(!RISSUBSET(r, v->visible)) { ulong dest; /* try to position range in the middle of the screen */ dest = text_nl(v->t, r.p0, -((int)v->f.maxlines)/2); view_set(v, dest); if (!RINTERSECT(r, v->visible)) { /* lines are too long, quit being fancy, start with line contain 'r' */ dest = text_startOfLine(v->t, r.p0); view_set(v,dest); } if (!RINTERSECT(r, v->visible)) { /* goddamm! we can't even fit a whole line. no more mr nice guy */ view_set(v,r.p0); /* Now _that_ oughta do it! */ } } assert(RINTERSECT(r, v->visible)); assert(view_invariants(v)); assert(ISVISIBLE(v)); } /* Handle a mouse-click in 'v's scrollbar */ void view_scroll(View *v, Mouse *m) { int y; ulong n,base = v->visible.p0; int lineheight = v->f.font->height; ulong runepos; assert(m->buttons); y = clip(m->xy.y - v->f.r.min.y, 0, Dy(v->f.r)); if (y < v->f.font->height && m->buttons != MIDDLE){ y = lineheight; m->xy.y += lineheight; } runepos = frcharofpt(&v->f, m->xy); /* * With left and middle buttons, we try to scroll back such that * we start at the start of a line. Sometimes that isn't possible, * if lines are too big, so we jump again to some fallback position. * TODO: work this stuff out offscreen. */ switch(m->buttons){ case RIGHT: view_set(v, base + runepos); break; case LEFT: n = back_height(v->t, v->visible.p0, v->f.font, Dx(v->f.r), m->xy.y - v->f.r.min.y); view_set(v, n); break; default: runepos = (text_length(v->t) * y) / Dy(v->f.r); n = text_startOfLine(v->t, runepos); view_set(v, n); if (runepos > v->visible.p1) { view_set(v, runepos); } } } /* Scroll 'v' to the left or right a bit, if possible */ void view_hscroll(View*v, Bool left) { ulong old = v->visible.p0; assert(!v->scroll); assert(ISTAG(v)); if(left){ if(v->visible.p0) v->visible.p0--; } else { if(v->visible.p1 < text_length(v->t)) v->visible.p0++; } if (old != v->visible.p0){ frdelete(&v->f, 0, v->f.nchars); fill(v); } } wily-0.13.41/wily/global.h100600 2743 200 767 6541666722 13553 0ustar garypgrad/* wily.c */ extern char*filetools; extern char*dirtools; /* global.c */ extern Bool show_dot_files; extern Bool autoindent_enabled; extern View *last_selection; extern char * notfilename, *notdoubleclick , *notcommand, *notaddress, *notinclude; extern char* whitespace; extern Path wilydir; /* icons.c */ extern Cursor boxcursor; extern Cursor fatarrow; extern Cursor *cursor; /* tile.c */ extern Tile *wily; /* wily.c */ extern int tagheight; extern int tabsize; /* ../sam/libframe/frinit.c */ wily-0.13.41/wily/file.c100644 2743 200 11235 6415665722 13264 0ustar garypgrad/******************************************* * Data read/write files, directories *******************************************/ #include "wily.h" #include "data.h" static int data_getstat (Data*, char*, char*, Stat*); static void data_opennew (Data*, char*, char*path); static int data_getdir (Data*, char*, char*, Stat*); static int data_getfile (Data*, char*, char*, Stat*); static void data_settag (Data*, char*); static Data * data_alloc (void); /* * Open a new 'data' to represent 'label'. Either read 'label', or if * it doesn't exist and 'create' is set, return an empty window to * represent where we _will_ write it. * * Return (View*)0 if 'label' exists but we can't read it, or it doesn't * exist and we don't want to create it. */ View* data_open(char*label, Bool create) { Data *d; Stat buf; Path path; Bool failure; label2path(path, label); d = data_alloc(); failure = false; if(stat(path,&buf)) { /* doesn't exist -- yet */ if(create) data_opennew(d, label, path); else failure = true; } else { failure = data_getstat(d, label, path,&buf); } if(failure){ data_listremove(d); free(d); return 0; } else { if(d->names) add_slash(path); data_settag(d, path); win_new(path, d->tag, d->t); return text_view(d->t); } } /* * Read file or directory 'label' into 'd'. * Return 0 for success. */ int data_get(Data *d, char *label) { Stat buf; Path path; if(data_backup(d)) return -1; /* If we did this, we'd lose data */ if(!label) label = d->label; /* is strcpy(a,a) bad? */ label2path(path,label); if(stat(path,&buf)){ diag(0, "Couldn't stat [%s (%s)]", path, label); return -1; } else { return data_getstat(d, label, path, &buf); } } /* Load 'd' with 'path', which has stat buffer 'buf'. * Returns 0 if we loaded succesfully. */ static int data_getstat(Data*d, char* label, char*path, Stat*buf) { int failed; cursorswitch(&boxcursor); bflush(); undo_reset(d->t); failed = S_ISDIR(buf->st_mode) ? data_getdir(d, label, path, buf) : data_getfile(d, label, path, buf); undo_start(d->t); if(!failed) undo_mark(d->t); cursorswitch(cursor); return failed; } /* Load 'd' with new file 'path'. */ static void data_opennew(Data*d, char*label, char*path) { /* d */ pathcontract(d->label, label); strcpy(d->cachedlabel, d->label); d->has_stat = false; data_setbackup(d, path); dirnames_free(d->names); d->names = 0; /* d->t */ text_replace(d->t, text_all(d->t), rstring(0,0)); undo_start(d->t); undo_mark(d->t); /* d->tag */ tag_setlabel(d->tag, d->label); tag_rmtool(d->tag, "Put"); } /* Load 'd' with directory 'path', which has stat buffer 'buf'. * Returns 0 if we loaded succesfully. */ static int data_getdir(Data*d, char*label, char*path, Stat*buf) { DIR* dirp; if((dirp = opendir(path)) == NULL) { diag(0, "opendir [%s]", path); return -1; /* failure - modify nothing */ } /* d */ pathcontract(d->label,label); add_slash(d->label); strcpy(d->cachedlabel, d->label); d->has_stat = true; d->stat = *buf; data_setbackup(d,0); dirnames_free(d->names); d->names = dirnames(dirp, path); /* d->t */ text_formatdir(d->t, d->names); /* d->tag */ tag_rmtool(d->tag, "Put"); tag_addtool(d->tag, "Get"); tag_setlabel(d->tag, d->label); return 0; } /* Load 'd' with file 'path', which has stat buffer 'buf'. * Returns 0 if we loaded succesfully. */ static int data_getfile(Data*d, char*label, char*path, Stat*buf) { int fd; extern Bool utfHadNulls; if((fd = open(path, O_RDONLY)) == -1) { diag(path, "open [%s]", path); return -1; /* failure - modify nothing */ } /* d */ pathcontract(d->label, label); strcpy(d->cachedlabel, d->label); d->has_stat = true; d->stat = *buf; data_setbackup(d,path); dirnames_free(d->names); d->names = 0; /* d->t */ text_read(d->t, fd, buf->st_size); close(fd); if (utfHadNulls) { diag(path, "removed nulls from [%s]", path); data_setbackup(d,0); } /* d->tag */ tag_rmtool(d->tag, "Put"); tag_rmtool(d->tag, "Get"); tag_setlabel(d->tag, d->label); return 0; } /* Fill 'buf' with appropriate stuff for d's tag */ static void data_settag(Data*d, char *path) { Path buf; char*common; char*specific; common = d->names? dirtools : filetools; specific = tag_match(path); sprintf (buf, "%s %s | %s %s ", d->label, d->names? "Get":"", filetools, specific); tag_set(d->tag, buf); } static Data * data_alloc(void) { Data *d; static Id id; d = NEW(Data); d->id = id++; d->next = dataroot; dataroot = d; d->t = text_alloc(d, true); d->tag = text_alloc(d, false); d->names = 0; d->backupto = 0; d->fd = 0; d->emask = 0; d->has_stat = false; strcpy(d->label, ""); strcpy(d->cachedlabel, ""); return d; } wily-0.13.41/wily/click.c100644 2743 200 6511 6332624015 13377 0ustar garypgrad/******************************************* * Handle double-click, etc. *******************************************/ #include "wily.h" #include "text.h" #include /* Matching brackets for double-click */ static Rune l1[] = { '{', '[', '(', '<', 0253, 0}; static Rune r1[] = {'}', ']', ')', '>', 0273, 0}; static Rune l2[] = { '\n', 0}; static Rune r2[] = {'\n', 0}; static Rune l3[] = { '\'', '"', '`', '>', 0}; static Rune r3[] = {'\'', '"', '`', '<', 0}; Rune *left[]= { l1, l2, l3, 0}; Rune *right[]= { r1, r2, r3, 0}; /* Return false if 'c' is obviously not an alphanumeric character, * or if it is in the stoplist. */ static Bool okchar(int c, char *stoplist) { /* * Hard to get absolutely right. Use what we know about ASCII * and assume anything above the Latin control characters is * potentially an alphanumeric. */ if(c <= ' ') return false; if(0x7F<=c && c<=0xA0) return false; if(utfrune(stoplist, c)) return false; return 1; } static int clickmatch(Text *t, int cl, int cr, int dir) { int c, nest; nest=1; while((c=(dir>0? Tgetc(t) : Tbgetc(t))) > 0) { if(cl=='\n' && c==0x04) /* EOT is trouble */ return 1; if(c == cr){ if(--nest == 0) return 1; }else if(c == cl) nest++; } return cl=='\n' && nest==1; } static Rune * strrune(Rune *s, Rune c) { Rune c1; if(c == 0) { while(*s++) ; return s-1; } while( (c1 = *s++)) if(c1 == c) return s-1; return 0; } /* Expand the selection (pp0-pp1) left and right, stopping * at characters that aren't alphanumeric or are in the stop list 's' */ Range text_expand(Text *t, Range r, char *s) { int c; Tgetcset(t, r.p1); while( (c = Tgetc(t)) !=-1 && okchar(c,s)) r.p1++; Tbgetcset(t, r.p0); while((c = Tbgetc(t)) != -1 && okchar(c,s)) r.p0--; return r; } /* * Expand a doubleclick at p0, return the resulting range. */ Range text_doubleclick(Text *t, ulong p0) { int c, i; Rune *r, *l; Range dot; if(p0 > t->length) return dot; dot.p0 = dot.p1 = p0; for(i=0; left[i]; i++){ l = left[i]; r = right[i]; /* try left match */ if(p0 == 0){ Tgetcset(t, p0); c = '\n'; }else{ Tgetcset(t, p0-1); c = Tgetc(t); } if(c!=-1 && strrune(l, c)){ if(clickmatch(t, c, r[strrune(l, c)-l], 1)){ dot.p0 = p0; dot.p1 = t->pos-(c!='\n'); } return dot; } /* try right match */ if(p0 == t->length){ Tbgetcset(t, p0); c = '\n'; }else{ Tbgetcset(t, p0+1); c = Tbgetc(t); } if(c !=-1 && strrune(r, c)){ if(clickmatch(t, c, l[strrune(r, c)-r], -1)){ dot.p0 = t->pos; if(c!='\n' || t->pos!=0 || (Tgetcset(t, 0),Tgetc(t))=='\n') dot.p0++; dot.p1 = p0+(p0length && c=='\n'); } return dot; } } /* try filling out word to right */ Tgetcset(t, p0); while((c=Tgetc(t))!=-1 && okchar(c, notdoubleclick)) dot.p1++; /* try filling out word to left */ Tbgetcset(t, p0); while((c=Tbgetc(t))!=-1 && okchar(c, notdoubleclick)) dot.p0--; return dot; } /* * Find start of word, going back from p0. */ ulong text_startofword(Text *t, ulong p0) { int c; Tbgetcset(t, p0); /* skip over special chars then skip until special char */ while ( (c=Tbgetc(t))!=-1 && c != '\n' && !okchar(c, notdoubleclick) ) ; if(c=='\n' && (t->pos != p0-1)) return t->pos + 1; while ( (c=Tbgetc(t))!=-1 && okchar(c, notdoubleclick) ) ; return t->pos + (c!=-1); } wily-0.13.41/wily/scroll.c100644 2743 200 5225 6332625223 13613 0ustar garypgrad/******************************************* * Display scroll_bars *******************************************/ #include "wily.h" static Bitmap *dkgrey_o, *dkgrey_e; struct Scroll { Rectangle r; Bitmap *b; ulong thumb, extent, max; }; static Rectangle getthumb(Scroll *, ulong , ulong , ulong ); /* Initialize bitmaps for scrollbars. Called once, on system entry. */ void scroll_init(void) { int x, y; int dx = 4, dy = 2; dkgrey_o = balloc(Rect(0, 0, dx, dy), 0); bitblt(dkgrey_o, dkgrey_o->r.min, dkgrey_o, dkgrey_o->r, F); for (x = 0; x < dx; x += 2) for (y = (x % 4) / 2; y < dy; y += 2) point(dkgrey_o, Pt(x, y), 0, Zero); dkgrey_e = balloc(Rect(0, 0, dx, dy), 0); bitblt(dkgrey_e, dkgrey_e->r.min, dkgrey_e, dkgrey_e->r, F); for (x = 1; x < dx; x += 2) for (y = (x % 4) / 2; y < dy; y += 2) point(dkgrey_e, Pt(x, y), 0, Zero); } void scroll_setrects(Scroll*s, Bitmap *b, Rectangle r) { if(!s) return; s->r = r; s->b = b; s->thumb = s->extent = s->max = 0; if(b) { bitblt(b, r.min, b, r, Zero); border(b, r, 1, F); } assert(Dx(s->r)<=SCROLLWIDTH); } Scroll * scroll_alloc(Bitmap *b, Rectangle r) { Scroll *s; s = NEW(Scroll); scroll_setrects(s,b,r); return s; } void scroll_set(Scroll *s, ulong thumb, ulong extent, ulong max) { Rectangle q, oldr, newr, above, below; oldr = getthumb(s, s->extent, s->max, s->thumb); above = below = s->r; above.max.y = oldr.min.y; below.min.y = oldr.max.y; newr = getthumb(s, extent, max, thumb); /* Sections that before were NOT in the thumb, but now are */ q = newr; if (rectclip(&q, above)) bitblt(s->b, q.min, s->b, q, Zero); q = newr; if (rectclip(&q, below)) bitblt(s->b, q.min, s->b, q, Zero); above = below = s->r; above.max.y = newr.min.y; below.min.y = newr.max.y; /* Sections that before WERE in the thumb, but now are NOT */ q = oldr; if (rectclip(&q, above)) { if (s->r.min.x % 2 == 0) texture(s->b, q, dkgrey_e, S); else texture(s->b, q, dkgrey_o, S); } q = oldr; if (rectclip(&q, below)) { if (s->r.min.x % 2 == 0) texture(s->b, q, dkgrey_e, S); else texture(s->b, q, dkgrey_o, S); } s->thumb = thumb; s->extent = extent; s->max = max; } static ulong div_down(ulong p, ulong q) { return p / q; } static ulong div_up(ulong p, ulong q) { return (p + q - 1) / q; } static Rectangle getthumb(Scroll *s, ulong extent, ulong max, ulong thumb) { Rectangle r; ulong length; r = inset(s->r, 1); assert (Dx(s->r)<= SCROLLWIDTH); length = Dy(r); if (extent < max) { r.min.y = r.min.y + div_down(length * thumb, max); if (thumb < max) { r.max.y = r.min.y + div_up(length * extent, max); } else r.min.y = r.max.y; } return r; } wily-0.13.41/wily/line.c100644 2743 200 4406 6332630437 13247 0ustar garypgrad/*********************************************************** * Functions to do with finding/counting lines. * * Currently Wily doesn't keep track of line boundaries, * and searches for them when it needs to. These functions * are all in the one file in case we ever decide to cache any * of this information. ***********************************************************/ #include "wily.h" #include "text.h" /* What line number is at Rune position p? */ int text_linenumber(Text *t, ulong p) { int c; int newlines=1; Tbgetcset(t, p); while ( (c=Tbgetc(t)) != -1) if( c == NEWLINE) newlines++; return newlines; } /* * If 't' has at least 'n' lines, fills 'r' with the range for line 'n', * and returns true. Otherwise, fills 'r' with gibberish and returns * false. */ Bool text_findline(Text *t, Range *r, ulong n) { Bool foundstart = false; int c; if (n==0) return false; else if (n==1) { foundstart = true; r->p0 = 0; } n--; Tgetcset(t,0); for( ; (c=Tgetc(t)) != -1; ) { if( c == NEWLINE ) { if (foundstart) break; else if (!--n) { r->p0 = t->pos; foundstart = true; } } } r->p1 = t->pos; return foundstart; } /* Return the range for the last line of 't' */ Range text_lastline(Text *t) { int c; Tbgetcset(t, t->length); while ( (c=Tbgetc(t)) != -1 && c != NEWLINE) ; return range(t->pos+1, t->length); } /* * Find the offset of the first character of the line 'delta' away from 'pos'. *'delta' may be positive or negative. * * text_nl(t, pos, 0): start of current line * text_nl(t, pos, -1): start of line above * text_nl(t, pos, 1): start of line below */ ulong text_nl(Text *t, ulong pos, int delta) { int c; ulong retval; assert(pos <= t->length); if(delta > 0) { Tgetcset(t, pos); while ( (c=Tgetc(t)) != -1 ) if(c==NEWLINE) if(!--delta) break; } else { Tbgetcset(t,pos); while ( (c=Tbgetc(t)) != -1 ) if(c==NEWLINE) if(!delta++) break; } retval = t->pos; if (!(retval == 0 || retval == t->length)) retval++; return retval; } /* Return the position of the first character of the line containing 'p' */ ulong text_startOfLine(Text *t, ulong p) { int c; Tbgetcset(t,p); do { c=Tbgetc(t); } while ( c != -1 && c != NEWLINE); return t->pos ? t->pos+1 : t->pos; } wily-0.13.41/wily/label.c100644 2743 200 3261 6332624526 13377 0ustar garypgrad/************************************************************* Various routines to do with a Data's label and/or path *************************************************************/ #include "wily.h" #include "data.h" static void data_restat(Data*d); #define DATALABEL(d) ((d)?(d)->label:wilydir) void data_addcontext(Data*d, char*dest, char*orig) { addcontext(dest, DATALABEL(d), orig); labelclean(dest); } /* Copy d's label (or wilydir) to 'dest' */ void data_getlabel(Data*d, char*dest){ strcpy(dest, DATALABEL(d)); } /* D's label has been changed to 's', * update our internal structures. */ void data_setlabel(Data*d, char *s) { assert(d); /* Just record the new label, only update * other stuff on demand. */ strcpy(d->label, s); if(STRSAME(d->label, d->cachedlabel)) { if(!data_isdirty(d)) { tag_rmtool(d->tag, "Put"); } } else { tag_addtool(d->tag, "Get"); tag_addtool(d->tag, "Put"); } } /* Return pointer to View with same 'label', or null. */ View * data_find(char*label) { Data *d; Stat buf; Path path; /* Search for data with same label */ for(d=dataroot; d; d=d->next) { if (STRSAME(d->label, label)) return text_view(d->t); } /* Search for data with same stat buffer */ label2path(path,label); if(stat(path,&buf)) return 0; for(d=dataroot; d; d=d->next) { data_restat(d); if (d->has_stat && !statcmp(&buf, &d->stat)) return text_view(d->t); } return 0; } /* If 'label' has changed under us, update * some other information. */ static void data_restat(Data*d) { if(strcmp(d->label, d->cachedlabel)) { Path path; strcpy(d->cachedlabel, d->label); label2path(path, d->label); d->has_stat = !stat(path, &d->stat); } } wily-0.13.41/wily/undo.c100644 2743 200 15355 6332624650 13312 0ustar garypgrad/******************************************* * Maintain Undo chains, Undo methods *******************************************/ #include "wily.h" #include "text.h" /* We currently manage our Undo chain as a linked list, * and separately alloc small buffers every time. * If we cared about efficiency, we'd make all the u->s * entries share bigger chunks of Runes. * * For now, it doesn't seem to be a problem, and simpler * is better. */ struct Undo { Undo *next; Range r; /* where to replace */ Rstring s; /* what to replace with */ ulong alloced; /* bytes alloced at s.p0 */ }; static Bool undoing = false; /* prevent recording undo ops */ static Range illegal_range = {10,1}; static Undo * reverse (Text*, Range, Rstring); static Bool append (Text*, Range r, Rstring s); static void reset (Undo**); static void save_state (Text *); static void update_state (Text *); static Range shift (Text *, Undo **, Undo **, Bool ); static void text_rmtool(Text*t, char*s) { if(t->data) tag_rmtool(data_tag(t->data), s); } static void text_addtool(Text*t, char*s) { tag_addtool(data_tag(t->data), s); } /* Record information allowing us to undo the replacement of * 'r' in 't' with 's'. This replacement hasn't happened yet. */ void undo_record (Text *t, Range r, Rstring s) { Undo *u; assert(ROK(r)); assert(RSOK(s)); assert(r.p1 <= t->length); if(undoing || t->undoing == NoUndo) return; save_state(t); if(!append(t, r, s)) { /* remove old t->undone trail */ reset(&t->undone); u = reverse(t, r, s); u->next = t->did; t->did = u; } t->undoing = MoreUndo; update_state(t); } /* Undo the top operation in the undo stack, and move it to the redo * stack. Keep going to mark if appropriate. * Return the range that was inserted. */ Range undo_undo(Text *t, Bool all) { Range r; if (!t->did) return illegal_range; save_state(t); do { r = shift(t, &t->did, &t->undone, true); } while (all && t->did && t->did != t->mark); update_state(t); return (all ? illegal_range : r); } /* The mirror of undo_undo */ Range undo_redo(Text *t, Bool all) { Range r; Undo *tmp; save_state(t); tmp = t->did; t->did = t->undone; t->undone = tmp; r = undo_undo(t, all); tmp = t->did; t->did = t->undone; t->undone = tmp; update_state(t); return r; } /* Throw away all the undo information. */ void undo_free(Text*t) { reset(&t->did); reset(&t->undone); } /* Throw away all the undo information, leave in NoUndo state. */ void undo_reset(Text*t) { undo_free(t); t->undoing = NoUndo; text_rmtool(t, "Put"); text_rmtool(t, "Undo"); text_rmtool(t, "Redo"); } /* Start undoing on this Text. */ void undo_start(Text*t) { t->undoing = StartUndo; } /* * Make sure we don't merge whatever's currently on top of the undo * stack with the next operation. */ void undo_break(Text*t) { if(t->undoing==MoreUndo) t->undoing = StartUndo; } /* Remember this point in the Undo history * for future reference. */ void undo_mark(Text*t) { t->mark = t->did; t->undoing = StartUndo; } /* Are we at the same point in the history as we marked earlier? */ Bool undo_atmark(Text*t) { return t->mark == t->did; } /********************************************************* INTERNAL STUFF *********************************************************/ static void tag (Text *, Bool , Bool , char *); static Bool undo_eq(Undo*u, Range r, Rstring s); /* * We are about to replace the text at 'r' with 's'. If we can record * the undo information for this by modifying t->undo, and/or t->undone, * do so, and return true. Otherwise, return false. */ static Bool append(Text *t, Range r, Rstring s) { Undo *u; Rune *buf; int rlen, slen; if (undo_eq(t->did, r, s)) { /* * What we're about to do is exactly what would happen by * an Undo operation. Therefore, we just move the front of * the undo queue to the front of the redo queue. */ save_state(t); shift(t, &t->did, &t->undone, false); update_state(t); return true; } if (!(t->did && t->undoing==MoreUndo && t->did != t->mark)) return false; u = t->did; if(u->r.p1 == r.p0 && RLEN(r)==0 && RSLEN(u->s)==0) { u->r.p1 += RSLEN(s); return true; } if (RLEN(u->r)==0 && RSLEN(s)==0 && u->r.p0 == r.p1) { slen = RSLEN(u->s); rlen = RLEN(r); buf = salloc ( (slen + rlen) * sizeof(Rune) ); text_copy( t, r, buf); memcpy(buf + rlen, u->s.r0, slen*sizeof(Rune)); free(u->s.r0); u->s.r0 = buf; u->s.r1 = buf + slen + rlen; u->r.p0 = u->r.p1 = r.p0; return true; } return false; } /* Free all the nodes in the list, set the head of the list to 0.*/ static void reset(Undo**head) { Undo *u, *next; for(u = *head; u; u = next){ next = u->next; free(u->s.r0); free(u); } *head = 0; } /* * We use save_state() and update_state() to compare our undo state * before and after operations. These two functions use 'did' and * 'undone' */ static Undo *did, *undone; static Bool state_count = 0; static void save_state(Text *t) { if(state_count++) return; did = t->did; undone = t->undone; } static void update_state(Text *t) { if(--state_count) return; if(t->needsbackup) { tag(t, (Bool)did, (Bool)t->did, "Undo"); tag(t, (Bool)undone, (Bool)t->undone, "Redo"); tag(t, t->did == t->mark, did==t->mark, "Put"); } } /* * If 'change_text', do the replacement at 'from'. * * Reverse the top of 'from', add it to 'to'. * * Returns the range of any text inserted, or gibberish if !change_text */ static Range shift(Text *t, Undo **from, Undo **to, Bool change_text) { Range r; Undo *u; Undo *rev; u = *from; assert(u); *from = u->next; rev = reverse(t, u->r, u->s); if(change_text){ undoing=true; r = text_replace(t, u->r, u->s); undoing = false; } free(u->s.r0); free(u); rev->next = *to; *to = rev; return r; } /*If the state has changed to (true/false), (add/remove) 's' * in all the tags associated with 't' */ static void tag(Text *t, Bool before, Bool after, char *s) { if(before!=after) (after? text_addtool : text_rmtool)(t,s); } /* * Compare two rune strings. Return a number >0, <0 or 0 to indicate if * s1 is lexically after, before or equal to s2 */ int rstrcmp(Rstring s1, Rstring s2) { Rune *p1, *p2; int diff; for ( p1=s1.r0, p2 = s2.r0; p1r.p0 && r.p1 == u->r.p1 && !rstrcmp(u->s, s); } /* Return undo entry to undo the replacement of 'r' in 't' with 's' */ static Undo * reverse(Text*t, Range r, Rstring s) { Undo *u; u = NEW(Undo); u->r.p0 = r.p0; u->r.p1 = r.p0 + RSLEN(s); u->alloced = RLEN(r); u->s.r0 = (Rune*)salloc(u->alloced*sizeof(Rune)); text_copy(t, r, u->s.r0); u->s.r1 = u->s.r0 + RLEN(r); return u; } wily-0.13.41/wily/textpage.c100644 2743 200 7236 6352447723 14153 0ustar garypgradenum { PAGESIZE = BUFSIZE; } struct TextPage { TextPage *next, *prev; Rune *buf; /* Points to PAGESIZE bytes */ Range gap; int nrunes; /* active bytes in this page */ ulong base; Bool isLineCountValid; int LineCount; } /* Read the contents of 't' from 'fd', which should have 'len' bytes. * Return 0 for success, -1 for failure */ int text_read(Text *t, int fd, int len) { int desired, nread; char buf[RUNES_PER_PAGE]; extern int utftotext_unconverted; int offset; TextPage *page; text_clear(t); while(len > 0) { desired = MIN(len, sizeof(buf) - leftover); nread = read(fd, buf + leftover, desired); if(nread<=0) return -1; len -= nread; total = leftover + nread; page = text_appendPage(t, buf, total, &leftover); if (leftover ) { memcpy(buf, buf + nconverted, leftover); } } if (leftover) { warn("incomplete runes"); } } text_appendPage(Text*t, char*buf, int total, int*leftover) { Page* p = newPage(); /* Make sure we can fit all these bytes on one page */ assert(total <= RUNES_PER_PAGE); p->nrunes = utftotext(p->buf, buf, total); *leftover = utftotext_unconverted; p->gap.p0 = p->nrunes; p->gap.p1 = RUNES_PER_PAGE; if(t->tail) { t->tail->next = p; p->prev = t->tail; } else { t->tail = t->head = p; } } Page* newPage() { Page*p = oalloc(sizeof(Page)); p->buf = pagealloc(); p->gap = Range( return p; } int text_write_range(Text*t, Range r, int fd) { Page *p; for (p = firstInRange(t,r); p && page_contains(p,r); p= p->next) page_writeRange(p,r,fd); } } void text_copy(Text*t, Range r, Rune*buf) { Page *p; for (p = firstInRange(t,r); p && page_contains(p,r); p= p->next) buf = page_copy(p, r, buf); } /* Replace data in range 'r' of 't' with 's'. Update displays. * Return the range of the inserted text. */ Range text_replace(Text *t, Range r, Rstring s){ Page*p; for(p = t->head; p; p = p->next) if (p->base + p->len > r.p0) break; if(!p) { } if(p->len + RSLEN(s) - RLEN(r) <= RUNES_PER_PAGE) { } if(RLEN(r)) text_delete(t,r); text_updatePages(t); if(RSLEN(s)) text_insert(t, r.p0, s); text_updatePages(t); } void text_updatePages(Text*t) { Page*p; ulong base = 0; for(p = t->head; p; p=p->next){ p->base = base; base += p->nrunes; } } void text_delete(Text*t, Range r) { Page *p, *next; p = firstInRange(t,r); while(p && page_contains(p,r)){ if (page_containedIn(p,r)) { next = p->next; text_rmpage(t,p); p = next; } else { page_delete(p,r); p = p->next; } } } void text_insert(Text*t, ulong p, Rstring s){ } /** Is 'p' contained completely in 'r'? **/ Bool page_containedIn(Page*p, Range r) { } /** Completely remove 'p' from 't' **/ void text_rmpage(Text*t, Page *p) { } /** Delete 'r' from 'p' **/ void page_delete(Page*p, Range r) { /* move and extend p's gap */ } /** Returns first Page in 't' which contains 'r', (or returns 0) **/ Page* firstInRange(Text*t, Range r){ Page *p; for(p = t->head; p ; p = p->next) if (page_contains(p,r)) break; return p; } Boolean page_contains(Page*p, Range r) { ulong start,end; start = p->base; end = p->base + nrunes; /* contains r.p0 or contains r.p1 */ return !(r.p0>=end || r.p1