plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

plan9.c (5463B)


      1 #include <u.h>
      2 #include <sys/types.h>
      3 #include <sys/stat.h>
      4 #include <errno.h>
      5 
      6 #include <u.h>
      7 #include <libc.h>
      8 #include <draw.h>
      9 #include <thread.h>
     10 #include <mouse.h>
     11 #include <cursor.h>
     12 #include <keyboard.h>
     13 #include <frame.h>
     14 #define Tversion Tversion9p
     15 #define Twrite Twrite9p
     16 #include <fcall.h>
     17 #undef Tversion
     18 #undef Twrite
     19 #include <9pclient.h>
     20 #include <plumb.h>
     21 #include "flayer.h"
     22 #include "samterm.h"
     23 
     24 static char *exname;
     25 
     26 #define STACK 16384
     27 
     28 void
     29 usage(void)
     30 {
     31 	fprint(2, "usage: samterm -a -W winsize\n");
     32 	threadexitsall("usage");
     33 }
     34 
     35 void
     36 getscreen(int argc, char **argv)
     37 {
     38 	char *t;
     39 
     40 	ARGBEGIN{
     41 	case 'a':
     42 		autoindent = 1;
     43 		break;
     44 	case 'W':
     45 		winsize = EARGF(usage());
     46 		break;
     47 	default:
     48 		usage();
     49 	}ARGEND
     50 
     51 	if(initdraw(panic1, nil, "sam") < 0){
     52 		fprint(2, "samterm: initdraw: %r\n");
     53 		threadexitsall("init");
     54 	}
     55 	t = getenv("tabstop");
     56 	if(t != nil){
     57 		maxtab = strtoul(t, nil, 0);
     58 		free(t);
     59 	}
     60 	draw(screen, screen->clipr, display->white, nil, ZP);
     61 }
     62 
     63 int
     64 screensize(int *w, int *h)
     65 {
     66 	int fd, n;
     67 	char buf[5*12+1];
     68 
     69 	fd = open("/dev/screen", OREAD);
     70 	if(fd < 0)
     71 		return 0;
     72 	n = read(fd, buf, sizeof(buf)-1);
     73 	close(fd);
     74 	if (n != sizeof(buf)-1)
     75 		return 0;
     76 	buf[n] = 0;
     77 	if (h) {
     78 		*h = atoi(buf+4*12)-atoi(buf+2*12);
     79 		if (*h < 0)
     80 			return 0;
     81 	}
     82 	if (w) {
     83 		*w = atoi(buf+3*12)-atoi(buf+1*12);
     84 		if (*w < 0)
     85 			return 0;
     86 	}
     87 	return 1;
     88 }
     89 
     90 int
     91 snarfswap(char *fromsam, int nc, char **tosam)
     92 {
     93 	char *s;
     94 
     95 	s = getsnarf();
     96 	putsnarf(fromsam);
     97 	*tosam = s;
     98 	return s ? strlen(s) : 0;
     99 }
    100 
    101 void
    102 dumperrmsg(int count, int type, int count0, int c)
    103 {
    104 	fprint(2, "samterm: host mesg: count %d %ux %ux %ux %s...ignored\n",
    105 		count, type, count0, c, rcvstring());
    106 }
    107 
    108 void
    109 removeextern(void)
    110 {
    111 	remove(exname);
    112 }
    113 
    114 Readbuf	hostbuf[2];
    115 Readbuf	plumbbuf[2];
    116 
    117 void
    118 extproc(void *argv)
    119 {
    120 	Channel *c;
    121 	int i, n, which, fd;
    122 	void **arg;
    123 
    124 	arg = argv;
    125 	c = arg[0];
    126 	fd = (int)(uintptr)arg[1];
    127 
    128 	i = 0;
    129 	for(;;){
    130 		i = 1-i;	/* toggle */
    131 		n = read(fd, plumbbuf[i].data, sizeof plumbbuf[i].data);
    132 if(0) fprint(2, "ext %d\n", n);
    133 		if(n <= 0){
    134 			fprint(2, "samterm: extern read error: %r\n");
    135 			threadexits("extern");	/* not a fatal error */
    136 		}
    137 		plumbbuf[i].n = n;
    138 		which = i;
    139 		send(c, &which);
    140 	}
    141 }
    142 
    143 void
    144 extstart(void)
    145 {
    146 	char *user, *disp;
    147 	int fd, flags;
    148 	static void *arg[2];
    149 
    150 	user = getenv("USER");
    151 	if(user == nil)
    152 		return;
    153 	disp = getenv("DISPLAY");
    154 	if(disp){
    155 		exname = smprint("/tmp/.sam.%s.%s", user, disp);
    156 		free(disp);
    157 	}
    158 	else
    159 		exname = smprint("/tmp/.sam.%s", user);
    160 	free(user);
    161 	if(exname == nil){
    162 		fprint(2, "not posting for B: out of memory\n");
    163 		return;
    164 	}
    165 
    166 	if(mkfifo(exname, 0600) < 0){
    167 		struct stat st;
    168 		if(errno != EEXIST || stat(exname, &st) < 0)
    169 			return;
    170 		if(!S_ISFIFO(st.st_mode)){
    171 			removeextern();
    172 			if(mkfifo(exname, 0600) < 0)
    173 				return;
    174 		}
    175 	}
    176 
    177 	fd = open(exname, OREAD|ONONBLOCK);
    178 	if(fd == -1){
    179 		removeextern();
    180 		return;
    181 	}
    182 
    183 	/*
    184 	 * Turn off no-delay and provide ourselves as a lingering
    185 	 * writer so as not to get end of file on read.
    186 	 */
    187 	flags = fcntl(fd, F_GETFL, 0);
    188 	if(flags<0 || fcntl(fd, F_SETFL, flags&~O_NONBLOCK)<0
    189 	||open(exname, OWRITE) < 0){
    190 		close(fd);
    191 		removeextern();
    192 		return;
    193 	}
    194 
    195 	plumbc = chancreate(sizeof(int), 0);
    196 	chansetname(plumbc, "plumbc");
    197 	arg[0] = plumbc;
    198 	arg[1] = (void*)(uintptr)fd;
    199 	proccreate(extproc, arg, STACK);
    200 	atexit(removeextern);
    201 }
    202 
    203 int
    204 plumbformat(Plumbmsg *m, int i)
    205 {
    206 	char *addr, *data, *act;
    207 	int n;
    208 
    209 	data = (char*)plumbbuf[i].data;
    210 	n = m->ndata;
    211 	if(n == 0 || 2+n+2 >= READBUFSIZE){
    212 		plumbfree(m);
    213 		return 0;
    214 	}
    215 	act = plumblookup(m->attr, "action");
    216 	if(act!=nil && strcmp(act, "showfile")!=0){
    217 		/* can't handle other cases yet */
    218 		plumbfree(m);
    219 		return 0;
    220 	}
    221 	addr = plumblookup(m->attr, "addr");
    222 	if(addr){
    223 		if(addr[0] == '\0')
    224 			addr = nil;
    225 		else
    226 			addr = strdup(addr);	/* copy to safe storage; we'll overwrite data */
    227 	}
    228 	memmove(data, "B ", 2);	/* we know there's enough room for this */
    229 	memmove(data+2, m->data, n);
    230 	n += 2;
    231 	if(data[n-1] != '\n')
    232 		data[n++] = '\n';
    233 	if(addr != nil){
    234 		if(n+strlen(addr)+1+1 <= READBUFSIZE)
    235 			n += sprint(data+n, "%s\n", addr);
    236 		free(addr);
    237 	}
    238 	plumbbuf[i].n = n;
    239 	plumbfree(m);
    240 	return 1;
    241 }
    242 
    243 void
    244 plumbproc(void *arg)
    245 {
    246 	CFid *fid;
    247 	int i;
    248 	Plumbmsg *m;
    249 
    250 	fid = arg;
    251 	i = 0;
    252 	for(;;){
    253 		m = plumbrecvfid(fid);
    254 		if(m == nil){
    255 			fprint(2, "samterm: plumb read error: %r\n");
    256 			threadexits("plumb");	/* not a fatal error */
    257 		}
    258 		if(plumbformat(m, i)){
    259 			send(plumbc, &i);
    260 			i = 1-i;	/* toggle */
    261 		}
    262 	}
    263 }
    264 
    265 int
    266 plumbstart(void)
    267 {
    268 	CFid *fid;
    269 
    270 	plumbfd = plumbopen("send", OWRITE|OCEXEC);	/* not open is ok */
    271 	fid = plumbopenfid("edit", OREAD|OCEXEC);
    272 	if(fid == nil)
    273 		return -1;
    274 	plumbc = chancreate(sizeof(int), 0);
    275 	chansetname(plumbc, "plumbc");
    276 	if(plumbc == nil){
    277 		fsclose(fid);
    278 		return -1;
    279 	}
    280 	threadcreate(plumbproc, fid, STACK);
    281 	return 1;
    282 }
    283 
    284 void
    285 hostproc(void *arg)
    286 {
    287 	Channel *c;
    288 	int i, n, which;
    289 
    290 	c = arg;
    291 
    292 	i = 0;
    293 	for(;;){
    294 		i = 1-i;	/* toggle */
    295 		n = read(hostfd[0], hostbuf[i].data, sizeof hostbuf[i].data);
    296 if(0) fprint(2, "hostproc %d\n", n);
    297 		if(n <= 0){
    298 			if(n == 0){
    299 				if(exiting)
    300 					threadexits(nil);
    301 				werrstr("unexpected eof");
    302 			}
    303 			fprint(2, "samterm: host read error: %r\n");
    304 			threadexitsall("host");
    305 		}
    306 		hostbuf[i].n = n;
    307 		which = i;
    308 if(0) fprint(2, "hostproc send %d\n", which);
    309 		send(c, &which);
    310 	}
    311 }
    312 
    313 void
    314 hoststart(void)
    315 {
    316 	hostc = chancreate(sizeof(int), 0);
    317 	chansetname(hostc, "hostc");
    318 	proccreate(hostproc, hostc, STACK);
    319 }