1 /*
2 * zle_utils.c - miscellaneous line editor utilities
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1992-1997 Paul Falstad
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Paul Falstad or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Paul Falstad and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Paul Falstad and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Paul Falstad and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30 #include "zle.mdh"
31 #include "zle_utils.pro"
32
33 /* Primary cut buffer */
34
35 /**/
36 struct cutbuffer cutbuf;
37
38 /* Emacs-style kill buffer ring */
39
40 /**/
41 struct cutbuffer *kring;
42 /**/
43 int kringsize, kringnum;
44
45 /* Vi named cut buffers. 0-25 are the named buffers "a to "z, and *
46 * 26-35 are the numbered buffer stack "0 to "9. */
47
48 /**/
49 struct cutbuffer vibuf[36];
50
51 /* the line before last mod (for undo purposes) */
52
53 /**/
54 ZLE_STRING_T lastline;
55 /**/
56 int lastlinesz, lastll, lastcs;
57
58 /* size of line buffer */
59
60 /**/
61 int linesz;
62
63 /* make sure that the line buffer has at least sz chars */
64
65 /**/
66 void
sizeline(int sz)67 sizeline(int sz)
68 {
69 int cursz = (zlemetaline != NULL) ? metalinesz : linesz;
70
71 while (sz > cursz) {
72 if (cursz < 256)
73 cursz = 256;
74 else
75 cursz *= 4;
76
77 if (zlemetaline != NULL) {
78 /* One spare character for the NULL */
79 zlemetaline = realloc(zlemetaline, cursz + 1);
80 } else {
81 /* One spare character for the NULL, one for the newline */
82 zleline =
83 (ZLE_STRING_T)realloc(zleline,
84 (cursz + 2) * ZLE_CHAR_SIZE);
85 }
86 }
87
88 if (zlemetaline != NULL)
89 metalinesz = cursz;
90 else
91 linesz = cursz;
92 }
93
94 /*
95 * Insert a character, called from main shell.
96 * Note this always operates on the metafied multibyte version of the
97 * line.
98 */
99
100 /**/
101 mod_export void
zleaddtoline(int chr)102 zleaddtoline(int chr)
103 {
104 spaceinline(1);
105 zlemetaline[zlemetacs++] = chr;
106 }
107
108 /*
109 * Convert a line editor character to a possibly multibyte character
110 * in a metafied string. To be safe buf should have space for at least
111 * 2 * MB_CUR_MAX chars for multibyte mode and 2 otherwise. Returns the
112 * length of the string added.
113 */
114
115 /**/
116 int
zlecharasstring(ZLE_CHAR_T inchar,char * buf)117 zlecharasstring(ZLE_CHAR_T inchar, char *buf)
118 {
119 #ifdef MULTIBYTE_SUPPORT
120 int ret;
121 char *ptr;
122
123 #ifdef __STDC_ISO_10646__
124 if (ZSH_INVALID_WCHAR_TEST(inchar)) {
125 buf[0] = ZSH_INVALID_WCHAR_TO_CHAR(inchar);
126 ret = 1;
127 } else
128 #endif
129 {
130 ret = wctomb(buf, inchar);
131 if (ret <= 0) {
132 /* Ick. */
133 buf[0] = '?';
134 return 1;
135 }
136 }
137 ptr = buf + ret - 1;
138 for (;;) {
139 if (imeta(*ptr)) {
140 char *ptr2 = buf + ret - 1;
141 for (;;) {
142 ptr2[1] = ptr2[0];
143 if (ptr2 == ptr)
144 break;
145 ptr2--;
146 }
147 *ptr = Meta;
148 ptr[1] ^= 32;
149 ret++;
150 }
151
152 if (ptr == buf)
153 return ret;
154 ptr--;
155 }
156 #else
157 if (imeta(inchar)) {
158 buf[0] = Meta;
159 buf[1] = inchar ^ 32;
160 return 2;
161 } else {
162 buf[0] = inchar;
163 return 1;
164 }
165 #endif
166 }
167
168 /*
169 * Input: a line in internal zle format, possibly using wide characters,
170 * possibly not, together with its length and the cursor position.
171 * The length must be accurate and includes all characters (no NULL
172 * termination is expected). The input cursor position is only
173 * significant if outcs is non-NULL.
174 *
175 * Output: an ordinary NULL-terminated string, using multibyte characters
176 * instead of wide characters where appropriate and with the contents
177 * metafied.
178 *
179 * If outllp is non-NULL, assign the new length. This is the conventional
180 * string length, without the NULL byte.
181 *
182 * If outcsp is non-NULL, assign the new character position.
183 * If outcsp is &zlemetacs, update the positions in the region_highlight
184 * array, too. This is a bit of a hack.
185 *
186 * If useheap is 1, memory is returned from the heap, else is allocated
187 * for later freeing.
188 */
189
190 /**/
191 mod_export char *
zlelineasstring(ZLE_STRING_T instr,int inll,int incs,int * outllp,int * outcsp,int useheap)192 zlelineasstring(ZLE_STRING_T instr, int inll, int incs, int *outllp,
193 int *outcsp, int useheap)
194 {
195 int outcs, outll, sub;
196 struct region_highlight *rhp;
197
198 #ifdef MULTIBYTE_SUPPORT
199 char *s;
200 int i, j;
201 size_t mb_len = 0;
202 mbstate_t mbs;
203
204 s = zalloc(inll * MB_CUR_MAX + 1);
205
206 outcs = 0;
207 memset(&mbs, 0, sizeof(mbs));
208 for (i=0; i < inll; i++) {
209 if (incs == 0)
210 outcs = mb_len;
211 incs--;
212 if (region_highlights && outcsp == &zlemetacs) {
213 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
214 rhp < region_highlights + n_region_highlights;
215 rhp++) {
216 if (rhp->flags & ZRH_PREDISPLAY)
217 sub = predisplaylen;
218 else
219 sub = 0;
220 if (rhp->start - sub == 0)
221 rhp->start_meta = sub + mb_len;
222 rhp->start--;
223 if (rhp->end - sub == 0)
224 rhp->end_meta = sub + mb_len;
225 rhp->end--;
226 }
227 }
228 #ifdef __STDC_ISO_10646__
229 if (ZSH_INVALID_WCHAR_TEST(instr[i])) {
230 s[mb_len++] = ZSH_INVALID_WCHAR_TO_CHAR(instr[i]);
231 } else
232 #endif
233 {
234 j = wcrtomb(s + mb_len, instr[i], &mbs);
235 if (j == -1) {
236 /* invalid char */
237 s[mb_len++] = ZWC('?');
238 memset(&mbs, 0, sizeof(mbs));
239 } else {
240 mb_len += j;
241 }
242 }
243 }
244 if (incs == 0)
245 outcs = mb_len;
246 if (region_highlights && outcsp == &zlemetacs) {
247 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
248 rhp < region_highlights + n_region_highlights;
249 rhp++) {
250 if (rhp->flags & ZRH_PREDISPLAY)
251 sub = predisplaylen;
252 else
253 sub = 0;
254 if (rhp->start - sub == 0)
255 rhp->start_meta = sub + mb_len;
256 if (rhp->end - sub == 0)
257 rhp->end_meta = sub + mb_len;
258 }
259 }
260 s[mb_len] = '\0';
261
262 outll = mb_len;
263 #else
264 outll = inll;
265 outcs = incs;
266 if (region_highlights && outcsp == &zlemetacs) {
267 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
268 rhp < region_highlights + n_region_highlights;
269 rhp++) {
270 rhp->start_meta = rhp->start;
271 rhp->end_meta = rhp->end;
272 }
273 }
274 #endif
275
276 /*
277 * *outcsp and *outllp are to be indexes into the final string,
278 * not character offsets, so we need to take account of any
279 * metafiable characters.
280 */
281 if (outcsp != NULL || outllp != NULL) {
282 #ifdef MULTIBYTE_SUPPORT
283 char *strp = s;
284 #else
285 char *strp = instr;
286 #endif
287 char *stopcs = strp + outcs;
288 char *stopll = strp + outll;
289 char *startp = strp;
290
291 if (region_highlights && outcsp == &zlemetacs) {
292 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
293 rhp < region_highlights + n_region_highlights;
294 rhp++) {
295 /* Used as temporary storage */
296 rhp->start = rhp->start_meta;
297 rhp->end = rhp->end_meta;
298 }
299 }
300 while (strp < stopll) {
301 if (imeta(*strp)) {
302 if (strp < stopcs)
303 outcs++;
304 if (region_highlights && outcsp == &zlemetacs) {
305 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
306 rhp < region_highlights + n_region_highlights;
307 rhp++) {
308 if (rhp->flags & ZRH_PREDISPLAY)
309 sub = predisplaylen;
310 else
311 sub = 0;
312 if (strp < startp + rhp->start - sub) {
313 rhp->start_meta++;
314 }
315 if (strp < startp + rhp->end - sub) {
316 rhp->end_meta++;
317 }
318 }
319 }
320 outll++;
321 }
322 strp++;
323 }
324 if (outcsp != NULL)
325 *outcsp = outcs;
326 if (outllp != NULL)
327 *outllp = outll;
328 }
329
330 #ifdef MULTIBYTE_SUPPORT
331 if (useheap) {
332 char *ret = metafy(s, mb_len, META_HEAPDUP);
333
334 zfree(s, inll * MB_CUR_MAX + 1);
335
336 return ret;
337 }
338 return metafy(s, mb_len, META_REALLOC);
339 #else
340 return metafy(instr, inll, useheap ? META_HEAPDUP : META_DUP);
341 #endif
342 }
343
344
345 /*
346 * Input a NULL-terminated metafied string instr.
347 * Output a line in internal zle format, together with its length
348 * in the appropriate character units. Note that outll may not be NULL.
349 *
350 * If outsz is non-NULL, the number of allocated characters in the
351 * string is written there. For compatibility with use of the linesz
352 * variable (allocate size of zleline), at least two characters are
353 * allocated more than needed for immediate use. (The extra characters
354 * may take a newline and a null at a later stage.) These are not
355 * included in *outsz.
356 *
357 * If outcs is non-NULL, the character position in the original
358 * string incs (a standard string offset, i.e. incremented 2 for
359 * each metafied character) is converted into the corresponding
360 * character position in *outcs.
361 *
362 * If, further, outcs is &zlecs, we update the positions in the
363 * region_highlight array, too. (This is a bit of a hack.)
364 *
365 * Note that instr is modified in place, hence should be copied
366 * first if necessary;
367 *
368 * Memory for the returned string is permanently allocated. *outsz may
369 * be longer than the *outll returned. Hence it should be freed with
370 * zfree(outstr, *outsz) or free(outstr), not zfree(outstr, *outll).
371 */
372
373 /**/
374 mod_export ZLE_STRING_T
stringaszleline(char * instr,int incs,int * outll,int * outsz,int * outcs)375 stringaszleline(char *instr, int incs, int *outll, int *outsz, int *outcs)
376 {
377 ZLE_STRING_T outstr;
378 int ll, sz, sub;
379 struct region_highlight *rhp;
380 #ifdef MULTIBYTE_SUPPORT
381 mbstate_t mbs;
382 #endif
383
384 if (outcs) {
385 /*
386 * Take account of Meta characters in the input string
387 * before we unmetafy it. This does not yet take account
388 * of multibyte characters. If there are none, this
389 * is all the processing required to calculate outcs.
390 */
391 char *inptr = instr, *cspos = instr + incs;
392 if (region_highlights && outcs == &zlecs) {
393 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
394 rhp < region_highlights + n_region_highlights;
395 rhp++) {
396 rhp->start = rhp->start_meta;
397 rhp->end = rhp->end_meta;
398 }
399 }
400 while (*inptr) {
401 if (*inptr == Meta) {
402 if (inptr < cspos) {
403 incs--;
404 }
405 if (region_highlights && outcs == &zlecs) {
406 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
407 rhp < region_highlights + n_region_highlights;
408 rhp++) {
409 if (rhp->flags & ZRH_PREDISPLAY)
410 sub = predisplaylen;
411 else
412 sub = 0;
413 if (inptr - instr < rhp->start - sub) {
414 rhp->start_meta--;
415 }
416 if (inptr - instr < rhp->end - sub) {
417 rhp->end_meta--;
418 }
419 }
420 }
421 inptr++;
422 }
423 inptr++;
424 }
425 }
426 unmetafy(instr, &ll);
427
428 /*
429 * ll is the maximum number of characters there can be in
430 * the output string; the closer to ASCII the string, the
431 * better the guess. For the 2 see above.
432 */
433 sz = (ll + 2) * ZLE_CHAR_SIZE;
434 if (outsz)
435 *outsz = ll;
436 outstr = (ZLE_STRING_T)zalloc(sz);
437
438 #ifdef MULTIBYTE_SUPPORT
439 if (ll) {
440 char *inptr = instr;
441 wchar_t *outptr = outstr;
442
443 /* Reset shift state to input complete string */
444 memset(&mbs, '\0', sizeof mbs);
445
446 while (ll > 0) {
447 size_t cnt = mbrtowc(outptr, inptr, ll, &mbs);
448
449 #ifdef __STDC_ISO_10646__
450 if (cnt == MB_INCOMPLETE || cnt == MB_INVALID) {
451 /* Use private encoding for invalid single byte */
452 *outptr = ZSH_CHAR_TO_INVALID_WCHAR(*inptr);
453 cnt = 1;
454 }
455 #else
456 /*
457 * At this point we don't handle either incomplete (-2) or
458 * invalid (-1) multibyte sequences. Use the current length
459 * and return.
460 */
461 if (cnt == MB_INCOMPLETE || cnt == MB_INVALID)
462 break;
463 #endif
464
465 if (cnt == 0) {
466 /* Converting '\0' returns 0, but a '\0' is a real
467 * character for us, so we should consume 1 byte
468 * (certainly true for Unicode and unlikely to be false
469 * in any non-pathological multibyte representation). */
470 cnt = 1;
471 } else if (cnt > (size_t)ll) {
472 /*
473 * Some multibyte implementations return the
474 * full length of a previous incomplete character
475 * instead of the remaining length.
476 * This is paranoia: it only applies if we start
477 * midway through a multibyte character, which
478 * presumably can't happen.
479 */
480 cnt = ll;
481 }
482
483 if (outcs) {
484 int offs = inptr - instr;
485 if (offs <= incs && incs < offs + (int)cnt)
486 *outcs = outptr - outstr;
487 if (region_highlights && outcs == &zlecs) {
488 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
489 rhp < region_highlights + n_region_highlights;
490 rhp++) {
491 if (rhp->flags & ZRH_PREDISPLAY)
492 sub = predisplaylen;
493 else
494 sub = 0;
495 if (offs <= rhp->start_meta - sub &&
496 rhp->start_meta - sub < offs + (int)cnt) {
497 rhp->start = outptr - outstr + sub;
498 }
499 if (offs <= rhp->end_meta - sub &&
500 rhp->end_meta - sub < offs + (int)cnt) {
501 rhp->end = outptr - outstr + sub;
502 }
503 }
504 }
505 }
506
507 inptr += cnt;
508 outptr++;
509 ll -= cnt;
510 }
511 if (outcs && inptr <= instr + incs)
512 *outcs = outptr - outstr;
513 *outll = outptr - outstr;
514 } else {
515 *outll = 0;
516 if (outcs)
517 *outcs = 0;
518 }
519 #else
520 memcpy(outstr, instr, ll);
521 *outll = ll;
522 if (outcs)
523 *outcs = incs;
524 if (region_highlights && outcs == &zlecs) {
525 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
526 rhp < region_highlights + n_region_highlights;
527 rhp++) {
528 rhp->start = rhp->start_meta;
529 rhp->end = rhp->end_meta;
530 }
531 }
532 #endif
533
534 return outstr;
535 }
536
537 /*
538 * This function is called when we are playing very nasty tricks
539 * indeed: see bufferwords in hist.c. Consequently we can make
540 * absolutely no assumption about the state whatsoever, except
541 * that it has one.
542 */
543
544 /**/
545 mod_export char *
zlegetline(int * ll,int * cs)546 zlegetline(int *ll, int *cs)
547 {
548 if (zlemetaline != NULL) {
549 *ll = zlemetall;
550 *cs = zlemetacs;
551 return ztrdup(zlemetaline);
552 }
553 if (zleline)
554 return zlelineasstring(zleline, zlell, zlecs, ll, cs, 0);
555 *ll = *cs = 0;
556 return ztrdup("");
557 }
558
559
560 /* Forward reference */
561 struct zle_region;
562
563 /* A non-special entry in region_highlight */
564 struct zle_region {
565 struct zle_region *next;
566 /* Entries of region_highlight, as needed */
567 int atr;
568 int start;
569 int end;
570 int flags;
571 };
572
573 /* Forward reference */
574 struct zle_position;
575
576 /* A saved set of position information */
577 struct zle_position {
578 /* Link pointer */
579 struct zle_position *next;
580 /* Cursor position */
581 int cs;
582 /* Mark */
583 int mk;
584 /* Line length */
585 int ll;
586 struct zle_region *regions;
587 };
588
589 /* LIFO stack of positions */
590 static struct zle_position *zle_positions;
591
592 /*
593 * Save positions including cursor, end-of-line and
594 * (non-special) region highlighting.
595 *
596 * Must be matched by a subsequent zle_restore_positions().
597 */
598
599 /**/
600 mod_export void
zle_save_positions(void)601 zle_save_positions(void)
602 {
603 struct region_highlight *rhp;
604 struct zle_position *newpos;
605 struct zle_region **newrhpp, *newrhp;
606
607 newpos = (struct zle_position *)zalloc(sizeof(*newpos));
608
609 newpos->mk = mark;
610 if (zlemetaline) {
611 /* Use metafied information */
612 newpos->cs = zlemetacs;
613 newpos->ll = zlemetall;
614 } else {
615 /* Use unmetafied information */
616 newpos->cs = zlecs;
617 newpos->ll = zlell;
618
619 }
620
621 newrhpp = &newpos->regions;
622 *newrhpp = NULL;
623 if (region_highlights) {
624 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
625 rhp < region_highlights + n_region_highlights;
626 rhp++) {
627 /*
628 * This is a FIFO stack, so we preserve the order
629 * of entries when we restore region_highlights.
630 */
631 newrhp = *newrhpp = (struct zle_region *)zalloc(sizeof(**newrhpp));
632 newrhp->next = NULL;
633 newrhp->atr = rhp->atr;
634 newrhp->flags = rhp->flags;
635 if (zlemetaline) {
636 newrhp->start = rhp->start_meta;
637 newrhp->end = rhp->end_meta;
638 } else {
639 newrhp->start = rhp->start;
640 newrhp->end = rhp->end;
641 }
642 newrhpp = &newrhp->next;
643 }
644 }
645
646 newpos->next = zle_positions;
647 zle_positions = newpos;
648 }
649
650 /*
651 * Restore positions previously saved.
652 * Relies on zlemetaline being restored correctly beforehand,
653 * so that it can tell whether to use metafied positions or not.
654 */
655
656 /**/
657 mod_export void
zle_restore_positions(void)658 zle_restore_positions(void)
659 {
660 struct zle_position *oldpos = zle_positions;
661 struct zle_region *oldrhp;
662 struct region_highlight *rhp;
663 int nreg;
664
665 zle_positions = oldpos->next;
666
667 mark = oldpos->mk;
668 if (zlemetaline) {
669 /* Use metafied information */
670 zlemetacs = oldpos->cs;
671 zlemetall = oldpos->ll;
672 } else {
673 /* Use unmetafied information */
674 zlecs = oldpos->cs;
675 zlell = oldpos->ll;
676 }
677
678 if (oldpos->regions) {
679 /* Count number of regions and see if the array needs resizing */
680 for (nreg = 0, oldrhp = oldpos->regions;
681 oldrhp;
682 nreg++, oldrhp = oldrhp->next)
683 ;
684 if (nreg + N_SPECIAL_HIGHLIGHTS != n_region_highlights) {
685 n_region_highlights = nreg + N_SPECIAL_HIGHLIGHTS;
686 region_highlights = (struct region_highlight *)
687 zrealloc(region_highlights,
688 sizeof(struct region_highlight) * n_region_highlights);
689 }
690 oldrhp = oldpos->regions;
691 rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
692 while (oldrhp) {
693 struct zle_region *nextrhp = oldrhp->next;
694
695 rhp->atr = oldrhp->atr;
696 rhp->flags = oldrhp->flags;
697 if (zlemetaline) {
698 rhp->start_meta = oldrhp->start;
699 rhp->end_meta = oldrhp->end;
700 } else {
701 rhp->start = oldrhp->start;
702 rhp->end = oldrhp->end;
703 }
704
705 zfree(oldrhp, sizeof(*oldrhp));
706 oldrhp = nextrhp;
707 rhp++;
708 }
709 } else if (region_highlights) {
710 zfree(region_highlights, sizeof(struct region_highlight) *
711 n_region_highlights);
712 region_highlights = NULL;
713 n_region_highlights = 0;
714 }
715
716 zfree(oldpos, sizeof(*oldpos));
717 }
718
719 /*
720 * Discard positions previously saved, the line has been updated.
721 */
722
723 /**/
724 mod_export void
zle_free_positions(void)725 zle_free_positions(void)
726 {
727 struct zle_position *oldpos = zle_positions;
728 struct zle_region *oldrhp;
729
730 zle_positions = oldpos->next;
731 oldrhp = oldpos->regions;
732 while (oldrhp) {
733 struct zle_region *nextrhp = oldrhp->next;
734 zfree(oldrhp, sizeof(*oldrhp));
735 oldrhp = nextrhp;
736 }
737 zfree(oldpos, sizeof(*oldpos));
738 }
739
740 /*
741 * Basic utility functions for adding to line or removing from line.
742 * At this level the counts supplied are raw character counts, so
743 * the calling code must be aware of combining characters where
744 * necessary, e.g. if we want to delete a + combing grave forward
745 * from the cursor, then shiftchars() gets the count 2 (not 1).
746 *
747 * This is necessary because these utility functions don't know about
748 * zlecs, and we need to count combined characters from there.
749 */
750
751 /* insert space for ct chars at cursor position */
752
753 /**/
754 mod_export void
spaceinline(int ct)755 spaceinline(int ct)
756 {
757 int i, sub;
758 struct region_highlight *rhp;
759
760 if (zlemetaline) {
761 sizeline(ct + zlemetall);
762 for (i = zlemetall; --i >= zlemetacs;)
763 zlemetaline[i + ct] = zlemetaline[i];
764 zlemetall += ct;
765 zlemetaline[zlemetall] = '\0';
766
767 if (mark > zlemetacs)
768 mark += ct;
769
770 if (region_highlights) {
771 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
772 rhp < region_highlights + n_region_highlights;
773 rhp++) {
774 if (rhp->flags & ZRH_PREDISPLAY)
775 sub = predisplaylen;
776 else
777 sub = 0;
778 if (rhp->start_meta - sub >= zlemetacs) {
779 rhp->start_meta += ct;
780 }
781 if (rhp->end_meta - sub >= zlemetacs) {
782 rhp->end_meta += ct;
783 }
784 }
785 }
786 } else {
787 sizeline(ct + zlell);
788 for (i = zlell; --i >= zlecs;)
789 zleline[i + ct] = zleline[i];
790 zlell += ct;
791 zleline[zlell] = ZWC('\0');
792
793 if (mark > zlecs)
794 mark += ct;
795 if (viinsbegin > zlecs)
796 viinsbegin = 0;
797
798 if (region_highlights) {
799 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
800 rhp < region_highlights + n_region_highlights;
801 rhp++) {
802 if (rhp->flags & ZRH_PREDISPLAY)
803 sub = predisplaylen;
804 else
805 sub = 0;
806 if (rhp->start - sub >= zlecs) {
807 rhp->start += ct;
808 }
809 if (rhp->end - sub >= zlecs) {
810 rhp->end += ct;
811 }
812 }
813 }
814 }
815 region_active = 0;
816 }
817
818 /*
819 * Within the ZLE line, cut the "cnt" characters from position "to".
820 */
821
822 /**/
823 void
shiftchars(int to,int cnt)824 shiftchars(int to, int cnt)
825 {
826 struct region_highlight *rhp;
827 int sub;
828
829 if (mark >= to + cnt)
830 mark -= cnt;
831 else if (mark > to)
832 mark = to;
833
834 if (zlemetaline) {
835 /* before to is updated... */
836 if (region_highlights) {
837 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
838 rhp < region_highlights + n_region_highlights;
839 rhp++) {
840 if (rhp->flags & ZRH_PREDISPLAY)
841 sub = predisplaylen;
842 else
843 sub = 0;
844 if (rhp->start_meta - sub > to) {
845 if (rhp->start_meta - sub > to + cnt)
846 rhp->start_meta -= cnt;
847 else
848 rhp->start_meta = to;
849 }
850 if (rhp->end_meta - sub > to) {
851 if (rhp->end_meta - sub > to + cnt)
852 rhp->end_meta -= cnt;
853 else
854 rhp->end_meta = to;
855 }
856 }
857 }
858
859 while (to + cnt < zlemetall) {
860 zlemetaline[to] = zlemetaline[to + cnt];
861 to++;
862 }
863 zlemetaline[zlemetall = to] = '\0';
864 } else {
865 /* before to is updated... */
866 if (region_highlights) {
867 for (rhp = region_highlights + N_SPECIAL_HIGHLIGHTS;
868 rhp < region_highlights + n_region_highlights;
869 rhp++) {
870 if (rhp->flags & ZRH_PREDISPLAY)
871 sub = predisplaylen;
872 else
873 sub = 0;
874 if (rhp->start - sub > to) {
875 if (rhp->start - sub > to + cnt)
876 rhp->start -= cnt;
877 else
878 rhp->start = to;
879 }
880 if (rhp->end - sub > to) {
881 if (rhp->end - sub > to + cnt)
882 rhp->end -= cnt;
883 else
884 rhp->end = to;
885 }
886 }
887 }
888
889 while (to + cnt < zlell) {
890 zleline[to] = zleline[to + cnt];
891 to++;
892 }
893 zleline[zlell = to] = ZWC('\0');
894 }
895 region_active = 0;
896 }
897
898 /*
899 * Put the ct characters starting at zleline + i into the
900 * cutbuffer, circling the kill ring if necessary (it's
901 * not if we're dealing with vi buffers, which is detected
902 * internally). The text is not removed from zleline.
903 *
904 * dir indicates how the text is to be added to the cutbuffer,
905 * if the cutbuffer wasn't zeroed (this depends on the last
906 * command being a kill). If dir is 1, the new text goes
907 * to the front of the cut buffer. If dir is -1, the cutbuffer
908 * is completely overwritten.
909 */
910
911 /**/
912 void
cut(int i,int ct,int flags)913 cut(int i, int ct, int flags)
914 {
915 cuttext(zleline + i, ct, flags);
916 }
917
918 /*
919 * As cut, but explicitly supply the text together with its length.
920 */
921
922 /**/
923 void
cuttext(ZLE_STRING_T line,int ct,int flags)924 cuttext(ZLE_STRING_T line, int ct, int flags)
925 {
926 if (!(ct || vilinerange) || zmod.flags & MOD_NULL)
927 return;
928
929 UNMETACHECK();
930 if (zmod.flags & MOD_VIBUF) {
931 struct cutbuffer *b = &vibuf[zmod.vibuf];
932
933 if (!(zmod.flags & MOD_VIAPP) || !b->buf) {
934 free(b->buf);
935 b->buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
936 ZS_memcpy(b->buf, line, ct);
937 b->len = ct;
938 b->flags = vilinerange ? CUTBUFFER_LINE : 0;
939 } else {
940 int len = b->len;
941
942 if(vilinerange)
943 b->flags |= CUTBUFFER_LINE;
944 b->buf = (ZLE_STRING_T)
945 realloc((char *)b->buf,
946 (ct + len + !!(b->flags & CUTBUFFER_LINE))
947 * ZLE_CHAR_SIZE);
948 if (b->flags & CUTBUFFER_LINE)
949 b->buf[len++] = ZWC('\n');
950 ZS_memcpy(b->buf + len, line, ct);
951 b->len = len + ct;
952 }
953 } else if (flags & CUT_YANK) {
954 /* Save in "0 */
955 free(vibuf[26].buf);
956 vibuf[26].buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
957 ZS_memcpy(vibuf[26].buf, line, ct);
958 vibuf[26].len = ct;
959 vibuf[26].flags = vilinerange ? CUTBUFFER_LINE : 0;
960 } else {
961 /* Save in "1, shifting "1-"8 along to "2-"9 */
962 int n;
963 free(vibuf[35].buf);
964 for(n=35; n>27; n--)
965 vibuf[n] = vibuf[n-1];
966 vibuf[27].buf = (ZLE_STRING_T)zalloc(ct * ZLE_CHAR_SIZE);
967 ZS_memcpy(vibuf[27].buf, line, ct);
968 vibuf[27].len = ct;
969 vibuf[27].flags = vilinerange ? CUTBUFFER_LINE : 0;
970 }
971 if (!cutbuf.buf) {
972 cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE);
973 cutbuf.buf[0] = ZWC('\0');
974 cutbuf.len = cutbuf.flags = 0;
975 } else if (!(lastcmd & ZLE_KILL) || (flags & CUT_REPLACE)) {
976 Cutbuffer kptr;
977 if (!kring) {
978 kringsize = KRINGCTDEF;
979 kring = (Cutbuffer)zshcalloc(kringsize * sizeof(struct cutbuffer));
980 } else
981 kringnum = (kringnum + 1) % kringsize;
982 kptr = kring + kringnum;
983 if (kptr->buf)
984 free(kptr->buf);
985 *kptr = cutbuf;
986 cutbuf.buf = (ZLE_STRING_T)zalloc(ZLE_CHAR_SIZE);
987 cutbuf.buf[0] = ZWC('\0');
988 cutbuf.len = cutbuf.flags = 0;
989 }
990 if (flags & (CUT_FRONT|CUT_REPLACE)) {
991 ZLE_STRING_T s = (ZLE_STRING_T)zalloc((cutbuf.len + ct)*ZLE_CHAR_SIZE);
992
993 ZS_memcpy(s, line, ct);
994 ZS_memcpy(s + ct, cutbuf.buf, cutbuf.len);
995 free(cutbuf.buf);
996 cutbuf.buf = s;
997 cutbuf.len += ct;
998 } else {
999 /* don't alloc 0 bytes; length 0 occurs for blank lines in vi mode */
1000 cutbuf.buf = realloc((char *)cutbuf.buf,
1001 (cutbuf.len + (ct ? ct : 1)) * ZLE_CHAR_SIZE);
1002 ZS_memcpy(cutbuf.buf + cutbuf.len, line, ct);
1003 cutbuf.len += ct;
1004 }
1005 if(vilinerange)
1006 cutbuf.flags |= CUTBUFFER_LINE;
1007 else
1008 cutbuf.flags &= ~CUTBUFFER_LINE;
1009 }
1010
1011 /*
1012 * Now we're back in the world of zlecs where we need to keep
1013 * track of whether we're on a combining character.
1014 */
1015
1016 /**/
1017 mod_export void
backkill(int ct,int flags)1018 backkill(int ct, int flags)
1019 {
1020 UNMETACHECK();
1021 if (flags & CUT_RAW) {
1022 zlecs -= ct;
1023 } else {
1024 int origcs = zlecs;
1025 while (ct--)
1026 DECCS();
1027 ct = origcs - zlecs;
1028 }
1029
1030 cut(zlecs, ct, flags);
1031 shiftchars(zlecs, ct);
1032 CCRIGHT();
1033 }
1034
1035 /**/
1036 mod_export void
forekill(int ct,int flags)1037 forekill(int ct, int flags)
1038 {
1039 int i = zlecs;
1040
1041 UNMETACHECK();
1042 if (!(flags & CUT_RAW)) {
1043 int n = ct;
1044 while (n--)
1045 INCCS();
1046 ct = zlecs - i;
1047 zlecs = i;
1048 }
1049
1050 cut(i, ct, flags);
1051 shiftchars(i, ct);
1052 CCRIGHT();
1053 }
1054
1055 /**/
1056 mod_export void
backdel(int ct,int flags)1057 backdel(int ct, int flags)
1058 {
1059 if (flags & CUT_RAW) {
1060 if (zlemetaline != NULL) {
1061 shiftchars(zlemetacs -= ct, ct);
1062 } else {
1063 shiftchars(zlecs -= ct, ct);
1064 CCRIGHT();
1065 }
1066 } else {
1067 int n = ct, origcs = zlecs;
1068 DPUTS(zlemetaline != NULL, "backdel needs CUT_RAW when metafied");
1069 while (n--)
1070 DECCS();
1071 shiftchars(zlecs, origcs - zlecs);
1072 CCRIGHT();
1073 }
1074 }
1075
1076 /**/
1077 mod_export void
foredel(int ct,int flags)1078 foredel(int ct, int flags)
1079 {
1080 if (flags & CUT_RAW) {
1081 if (zlemetaline != NULL) {
1082 shiftchars(zlemetacs, ct);
1083 } else if (flags & CUT_RAW) {
1084 shiftchars(zlecs, ct);
1085 CCRIGHT();
1086 }
1087 } else {
1088 int origcs = zlecs;
1089 int n = ct;
1090 DPUTS(zlemetaline != NULL, "foredel needs CUT_RAW when metafied");
1091 while (n--)
1092 INCCS();
1093 ct = zlecs - origcs;
1094 zlecs = origcs;
1095 shiftchars(zlecs, ct);
1096 CCRIGHT();
1097 }
1098 }
1099
1100 /**/
1101 void
setline(char * s,int flags)1102 setline(char *s, int flags)
1103 {
1104 char *scp;
1105
1106 UNMETACHECK();
1107 if (flags & ZSL_COPY)
1108 scp = ztrdup(s);
1109 else
1110 scp = s;
1111 /*
1112 * TBD: we could make this more efficient by passing the existing
1113 * allocated line to stringaszleline.
1114 */
1115 free(zleline);
1116
1117 viinsbegin = 0;
1118 zleline = stringaszleline(scp, 0, &zlell, &linesz, NULL);
1119
1120 if ((flags & ZSL_TOEND) && (zlecs = zlell) && invicmdmode())
1121 DECCS();
1122 else if (zlecs > zlell)
1123 zlecs = zlell;
1124 CCRIGHT();
1125 if (flags & ZSL_COPY)
1126 free(scp);
1127 }
1128
1129 /**/
1130 int
findbol(void)1131 findbol(void)
1132 {
1133 int x = zlecs;
1134
1135 while (x > 0 && zleline[x - 1] != ZWC('\n'))
1136 x--;
1137 return x;
1138 }
1139
1140 /**/
1141 int
findeol(void)1142 findeol(void)
1143 {
1144 int x = zlecs;
1145
1146 while (x != zlell && zleline[x] != ZWC('\n'))
1147 x++;
1148 return x;
1149 }
1150
1151 /**/
1152 void
findline(int * a,int * b)1153 findline(int *a, int *b)
1154 {
1155 *a = findbol();
1156 *b = findeol();
1157 }
1158
1159 /*
1160 * Query the user, and return 1 for yes, 0 for no. The question is assumed to
1161 * have been printed already, and the cursor is left immediately after the
1162 * response echoed. (Might cause a problem if this takes it onto the next
1163 * line.) <Tab> is interpreted as 'y'; any other control character is
1164 * interpreted as 'n'. If there are any characters in the buffer, this is
1165 * taken as a negative response, and no characters are read. Case is folded.
1166 */
1167
1168 /**/
1169 mod_export int
getzlequery(void)1170 getzlequery(void)
1171 {
1172 ZLE_INT_T c;
1173 #ifdef FIONREAD
1174 int val;
1175
1176 /* check for typeahead, which is treated as a negative response */
1177 ioctl(SHTTY, FIONREAD, (char *)&val);
1178 if (val) {
1179 putc('n', shout);
1180 return 0;
1181 }
1182 #endif
1183
1184 /* get a character from the tty and interpret it */
1185 c = getfullchar(0);
1186 /*
1187 * We'll interpret an interruption here as only interrupting the
1188 * query, not the line editor.
1189 */
1190 errflag &= ~ERRFLAG_INT;
1191 if (c == ZWC('\t'))
1192 c = ZWC('y');
1193 else if (ZC_icntrl(c) || c == ZLEEOF)
1194 c = ZWC('n');
1195 else
1196 c = ZC_tolower(c);
1197 /* echo response and return */
1198 if (c != ZWC('\n')) {
1199 REFRESH_ELEMENT re;
1200 re.chr = c;
1201 re.atr = 0;
1202 zwcputc(&re, NULL);
1203 }
1204 return c == ZWC('y');
1205 }
1206
1207 /* Format a string, keybinding style. */
1208
1209 /**/
1210 char *
bindztrdup(char * str)1211 bindztrdup(char *str)
1212 {
1213 int c, len = 1;
1214 char *buf, *ptr, *ret;
1215
1216 for(ptr = str; *ptr; ptr++) {
1217 c = *ptr == Meta ? STOUC(*++ptr) ^ 32 : STOUC(*ptr);
1218 if(c & 0x80) {
1219 len += 3;
1220 c &= 0x7f;
1221 }
1222 if(c < 32 || c == 0x7f) {
1223 len++;
1224 c ^= 64;
1225 }
1226 len += c == '\\' || c == '^';
1227 len++;
1228 }
1229 ptr = buf = zalloc(len);
1230 for(; *str; str++) {
1231 c = *str == Meta ? STOUC(*++str) ^ 32 : STOUC(*str);
1232 if(c & 0x80) {
1233 *ptr++ = '\\';
1234 *ptr++ = 'M';
1235 *ptr++ = '-';
1236 c &= 0x7f;
1237 }
1238 if(c < 32 || c == 0x7f) {
1239 *ptr++ = '^';
1240 c ^= 64;
1241 }
1242 if(c == '\\' || c == '^')
1243 *ptr++ = '\\';
1244 *ptr++ = c;
1245 }
1246 *ptr = 0;
1247 ret = dquotedztrdup(buf);
1248 zsfree(buf);
1249 return ret;
1250 }
1251
1252 /* Display a metafied string, keybinding-style. */
1253
1254 /**/
1255 int
printbind(char * str,FILE * stream)1256 printbind(char *str, FILE *stream)
1257 {
1258 char *b = bindztrdup(str);
1259 int ret = zputs(b, stream);
1260
1261 zsfree(b);
1262 return ret;
1263 }
1264
1265 /*
1266 * Display a message where the completion list normally goes.
1267 * The message must be metafied.
1268 *
1269 * TODO: there's some advantage in using a ZLE_STRING_T array here,
1270 * together with improvements in other places, but messages don't
1271 * need to be particularly efficient.
1272 */
1273
1274 /**/
1275 mod_export void
showmsg(char const * msg)1276 showmsg(char const *msg)
1277 {
1278 char const *p;
1279 int up = 0, cc = 0;
1280 ZLE_CHAR_T c;
1281 #ifdef MULTIBYTE_SUPPORT
1282 char *umsg;
1283 int ulen, eol = 0;
1284 size_t width;
1285 mbstate_t mbs;
1286 #endif
1287
1288 trashzle();
1289 clearflag = isset(USEZLE) && !termflags && isset(ALWAYSLASTPROMPT);
1290
1291 #ifdef MULTIBYTE_SUPPORT
1292 umsg = ztrdup(msg);
1293 p = unmetafy(umsg, &ulen);
1294 memset(&mbs, 0, sizeof mbs);
1295
1296 mb_charinit();
1297 while (ulen > 0) {
1298 char const *n;
1299 if (*p == '\n') {
1300 ulen--;
1301 p++;
1302
1303 putc('\n', shout);
1304 up += 1 + cc / zterm_columns;
1305 cc = 0;
1306 } else {
1307 /*
1308 * Extract the next wide character from the multibyte string.
1309 */
1310 size_t cnt = eol ? MB_INVALID : mbrtowc(&c, p, ulen, &mbs);
1311
1312 switch (cnt) {
1313 case MB_INCOMPLETE:
1314 eol = 1;
1315 /* FALL THROUGH */
1316 case MB_INVALID:
1317 /*
1318 * This really shouldn't be happening here, but...
1319 * Treat it as a single byte character; it may get
1320 * prettified.
1321 */
1322 memset(&mbs, 0, sizeof mbs);
1323 n = nicechar(*p);
1324 cnt = 1;
1325 width = strlen(n);
1326 break;
1327 case 0:
1328 cnt = 1;
1329 /* FALL THROUGH */
1330 default:
1331 /*
1332 * Paranoia: only needed if we start in the middle
1333 * of a multibyte string and only in some implementations.
1334 */
1335 if (cnt > (size_t)ulen)
1336 cnt = ulen;
1337 n = wcs_nicechar(c, &width, NULL);
1338 break;
1339 }
1340 ulen -= cnt;
1341 p += cnt;
1342
1343 zputs(n, shout);
1344 cc += width;
1345 }
1346 }
1347
1348 free(umsg);
1349 #else
1350 for(p = msg; (c = *p); p++) {
1351 if(c == Meta)
1352 c = *++p ^ 32;
1353 if(c == '\n') {
1354 putc('\n', shout);
1355 up += 1 + cc / zterm_columns;
1356 cc = 0;
1357 } else {
1358 char const *n = nicechar(c);
1359 zputs(n, shout);
1360 cc += strlen(n);
1361 }
1362 }
1363 #endif
1364 up += cc / zterm_columns;
1365
1366 if (clearflag) {
1367 putc('\r', shout);
1368 tcmultout(TCUP, TCMULTUP, up + nlnct);
1369 } else
1370 putc('\n', shout);
1371 showinglist = 0;
1372 }
1373
1374 /* handle the error flag */
1375
1376 /**/
1377 int
handlefeep(UNUSED (char ** args))1378 handlefeep(UNUSED(char **args))
1379 {
1380 zbeep();
1381 return 0;
1382 }
1383
1384 /* user control of auto-suffixes -- see iwidgets.list */
1385
1386 /**/
1387 int
handlesuffix(UNUSED (char ** args))1388 handlesuffix(UNUSED(char **args))
1389 {
1390 return 0;
1391 }
1392
1393 /***************/
1394 /* undo system */
1395 /***************/
1396
1397 /* head of the undo list, and the current position */
1398
1399 /**/
1400 struct change *curchange;
1401
1402 static struct change *changes;
1403
1404 /* list of pending changes, not yet in the undo system */
1405
1406 static struct change *nextchanges, *endnextchanges;
1407
1408 /* incremented to provide a unique change number */
1409
1410 /**/
1411 zlong undo_changeno;
1412
1413 /* If positive, don't undo beyond this point */
1414
1415 static zlong undo_limitno;
1416
1417 /**/
1418 void
initundo(void)1419 initundo(void)
1420 {
1421 nextchanges = NULL;
1422 changes = curchange = zalloc(sizeof(*curchange));
1423 curchange->prev = curchange->next = NULL;
1424 curchange->del = curchange->ins = NULL;
1425 curchange->dell = curchange->insl = 0;
1426 curchange->changeno = undo_changeno = undo_limitno = 0;
1427 lastline = zalloc((lastlinesz = linesz) * ZLE_CHAR_SIZE);
1428 ZS_memcpy(lastline, zleline, (lastll = zlell));
1429 lastcs = zlecs;
1430 }
1431
1432 /**/
1433 void
freeundo(void)1434 freeundo(void)
1435 {
1436 freechanges(changes);
1437 freechanges(nextchanges);
1438 zfree(lastline, lastlinesz);
1439 lastline = NULL;
1440 lastlinesz = 0;
1441 }
1442
1443 /**/
1444 static void
freechanges(struct change * p)1445 freechanges(struct change *p)
1446 {
1447 struct change *n;
1448
1449 for(; p; p = n) {
1450 n = p->next;
1451 free(p->del);
1452 free(p->ins);
1453 zfree(p, sizeof(*p));
1454 }
1455 }
1456
1457 /* register pending changes in the undo system */
1458
1459 /**/
1460 mod_export void
handleundo(void)1461 handleundo(void)
1462 {
1463 int remetafy;
1464
1465 /*
1466 * Yuk: we call this from within the completion system,
1467 * so we need to convert back to the form which can be
1468 * copied into undo entries.
1469 */
1470 if (zlemetaline != NULL) {
1471 unmetafy_line();
1472 remetafy = 1;
1473 } else
1474 remetafy = 0;
1475
1476 mkundoent();
1477 if(nextchanges) {
1478 setlastline();
1479 if(curchange->next) {
1480 freechanges(curchange->next);
1481 curchange->next = NULL;
1482 free(curchange->del);
1483 free(curchange->ins);
1484 curchange->del = curchange->ins = NULL;
1485 curchange->dell = curchange->insl = 0;
1486 }
1487 nextchanges->prev = curchange->prev;
1488 if(curchange->prev)
1489 curchange->prev->next = nextchanges;
1490 else
1491 changes = nextchanges;
1492 curchange->prev = endnextchanges;
1493 endnextchanges->next = curchange;
1494 nextchanges = endnextchanges = NULL;
1495 }
1496
1497 if (remetafy)
1498 metafy_line();
1499 }
1500
1501 /* add an entry to the undo system, if anything has changed */
1502
1503 /**/
1504 void
mkundoent(void)1505 mkundoent(void)
1506 {
1507 int pre, suf;
1508 int sh = zlell < lastll ? zlell : lastll;
1509 struct change *ch;
1510
1511 UNMETACHECK();
1512 if(lastll == zlell && !ZS_memcmp(lastline, zleline, zlell)) {
1513 lastcs = zlecs;
1514 return;
1515 }
1516 for(pre = 0; pre < sh && zleline[pre] == lastline[pre]; )
1517 pre++;
1518 for(suf = 0; suf < sh - pre &&
1519 zleline[zlell - 1 - suf] == lastline[lastll - 1 - suf]; )
1520 suf++;
1521 ch = zalloc(sizeof(*ch));
1522 ch->next = NULL;
1523 ch->hist = histline;
1524 ch->off = pre;
1525 ch->old_cs = lastcs;
1526 ch->new_cs = zlecs;
1527 if(suf + pre == lastll) {
1528 ch->del = NULL;
1529 ch->dell = 0;
1530 } else {
1531 ch->dell = lastll - pre - suf;
1532 ch->del = (ZLE_STRING_T)zalloc(ch->dell * ZLE_CHAR_SIZE);
1533 ZS_memcpy(ch->del, lastline + pre, ch->dell);
1534 }
1535 if(suf + pre == zlell) {
1536 ch->ins = NULL;
1537 ch->insl = 0;
1538 } else {
1539 ch->insl = zlell - pre - suf;
1540 ch->ins = (ZLE_STRING_T)zalloc(ch->insl * ZLE_CHAR_SIZE);
1541 ZS_memcpy(ch->ins, zleline + pre, ch->insl);
1542 }
1543 if(nextchanges) {
1544 ch->flags = CH_PREV;
1545 ch->prev = endnextchanges;
1546 endnextchanges->flags |= CH_NEXT;
1547 endnextchanges->next = ch;
1548 } else {
1549 nextchanges = ch;
1550 ch->flags = 0;
1551 ch->prev = NULL;
1552 }
1553 ch->changeno = ++undo_changeno;
1554 endnextchanges = ch;
1555 }
1556
1557 /* set lastline to match line */
1558
1559 /**/
1560 void
setlastline(void)1561 setlastline(void)
1562 {
1563 UNMETACHECK();
1564 if(lastlinesz != linesz)
1565 lastline = realloc(lastline, (lastlinesz = linesz) * ZLE_CHAR_SIZE);
1566 ZS_memcpy(lastline, zleline, (lastll = zlell));
1567 lastcs = zlecs;
1568 }
1569
1570 /* move backwards through the change list */
1571
1572 /**/
1573 int
undo(char ** args)1574 undo(char **args)
1575 {
1576 zlong last_change;
1577
1578 if (*args)
1579 last_change = zstrtol(*args, NULL, 0);
1580 else
1581 last_change = (zlong)-1;
1582
1583 handleundo();
1584 do {
1585 struct change *prev = curchange->prev;
1586 if(!prev)
1587 return 1;
1588 if (prev->changeno <= last_change)
1589 break;
1590 if (prev->changeno <= undo_limitno && !*args)
1591 return 1;
1592 if (!unapplychange(prev)) {
1593 if (last_change >= 0) {
1594 unapplychange(prev);
1595 curchange = prev;
1596 }
1597 } else {
1598 curchange = prev;
1599 }
1600 } while (last_change >= (zlong)0 || (curchange->flags & CH_PREV));
1601 setlastline();
1602 return 0;
1603 }
1604
1605 /**/
1606 static int
unapplychange(struct change * ch)1607 unapplychange(struct change *ch)
1608 {
1609 if(ch->hist != histline) {
1610 Histent he = quietgethist(ch->hist);
1611 DPUTS(he == NULL, "quietgethist(ch->hist) returned NULL");
1612 if(he == NULL)
1613 return 1;
1614 zle_setline(he);
1615 zlecs = ch->new_cs;
1616 return 0;
1617 }
1618 zlecs = ch->off;
1619 if(ch->ins)
1620 foredel(ch->insl, CUT_RAW);
1621 if(ch->del) {
1622 spaceinline(ch->dell);
1623 ZS_memcpy(zleline + zlecs, ch->del, ch->dell);
1624 zlecs += ch->dell;
1625 }
1626 zlecs = ch->old_cs;
1627 return 1;
1628 }
1629
1630 /* move forwards through the change list */
1631
1632 /**/
1633 int
redo(UNUSED (char ** args))1634 redo(UNUSED(char **args))
1635 {
1636 handleundo();
1637 do {
1638 if(!curchange->next)
1639 return 1;
1640 if (applychange(curchange))
1641 curchange = curchange->next;
1642 else
1643 break;
1644 } while(curchange->prev->flags & CH_NEXT);
1645 setlastline();
1646 return 0;
1647 }
1648
1649 /**/
1650 static int
applychange(struct change * ch)1651 applychange(struct change *ch)
1652 {
1653 if(ch->hist != histline) {
1654 Histent he = quietgethist(ch->hist);
1655 DPUTS(he == NULL, "quietgethist(ch->hist) returned NULL");
1656 if(he == NULL)
1657 return 1;
1658 zle_setline(he);
1659 zlecs = ch->old_cs;
1660 return 0;
1661 }
1662 zlecs = ch->off;
1663 if(ch->del)
1664 foredel(ch->dell, CUT_RAW);
1665 if(ch->ins) {
1666 spaceinline(ch->insl);
1667 ZS_memcpy(zleline + zlecs, ch->ins, ch->insl);
1668 zlecs += ch->insl;
1669 }
1670 zlecs = ch->new_cs;
1671 return 1;
1672 }
1673
1674 /* vi undo: toggle between the end of the undo list and the preceding point */
1675
1676 /**/
1677 int
viundochange(char ** args)1678 viundochange(char **args)
1679 {
1680 handleundo();
1681 if(curchange->next) {
1682 do {
1683 applychange(curchange);
1684 curchange = curchange->next;
1685 } while(curchange->next);
1686 setlastline();
1687 return 0;
1688 } else
1689 return undo(args);
1690 }
1691
1692 /**/
1693 int
splitundo(UNUSED (char ** args))1694 splitundo(UNUSED(char **args))
1695 {
1696 if (vistartchange >= 0) {
1697 mergeundo();
1698 vistartchange = undo_changeno;
1699 }
1700 handleundo();
1701 return 0;
1702 }
1703
1704 /**/
1705 void
mergeundo(void)1706 mergeundo(void)
1707 {
1708 struct change *current;
1709 for (current = curchange->prev;
1710 current && current->prev && current->changeno > vistartchange+1;
1711 current = current->prev) {
1712 current->flags |= CH_PREV;
1713 current->prev->flags |= CH_NEXT;
1714 }
1715 vistartchange = -1;
1716 }
1717
1718 /*
1719 * Call a ZLE hook: a user-defined widget called at a specific point
1720 * within the line editor.
1721 *
1722 * A single argument arg is passed to the function (in addition to the
1723 * function name). It may be NULL.
1724 */
1725
1726 /**/
1727 void
zlecallhook(char * name,char * arg)1728 zlecallhook(char *name, char *arg)
1729 {
1730 Thingy thingy = rthingy_nocreate(name);
1731 int saverrflag, savretflag;
1732 char *args[2];
1733
1734 if (!thingy)
1735 return;
1736
1737 /* If anything here needs changing, see also redrawhook() */
1738
1739 saverrflag = errflag;
1740 savretflag = retflag;
1741
1742 args[0] = arg;
1743 args[1] = NULL;
1744 execzlefunc(thingy, args, 1, 0);
1745 unrefthingy(thingy);
1746
1747 /* Retain any user interrupt error status */
1748 errflag = saverrflag | (errflag & ERRFLAG_INT);
1749 retflag = savretflag;
1750 }
1751
1752 /*
1753 * Return the number corresponding to the last change made.
1754 */
1755
1756 /**/
1757 zlong
get_undo_current_change(UNUSED (Param pm))1758 get_undo_current_change(UNUSED(Param pm))
1759 {
1760 int remetafy;
1761
1762 /*
1763 * Yuk: we call this from within the completion system,
1764 * so we need to convert back to the form which can be
1765 * copied into undo entries.
1766 */
1767 if (zlemetaline != NULL) {
1768 unmetafy_line();
1769 remetafy = 1;
1770 } else
1771 remetafy = 0;
1772
1773 /* add entry for any pending changes */
1774 mkundoent();
1775 setlastline();
1776
1777 if (remetafy)
1778 metafy_line();
1779
1780 return undo_changeno;
1781 }
1782
1783 /**/
1784 zlong
get_undo_limit_change(UNUSED (Param pm))1785 get_undo_limit_change(UNUSED(Param pm))
1786 {
1787 return undo_limitno;
1788 }
1789
1790 /**/
1791 void
set_undo_limit_change(UNUSED (Param pm),zlong value)1792 set_undo_limit_change(UNUSED(Param pm), zlong value)
1793 {
1794 undo_limitno = value;
1795 }
1796