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
);
97 * Delete line "lp". Fix all of the links that might point at it (they are
98 * moved to offset 0 of the next line. Unlink the line from whatever buffer it
99 * might be in. Release the memory. The buffers are updated too; the magic
100 * conditions described in the above comments don't hold here.
110 if (wp
->w_linep
== lp
)
111 wp
->w_linep
= lp
->l_fp
;
113 if (wp
->w_dotp
== lp
) {
114 wp
->w_dotp
= lp
->l_fp
;
118 if (wp
->w_markp
== lp
) {
119 wp
->w_markp
= lp
->l_fp
;
123 if (wp
->w_imarkp
== lp
) {
124 wp
->w_imarkp
= lp
->l_fp
;
133 if (bp
->b_nwnd
== 0) {
134 if (bp
->b_dotp
== lp
) {
135 bp
->b_dotp
= lp
->l_fp
;
139 if (bp
->b_markp
== lp
) {
140 bp
->b_markp
= lp
->l_fp
;
148 lp
->l_bp
->l_fp
= lp
->l_fp
;
149 lp
->l_fp
->l_bp
= lp
->l_bp
;
155 * This routine gets called when a character is changed in place in the current
156 * buffer. It updates all of the required flags in the buffer and window
157 * system. The flag used is passed as an argument; if the buffer is being
158 * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
159 * mode line needs to be updated (the "*" has to be set).
166 if (curbp
->b_nwnd
!= 1) /* Ensure hard. */
169 if ((curbp
->b_flag
&BFCHG
) == 0) { /* First change, so */
171 flag
|= WFMODE
; /* update mode lines. */
172 curbp
->b_flag
|= BFCHG
;
177 if (wp
->w_bufp
== curbp
)
185 * insert spaces forward into text
186 * default flag and numeric argument
189 insspace(int f
, int n
)
196 * Insert "n" copies of the character "c" at the current location of dot. In
197 * the easy case all that happens is the text is stored in the line. In the
198 * hard case, the line has to be reallocated. When the window list is updated,
199 * take special care; I screwed it up once. You always update dot in the
200 * current window. You update mark, and a dot in another window, if it is
201 * greater than the place where you did the insert. Return TRUE if all is
202 * well, and FALSE on errors.
205 linsert(int n
, UCS c
)
211 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
212 return(rdonly()); /* we are in read only mode */
214 dotp
= curwp
->w_dotp
;
215 doto
= curwp
->w_doto
;
218 if(!geninsert(&(curwp
->w_dotp
), &(curwp
->w_doto
), curbp
->b_linep
,
219 c
, (curwp
->w_markp
) ? 1 : 0, n
, &curbp
->b_linecnt
))
222 wp
= wheadp
; /* Update windows */
224 if (wp
->w_linep
== dotp
)
225 wp
->w_linep
= wp
->w_dotp
;
227 if (wp
->w_imarkp
== dotp
) { /* added for internal mark */
228 wp
->w_imarkp
= wp
->w_dotp
;
229 if (wp
->w_imarko
> doto
)
233 if (wp
->w_markp
== dotp
) {
235 if (wp
->w_marko
> doto
)
246 * geninsert - do the actual work of inserting a character into
250 geninsert(LINE
**dotp
, int *doto
, LINE
*linep
, UCS c
, int attb
, int n
, long *lines
)
259 if (*dotp
== linep
) { /* At the end: special */
261 emlwrite("Programmer botch: geninsert", NULL
);
265 if ((lp1
=lalloc(n
)) == NULL
) /* Allocate new line */
268 lp2
= (*dotp
)->l_bp
; /* Previous line */
269 lp2
->l_fp
= lp1
; /* Link in */
275 ac
.c
= (c
& CELLMASK
);
276 cp1
= &(*dotp
)->l_text
[0];
286 if ((*dotp
)->l_used
+n
> (*dotp
)->l_size
) { /* Hard: reallocate */
287 if ((lp1
=lalloc((*dotp
)->l_used
+n
)) == NULL
)
290 cp1
= &(*dotp
)->l_text
[0];
291 cp2
= &lp1
->l_text
[0];
292 while (cp1
!= &(*dotp
)->l_text
[*doto
])
296 while (cp1
!= &(*dotp
)->l_text
[(*dotp
)->l_used
])
299 (*dotp
)->l_bp
->l_fp
= lp1
;
300 lp1
->l_fp
= (*dotp
)->l_fp
;
301 (*dotp
)->l_fp
->l_bp
= lp1
;
302 lp1
->l_bp
= (*dotp
)->l_bp
;
304 /* global may be keeping track of mark/imark */
306 if (wheadp
->w_imarkp
== *dotp
)
307 wheadp
->w_imarkp
= lp1
;
309 if (wheadp
->w_markp
== *dotp
)
310 wheadp
->w_markp
= lp1
;
313 free((char *) (*dotp
));
315 } else { /* Easy: in place */
316 (*dotp
)->l_used
+= n
;
317 cp2
= &(*dotp
)->l_text
[(*dotp
)->l_used
];
319 while (cp1
!= &(*dotp
)->l_text
[*doto
])
323 ac
.c
= (c
& CELLMASK
);
324 while(n
--) /* add the chars */
325 (*dotp
)->l_text
[(*doto
)++] = ac
;
332 * Insert a newline into the buffer at the current location of dot in the
333 * current window. The funny ass-backwards way it does things is not a botch;
334 * it just makes the last line in the file not a special case. Return TRUE if
335 * everything works out and FALSE on error (memory allocation failure). The
336 * update of dot and mark is a bit easier than in the above case, because the
337 * split forces more updating.
349 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
350 return(rdonly()); /* we are in read only mode */
353 lp1
= curwp
->w_dotp
; /* Get the address and */
354 doto
= curwp
->w_doto
; /* offset of "." */
355 if ((lp2
=lalloc(doto
)) == NULL
) /* New first half line */
358 cp1
= &lp1
->l_text
[0]; /* Shuffle text around */
359 cp2
= &lp2
->l_text
[0];
360 while (cp1
!= &lp1
->l_text
[doto
])
363 cp2
= &lp1
->l_text
[0];
364 while (cp1
!= &lp1
->l_text
[lp1
->l_used
])
368 lp2
->l_bp
= lp1
->l_bp
;
370 lp2
->l_bp
->l_fp
= lp2
;
372 wp
= wheadp
; /* Windows */
374 if (wp
->w_linep
== lp1
)
377 if (wp
->w_dotp
== lp1
) {
378 if (wp
->w_doto
< doto
)
384 if (wp
->w_imarkp
== lp1
) { /* ADDED for internal mark */
385 if (wp
->w_imarko
< doto
)
388 wp
->w_imarko
-= doto
;
391 if (wp
->w_markp
== lp1
) {
392 if (wp
->w_marko
< doto
)
401 * Keep track of the number of lines in the buffer.
409 * This function deletes "n" characters, starting at dot. It understands how do deal
410 * with end of lines, etc. It returns TRUE if all of the characters were
411 * deleted, and FALSE if they were not (because dot ran into the end of the
412 * buffer. The "preserve" function is used to save what was deleted.
415 ldelete(long n
, int (*preserve
)(UCS
))
424 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
425 return(rdonly()); /* we are in read only mode */
428 dotp
= curwp
->w_dotp
;
429 doto
= curwp
->w_doto
;
430 if (dotp
== curbp
->b_linep
) /* Hit end of buffer. */
432 chunk
= dotp
->l_used
-doto
; /* Size of chunk. */
435 if (chunk
== 0) { /* End of line, merge. */
437 if (ldelnewline() == FALSE
438 || (preserve
? (*preserve
)('\n') == FALSE
: 0))
445 cp1
= &dotp
->l_text
[doto
]; /* Scrunch text. */
447 if (preserve
) { /* Kill? */
449 if ((*preserve
)(cp1
->c
) == FALSE
)
453 cp1
= &dotp
->l_text
[doto
];
456 while (cp2
!= &dotp
->l_text
[dotp
->l_used
])
459 dotp
->l_used
-= chunk
;
460 wp
= wheadp
; /* Fix windows */
462 if (wp
->w_dotp
==dotp
&& wp
->w_doto
>=doto
) {
464 if (wp
->w_doto
< doto
)
468 if (wp
->w_markp
==dotp
&& wp
->w_marko
>=doto
) {
469 wp
->w_marko
-= chunk
;
470 if (wp
->w_marko
< doto
)
474 if (wp
->w_imarkp
==dotp
&& wp
->w_imarko
>=doto
) {
475 wp
->w_imarko
-= chunk
;
476 if (wp
->w_imarko
< doto
)
486 if (preserve
== kinsert
&& ksize() > 0)
487 mswin_killbuftoclip (kremove
);
494 * Delete a newline. Join the current line with the next line. If the next line
495 * is the magic header line always return TRUE; merging the last line with the
496 * header line can be thought of as always being a successful operation, even
497 * if nothing is done, and this makes the kill buffer work "right". Easy cases
498 * can be done by shuffling data around. Hard cases require that lines be moved
499 * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
512 if (curbp
->b_mode
&MDVIEW
) /* don't allow this command if */
513 return(rdonly()); /* we are in read only mode */
517 if (lp2
== curbp
->b_linep
) { /* At the buffer end. */
518 if (lp1
->l_used
== 0) { /* Blank line. */
526 if (lp2
->l_used
<= lp1
->l_size
-lp1
->l_used
) {
527 cp1
= &lp1
->l_text
[lp1
->l_used
];
528 cp2
= &lp2
->l_text
[0];
529 while (cp2
!= &lp2
->l_text
[lp2
->l_used
])
534 if (wp
->w_linep
== lp2
)
536 if (wp
->w_dotp
== lp2
) {
538 wp
->w_doto
+= lp1
->l_used
;
540 if (wp
->w_markp
== lp2
) {
542 wp
->w_marko
+= lp1
->l_used
;
544 if (wp
->w_imarkp
== lp2
) {
546 wp
->w_imarko
+= lp1
->l_used
;
550 lp1
->l_used
+= lp2
->l_used
;
551 lp1
->l_fp
= lp2
->l_fp
;
552 lp2
->l_fp
->l_bp
= lp1
;
558 if ((lp3
=lalloc(lp1
->l_used
+lp2
->l_used
)) == NULL
)
561 cp1
= &lp1
->l_text
[0];
562 cp2
= &lp3
->l_text
[0];
563 while (cp1
!= &lp1
->l_text
[lp1
->l_used
])
566 cp1
= &lp2
->l_text
[0];
567 while (cp1
!= &lp2
->l_text
[lp2
->l_used
])
570 lp1
->l_bp
->l_fp
= lp3
;
571 lp3
->l_fp
= lp2
->l_fp
;
572 lp2
->l_fp
->l_bp
= lp3
;
573 lp3
->l_bp
= lp1
->l_bp
;
576 if (wp
->w_linep
==lp1
|| wp
->w_linep
==lp2
)
578 if (wp
->w_dotp
== lp1
)
580 else if (wp
->w_dotp
== lp2
) {
582 wp
->w_doto
+= lp1
->l_used
;
584 if (wp
->w_markp
== lp1
)
586 else if (wp
->w_markp
== lp2
) {
588 wp
->w_marko
+= lp1
->l_used
;
590 if (wp
->w_imarkp
== lp1
)
592 else if (wp
->w_imarkp
== lp2
) {
594 wp
->w_imarko
+= lp1
->l_used
;
607 * Tell the caller if the given line is blank or not.
616 && quote_match(glo_quote_str
, line
, qstr
, NLINE
))
617 ? ucs4_strlen(qstr
) : 0;
619 for(; n
< llength(line
); n
++)
620 if(!ucs4_isspace(lgetc(line
, n
).c
)
621 || lgetc(line
, n
).c
>= 0xff
622 || (unsigned char) lgetc(line
,n
).c
!= NBSPC
)
630 * Delete all of the text saved in the kill buffer. Called by commands when a
631 * new kill context is being created. The kill buffer array is released, just
632 * in case the buffer has grown to immense size. No errors.
647 pkbufdel(struct pkbuf
**buf
)
650 pkchunkdel(&(*buf
)->first
);
658 pkchunkdel(struct pkchunk
**chunk
)
662 pkchunkdel(&(*chunk
)->next
);
664 free((char *) *chunk
);
671 * Insert a character to the kill buffer, enlarging the buffer if there isn't
672 * any room. Always grow the buffer in chunks, on the assumption that if you
673 * put something in the kill buffer you are going to put more stuff there too
674 * later. Return TRUE if all is well, and FALSE on errors.
679 return(pkbufinsert(c
, &kbufp
));
685 return(pkbufinsert(c
, &fbufp
));
689 pkbufinsert(UCS c
, struct pkbuf
**buf
)
692 if((*buf
= (struct pkbuf
*) malloc(sizeof(struct pkbuf
))) != NULL
)
693 memset(*buf
, 0, sizeof(struct pkbuf
));
698 if((*buf
)->total
% KBLOCK
== 0){
699 struct pkchunk
*p
= (*buf
)->last
;
700 if(((*buf
)->last
= (struct pkchunk
*) malloc(sizeof(struct pkchunk
))) != NULL
){
701 memset((*buf
)->last
, 0, sizeof(struct pkchunk
));
703 p
->next
= (*buf
)->last
;
705 (*buf
)->first
= (*buf
)->last
;
711 (*buf
)->last
->bufp
[(*buf
)->last
->used
++] = c
;
718 * These functions get characters from the requested buffer. If the
719 * character index "n" is off the end, it returns "-1". This lets the
720 * caller just scan along until it gets a "-1" back.
725 return(pkbufremove(n
, kbufp
));
731 return(pkbufremove(n
, fbufp
));
736 * This would be type UCS except that it needs to return -1.
739 pkbufremove(int n
, struct pkbuf
*buf
)
741 if(n
>= 0 && buf
&& n
< buf
->total
){
742 register struct pkchunk
*p
= buf
->first
;
743 int block
= n
/ KBLOCK
;
749 return(p
->bufp
[n
% KBLOCK
]);
757 * This function just returns the current size of the kill buffer
762 return(kbufp
? (int) kbufp
->total
: 0);
766 static REGION last_region_added
;
769 set_last_region_added(REGION
*region
)
772 last_region_added
= (*region
);
774 memset(&last_region_added
, 0, sizeof(last_region_added
));
779 get_last_region_added(void)
781 return(&last_region_added
);