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: cut.c,v 8.19 1994/01/11 22:17:59 bostic Exp $ (Berkeley) $Date: 1994/01/11 22:17:59 $";
12 #include <sys/types.h>
22 static int cb_line
__P((SCR
*, EXF
*, recno_t
, size_t, size_t, TEXT
**));
23 static int cb_rotate
__P((SCR
*));
27 * Put a range of lines/columns into a buffer.
29 * There are two buffer areas, both found in the global structure. The first
30 * is the linked list of all the buffers the user has named, the second is the
31 * default buffer storage. There is a pointer, too, which is the current
32 * default buffer, i.e. it may point to the default buffer or a named buffer
33 * depending on into what buffer the last text was cut. In both delete and
34 * yank operations, text is cut into either the buffer named by the user, or
35 * the default buffer. If it's a delete of information on more than a single
36 * line, the contents of the numbered buffers are rotated up one, the contents
37 * of the buffer named '9' are discarded, and the text is also cut into the
40 * In all cases, upper-case buffer names are the same as lower-case names,
41 * with the exception that they cause the buffer to be appended to instead
45 * The contents of the default buffer would disappear after most operations in
46 * historic vi. It's unclear that this is useful, so we don't bother.
48 * When users explicitly cut text into the numeric buffers, historic vi became
49 * genuinely strange. I've never been able to figure out what was supposed to
50 * happen. It behaved differently if you deleted text than if you yanked text,
51 * and, in the latter case, the text was appended to the buffer instead of
52 * replacing the contents. Hopefully it's not worth getting right.
55 cut(sp
, ep
, cbp
, namep
, fm
, tm
, flags
)
67 int append
, namedbuffer
, setdefcb
;
69 #if defined(DEBUG) && 0
70 TRACE(sp
, "cut: from {%lu, %d}, to {%lu, %d}%s\n",
71 fm
->lno
, fm
->cno
, tm
->lno
, tm
->cno
,
72 LF_ISSET(CUT_LINEMODE
) ? " LINE MODE" : "");
75 if (LF_ISSET(CUT_DELETE
) && fm
->lno
!= tm
->lno
) {
81 cbp
= sp
->gp
->dcb_store
;
82 append
= namedbuffer
= 0;
86 defcb
: CBNAME(sp
, cbp
, name
);
87 append
= isupper(name
);
88 namedbuffer
= setdefcb
= 1;
91 append
= namedbuffer
= setdefcb
= 0;
94 * If this is a new buffer, create it and add it into the list.
95 * Otherwise, if it's not an append, free its current contents.
98 CALLOC(sp
, cbp
, CB
*, 1, sizeof(CB
));
100 CIRCLEQ_INIT(&cbp
->textq
);
102 LIST_INSERT_HEAD(&sp
->gp
->cutq
, cbp
, q
);
104 sp
->gp
->dcb_store
= cbp
;
105 } else if (!append
) {
106 text_lfree(&cbp
->textq
);
111 /* In line mode, it's pretty easy, just cut the lines. */
112 if (LF_ISSET(CUT_LINEMODE
)) {
113 for (lno
= fm
->lno
; lno
<= tm
->lno
; ++lno
) {
114 if (cb_line(sp
, ep
, lno
, 0, 0, &tp
))
116 CIRCLEQ_INSERT_TAIL(&cbp
->textq
, tp
, q
);
119 cbp
->flags
|= CB_LMODE
;
121 /* Get the first line. */
122 len
= fm
->lno
< tm
->lno
? 0 : tm
->cno
- fm
->cno
;
123 if (cb_line(sp
, ep
, fm
->lno
, fm
->cno
, len
, &tp
))
125 CIRCLEQ_INSERT_TAIL(&cbp
->textq
, tp
, q
);
128 /* Get the intermediate lines. */
129 for (lno
= fm
->lno
; ++lno
< tm
->lno
;) {
130 if (cb_line(sp
, ep
, lno
, 0, 0, &tp
))
132 CIRCLEQ_INSERT_TAIL(&cbp
->textq
, tp
, q
);
136 /* Get the last line. */
137 if (tm
->lno
> fm
->lno
&& tm
->cno
> 0) {
138 if (cb_line(sp
, ep
, lno
, 0, tm
->cno
, &tp
)) {
141 "Contents of %s buffer lost.",
143 text_lfree(&cbp
->textq
);
148 CIRCLEQ_INSERT_TAIL(&cbp
->textq
, tp
, q
);
153 sp
->gp
->dcbp
= cbp
; /* Repoint default buffer. */
159 * Rotate the numbered buffers up one.
168 for (cbp
= sp
->gp
->cutq
.lh_first
; cbp
!= NULL
; cbp
= cbp
->q
.le_next
)
198 if (del_cbp
!= NULL
) {
199 LIST_REMOVE(del_cbp
, q
);
200 text_lfree(&del_cbp
->textq
);
201 FREE(del_cbp
, sizeof(CB
));
208 * Cut a portion of a single line.
211 cb_line(sp
, ep
, lno
, fcno
, clen
, newp
)
222 if ((p
= file_gline(sp
, ep
, lno
, &len
)) == NULL
) {
223 GETLINE_ERR(sp
, lno
);
227 if ((*newp
= tp
= text_init(sp
, NULL
, 0, len
)) == NULL
)
231 * A length of zero means to cut from the MARK to the end
237 memmove(tp
->lb
, p
+ fcno
, clen
);
245 * Allocate a new TEXT structure.
248 text_init(sp
, p
, len
, total_len
)
251 size_t len
, total_len
;
255 MALLOC(sp
, tp
, TEXT
*, sizeof(TEXT
));
258 /* ANSI C doesn't define a call to malloc(2) for 0 bytes. */
259 if (tp
->lb_len
= total_len
) {
260 MALLOC(sp
, tp
->lb
, CHAR_T
*, tp
->lb_len
);
261 if (tp
->lb
== NULL
) {
265 if (p
!= NULL
&& len
!= 0)
266 memmove(tp
->lb
, p
, len
);
270 tp
->ai
= tp
->insert
= tp
->offset
= tp
->owrite
= 0;
278 * Free a chain of text structures.
286 while ((tp
= headp
->cqh_first
) != (void *)headp
) {
287 CIRCLEQ_REMOVE(headp
, tp
, q
);
294 * Free a text structure.
301 FREE(tp
->lb
, tp
->lb_len
);
303 FREE(tp
->wd
, tp
->wd_len
);
304 FREE(tp
, sizeof(TEXT
));
309 * Put text buffer contents into the file.
312 * Historically, pasting into a file with no lines in vi would preserve
313 * the single blank line. This is almost certainly a result of the fact
314 * that historic vi couldn't deal with a file that had no lines in it.
315 * This implementation treats that as a bug, and does not retain the
319 put(sp
, ep
, cbp
, namep
, cp
, rp
, append
)
330 size_t blen
, clen
, len
;
337 msgq(sp
, M_ERR
, "The default buffer is empty.");
342 CBNAME(sp
, cbp
, name
);
345 "Buffer %s is empty.", charname(sp
, name
));
349 tp
= cbp
->textq
.cqh_first
;
352 * It's possible to do a put into an empty file, meaning that the
353 * cut buffer simply becomes the file. It's a special case so
354 * that we can ignore it in general.
356 * Historical practice is that the cursor ends up on the first
357 * non-blank character of the first line inserted.
360 if (file_lline(sp
, ep
, &lno
))
363 for (; tp
!= (void *)&cbp
->textq
;
364 ++lno
, tp
= tp
->q
.cqe_next
)
365 if (file_aline(sp
, ep
, 1, lno
, tp
->lb
, tp
->len
))
369 (void)nonblank(sp
, ep
, rp
->lno
, &rp
->cno
);
374 /* If a line mode buffer, append each new line into the file. */
375 if (F_ISSET(cbp
, CB_LMODE
)) {
376 lno
= append
? cp
->lno
: cp
->lno
- 1;
378 for (; tp
!= (void *)&cbp
->textq
; ++lno
, tp
= tp
->q
.cqe_next
)
379 if (file_aline(sp
, ep
, 1, lno
, tp
->lb
, tp
->len
))
382 (void)nonblank(sp
, ep
, rp
->lno
, &rp
->cno
);
387 * If buffer was cut in character mode, replace the current line with
388 * one built from the portion of the first line to the left of the
389 * split plus the first line in the CB. Append each intermediate line
390 * in the CB. Append a line built from the portion of the first line
391 * to the right of the split plus the last line in the CB.
393 * Get the first line.
396 if ((p
= file_gline(sp
, ep
, lno
, &len
)) == NULL
) {
397 GETLINE_ERR(sp
, lno
);
401 GET_SPACE_RET(sp
, bp
, blen
, tp
->len
+ len
+ 1);
404 /* Original line, left of the split. */
405 if (len
> 0 && (clen
= cp
->cno
+ (append
? 1 : 0)) > 0) {
406 memmove(bp
, p
, clen
);
411 /* First line from the CB. */
412 memmove(t
, tp
->lb
, tp
->len
);
415 /* Calculate length left in original line. */
416 clen
= len
? len
- cp
->cno
- (append
? 1 : 0) : 0;
419 * If no more lines in the CB, append the rest of the original
420 * line and quit. Otherwise, build the last line before doing
421 * the intermediate lines, because the line changes will lose
424 if (tp
->q
.cqe_next
== (void *)&cbp
->textq
) {
426 * Historical practice is that if a non-line mode put
427 * is inside a single line, the cursor ends up on the
428 * last character inserted.
431 rp
->cno
= (t
- bp
) - 1;
437 if (file_sline(sp
, ep
, lno
, bp
, t
- bp
))
441 * Have to build both the first and last lines of the
442 * put before doing any sets or we'll lose the cached
443 * line. Build both the first and last lines in the
444 * same buffer, so we don't have to have another buffer
447 * Last part of original line; check for space, reset
448 * the pointer into the buffer.
450 ltp
= cbp
->textq
.cqh_last
;
452 ADD_SPACE_RET(sp
, bp
, blen
, ltp
->len
+ clen
);
455 /* Add in last part of the CB. */
456 memmove(t
, ltp
->lb
, ltp
->len
);
458 memmove(t
+ ltp
->len
, p
, clen
);
462 * Now: bp points to the first character of the first
463 * line, t points to the last character of the last
464 * line, t - bp is the length of the first line, and
465 * clen is the length of the last. Just figured you'd
468 * Output the line replacing the original line.
470 if (file_sline(sp
, ep
, lno
, bp
, t
- bp
))
474 * Historical practice is that if a non-line mode put
475 * covers multiple lines, the cursor ends up on the
476 * first character inserted. (Of course.)
479 rp
->cno
= (t
- bp
) - 1;
481 /* Output any intermediate lines in the CB. */
482 for (tp
= tp
->q
.cqe_next
;
483 tp
->q
.cqe_next
!= (void *)&cbp
->textq
;
484 ++lno
, tp
= tp
->q
.cqe_next
)
485 if (file_aline(sp
, ep
, 1, lno
, tp
->lb
, tp
->len
))
488 if (file_aline(sp
, ep
, 1, lno
, t
, clen
)) {
489 mem
: FREE_SPACE(sp
, bp
, blen
);
493 FREE_SPACE(sp
, bp
, blen
);
496 ret
: sp
->rptlines
[L_PUT
] += lno
- cp
->lno
;