* New version 2.26
[alpine.git] / pico / line.c
blob8b00bcfb4061f964182eb84a890b71960fef088a
1 /*
2 * ========================================================================
3 * Copyright 2006-2007 University of Washington
4 * Copyright 2013-2022 Eduardo Chappa
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * ========================================================================
14 * Program: Line management routines
18 * The functions in this file are a general set of line management utilities.
19 * They are the only routines that touch the text. They also touch the buffer
20 * and window structures, to make sure that the necessary updating gets done.
21 * There are routines in this file that handle the kill buffer too. It isn't
22 * here for any good reason.
24 * Note that this code only updates the dot and mark values in the window list.
25 * Since all the code acts on the current window, the buffer that we are
26 * editing must be being displayed, which means that "b_nwnd" is non zero,
27 * which means that the dot and mark values in the buffer headers are nonsense.
30 #include "headers.h"
32 #define NBLOCK 16 /* Line block chunk size */
33 #define KBLOCK 1024 /* Kill buffer block size */
37 * Struct to manage the kill and justify buffers
39 struct pkchunk {
40 short used; /* # of characters used in this buffer */
41 UCS bufp[KBLOCK]; /* buffer containing text */
42 struct pkchunk *next; /* pointer to next chunk */
45 static struct pkbuf {
46 long total; /* # of UCS characters used in buffer */
47 struct pkchunk *first; /* first one of these in the chain */
48 struct pkchunk *last; /* last one of these in the chain */
49 } *kbufp, *fbufp;
52 void insspace(int, int);
53 int ldelnewline(void);
54 void pkbufdel(struct pkbuf **);
55 void pkchunkdel(struct pkchunk **);
56 int pkbufinsert(UCS, struct pkbuf **);
57 long pkbufremove(int, struct pkbuf *);
61 * This routine allocates a block of memory large enough to hold a LINE
62 * containing "used" characters. The block is always rounded up a bit. Return
63 * a pointer to the new block, or NULL if there isn't any memory left. Print a
64 * message in the message line if no space.
66 LINE *
67 lalloc(int used)
69 register LINE *lp = NULL;
70 register int size;
71 EML eml;
72 static int displayed = 0;
74 if((size = (used+NBLOCK-1) & ~(NBLOCK-1)) > NLINE)
75 size *= 2;
77 if (size == 0) /* Assume that an empty */
78 size = NBLOCK; /* line is for type-in. */
80 if (displayed == 0 && (lp = (LINE *) malloc(sizeof(LINE)+(size*sizeof(CELL)))) == NULL){
81 eml.s = comatose(size);
82 emlwrite("Cannot allocate %s bytes (read file incomplete)", &eml);
83 displayed++;
84 return (NULL);
87 lp->l_size = size;
88 lp->l_used = used;
89 lp->l_sig = 0; /* assume it is not a signature line */
90 memset((void *)lp->l_text, 0, size*sizeof(CELL));
91 return (lp);
95 * Delete line "lp". Fix all of the links that might point at it (they are
96 * moved to offset 0 of the next line. Unlink the line from whatever buffer it
97 * might be in. Release the memory. The buffers are updated too; the magic
98 * conditions described in the above comments don't hold here.
100 void
101 lfree(LINE *lp)
103 register BUFFER *bp;
104 register WINDOW *wp;
106 wp = wheadp;
107 while (wp != NULL) {
108 if (wp->w_linep == lp)
109 wp->w_linep = lp->l_fp;
111 if (wp->w_dotp == lp) {
112 wp->w_dotp = lp->l_fp;
113 wp->w_doto = 0;
116 if (wp->w_markp == lp) {
117 wp->w_markp = lp->l_fp;
118 wp->w_marko = 0;
121 if (wp->w_imarkp == lp) {
122 wp->w_imarkp = lp->l_fp;
123 wp->w_imarko = 0;
126 wp = wp->w_wndp;
129 bp = bheadp;
130 while (bp != NULL) {
131 if (bp->b_nwnd == 0) {
132 if (bp->b_dotp == lp) {
133 bp->b_dotp = lp->l_fp;
134 bp->b_doto = 0;
137 if (bp->b_markp == lp) {
138 bp->b_markp = lp->l_fp;
139 bp->b_marko = 0;
143 bp = bp->b_bufp;
146 lp->l_bp->l_fp = lp->l_fp;
147 lp->l_fp->l_bp = lp->l_bp;
148 free((char *) lp);
153 * This routine gets called when a character is changed in place in the current
154 * buffer. It updates all of the required flags in the buffer and window
155 * system. The flag used is passed as an argument; if the buffer is being
156 * displayed in more than 1 window we change EDIT to HARD. Set MODE if the
157 * mode line needs to be updated (the "*" has to be set).
159 void
160 lchange(int flag)
162 register WINDOW *wp;
164 if (curbp->b_nwnd != 1) /* Ensure hard. */
165 flag = WFHARD;
167 if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
168 if(Pmaster == NULL)
169 flag |= WFMODE; /* update mode lines. */
170 curbp->b_flag |= BFCHG;
173 wp = wheadp;
174 while (wp != NULL) {
175 if (wp->w_bufp == curbp)
176 wp->w_flag |= flag;
177 wp = wp->w_wndp;
183 * insert spaces forward into text
184 * default flag and numeric argument
186 void
187 insspace(int f, int n)
189 linsert(n, ' ');
190 backchar(f, n);
194 * Insert "n" copies of the character "c" at the current location of dot. In
195 * the easy case all that happens is the text is stored in the line. In the
196 * hard case, the line has to be reallocated. When the window list is updated,
197 * take special care; I screwed it up once. You always update dot in the
198 * current window. You update mark, and a dot in another window, if it is
199 * greater than the place where you did the insert. Return TRUE if all is
200 * well, and FALSE on errors.
203 linsert(int n, UCS c)
205 register LINE *dotp;
206 register int doto;
207 register WINDOW *wp;
209 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
210 return(rdonly()); /* we are in read only mode */
212 dotp = curwp->w_dotp;
213 doto = curwp->w_doto;
214 lchange(WFEDIT);
216 if(!geninsert(&(curwp->w_dotp), &(curwp->w_doto), curbp->b_linep,
217 c, (curwp->w_markp) ? 1 : 0, n, &curbp->b_linecnt))
218 return(FALSE);
220 wp = wheadp; /* Update windows */
221 while (wp != NULL) {
222 if (wp->w_linep == dotp)
223 wp->w_linep = wp->w_dotp;
225 if (wp->w_imarkp == dotp) { /* added for internal mark */
226 wp->w_imarkp = wp->w_dotp;
227 if (wp->w_imarko > doto)
228 wp->w_imarko += n;
231 if (wp->w_markp == dotp) {
232 wp->w_markp = dotp;
233 if (wp->w_marko > doto)
234 wp->w_marko += n;
236 wp = wp->w_wndp;
239 return (TRUE);
244 * geninsert - do the actual work of inserting a character into
245 * the list of lines.
248 geninsert(LINE **dotp, int *doto, LINE *linep, UCS c, int attb, int n, long *lines)
250 register LINE *lp1;
251 register LINE *lp2;
252 register CELL *cp1;
253 register CELL *cp2;
254 CELL ac;
256 ac.a = attb;
257 if (*dotp == linep) { /* At the end: special */
258 if (*doto != 0) {
259 emlwrite("Programmer botch: geninsert", NULL);
260 return (FALSE);
263 if ((lp1=lalloc(n)) == NULL) /* Allocate new line */
264 return (FALSE);
266 lp2 = (*dotp)->l_bp; /* Previous line */
267 lp2->l_fp = lp1; /* Link in */
268 lp1->l_fp = *dotp;
269 (*dotp)->l_bp = lp1;
270 lp1->l_bp = lp2;
271 *doto = n;
272 *dotp = lp1;
273 ac.c = (c & CELLMASK);
274 cp1 = &(*dotp)->l_text[0];
275 while(n--)
276 *cp1++ = ac;
278 if(lines)
279 (*lines)++;
281 return (TRUE);
284 if ((*dotp)->l_used+n > (*dotp)->l_size) { /* Hard: reallocate */
285 if ((lp1=lalloc((*dotp)->l_used+n)) == NULL)
286 return (FALSE);
288 cp1 = &(*dotp)->l_text[0];
289 cp2 = &lp1->l_text[0];
290 while (cp1 != &(*dotp)->l_text[*doto])
291 *cp2++ = *cp1++;
293 cp2 += n;
294 while (cp1 != &(*dotp)->l_text[(*dotp)->l_used])
295 *cp2++ = *cp1++;
297 (*dotp)->l_bp->l_fp = lp1;
298 lp1->l_fp = (*dotp)->l_fp;
299 (*dotp)->l_fp->l_bp = lp1;
300 lp1->l_bp = (*dotp)->l_bp;
302 /* global may be keeping track of mark/imark */
303 if(wheadp){
304 if (wheadp->w_imarkp == *dotp)
305 wheadp->w_imarkp = lp1;
307 if (wheadp->w_markp == *dotp)
308 wheadp->w_markp = lp1;
311 free((char *) (*dotp));
312 *dotp = lp1;
313 } else { /* Easy: in place */
314 (*dotp)->l_used += n;
315 cp2 = &(*dotp)->l_text[(*dotp)->l_used];
316 cp1 = cp2-n;
317 while (cp1 != &(*dotp)->l_text[*doto])
318 *--cp2 = *--cp1;
321 ac.c = (c & CELLMASK);
322 while(n--) /* add the chars */
323 (*dotp)->l_text[(*doto)++] = ac;
325 return(TRUE);
330 * Insert a newline into the buffer at the current location of dot in the
331 * current window. The funny ass-backwards way it does things is not a botch;
332 * it just makes the last line in the file not a special case. Return TRUE if
333 * everything works out and FALSE on error (memory allocation failure). The
334 * update of dot and mark is a bit easier than in the above case, because the
335 * split forces more updating.
338 lnewline(void)
340 register CELL *cp1;
341 register CELL *cp2;
342 register LINE *lp1;
343 register LINE *lp2;
344 register int doto;
345 register WINDOW *wp;
347 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
348 return(rdonly()); /* we are in read only mode */
350 lchange(WFHARD);
351 lp1 = curwp->w_dotp; /* Get the address and */
352 doto = curwp->w_doto; /* offset of "." */
353 if ((lp2=lalloc(doto)) == NULL) /* New first half line */
354 return (FALSE);
356 cp1 = &lp1->l_text[0]; /* Shuffle text around */
357 cp2 = &lp2->l_text[0];
358 while (cp1 != &lp1->l_text[doto])
359 *cp2++ = *cp1++;
361 cp2 = &lp1->l_text[0];
362 while (cp1 != &lp1->l_text[lp1->l_used])
363 *cp2++ = *cp1++;
365 lp1->l_used -= doto;
366 lp2->l_bp = lp1->l_bp;
367 lp1->l_bp = lp2;
368 lp2->l_bp->l_fp = lp2;
369 lp2->l_fp = lp1;
370 wp = wheadp; /* Windows */
371 while (wp != NULL) {
372 if (wp->w_linep == lp1)
373 wp->w_linep = lp2;
375 if (wp->w_dotp == lp1) {
376 if (wp->w_doto < doto)
377 wp->w_dotp = lp2;
378 else
379 wp->w_doto -= doto;
382 if (wp->w_imarkp == lp1) { /* ADDED for internal mark */
383 if (wp->w_imarko < doto)
384 wp->w_imarkp = lp2;
385 else
386 wp->w_imarko -= doto;
389 if (wp->w_markp == lp1) {
390 if (wp->w_marko < doto)
391 wp->w_markp = lp2;
392 else
393 wp->w_marko -= doto;
395 wp = wp->w_wndp;
399 * Keep track of the number of lines in the buffer.
401 ++curbp->b_linecnt;
402 return (TRUE);
407 * This function deletes "n" characters, starting at dot. It understands how do deal
408 * with end of lines, etc. It returns TRUE if all of the characters were
409 * deleted, and FALSE if they were not (because dot ran into the end of the
410 * buffer. The "preserve" function is used to save what was deleted.
413 ldelete(long n, int (*preserve)(UCS))
415 register CELL *cp1;
416 register CELL *cp2;
417 register LINE *dotp;
418 register int doto;
419 register int chunk;
420 register WINDOW *wp;
422 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
423 return(rdonly()); /* we are in read only mode */
425 while (n != 0) {
426 dotp = curwp->w_dotp;
427 doto = curwp->w_doto;
428 if (dotp == curbp->b_linep) /* Hit end of buffer. */
429 return (FALSE);
430 chunk = dotp->l_used-doto; /* Size of chunk. */
431 if (chunk > n)
432 chunk = n;
433 if (chunk == 0) { /* End of line, merge. */
434 lchange(WFHARD);
435 if (ldelnewline() == FALSE
436 || (preserve ? (*preserve)('\n') == FALSE : 0))
437 return (FALSE);
438 --n;
439 continue;
442 lchange(WFEDIT);
443 cp1 = &dotp->l_text[doto]; /* Scrunch text. */
444 cp2 = cp1 + chunk;
445 if (preserve) { /* Kill? */
446 while (cp1 != cp2) {
447 if ((*preserve)(cp1->c) == FALSE)
448 return (FALSE);
449 ++cp1;
451 cp1 = &dotp->l_text[doto];
454 while (cp2 != &dotp->l_text[dotp->l_used])
455 *cp1++ = *cp2++;
457 dotp->l_used -= chunk;
458 wp = wheadp; /* Fix windows */
459 while (wp != NULL) {
460 if (wp->w_dotp==dotp && wp->w_doto>=doto) {
461 wp->w_doto -= chunk;
462 if (wp->w_doto < doto)
463 wp->w_doto = doto;
466 if (wp->w_markp==dotp && wp->w_marko>=doto) {
467 wp->w_marko -= chunk;
468 if (wp->w_marko < doto)
469 wp->w_marko = doto;
472 if (wp->w_imarkp==dotp && wp->w_imarko>=doto) {
473 wp->w_imarko -= chunk;
474 if (wp->w_imarko < doto)
475 wp->w_imarko = doto;
478 wp = wp->w_wndp;
480 n -= chunk;
483 #ifdef _WINDOWS
484 if (preserve == kinsert && ksize() > 0)
485 mswin_killbuftoclip (kremove);
486 #endif
488 return (TRUE);
492 * Delete a newline. Join the current line with the next line. If the next line
493 * is the magic header line always return TRUE; merging the last line with the
494 * header line can be thought of as always being a successful operation, even
495 * if nothing is done, and this makes the kill buffer work "right". Easy cases
496 * can be done by shuffling data around. Hard cases require that lines be moved
497 * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
498 * "ldelete" only.
501 ldelnewline(void)
503 register CELL *cp1;
504 register CELL *cp2;
505 register LINE *lp1;
506 register LINE *lp2;
507 register LINE *lp3;
508 register WINDOW *wp;
510 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
511 return(rdonly()); /* we are in read only mode */
513 lp1 = curwp->w_dotp;
514 lp2 = lp1->l_fp;
515 if (lp2 == curbp->b_linep) { /* At the buffer end. */
516 if (lp1->l_used == 0) { /* Blank line. */
517 lfree(lp1);
518 --curbp->b_linecnt;
521 return (TRUE);
524 if (lp2->l_used <= lp1->l_size-lp1->l_used) {
525 cp1 = &lp1->l_text[lp1->l_used];
526 cp2 = &lp2->l_text[0];
527 while (cp2 != &lp2->l_text[lp2->l_used])
528 *cp1++ = *cp2++;
530 wp = wheadp;
531 while (wp != NULL) {
532 if (wp->w_linep == lp2)
533 wp->w_linep = lp1;
534 if (wp->w_dotp == lp2) {
535 wp->w_dotp = lp1;
536 wp->w_doto += lp1->l_used;
538 if (wp->w_markp == lp2) {
539 wp->w_markp = lp1;
540 wp->w_marko += lp1->l_used;
542 if (wp->w_imarkp == lp2) {
543 wp->w_imarkp = lp1;
544 wp->w_imarko += lp1->l_used;
546 wp = wp->w_wndp;
548 lp1->l_used += lp2->l_used;
549 lp1->l_fp = lp2->l_fp;
550 lp2->l_fp->l_bp = lp1;
551 free((char *) lp2);
552 --curbp->b_linecnt;
553 return (TRUE);
556 if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
557 return (FALSE);
559 cp1 = &lp1->l_text[0];
560 cp2 = &lp3->l_text[0];
561 while (cp1 != &lp1->l_text[lp1->l_used])
562 *cp2++ = *cp1++;
564 cp1 = &lp2->l_text[0];
565 while (cp1 != &lp2->l_text[lp2->l_used])
566 *cp2++ = *cp1++;
568 lp1->l_bp->l_fp = lp3;
569 lp3->l_fp = lp2->l_fp;
570 lp2->l_fp->l_bp = lp3;
571 lp3->l_bp = lp1->l_bp;
572 wp = wheadp;
573 while (wp != NULL) {
574 if (wp->w_linep==lp1 || wp->w_linep==lp2)
575 wp->w_linep = lp3;
576 if (wp->w_dotp == lp1)
577 wp->w_dotp = lp3;
578 else if (wp->w_dotp == lp2) {
579 wp->w_dotp = lp3;
580 wp->w_doto += lp1->l_used;
582 if (wp->w_markp == lp1)
583 wp->w_markp = lp3;
584 else if (wp->w_markp == lp2) {
585 wp->w_markp = lp3;
586 wp->w_marko += lp1->l_used;
588 if (wp->w_imarkp == lp1)
589 wp->w_imarkp = lp3;
590 else if (wp->w_imarkp == lp2) {
591 wp->w_imarkp = lp3;
592 wp->w_imarko += lp1->l_used;
594 wp = wp->w_wndp;
597 free((char *) lp1);
598 free((char *) lp2);
599 --curbp->b_linecnt;
600 return (TRUE);
605 * Tell the caller if the given line is blank or not.
608 lisblank(LINE *line)
610 int n = 0;
611 UCS qstr[NLINE];
613 n = (glo_quote_str
614 && quote_match(glo_quote_str, line, qstr, NLINE))
615 ? ucs4_strlen(qstr) : 0;
617 for(; n < llength(line); n++)
618 if(!ucs4_isspace(lgetc(line, n).c)
619 || lgetc(line, n).c >= 0xff
620 || (unsigned char) lgetc(line,n).c != (unsigned char) NBSPC)
621 return(FALSE);
623 return(TRUE);
628 * Delete all of the text saved in the kill buffer. Called by commands when a
629 * new kill context is being created. The kill buffer array is released, just
630 * in case the buffer has grown to immense size. No errors.
632 void
633 kdelete(void)
635 pkbufdel(&kbufp);
638 void
639 fdelete(void)
641 pkbufdel(&fbufp);
644 void
645 pkbufdel(struct pkbuf **buf)
647 if (*buf) {
648 pkchunkdel(&(*buf)->first);
649 free((char *) *buf);
650 *buf = NULL;
655 void
656 pkchunkdel(struct pkchunk **chunk)
658 if(chunk){
659 if((*chunk)->next)
660 pkchunkdel(&(*chunk)->next);
662 free((char *) *chunk);
663 *chunk = NULL;
669 * Insert a character to the kill buffer, enlarging the buffer if there isn't
670 * any room. Always grow the buffer in chunks, on the assumption that if you
671 * put something in the kill buffer you are going to put more stuff there too
672 * later. Return TRUE if all is well, and FALSE on errors.
675 kinsert(UCS c)
677 return(pkbufinsert(c, &kbufp));
681 finsert(UCS c)
683 return(pkbufinsert(c, &fbufp));
687 pkbufinsert(UCS c, struct pkbuf **buf)
689 if(!*buf){
690 if((*buf = (struct pkbuf *) malloc(sizeof(struct pkbuf))) != NULL)
691 memset(*buf, 0, sizeof(struct pkbuf));
692 else
693 return(FALSE);
696 if((*buf)->total % KBLOCK == 0){
697 struct pkchunk *p = (*buf)->last;
698 if(((*buf)->last = (struct pkchunk *) malloc(sizeof(struct pkchunk))) != NULL){
699 memset((*buf)->last, 0, sizeof(struct pkchunk));
700 if(p)
701 p->next = (*buf)->last;
702 else
703 (*buf)->first = (*buf)->last;
705 else
706 return(FALSE);
709 (*buf)->last->bufp[(*buf)->last->used++] = c;
710 (*buf)->total++;
711 return (TRUE);
716 * These functions get characters from the requested buffer. If the
717 * character index "n" is off the end, it returns "-1". This lets the
718 * caller just scan along until it gets a "-1" back.
720 long
721 kremove(int n)
723 return(pkbufremove(n, kbufp));
726 long
727 fremove(int n)
729 return(pkbufremove(n, fbufp));
734 * This would be type UCS except that it needs to return -1.
736 long
737 pkbufremove(int n, struct pkbuf *buf)
739 if(n >= 0 && buf && n < buf->total){
740 register struct pkchunk *p = buf->first;
741 int block = n / KBLOCK;
743 while(block--)
744 if(!(p = p->next))
745 return(-1);
747 return(p->bufp[n % KBLOCK]);
749 else
750 return(-1);
755 * This function just returns the current size of the kill buffer
758 ksize(void)
760 return(kbufp ? (int) kbufp->total : 0);
764 static REGION last_region_added;
766 void
767 set_last_region_added(REGION *region)
769 if(region)
770 last_region_added = (*region);
771 else
772 memset(&last_region_added, 0, sizeof(last_region_added));
776 REGION *
777 get_last_region_added(void)
779 return(&last_region_added);