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
11static 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
25static 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 */
33int
34ip_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 */
71int
72ip_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 */
92int
93ip_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 */
107int
108ip_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 */
124void
125ip_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 */
151int
152ip_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 */
168int
169ip_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 */
187int
188ip_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 */
222int
223ip_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 */
237int
238ip_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 */
254int
255ip_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 */
293int
294ip_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 */
317int
318ip_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 */
335int
336ip_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 */
354int
355ip_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 */
369void
370ip_usage()
371{
372#define USAGE "\
373usage: 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 */
382static int
383ip_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);
411value:				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