5 * Keith Bostic. All rights reserved.
7 * See the LICENSE file for redistribution information.
13 static const char sccsid
[] = "Id: ip_read.c,v 8.23 2001/06/25 15:19:24 skimo Exp (Berkeley) Date: 2001/06/25 15:19:24";
16 #include <sys/types.h>
17 #include <sys/queue.h>
20 #include <bitstring.h>
27 #include <netinet/in.h>
29 #include "../common/common.h"
30 #include "../ex/script.h"
31 #include "../ipc/ip.h"
34 extern GS
*__global_list
;
36 VIPFUNLIST
const vipfuns
[] = {
37 /* VI_C_BOL Cursor to start of line. */
39 /* VI_C_BOTTOM 2 /* Cursor to bottom. */
41 /* VI_C_DEL 3 /* Cursor delete. */
43 /* VI_C_DOWN Cursor down N lines: IPO_INT. */
45 /* VI_C_EOL 5 /* Cursor to end of line. */
47 /* VI_C_INSERT 6 /* Cursor: enter insert mode. */
49 /* VI_C_LEFT 7 /* Cursor left. */
51 /* VI_C_PGDOWN 8 /* Cursor down N pages: IPO_INT. */
53 /* VI_C_PGUP 9 /* Cursor up N lines: IPO_INT. */
55 /* VI_C_RIGHT 10 /* Cursor right. */
57 /* VI_C_SEARCH 11 /* Cursor: search: IPO_INT, IPO_STR. */
59 /* VI_C_SETTOP 12 /* Cursor: set screen top line: IPO_INT. */
61 /* VI_C_TOP 13 /* Cursor to top. */
63 /* VI_C_UP 14 /* Cursor up N lines: IPO_INT. */
65 /* VI_EDIT 15 /* Edit a file: IPO_STR. */
67 /* VI_EDITOPT 16 /* Edit option: 2 * IPO_STR, IPO_INT. */
69 /* VI_EDITSPLIT 17 /* Split to a file: IPO_STR. */
71 /* VI_EOF 18 /* End of input (NOT ^D). */
73 /* VI_ERR 19 /* Input error. */
77 /* VI_INTERRUPT 20 /* Interrupt. */
79 /* VI_MOUSE_MOVE 21 /* Mouse click move: IPO_INT, IPO_INT. */
81 /* VI_QUIT 22 /* Quit. */
83 /* VI_RESIZE Screen resize: IPO_INT, IPO_INT. */
85 /* VI_SEL_END 24 /* Select end: IPO_INT, IPO_INT. */
87 /* VI_SEL_START 25 /* Select start: IPO_INT, IPO_INT. */
89 /* VI_SIGHUP 26 /* SIGHUP. */
91 /* VI_SIGTERM 27 /* SIGTERM. */
93 /* VI_STRING Input string: IPO_STR. */
95 /* VI_TAG 29 /* Tag. */
97 /* VI_TAGAS 30 /* Tag to a string: IPO_STR. */
99 /* VI_TAGSPLIT 31 /* Split to a tag. */
101 /* VI_UNDO 32 /* Undo. */
103 /* VI_WQ 33 /* Write and quit. */
105 /* VI_WRITE 34 /* Write. */
107 /* VI_WRITEAS 35 /* Write as another file: IPO_STR. */
112 typedef enum { INP_OK
=0, INP_EOF
, INP_ERR
, INP_TIMEOUT
} input_t
;
114 static input_t ip_read
__P((SCR
*, IP_PRIVATE
*, struct timeval
*, int, int*));
115 static int ip_resize
__P((SCR
*, u_int32_t
, u_int32_t
));
116 static int ip_trans
__P((SCR
*, IP_PRIVATE
*, EVENT
*));
120 * Return a single event.
122 * PUBLIC: int ip_event __P((SCR *, EVENT *, u_int32_t, int));
125 ip_event(SCR
*sp
, EVENT
*evp
, u_int32_t flags
, int ms
)
127 return ip_wevent(sp
->wp
, sp
, evp
, flags
, ms
);
131 * XXX probably better to require new_window to send size
132 * so we never have to call ip_wevent with sp == NULL
135 * Return a single event.
137 * PUBLIC: int ip_wevent __P((WIN *, SCR *, EVENT *, u_int32_t, int));
140 ip_wevent(WIN
*wp
, SCR
*sp
, EVENT
*evp
, u_int32_t flags
, int ms
)
143 struct timeval t
, *tp
;
147 if (LF_ISSET(EC_INTERRUPT
)) { /* XXX */
148 evp
->e_event
= E_TIMEOUT
;
152 ipp
= sp
== NULL
? WIPP(wp
) : IPP(sp
);
154 /* Discard the last command. */
155 if (ipp
->iskip
!= 0) {
156 ipp
->iblen
-= ipp
->iskip
;
157 memmove(ipp
->ibuf
, ipp
->ibuf
+ ipp
->iskip
, ipp
->iblen
);
161 termread
= F_ISSET(ipp
, IP_IN_EX
) ||
162 (sp
&& F_ISSET(sp
, SC_SCR_EXWROTE
));
164 /* Process possible remaining commands */
165 if (!termread
&& ipp
->iblen
>= IPO_CODE_LEN
&& ip_trans(sp
, ipp
, evp
))
172 t
.tv_sec
= ms
/ 1000;
173 t
.tv_usec
= (ms
% 1000) * 1000;
177 /* Read input events. */
179 switch (ip_read(sp
, ipp
, tp
, termread
, &nr
)) {
182 evp
->e_csp
= ipp
->tbuf
;
184 evp
->e_event
= E_STRING
;
185 } else if (!ip_trans(sp
, ipp
, evp
))
189 evp
->e_event
= E_EOF
;
192 evp
->e_event
= E_ERR
;
195 evp
->e_event
= E_TIMEOUT
;
207 * Read characters from the input.
210 ip_read(SCR
*sp
, IP_PRIVATE
*ipp
, struct timeval
*tp
, int termread
, int *nr
)
223 gp
= sp
== NULL
? __global_list
: sp
->gp
;
224 bp
= ipp
->ibuf
+ ipp
->iblen
;
225 blen
= sizeof(ipp
->ibuf
) - ipp
->iblen
;
226 fd
= termread
? ipp
->t_fd
: ipp
->i_fd
;
229 * 1: A read with an associated timeout, e.g., trying to complete
230 * a map sequence. If input exists, we fall into #2.
237 switch (select(fd
+ 1,
238 &rdfd
, NULL
, NULL
, tp
== NULL
? &poll
: tp
)) {
240 return (INP_TIMEOUT
);
251 * Select on the command input and scripting window file descriptors.
252 * It's ugly that we wait on scripting file descriptors here, but it's
253 * the only way to keep from locking out scripting windows.
255 if (sp
!= NULL
&& F_ISSET(gp
, G_SCRWIN
)) {
259 if (sscr_check_input(sp
, &rdfd
, maxfd
))
266 switch (*nr
= read(fd
, termread
? (char *)ipp
->tbuf
: bp
,
267 termread
? sizeof(ipp
->tbuf
)/sizeof(CHAR_T
)
272 case -1: /* Error or interrupt. */
274 msgq(sp
, M_SYSERR
, "input");
276 default: /* Input characters. */
277 if (!termread
) ipp
->iblen
+= *nr
;
279 CHAR2INT(sp
, (char *)ipp
->tbuf
, *nr
, wp
, wlen
);
280 MEMMOVEW(ipp
->tbuf
, wp
, wlen
);
290 * Translate messages into events.
293 ip_trans(SCR
*sp
, IP_PRIVATE
*ipp
, EVENT
*evp
)
300 if (ipp
->ibuf
[0] == CODE_OOB
||
301 ipp
->ibuf
[0] >= VI_EVENT_SUP
)
304 * XXX: Protocol is out of sync?
308 fmt
= vipfuns
[ipp
->ibuf
[0]-1].format
;
309 evp
->e_event
= vipfuns
[ipp
->ibuf
[0]-1].e_event
;
310 evp
->e_ipcom
= ipp
->ibuf
[0];
312 for (skip
= IPO_CODE_LEN
; *fmt
!= '\0'; ++fmt
)
316 if (ipp
->iblen
< skip
+ IPO_INT_LEN
)
318 memcpy(&val
, ipp
->ibuf
+ skip
, IPO_INT_LEN
);
328 if (ipp
->iblen
< skip
+ IPO_INT_LEN
)
330 memcpy(&val
, ipp
->ibuf
+ skip
, IPO_INT_LEN
);
333 if (ipp
->iblen
< skip
+ val
)
336 CHAR2INT(sp
, ipp
->ibuf
+ skip
, val
,
338 MEMCPYW(ipp
->tbuf
, wp
, wlen
);
339 evp
->e_str1
= ipp
->tbuf
;
342 CHAR2INT(sp
, ipp
->ibuf
+ skip
, val
,
344 MEMCPYW(ipp
->tbuf
, wp
, wlen
);
345 evp
->e_str2
= ipp
->tbuf
;
354 if (evp
->e_event
== E_WRESIZE
)
355 (void)ip_resize(sp
, evp
->e_val1
, evp
->e_val2
);
362 * Reset the options for a resize event.
365 ip_resize(SCR
*sp
, u_int32_t lines
, u_int32_t columns
)
372 * The IP screen has to know the lines and columns before anything
373 * else happens. So, we may not have a valid SCR pointer, and we
374 * have to deal with that.
378 OG_VAL(gp
, GO_LINES
) = OG_D_VAL(gp
, GO_LINES
) = lines
;
379 OG_VAL(gp
, GO_COLUMNS
) = OG_D_VAL(gp
, GO_COLUMNS
) = columns
;
383 rval
= api_opts_set(sp
, L("lines"), NULL
, lines
, 0);
384 if (api_opts_set(sp
, L("columns"), NULL
, columns
, 0))