xref: /freebsd-src/contrib/nvi/common/line.c (revision 110d525ec6188f3c9dc4f54c4bc1cced2f7184cd)
1b8ba871bSPeter Wemm /*-
2b8ba871bSPeter Wemm  * Copyright (c) 1992, 1993, 1994
3b8ba871bSPeter Wemm  *	The Regents of the University of California.  All rights reserved.
4b8ba871bSPeter Wemm  * Copyright (c) 1992, 1993, 1994, 1995, 1996
5b8ba871bSPeter Wemm  *	Keith Bostic.  All rights reserved.
6b8ba871bSPeter Wemm  *
7b8ba871bSPeter Wemm  * See the LICENSE file for redistribution information.
8b8ba871bSPeter Wemm  */
9b8ba871bSPeter Wemm 
10b8ba871bSPeter Wemm #include "config.h"
11b8ba871bSPeter Wemm 
12b8ba871bSPeter Wemm #include <sys/types.h>
13b8ba871bSPeter Wemm #include <sys/queue.h>
14b8ba871bSPeter Wemm #include <sys/time.h>
15b8ba871bSPeter Wemm 
16b8ba871bSPeter Wemm #include <bitstring.h>
17b8ba871bSPeter Wemm #include <errno.h>
18b8ba871bSPeter Wemm #include <limits.h>
19b8ba871bSPeter Wemm #include <stdio.h>
20b8ba871bSPeter Wemm #include <string.h>
21b8ba871bSPeter Wemm 
22b8ba871bSPeter Wemm #include "common.h"
23b8ba871bSPeter Wemm #include "../vi/vi.h"
24b8ba871bSPeter Wemm 
25c271fa92SBaptiste Daroussin static int scr_update(SCR *, recno_t, lnop_t, int);
26b8ba871bSPeter Wemm 
27b8ba871bSPeter Wemm /*
28b8ba871bSPeter Wemm  * db_eget --
29b8ba871bSPeter Wemm  *	Front-end to db_get, special case handling for empty files.
30b8ba871bSPeter Wemm  *
31c271fa92SBaptiste Daroussin  * PUBLIC: int db_eget(SCR *, recno_t, CHAR_T **, size_t *, int *);
32b8ba871bSPeter Wemm  */
33b8ba871bSPeter Wemm int
db_eget(SCR * sp,recno_t lno,CHAR_T ** pp,size_t * lenp,int * isemptyp)34*110d525eSBaptiste Daroussin db_eget(SCR *sp,
35f0957ccaSPeter Wemm 	recno_t lno,				/* Line number. */
36f0957ccaSPeter Wemm 	CHAR_T **pp,				/* Pointer store. */
37f0957ccaSPeter Wemm 	size_t *lenp,				/* Length store. */
38f0957ccaSPeter Wemm 	int *isemptyp)
39b8ba871bSPeter Wemm {
40b8ba871bSPeter Wemm 	recno_t l1;
41b8ba871bSPeter Wemm 
42b8ba871bSPeter Wemm 	if (isemptyp != NULL)
43b8ba871bSPeter Wemm 		*isemptyp = 0;
44b8ba871bSPeter Wemm 
45b8ba871bSPeter Wemm 	/* If the line exists, simply return it. */
46b8ba871bSPeter Wemm 	if (!db_get(sp, lno, 0, pp, lenp))
47b8ba871bSPeter Wemm 		return (0);
48b8ba871bSPeter Wemm 
49b8ba871bSPeter Wemm 	/*
50b8ba871bSPeter Wemm 	 * If the user asked for line 0 or line 1, i.e. the only possible
51b8ba871bSPeter Wemm 	 * line in an empty file, find the last line of the file; db_last
52b8ba871bSPeter Wemm 	 * fails loudly.
53b8ba871bSPeter Wemm 	 */
54b8ba871bSPeter Wemm 	if ((lno == 0 || lno == 1) && db_last(sp, &l1))
55b8ba871bSPeter Wemm 		return (1);
56b8ba871bSPeter Wemm 
57b8ba871bSPeter Wemm 	/* If the file isn't empty, fail loudly. */
58f0957ccaSPeter Wemm 	if ((lno != 0 && lno != 1) || l1 != 0) {
59b8ba871bSPeter Wemm 		db_err(sp, lno);
60b8ba871bSPeter Wemm 		return (1);
61b8ba871bSPeter Wemm 	}
62b8ba871bSPeter Wemm 
63b8ba871bSPeter Wemm 	if (isemptyp != NULL)
64b8ba871bSPeter Wemm 		*isemptyp = 1;
65b8ba871bSPeter Wemm 
66b8ba871bSPeter Wemm 	return (1);
67b8ba871bSPeter Wemm }
68b8ba871bSPeter Wemm 
69b8ba871bSPeter Wemm /*
70b8ba871bSPeter Wemm  * db_get --
71b8ba871bSPeter Wemm  *	Look in the text buffers for a line, followed by the cache, followed
72b8ba871bSPeter Wemm  *	by the database.
73b8ba871bSPeter Wemm  *
74c271fa92SBaptiste Daroussin  * PUBLIC: int db_get(SCR *, recno_t, u_int32_t, CHAR_T **, size_t *);
75b8ba871bSPeter Wemm  */
76b8ba871bSPeter Wemm int
db_get(SCR * sp,recno_t lno,u_int32_t flags,CHAR_T ** pp,size_t * lenp)77*110d525eSBaptiste Daroussin db_get(SCR *sp,
78f0957ccaSPeter Wemm 	recno_t lno,				/* Line number. */
79f0957ccaSPeter Wemm 	u_int32_t flags,
80f0957ccaSPeter Wemm 	CHAR_T **pp,				/* Pointer store. */
81f0957ccaSPeter Wemm 	size_t *lenp)				/* Length store. */
82b8ba871bSPeter Wemm {
83b8ba871bSPeter Wemm 	DBT data, key;
84b8ba871bSPeter Wemm 	EXF *ep;
85b8ba871bSPeter Wemm 	TEXT *tp;
86b8ba871bSPeter Wemm 	recno_t l1, l2;
87f0957ccaSPeter Wemm 	CHAR_T *wp;
88f0957ccaSPeter Wemm 	size_t wlen;
89b8ba871bSPeter Wemm 
90b8ba871bSPeter Wemm 	/*
91b8ba871bSPeter Wemm 	 * The underlying recno stuff handles zero by returning NULL, but
92b8ba871bSPeter Wemm 	 * have to have an OOB condition for the look-aside into the input
93b8ba871bSPeter Wemm 	 * buffer anyway.
94b8ba871bSPeter Wemm 	 */
95b8ba871bSPeter Wemm 	if (lno == 0)
96b8ba871bSPeter Wemm 		goto err1;
97b8ba871bSPeter Wemm 
98b8ba871bSPeter Wemm 	/* Check for no underlying file. */
99b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
100b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
101b8ba871bSPeter Wemm 		goto err3;
102b8ba871bSPeter Wemm 	}
103b8ba871bSPeter Wemm 
104b8ba871bSPeter Wemm 	if (LF_ISSET(DBG_NOCACHE))
105b8ba871bSPeter Wemm 		goto nocache;
106b8ba871bSPeter Wemm 
107b8ba871bSPeter Wemm 	/*
108b8ba871bSPeter Wemm 	 * Look-aside into the TEXT buffers and see if the line we want
109b8ba871bSPeter Wemm 	 * is there.
110b8ba871bSPeter Wemm 	 */
111b8ba871bSPeter Wemm 	if (F_ISSET(sp, SC_TINPUT)) {
112f0957ccaSPeter Wemm 		l1 = ((TEXT *)TAILQ_FIRST(sp->tiq))->lno;
113f0957ccaSPeter Wemm 		l2 = ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno;
114b8ba871bSPeter Wemm 		if (l1 <= lno && l2 >= lno) {
115b8ba871bSPeter Wemm #if defined(DEBUG) && 0
116b8ba871bSPeter Wemm 	TRACE(sp, "retrieve TEXT buffer line %lu\n", (u_long)lno);
117b8ba871bSPeter Wemm #endif
118f0957ccaSPeter Wemm 			for (tp = TAILQ_FIRST(sp->tiq);
119f0957ccaSPeter Wemm 			    tp->lno != lno; tp = TAILQ_NEXT(tp, q));
120b8ba871bSPeter Wemm 			if (lenp != NULL)
121b8ba871bSPeter Wemm 				*lenp = tp->len;
122b8ba871bSPeter Wemm 			if (pp != NULL)
123b8ba871bSPeter Wemm 				*pp = tp->lb;
124b8ba871bSPeter Wemm 			return (0);
125b8ba871bSPeter Wemm 		}
126b8ba871bSPeter Wemm 		/*
127b8ba871bSPeter Wemm 		 * Adjust the line number for the number of lines used
128b8ba871bSPeter Wemm 		 * by the text input buffers.
129b8ba871bSPeter Wemm 		 */
130b8ba871bSPeter Wemm 		if (lno > l2)
131b8ba871bSPeter Wemm 			lno -= l2 - l1;
132b8ba871bSPeter Wemm 	}
133b8ba871bSPeter Wemm 
134b8ba871bSPeter Wemm 	/* Look-aside into the cache, and see if the line we want is there. */
135b8ba871bSPeter Wemm 	if (lno == ep->c_lno) {
136b8ba871bSPeter Wemm #if defined(DEBUG) && 0
137b8ba871bSPeter Wemm 	TRACE(sp, "retrieve cached line %lu\n", (u_long)lno);
138b8ba871bSPeter Wemm #endif
139b8ba871bSPeter Wemm 		if (lenp != NULL)
140b8ba871bSPeter Wemm 			*lenp = ep->c_len;
141b8ba871bSPeter Wemm 		if (pp != NULL)
142b8ba871bSPeter Wemm 			*pp = ep->c_lp;
143b8ba871bSPeter Wemm 		return (0);
144b8ba871bSPeter Wemm 	}
145b8ba871bSPeter Wemm 	ep->c_lno = OOBLNO;
146b8ba871bSPeter Wemm 
147b8ba871bSPeter Wemm nocache:
148b8ba871bSPeter Wemm 	/* Get the line from the underlying database. */
149b8ba871bSPeter Wemm 	key.data = &lno;
150b8ba871bSPeter Wemm 	key.size = sizeof(lno);
151b8ba871bSPeter Wemm 	switch (ep->db->get(ep->db, &key, &data, 0)) {
152b8ba871bSPeter Wemm 	case -1:
153b8ba871bSPeter Wemm 		goto err2;
154b8ba871bSPeter Wemm 	case 1:
155b8ba871bSPeter Wemm err1:		if (LF_ISSET(DBG_FATAL))
156b8ba871bSPeter Wemm err2:			db_err(sp, lno);
157f0957ccaSPeter Wemm alloc_err:
158b8ba871bSPeter Wemm err3:		if (lenp != NULL)
159b8ba871bSPeter Wemm 			*lenp = 0;
160b8ba871bSPeter Wemm 		if (pp != NULL)
161b8ba871bSPeter Wemm 			*pp = NULL;
162b8ba871bSPeter Wemm 		return (1);
163f0957ccaSPeter Wemm 	}
164f0957ccaSPeter Wemm 
165f0957ccaSPeter Wemm 	if (FILE2INT(sp, data.data, data.size, wp, wlen)) {
166f0957ccaSPeter Wemm 		if (!F_ISSET(sp, SC_CONV_ERROR)) {
167f0957ccaSPeter Wemm 			F_SET(sp, SC_CONV_ERROR);
168f0957ccaSPeter Wemm 			msgq(sp, M_ERR, "324|Conversion error on line %d", lno);
169f0957ccaSPeter Wemm 		}
170f0957ccaSPeter Wemm 		goto err3;
171b8ba871bSPeter Wemm 	}
172b8ba871bSPeter Wemm 
173b8ba871bSPeter Wemm 	/* Reset the cache. */
174f0957ccaSPeter Wemm 	if (wp != data.data) {
175f0957ccaSPeter Wemm 		BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen);
176f0957ccaSPeter Wemm 		MEMCPY(ep->c_lp, wp, wlen);
177f0957ccaSPeter Wemm 	} else
178b8ba871bSPeter Wemm 		ep->c_lp = data.data;
179f0957ccaSPeter Wemm 	ep->c_lno = lno;
180f0957ccaSPeter Wemm 	ep->c_len = wlen;
181b8ba871bSPeter Wemm 
182b8ba871bSPeter Wemm #if defined(DEBUG) && 0
183b8ba871bSPeter Wemm 	TRACE(sp, "retrieve DB line %lu\n", (u_long)lno);
184b8ba871bSPeter Wemm #endif
185b8ba871bSPeter Wemm 	if (lenp != NULL)
186f0957ccaSPeter Wemm 		*lenp = wlen;
187b8ba871bSPeter Wemm 	if (pp != NULL)
188b8ba871bSPeter Wemm 		*pp = ep->c_lp;
189b8ba871bSPeter Wemm 	return (0);
190b8ba871bSPeter Wemm }
191b8ba871bSPeter Wemm 
192b8ba871bSPeter Wemm /*
193b8ba871bSPeter Wemm  * db_delete --
194b8ba871bSPeter Wemm  *	Delete a line from the file.
195b8ba871bSPeter Wemm  *
196c271fa92SBaptiste Daroussin  * PUBLIC: int db_delete(SCR *, recno_t);
197b8ba871bSPeter Wemm  */
198b8ba871bSPeter Wemm int
db_delete(SCR * sp,recno_t lno)199*110d525eSBaptiste Daroussin db_delete(SCR *sp, recno_t lno)
200b8ba871bSPeter Wemm {
201b8ba871bSPeter Wemm 	DBT key;
202b8ba871bSPeter Wemm 	EXF *ep;
203b8ba871bSPeter Wemm 
204b8ba871bSPeter Wemm #if defined(DEBUG) && 0
205b8ba871bSPeter Wemm 	TRACE(sp, "delete line %lu\n", (u_long)lno);
206b8ba871bSPeter Wemm #endif
207b8ba871bSPeter Wemm 	/* Check for no underlying file. */
208b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
209b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
210b8ba871bSPeter Wemm 		return (1);
211b8ba871bSPeter Wemm 	}
212b8ba871bSPeter Wemm 
213b8ba871bSPeter Wemm 	/* Update marks, @ and global commands. */
214b8ba871bSPeter Wemm 	if (mark_insdel(sp, LINE_DELETE, lno))
215b8ba871bSPeter Wemm 		return (1);
216b8ba871bSPeter Wemm 	if (ex_g_insdel(sp, LINE_DELETE, lno))
217b8ba871bSPeter Wemm 		return (1);
218b8ba871bSPeter Wemm 
219b8ba871bSPeter Wemm 	/* Log change. */
220b8ba871bSPeter Wemm 	log_line(sp, lno, LOG_LINE_DELETE);
221b8ba871bSPeter Wemm 
222b8ba871bSPeter Wemm 	/* Update file. */
223b8ba871bSPeter Wemm 	key.data = &lno;
224b8ba871bSPeter Wemm 	key.size = sizeof(lno);
225b8ba871bSPeter Wemm 	if (ep->db->del(ep->db, &key, 0) == 1) {
226b8ba871bSPeter Wemm 		msgq(sp, M_SYSERR,
227b8ba871bSPeter Wemm 		    "003|unable to delete line %lu", (u_long)lno);
228b8ba871bSPeter Wemm 		return (1);
229b8ba871bSPeter Wemm 	}
230b8ba871bSPeter Wemm 
231b8ba871bSPeter Wemm 	/* Flush the cache, update line count, before screen update. */
232b8ba871bSPeter Wemm 	if (lno <= ep->c_lno)
233b8ba871bSPeter Wemm 		ep->c_lno = OOBLNO;
234b8ba871bSPeter Wemm 	if (ep->c_nlines != OOBLNO)
235b8ba871bSPeter Wemm 		--ep->c_nlines;
236b8ba871bSPeter Wemm 
237b8ba871bSPeter Wemm 	/* File now modified. */
238b8ba871bSPeter Wemm 	if (F_ISSET(ep, F_FIRSTMODIFY))
239b8ba871bSPeter Wemm 		(void)rcv_init(sp);
240b8ba871bSPeter Wemm 	F_SET(ep, F_MODIFIED);
241b8ba871bSPeter Wemm 
242b8ba871bSPeter Wemm 	/* Update screen. */
243b8ba871bSPeter Wemm 	return (scr_update(sp, lno, LINE_DELETE, 1));
244b8ba871bSPeter Wemm }
245b8ba871bSPeter Wemm 
246b8ba871bSPeter Wemm /*
247b8ba871bSPeter Wemm  * db_append --
248b8ba871bSPeter Wemm  *	Append a line into the file.
249b8ba871bSPeter Wemm  *
250c271fa92SBaptiste Daroussin  * PUBLIC: int db_append(SCR *, int, recno_t, CHAR_T *, size_t);
251b8ba871bSPeter Wemm  */
252b8ba871bSPeter Wemm int
db_append(SCR * sp,int update,recno_t lno,CHAR_T * p,size_t len)253*110d525eSBaptiste Daroussin db_append(SCR *sp, int update, recno_t lno, CHAR_T *p, size_t len)
254b8ba871bSPeter Wemm {
255b8ba871bSPeter Wemm 	DBT data, key;
256b8ba871bSPeter Wemm 	EXF *ep;
257f0957ccaSPeter Wemm 	char *fp;
258f0957ccaSPeter Wemm 	size_t flen;
259b8ba871bSPeter Wemm 	int rval;
260b8ba871bSPeter Wemm 
261b8ba871bSPeter Wemm #if defined(DEBUG) && 0
262b8ba871bSPeter Wemm 	TRACE(sp, "append to %lu: len %u {%.*s}\n", lno, len, MIN(len, 20), p);
263b8ba871bSPeter Wemm #endif
264b8ba871bSPeter Wemm 	/* Check for no underlying file. */
265b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
266b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
267b8ba871bSPeter Wemm 		return (1);
268b8ba871bSPeter Wemm 	}
269b8ba871bSPeter Wemm 
270f0957ccaSPeter Wemm 	INT2FILE(sp, p, len, fp, flen);
271f0957ccaSPeter Wemm 
272b8ba871bSPeter Wemm 	/* Update file. */
273b8ba871bSPeter Wemm 	key.data = &lno;
274b8ba871bSPeter Wemm 	key.size = sizeof(lno);
275f0957ccaSPeter Wemm 	data.data = fp;
276f0957ccaSPeter Wemm 	data.size = flen;
277b8ba871bSPeter Wemm 	if (ep->db->put(ep->db, &key, &data, R_IAFTER) == -1) {
278b8ba871bSPeter Wemm 		msgq(sp, M_SYSERR,
279b8ba871bSPeter Wemm 		    "004|unable to append to line %lu", (u_long)lno);
280b8ba871bSPeter Wemm 		return (1);
281b8ba871bSPeter Wemm 	}
282b8ba871bSPeter Wemm 
283b8ba871bSPeter Wemm 	/* Flush the cache, update line count, before screen update. */
284b8ba871bSPeter Wemm 	if (lno < ep->c_lno)
285b8ba871bSPeter Wemm 		ep->c_lno = OOBLNO;
286b8ba871bSPeter Wemm 	if (ep->c_nlines != OOBLNO)
287b8ba871bSPeter Wemm 		++ep->c_nlines;
288b8ba871bSPeter Wemm 
289b8ba871bSPeter Wemm 	/* File now dirty. */
290b8ba871bSPeter Wemm 	if (F_ISSET(ep, F_FIRSTMODIFY))
291b8ba871bSPeter Wemm 		(void)rcv_init(sp);
292b8ba871bSPeter Wemm 	F_SET(ep, F_MODIFIED);
293b8ba871bSPeter Wemm 
294b8ba871bSPeter Wemm 	/* Log change. */
295b8ba871bSPeter Wemm 	log_line(sp, lno + 1, LOG_LINE_APPEND);
296b8ba871bSPeter Wemm 
297b8ba871bSPeter Wemm 	/* Update marks, @ and global commands. */
298b8ba871bSPeter Wemm 	rval = 0;
299b8ba871bSPeter Wemm 	if (mark_insdel(sp, LINE_INSERT, lno + 1))
300b8ba871bSPeter Wemm 		rval = 1;
301b8ba871bSPeter Wemm 	if (ex_g_insdel(sp, LINE_INSERT, lno + 1))
302b8ba871bSPeter Wemm 		rval = 1;
303b8ba871bSPeter Wemm 
304b8ba871bSPeter Wemm 	/*
305b8ba871bSPeter Wemm 	 * Update screen.
306b8ba871bSPeter Wemm 	 *
307b8ba871bSPeter Wemm 	 * XXX
308b8ba871bSPeter Wemm 	 * Nasty hack.  If multiple lines are input by the user, they aren't
309b8ba871bSPeter Wemm 	 * committed until an <ESC> is entered.  The problem is the screen was
310b8ba871bSPeter Wemm 	 * updated/scrolled as each line was entered.  So, when this routine
311b8ba871bSPeter Wemm 	 * is called to copy the new lines from the cut buffer into the file,
312b8ba871bSPeter Wemm 	 * it has to know not to update the screen again.
313b8ba871bSPeter Wemm 	 */
314b8ba871bSPeter Wemm 	return (scr_update(sp, lno, LINE_APPEND, update) || rval);
315b8ba871bSPeter Wemm }
316b8ba871bSPeter Wemm 
317b8ba871bSPeter Wemm /*
318b8ba871bSPeter Wemm  * db_insert --
319b8ba871bSPeter Wemm  *	Insert a line into the file.
320b8ba871bSPeter Wemm  *
321c271fa92SBaptiste Daroussin  * PUBLIC: int db_insert(SCR *, recno_t, CHAR_T *, size_t);
322b8ba871bSPeter Wemm  */
323b8ba871bSPeter Wemm int
db_insert(SCR * sp,recno_t lno,CHAR_T * p,size_t len)324*110d525eSBaptiste Daroussin db_insert(SCR *sp, recno_t lno, CHAR_T *p, size_t len)
325b8ba871bSPeter Wemm {
326b8ba871bSPeter Wemm 	DBT data, key;
327b8ba871bSPeter Wemm 	EXF *ep;
328f0957ccaSPeter Wemm 	char *fp;
329f0957ccaSPeter Wemm 	size_t flen;
330b8ba871bSPeter Wemm 	int rval;
331b8ba871bSPeter Wemm 
332b8ba871bSPeter Wemm #if defined(DEBUG) && 0
333b8ba871bSPeter Wemm 	TRACE(sp, "insert before %lu: len %lu {%.*s}\n",
334b8ba871bSPeter Wemm 	    (u_long)lno, (u_long)len, MIN(len, 20), p);
335b8ba871bSPeter Wemm #endif
336b8ba871bSPeter Wemm 	/* Check for no underlying file. */
337b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
338b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
339b8ba871bSPeter Wemm 		return (1);
340b8ba871bSPeter Wemm 	}
341b8ba871bSPeter Wemm 
342f0957ccaSPeter Wemm 	INT2FILE(sp, p, len, fp, flen);
343f0957ccaSPeter Wemm 
344b8ba871bSPeter Wemm 	/* Update file. */
345b8ba871bSPeter Wemm 	key.data = &lno;
346b8ba871bSPeter Wemm 	key.size = sizeof(lno);
347f0957ccaSPeter Wemm 	data.data = fp;
348f0957ccaSPeter Wemm 	data.size = flen;
349b8ba871bSPeter Wemm 	if (ep->db->put(ep->db, &key, &data, R_IBEFORE) == -1) {
350b8ba871bSPeter Wemm 		msgq(sp, M_SYSERR,
351b8ba871bSPeter Wemm 		    "005|unable to insert at line %lu", (u_long)lno);
352b8ba871bSPeter Wemm 		return (1);
353b8ba871bSPeter Wemm 	}
354b8ba871bSPeter Wemm 
355b8ba871bSPeter Wemm 	/* Flush the cache, update line count, before screen update. */
356b8ba871bSPeter Wemm 	if (lno >= ep->c_lno)
357b8ba871bSPeter Wemm 		ep->c_lno = OOBLNO;
358b8ba871bSPeter Wemm 	if (ep->c_nlines != OOBLNO)
359b8ba871bSPeter Wemm 		++ep->c_nlines;
360b8ba871bSPeter Wemm 
361b8ba871bSPeter Wemm 	/* File now dirty. */
362b8ba871bSPeter Wemm 	if (F_ISSET(ep, F_FIRSTMODIFY))
363b8ba871bSPeter Wemm 		(void)rcv_init(sp);
364b8ba871bSPeter Wemm 	F_SET(ep, F_MODIFIED);
365b8ba871bSPeter Wemm 
366b8ba871bSPeter Wemm 	/* Log change. */
367b8ba871bSPeter Wemm 	log_line(sp, lno, LOG_LINE_INSERT);
368b8ba871bSPeter Wemm 
369b8ba871bSPeter Wemm 	/* Update marks, @ and global commands. */
370b8ba871bSPeter Wemm 	rval = 0;
371b8ba871bSPeter Wemm 	if (mark_insdel(sp, LINE_INSERT, lno))
372b8ba871bSPeter Wemm 		rval = 1;
373b8ba871bSPeter Wemm 	if (ex_g_insdel(sp, LINE_INSERT, lno))
374b8ba871bSPeter Wemm 		rval = 1;
375b8ba871bSPeter Wemm 
376b8ba871bSPeter Wemm 	/* Update screen. */
377b8ba871bSPeter Wemm 	return (scr_update(sp, lno, LINE_INSERT, 1) || rval);
378b8ba871bSPeter Wemm }
379b8ba871bSPeter Wemm 
380b8ba871bSPeter Wemm /*
381b8ba871bSPeter Wemm  * db_set --
382b8ba871bSPeter Wemm  *	Store a line in the file.
383b8ba871bSPeter Wemm  *
384c271fa92SBaptiste Daroussin  * PUBLIC: int db_set(SCR *, recno_t, CHAR_T *, size_t);
385b8ba871bSPeter Wemm  */
386b8ba871bSPeter Wemm int
db_set(SCR * sp,recno_t lno,CHAR_T * p,size_t len)387*110d525eSBaptiste Daroussin db_set(SCR *sp, recno_t lno, CHAR_T *p, size_t len)
388b8ba871bSPeter Wemm {
389b8ba871bSPeter Wemm 	DBT data, key;
390b8ba871bSPeter Wemm 	EXF *ep;
391f0957ccaSPeter Wemm 	char *fp;
392f0957ccaSPeter Wemm 	size_t flen;
393b8ba871bSPeter Wemm 
394b8ba871bSPeter Wemm #if defined(DEBUG) && 0
395b8ba871bSPeter Wemm 	TRACE(sp, "replace line %lu: len %lu {%.*s}\n",
396b8ba871bSPeter Wemm 	    (u_long)lno, (u_long)len, MIN(len, 20), p);
397b8ba871bSPeter Wemm #endif
398b8ba871bSPeter Wemm 	/* Check for no underlying file. */
399b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
400b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
401b8ba871bSPeter Wemm 		return (1);
402b8ba871bSPeter Wemm 	}
403b8ba871bSPeter Wemm 
404b8ba871bSPeter Wemm 	/* Log before change. */
405b8ba871bSPeter Wemm 	log_line(sp, lno, LOG_LINE_RESET_B);
406b8ba871bSPeter Wemm 
407f0957ccaSPeter Wemm 	INT2FILE(sp, p, len, fp, flen);
408f0957ccaSPeter Wemm 
409b8ba871bSPeter Wemm 	/* Update file. */
410b8ba871bSPeter Wemm 	key.data = &lno;
411b8ba871bSPeter Wemm 	key.size = sizeof(lno);
412f0957ccaSPeter Wemm 	data.data = fp;
413f0957ccaSPeter Wemm 	data.size = flen;
414b8ba871bSPeter Wemm 	if (ep->db->put(ep->db, &key, &data, 0) == -1) {
415b8ba871bSPeter Wemm 		msgq(sp, M_SYSERR,
416b8ba871bSPeter Wemm 		    "006|unable to store line %lu", (u_long)lno);
417b8ba871bSPeter Wemm 		return (1);
418b8ba871bSPeter Wemm 	}
419b8ba871bSPeter Wemm 
420b8ba871bSPeter Wemm 	/* Flush the cache, before logging or screen update. */
421b8ba871bSPeter Wemm 	if (lno == ep->c_lno)
422b8ba871bSPeter Wemm 		ep->c_lno = OOBLNO;
423b8ba871bSPeter Wemm 
424b8ba871bSPeter Wemm 	/* File now dirty. */
425b8ba871bSPeter Wemm 	if (F_ISSET(ep, F_FIRSTMODIFY))
426b8ba871bSPeter Wemm 		(void)rcv_init(sp);
427b8ba871bSPeter Wemm 	F_SET(ep, F_MODIFIED);
428b8ba871bSPeter Wemm 
429b8ba871bSPeter Wemm 	/* Log after change. */
430b8ba871bSPeter Wemm 	log_line(sp, lno, LOG_LINE_RESET_F);
431b8ba871bSPeter Wemm 
432b8ba871bSPeter Wemm 	/* Update screen. */
433b8ba871bSPeter Wemm 	return (scr_update(sp, lno, LINE_RESET, 1));
434b8ba871bSPeter Wemm }
435b8ba871bSPeter Wemm 
436b8ba871bSPeter Wemm /*
437b8ba871bSPeter Wemm  * db_exist --
438b8ba871bSPeter Wemm  *	Return if a line exists.
439b8ba871bSPeter Wemm  *
440c271fa92SBaptiste Daroussin  * PUBLIC: int db_exist(SCR *, recno_t);
441b8ba871bSPeter Wemm  */
442b8ba871bSPeter Wemm int
db_exist(SCR * sp,recno_t lno)443*110d525eSBaptiste Daroussin db_exist(SCR *sp, recno_t lno)
444b8ba871bSPeter Wemm {
445b8ba871bSPeter Wemm 	EXF *ep;
446b8ba871bSPeter Wemm 
447b8ba871bSPeter Wemm 	/* Check for no underlying file. */
448b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
449b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
450b8ba871bSPeter Wemm 		return (1);
451b8ba871bSPeter Wemm 	}
452b8ba871bSPeter Wemm 
453b8ba871bSPeter Wemm 	if (lno == OOBLNO)
454b8ba871bSPeter Wemm 		return (0);
455b8ba871bSPeter Wemm 
456b8ba871bSPeter Wemm 	/*
457b8ba871bSPeter Wemm 	 * Check the last-line number cache.  Adjust the cached line
458b8ba871bSPeter Wemm 	 * number for the lines used by the text input buffers.
459b8ba871bSPeter Wemm 	 */
460b8ba871bSPeter Wemm 	if (ep->c_nlines != OOBLNO)
461b8ba871bSPeter Wemm 		return (lno <= (F_ISSET(sp, SC_TINPUT) ?
462f0957ccaSPeter Wemm 		    ep->c_nlines + (((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno -
463f0957ccaSPeter Wemm 		    ((TEXT *)TAILQ_FIRST(sp->tiq))->lno) : ep->c_nlines));
464b8ba871bSPeter Wemm 
465b8ba871bSPeter Wemm 	/* Go get the line. */
466b8ba871bSPeter Wemm 	return (!db_get(sp, lno, 0, NULL, NULL));
467b8ba871bSPeter Wemm }
468b8ba871bSPeter Wemm 
469b8ba871bSPeter Wemm /*
470b8ba871bSPeter Wemm  * db_last --
471b8ba871bSPeter Wemm  *	Return the number of lines in the file.
472b8ba871bSPeter Wemm  *
473c271fa92SBaptiste Daroussin  * PUBLIC: int db_last(SCR *, recno_t *);
474b8ba871bSPeter Wemm  */
475b8ba871bSPeter Wemm int
db_last(SCR * sp,recno_t * lnop)476*110d525eSBaptiste Daroussin db_last(SCR *sp, recno_t *lnop)
477b8ba871bSPeter Wemm {
478b8ba871bSPeter Wemm 	DBT data, key;
479b8ba871bSPeter Wemm 	EXF *ep;
480b8ba871bSPeter Wemm 	recno_t lno;
481f0957ccaSPeter Wemm 	CHAR_T *wp;
482f0957ccaSPeter Wemm 	size_t wlen;
483b8ba871bSPeter Wemm 
484b8ba871bSPeter Wemm 	/* Check for no underlying file. */
485b8ba871bSPeter Wemm 	if ((ep = sp->ep) == NULL) {
486b8ba871bSPeter Wemm 		ex_emsg(sp, NULL, EXM_NOFILEYET);
487b8ba871bSPeter Wemm 		return (1);
488b8ba871bSPeter Wemm 	}
489b8ba871bSPeter Wemm 
490b8ba871bSPeter Wemm 	/*
491b8ba871bSPeter Wemm 	 * Check the last-line number cache.  Adjust the cached line
492b8ba871bSPeter Wemm 	 * number for the lines used by the text input buffers.
493b8ba871bSPeter Wemm 	 */
494b8ba871bSPeter Wemm 	if (ep->c_nlines != OOBLNO) {
495b8ba871bSPeter Wemm 		*lnop = ep->c_nlines;
496b8ba871bSPeter Wemm 		if (F_ISSET(sp, SC_TINPUT))
497f0957ccaSPeter Wemm 			*lnop += ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno -
498f0957ccaSPeter Wemm 			    ((TEXT *)TAILQ_FIRST(sp->tiq))->lno;
499b8ba871bSPeter Wemm 		return (0);
500b8ba871bSPeter Wemm 	}
501b8ba871bSPeter Wemm 
502b8ba871bSPeter Wemm 	key.data = &lno;
503b8ba871bSPeter Wemm 	key.size = sizeof(lno);
504b8ba871bSPeter Wemm 
505b8ba871bSPeter Wemm 	switch (ep->db->seq(ep->db, &key, &data, R_LAST)) {
506b8ba871bSPeter Wemm 	case -1:
507f0957ccaSPeter Wemm alloc_err:
508b8ba871bSPeter Wemm 		msgq(sp, M_SYSERR, "007|unable to get last line");
509b8ba871bSPeter Wemm 		*lnop = 0;
510b8ba871bSPeter Wemm 		return (1);
511b8ba871bSPeter Wemm 	case 1:
512b8ba871bSPeter Wemm 		*lnop = 0;
513b8ba871bSPeter Wemm 		return (0);
514b8ba871bSPeter Wemm 	}
515b8ba871bSPeter Wemm 
516b8ba871bSPeter Wemm 	memcpy(&lno, key.data, sizeof(lno));
517f0957ccaSPeter Wemm 
518f0957ccaSPeter Wemm 	if (lno != ep->c_lno) {
519f0957ccaSPeter Wemm 		FILE2INT(sp, data.data, data.size, wp, wlen);
520f0957ccaSPeter Wemm 
521f0957ccaSPeter Wemm 		/* Fill the cache. */
522f0957ccaSPeter Wemm 		if (wp != data.data) {
523f0957ccaSPeter Wemm 			BINC_GOTOW(sp, ep->c_lp, ep->c_blen, wlen);
524f0957ccaSPeter Wemm 			MEMCPY(ep->c_lp, wp, wlen);
525f0957ccaSPeter Wemm 		} else
526b8ba871bSPeter Wemm 			ep->c_lp = data.data;
527f0957ccaSPeter Wemm 		ep->c_lno = lno;
528f0957ccaSPeter Wemm 		ep->c_len = wlen;
529f0957ccaSPeter Wemm 	}
530f0957ccaSPeter Wemm 	ep->c_nlines = lno;
531b8ba871bSPeter Wemm 
532b8ba871bSPeter Wemm 	/* Return the value. */
533b8ba871bSPeter Wemm 	*lnop = (F_ISSET(sp, SC_TINPUT) &&
534f0957ccaSPeter Wemm 	    ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno > lno ?
535f0957ccaSPeter Wemm 	    ((TEXT *)TAILQ_LAST(sp->tiq, _texth))->lno : lno);
536f0957ccaSPeter Wemm 	return (0);
537f0957ccaSPeter Wemm }
538f0957ccaSPeter Wemm 
539f0957ccaSPeter Wemm /*
540f0957ccaSPeter Wemm  * db_rget --
541c271fa92SBaptiste Daroussin  *	Retrieve a raw line from the database.
542f0957ccaSPeter Wemm  *
543c271fa92SBaptiste Daroussin  * PUBLIC: int db_rget(SCR *, recno_t, char **, size_t *);
544f0957ccaSPeter Wemm  */
545f0957ccaSPeter Wemm int
db_rget(SCR * sp,recno_t lno,char ** pp,size_t * lenp)546*110d525eSBaptiste Daroussin db_rget(SCR *sp,
547f0957ccaSPeter Wemm 	recno_t lno,				/* Line number. */
548f0957ccaSPeter Wemm 	char **pp,				/* Pointer store. */
549f0957ccaSPeter Wemm 	size_t *lenp)				/* Length store. */
550f0957ccaSPeter Wemm {
551f0957ccaSPeter Wemm 	DBT data, key;
552c271fa92SBaptiste Daroussin 	EXF *ep = sp->ep;
553c271fa92SBaptiste Daroussin 	int rval;
554f0957ccaSPeter Wemm 
555f0957ccaSPeter Wemm 	/* Get the line from the underlying database. */
556f0957ccaSPeter Wemm 	key.data = &lno;
557f0957ccaSPeter Wemm 	key.size = sizeof(lno);
558c271fa92SBaptiste Daroussin 	if ((rval = ep->db->get(ep->db, &key, &data, 0)) == 0)
559c271fa92SBaptiste Daroussin 	{
560f0957ccaSPeter Wemm 		*lenp = data.size;
561f0957ccaSPeter Wemm 		*pp = data.data;
562c271fa92SBaptiste Daroussin 	}
563c271fa92SBaptiste Daroussin 
564c271fa92SBaptiste Daroussin 	return (rval);
565f0957ccaSPeter Wemm }
566f0957ccaSPeter Wemm 
567f0957ccaSPeter Wemm /*
568f0957ccaSPeter Wemm  * db_rset --
569c271fa92SBaptiste Daroussin  *	Store a raw line into the database.
570f0957ccaSPeter Wemm  *
571c271fa92SBaptiste Daroussin  * PUBLIC: int db_rset(SCR *, recno_t, char *, size_t);
572f0957ccaSPeter Wemm  */
573f0957ccaSPeter Wemm int
db_rset(SCR * sp,recno_t lno,char * p,size_t len)574*110d525eSBaptiste Daroussin db_rset(SCR *sp, recno_t lno, char *p, size_t len)
575f0957ccaSPeter Wemm {
576f0957ccaSPeter Wemm 	DBT data, key;
577c271fa92SBaptiste Daroussin 	EXF *ep = sp->ep;
578f0957ccaSPeter Wemm 
579f0957ccaSPeter Wemm 	/* Update file. */
580f0957ccaSPeter Wemm 	key.data = &lno;
581f0957ccaSPeter Wemm 	key.size = sizeof(lno);
582f0957ccaSPeter Wemm 	data.data = p;
583f0957ccaSPeter Wemm 	data.size = len;
584c271fa92SBaptiste Daroussin 	return ep->db->put(ep->db, &key, &data, 0);
585b8ba871bSPeter Wemm }
586b8ba871bSPeter Wemm 
587b8ba871bSPeter Wemm /*
588b8ba871bSPeter Wemm  * db_err --
589b8ba871bSPeter Wemm  *	Report a line error.
590b8ba871bSPeter Wemm  *
591c271fa92SBaptiste Daroussin  * PUBLIC: void db_err(SCR *, recno_t);
592b8ba871bSPeter Wemm  */
593b8ba871bSPeter Wemm void
db_err(SCR * sp,recno_t lno)594*110d525eSBaptiste Daroussin db_err(SCR *sp, recno_t lno)
595b8ba871bSPeter Wemm {
596b8ba871bSPeter Wemm 	msgq(sp, M_ERR,
597b8ba871bSPeter Wemm 	    "008|Error: unable to retrieve line %lu", (u_long)lno);
598b8ba871bSPeter Wemm }
599b8ba871bSPeter Wemm 
600b8ba871bSPeter Wemm /*
601b8ba871bSPeter Wemm  * scr_update --
602b8ba871bSPeter Wemm  *	Update all of the screens that are backed by the file that
603b8ba871bSPeter Wemm  *	just changed.
604b8ba871bSPeter Wemm  */
605b8ba871bSPeter Wemm static int
scr_update(SCR * sp,recno_t lno,lnop_t op,int current)606*110d525eSBaptiste Daroussin scr_update(SCR *sp, recno_t lno, lnop_t op, int current)
607b8ba871bSPeter Wemm {
608b8ba871bSPeter Wemm 	EXF *ep;
609b8ba871bSPeter Wemm 	SCR *tsp;
610b8ba871bSPeter Wemm 
611b8ba871bSPeter Wemm 	if (F_ISSET(sp, SC_EX))
612b8ba871bSPeter Wemm 		return (0);
613b8ba871bSPeter Wemm 
614b8ba871bSPeter Wemm 	ep = sp->ep;
615b8ba871bSPeter Wemm 	if (ep->refcnt != 1)
616f0957ccaSPeter Wemm 		TAILQ_FOREACH(tsp, sp->gp->dq, q)
617b8ba871bSPeter Wemm 			if (sp != tsp && tsp->ep == ep)
618b8ba871bSPeter Wemm 				if (vs_change(tsp, lno, op))
619b8ba871bSPeter Wemm 					return (1);
620b8ba871bSPeter Wemm 	return (current ? vs_change(sp, lno, op) : 0);
621b8ba871bSPeter Wemm }
622