1 | |
---|
2 | /* |
---|
3 | * wmh.c -- window front-end to nmh |
---|
4 | * |
---|
5 | * $Id: wmh.c,v 1.1.1.1 1999-02-07 18:14:18 danw Exp $ |
---|
6 | */ |
---|
7 | |
---|
8 | /* |
---|
9 | * TODO: |
---|
10 | * Pass signals to client during execution |
---|
11 | * |
---|
12 | * Figure out a way for the user to say how big the Scan/Display |
---|
13 | * windows should be, and where all the windows should be. |
---|
14 | */ |
---|
15 | |
---|
16 | #include <h/mh.h> |
---|
17 | #include <h/signals.h> |
---|
18 | #include <h/vmhsbr.h> |
---|
19 | #include <errno.h> |
---|
20 | #include <setjmp.h> |
---|
21 | #include <signal.h> |
---|
22 | |
---|
23 | #include <sys/uio.h> |
---|
24 | #include <vt.h> |
---|
25 | #include <bitmap.h> |
---|
26 | #include <tools.h> |
---|
27 | |
---|
28 | #define ALARM ((unsigned int) 10) |
---|
29 | #define PAUSE ((unsigned int) 2) |
---|
30 | |
---|
31 | #define SZ(a) (sizeof a / sizeof a[0]) |
---|
32 | |
---|
33 | static struct swit switches[] = { |
---|
34 | #define PRMPTSW 0 |
---|
35 | { "prompt string", 6 }, |
---|
36 | #define PROGSW 1 |
---|
37 | { "vmhproc program", 7 }, |
---|
38 | #define NPROGSW 2 |
---|
39 | { "novmhproc", 9 }, |
---|
40 | #define VERSIONSW 3 |
---|
41 | { "version", 0 }, |
---|
42 | #define HELPSW 4 |
---|
43 | { "help", 4 }, |
---|
44 | { NULL, NULL } |
---|
45 | }; |
---|
46 | /* PEERS */ |
---|
47 | static int PEERpid = NOTOK; |
---|
48 | |
---|
49 | static jmp_buf PEERctx; |
---|
50 | |
---|
51 | |
---|
52 | /* WINDOWS */ |
---|
53 | static int dfd = NOTOK; |
---|
54 | static int twd = NOTOK; |
---|
55 | static char *myprompt = "(%s) "; |
---|
56 | |
---|
57 | struct line { |
---|
58 | int l_no; |
---|
59 | char *l_buf; |
---|
60 | struct line *l_prev; |
---|
61 | struct line *l_next; |
---|
62 | }; |
---|
63 | |
---|
64 | #define W_NULL 0x00 |
---|
65 | #define W_CMND 0x01 |
---|
66 | #define W_FAKE 0x02 |
---|
67 | #define W_EBAR 0x04 |
---|
68 | |
---|
69 | typedef struct { |
---|
70 | int w_fd; |
---|
71 | int w_flags; |
---|
72 | int w_wd; |
---|
73 | struct wstate w_ws; |
---|
74 | char *w_eb; |
---|
75 | int w_ebloc; |
---|
76 | int w_ebsize; |
---|
77 | int w_cbase; |
---|
78 | int w_height; |
---|
79 | int w_cheight; |
---|
80 | int w_width; |
---|
81 | int w_cwidth; |
---|
82 | struct line *w_head; |
---|
83 | struct line *w_top; |
---|
84 | struct line *w_bottom; |
---|
85 | struct line *w_tail; |
---|
86 | char w_buffer[BUFSIZ]; |
---|
87 | int w_bufpos; |
---|
88 | } WINDOW; |
---|
89 | |
---|
90 | |
---|
91 | static WINDOW *Scan; |
---|
92 | static WINDOW *Status; |
---|
93 | static WINDOW *Display; |
---|
94 | static WINDOW *Command; |
---|
95 | |
---|
96 | #define NWIN 4 |
---|
97 | static int numwins; |
---|
98 | WINDOW *windows[NWIN + 1]; |
---|
99 | |
---|
100 | WINDOW *WINnew (); |
---|
101 | |
---|
102 | |
---|
103 | #ifdef HAVE_TERMIOS_H |
---|
104 | static struct termios tio; |
---|
105 | # define ERASE tio.c_cc[VERASE] |
---|
106 | # define KILL tio.c_cc[VKILL] |
---|
107 | # define INTR tio.c_cc[VINTR] |
---|
108 | #else |
---|
109 | # ifdef HAVE_TERMIO_H |
---|
110 | static struct termio tio; |
---|
111 | # define ERASE tio.c_cc[VERASE] |
---|
112 | # define KILL tio.c_cc[VKILL] |
---|
113 | # define INTR tio.c_cc[VINTR] |
---|
114 | # else |
---|
115 | static struct sgttyb tio; |
---|
116 | static struct tchars tc; |
---|
117 | # define ERASE tio.sg_erase |
---|
118 | # define KILL tio.sg_kill |
---|
119 | # define INTR tc.t_intrc |
---|
120 | # define EOFC tc.t_eofc |
---|
121 | # endif |
---|
122 | #endif |
---|
123 | |
---|
124 | #define WERASC ltc.t_werasc |
---|
125 | static struct ltchars ltc; |
---|
126 | |
---|
127 | extern int errno; |
---|
128 | |
---|
129 | int ALRMser (), PIPEser (), SIGser (); |
---|
130 | int ADJser (), REFser (); |
---|
131 | |
---|
132 | /* |
---|
133 | * static prototypes |
---|
134 | */ |
---|
135 | static void adorn(char *, char *, ...); |
---|
136 | |
---|
137 | |
---|
138 | int |
---|
139 | main (int argc, char **argv) |
---|
140 | { |
---|
141 | int vecp = 1, nprog = 0; |
---|
142 | char *cp, buffer[BUFSIZ], **argp; |
---|
143 | char **arguments, *vec[MAXARGS]; |
---|
144 | |
---|
145 | #ifdef LOCALE |
---|
146 | setlocale(LC_ALL, ""); |
---|
147 | #endif |
---|
148 | invo_name = r1bindex (argv[0], '/'); |
---|
149 | |
---|
150 | /* read user profile/context */ |
---|
151 | context_read(); |
---|
152 | |
---|
153 | arguments = getarguments (invo_name, argc,argv, 1); |
---|
154 | argp = arguments; |
---|
155 | |
---|
156 | while ((cp = *argp++)) |
---|
157 | if (*cp == '-') |
---|
158 | switch (smatch (++cp, switches)) { |
---|
159 | case AMBIGSW: |
---|
160 | ambigsw (cp, switches); |
---|
161 | done (1); |
---|
162 | case UNKWNSW: |
---|
163 | vec[vecp++] = --cp; |
---|
164 | continue; |
---|
165 | |
---|
166 | case HELPSW: |
---|
167 | snprintf (buffer, sizeof(buffer), "%s [switches for vmhproc]", |
---|
168 | invo_name); |
---|
169 | print_help (buffer, switches, 1); |
---|
170 | done (1); |
---|
171 | case VERSIONSW: |
---|
172 | print_version(invo_name); |
---|
173 | done (1); |
---|
174 | |
---|
175 | case PRMPTSW: |
---|
176 | if (!(myprompt = *argp++) || *myprompt == '-') |
---|
177 | adios (NULL, "missing argument to %s", argp[-2]); |
---|
178 | continue; |
---|
179 | |
---|
180 | case PROGSW: |
---|
181 | if (!(vmhproc = *argp++) || *vmhproc == '-') |
---|
182 | adios (NULL, "missing argument to %s", argp[-2]); |
---|
183 | continue; |
---|
184 | case NPROGSW: |
---|
185 | nprog++; |
---|
186 | continue; |
---|
187 | } |
---|
188 | else |
---|
189 | vec[vecp++] = cp; |
---|
190 | |
---|
191 | SIGinit (); |
---|
192 | if (WINinit (nprog) == NOTOK) { |
---|
193 | vec[vecp] = NULL; |
---|
194 | |
---|
195 | vec[0] = r1bindex (vmhproc, '/'); |
---|
196 | execvp (vmhproc, vec); |
---|
197 | adios (vmhproc, "unable to exec"); |
---|
198 | } |
---|
199 | PEERinit (vecp, vec); |
---|
200 | |
---|
201 | vmh (); |
---|
202 | |
---|
203 | done (0); |
---|
204 | } |
---|
205 | |
---|
206 | |
---|
207 | static void |
---|
208 | vmh (void) |
---|
209 | { |
---|
210 | char buffer[BUFSIZ], prompt[BUFSIZ]; |
---|
211 | |
---|
212 | for (;;) { |
---|
213 | pLOOP (RC_QRY, NULL); |
---|
214 | |
---|
215 | snprintf (prompt, sizeof(prompt), myprompt, invo_name); |
---|
216 | |
---|
217 | switch (WINgetstr (Command, prompt, buffer)) { |
---|
218 | case NOTOK: |
---|
219 | break; |
---|
220 | |
---|
221 | case OK: |
---|
222 | done (0); /* NOTREACHED */ |
---|
223 | |
---|
224 | default: |
---|
225 | if (*buffer) |
---|
226 | pLOOP (RC_CMD, buffer); |
---|
227 | break; |
---|
228 | } |
---|
229 | } |
---|
230 | } |
---|
231 | |
---|
232 | /* PEERS */ |
---|
233 | |
---|
234 | static int |
---|
235 | PEERinit (int vecp, char *vec[]) |
---|
236 | { |
---|
237 | int pfd0[2], pfd1[2]; |
---|
238 | char buf1[BUFSIZ], buf2[BUFSIZ]; |
---|
239 | register WINDOW **w; |
---|
240 | |
---|
241 | SIGNAL (SIGPIPE, PIPEser); |
---|
242 | |
---|
243 | if (pipe (pfd0) == NOTOK || pipe (pfd1) == NOTOK) |
---|
244 | adios ("pipe", "unable to"); |
---|
245 | switch (PEERpid = vfork ()) { |
---|
246 | case NOTOK: |
---|
247 | adios ("vfork", "unable to");/* NOTREACHED */ |
---|
248 | |
---|
249 | case OK: |
---|
250 | for (w = windows; *w; w++) |
---|
251 | if ((*w)->w_fd != NOTOK) |
---|
252 | close ((*w)->w_fd); |
---|
253 | close (pfd0[0]); |
---|
254 | close (pfd1[1]); |
---|
255 | |
---|
256 | vec[vecp++] = "-vmhread"; |
---|
257 | snprintf (buf1, sizeof(buf1), "%d", pfd1[0]); |
---|
258 | vec[vecp++] = buf1; |
---|
259 | vec[vecp++] = "-vmhwrite"; |
---|
260 | snprintf (buf2, sizeof(buf2), "%d", pfd0[1]); |
---|
261 | vec[vecp++] = buf2; |
---|
262 | vec[vecp] = NULL; |
---|
263 | |
---|
264 | SIGNAL (SIGINT, SIG_DFL); |
---|
265 | SIGNAL (SIGQUIT, SIG_DFL); |
---|
266 | SIGNAL (SIGTERM, SIG_DFL); |
---|
267 | |
---|
268 | vec[0] = r1bindex (vmhproc, '/'); |
---|
269 | execvp (vmhproc, vec); |
---|
270 | perror (vmhproc); |
---|
271 | _exit (-1); /* NOTREACHED */ |
---|
272 | |
---|
273 | default: |
---|
274 | close (pfd0[1]); |
---|
275 | close (pfd1[0]); |
---|
276 | |
---|
277 | rcinit (pfd0[0], pfd1[1]); |
---|
278 | return pINI (); |
---|
279 | } |
---|
280 | } |
---|
281 | |
---|
282 | |
---|
283 | static int |
---|
284 | pINI (void) |
---|
285 | { |
---|
286 | int len, buflen; |
---|
287 | char *bp, buffer[BUFSIZ]; |
---|
288 | struct record rcs, *rc; |
---|
289 | WINDOW **w; |
---|
290 | |
---|
291 | rc = &rcs; |
---|
292 | initrc (rc); |
---|
293 | |
---|
294 | /* Get buffer ready to go */ |
---|
295 | bp = buffer; |
---|
296 | buflen = sizeof(buffer); |
---|
297 | |
---|
298 | snprintf (bp, buflen, "%d %d", RC_VRSN, numwins); |
---|
299 | len = strlen (bp); |
---|
300 | bp += len; |
---|
301 | buflen -= len; |
---|
302 | |
---|
303 | for (w = windows; *w; w++) { |
---|
304 | snprintf (bp, buflen, " %d", (*w)->w_height); |
---|
305 | len = strlen (bp); |
---|
306 | bp += len; |
---|
307 | buflen -= len; |
---|
308 | } |
---|
309 | |
---|
310 | switch (str2rc (RC_INI, buffer, rc)) { |
---|
311 | case RC_ACK: |
---|
312 | return OK; |
---|
313 | |
---|
314 | case RC_ERR: |
---|
315 | if (rc->rc_len) |
---|
316 | adios (NULL, "%s", rc->rc_data); |
---|
317 | else |
---|
318 | adios (NULL, "pINI peer error"); |
---|
319 | |
---|
320 | case RC_XXX: |
---|
321 | adios (NULL, "%s", rc->rc_data); |
---|
322 | |
---|
323 | default: |
---|
324 | adios (NULL, "pINI protocol screw-up"); |
---|
325 | } |
---|
326 | /* NOTREACHED */ |
---|
327 | } |
---|
328 | |
---|
329 | |
---|
330 | static int |
---|
331 | pLOOP (char code, char *str) |
---|
332 | { |
---|
333 | int i; |
---|
334 | struct record rcs, *rc; |
---|
335 | WINDOW *w; |
---|
336 | |
---|
337 | rc = &rcs; |
---|
338 | initrc (rc); |
---|
339 | |
---|
340 | str2peer (code, str); |
---|
341 | for (;;) |
---|
342 | switch (peer2rc (rc)) { |
---|
343 | case RC_TTY: |
---|
344 | if (pTTY () == NOTOK) |
---|
345 | return NOTOK; |
---|
346 | break; |
---|
347 | |
---|
348 | case RC_WIN: |
---|
349 | if (sscanf (rc->rc_data, "%d", &i) != 1 |
---|
350 | || i <= 0 |
---|
351 | || i > numwins) { |
---|
352 | fmt2peer (RC_ERR, "no such window \"%s\"", rc->rc_data); |
---|
353 | return NOTOK; |
---|
354 | } |
---|
355 | if ((w = windows[i - 1])->w_flags & W_CMND) { |
---|
356 | fmt2peer (RC_ERR, "not a display window \"%s\"", rc->rc_data); |
---|
357 | return NOTOK; |
---|
358 | } |
---|
359 | if (pWIN (w) == NOTOK) |
---|
360 | return NOTOK; |
---|
361 | break; |
---|
362 | |
---|
363 | case RC_EOF: |
---|
364 | return OK; |
---|
365 | |
---|
366 | case RC_ERR: |
---|
367 | if (rc->rc_len) |
---|
368 | adorn (NULL, "%s", rc->rc_data); |
---|
369 | else |
---|
370 | adorn (NULL, "pLOOP(%s) peer error", |
---|
371 | code == RC_QRY ? "QRY" : "CMD"); |
---|
372 | return NOTOK; |
---|
373 | |
---|
374 | case RC_FIN: |
---|
375 | if (rc->rc_len) |
---|
376 | adorn (NULL, "%s", rc->rc_data); |
---|
377 | rcdone (); |
---|
378 | i = pidwait (PEERpid, OK); |
---|
379 | PEERpid = NOTOK; |
---|
380 | done (i); |
---|
381 | |
---|
382 | case RC_XXX: |
---|
383 | adios (NULL, "%s", rc->rc_data); |
---|
384 | |
---|
385 | default: |
---|
386 | adios (NULL, "pLOOP(%s) protocol screw-up", |
---|
387 | code == RC_QRY ? "QRY" : "CMD"); |
---|
388 | } |
---|
389 | } |
---|
390 | |
---|
391 | |
---|
392 | static int |
---|
393 | pTTY (void) |
---|
394 | { |
---|
395 | SIGNAL_HANDLER hstat, istat, qstat, tstat; |
---|
396 | struct record rcs, *rc; |
---|
397 | |
---|
398 | rc = &rcs; |
---|
399 | initrc (rc); |
---|
400 | |
---|
401 | if (ChangeWindowDepth (dfd, twd, 0) == NOTOK) |
---|
402 | adios ("failed", "ChangeWindowDepth"); |
---|
403 | |
---|
404 | /* should block here instead of ignore */ |
---|
405 | hstat = SIGNAL (SIGHUP, SIG_IGN); |
---|
406 | istat = SIGNAL (SIGINT, SIG_IGN); |
---|
407 | qstat = SIGNAL (SIGQUIT, SIG_IGN); |
---|
408 | tstat = SIGNAL (SIGTERM, SIG_IGN); |
---|
409 | |
---|
410 | rc2rc (RC_ACK, 0, NULL, rc); |
---|
411 | |
---|
412 | SIGNAL (SIGHUP, hstat); |
---|
413 | SIGNAL (SIGINT, istat); |
---|
414 | SIGNAL (SIGQUIT, qstat); |
---|
415 | SIGNAL (SIGTERM, tstat); |
---|
416 | |
---|
417 | switch (rc->rc_type) { |
---|
418 | case RC_EOF: |
---|
419 | rc2peer (RC_ACK, 0, NULL); |
---|
420 | return OK; |
---|
421 | |
---|
422 | case RC_ERR: |
---|
423 | if (rc->rc_len) |
---|
424 | adorn (NULL, "%s", rc->rc_data); |
---|
425 | else |
---|
426 | adorn (NULL, "pTTY peer error"); |
---|
427 | return NOTOK; |
---|
428 | |
---|
429 | case RC_XXX: |
---|
430 | adios (NULL, "%s", rc->rc_data); |
---|
431 | |
---|
432 | default: |
---|
433 | adios (NULL, "pTTY protocol screw-up"); |
---|
434 | } |
---|
435 | /* NOTREACHED */ |
---|
436 | } |
---|
437 | |
---|
438 | |
---|
439 | static int |
---|
440 | pWIN (WINDOW *w) |
---|
441 | { |
---|
442 | int i; |
---|
443 | |
---|
444 | if ((i = pWINaux (w)) == OK) |
---|
445 | WINless (w); |
---|
446 | |
---|
447 | return i; |
---|
448 | } |
---|
449 | |
---|
450 | |
---|
451 | static int |
---|
452 | pWINaux (WINDOW *w) |
---|
453 | { |
---|
454 | register int n; |
---|
455 | register char *bp; |
---|
456 | register struct line *lp, *mp; |
---|
457 | struct record rcs, *rc; |
---|
458 | |
---|
459 | rc = &rcs; |
---|
460 | initrc (rc); |
---|
461 | |
---|
462 | for (lp = w->w_head; lp; lp = mp) { |
---|
463 | mp = lp->l_next; |
---|
464 | free (lp->l_buf); |
---|
465 | free ((char *) lp); |
---|
466 | } |
---|
467 | w->w_head = w->w_top = w->w_bottom = w->w_tail = NULL; |
---|
468 | w->w_bufpos = 0; |
---|
469 | |
---|
470 | for (;;) |
---|
471 | switch (rc2rc (RC_ACK, 0, NULL, rc)) { |
---|
472 | case RC_DATA: |
---|
473 | for (bp = rc->rc_data, n = rc->rc_len; n-- > 0; ) |
---|
474 | WINputc (w, *bp++); |
---|
475 | break; |
---|
476 | |
---|
477 | case RC_EOF: |
---|
478 | rc2peer (RC_ACK, 0, NULL); |
---|
479 | if (w->w_bufpos) |
---|
480 | WINputc (w, '\n'); |
---|
481 | return OK; |
---|
482 | |
---|
483 | case RC_ERR: |
---|
484 | if (rc->rc_len) |
---|
485 | adorn (NULL, "%s", rc->rc_data); |
---|
486 | else |
---|
487 | adorn (NULL, "pWIN peer error"); |
---|
488 | return NOTOK; |
---|
489 | |
---|
490 | case RC_XXX: |
---|
491 | adios (NULL, "%s", rc->rc_data); |
---|
492 | |
---|
493 | default: |
---|
494 | adios (NULL, "pWIN protocol screw-up"); |
---|
495 | } |
---|
496 | /* NOTREACHED */ |
---|
497 | } |
---|
498 | |
---|
499 | |
---|
500 | static int |
---|
501 | pFIN (void) |
---|
502 | { |
---|
503 | int status; |
---|
504 | |
---|
505 | if (PEERpid <= OK) |
---|
506 | return OK; |
---|
507 | |
---|
508 | rc2peer (RC_FIN, 0, NULL); |
---|
509 | rcdone (); |
---|
510 | |
---|
511 | switch (setjmp (PEERctx)) { |
---|
512 | case OK: |
---|
513 | SIGNAL (SIGALRM, ALRMser); |
---|
514 | alarm (ALARM); |
---|
515 | |
---|
516 | status = pidwait (PEERpid, OK); |
---|
517 | |
---|
518 | alarm (0); |
---|
519 | break; |
---|
520 | |
---|
521 | default: |
---|
522 | kill (PEERpid, SIGKILL); |
---|
523 | status = NOTOK; |
---|
524 | break; |
---|
525 | } |
---|
526 | PEERpid = NOTOK; |
---|
527 | |
---|
528 | return status; |
---|
529 | } |
---|
530 | |
---|
531 | /* WINDOWS */ |
---|
532 | |
---|
533 | /* should dynamically determine all this stuff from gconfig... */ |
---|
534 | |
---|
535 | #define MyX 20 /* anchored hpos */ |
---|
536 | #define MyY 40 /* .. vpos */ |
---|
537 | #define MyW 800 /* .. width */ |
---|
538 | #define MyH 500 /* .. height */ |
---|
539 | #define MyS 30 /* .. height for Status, about one line */ |
---|
540 | |
---|
541 | |
---|
542 | #define MySlop 45 /* slop */ |
---|
543 | |
---|
544 | #define EWIDTH 25 /* Width of vertical EBAR */ |
---|
545 | #define ESLOP 5 /* .. slop */ |
---|
546 | |
---|
547 | |
---|
548 | static intWINinit (nprog) { |
---|
549 | short wx, wy, wh, sy; |
---|
550 | struct gconfig gc; |
---|
551 | |
---|
552 | if (GetGraphicsConfig (fileno (stderr), &gc) == NOTOK) |
---|
553 | if (nprog) |
---|
554 | return NOTOK; |
---|
555 | else |
---|
556 | adios (NULL, "not a window"); |
---|
557 | |
---|
558 | if ((dfd = open ("/dev/ttyw0", O_RDWR)) == NOTOK) |
---|
559 | adios ("/dev/ttyw0", "unable to open"); |
---|
560 | |
---|
561 | if ((twd = GetTopWindow (dfd)) == NOTOK) |
---|
562 | adios ("failed", "GetTopWindow"); |
---|
563 | |
---|
564 | BlockRefreshAdjust (1); |
---|
565 | |
---|
566 | numwins = 0; |
---|
567 | |
---|
568 | wx = gc.w - (MyX + MyW + EWIDTH + ESLOP); |
---|
569 | Scan = WINnew (wx, wy = MyY, MyW, wh = MyH * 2 / 3, "Scan", W_EBAR); |
---|
570 | |
---|
571 | wy += wh + MySlop; |
---|
572 | Status = WINnew (wx, sy = wy, MyW, wh = MyS, "Status", W_FAKE); |
---|
573 | |
---|
574 | wy += wh + MySlop; |
---|
575 | Display = WINnew (wx, wy, MyW, MyH, "Display", W_EBAR); |
---|
576 | |
---|
577 | Command = WINnew (wx, sy, MyW, MyS, invo_name, W_CMND); |
---|
578 | |
---|
579 | windows[numwins] = NULL; |
---|
580 | |
---|
581 | return OK; |
---|
582 | } |
---|
583 | |
---|
584 | |
---|
585 | WINDOW * |
---|
586 | WINnew (short wx, short wy, short ww, short wh, char *name, int flags) |
---|
587 | { |
---|
588 | register WINDOW *w; |
---|
589 | |
---|
590 | if ((w = (WINDOW *) calloc (1, sizeof *w)) == NULL) |
---|
591 | adios (NULL, "unable to allocate window"); |
---|
592 | |
---|
593 | if ((w->w_flags = flags) & W_FAKE) { |
---|
594 | w->w_fd = NOTOK; |
---|
595 | w->w_height = 1; |
---|
596 | |
---|
597 | goto out; |
---|
598 | } |
---|
599 | |
---|
600 | if (w->w_flags & W_EBAR) |
---|
601 | ww += EWIDTH + ESLOP; |
---|
602 | else |
---|
603 | wx += EWIDTH + ESLOP; |
---|
604 | |
---|
605 | if ((w->w_fd = OpenWindow (wx, wy, ww, wh, name)) == NOTOK) |
---|
606 | adios ("failed", "OpenWindow"); |
---|
607 | if ((w->w_wd = GetTopWindow (dfd)) == NOTOK) |
---|
608 | adios ("failed", "GetTopWindow"); |
---|
609 | if (GetWindowState (w->w_fd, &w->w_ws) == NOTOK) |
---|
610 | adios ("failed", "GetWindowState"); |
---|
611 | if (SetLineDisc (w->w_fd, TWSDISC) == NOTOK) |
---|
612 | adios ("failed", "SetLineDisc"); |
---|
613 | |
---|
614 | SetBuf (w->w_fd, 1024); |
---|
615 | SetAdjust (w->w_fd, numwins, ADJser); |
---|
616 | SetRefresh (w->w_fd, numwins, REFser); |
---|
617 | |
---|
618 | SetAddressing (w->w_fd, VT_ABSOLUTE); |
---|
619 | |
---|
620 | if (w->w_flags & W_EBAR) { |
---|
621 | w->w_eb = CreateElevatorBar (w->w_fd, 0, 0, EWIDTH, |
---|
622 | w->w_ws.height, VT_Gray50, 1, EB_VERTICAL, |
---|
623 | EB_ARROWS, w->w_ebloc = 0, w->w_ebsize = EB_MAX, |
---|
624 | VT_White); |
---|
625 | if (w->w_eb == NULL) |
---|
626 | adios (NULL, "CreateElevatorBar failed"); |
---|
627 | RefreshElevatorBar (w->w_eb); |
---|
628 | } |
---|
629 | |
---|
630 | if ((w->w_cbase = CharacterBaseline (w->w_ws.font)) <= 0) |
---|
631 | w->w_cbase = 14; |
---|
632 | |
---|
633 | if ((w->w_cheight = CharacterHeight (w->w_ws.font)) <= 0) |
---|
634 | w->w_cheight = 20; |
---|
635 | w->w_height = w->w_ws.height / w->w_cheight; |
---|
636 | if (w->w_height < 1) |
---|
637 | w->w_height = 1; |
---|
638 | |
---|
639 | /* 1 em */ |
---|
640 | if ((w->w_cwidth = CharacterWidth (w->w_ws.font, 'm')) <= 0) |
---|
641 | w->w_cwidth = 10; |
---|
642 | w->w_width = (w->w_ws.width - (w->w_eb ? (EWIDTH + ESLOP) : 0)) |
---|
643 | / w->w_cwidth; |
---|
644 | if (w->w_width < 1) |
---|
645 | w->w_width = 1; |
---|
646 | |
---|
647 | out: ; |
---|
648 | windows[numwins++] = w; |
---|
649 | |
---|
650 | return w; |
---|
651 | } |
---|
652 | |
---|
653 | |
---|
654 | static int |
---|
655 | WINgetstr (WINDOW *w, char *prompt, char *buffer) |
---|
656 | { |
---|
657 | register int c; |
---|
658 | register char *bp, *ip; |
---|
659 | char image[BUFSIZ]; |
---|
660 | struct vtseq vts; |
---|
661 | register struct vtseq *vt = &vts; |
---|
662 | |
---|
663 | if (w->w_eb != NULL) |
---|
664 | adios (NULL, "internal error--elevator bar found"); |
---|
665 | |
---|
666 | if (w->w_head == NULL |
---|
667 | && (w->w_head = (struct line *) calloc (1, sizeof *w->w_head)) |
---|
668 | == NULL) |
---|
669 | adios (NULL, "unable to allocate line storage"); |
---|
670 | w->w_head->l_buf = image; |
---|
671 | w->w_top = w->w_bottom = w->w_tail = w->w_head; |
---|
672 | |
---|
673 | if (ChangeWindowDepth (dfd, w->w_wd, 0) == NOTOK) |
---|
674 | adios ("failed", "ChangeWindowDepth"); |
---|
675 | |
---|
676 | strncpy (image, prompt, sizeof(image)); |
---|
677 | bp = ip = image + strlen (image); |
---|
678 | |
---|
679 | Redisplay (w, 0); |
---|
680 | |
---|
681 | for (;;) |
---|
682 | switch (getvtseq (w->w_fd, vt)) { |
---|
683 | case VT_HARDKEY: |
---|
684 | DisplayStatus (w->w_fd, "no hardkeys, please"); |
---|
685 | break; |
---|
686 | |
---|
687 | case VT_ASCII: |
---|
688 | switch (c = toascii (vt->u.ascii)) { |
---|
689 | case '\f': /* refresh? */ |
---|
690 | break; |
---|
691 | |
---|
692 | case '\r': |
---|
693 | case '\n': |
---|
694 | strcpy (buffer, ip); |
---|
695 | return DONE; |
---|
696 | |
---|
697 | default: |
---|
698 | if (c == INTR) { |
---|
699 | adorn (NULL, "Interrupt"); |
---|
700 | return NOTOK; |
---|
701 | } |
---|
702 | |
---|
703 | if (c == EOFC) { |
---|
704 | if (bp <= ip) |
---|
705 | return OK; |
---|
706 | break; |
---|
707 | } |
---|
708 | |
---|
709 | if (c == ERASE) { |
---|
710 | if (bp <= ip) |
---|
711 | continue; |
---|
712 | bp--; |
---|
713 | break; |
---|
714 | } |
---|
715 | |
---|
716 | if (c == KILL) { |
---|
717 | if (bp <= ip) |
---|
718 | continue; |
---|
719 | bp = ip; |
---|
720 | break; |
---|
721 | } |
---|
722 | |
---|
723 | if (c == WERASC) { |
---|
724 | if (bp <= ip) |
---|
725 | continue; |
---|
726 | do { |
---|
727 | bp--; |
---|
728 | } while (isspace (*bp) && bp > ip); |
---|
729 | if (bp > ip) { |
---|
730 | do { |
---|
731 | bp--; |
---|
732 | } while (!isspace (*bp) && bp > buffer); |
---|
733 | if (isspace (*bp)) |
---|
734 | bp++; |
---|
735 | } |
---|
736 | break; |
---|
737 | } |
---|
738 | |
---|
739 | if (c < ' ' || c >= '\177') |
---|
740 | continue; |
---|
741 | *bp++ = c; |
---|
742 | break; |
---|
743 | } |
---|
744 | *bp = NULL; |
---|
745 | Redisplay (w, 0); |
---|
746 | break; |
---|
747 | |
---|
748 | case VT_MOUSE: |
---|
749 | switch (vt->u.mouse.buttons |
---|
750 | & (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) { |
---|
751 | case VT_MOUSE_LEFT: |
---|
752 | DisplayStatus (w->w_fd, "use middle or right button"); |
---|
753 | break; |
---|
754 | |
---|
755 | #define WPOP "WMH\0Advance\0Burst\0Exit\0EOF\0" |
---|
756 | case VT_MOUSE_MIDDLE: |
---|
757 | SetPosition (w->w_fd, vt->u.mouse.x, |
---|
758 | vt->u.mouse.y); |
---|
759 | switch (DisplayPopUp (w->w_fd, WPOP)) { |
---|
760 | case 1: /* Advance */ |
---|
761 | do_advance: ; |
---|
762 | strcpy (buffer, "advance"); |
---|
763 | return DONE; |
---|
764 | |
---|
765 | case 2: /* Burst */ |
---|
766 | strcpy (buffer, "burst"); |
---|
767 | return DONE; |
---|
768 | |
---|
769 | case 3: /* Exit */ |
---|
770 | strcpy (buffer, "exit"); |
---|
771 | return DONE; |
---|
772 | |
---|
773 | case 4: /* EOF */ |
---|
774 | return OK; |
---|
775 | |
---|
776 | default: /* failed or none taken */ |
---|
777 | break; |
---|
778 | } |
---|
779 | break; |
---|
780 | #undef WPOP |
---|
781 | |
---|
782 | case VT_MOUSE_RIGHT: |
---|
783 | goto do_advance; |
---|
784 | } |
---|
785 | break; |
---|
786 | |
---|
787 | case VT_EOF: |
---|
788 | adios (NULL, "end-of-file on window");/* NOTREACHED */ |
---|
789 | |
---|
790 | default: |
---|
791 | DisplayStatus (w->w_fd, "unknown VT sequence"); |
---|
792 | break; |
---|
793 | } |
---|
794 | } |
---|
795 | |
---|
796 | |
---|
797 | static int |
---|
798 | WINputc (WINDOW *w, char c) |
---|
799 | { |
---|
800 | register int i; |
---|
801 | register char *cp; |
---|
802 | register struct line *lp; |
---|
803 | |
---|
804 | switch (c) { |
---|
805 | default: |
---|
806 | if (!isascii (c)) { |
---|
807 | if (WINputc (w, 'M') == NOTOK || WINputc (w, '-') == NOTOK) |
---|
808 | return NOTOK; |
---|
809 | c = toascii (c); |
---|
810 | } |
---|
811 | else |
---|
812 | if (c < ' ' || c == '\177') { |
---|
813 | if (WINputc (w, '^') == NOTOK) |
---|
814 | return NOTOK; |
---|
815 | c ^= 0100; |
---|
816 | } |
---|
817 | break; |
---|
818 | |
---|
819 | case '\t': |
---|
820 | for (i = 8 - (w->w_bufpos & 0x07); i > 0; i--) |
---|
821 | if (WINputc (w, ' ') == NOTOK) |
---|
822 | return NOTOK; |
---|
823 | return OK; |
---|
824 | |
---|
825 | case '\b': |
---|
826 | if (w->w_bufpos > 0) |
---|
827 | w->w_bufpos--; |
---|
828 | return OK; |
---|
829 | |
---|
830 | case '\n': |
---|
831 | break; |
---|
832 | } |
---|
833 | |
---|
834 | if (c != '\n') { |
---|
835 | w->w_buffer[w->w_bufpos++] = c; |
---|
836 | return OK; |
---|
837 | } |
---|
838 | |
---|
839 | w->w_buffer[w->w_bufpos] = NULL; |
---|
840 | w->w_bufpos = 0; |
---|
841 | |
---|
842 | if ((lp = (struct line *) calloc (1, sizeof *lp)) == NULL) |
---|
843 | adios (NULL, "unable to allocate line storage"); |
---|
844 | |
---|
845 | lp->l_no = (w->w_tail ? w->w_tail->l_no : 0) + 1; |
---|
846 | lp->l_buf = getcpy (w->w_buffer); |
---|
847 | for (cp = lp->l_buf + strlen (lp->l_buf) - 1; cp >= lp->l_buf; cp--) |
---|
848 | if (isspace (*cp)) |
---|
849 | *cp = NULL; |
---|
850 | else |
---|
851 | break; |
---|
852 | |
---|
853 | if (w->w_head == NULL) |
---|
854 | w->w_head = lp; |
---|
855 | if (w->w_top == NULL) |
---|
856 | w->w_top = lp; |
---|
857 | if (w->w_bottom == NULL) |
---|
858 | w->w_bottom = lp; |
---|
859 | if (w->w_tail) |
---|
860 | w->w_tail->l_next = lp; |
---|
861 | lp->l_prev = w->w_tail; |
---|
862 | w->w_tail = lp; |
---|
863 | |
---|
864 | return DONE; |
---|
865 | } |
---|
866 | |
---|
867 | #define PSLOP 2 |
---|
868 | |
---|
869 | |
---|
870 | static char mylineno[5]; |
---|
871 | |
---|
872 | static bool cancel[] = { 1 }; |
---|
873 | static struct choice mychoices[] = { LABEL, "cancel", VT_White }; |
---|
874 | |
---|
875 | static struct question myquestions[] = { |
---|
876 | STRING, "Line", SZ (mylineno), (struct choice *) 0, |
---|
877 | |
---|
878 | TOGGLE, "", SZ (mychoices), mychoices |
---|
879 | }; |
---|
880 | |
---|
881 | static struct menu mymenu = { "Goto", SZ (myquestions), myquestions }; |
---|
882 | |
---|
883 | static int *myanswers[] = { (int *) mylineno, (int *) cancel }; |
---|
884 | |
---|
885 | |
---|
886 | static void |
---|
887 | WINless (WINDOW *w) |
---|
888 | { |
---|
889 | int clear, pos, forw, refresh; |
---|
890 | struct vtseq vts; |
---|
891 | register struct vtseq *vt = &vts; |
---|
892 | |
---|
893 | if (w->w_fd == NOTOK) { |
---|
894 | if (w->w_head) |
---|
895 | DisplayStatus (dfd, w->w_top->l_buf); |
---|
896 | else |
---|
897 | RemoveStatus (dfd); |
---|
898 | |
---|
899 | return; |
---|
900 | } |
---|
901 | |
---|
902 | if (ChangeWindowDepth (dfd, w->w_wd, 0) == NOTOK) |
---|
903 | adios ("failed", "ChangeWindowDepth"); |
---|
904 | |
---|
905 | Redisplay (w, 0); |
---|
906 | |
---|
907 | if (w->w_bottom == w->w_tail) |
---|
908 | return; |
---|
909 | |
---|
910 | if (w->w_eb == NULL) |
---|
911 | adios (NULL, "internal error--no elevator bar"); |
---|
912 | |
---|
913 | for (clear = refresh = 0, forw = 1;;) { |
---|
914 | if (clear) { |
---|
915 | RemoveStatus (w->w_fd); |
---|
916 | clear = 0; |
---|
917 | } |
---|
918 | if (refresh) { |
---|
919 | Redisplay (w, 0); |
---|
920 | refresh = 0; |
---|
921 | } |
---|
922 | |
---|
923 | switch (getvtseq (w->w_fd, vt)) { |
---|
924 | case VT_HARDKEY: |
---|
925 | case VT_ASCII: |
---|
926 | DisplayStatus (w->w_fd, "use the mouse"); |
---|
927 | clear++; |
---|
928 | break; |
---|
929 | |
---|
930 | case VT_MOUSE: |
---|
931 | switch (vt->u.mouse.buttons |
---|
932 | & (VT_MOUSE_LEFT | VT_MOUSE_MIDDLE | VT_MOUSE_RIGHT)) { |
---|
933 | case VT_MOUSE_LEFT: |
---|
934 | if ((pos = vt->u.mouse.x) < EWIDTH) { |
---|
935 | pos = w->w_ebloc = DoElevatorBar (w->w_eb, pos, |
---|
936 | vt->u.mouse.y); |
---|
937 | refresh = WINgoto (w, ((pos * (w->w_tail->l_no |
---|
938 | - w->w_head->l_no)) |
---|
939 | / EB_MAX) + w->w_head->l_no); |
---|
940 | } |
---|
941 | break; |
---|
942 | |
---|
943 | #define WPOP "Paging\0Next\0Prev\0Left\0Right\0First\0Last\0Goto ...\0Exit\0" |
---|
944 | case VT_MOUSE_MIDDLE: |
---|
945 | SetPosition (w->w_fd, vt->u.mouse.x, |
---|
946 | vt->u.mouse.y); |
---|
947 | switch (DisplayPopUp (w->w_fd, WPOP)) { |
---|
948 | case 1: /* Next */ |
---|
949 | do_next_page: ; |
---|
950 | if (w->w_bottom == w->w_tail) |
---|
951 | forw = 0; |
---|
952 | refresh = WINgoto (w, w->w_bottom->l_no + 1 - PSLOP); |
---|
953 | break; |
---|
954 | |
---|
955 | case 2: /* Prev */ |
---|
956 | do_prev_page: ; |
---|
957 | if (w->w_top == w->w_head) |
---|
958 | forw = 1; |
---|
959 | refresh = WINgoto (w, w->w_top->l_no |
---|
960 | - w->w_height + PSLOP); |
---|
961 | break; |
---|
962 | |
---|
963 | case 3: /* Left */ |
---|
964 | case 4: /* Right */ |
---|
965 | DisplayStatus (w->w_fd, "not yet"); |
---|
966 | clear++; |
---|
967 | break; |
---|
968 | |
---|
969 | case 5: /* First */ |
---|
970 | forw = 1; |
---|
971 | refresh = WINgoto (w, w->w_head->l_no); |
---|
972 | break; |
---|
973 | |
---|
974 | case 6: /* Last */ |
---|
975 | forw = 0; |
---|
976 | refresh = WINgoto (w, w->w_tail->l_no |
---|
977 | - w->w_height + 1); |
---|
978 | break; |
---|
979 | |
---|
980 | case 7: /* Goto ... */ |
---|
981 | snprintf (mylineno, sizeof(mylineno), |
---|
982 | "%d", w->w_top->l_no); |
---|
983 | cancel[0] = 0; |
---|
984 | if (PresentMenu (&mymenu, myanswers) |
---|
985 | || cancel[0]) |
---|
986 | break; |
---|
987 | if (sscanf (mylineno, "%d", &pos) != 1) { |
---|
988 | DisplayStatus (w->w_fd, "bad format"); |
---|
989 | clear++; |
---|
990 | break; |
---|
991 | } |
---|
992 | if (pos < w->w_head->l_no |
---|
993 | || pos > w->w_tail->l_no) { |
---|
994 | DisplayStatus (w->w_fd, "no such line"); |
---|
995 | clear++; |
---|
996 | break; |
---|
997 | } |
---|
998 | refresh = WINgoto (w, pos); |
---|
999 | break; |
---|
1000 | |
---|
1001 | case 8: /* Exit */ |
---|
1002 | return; |
---|
1003 | |
---|
1004 | default: /* failed or none taken */ |
---|
1005 | break; |
---|
1006 | } |
---|
1007 | break; |
---|
1008 | #undef WPOP |
---|
1009 | |
---|
1010 | case VT_MOUSE_RIGHT: |
---|
1011 | if (forw) { |
---|
1012 | if (w->w_bottom == w->w_tail) |
---|
1013 | return; |
---|
1014 | else |
---|
1015 | goto do_next_page; |
---|
1016 | } |
---|
1017 | else |
---|
1018 | goto do_prev_page; |
---|
1019 | } |
---|
1020 | break; |
---|
1021 | |
---|
1022 | case VT_EOF: |
---|
1023 | adios (NULL, "end-of-file on window");/* NOTREACHED */ |
---|
1024 | |
---|
1025 | default: |
---|
1026 | DisplayStatus (w->w_fd, "unknown VT sequence"); |
---|
1027 | clear++; |
---|
1028 | break; |
---|
1029 | } |
---|
1030 | } |
---|
1031 | } |
---|
1032 | |
---|
1033 | |
---|
1034 | static int |
---|
1035 | WINgoto (WINDOW *w, int n) |
---|
1036 | { |
---|
1037 | register int i, j; |
---|
1038 | register struct line *lp; |
---|
1039 | |
---|
1040 | if (n > (i = w->w_tail->l_no - w->w_height + 1)) |
---|
1041 | n = i; |
---|
1042 | if (n < w->w_head->l_no) |
---|
1043 | n = w->w_head->l_no; |
---|
1044 | |
---|
1045 | if ((i = n - (lp = w->w_head)->l_no) |
---|
1046 | > (j = abs (n - w->w_top->l_no))) |
---|
1047 | i = j, lp = w->w_top; |
---|
1048 | |
---|
1049 | if (i > (j = abs (w->w_tail->l_no - n))) |
---|
1050 | i = j, lp = w->w_tail; |
---|
1051 | |
---|
1052 | if (n >= lp->l_no) { |
---|
1053 | for (; lp; lp = lp->l_next) |
---|
1054 | if (lp->l_no == n) |
---|
1055 | break; |
---|
1056 | } |
---|
1057 | else { |
---|
1058 | for (; lp; lp = lp->l_prev) |
---|
1059 | if (lp->l_no == n) |
---|
1060 | break; |
---|
1061 | if (!lp) |
---|
1062 | lp = w->w_head; |
---|
1063 | } |
---|
1064 | |
---|
1065 | if (w->w_top == lp) |
---|
1066 | return 0; |
---|
1067 | |
---|
1068 | w->w_top = lp; |
---|
1069 | |
---|
1070 | return 1; |
---|
1071 | } |
---|
1072 | |
---|
1073 | |
---|
1074 | static int |
---|
1075 | ADJser (int id, short ww, short wh) |
---|
1076 | { |
---|
1077 | register WINDOW *w; |
---|
1078 | |
---|
1079 | if (id < 0 || id >= numwins) |
---|
1080 | adios (NULL, "ADJser on bogus window (%d)", id); |
---|
1081 | w = windows[id]; |
---|
1082 | if (w->w_fd == NOTOK) |
---|
1083 | adios (NULL, "ADJser on closed window (%d)", id); |
---|
1084 | |
---|
1085 | w->w_ws.width = w->w_ws.tw = ww; |
---|
1086 | w->w_ws.height = w->w_ws.th = wh; |
---|
1087 | |
---|
1088 | if (w->w_eb) { |
---|
1089 | DeleteElevatorBar (w->w_eb); |
---|
1090 | w->w_eb = CreateElevatorBar (w->w_fd, 0, 0, EWIDTH, |
---|
1091 | w->w_ws.height, VT_Gray50, 1, EB_VERTICAL, |
---|
1092 | EB_ARROWS, w->w_ebloc = 0, w->w_ebsize = EB_MAX, |
---|
1093 | VT_White); |
---|
1094 | if (w->w_eb == NULL) |
---|
1095 | adios (NULL, "CreateElevatorBar failed"); |
---|
1096 | } |
---|
1097 | |
---|
1098 | Redisplay (w, 1); |
---|
1099 | } |
---|
1100 | |
---|
1101 | |
---|
1102 | static int |
---|
1103 | REFser (int id, short wx, short wy, short ww, short wh) |
---|
1104 | { |
---|
1105 | short cx, cy, cw, ch; |
---|
1106 | register WINDOW *w; |
---|
1107 | |
---|
1108 | if (id < 0 || id >= numwins) |
---|
1109 | adios (NULL, "REFser on bogus window (%d)", id); |
---|
1110 | w = windows[id]; |
---|
1111 | if (w->w_fd == NOTOK) |
---|
1112 | adios (NULL, "REFser on closed window (%d)", id); |
---|
1113 | |
---|
1114 | |
---|
1115 | if (GetWindowState (w->w_fd, &w->w_ws) == NOTOK) |
---|
1116 | adios ("failed", "GetWindowState"); |
---|
1117 | |
---|
1118 | GetPermanentClipping (w->w_fd, &cx, &cy, &cw, &ch); |
---|
1119 | SetPermanentClipping (w->w_fd, wx, wy, ww, wh); |
---|
1120 | Redisplay (w, 1); |
---|
1121 | SetPermanentClipping (w->w_fd, cx, cy, cw, ch); |
---|
1122 | } |
---|
1123 | |
---|
1124 | |
---|
1125 | static void |
---|
1126 | Redisplay (WINDOW *w, int doeb) |
---|
1127 | { |
---|
1128 | register int y; |
---|
1129 | short sx; |
---|
1130 | register struct line *lp; |
---|
1131 | |
---|
1132 | if (w->w_fd == NOTOK) |
---|
1133 | return; |
---|
1134 | |
---|
1135 | sx = w->w_eb ? (EWIDTH + ESLOP) : 0; |
---|
1136 | w->w_height = w->w_ws.height / w->w_cheight; |
---|
1137 | if (w->w_height < 1) |
---|
1138 | w->w_height = 1; |
---|
1139 | |
---|
1140 | w->w_width = (w->w_ws.width - (w->w_eb ? (EWIDTH + ESLOP) : 0)) |
---|
1141 | / w->w_cwidth; |
---|
1142 | if (w->w_width < 1) |
---|
1143 | w->w_width = 1; |
---|
1144 | |
---|
1145 | SetPosition (w->w_fd, sx, 0); |
---|
1146 | SetColor (w->w_fd, VT_White); |
---|
1147 | PaintRectangleInterior (w->w_fd, w->w_ws.width, w->w_ws.height); |
---|
1148 | |
---|
1149 | if (w->w_head) { |
---|
1150 | SetColor (w->w_fd, VT_Black); |
---|
1151 | for (lp = w->w_top, y = 0; |
---|
1152 | lp && y < w->w_height; |
---|
1153 | w->w_bottom = lp, lp = lp->l_next, y++) { |
---|
1154 | SetPosition (w->w_fd, sx, y * w->w_cheight + w->w_cbase); |
---|
1155 | PaintString (w->w_fd, VT_STREND, lp->l_buf); |
---|
1156 | } |
---|
1157 | } |
---|
1158 | |
---|
1159 | if (w->w_eb) { |
---|
1160 | if ((y = EB_LOC (w)) != w->w_ebloc) |
---|
1161 | MoveElevator (w->w_eb, w->w_ebloc = y); |
---|
1162 | if ((y = EB_SIZE (w)) != w->w_ebsize) |
---|
1163 | SizeElevator (w->w_eb, w->w_ebsize = y); |
---|
1164 | if (doeb) |
---|
1165 | RefreshElevatorBar (w->w_eb); |
---|
1166 | } |
---|
1167 | |
---|
1168 | Flush (w->w_fd); |
---|
1169 | } |
---|
1170 | |
---|
1171 | |
---|
1172 | static int |
---|
1173 | EB_SIZE (WINDOW *w) |
---|
1174 | { |
---|
1175 | register int i; |
---|
1176 | |
---|
1177 | if (w->w_head == NULL) |
---|
1178 | return 0; |
---|
1179 | |
---|
1180 | if ((i = w->w_tail->l_no - w->w_head->l_no) <= 0) |
---|
1181 | return EB_MAX; |
---|
1182 | |
---|
1183 | return (((w->w_bottom->l_no - w->w_top->l_no) * EB_MAX) / i); |
---|
1184 | } |
---|
1185 | |
---|
1186 | |
---|
1187 | static int |
---|
1188 | EB_LOC (WINDOW *w) |
---|
1189 | { |
---|
1190 | register int i; |
---|
1191 | |
---|
1192 | if (w->w_head == NULL) |
---|
1193 | return 0; |
---|
1194 | |
---|
1195 | if ((i = w->w_tail->l_no - w->w_head->l_no) <= 0) |
---|
1196 | return EB_MAX; |
---|
1197 | |
---|
1198 | return (((w->w_top->l_no - w->w_head->l_no) * EB_MAX) / i); |
---|
1199 | } |
---|
1200 | |
---|
1201 | /* SIGNALS */ |
---|
1202 | |
---|
1203 | static void |
---|
1204 | SIGinit (void) |
---|
1205 | { |
---|
1206 | foreground (); |
---|
1207 | if (ioctl (fileno (stdin), TIOCGETP, (char *) &tio) == NOTOK) |
---|
1208 | adios ("failed", "ioctl TIOCGETP"); |
---|
1209 | if (ioctl (fileno (stdin), TIOCGETC, (char *) &tc) == NOTOK) |
---|
1210 | adios ("failed", "ioctl TIOCGETC"); |
---|
1211 | if (ioctl (fileno (stdin), TIOCGLTC, (char *) <c) == NOTOK) |
---|
1212 | adios ("failed", "ioctl TIOCGLTC"); |
---|
1213 | sideground (); |
---|
1214 | |
---|
1215 | SIGNAL (SIGHUP, SIGser); |
---|
1216 | SIGNAL (SIGINT, SIGser); |
---|
1217 | SIGNAL (SIGQUIT, SIGser); |
---|
1218 | } |
---|
1219 | |
---|
1220 | |
---|
1221 | static void |
---|
1222 | foreground (void) |
---|
1223 | { |
---|
1224 | #ifdef TIOCGPGRP |
---|
1225 | int pgrp, tpgrp; |
---|
1226 | SIGNAL_HANDLER tstat; |
---|
1227 | |
---|
1228 | if ((pgrp = getpgrp (0)) == NOTOK) |
---|
1229 | adios ("process group", "unable to determine"); |
---|
1230 | for (;;) { |
---|
1231 | if (ioctl (fileno (stdin), TIOCGPGRP, (char *) &tpgrp) == NOTOK) |
---|
1232 | adios ("tty's process group", "unable to determine"); |
---|
1233 | if (pgrp == tpgrp) |
---|
1234 | break; |
---|
1235 | |
---|
1236 | tstat = SIGNAL (SIGTTIN, SIG_DFL); |
---|
1237 | kill (0, SIGTTIN); |
---|
1238 | SIGNAL (SIGTTIN, tstat); |
---|
1239 | } |
---|
1240 | |
---|
1241 | SIGNAL (SIGTTIN, SIG_IGN); |
---|
1242 | SIGNAL (SIGTTOU, SIG_IGN); |
---|
1243 | SIGNAL (SIGTSTP, SIG_IGN); |
---|
1244 | #endif TIOCGPGRP |
---|
1245 | } |
---|
1246 | |
---|
1247 | |
---|
1248 | static void |
---|
1249 | sideground (void) |
---|
1250 | { |
---|
1251 | #ifdef TIOCGPGRP |
---|
1252 | SIGNAL (SIGTTIN, SIG_DFL); |
---|
1253 | SIGNAL (SIGTTOU, SIG_DFL); |
---|
1254 | SIGNAL (SIGTSTP, SIG_DFL); |
---|
1255 | #endif TIOCGPGRP |
---|
1256 | } |
---|
1257 | |
---|
1258 | |
---|
1259 | static int |
---|
1260 | ALRMser (int sig) |
---|
1261 | { |
---|
1262 | longjmp (PEERctx, DONE); |
---|
1263 | } |
---|
1264 | |
---|
1265 | |
---|
1266 | static int |
---|
1267 | PIPEser (int sig) |
---|
1268 | { |
---|
1269 | #ifndef RELIABLE_SIGNALS |
---|
1270 | SIGNAL (sig, SIG_IGN); |
---|
1271 | #endif |
---|
1272 | |
---|
1273 | adios (NULL, "lost peer"); |
---|
1274 | } |
---|
1275 | |
---|
1276 | |
---|
1277 | static int |
---|
1278 | SIGser (int sig) |
---|
1279 | { |
---|
1280 | #ifndef RELIABLE_SIGNALS |
---|
1281 | SIGNAL (sig, SIG_IGN); |
---|
1282 | #endif |
---|
1283 | |
---|
1284 | done (1); |
---|
1285 | } |
---|
1286 | |
---|
1287 | |
---|
1288 | void |
---|
1289 | done (int status) |
---|
1290 | { |
---|
1291 | if (dfd != NOTOK) |
---|
1292 | RemoveStatus (dfd); |
---|
1293 | |
---|
1294 | pFIN (); |
---|
1295 | |
---|
1296 | exit (status); |
---|
1297 | } |
---|
1298 | |
---|
1299 | |
---|
1300 | static void |
---|
1301 | adorn (char *what, char *fmt, ...) |
---|
1302 | { |
---|
1303 | va_list ap |
---|
1304 | char *cp; |
---|
1305 | |
---|
1306 | cp = invo_name; |
---|
1307 | invo_name = NULL; |
---|
1308 | |
---|
1309 | va_start(ap, fmt); |
---|
1310 | advertise (what, NULL, fmt, ap); |
---|
1311 | va_end(ap); |
---|
1312 | |
---|
1313 | invo_name = cp; |
---|
1314 | } |
---|
1315 | |
---|
1316 | |
---|
1317 | void |
---|
1318 | advertise (char *what, char *tail, va_list ap) |
---|
1319 | { |
---|
1320 | int eindex = errno; |
---|
1321 | char buffer[BUFSIZ], err[BUFSIZ]; |
---|
1322 | struct iovec iob[20]; |
---|
1323 | register struct iovec *iov = iob; |
---|
1324 | |
---|
1325 | fflush (stdout); |
---|
1326 | fflush (stderr); |
---|
1327 | |
---|
1328 | if (invo_name) { |
---|
1329 | iov->iov_len = strlen (iov->iov_base = invo_name); |
---|
1330 | iov++; |
---|
1331 | iov->iov_len = strlen (iov->iov_base = ": "); |
---|
1332 | iov++; |
---|
1333 | } |
---|
1334 | |
---|
1335 | vsnprintf (buffer, sizeof(buffer), fmt, ap); |
---|
1336 | iov->iov_len = strlen (iov->iov_base = buffer); |
---|
1337 | iov++; |
---|
1338 | if (what) { |
---|
1339 | if (*what) { |
---|
1340 | iov->iov_len = strlen (iov->iov_base = " "); |
---|
1341 | iov++; |
---|
1342 | iov->iov_len = strlen (iov->iov_base = what); |
---|
1343 | iov++; |
---|
1344 | iov->iov_len = strlen (iov->iov_base = ": "); |
---|
1345 | iov++; |
---|
1346 | } |
---|
1347 | if (!(iov->iov_base = strerror (eindex))) { |
---|
1348 | snprintf (err, sizeof(err), "unknown error %d", eindex); |
---|
1349 | iov->iov_base = err; |
---|
1350 | } |
---|
1351 | iov->iov_len = strlen (iov->iov_base); |
---|
1352 | iov++; |
---|
1353 | } |
---|
1354 | if (tail && *tail) { |
---|
1355 | iov->iov_len = strlen (iov->iov_base = ", "); |
---|
1356 | iov++; |
---|
1357 | iov->iov_len = strlen (iov->iov_base = tail); |
---|
1358 | iov++; |
---|
1359 | } |
---|
1360 | iov->iov_len = strlen (iov->iov_base = "\n"); |
---|
1361 | iov++; |
---|
1362 | |
---|
1363 | if (dfd != NOTOK) |
---|
1364 | DisplayVector (iob, iov - iob); |
---|
1365 | else |
---|
1366 | writev (fileno (stderr), iob, iov - iob); |
---|
1367 | } |
---|
1368 | |
---|
1369 | |
---|
1370 | static void |
---|
1371 | DisplayVector (struct iovec *iov, int n) |
---|
1372 | { |
---|
1373 | register int i; |
---|
1374 | register char *cp; |
---|
1375 | char buffer[BUFSIZ]; |
---|
1376 | |
---|
1377 | for (i = 0, cp = NULL; i < n; i++, iov++) { |
---|
1378 | snprintf (buffer, sizeof(buffer), "%*.*s", iov->iov_len, |
---|
1379 | iov->iov_len, iov->iov_base); |
---|
1380 | cp = add (buffer, cp); |
---|
1381 | } |
---|
1382 | |
---|
1383 | DisplayStatus (dfd, cp); |
---|
1384 | free (cp); |
---|
1385 | sleep (PAUSE); |
---|
1386 | RemoveStatus (dfd); |
---|
1387 | } |
---|