1 #if !defined(lint) && !defined(DOS)
2 static char rcsid
[] = "$Id: line.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2016 Eduardo Chappa
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.apache.org/licenses/LICENSE-2.0
16 * ========================================================================
18 * Program: Line management routines
22 * The functions in this file are a general set of line management utilities.
23 * They are the only routines that touch the text. They also touch the buffer
24 * and window structures, to make sure that the necessary updating gets done.
25 * There are routines in this file that handle the kill buffer too. It isn't
26 * here for any good reason.
28 * Note that this code only updates the dot and mark values in the window list.
29 * Since all the code acts on the current window, the buffer that we are
30 * editing must be being displayed, which means that "b_nwnd" is non zero,
31 * which means that the dot and mark values in the buffer headers are nonsense.
36 #define NBLOCK 16 /* Line block chunk size */
37 #define KBLOCK 1024 /* Kill buffer block size */
41 * Struct to manage the kill and justify buffers
44 short used
; /* # of characters used in this buffer */
45 UCS bufp
[KBLOCK
]; /* buffer containing text */
46 struct pkchunk
*next
; /* pointer to next chunk */
50 long total
; /* # of UCS characters used in buffer */
51 struct pkchunk
*first
; /* first one of these in the chain */
52 struct pkchunk
*last
; /* last one of these in the chain */
56 void insspace(int, int);
57 int ldelnewline(void);
58 void pkbufdel(struct pkbuf
**);
59 void pkchunkdel(struct pkchunk
**);
60 int pkbufinsert(UCS
, struct pkbuf
**);
61 long pkbufremove(int, struct pkbuf
*);
65 * This routine allocates a block of memory large enough to hold a LINE
66 * containing "used" characters. The block is always rounded up a bit. Return
67 * a pointer to the new block, or NULL if there isn't any memory left. Print a
68 * message in the message line if no space.
76 static int displayed
= 0;
78 if((size
= (used
+NBLOCK
-1) & ~(NBLOCK
-1)) > NLINE
)
81 if (size
== 0) /* Assume that an empty */
82 size
= NBLOCK
; /* line is for type-in. */
84 if (displayed
== 0 && (lp
= (LINE
*) malloc(sizeof(LINE
)+(size
*sizeof(CELL
)))) == NULL
){
85 eml
.s
= comatose(size
);
86 emlwrite("Cannot allocate %s bytes (read file incomplete)", &eml
);
93 lp
->l_sig
= 0; /* assume it is not a signature line */
98 * Delete line "lp". Fix all of the links that might point at it (they are
99 * moved to offset 0 of the next line. Unlink the line from whatever buffer it
100 * might be in. Release the memory. The buffers are updated too; the magic
101 * conditions described in the above comments don't hold here.
111 if (wp
->w_linep
== lp
)
112 wp
->w_linep
= lp
->l_fp
;
114 if (wp
->w_dotp
== lp
) {
115 wp
->w_dotp
= lp
->l_fp
;
119 if (wp
->w_markp
== lp
) {
120 wp
->w_markp
= lp
->l_fp
;
124 if (wp
->w_imarkp
== lp
) {
125 wp
->w_imarkp
= lp
->l_fp
;
134 if (bp
->b_nwnd
== 0) {
135 if (bp
->b_dotp
== lp
) {
136 bp
->b_dotp
= lp
->l_fp
;
140 if (bp
->b_markp
== lp
) {
141 bp
->b_markp
= lp
->l_fp
;
149 lp
->l_bp
->l_fp
= lp
->l_fp
;
150 lp
->l_fp
->l_bp
= lp
->l_bp
;
156 * This routine gets called when a character is changed in place in the current
157 * buffer. It updates all of the required flags in the buffer and window
158 * system. The flag used is passed as an argument; if the buffer is being
159 * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
160 * mode line needs to be updated (the "*" has to be set).
167 if (curbp
->b_nwnd
!= 1) /* Ensure hard. */
170 if ((curbp
->b_flag
&BFCHG
) == 0) { /* First change, so */
172 flag
|= WFMODE
; /* update mode lines. */
173 curbp
->b_flag
|= BFCHG
;
178 if (wp
->w_bufp
== curbp
)
186 * insert spaces forward into text
187 * default flag and numeric argument
190 insspace(int f
, int n
)
197 * Insert "n" copies of the character "c" at the current location of dot. In
198 * the easy case all that happens is the text is stored in the line. In the
199 * hard case, the line has to be reallocated. When the window list is updated,
200 * take special care; I screwed it up once. You always update dot in the
201 * current window. You update mark, and a dot in another window, if it is
202 * greater than the place where you did the insert. Return TRUE if all is
203 * well, and FALSE on errors.
206 linsert(int n
, UCS c
)
212 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
213 return(rdonly()); /* we are in read only mode */
215 dotp
= curwp
->w_dotp
;
216 doto
= curwp
->w_doto
;
219 if(!geninsert(&(curwp
->w_dotp
), &(curwp
->w_doto
), curbp
->b_linep
,
220 c
, (curwp
->w_markp
) ? 1 : 0, n
, &curbp
->b_linecnt
))
223 wp
= wheadp
; /* Update windows */
225 if (wp
->w_linep
== dotp
)
226 wp
->w_linep
= wp
->w_dotp
;
228 if (wp
->w_imarkp
== dotp
) { /* added for internal mark */
229 wp
->w_imarkp
= wp
->w_dotp
;
230 if (wp
->w_imarko
> doto
)
234 if (wp
->w_markp
== dotp
) {
236 if (wp
->w_marko
> doto
)
247 * geninsert - do the actual work of inserting a character into
251 geninsert(LINE
**dotp
, int *doto
, LINE
*linep
, UCS c
, int attb
, int n
, long *lines
)
260 if (*dotp
== linep
) { /* At the end: special */
262 emlwrite("Programmer botch: geninsert", NULL
);
266 if ((lp1
=lalloc(n
)) == NULL
) /* Allocate new line */
269 lp2
= (*dotp
)->l_bp
; /* Previous line */
270 lp2
->l_fp
= lp1
; /* Link in */
276 ac
.c
= (c
& CELLMASK
);
277 cp1
= &(*dotp
)->l_text
[0];
287 if ((*dotp
)->l_used
+n
> (*dotp
)->l_size
) { /* Hard: reallocate */
288 if ((lp1
=lalloc((*dotp
)->l_used
+n
)) == NULL
)
291 cp1
= &(*dotp
)->l_text
[0];
292 cp2
= &lp1
->l_text
[0];
293 while (cp1
!= &(*dotp
)->l_text
[*doto
])
297 while (cp1
!= &(*dotp
)->l_text
[(*dotp
)->l_used
])
300 (*dotp
)->l_bp
->l_fp
= lp1
;
301 lp1
->l_fp
= (*dotp
)->l_fp
;
302 (*dotp
)->l_fp
->l_bp
= lp1
;
303 lp1
->l_bp
= (*dotp
)->l_bp
;
305 /* global may be keeping track of mark/imark */
307 if (wheadp
->w_imarkp
== *dotp
)
308 wheadp
->w_imarkp
= lp1
;
310 if (wheadp
->w_markp
== *dotp
)
311 wheadp
->w_markp
= lp1
;
314 free((char *) (*dotp
));
316 } else { /* Easy: in place */
317 (*dotp
)->l_used
+= n
;
318 cp2
= &(*dotp
)->l_text
[(*dotp
)->l_used
];
320 while (cp1
!= &(*dotp
)->l_text
[*doto
])
324 ac
.c
= (c
& CELLMASK
);
325 while(n
--) /* add the chars */
326 (*dotp
)->l_text
[(*doto
)++] = ac
;
333 * Insert a newline into the buffer at the current location of dot in the
334 * current window. The funny ass-backwards way it does things is not a botch;
335 * it just makes the last line in the file not a special case. Return TRUE if
336 * everything works out and FALSE on error (memory allocation failure). The
337 * update of dot and mark is a bit easier than in the above case, because the
338 * split forces more updating.
350 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
351 return(rdonly()); /* we are in read only mode */
354 lp1
= curwp
->w_dotp
; /* Get the address and */
355 doto
= curwp
->w_doto
; /* offset of "." */
356 if ((lp2
=lalloc(doto
)) == NULL
) /* New first half line */
359 cp1
= &lp1
->l_text
[0]; /* Shuffle text around */
360 cp2
= &lp2
->l_text
[0];
361 while (cp1
!= &lp1
->l_text
[doto
])
364 cp2
= &lp1
->l_text
[0];
365 while (cp1
!= &lp1
->l_text
[lp1
->l_used
])
369 lp2
->l_bp
= lp1
->l_bp
;
371 lp2
->l_bp
->l_fp
= lp2
;
373 wp
= wheadp
; /* Windows */
375 if (wp
->w_linep
== lp1
)
378 if (wp
->w_dotp
== lp1
) {
379 if (wp
->w_doto
< doto
)
385 if (wp
->w_imarkp
== lp1
) { /* ADDED for internal mark */
386 if (wp
->w_imarko
< doto
)
389 wp
->w_imarko
-= doto
;
392 if (wp
->w_markp
== lp1
) {
393 if (wp
->w_marko
< doto
)
402 * Keep track of the number of lines in the buffer.
410 * This function deletes "n" characters, starting at dot. It understands how do deal
411 * with end of lines, etc. It returns TRUE if all of the characters were
412 * deleted, and FALSE if they were not (because dot ran into the end of the
413 * buffer. The "preserve" function is used to save what was deleted.
416 ldelete(long n
, int (*preserve
)(UCS
))
425 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
426 return(rdonly()); /* we are in read only mode */
429 dotp
= curwp
->w_dotp
;
430 doto
= curwp
->w_doto
;
431 if (dotp
== curbp
->b_linep
) /* Hit end of buffer. */
433 chunk
= dotp
->l_used
-doto
; /* Size of chunk. */
436 if (chunk
== 0) { /* End of line, merge. */
438 if (ldelnewline() == FALSE
439 || (preserve
? (*preserve
)('\n') == FALSE
: 0))
446 cp1
= &dotp
->l_text
[doto
]; /* Scrunch text. */
448 if (preserve
) { /* Kill? */
450 if ((*preserve
)(cp1
->c
) == FALSE
)
454 cp1
= &dotp
->l_text
[doto
];
457 while (cp2
!= &dotp
->l_text
[dotp
->l_used
])
460 dotp
->l_used
-= chunk
;
461 wp
= wheadp
; /* Fix windows */
463 if (wp
->w_dotp
==dotp
&& wp
->w_doto
>=doto
) {
465 if (wp
->w_doto
< doto
)
469 if (wp
->w_markp
==dotp
&& wp
->w_marko
>=doto
) {
470 wp
->w_marko
-= chunk
;
471 if (wp
->w_marko
< doto
)
475 if (wp
->w_imarkp
==dotp
&& wp
->w_imarko
>=doto
) {
476 wp
->w_imarko
-= chunk
;
477 if (wp
->w_imarko
< doto
)
487 if (preserve
== kinsert
&& ksize() > 0)
488 mswin_killbuftoclip (kremove
);
495 * Delete a newline. Join the current line with the next line. If the next line
496 * is the magic header line always return TRUE; merging the last line with the
497 * header line can be thought of as always being a successful operation, even
498 * if nothing is done, and this makes the kill buffer work "right". Easy cases
499 * can be done by shuffling data around. Hard cases require that lines be moved
500 * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
513 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
514 return(rdonly()); /* we are in read only mode */
518 if (lp2
== curbp
->b_linep
) { /* At the buffer end. */
519 if (lp1
->l_used
== 0) { /* Blank line. */
527 if (lp2
->l_used
<= lp1
->l_size
-lp1
->l_used
) {
528 cp1
= &lp1
->l_text
[lp1
->l_used
];
529 cp2
= &lp2
->l_text
[0];
530 while (cp2
!= &lp2
->l_text
[lp2
->l_used
])
535 if (wp
->w_linep
== lp2
)
537 if (wp
->w_dotp
== lp2
) {
539 wp
->w_doto
+= lp1
->l_used
;
541 if (wp
->w_markp
== lp2
) {
543 wp
->w_marko
+= lp1
->l_used
;
545 if (wp
->w_imarkp
== lp2
) {
547 wp
->w_imarko
+= lp1
->l_used
;
551 lp1
->l_used
+= lp2
->l_used
;
552 lp1
->l_fp
= lp2
->l_fp
;
553 lp2
->l_fp
->l_bp
= lp1
;
559 if ((lp3
=lalloc(lp1
->l_used
+lp2
->l_used
)) == NULL
)
562 cp1
= &lp1
->l_text
[0];
563 cp2
= &lp3
->l_text
[0];
564 while (cp1
!= &lp1
->l_text
[lp1
->l_used
])
567 cp1
= &lp2
->l_text
[0];
568 while (cp1
!= &lp2
->l_text
[lp2
->l_used
])
571 lp1
->l_bp
->l_fp
= lp3
;
572 lp3
->l_fp
= lp2
->l_fp
;
573 lp2
->l_fp
->l_bp
= lp3
;
574 lp3
->l_bp
= lp1
->l_bp
;
577 if (wp
->w_linep
==lp1
|| wp
->w_linep
==lp2
)
579 if (wp
->w_dotp
== lp1
)
581 else if (wp
->w_dotp
== lp2
) {
583 wp
->w_doto
+= lp1
->l_used
;
585 if (wp
->w_markp
== lp1
)
587 else if (wp
->w_markp
== lp2
) {
589 wp
->w_marko
+= lp1
->l_used
;
591 if (wp
->w_imarkp
== lp1
)
593 else if (wp
->w_imarkp
== lp2
) {
595 wp
->w_imarko
+= lp1
->l_used
;
608 * Tell the caller if the given line is blank or not.
617 && quote_match(glo_quote_str
, line
, qstr
, NLINE
))
618 ? ucs4_strlen(qstr
) : 0;
620 for(; n
< llength(line
); n
++)
621 if(!ucs4_isspace(lgetc(line
, n
).c
)
622 || lgetc(line
, n
).c
>= 0xff
623 || (unsigned char) lgetc(line
,n
).c
!= NBSPC
)
631 * Delete all of the text saved in the kill buffer. Called by commands when a
632 * new kill context is being created. The kill buffer array is released, just
633 * in case the buffer has grown to immense size. No errors.
648 pkbufdel(struct pkbuf
**buf
)
651 pkchunkdel(&(*buf
)->first
);
659 pkchunkdel(struct pkchunk
**chunk
)
663 pkchunkdel(&(*chunk
)->next
);
665 free((char *) *chunk
);
672 * Insert a character to the kill buffer, enlarging the buffer if there isn't
673 * any room. Always grow the buffer in chunks, on the assumption that if you
674 * put something in the kill buffer you are going to put more stuff there too
675 * later. Return TRUE if all is well, and FALSE on errors.
680 return(pkbufinsert(c
, &kbufp
));
686 return(pkbufinsert(c
, &fbufp
));
690 pkbufinsert(UCS c
, struct pkbuf
**buf
)
693 if((*buf
= (struct pkbuf
*) malloc(sizeof(struct pkbuf
))) != NULL
)
694 memset(*buf
, 0, sizeof(struct pkbuf
));
699 if((*buf
)->total
% KBLOCK
== 0){
700 struct pkchunk
*p
= (*buf
)->last
;
701 if(((*buf
)->last
= (struct pkchunk
*) malloc(sizeof(struct pkchunk
))) != NULL
){
702 memset((*buf
)->last
, 0, sizeof(struct pkchunk
));
704 p
->next
= (*buf
)->last
;
706 (*buf
)->first
= (*buf
)->last
;
712 (*buf
)->last
->bufp
[(*buf
)->last
->used
++] = c
;
719 * These functions get characters from the requested buffer. If the
720 * character index "n" is off the end, it returns "-1". This lets the
721 * caller just scan along until it gets a "-1" back.
726 return(pkbufremove(n
, kbufp
));
732 return(pkbufremove(n
, fbufp
));
737 * This would be type UCS except that it needs to return -1.
740 pkbufremove(int n
, struct pkbuf
*buf
)
742 if(n
>= 0 && buf
&& n
< buf
->total
){
743 register struct pkchunk
*p
= buf
->first
;
744 int block
= n
/ KBLOCK
;
750 return(p
->bufp
[n
% KBLOCK
]);
758 * This function just returns the current size of the kill buffer
763 return(kbufp
? (int) kbufp
->total
: 0);
767 static REGION last_region_added
;
770 set_last_region_added(REGION
*region
)
773 last_region_added
= (*region
);
775 memset(&last_region_added
, 0, sizeof(last_region_added
));
780 get_last_region_added(void)
782 return(&last_region_added
);