NFS - Fix panic if the readdir base offset is beyond the directory EOF
[dragonfly.git] / contrib / nvi / ip_cl / ip_cl.c
blob5137b3f56abc0a7ec4c99c5cf32a28f63be92862
1 /*-
2 * Copyright (c) 1996
3 * Keith Bostic. All rights reserved.
5 * See the LICENSE file for redistribution information.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "@(#)ip_cl.c 8.4 (Berkeley) 10/13/96";
12 #endif /* not lint */
14 #include <sys/types.h>
15 #include <sys/ioctl.h>
16 #include <sys/queue.h>
17 #include <sys/select.h>
19 #include <bitstring.h>
20 #include <ctype.h>
21 #include <curses.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
30 #include "../common/common.h"
31 #include "../ip/ip.h"
32 #include "pathnames.h"
34 size_t cols, rows; /* Screen columns, rows. */
35 int die; /* Child died. */
36 int i_fd, o_fd; /* Input/output fd's. */
37 int resize; /* Window resized. */
39 void arg_format __P((int *, char **[], int, int));
40 void attach __P((void));
41 void ip_cur_end __P((void));
42 void ip_cur_init __P((void));
43 void ip_read __P((void));
44 void ip_resize __P((void));
45 int ip_send __P((char *, IP_BUF *));
46 void ip_siginit __P((void));
47 int ip_trans __P((char *, size_t, size_t *));
48 void nomem __P((void));
49 void onchld __P((int));
50 void onintr __P((int));
51 void onwinch __P((int));
52 void trace __P((const char *, ...));
53 void usage __P((void));
55 int
56 main(argc, argv)
57 int argc;
58 char *argv[];
60 fd_set fdset;
61 pid_t pid;
62 size_t blen, len, skip;
63 int ch, nr, rpipe[2], wpipe[2];
64 char *bp;
66 while ((ch = getopt(argc, argv, "D")) != EOF)
67 switch (ch) {
68 case 'D':
69 attach();
70 break;
71 case '?':
72 default:
73 usage();
75 argc -= optind;
76 argv += optind;
79 * Open the communications pipes. The pipes are named from our
80 * viewpoint, so we read from rpipe[0] and write to wpipe[1].
81 * Vi reads from wpipe[0], and writes to rpipe[1].
83 if (pipe(rpipe) == -1 || pipe(wpipe) == -1) {
84 perror("ip_cl: pipe");
85 exit (1);
87 i_fd = rpipe[0];
88 o_fd = wpipe[1];
91 * Format our arguments, adding a -I to the list. The first file
92 * descriptor to the -I argument is vi's input, and the second is
93 * vi's output.
95 arg_format(&argc, &argv, wpipe[0], rpipe[1]);
97 /* Run vi. */
98 switch (pid = fork()) {
99 case -1: /* Error. */
100 perror("ip_cl: fork");
101 exit (1);
102 case 0: /* Vi. */
103 execv(VI, argv);
104 perror("ip_cl: execv ../build/nvi");
105 exit (1);
106 default: /* Ip_cl. */
107 break;
111 * Allocate initial input buffer.
112 * XXX
113 * We don't dynamically resize, so there better not be any individual
114 * messages larger than this buffer.
116 blen = 4 * 1024;
117 if ((bp = malloc(blen)) == NULL)
118 nomem();
120 /* Clear the file descriptor mask. */
121 FD_ZERO(&fdset);
123 /* Initialize signals. */
124 ip_siginit();
126 /* Initialize the curses screen. */
127 ip_cur_init();
129 /* The first thing vi wants is the screen size. */
130 ip_resize();
132 /* Main loop. */
133 for (len = 0;;) {
134 if (die)
135 break;
137 * XXX
138 * Race #1: if there's an event coming from vi that requires
139 * that we know what size the screen is, and we take a resize
140 * signal, we'll differ from vi in the size of the screen for
141 * that event. Fixing this will requires information attached
142 * to message as to what set of state was in place when the
143 * message was sent. Not hard, but not worth doing now.
145 * Race #2: we cycle, handling resize events until there aren't
146 * any waiting. We then do a select. If the resize signal
147 * arrives after we exit the loop but before we enter select,
148 * we'll wait on the user to enter a keystroke, handle it and
149 * then handle the resize.
151 while (resize) {
152 resize = 0;
153 ip_resize();
154 ip_cur_end();
155 ip_cur_init();
158 /* Wait until vi or the screen wants to talk. */
159 FD_SET(i_fd, &fdset);
160 FD_SET(STDIN_FILENO, &fdset);
161 errno = 0;
162 switch (select(i_fd + 1, &fdset, NULL, NULL, NULL)) {
163 case 0:
164 abort(); /* Timeout. */
165 /* NOTREACHED */
166 case -1:
167 if (errno == EINTR)
168 continue;
169 perror("ip_cl: select");
170 exit (1);
171 default:
172 break;
175 /* Read waiting tty characters and send them to vi. */
176 if (FD_ISSET(STDIN_FILENO, &fdset)) {
177 ip_read();
178 continue;
181 /* Read waiting vi messages and translate to curses calls. */
182 switch (nr = read(i_fd, bp + len, blen - len)) {
183 case 0:
184 continue;
185 case -1:
186 perror("ip_cl: read");
187 exit (1);
188 default:
189 break;
192 /* Parse to data end or partial message. */
193 for (len += nr, skip = 0; len > skip &&
194 ip_trans(bp + skip, len - skip, &skip) == 1;);
196 /* Copy any partial messages down in the buffer. */
197 len -= skip;
198 if (len > 0)
199 memmove(bp, bp + skip, len);
202 /* End the screen. */
203 ip_cur_end();
205 exit (0);
209 * ip_read --
210 * Read characters from the screen and send them to vi.
212 void
213 ip_read()
215 IP_BUF ipb;
216 int nr;
217 char bp[1024];
219 /* Read waiting tty characters. */
220 switch (nr = read(STDIN_FILENO, bp, sizeof(bp))) {
221 case 0:
222 return;
223 case -1:
224 perror("ip_cl: read");
225 exit (1);
226 default:
227 break;
230 ipb.code = IPO_STRING;
231 ipb.len = nr;
232 ipb.str = bp;
233 ip_send("s", &ipb);
237 * ip_trans --
238 * Translate vi messages into curses calls.
241 ip_trans(bp, len, skipp)
242 char *bp;
243 size_t len, *skipp;
245 IP_BUF ipb;
246 size_t cno, lno, nlen, oldy, oldx, spcnt;
247 int ch;
248 char *fmt, *p;
250 switch (bp[0]) {
251 case IPO_ADDSTR:
252 case IPO_RENAME:
253 fmt = "s";
254 break;
255 case IPO_BUSY:
256 fmt = "s1";
257 break;
258 case IPO_ATTRIBUTE:
259 case IPO_MOVE:
260 fmt = "12";
261 break;
262 case IPO_REWRITE:
263 fmt = "1";
264 break;
265 default:
266 fmt = "";
269 nlen = IPO_CODE_LEN;
270 p = bp + IPO_CODE_LEN;
271 for (; *fmt != '\0'; ++fmt)
272 switch (*fmt) {
273 case '1':
274 nlen += IPO_INT_LEN;
275 if (len < nlen)
276 return (0);
277 memcpy(&ipb.val1, p, IPO_INT_LEN);
278 ipb.val1 = ntohl(ipb.val1);
279 p += IPO_INT_LEN;
280 break;
281 case '2':
282 nlen += IPO_INT_LEN;
283 if (len < nlen)
284 return (0);
285 memcpy(&ipb.val2, p, IPO_INT_LEN);
286 ipb.val2 = ntohl(ipb.val2);
287 p += IPO_INT_LEN;
288 break;
289 case 's':
290 nlen += IPO_INT_LEN;
291 if (len < nlen)
292 return (0);
293 memcpy(&ipb.len, p, IPO_INT_LEN);
294 ipb.len = ntohl(ipb.len);
295 p += IPO_INT_LEN;
296 nlen += ipb.len;
297 if (len < nlen)
298 return (0);
299 ipb.str = p;
300 p += ipb.len;
301 break;
303 *skipp += nlen;
305 switch (bp[0]) {
306 case IPO_ADDSTR:
307 #ifdef TR
308 trace("addnstr {%.*s}\n", (int)ipb.len, ipb.str);
309 #endif
310 (void)addnstr(ipb.str, ipb.len);
311 break;
312 case IPO_ATTRIBUTE:
313 switch (ipb.val1) {
314 case SA_ALTERNATE:
315 #ifdef TR
316 trace("attr: alternate\n");
317 #endif
319 * XXX
320 * Nothing.
322 break;
323 case SA_INVERSE:
324 #ifdef TR
325 trace("attr: inverse\n");
326 #endif
327 if (ipb.val2)
328 (void)standout();
329 else
330 (void)standend();
331 break;
332 default:
333 abort();
334 /* NOTREACHED */
336 break;
337 case IPO_BELL:
338 #ifdef TR
339 trace("bell\n");
340 #endif
341 (void)write(1, "\007", 1); /* '\a' */
342 break;
343 case IPO_BUSY:
344 #ifdef TR
345 trace("busy {%.*s}\n", (int)ipb.len, ipb.str);
346 #endif
348 * XXX
349 * Nothing...
350 * ip_busy(ipb.str, ipb.len);
352 break;
353 case IPO_CLRTOEOL:
354 #ifdef TR
355 trace("clrtoeol\n");
356 #endif
357 clrtoeol();
358 break;
359 case IPO_DELETELN:
360 #ifdef TR
361 trace("deleteln\n");
362 #endif
363 deleteln();
364 break;
365 case IPO_INSERTLN:
366 #ifdef TR
367 trace("insertln\n");
368 #endif
369 insertln();
370 break;
371 case IPO_MOVE:
372 #ifdef TR
373 trace("move: %lu %lu\n", (u_long)ipb.val1, (u_long)ipb.val2);
374 #endif
375 (void)move(ipb.val1, ipb.val2);
376 break;
377 case IPO_REDRAW:
378 #ifdef TR
379 trace("redraw\n");
380 #endif
381 clearok(curscr, 1);
382 refresh();
383 break;
384 case IPO_REFRESH:
385 #ifdef TR
386 trace("refresh\n");
387 #endif
388 refresh();
389 break;
390 case IPO_RENAME:
391 #ifdef TR
392 trace("rename {%.*s}\n", (int)ipb.len, ipb.str);
393 #endif
395 * XXX
396 * Nothing...
397 * ip_rename(ipb.str, ipb.len);
399 break;
400 case IPO_REWRITE:
401 #ifdef TR
402 trace("rewrite {%lu}\n", (u_long)ipb.val1);
403 #endif
404 getyx(stdscr, oldy, oldx);
405 for (lno = ipb.val1, cno = spcnt = 0;;) {
406 (void)move(lno, cno);
407 ch = winch(stdscr);
408 if (isblank(ch))
409 ++spcnt;
410 else {
411 (void)move(lno, cno - spcnt);
412 for (; spcnt > 0; --spcnt)
413 (void)addch(' ');
414 (void)addch(ch);
416 if (++cno >= cols)
417 break;
419 (void)move(oldy, oldx);
420 break;
421 default:
423 * XXX: Protocol is out of sync?
425 abort();
428 return (1);
432 * arg_format
434 void
435 arg_format(argcp, argvp, i_fd, o_fd)
436 int *argcp, i_fd, o_fd;
437 char **argvp[];
439 char **largv, *iarg, *p;
441 /* Get space for the argument array and the -I argument. */
442 if ((iarg = malloc(64)) == NULL ||
443 (largv = malloc((*argcp + 3) * sizeof(char *))) == NULL) {
444 perror("ip_cl");
445 exit (1);
447 memcpy(largv + 2, *argvp, *argcp * sizeof(char *) + 1);
449 /* Reset argv[0] to be the exec'd program. */
450 if ((p = strrchr(VI, '/')) == NULL)
451 largv[0] = VI;
452 else
453 largv[0] = p + 1;
455 /* Create the -I argument. */
456 (void)sprintf(iarg, "-I%d%s%d", i_fd, ".", o_fd);
457 largv[1] = iarg;
459 /* Reset the argument array. */
460 *argvp = largv;
464 * ip_cur_init --
465 * Initialize the curses screen.
467 void
468 ip_cur_init()
471 * XXX
472 * This is 4BSD curses' specific -- if this is to be a real program
473 * we'll have to do all the stuff that we do in the cl directory to
474 * run with different curses variants.
476 if (initscr() == ERR) {
477 perror("ip_cl: initscr");
478 exit (1);
480 noecho();
481 nonl();
482 raw();
483 idlok(stdscr, 1);
487 * ip_cur_end --
488 * End the curses screen.
490 void
491 ip_cur_end()
493 (void)move(0, 0);
494 (void)deleteln();
495 (void)move(rows - 1, 0);
496 (void)refresh();
497 (void)endwin();
501 * ip_siginit --
502 * Initialize the signals.
504 void
505 ip_siginit()
507 /* We need to know if vi dies horribly. */
508 (void)signal(SIGCHLD, onchld);
510 /* We want to allow interruption at least for now. */
511 (void)signal(SIGINT, onintr);
513 #ifdef SIGWINCH
514 /* We need to know if the screen is resized. */
515 (void)signal(SIGWINCH, onwinch);
516 #endif
520 * ip_resize --
521 * Send the window size.
523 void
524 ip_resize()
526 struct winsize win;
527 IP_BUF ipb;
529 if (ioctl(STDERR_FILENO, TIOCGWINSZ, &win) == -1) {
530 perror("ip_cl: TIOCGWINSZ");
531 exit(1);
534 if (rows == win.ws_row && cols == win.ws_col)
535 return;
537 ipb.val1 = rows = win.ws_row;
538 ipb.val2 = cols = win.ws_col;
539 ipb.code = IPO_RESIZE;
540 ip_send("12", &ipb);
544 * ip_send --
545 * Construct and send an IP buffer.
548 ip_send(fmt, ipbp)
549 char *fmt;
550 IP_BUF *ipbp;
552 static char *bp;
553 static size_t blen;
554 size_t off;
555 u_int32_t ilen;
556 int nlen, n, nw;
557 char *p;
559 if (blen == 0 && (bp = malloc(blen = 512)) == NULL)
560 nomem();
562 p = bp;
563 nlen = 0;
564 *p++ = ipbp->code;
565 nlen += IPO_CODE_LEN;
567 if (fmt != NULL)
568 for (; *fmt != '\0'; ++fmt)
569 switch (*fmt) {
570 case '1': /* Value 1. */
571 ilen = htonl(ipbp->val1);
572 goto value;
573 case '2': /* Value 2. */
574 ilen = htonl(ipbp->val2);
575 value: nlen += IPO_INT_LEN;
576 if (nlen >= blen) {
577 blen = blen * 2 + nlen;
578 off = p - bp;
579 if ((bp = realloc(bp, blen)) == NULL)
580 nomem();
581 p = bp + off;
583 memmove(p, &ilen, IPO_INT_LEN);
584 p += IPO_INT_LEN;
585 break;
586 case 's': /* String. */
587 ilen = ipbp->len; /* XXX: conversion. */
588 ilen = htonl(ilen);
589 nlen += IPO_INT_LEN + ipbp->len;
590 if (nlen >= blen) {
591 blen = blen * 2 + nlen;
592 off = p - bp;
593 if ((bp = realloc(bp, blen)) == NULL)
594 nomem();
595 p = bp + off;
597 memmove(p, &ilen, IPO_INT_LEN);
598 p += IPO_INT_LEN;
599 memmove(p, ipbp->str, ipbp->len);
600 p += ipbp->len;
601 break;
603 #ifdef TR
604 trace("WROTE: ");
605 for (n = p - bp, p = bp; n > 0; --n, ++p)
606 if (isprint(*p))
607 (void)trace("%c", *p);
608 else
609 trace("<%x>", (u_char)*p);
610 trace("\n");
611 #endif
613 for (n = p - bp, p = bp; n > 0; n -= nw, p += nw)
614 if ((nw = write(o_fd, p, n)) < 0) {
615 perror("ip_cl: write");
616 exit(1);
619 return (0);
622 void
623 nomem()
625 perror("ip_cl");
626 exit (1);
630 * onchld --
631 * Handle SIGCHLD.
633 void
634 onchld(signo)
635 int signo;
637 die = 1;
639 #ifdef TR
640 trace("SIGCHLD\n");
641 #endif
643 /* Interrupt select if it's running. */
644 (void)kill(getpid(), SIGINT);
648 * onintr --
649 * Handle SIGINT.
651 void
652 onintr(signo)
653 int signo;
656 * If we receive an interrupt, we may have sent it ourselves.
657 * If not, die from the signal.
659 if (die)
660 return;
661 (void)signal(SIGINT, SIG_DFL);
662 kill(getpid(), SIGINT);
666 * onwinch --
667 * Handle SIGWINCH.
669 void
670 onwinch(signo)
671 int signo;
673 resize = 1;
676 void
677 attach()
679 int fd;
680 char ch;
682 (void)printf("process %lu waiting, enter <CR> to continue: ",
683 (u_long)getpid());
684 (void)fflush(stdout);
686 if ((fd = open(_PATH_TTY, O_RDONLY, 0)) < 0) {
687 perror(_PATH_TTY);
688 exit (1);;
690 do {
691 if (read(fd, &ch, 1) != 1) {
692 (void)close(fd);
693 return;
695 } while (ch != '\n' && ch != '\r');
696 (void)close(fd);
699 #ifdef TR
700 #ifdef __STDC__
701 #include <stdarg.h>
702 #else
703 #include <varargs.h>
704 #endif
707 * TR --
708 * debugging trace routine.
710 void
711 #ifdef __STDC__
712 trace(const char *fmt, ...)
713 #else
714 trace(fmt, va_alist)
715 char *fmt;
716 va_dcl
717 #endif
719 static FILE *tfp;
720 va_list ap;
722 if (tfp == NULL && (tfp = fopen(TR, "w")) == NULL)
723 tfp = stderr;
725 #ifdef __STDC__
726 va_start(ap, fmt);
727 #else
728 va_start(ap);
729 #endif
730 (void)vfprintf(tfp, fmt, ap);
731 va_end(ap);
733 (void)fflush(tfp);
735 #endif
737 void
738 usage()
740 (void)fprintf(stderr, "usage: ip_cl [-D]\n");
741 exit(1);