* Deactivate some color code from Pico (as standalone editor) until
[alpine.git] / pico / line.c
blob582954702569fe2b8cc2c7f6a80d85f96ce3504a
1 #if !defined(lint) && !defined(DOS)
2 static char rcsid[] = "$Id: line.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $";
3 #endif
5 /*
6 * ========================================================================
7 * Copyright 2006-2007 University of Washington
8 * Copyright 2013-2017 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.
34 #include "headers.h"
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
43 struct pkchunk {
44 short used; /* # of characters used in this buffer */
45 UCS bufp[KBLOCK]; /* buffer containing text */
46 struct pkchunk *next; /* pointer to next chunk */
49 static struct pkbuf {
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 */
53 } *kbufp, *fbufp;
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.
70 LINE *
71 lalloc(int used)
73 register LINE *lp;
74 register int size;
75 EML eml;
76 static int displayed = 0;
78 if((size = (used+NBLOCK-1) & ~(NBLOCK-1)) > NLINE)
79 size *= 2;
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);
87 displayed++;
88 return (NULL);
91 lp->l_size = size;
92 lp->l_used = used;
93 lp->l_sig = 0; /* assume it is not a signature line */
94 return (lp);
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.
103 void
104 lfree(LINE *lp)
106 register BUFFER *bp;
107 register WINDOW *wp;
109 wp = wheadp;
110 while (wp != NULL) {
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;
116 wp->w_doto = 0;
119 if (wp->w_markp == lp) {
120 wp->w_markp = lp->l_fp;
121 wp->w_marko = 0;
124 if (wp->w_imarkp == lp) {
125 wp->w_imarkp = lp->l_fp;
126 wp->w_imarko = 0;
129 wp = wp->w_wndp;
132 bp = bheadp;
133 while (bp != NULL) {
134 if (bp->b_nwnd == 0) {
135 if (bp->b_dotp == lp) {
136 bp->b_dotp = lp->l_fp;
137 bp->b_doto = 0;
140 if (bp->b_markp == lp) {
141 bp->b_markp = lp->l_fp;
142 bp->b_marko = 0;
146 bp = bp->b_bufp;
149 lp->l_bp->l_fp = lp->l_fp;
150 lp->l_fp->l_bp = lp->l_bp;
151 free((char *) lp);
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).
162 void
163 lchange(int flag)
165 register WINDOW *wp;
167 if (curbp->b_nwnd != 1) /* Ensure hard. */
168 flag = WFHARD;
170 if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
171 if(Pmaster == NULL)
172 flag |= WFMODE; /* update mode lines. */
173 curbp->b_flag |= BFCHG;
176 wp = wheadp;
177 while (wp != NULL) {
178 if (wp->w_bufp == curbp)
179 wp->w_flag |= flag;
180 wp = wp->w_wndp;
186 * insert spaces forward into text
187 * default flag and numeric argument
189 void
190 insspace(int f, int n)
192 linsert(n, ' ');
193 backchar(f, 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)
208 register LINE *dotp;
209 register int doto;
210 register WINDOW *wp;
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;
217 lchange(WFEDIT);
219 if(!geninsert(&(curwp->w_dotp), &(curwp->w_doto), curbp->b_linep,
220 c, (curwp->w_markp) ? 1 : 0, n, &curbp->b_linecnt))
221 return(FALSE);
223 wp = wheadp; /* Update windows */
224 while (wp != NULL) {
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)
231 wp->w_imarko += n;
234 if (wp->w_markp == dotp) {
235 wp->w_markp = dotp;
236 if (wp->w_marko > doto)
237 wp->w_marko += n;
239 wp = wp->w_wndp;
242 return (TRUE);
247 * geninsert - do the actual work of inserting a character into
248 * the list of lines.
251 geninsert(LINE **dotp, int *doto, LINE *linep, UCS c, int attb, int n, long *lines)
253 register LINE *lp1;
254 register LINE *lp2;
255 register CELL *cp1;
256 register CELL *cp2;
257 CELL ac;
259 ac.a = attb;
260 if (*dotp == linep) { /* At the end: special */
261 if (*doto != 0) {
262 emlwrite("Programmer botch: geninsert", NULL);
263 return (FALSE);
266 if ((lp1=lalloc(n)) == NULL) /* Allocate new line */
267 return (FALSE);
269 lp2 = (*dotp)->l_bp; /* Previous line */
270 lp2->l_fp = lp1; /* Link in */
271 lp1->l_fp = *dotp;
272 (*dotp)->l_bp = lp1;
273 lp1->l_bp = lp2;
274 *doto = n;
275 *dotp = lp1;
276 ac.c = (c & CELLMASK);
277 cp1 = &(*dotp)->l_text[0];
278 while(n--)
279 *cp1++ = ac;
281 if(lines)
282 (*lines)++;
284 return (TRUE);
287 if ((*dotp)->l_used+n > (*dotp)->l_size) { /* Hard: reallocate */
288 if ((lp1=lalloc((*dotp)->l_used+n)) == NULL)
289 return (FALSE);
291 cp1 = &(*dotp)->l_text[0];
292 cp2 = &lp1->l_text[0];
293 while (cp1 != &(*dotp)->l_text[*doto])
294 *cp2++ = *cp1++;
296 cp2 += n;
297 while (cp1 != &(*dotp)->l_text[(*dotp)->l_used])
298 *cp2++ = *cp1++;
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 */
306 if(wheadp){
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));
315 *dotp = lp1;
316 } else { /* Easy: in place */
317 (*dotp)->l_used += n;
318 cp2 = &(*dotp)->l_text[(*dotp)->l_used];
319 cp1 = cp2-n;
320 while (cp1 != &(*dotp)->l_text[*doto])
321 *--cp2 = *--cp1;
324 ac.c = (c & CELLMASK);
325 while(n--) /* add the chars */
326 (*dotp)->l_text[(*doto)++] = ac;
328 return(TRUE);
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.
341 lnewline(void)
343 register CELL *cp1;
344 register CELL *cp2;
345 register LINE *lp1;
346 register LINE *lp2;
347 register int doto;
348 register WINDOW *wp;
350 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
351 return(rdonly()); /* we are in read only mode */
353 lchange(WFHARD);
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 */
357 return (FALSE);
359 cp1 = &lp1->l_text[0]; /* Shuffle text around */
360 cp2 = &lp2->l_text[0];
361 while (cp1 != &lp1->l_text[doto])
362 *cp2++ = *cp1++;
364 cp2 = &lp1->l_text[0];
365 while (cp1 != &lp1->l_text[lp1->l_used])
366 *cp2++ = *cp1++;
368 lp1->l_used -= doto;
369 lp2->l_bp = lp1->l_bp;
370 lp1->l_bp = lp2;
371 lp2->l_bp->l_fp = lp2;
372 lp2->l_fp = lp1;
373 wp = wheadp; /* Windows */
374 while (wp != NULL) {
375 if (wp->w_linep == lp1)
376 wp->w_linep = lp2;
378 if (wp->w_dotp == lp1) {
379 if (wp->w_doto < doto)
380 wp->w_dotp = lp2;
381 else
382 wp->w_doto -= doto;
385 if (wp->w_imarkp == lp1) { /* ADDED for internal mark */
386 if (wp->w_imarko < doto)
387 wp->w_imarkp = lp2;
388 else
389 wp->w_imarko -= doto;
392 if (wp->w_markp == lp1) {
393 if (wp->w_marko < doto)
394 wp->w_markp = lp2;
395 else
396 wp->w_marko -= doto;
398 wp = wp->w_wndp;
402 * Keep track of the number of lines in the buffer.
404 ++curbp->b_linecnt;
405 return (TRUE);
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))
418 register CELL *cp1;
419 register CELL *cp2;
420 register LINE *dotp;
421 register int doto;
422 register int chunk;
423 register WINDOW *wp;
425 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
426 return(rdonly()); /* we are in read only mode */
428 while (n != 0) {
429 dotp = curwp->w_dotp;
430 doto = curwp->w_doto;
431 if (dotp == curbp->b_linep) /* Hit end of buffer. */
432 return (FALSE);
433 chunk = dotp->l_used-doto; /* Size of chunk. */
434 if (chunk > n)
435 chunk = n;
436 if (chunk == 0) { /* End of line, merge. */
437 lchange(WFHARD);
438 if (ldelnewline() == FALSE
439 || (preserve ? (*preserve)('\n') == FALSE : 0))
440 return (FALSE);
441 --n;
442 continue;
445 lchange(WFEDIT);
446 cp1 = &dotp->l_text[doto]; /* Scrunch text. */
447 cp2 = cp1 + chunk;
448 if (preserve) { /* Kill? */
449 while (cp1 != cp2) {
450 if ((*preserve)(cp1->c) == FALSE)
451 return (FALSE);
452 ++cp1;
454 cp1 = &dotp->l_text[doto];
457 while (cp2 != &dotp->l_text[dotp->l_used])
458 *cp1++ = *cp2++;
460 dotp->l_used -= chunk;
461 wp = wheadp; /* Fix windows */
462 while (wp != NULL) {
463 if (wp->w_dotp==dotp && wp->w_doto>=doto) {
464 wp->w_doto -= chunk;
465 if (wp->w_doto < doto)
466 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)
472 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)
478 wp->w_imarko = doto;
481 wp = wp->w_wndp;
483 n -= chunk;
486 #ifdef _WINDOWS
487 if (preserve == kinsert && ksize() > 0)
488 mswin_killbuftoclip (kremove);
489 #endif
491 return (TRUE);
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
501 * "ldelete" only.
504 ldelnewline(void)
506 register CELL *cp1;
507 register CELL *cp2;
508 register LINE *lp1;
509 register LINE *lp2;
510 register LINE *lp3;
511 register WINDOW *wp;
513 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
514 return(rdonly()); /* we are in read only mode */
516 lp1 = curwp->w_dotp;
517 lp2 = lp1->l_fp;
518 if (lp2 == curbp->b_linep) { /* At the buffer end. */
519 if (lp1->l_used == 0) { /* Blank line. */
520 lfree(lp1);
521 --curbp->b_linecnt;
524 return (TRUE);
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])
531 *cp1++ = *cp2++;
533 wp = wheadp;
534 while (wp != NULL) {
535 if (wp->w_linep == lp2)
536 wp->w_linep = lp1;
537 if (wp->w_dotp == lp2) {
538 wp->w_dotp = lp1;
539 wp->w_doto += lp1->l_used;
541 if (wp->w_markp == lp2) {
542 wp->w_markp = lp1;
543 wp->w_marko += lp1->l_used;
545 if (wp->w_imarkp == lp2) {
546 wp->w_imarkp = lp1;
547 wp->w_imarko += lp1->l_used;
549 wp = wp->w_wndp;
551 lp1->l_used += lp2->l_used;
552 lp1->l_fp = lp2->l_fp;
553 lp2->l_fp->l_bp = lp1;
554 free((char *) lp2);
555 --curbp->b_linecnt;
556 return (TRUE);
559 if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
560 return (FALSE);
562 cp1 = &lp1->l_text[0];
563 cp2 = &lp3->l_text[0];
564 while (cp1 != &lp1->l_text[lp1->l_used])
565 *cp2++ = *cp1++;
567 cp1 = &lp2->l_text[0];
568 while (cp1 != &lp2->l_text[lp2->l_used])
569 *cp2++ = *cp1++;
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;
575 wp = wheadp;
576 while (wp != NULL) {
577 if (wp->w_linep==lp1 || wp->w_linep==lp2)
578 wp->w_linep = lp3;
579 if (wp->w_dotp == lp1)
580 wp->w_dotp = lp3;
581 else if (wp->w_dotp == lp2) {
582 wp->w_dotp = lp3;
583 wp->w_doto += lp1->l_used;
585 if (wp->w_markp == lp1)
586 wp->w_markp = lp3;
587 else if (wp->w_markp == lp2) {
588 wp->w_markp = lp3;
589 wp->w_marko += lp1->l_used;
591 if (wp->w_imarkp == lp1)
592 wp->w_imarkp = lp3;
593 else if (wp->w_imarkp == lp2) {
594 wp->w_imarkp = lp3;
595 wp->w_imarko += lp1->l_used;
597 wp = wp->w_wndp;
600 free((char *) lp1);
601 free((char *) lp2);
602 --curbp->b_linecnt;
603 return (TRUE);
608 * Tell the caller if the given line is blank or not.
611 lisblank(LINE *line)
613 int n = 0;
614 UCS qstr[NLINE];
616 n = (glo_quote_str
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)
624 return(FALSE);
626 return(TRUE);
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.
635 void
636 kdelete(void)
638 pkbufdel(&kbufp);
641 void
642 fdelete(void)
644 pkbufdel(&fbufp);
647 void
648 pkbufdel(struct pkbuf **buf)
650 if (*buf) {
651 pkchunkdel(&(*buf)->first);
652 free((char *) *buf);
653 *buf = NULL;
658 void
659 pkchunkdel(struct pkchunk **chunk)
661 if(chunk){
662 if((*chunk)->next)
663 pkchunkdel(&(*chunk)->next);
665 free((char *) *chunk);
666 *chunk = NULL;
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.
678 kinsert(UCS c)
680 return(pkbufinsert(c, &kbufp));
684 finsert(UCS c)
686 return(pkbufinsert(c, &fbufp));
690 pkbufinsert(UCS c, struct pkbuf **buf)
692 if(!*buf){
693 if((*buf = (struct pkbuf *) malloc(sizeof(struct pkbuf))) != NULL)
694 memset(*buf, 0, sizeof(struct pkbuf));
695 else
696 return(FALSE);
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));
703 if(p)
704 p->next = (*buf)->last;
705 else
706 (*buf)->first = (*buf)->last;
708 else
709 return(FALSE);
712 (*buf)->last->bufp[(*buf)->last->used++] = c;
713 (*buf)->total++;
714 return (TRUE);
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.
723 long
724 kremove(int n)
726 return(pkbufremove(n, kbufp));
729 long
730 fremove(int n)
732 return(pkbufremove(n, fbufp));
737 * This would be type UCS except that it needs to return -1.
739 long
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;
746 while(block--)
747 if(!(p = p->next))
748 return(-1);
750 return(p->bufp[n % KBLOCK]);
752 else
753 return(-1);
758 * This function just returns the current size of the kill buffer
761 ksize(void)
763 return(kbufp ? (int) kbufp->total : 0);
767 static REGION last_region_added;
769 void
770 set_last_region_added(REGION *region)
772 if(region)
773 last_region_added = (*region);
774 else
775 memset(&last_region_added, 0, sizeof(last_region_added));
779 REGION *
780 get_last_region_added(void)
782 return(&last_region_added);