commit - efc2b0c99e1a4f9d2be9e72785d566df903c66fb
commit + af78a4cd2b73800af86db8d999d80b1ef0e9bd75
blob - 7b1f73098d4880371ec4348f5a6c3277730c6370
blob + 7c6955065b2208d48858269988a4518fd806bc1b
--- NOTES
+++ NOTES
This is a port of some Plan 9 libraries and programs to Unix.
-Some parts expect that the tree is installed in /usr/local/plan9.
-Most are position independent. The few hard-coded references
-(there's one in sam) should really be fixed.
-
* Obtaining the source
Tarballs will be posted nightly (but only when there are updates!) at
* Building
-To build, cd into src and run make; mk install. This will place binaries
-in "bin". At time of writing, the commands are sam, samterm, rc, and mk.
+First, you need to extract the tarball or check out the CVS tree
+(see below for CVS). You should be able to install the tree anywhere
+-- tools check the environment variable $PLAN9 for the root of the
+tree. Most of them assume /usr/local/plan9 if $PLAN9 is not set.
+
+To build and install, cd into the plan9/ directory and run "./INSTALL".
+This will first build "mk" and then use mk to build the rest of the
+system, installing libraries in plan9/lib/ and binaries in plan9/bin/.
There are a few shell scripts already included in bin -- B, Bwait,
-and samsave.
+and samsave. Arguably these directories should be broken up by
+architecture so that
-The "make" builds mk. Mk builds the rest.
+* Writing programs
+The bin/ directory contains shell scripts 9a, 9c, 9l, and 9ar that mimic
+the Plan 9 tools pretty well, except in the object names: "9c x.c" produces
+x.o not x.9, and "9l x.o" produces "a.out" not "9.out" or "o.out".
+
+Mkfiles look substantially the same as in Plan 9, with slightly different
+names for the included rules. The most significant
+difference is that, since there is no autolinker, the Plan 9 libraries
+needed must be named explicitly. The variable SHORTLIBS can
+be used to list them without giving paths, e.g.:
+
+ SHORTLIBS=thread bio 9
+
+The default is "SHORTLIBS=9". (Libc is known as lib9; libregexp is
+known as libregexp9; the rest of the libraries retain their usual names.)
+
+Various function names (like open, accept, dup, malloc) are #defined in
+order to provide routines that mimic the Plan 9 interface better
+(for example, open handles the OCEXEC flag). Lib9.h contains these
+definitions. Function "foo" is #defined to "p9foo". These definitions
+can cause problems in the rare case that other Unix headers are needed
+as well. To avoid this, #define NOPLAN9DEFINES before including lib9.h,
+and then add the p9 prefix yourself for the renamed functions you wish to use.
+
+* 9P servers and "name spaces"
+
+A few Plan 9 programs, notably the plumber and acme, are heavily
+dependent on the use of 9P to interact with other programs. Rather
+than rewrite them, they have been left alone. Via the helper program 9pserve,
+they post a Unix domain socket with a well-known name (for example,
+"acme" or "plumb") in the directory /tmp/ns.$USER.$DISPLAY.
+Clients connect to that socket and interact via 9P. 9pserve takes
+care of muxing the various clients of that socket onto a single 9P
+conversation with the actual server, just like the kernel does on Plan 9.
+
+The choice of "namespace" directory is meant to provide a different
+name space for each X11 session a user has. The environment variable
+$NAMESPACE overrides this. The command "namespace" prints the
+current name space directory.
+
+In order to run normal Unix commands with their input or output
+connected to a 9P server, there is a new 9P request "openfd" whose
+response contains a real Unix file descriptor. 9pserve handles
+this request by sending a normal open to the real 9P server and
+sending back one side of a pipe. Then 9pserver forks a thread to
+ferry bytes back and forth between its end of the pipe and the 9P
+conversation. This works reasonably well, but has the drawback
+that reads are no longer "demand-driven" (the ferry thread issues
+the reads and fills the pipe regardless of whether the other end
+of the pipe is being read) and writes cannot return errors (writes
+to the pipe by the application will always succeed even though the
+write in the ferry thread might actually draw an interesting error).
+This doesn't cause too many problems in practice, but is worth
+keeping in mind.
+
+The command "9p" interacts with a given server to read or write
+a particular file. Run "9p" for a usage message.
+
+* Plumbing
+
+There is a plumber. It expects to find a plumbing rule file in
+$HOME/lib/plumbing. $PLAN9/plumb/initial.plumbing is a
+good start.
+
+Sam and acme interact with the plumber as they do on Plan 9.
+(If there is no plumber, sam falls back to a named pipe
+as it always has on Unix.) Unlike on Plan 9, there is a "web"
+command whose purpose is to load files or URLs in a running
+web browser. Right now, only Mozilla Firebird and Opera are
+supported, but it should be easy to add others to the script.
+The plumbing rules in $PLAN9/plumb/basic know to run "web"
+to handle URLs.
+
+Because sam and acme read from the plumber using file descriptors
+(and therefore the openfd hack described above), if the editor exits,
+this fact is not noted until the ferry thread tries to write the next
+plumbing message to the pipe. At this point the ferry thread closes
+the corresponding plumber fid, but the plumber thinks the message
+has been sent -- the message is lost. The message did serve a purpose --
+now the plumber knows there are no readers of the "edit" channel,
+so when it gets the next message it will start a new editor.
+This situation doesn't happen often, but it is worth keeping in mind.
+
+Both acme and sam try to raise themselves when they get plumbing
+messages.
+
+* Acme
+
+Acme works.
+
+Programs executed with the middle button interact with acme by the
+"openfd" trick described above. In a plain execution (as opposed
+to >prog or |prog), because of the delay introduced by the pipes,
+there is no guarantee that the command output will finish being
+displayed before the exit status notice is displayed. This can be
+annoying.
+
+There is a "win" shell. Of course, since we're on Unix, win can't
+tell when programs are reading from the tty, so proper input point
+management is right out the window.
+
* Helping out
If you'd like to help out, great!
-The TODO file contains our (somewhat long) to do list.
+The TODO file contains a small list.
If you port this code to other architectures, please share your changes
so others can benefit. See PORTING for some notes.
blob - e09311a659bc301decc38657be1883fa5d5f6032
blob + 7ca8745fa4b87cb779d566edf0eeeb5ff8e220c1
--- TODO
+++ TODO
- bug with discovery of initial window size in certain cases
(reported by Sean Dorward)
-* Plumber
- - have named-pipe-based plumber from Caerwyn Jones
- - 9term right-click plumbs
- - plumb rules file runs B
- - easy to hook up web browser:
-
-# urls to web browser
-type is text
-data matches '(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=]+([:.][a-zA-Z0-9_?,%#~&/\-+=]+)*'
-plumb to web
-plumb start /usr/rsc/bin/web $0
-
- - want to change back to 9P-based plumber, need to build
- infrastructure first
-
-* Acme
- - with 9P infrastructure, should "just work".
-
* upas/fs+Mail
- with 9P infrastructure, should "just work".
blob - /dev/null
blob + 39615200bd24795c643ea3a347442900ef99c567 (mode 755)
--- /dev/null
+++ bin/web
+#!/bin/sh
+
+plumb1()
+{
+ case $BROWSER in
+ # Other browsers here
+ # ...
+ *opera*)
+ $BROWSER -remote 'openURL('$i', new-page)'
+ ;;
+ *firebird*)
+ $BROWSER -remote 'openURL('$i', new-window)'
+ ;;
+ esac
+}
+
+if [ $# = 0 ]
+then
+ plumb1 about:blank
+else
+ for i
+ do
+ if [ -f "$i" ]
+ then
+ i=file://`pwd`/$i
+ fi
+ plumb1 $i
+ done
+fi
+
+case $BROWSER in
+*opera*)
+ $BROWSER -remote 'raise()'
+esac
+
blob - 918cc51b12f20057a0e9fc5d864ed3eb0217c8bd
blob + 23fd7adcac1c35c9faae3d44d39c2db45d6a0d82
--- plumb/basic
+++ plumb/basic
arg isfile $data
plumb start gv $data
-type is text
-data matches 'Local (.*)'
-plumb to none
-plumb start rc -c $1
+# urls to internet explorer on another machine
+type is text
+data matches '(https?|ftp|file|gopher|mailto|news|nntp|telnet|wais|prospero)://[a-zA-Z0-9_@\-]+([.:][a-zA-Z0-9_@\-]+)*/?[a-zA-Z0-9_?,%#~&/\-+=@]+([:.][@a-zA-Z0-9_?,%#~&/\-+=]+)*'
+plumb to web
+plumb start /usr/rsc/bin/web $0
+# plumb start winstart iexplore -new $0
+
blob - cfee0013b4a7b8b9bca1152733fb20d01d380ed2
blob + 41a0a2f7c168a7ff8316e9626766bcb8e8189cb6
--- src/cmd/9term/9term.c
+++ src/cmd/9term/9term.c
i = 0;
for(;;){
i = 1-i; /* toggle */
- n = read(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
+ n = threadread(rcfd[0], rcbuf[i].data, sizeof rcbuf[i].data);
if(n <= 0){
if(n < 0)
fprint(2, "9term: host read error: %r\n");
hoststart(void)
{
hostc = chancreate(sizeof(int), 0);
- proccreate(hostproc, hostc, 32*1024);
+ threadcreate(hostproc, hostc, 32*1024);
}
void
blob - ca7eba424903b06e6a50574a028838efc5c2f241
blob + 6b2592883429f687f6eaaca88721ddc53cb15da2
--- src/cmd/acme/look.c
+++ src/cmd/acme/look.c
openfile(nil, &e);
free(e.name);
free(e.u.at);
+ drawtopwindow();
}
void
winsettag(w);
textscrdraw(&w->body);
textsetselect(&w->tag, w->tag.file->b.nc, w->tag.file->b.nc);
+ drawtopwindow();
}
int
blob - 0bffad3d736f24f73c9833132cdf4d6b82ea28c7
blob + 2052843178e152eded81f007ba8739be92fea78c
--- src/cmd/samterm/mesg.c
+++ src/cmd/samterm/mesg.c
void hsetdot(int, long, long);
void hmoveto(int, long);
void hsetsnarf(int);
-/* void hplumb(int); */
+void hplumb(int);
void clrlock(void);
int snarfswap(char*, int, char**);
threadexitsall(nil);
break;
-/*
case Hplumb:
hplumb(m);
break;
-*/
}
}
setcursor(mousectl, cursor);
}
-/*
void
hplumb(int nc)
{
}
free(s);
}
-*/
void
hgrow(int m, long a, long new, int req)
blob - 67997f399810e74d249eb9de12326bd5d0c676c4
blob + facc78d2ee0236bbe30f949a5365a1222c4bdf9b
--- src/cmd/samterm/mkfile
+++ src/cmd/samterm/mkfile
CFLAGS=$CFLAGS -I../sam
LDFLAGS=$LDFLAGS -L$X11/lib -lX11 -lm
-SHORTLIB=frame draw thread regexp9 bio 9
+SHORTLIB=frame draw plumb fs mux thread regexp9 bio 9
<$PLAN9/src/mkone
blob - 60ef5c0ec33d61fd29aeb7e1eaf2abec34c87e99
blob + 7c4ed39b86faba29c867d48a6837407cdf9435d7
--- src/cmd/samterm/plan9.c
+++ src/cmd/samterm/plan9.c
#include <cursor.h>
#include <keyboard.h>
#include <frame.h>
+#include <plumb.h>
#include "flayer.h"
#include "samterm.h"
atexit(removeextern);
}
-#if 0
int
-plumbformat(int i)
+plumbformat(Plumbmsg *m, int i)
{
- Plumbmsg *m;
char *addr, *data, *act;
int n;
data = (char*)plumbbuf[i].data;
- m = plumbunpack(data, plumbbuf[i].n);
- if(m == nil)
- return 0;
n = m->ndata;
- if(n == 0){
+ if(n == 0 || 2+n+2 >= READBUFSIZE){
plumbfree(m);
return 0;
}
plumbproc(void *argv)
{
Channel *c;
- int i, n, which, *fdp;
+ int i, *fdp;
void **arg;
+ Plumbmsg *m;
arg = argv;
c = arg[0];
i = 0;
threadfdnoblock(*fdp);
for(;;){
- i = 1-i; /* toggle */
- n = threadread(*fdp, plumbbuf[i].data, READBUFSIZE);
- if(n <= 0){
+ m = threadplumbrecv(*fdp);
+ if(m == nil){
fprint(2, "samterm: plumb read error: %r\n");
threadexits("plumb"); /* not a fatal error */
}
- plumbbuf[i].n = n;
- if(plumbformat(i)){
- which = i;
- send(c, &which);
+ if(plumbformat(m, i)){
+ send(c, &i);
+ i = 1-i; /* toggle */
}
}
}
close(fd);
return -1;
}
- arg[0] =plumbc;
+ arg[0] = plumbc;
arg[1] = &fd;
threadcreate(plumbproc, arg, STACK);
return 1;
}
-#endif
-int
-plumbstart(void)
-{
- return -1;
-}
-
void
hostproc(void *arg)
{
blob - fb6a91449fbfb31e090eb0b1dfd2eda2d6dac777
blob + 1283f430f09ef8b88ea7845511598eeb88f288d4
--- src/libdraw/x11-init.c
+++ src/libdraw/x11-init.c
{
char buf[200];
+ if(e->request_code == 42) /* XSetInputFocus */
+ return 0;
print("X error: error_code=%d, request_code=%d, minor=%d disp=%p\n",
e->error_code, e->request_code, e->minor_code, d);
XGetErrorText(d, e->error_code, buf, sizeof buf);
blob - ac4aa40c5021c75e2150273603d00b6cf7fac716
blob + e27202f544b48e934cb16249117bc3a2bd90c138
--- src/libdraw/x11-wsys.c
+++ src/libdraw/x11-wsys.c
void
drawtopwindow(void)
{
- XRaiseWindow(_x.display, _x.drawable);
+ XMapRaised(_x.display, _x.drawable);
XFlush(_x.display);
+ XSetInputFocus(_x.display, _x.drawable, RevertToPointerRoot,
+ CurrentTime);
+ XFlush(_x.display);
}