2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
9 static char sccsid
[] = "$Id: db.c,v 8.20 1993/12/29 16:11:01 bostic Exp $ (Berkeley) $Date: 1993/12/29 16:11:01 $";
12 #include <sys/types.h>
20 static inline int scr_update
__P((SCR
*, EXF
*, recno_t
, enum operation
, int));
24 * Look in the text buffers for a line; if it's not there
25 * call file_rline to retrieve it from the database.
28 file_gline(sp
, ep
, lno
, lenp
)
31 recno_t lno
; /* Line number. */
32 size_t *lenp
; /* Length store. */
38 * The underlying recno stuff handles zero by returning NULL, but
39 * have to have an oob condition for the look-aside into the input
46 * Look-aside into the TEXT buffers and see if the line we want
49 if (F_ISSET(sp
, S_INPUT
)) {
50 l1
= ((TEXT
*)sp
->tiq
.cqh_first
)->lno
;
51 l2
= ((TEXT
*)sp
->tiq
.cqh_last
)->lno
;
52 if (l1
<= lno
&& l2
>= lno
) {
53 for (tp
= sp
->tiq
.cqh_first
;
54 tp
->lno
!= lno
; tp
= tp
->q
.cqe_next
);
60 * Adjust the line number for the number of lines used
61 * by the text input buffers.
66 return (file_rline(sp
, ep
, lno
, lenp
));
71 * Look in the cache for a line; if it's not there retrieve
75 file_rline(sp
, ep
, lno
, lenp
)
78 recno_t lno
; /* Line number. */
79 size_t *lenp
; /* Length store. */
83 /* Check the cache. */
84 if (lno
== ep
->c_lno
) {
91 /* Get the line from the underlying database. */
93 key
.size
= sizeof(lno
);
94 switch (ep
->db
->get(ep
->db
, &key
, &data
, 0)) {
97 "Error: %s/%d: unable to get line %u: %s.",
98 tail(__FILE__
), __LINE__
, lno
, strerror(errno
));
107 /* Fill the cache. */
109 ep
->c_len
= data
.size
;
110 ep
->c_lp
= data
.data
;
117 * Delete a line from the file.
120 file_dline(sp
, ep
, lno
)
127 #if defined(DEBUG) && 0
128 TRACE(sp
, "delete line %lu\n", lno
);
133 * Marks and global commands have to know when lines are
134 * inserted or deleted.
136 mark_insdel(sp
, ep
, LINE_DELETE
, lno
);
137 global_insdel(sp
, ep
, LINE_DELETE
, lno
);
140 log_line(sp
, ep
, lno
, LOG_LINE_DELETE
);
144 key
.size
= sizeof(lno
);
145 if (ep
->db
->del(ep
->db
, &key
, 0) == 1) {
147 "Error: %s/%d: unable to delete line %u: %s.",
148 tail(__FILE__
), __LINE__
, lno
, strerror(errno
));
152 /* Flush the cache, update line count, before screen update. */
153 if (lno
<= ep
->c_lno
)
155 if (ep
->c_nlines
!= OOBLNO
)
158 /* File now dirty. */
159 if (F_ISSET(ep
, F_FIRSTMODIFY
))
160 (void)rcv_init(sp
, ep
);
161 F_SET(ep
, F_MODIFIED
);
164 return (scr_update(sp
, ep
, lno
, LINE_DELETE
, 1));
169 * Append a line into the file.
172 file_aline(sp
, ep
, update
, lno
, p
, len
)
183 #if defined(DEBUG) && 0
184 TRACE(sp
, "append to %lu: len %u {%.*s}\n", lno
, len
, MIN(len
, 20), p
);
187 * Very nasty special case. The historic vi code displays a single
188 * space (or a '$' if the list option is set) for the first line in
189 * an "empty" file. If we "insert" a line, that line gets scrolled
190 * down, not repainted, so it's incorrect when we refresh the the
191 * screen. This is really hard to find and fix in the vi code -- the
192 * text input functions detect it explicitly and don't insert a new
193 * line. The hack here is to repaint the screen if we're appending
197 if (file_lline(sp
, ep
, &lline
))
205 key
.size
= sizeof(lno
);
208 if (ep
->db
->put(ep
->db
, &key
, &data
, R_IAFTER
) == -1) {
210 "Error: %s/%d: unable to append to line %u: %s.",
211 tail(__FILE__
), __LINE__
, lno
, strerror(errno
));
215 /* Flush the cache, update line count, before screen update. */
218 if (ep
->c_nlines
!= OOBLNO
)
221 /* File now dirty. */
222 if (F_ISSET(ep
, F_FIRSTMODIFY
))
223 (void)rcv_init(sp
, ep
);
224 F_SET(ep
, F_MODIFIED
);
227 log_line(sp
, ep
, lno
+ 1, LOG_LINE_APPEND
);
232 * Marks and global commands have to know when lines are
233 * inserted or deleted.
235 mark_insdel(sp
, ep
, LINE_INSERT
, lno
+ 1);
236 global_insdel(sp
, ep
, LINE_INSERT
, lno
+ 1);
242 * Nasty hack. If multiple lines are input by the user, they aren't
243 * committed until an <ESC> is entered. The problem is the screen was
244 * updated/scrolled as each line was entered. So, when this routine
245 * is called to copy the new lines from the cut buffer into the file,
246 * it has to know not to update the screen again.
248 return (scr_update(sp
, ep
, lno
, LINE_APPEND
, update
));
253 * Insert a line into the file.
256 file_iline(sp
, ep
, lno
, p
, len
)
266 #if defined(DEBUG) && 0
268 "insert before %lu: len %u {%.*s}\n", lno
, len
, MIN(len
, 20), p
);
271 /* Very nasty special case. See comment in file_aline(). */
273 if (file_lline(sp
, ep
, &lline
))
281 key
.size
= sizeof(lno
);
284 if (ep
->db
->put(ep
->db
, &key
, &data
, R_IBEFORE
) == -1) {
286 "Error: %s/%d: unable to insert at line %u: %s.",
287 tail(__FILE__
), __LINE__
, lno
, strerror(errno
));
291 /* Flush the cache, update line count, before screen update. */
292 if (lno
>= ep
->c_lno
)
294 if (ep
->c_nlines
!= OOBLNO
)
297 /* File now dirty. */
298 if (F_ISSET(ep
, F_FIRSTMODIFY
))
299 (void)rcv_init(sp
, ep
);
300 F_SET(ep
, F_MODIFIED
);
303 log_line(sp
, ep
, lno
, LOG_LINE_INSERT
);
308 * Marks and global commands have to know when lines are
309 * inserted or deleted.
311 mark_insdel(sp
, ep
, LINE_INSERT
, lno
);
312 global_insdel(sp
, ep
, LINE_INSERT
, lno
);
315 return (scr_update(sp
, ep
, lno
, LINE_INSERT
, 1));
320 * Store a line in the file.
323 file_sline(sp
, ep
, lno
, p
, len
)
332 #if defined(DEBUG) && 0
334 "replace line %lu: len %u {%.*s}\n", lno
, len
, MIN(len
, 20), p
);
336 /* Log before change. */
337 log_line(sp
, ep
, lno
, LOG_LINE_RESET_B
);
341 key
.size
= sizeof(lno
);
344 if (ep
->db
->put(ep
->db
, &key
, &data
, 0) == -1) {
346 "Error: %s/%d: unable to store line %u: %s.",
347 tail(__FILE__
), __LINE__
, lno
, strerror(errno
));
351 /* Flush the cache, before logging or screen update. */
352 if (lno
== ep
->c_lno
)
355 /* File now dirty. */
356 if (F_ISSET(ep
, F_FIRSTMODIFY
))
357 (void)rcv_init(sp
, ep
);
358 F_SET(ep
, F_MODIFIED
);
360 /* Log after change. */
361 log_line(sp
, ep
, lno
, LOG_LINE_RESET_F
);
364 return (scr_update(sp
, ep
, lno
, LINE_RESET
, 1));
369 * Return the number of lines in the file.
372 file_lline(sp
, ep
, lnop
)
380 /* Check the cache. */
381 if (ep
->c_nlines
!= OOBLNO
) {
382 *lnop
= (F_ISSET(sp
, S_INPUT
) &&
383 ((TEXT
*)sp
->tiq
.cqh_last
)->lno
> ep
->c_nlines
?
384 ((TEXT
*)sp
->tiq
.cqh_last
)->lno
: ep
->c_nlines
);
389 key
.size
= sizeof(lno
);
391 switch (ep
->db
->seq(ep
->db
, &key
, &data
, R_LAST
)) {
394 "Error: %s/%d: unable to get last line: %s.",
395 tail(__FILE__
), __LINE__
, strerror(errno
));
402 memmove(&lno
, key
.data
, sizeof(lno
));
406 /* Fill the cache. */
407 ep
->c_nlines
= ep
->c_lno
= lno
;
408 ep
->c_len
= data
.size
;
409 ep
->c_lp
= data
.data
;
411 *lnop
= (F_ISSET(sp
, S_INPUT
) &&
412 ((TEXT
*)sp
->tiq
.cqh_last
)->lno
> lno
?
413 ((TEXT
*)sp
->tiq
.cqh_last
)->lno
: lno
);
419 * Update all of the screens that are backed by the file that
423 scr_update(sp
, ep
, lno
, op
, current
)
433 for (tsp
= sp
->gp
->dq
.cqh_first
;
434 tsp
!= (void *)&sp
->gp
->dq
; tsp
= tsp
->q
.cqe_next
)
435 if (sp
!= tsp
&& tsp
->ep
== ep
)
436 (void)sp
->s_change(tsp
, ep
, lno
, op
);
437 return (current
&& sp
->s_change(sp
, ep
, lno
, op
));