* Fix an error in compilation when Alpine is not built with S/MIME
[alpine.git] / pico / line.c
blob2e35e9318771e4bfbaf3626c74a1e910e9530dad
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-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.
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 return (lp);
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.
102 void
103 lfree(LINE *lp)
105 register BUFFER *bp;
106 register WINDOW *wp;
108 wp = wheadp;
109 while (wp != NULL) {
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;
115 wp->w_doto = 0;
118 if (wp->w_markp == lp) {
119 wp->w_markp = lp->l_fp;
120 wp->w_marko = 0;
123 if (wp->w_imarkp == lp) {
124 wp->w_imarkp = lp->l_fp;
125 wp->w_imarko = 0;
128 wp = wp->w_wndp;
131 bp = bheadp;
132 while (bp != NULL) {
133 if (bp->b_nwnd == 0) {
134 if (bp->b_dotp == lp) {
135 bp->b_dotp = lp->l_fp;
136 bp->b_doto = 0;
139 if (bp->b_markp == lp) {
140 bp->b_markp = lp->l_fp;
141 bp->b_marko = 0;
145 bp = bp->b_bufp;
148 lp->l_bp->l_fp = lp->l_fp;
149 lp->l_fp->l_bp = lp->l_bp;
150 free((char *) lp);
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).
161 void
162 lchange(int flag)
164 register WINDOW *wp;
166 if (curbp->b_nwnd != 1) /* Ensure hard. */
167 flag = WFHARD;
169 if ((curbp->b_flag&BFCHG) == 0) { /* First change, so */
170 if(Pmaster == NULL)
171 flag |= WFMODE; /* update mode lines. */
172 curbp->b_flag |= BFCHG;
175 wp = wheadp;
176 while (wp != NULL) {
177 if (wp->w_bufp == curbp)
178 wp->w_flag |= flag;
179 wp = wp->w_wndp;
185 * insert spaces forward into text
186 * default flag and numeric argument
188 void
189 insspace(int f, int n)
191 linsert(n, ' ');
192 backchar(f, 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)
207 register LINE *dotp;
208 register int doto;
209 register WINDOW *wp;
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;
216 lchange(WFEDIT);
218 if(!geninsert(&(curwp->w_dotp), &(curwp->w_doto), curbp->b_linep,
219 c, (curwp->w_markp) ? 1 : 0, n, &curbp->b_linecnt))
220 return(FALSE);
222 wp = wheadp; /* Update windows */
223 while (wp != NULL) {
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)
230 wp->w_imarko += n;
233 if (wp->w_markp == dotp) {
234 wp->w_markp = dotp;
235 if (wp->w_marko > doto)
236 wp->w_marko += n;
238 wp = wp->w_wndp;
241 return (TRUE);
246 * geninsert - do the actual work of inserting a character into
247 * the list of lines.
250 geninsert(LINE **dotp, int *doto, LINE *linep, UCS c, int attb, int n, long *lines)
252 register LINE *lp1;
253 register LINE *lp2;
254 register CELL *cp1;
255 register CELL *cp2;
256 CELL ac;
258 ac.a = attb;
259 if (*dotp == linep) { /* At the end: special */
260 if (*doto != 0) {
261 emlwrite("Programmer botch: geninsert", NULL);
262 return (FALSE);
265 if ((lp1=lalloc(n)) == NULL) /* Allocate new line */
266 return (FALSE);
268 lp2 = (*dotp)->l_bp; /* Previous line */
269 lp2->l_fp = lp1; /* Link in */
270 lp1->l_fp = *dotp;
271 (*dotp)->l_bp = lp1;
272 lp1->l_bp = lp2;
273 *doto = n;
274 *dotp = lp1;
275 ac.c = (c & CELLMASK);
276 cp1 = &(*dotp)->l_text[0];
277 while(n--)
278 *cp1++ = ac;
280 if(lines)
281 (*lines)++;
283 return (TRUE);
286 if ((*dotp)->l_used+n > (*dotp)->l_size) { /* Hard: reallocate */
287 if ((lp1=lalloc((*dotp)->l_used+n)) == NULL)
288 return (FALSE);
290 cp1 = &(*dotp)->l_text[0];
291 cp2 = &lp1->l_text[0];
292 while (cp1 != &(*dotp)->l_text[*doto])
293 *cp2++ = *cp1++;
295 cp2 += n;
296 while (cp1 != &(*dotp)->l_text[(*dotp)->l_used])
297 *cp2++ = *cp1++;
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 */
305 if(wheadp){
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));
314 *dotp = lp1;
315 } else { /* Easy: in place */
316 (*dotp)->l_used += n;
317 cp2 = &(*dotp)->l_text[(*dotp)->l_used];
318 cp1 = cp2-n;
319 while (cp1 != &(*dotp)->l_text[*doto])
320 *--cp2 = *--cp1;
323 ac.c = (c & CELLMASK);
324 while(n--) /* add the chars */
325 (*dotp)->l_text[(*doto)++] = ac;
327 return(TRUE);
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.
340 lnewline(void)
342 register CELL *cp1;
343 register CELL *cp2;
344 register LINE *lp1;
345 register LINE *lp2;
346 register int doto;
347 register WINDOW *wp;
349 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
350 return(rdonly()); /* we are in read only mode */
352 lchange(WFHARD);
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 */
356 return (FALSE);
358 cp1 = &lp1->l_text[0]; /* Shuffle text around */
359 cp2 = &lp2->l_text[0];
360 while (cp1 != &lp1->l_text[doto])
361 *cp2++ = *cp1++;
363 cp2 = &lp1->l_text[0];
364 while (cp1 != &lp1->l_text[lp1->l_used])
365 *cp2++ = *cp1++;
367 lp1->l_used -= doto;
368 lp2->l_bp = lp1->l_bp;
369 lp1->l_bp = lp2;
370 lp2->l_bp->l_fp = lp2;
371 lp2->l_fp = lp1;
372 wp = wheadp; /* Windows */
373 while (wp != NULL) {
374 if (wp->w_linep == lp1)
375 wp->w_linep = lp2;
377 if (wp->w_dotp == lp1) {
378 if (wp->w_doto < doto)
379 wp->w_dotp = lp2;
380 else
381 wp->w_doto -= doto;
384 if (wp->w_imarkp == lp1) { /* ADDED for internal mark */
385 if (wp->w_imarko < doto)
386 wp->w_imarkp = lp2;
387 else
388 wp->w_imarko -= doto;
391 if (wp->w_markp == lp1) {
392 if (wp->w_marko < doto)
393 wp->w_markp = lp2;
394 else
395 wp->w_marko -= doto;
397 wp = wp->w_wndp;
401 * Keep track of the number of lines in the buffer.
403 ++curbp->b_linecnt;
404 return (TRUE);
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))
417 register CELL *cp1;
418 register CELL *cp2;
419 register LINE *dotp;
420 register int doto;
421 register int chunk;
422 register WINDOW *wp;
424 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
425 return(rdonly()); /* we are in read only mode */
427 while (n != 0) {
428 dotp = curwp->w_dotp;
429 doto = curwp->w_doto;
430 if (dotp == curbp->b_linep) /* Hit end of buffer. */
431 return (FALSE);
432 chunk = dotp->l_used-doto; /* Size of chunk. */
433 if (chunk > n)
434 chunk = n;
435 if (chunk == 0) { /* End of line, merge. */
436 lchange(WFHARD);
437 if (ldelnewline() == FALSE
438 || (preserve ? (*preserve)('\n') == FALSE : 0))
439 return (FALSE);
440 --n;
441 continue;
444 lchange(WFEDIT);
445 cp1 = &dotp->l_text[doto]; /* Scrunch text. */
446 cp2 = cp1 + chunk;
447 if (preserve) { /* Kill? */
448 while (cp1 != cp2) {
449 if ((*preserve)(cp1->c) == FALSE)
450 return (FALSE);
451 ++cp1;
453 cp1 = &dotp->l_text[doto];
456 while (cp2 != &dotp->l_text[dotp->l_used])
457 *cp1++ = *cp2++;
459 dotp->l_used -= chunk;
460 wp = wheadp; /* Fix windows */
461 while (wp != NULL) {
462 if (wp->w_dotp==dotp && wp->w_doto>=doto) {
463 wp->w_doto -= chunk;
464 if (wp->w_doto < doto)
465 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)
471 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)
477 wp->w_imarko = doto;
480 wp = wp->w_wndp;
482 n -= chunk;
485 #ifdef _WINDOWS
486 if (preserve == kinsert && ksize() > 0)
487 mswin_killbuftoclip (kremove);
488 #endif
490 return (TRUE);
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
500 * "ldelete" only.
503 ldelnewline(void)
505 register CELL *cp1;
506 register CELL *cp2;
507 register LINE *lp1;
508 register LINE *lp2;
509 register LINE *lp3;
510 register WINDOW *wp;
512 if (curbp->b_mode&MDVIEW) /* don't allow this command if */
513 return(rdonly()); /* we are in read only mode */
515 lp1 = curwp->w_dotp;
516 lp2 = lp1->l_fp;
517 if (lp2 == curbp->b_linep) { /* At the buffer end. */
518 if (lp1->l_used == 0) { /* Blank line. */
519 lfree(lp1);
520 --curbp->b_linecnt;
523 return (TRUE);
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])
530 *cp1++ = *cp2++;
532 wp = wheadp;
533 while (wp != NULL) {
534 if (wp->w_linep == lp2)
535 wp->w_linep = lp1;
536 if (wp->w_dotp == lp2) {
537 wp->w_dotp = lp1;
538 wp->w_doto += lp1->l_used;
540 if (wp->w_markp == lp2) {
541 wp->w_markp = lp1;
542 wp->w_marko += lp1->l_used;
544 if (wp->w_imarkp == lp2) {
545 wp->w_imarkp = lp1;
546 wp->w_imarko += lp1->l_used;
548 wp = wp->w_wndp;
550 lp1->l_used += lp2->l_used;
551 lp1->l_fp = lp2->l_fp;
552 lp2->l_fp->l_bp = lp1;
553 free((char *) lp2);
554 --curbp->b_linecnt;
555 return (TRUE);
558 if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL)
559 return (FALSE);
561 cp1 = &lp1->l_text[0];
562 cp2 = &lp3->l_text[0];
563 while (cp1 != &lp1->l_text[lp1->l_used])
564 *cp2++ = *cp1++;
566 cp1 = &lp2->l_text[0];
567 while (cp1 != &lp2->l_text[lp2->l_used])
568 *cp2++ = *cp1++;
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;
574 wp = wheadp;
575 while (wp != NULL) {
576 if (wp->w_linep==lp1 || wp->w_linep==lp2)
577 wp->w_linep = lp3;
578 if (wp->w_dotp == lp1)
579 wp->w_dotp = lp3;
580 else if (wp->w_dotp == lp2) {
581 wp->w_dotp = lp3;
582 wp->w_doto += lp1->l_used;
584 if (wp->w_markp == lp1)
585 wp->w_markp = lp3;
586 else if (wp->w_markp == lp2) {
587 wp->w_markp = lp3;
588 wp->w_marko += lp1->l_used;
590 if (wp->w_imarkp == lp1)
591 wp->w_imarkp = lp3;
592 else if (wp->w_imarkp == lp2) {
593 wp->w_imarkp = lp3;
594 wp->w_imarko += lp1->l_used;
596 wp = wp->w_wndp;
599 free((char *) lp1);
600 free((char *) lp2);
601 --curbp->b_linecnt;
602 return (TRUE);
607 * Tell the caller if the given line is blank or not.
610 lisblank(LINE *line)
612 int n = 0;
613 UCS qstr[NLINE];
615 n = (glo_quote_str
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)
623 return(FALSE);
625 return(TRUE);
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.
634 void
635 kdelete(void)
637 pkbufdel(&kbufp);
640 void
641 fdelete(void)
643 pkbufdel(&fbufp);
646 void
647 pkbufdel(struct pkbuf **buf)
649 if (*buf) {
650 pkchunkdel(&(*buf)->first);
651 free((char *) *buf);
652 *buf = NULL;
657 void
658 pkchunkdel(struct pkchunk **chunk)
660 if(chunk){
661 if((*chunk)->next)
662 pkchunkdel(&(*chunk)->next);
664 free((char *) *chunk);
665 *chunk = NULL;
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.
677 kinsert(UCS c)
679 return(pkbufinsert(c, &kbufp));
683 finsert(UCS c)
685 return(pkbufinsert(c, &fbufp));
689 pkbufinsert(UCS c, struct pkbuf **buf)
691 if(!*buf){
692 if((*buf = (struct pkbuf *) malloc(sizeof(struct pkbuf))) != NULL)
693 memset(*buf, 0, sizeof(struct pkbuf));
694 else
695 return(FALSE);
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));
702 if(p)
703 p->next = (*buf)->last;
704 else
705 (*buf)->first = (*buf)->last;
707 else
708 return(FALSE);
711 (*buf)->last->bufp[(*buf)->last->used++] = c;
712 (*buf)->total++;
713 return (TRUE);
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.
722 long
723 kremove(int n)
725 return(pkbufremove(n, kbufp));
728 long
729 fremove(int n)
731 return(pkbufremove(n, fbufp));
736 * This would be type UCS except that it needs to return -1.
738 long
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;
745 while(block--)
746 if(!(p = p->next))
747 return(-1);
749 return(p->bufp[n % KBLOCK]);
751 else
752 return(-1);
757 * This function just returns the current size of the kill buffer
760 ksize(void)
762 return(kbufp ? (int) kbufp->total : 0);
766 static REGION last_region_added;
768 void
769 set_last_region_added(REGION *region)
771 if(region)
772 last_region_added = (*region);
773 else
774 memset(&last_region_added, 0, sizeof(last_region_added));
778 REGION *
779 get_last_region_added(void)
781 return(&last_region_added);