3 * Keith Bostic. All rights reserved.
5 * See the LICENSE file for redistribution information.
11 static const char sccsid
[] = "$Id: ip_read.c,v 8.21 2000/07/16 20:49:33 skimo Exp $ (Berkeley) $Date: 2000/07/16 20:49:33 $";
14 #include <sys/types.h>
15 #include <sys/queue.h>
18 #include <bitstring.h>
25 #include <netinet/in.h>
27 #include "../common/common.h"
28 #include "../ex/script.h"
29 #include "../ipc/ip.h"
32 extern GS
*__global_list
;
34 VIPFUNLIST
const vipfuns
[] = {
35 /* VI_C_BOL Cursor to start of line. */
37 /* VI_C_BOTTOM 2 /* Cursor to bottom. */
39 /* VI_C_DEL 3 /* Cursor delete. */
41 /* VI_C_DOWN Cursor down N lines: IPO_INT. */
43 /* VI_C_EOL 5 /* Cursor to end of line. */
45 /* VI_C_INSERT 6 /* Cursor: enter insert mode. */
47 /* VI_C_LEFT 7 /* Cursor left. */
49 /* VI_C_PGDOWN 8 /* Cursor down N pages: IPO_INT. */
51 /* VI_C_PGUP 9 /* Cursor up N lines: IPO_INT. */
53 /* VI_C_RIGHT 10 /* Cursor right. */
55 /* VI_C_SEARCH 11 /* Cursor: search: IPO_INT, IPO_STR. */
57 /* VI_C_SETTOP 12 /* Cursor: set screen top line: IPO_INT. */
59 /* VI_C_TOP 13 /* Cursor to top. */
61 /* VI_C_UP 14 /* Cursor up N lines: IPO_INT. */
63 /* VI_EDIT 15 /* Edit a file: IPO_STR. */
65 /* VI_EDITOPT 16 /* Edit option: 2 * IPO_STR, IPO_INT. */
67 /* VI_EDITSPLIT 17 /* Split to a file: IPO_STR. */
69 /* VI_EOF 18 /* End of input (NOT ^D). */
71 /* VI_ERR 19 /* Input error. */
75 /* VI_INTERRUPT 20 /* Interrupt. */
77 /* VI_MOUSE_MOVE 21 /* Mouse click move: IPO_INT, IPO_INT. */
79 /* VI_QUIT 22 /* Quit. */
81 /* VI_RESIZE Screen resize: IPO_INT, IPO_INT. */
83 /* VI_SEL_END 24 /* Select end: IPO_INT, IPO_INT. */
85 /* VI_SEL_START 25 /* Select start: IPO_INT, IPO_INT. */
87 /* VI_SIGHUP 26 /* SIGHUP. */
89 /* VI_SIGTERM 27 /* SIGTERM. */
91 /* VI_STRING Input string: IPO_STR. */
93 /* VI_TAG 29 /* Tag. */
95 /* VI_TAGAS 30 /* Tag to a string: IPO_STR. */
97 /* VI_TAGSPLIT 31 /* Split to a tag. */
99 /* VI_UNDO 32 /* Undo. */
101 /* VI_WQ 33 /* Write and quit. */
103 /* VI_WRITE 34 /* Write. */
105 /* VI_WRITEAS 35 /* Write as another file: IPO_STR. */
110 typedef enum { INP_OK
=0, INP_EOF
, INP_ERR
, INP_TIMEOUT
} input_t
;
112 static input_t ip_read
__P((SCR
*, IP_PRIVATE
*, struct timeval
*, int, int*));
113 static int ip_resize
__P((SCR
*, u_int32_t
, u_int32_t
));
114 static int ip_trans
__P((SCR
*, IP_PRIVATE
*, EVENT
*));
118 * Return a single event.
120 * PUBLIC: int ip_event __P((SCR *, EVENT *, u_int32_t, int));
123 ip_event(sp
, evp
, flags
, ms
)
129 return ip_wevent(sp
->wp
, sp
, evp
, flags
, ms
);
133 * XXX probably better to require new_window to send size
134 * so we never have to call ip_wevent with sp == NULL
137 * Return a single event.
139 * PUBLIC: int ip_wevent __P((WIN *, SCR *, EVENT *, u_int32_t, int));
142 ip_wevent(wp
, sp
, evp
, flags
, ms
)
150 struct timeval t
, *tp
;
154 if (LF_ISSET(EC_INTERRUPT
)) { /* XXX */
155 evp
->e_event
= E_TIMEOUT
;
159 ipp
= sp
== NULL
? WIPP(wp
) : IPP(sp
);
161 /* Discard the last command. */
162 if (ipp
->iskip
!= 0) {
163 ipp
->iblen
-= ipp
->iskip
;
164 memmove(ipp
->ibuf
, ipp
->ibuf
+ ipp
->iskip
, ipp
->iblen
);
168 termread
= F_ISSET(ipp
, IP_IN_EX
) ||
169 (sp
&& F_ISSET(sp
, SC_SCR_EXWROTE
));
171 /* Process possible remaining commands */
172 if (!termread
&& ipp
->iblen
>= IPO_CODE_LEN
&& ip_trans(sp
, ipp
, evp
))
179 t
.tv_sec
= ms
/ 1000;
180 t
.tv_usec
= (ms
% 1000) * 1000;
184 /* Read input events. */
186 switch (ip_read(sp
, ipp
, tp
, termread
, &nr
)) {
189 evp
->e_csp
= ipp
->tbuf
;
191 evp
->e_event
= E_STRING
;
192 } else if (!ip_trans(sp
, ipp
, evp
))
196 evp
->e_event
= E_EOF
;
199 evp
->e_event
= E_ERR
;
202 evp
->e_event
= E_TIMEOUT
;
214 * Read characters from the input.
217 ip_read(sp
, ipp
, tp
, termread
, nr
)
235 gp
= sp
== NULL
? __global_list
: sp
->gp
;
236 bp
= ipp
->ibuf
+ ipp
->iblen
;
237 blen
= sizeof(ipp
->ibuf
) - ipp
->iblen
;
238 fd
= termread
? ipp
->t_fd
: ipp
->i_fd
;
241 * 1: A read with an associated timeout, e.g., trying to complete
242 * a map sequence. If input exists, we fall into #2.
249 switch (select(fd
+ 1,
250 &rdfd
, NULL
, NULL
, tp
== NULL
? &poll
: tp
)) {
252 return (INP_TIMEOUT
);
263 * Select on the command input and scripting window file descriptors.
264 * It's ugly that we wait on scripting file descriptors here, but it's
265 * the only way to keep from locking out scripting windows.
267 if (sp
!= NULL
&& F_ISSET(gp
, G_SCRWIN
)) {
271 if (sscr_check_input(sp
, &rdfd
, maxfd
))
278 switch (*nr
= read(fd
, termread
? (char *)ipp
->tbuf
: bp
,
279 termread
? sizeof(ipp
->tbuf
)/sizeof(CHAR_T
)
284 case -1: /* Error or interrupt. */
286 msgq(sp
, M_SYSERR
, "input");
288 default: /* Input characters. */
289 if (!termread
) ipp
->iblen
+= *nr
;
291 CHAR2INT(sp
, (char *)ipp
->tbuf
, *nr
, wp
, wlen
);
292 MEMMOVEW(ipp
->tbuf
, wp
, wlen
);
302 * Translate messages into events.
305 ip_trans(sp
, ipp
, evp
)
315 if (ipp
->ibuf
[0] == CODE_OOB
||
316 ipp
->ibuf
[0] >= VI_EVENT_SUP
)
319 * XXX: Protocol is out of sync?
323 fmt
= vipfuns
[ipp
->ibuf
[0]-1].format
;
324 evp
->e_event
= vipfuns
[ipp
->ibuf
[0]-1].e_event
;
325 evp
->e_ipcom
= ipp
->ibuf
[0];
327 for (skip
= IPO_CODE_LEN
; *fmt
!= '\0'; ++fmt
)
331 if (ipp
->iblen
< skip
+ IPO_INT_LEN
)
333 memcpy(&val
, ipp
->ibuf
+ skip
, IPO_INT_LEN
);
343 if (ipp
->iblen
< skip
+ IPO_INT_LEN
)
345 memcpy(&val
, ipp
->ibuf
+ skip
, IPO_INT_LEN
);
348 if (ipp
->iblen
< skip
+ val
)
351 CHAR2INT(sp
, ipp
->ibuf
+ skip
, val
,
353 MEMCPYW(ipp
->tbuf
, wp
, wlen
);
354 evp
->e_str1
= ipp
->tbuf
;
357 CHAR2INT(sp
, ipp
->ibuf
+ skip
, val
,
359 MEMCPYW(ipp
->tbuf
, wp
, wlen
);
360 evp
->e_str2
= ipp
->tbuf
;
369 if (evp
->e_event
== E_WRESIZE
)
370 (void)ip_resize(sp
, evp
->e_val1
, evp
->e_val2
);
377 * Reset the options for a resize event.
380 ip_resize(sp
, lines
, columns
)
382 u_int32_t lines
, columns
;
389 * The IP screen has to know the lines and columns before anything
390 * else happens. So, we may not have a valid SCR pointer, and we
391 * have to deal with that.
395 OG_VAL(gp
, GO_LINES
) = OG_D_VAL(gp
, GO_LINES
) = lines
;
396 OG_VAL(gp
, GO_COLUMNS
) = OG_D_VAL(gp
, GO_COLUMNS
) = columns
;
400 rval
= api_opts_set(sp
, "lines", NULL
, lines
, 0);
401 if (api_opts_set(sp
, "columns", NULL
, columns
, 0))