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 }