1 /*-
2  * Copyright (c) 1996
3  *	Keith Bostic.  All rights reserved.
4  *
5  * See the LICENSE file for redistribution information.
6  */
7 
8 #include "config.h"
9 
10 #ifndef lint
11 static const char sccsid[] = "@(#)ip_funcs.c	8.4 (Berkeley) 10/13/96";
12 #endif /* not lint */
13 
14 #include <sys/types.h>
15 #include <sys/queue.h>
16 #include <sys/time.h>
17 
18 #include <bitstring.h>
19 #include <stdio.h>
20 
21 #include "../common/common.h"
22 #include "../vi/vi.h"
23 #include "ip.h"
24 
25 static int ip_send __P((SCR *, char *, IP_BUF *));
26 
27 /*
28  * ip_addstr --
29  *	Add len bytes from the string at the cursor, advancing the cursor.
30  *
31  * PUBLIC: int ip_addstr __P((SCR *, const char *, size_t));
32  */
33 int
ip_addstr(sp,str,len)34 ip_addstr(sp, str, len)
35 	SCR *sp;
36 	const char *str;
37 	size_t len;
38 {
39 	IP_BUF ipb;
40 	IP_PRIVATE *ipp;
41 	int iv, rval;
42 
43 	ipp = IPP(sp);
44 
45 	/*
46 	 * If ex isn't in control, it's the last line of the screen and
47 	 * it's a split screen, use inverse video.
48 	 */
49 	iv = 0;
50 	if (!F_ISSET(sp, SC_SCR_EXWROTE) &&
51 	    ipp->row == LASTLINE(sp) && IS_SPLIT(sp)) {
52 		iv = 1;
53 		ip_attr(sp, SA_INVERSE, 1);
54 	}
55 	ipb.code = IPO_ADDSTR;
56 	ipb.len = len;
57 	ipb.str = str;
58 	rval = ip_send(sp, "s", &ipb);
59 
60 	if (iv)
61 		ip_attr(sp, SA_INVERSE, 0);
62 	return (rval);
63 }
64 
65 /*
66  * ip_attr --
67  *	Toggle a screen attribute on/off.
68  *
69  * PUBLIC: int ip_attr __P((SCR *, scr_attr_t, int));
70  */
71 int
ip_attr(sp,attribute,on)72 ip_attr(sp, attribute, on)
73 	SCR *sp;
74 	scr_attr_t attribute;
75 	int on;
76 {
77 	IP_BUF ipb;
78 
79 	ipb.code = IPO_ATTRIBUTE;
80 	ipb.val1 = attribute;
81 	ipb.val2 = on;
82 
83 	return (ip_send(sp, "12", &ipb));
84 }
85 
86 /*
87  * ip_baud --
88  *	Return the baud rate.
89  *
90  * PUBLIC: int ip_baud __P((SCR *, u_long *));
91  */
92 int
ip_baud(sp,ratep)93 ip_baud(sp, ratep)
94 	SCR *sp;
95 	u_long *ratep;
96 {
97 	*ratep = 9600;		/* XXX: Translation: fast. */
98 	return (0);
99 }
100 
101 /*
102  * ip_bell --
103  *	Ring the bell/flash the screen.
104  *
105  * PUBLIC: int ip_bell __P((SCR *));
106  */
107 int
ip_bell(sp)108 ip_bell(sp)
109 	SCR *sp;
110 {
111 	IP_BUF ipb;
112 
113 	ipb.code = IPO_BELL;
114 
115 	return (ip_send(sp, NULL, &ipb));
116 }
117 
118 /*
119  * ip_busy --
120  *	Display a busy message.
121  *
122  * PUBLIC: void ip_busy __P((SCR *, const char *, busy_t));
123  */
124 void
ip_busy(sp,str,bval)125 ip_busy(sp, str, bval)
126 	SCR *sp;
127 	const char *str;
128 	busy_t bval;
129 {
130 	IP_BUF ipb;
131 
132 	ipb.code = IPO_BUSY;
133 	if (str == NULL) {
134 		ipb.len = 0;
135 		ipb.str = "";
136 	} else {
137 		ipb.len = strlen(str);
138 		ipb.str = str;
139 	}
140 	ipb.val1 = bval;
141 
142 	(void)ip_send(sp, "s1", &ipb);
143 }
144 
145 /*
146  * ip_clrtoeol --
147  *	Clear from the current cursor to the end of the line.
148  *
149  * PUBLIC: int ip_clrtoeol __P((SCR *));
150  */
151 int
ip_clrtoeol(sp)152 ip_clrtoeol(sp)
153 	SCR *sp;
154 {
155 	IP_BUF ipb;
156 
157 	ipb.code = IPO_CLRTOEOL;
158 
159 	return (ip_send(sp, NULL, &ipb));
160 }
161 
162 /*
163  * ip_cursor --
164  *	Return the current cursor position.
165  *
166  * PUBLIC: int ip_cursor __P((SCR *, size_t *, size_t *));
167  */
168 int
ip_cursor(sp,yp,xp)169 ip_cursor(sp, yp, xp)
170 	SCR *sp;
171 	size_t *yp, *xp;
172 {
173 	IP_PRIVATE *ipp;
174 
175 	ipp = IPP(sp);
176 	*yp = ipp->row;
177 	*xp = ipp->col;
178 	return (0);
179 }
180 
181 /*
182  * ip_deleteln --
183  *	Delete the current line, scrolling all lines below it.
184  *
185  * PUBLIC: int ip_deleteln __P((SCR *));
186  */
187 int
ip_deleteln(sp)188 ip_deleteln(sp)
189 	SCR *sp;
190 {
191 	IP_BUF ipb;
192 
193 	/*
194 	 * This clause is required because the curses screen uses reverse
195 	 * video to delimit split screens.  If the screen does not do this,
196 	 * this code won't be necessary.
197 	 *
198 	 * If the bottom line was in reverse video, rewrite it in normal
199 	 * video before it's scrolled.
200 	 */
201 	if (!F_ISSET(sp, SC_SCR_EXWROTE) && IS_SPLIT(sp)) {
202 		ipb.code = IPO_REWRITE;
203 		ipb.val1 = RLNO(sp, LASTLINE(sp));
204 		if (ip_send(sp, "1", &ipb))
205 			return (1);
206 	}
207 
208 	/*
209 	 * The bottom line is expected to be blank after this operation,
210 	 * and other screens must support that semantic.
211 	 */
212 	ipb.code = IPO_DELETELN;
213 	return (ip_send(sp, NULL, &ipb));
214 }
215 
216 /*
217  * ip_ex_adjust --
218  *	Adjust the screen for ex.
219  *
220  * PUBLIC: int ip_ex_adjust __P((SCR *, exadj_t));
221  */
222 int
ip_ex_adjust(sp,action)223 ip_ex_adjust(sp, action)
224 	SCR *sp;
225 	exadj_t action;
226 {
227 	abort();
228 	/* NOTREACHED */
229 }
230 
231 /*
232  * ip_insertln --
233  *	Push down the current line, discarding the bottom line.
234  *
235  * PUBLIC: int ip_insertln __P((SCR *));
236  */
237 int
ip_insertln(sp)238 ip_insertln(sp)
239 	SCR *sp;
240 {
241 	IP_BUF ipb;
242 
243 	ipb.code = IPO_INSERTLN;
244 
245 	return (ip_send(sp, NULL, &ipb));
246 }
247 
248 /*
249  * ip_keyval --
250  *	Return the value for a special key.
251  *
252  * PUBLIC: int ip_keyval __P((SCR *, scr_keyval_t, CHAR_T *, int *));
253  */
254 int
ip_keyval(sp,val,chp,dnep)255 ip_keyval(sp, val, chp, dnep)
256 	SCR *sp;
257 	scr_keyval_t val;
258 	CHAR_T *chp;
259 	int *dnep;
260 {
261 	/*
262 	 * VEOF, VERASE and VKILL are required by POSIX 1003.1-1990,
263 	 * VWERASE is a 4BSD extension.
264 	 */
265 	switch (val) {
266 	case KEY_VEOF:
267 		*dnep = '\004';		/* ^D */
268 		break;
269 	case KEY_VERASE:
270 		*dnep = '\b';		/* ^H */
271 		break;
272 	case KEY_VKILL:
273 		*dnep = '\025';		/* ^U */
274 		break;
275 #ifdef VWERASE
276 	case KEY_VWERASE:
277 		*dnep = '\027';		/* ^W */
278 		break;
279 #endif
280 	default:
281 		*dnep = 1;
282 		break;
283 	}
284 	return (0);
285 }
286 
287 /*
288  * ip_move --
289  *	Move the cursor.
290  *
291  * PUBLIC: int ip_move __P((SCR *, size_t, size_t));
292  */
293 int
ip_move(sp,lno,cno)294 ip_move(sp, lno, cno)
295 	SCR *sp;
296 	size_t lno, cno;
297 {
298 	IP_PRIVATE *ipp;
299 	IP_BUF ipb;
300 
301 	ipp = IPP(sp);
302 	ipp->row = lno;
303 	ipp->col = cno;
304 
305 	ipb.code = IPO_MOVE;
306 	ipb.val1 = RLNO(sp, lno);
307 	ipb.val2 = cno;
308 	return (ip_send(sp, "12", &ipb));
309 }
310 
311 /*
312  * ip_refresh --
313  *	Refresh the screen.
314  *
315  * PUBLIC: int ip_refresh __P((SCR *, int));
316  */
317 int
ip_refresh(sp,repaint)318 ip_refresh(sp, repaint)
319 	SCR *sp;
320 	int repaint;
321 {
322 	IP_BUF ipb;
323 
324 	ipb.code = repaint ? IPO_REDRAW : IPO_REFRESH;
325 
326 	return (ip_send(sp, NULL, &ipb));
327 }
328 
329 /*
330  * ip_rename --
331  *	Rename the file.
332  *
333  * PUBLIC: int ip_rename __P((SCR *));
334  */
335 int
ip_rename(sp)336 ip_rename(sp)
337 	SCR *sp;
338 {
339 	IP_BUF ipb;
340 
341 	ipb.code = IPO_RENAME;
342 	ipb.len = strlen(sp->frp->name);
343 	ipb.str = sp->frp->name;
344 
345 	return (ip_send(sp, "s", &ipb));
346 }
347 
348 /*
349  * ip_suspend --
350  *	Suspend a screen.
351  *
352  * PUBLIC: int ip_suspend __P((SCR *, int *));
353  */
354 int
ip_suspend(sp,allowedp)355 ip_suspend(sp, allowedp)
356 	SCR *sp;
357 	int *allowedp;
358 {
359 	*allowedp = 0;
360 	return (0);
361 }
362 
363 /*
364  * ip_usage --
365  *      Print out the ip usage messages.
366  *
367  * PUBLIC: void ip_usage __P((void));
368  */
369 void
ip_usage()370 ip_usage()
371 {
372 #define USAGE "\
373 usage: vi [-eFlRrSv] [-c command] [-I ifd.ofd] [-t tag] [-w size] [file ...]\n"
374         (void)fprintf(stderr, "%s", USAGE);
375 #undef  USAGE
376 }
377 
378 /*
379  * ip_send --
380  *	Construct and send an IP buffer.
381  */
382 static int
ip_send(sp,fmt,ipbp)383 ip_send(sp, fmt, ipbp)
384 	SCR *sp;
385 	char *fmt;
386 	IP_BUF *ipbp;
387 {
388 	IP_PRIVATE *ipp;
389 	size_t blen, off;
390 	u_int32_t ilen;
391 	int nlen, n, nw, rval;
392 	char *bp, *p;
393 
394 	ipp = IPP(sp);
395 
396 	GET_SPACE_RET(sp, bp, blen, 128);
397 
398 	p = bp;
399 	nlen = 0;
400 	*p++ = ipbp->code;
401 	nlen += IPO_CODE_LEN;
402 
403 	if (fmt != NULL)
404 		for (; *fmt != '\0'; ++fmt)
405 			switch (*fmt) {
406 			case '1':			/* Value 1. */
407 				ilen = htonl(ipbp->val1);
408 				goto value;
409 			case '2':			/* Value 2. */
410 				ilen = htonl(ipbp->val2);
411 value:				nlen += IPO_INT_LEN;
412 				off = p - bp;
413 				ADD_SPACE_RET(sp, bp, blen, nlen);
414 				p = bp + off;
415 				memmove(p, &ilen, IPO_INT_LEN);
416 				p += IPO_INT_LEN;
417 				break;
418 			case 's':			/* String. */
419 				ilen = ipbp->len;	/* XXX: conversion. */
420 				ilen = htonl(ilen);
421 				nlen += IPO_INT_LEN + ipbp->len;
422 				off = p - bp;
423 				ADD_SPACE_RET(sp, bp, blen, nlen);
424 				p = bp + off;
425 				memmove(p, &ilen, IPO_INT_LEN);
426 				p += IPO_INT_LEN;
427 				memmove(p, ipbp->str, ipbp->len);
428 				p += ipbp->len;
429 				break;
430 			}
431 
432 
433 	rval = 0;
434 	for (n = p - bp, p = bp; n > 0; n -= nw, p += nw)
435 		if ((nw = write(ipp->o_fd, p, n)) < 0) {
436 			rval = 1;
437 			break;
438 		}
439 
440 	FREE_SPACE(sp, bp, blen);
441 
442 	return (rval);
443 }
444