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.23 2001/06/25 15:19:24 skimo Exp $ (Berkeley) $Date: 2001/06/25 15:19:24 $";
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(SCR
*sp
, EVENT
*evp
, u_int32_t flags
, int ms
)
125 return ip_wevent(sp
->wp
, sp
, evp
, flags
, ms
);
129 * XXX probably better to require new_window to send size
130 * so we never have to call ip_wevent with sp == NULL
133 * Return a single event.
135 * PUBLIC: int ip_wevent __P((WIN *, SCR *, EVENT *, u_int32_t, int));
138 ip_wevent(WIN
*wp
, SCR
*sp
, EVENT
*evp
, u_int32_t flags
, int ms
)
141 struct timeval t
, *tp
;
145 if (LF_ISSET(EC_INTERRUPT
)) { /* XXX */
146 evp
->e_event
= E_TIMEOUT
;
150 ipp
= sp
== NULL
? WIPP(wp
) : IPP(sp
);
152 /* Discard the last command. */
153 if (ipp
->iskip
!= 0) {
154 ipp
->iblen
-= ipp
->iskip
;
155 memmove(ipp
->ibuf
, ipp
->ibuf
+ ipp
->iskip
, ipp
->iblen
);
159 termread
= F_ISSET(ipp
, IP_IN_EX
) ||
160 (sp
&& F_ISSET(sp
, SC_SCR_EXWROTE
));
162 /* Process possible remaining commands */
163 if (!termread
&& ipp
->iblen
>= IPO_CODE_LEN
&& ip_trans(sp
, ipp
, evp
))
170 t
.tv_sec
= ms
/ 1000;
171 t
.tv_usec
= (ms
% 1000) * 1000;
175 /* Read input events. */
177 switch (ip_read(sp
, ipp
, tp
, termread
, &nr
)) {
180 evp
->e_csp
= ipp
->tbuf
;
182 evp
->e_event
= E_STRING
;
183 } else if (!ip_trans(sp
, ipp
, evp
))
187 evp
->e_event
= E_EOF
;
190 evp
->e_event
= E_ERR
;
193 evp
->e_event
= E_TIMEOUT
;
205 * Read characters from the input.
208 ip_read(SCR
*sp
, IP_PRIVATE
*ipp
, struct timeval
*tp
, int termread
, int *nr
)
221 gp
= sp
== NULL
? __global_list
: sp
->gp
;
222 bp
= ipp
->ibuf
+ ipp
->iblen
;
223 blen
= sizeof(ipp
->ibuf
) - ipp
->iblen
;
224 fd
= termread
? ipp
->t_fd
: ipp
->i_fd
;
227 * 1: A read with an associated timeout, e.g., trying to complete
228 * a map sequence. If input exists, we fall into #2.
235 switch (select(fd
+ 1,
236 &rdfd
, NULL
, NULL
, tp
== NULL
? &poll
: tp
)) {
238 return (INP_TIMEOUT
);
249 * Select on the command input and scripting window file descriptors.
250 * It's ugly that we wait on scripting file descriptors here, but it's
251 * the only way to keep from locking out scripting windows.
253 if (sp
!= NULL
&& F_ISSET(gp
, G_SCRWIN
)) {
257 if (sscr_check_input(sp
, &rdfd
, maxfd
))
264 switch (*nr
= read(fd
, termread
? (char *)ipp
->tbuf
: bp
,
265 termread
? sizeof(ipp
->tbuf
)/sizeof(CHAR_T
)
270 case -1: /* Error or interrupt. */
272 msgq(sp
, M_SYSERR
, "input");
274 default: /* Input characters. */
275 if (!termread
) ipp
->iblen
+= *nr
;
277 CHAR2INT(sp
, (char *)ipp
->tbuf
, *nr
, wp
, wlen
);
278 MEMMOVEW(ipp
->tbuf
, wp
, wlen
);
288 * Translate messages into events.
291 ip_trans(SCR
*sp
, IP_PRIVATE
*ipp
, EVENT
*evp
)
298 if (ipp
->ibuf
[0] == CODE_OOB
||
299 ipp
->ibuf
[0] >= VI_EVENT_SUP
)
302 * XXX: Protocol is out of sync?
306 fmt
= vipfuns
[ipp
->ibuf
[0]-1].format
;
307 evp
->e_event
= vipfuns
[ipp
->ibuf
[0]-1].e_event
;
308 evp
->e_ipcom
= ipp
->ibuf
[0];
310 for (skip
= IPO_CODE_LEN
; *fmt
!= '\0'; ++fmt
)
314 if (ipp
->iblen
< skip
+ IPO_INT_LEN
)
316 memcpy(&val
, ipp
->ibuf
+ skip
, IPO_INT_LEN
);
326 if (ipp
->iblen
< skip
+ IPO_INT_LEN
)
328 memcpy(&val
, ipp
->ibuf
+ skip
, IPO_INT_LEN
);
331 if (ipp
->iblen
< skip
+ val
)
334 CHAR2INT(sp
, ipp
->ibuf
+ skip
, val
,
336 MEMCPYW(ipp
->tbuf
, wp
, wlen
);
337 evp
->e_str1
= ipp
->tbuf
;
340 CHAR2INT(sp
, ipp
->ibuf
+ skip
, val
,
342 MEMCPYW(ipp
->tbuf
, wp
, wlen
);
343 evp
->e_str2
= ipp
->tbuf
;
352 if (evp
->e_event
== E_WRESIZE
)
353 (void)ip_resize(sp
, evp
->e_val1
, evp
->e_val2
);
360 * Reset the options for a resize event.
363 ip_resize(SCR
*sp
, u_int32_t lines
, u_int32_t columns
)
370 * The IP screen has to know the lines and columns before anything
371 * else happens. So, we may not have a valid SCR pointer, and we
372 * have to deal with that.
376 OG_VAL(gp
, GO_LINES
) = OG_D_VAL(gp
, GO_LINES
) = lines
;
377 OG_VAL(gp
, GO_COLUMNS
) = OG_D_VAL(gp
, GO_COLUMNS
) = columns
;
381 rval
= api_opts_set(sp
, L("lines"), NULL
, lines
, 0);
382 if (api_opts_set(sp
, L("columns"), NULL
, columns
, 0))