File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / undo.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jul 30 08:16:45 2014 UTC (9 years, 11 months ago) by misho
Branches: readline, MAIN
CVS tags: v6_3p10_cross, v6_3p10, v6_3, p6, HEAD
readline 6.3

    1: /* readline.c -- a general facility for reading lines of input
    2:    with emacs style editing and completion. */
    3: 
    4: /* Copyright (C) 1987-2012 Free Software Foundation, Inc.
    5: 
    6:    This file is part of the GNU Readline Library (Readline), a library
    7:    for reading lines of text with interactive input and history editing.      
    8: 
    9:    Readline is free software: you can redistribute it and/or modify
   10:    it under the terms of the GNU General Public License as published by
   11:    the Free Software Foundation, either version 3 of the License, or
   12:    (at your option) any later version.
   13: 
   14:    Readline is distributed in the hope that it will be useful,
   15:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   16:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17:    GNU General Public License for more details.
   18: 
   19:    You should have received a copy of the GNU General Public License
   20:    along with Readline.  If not, see <http://www.gnu.org/licenses/>.
   21: */
   22: 
   23: #define READLINE_LIBRARY
   24: 
   25: #if defined (HAVE_CONFIG_H)
   26: #  include <config.h>
   27: #endif
   28: 
   29: #include <sys/types.h>
   30: 
   31: #if defined (HAVE_UNISTD_H)
   32: #  include <unistd.h>           /* for _POSIX_VERSION */
   33: #endif /* HAVE_UNISTD_H */
   34: 
   35: #if defined (HAVE_STDLIB_H)
   36: #  include <stdlib.h>
   37: #else
   38: #  include "ansi_stdlib.h"
   39: #endif /* HAVE_STDLIB_H */
   40: 
   41: #include <stdio.h>
   42: 
   43: /* System-specific feature definitions and include files. */
   44: #include "rldefs.h"
   45: 
   46: /* Some standard library routines. */
   47: #include "readline.h"
   48: #include "history.h"
   49: 
   50: #include "rlprivate.h"
   51: #include "xmalloc.h"
   52: 
   53: extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
   54: 
   55: /* Non-zero tells rl_delete_text and rl_insert_text to not add to
   56:    the undo list. */
   57: int _rl_doing_an_undo = 0;
   58: 
   59: /* How many unclosed undo groups we currently have. */
   60: int _rl_undo_group_level = 0;
   61: 
   62: /* The current undo list for THE_LINE. */
   63: UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
   64: 
   65: /* **************************************************************** */
   66: /*								    */
   67: /*			Undo, and Undoing			    */
   68: /*								    */
   69: /* **************************************************************** */
   70: 
   71: static UNDO_LIST *
   72: alloc_undo_entry (what, start, end, text)
   73:      enum undo_code what;
   74:      int start, end;
   75:      char *text;
   76: {
   77:   UNDO_LIST *temp;
   78: 
   79:   temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
   80:   temp->what = what;
   81:   temp->start = start;
   82:   temp->end = end;
   83:   temp->text = text;
   84: 
   85:   temp->next = (UNDO_LIST *)NULL;
   86:   return temp;
   87: }
   88: 
   89: /* Remember how to undo something.  Concatenate some undos if that
   90:    seems right. */
   91: void
   92: rl_add_undo (what, start, end, text)
   93:      enum undo_code what;
   94:      int start, end;
   95:      char *text;
   96: {
   97:   UNDO_LIST *temp;
   98: 
   99:   temp = alloc_undo_entry (what, start, end, text);
  100:   temp->next = rl_undo_list;
  101:   rl_undo_list = temp;
  102: }
  103: 
  104: /* Free an UNDO_LIST */
  105: void
  106: _rl_free_undo_list (ul)
  107:      UNDO_LIST *ul;
  108: {
  109:   UNDO_LIST *release;
  110: 
  111:   while (ul)
  112:     {
  113:       release = ul;
  114:       ul = ul->next;
  115: 
  116:       if (release->what == UNDO_DELETE)
  117: 	xfree (release->text);
  118: 
  119:       xfree (release);
  120:     }
  121: }
  122: 
  123: /* Free the existing undo list. */
  124: void
  125: rl_free_undo_list ()
  126: {
  127:   UNDO_LIST *release, *orig_list;
  128: 
  129:   orig_list = rl_undo_list;
  130:   _rl_free_undo_list (rl_undo_list);
  131:   rl_undo_list = (UNDO_LIST *)NULL;
  132:   replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
  133: }
  134: 
  135: UNDO_LIST *
  136: _rl_copy_undo_entry (entry)
  137:      UNDO_LIST *entry;
  138: {
  139:   UNDO_LIST *new;
  140: 
  141:   new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
  142:   new->text = entry->text ? savestring (entry->text) : 0;
  143:   return new;
  144: }
  145: 
  146: UNDO_LIST *
  147: _rl_copy_undo_list (head)
  148:      UNDO_LIST *head;
  149: {
  150:   UNDO_LIST *list, *new, *roving, *c;
  151: 
  152:   if (head == 0)
  153:     return head;
  154: 
  155:   list = head;
  156:   new = 0;
  157:   while (list)
  158:     {
  159:       c = _rl_copy_undo_entry (list);
  160:       if (new == 0)
  161: 	roving = new = c;
  162:       else
  163: 	{
  164: 	  roving->next = c;
  165: 	  roving = roving->next;
  166: 	}
  167:       list = list->next;
  168:     }
  169: 
  170:   roving->next = 0;
  171:   return new;
  172: }
  173: 
  174: /* Undo the next thing in the list.  Return 0 if there
  175:    is nothing to undo, or non-zero if there was. */
  176: int
  177: rl_do_undo ()
  178: {
  179:   UNDO_LIST *release;
  180:   int waiting_for_begin, start, end;
  181:   HIST_ENTRY *cur, *temp;
  182: 
  183: #define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
  184: 
  185:   start = end = waiting_for_begin = 0;
  186:   do
  187:     {
  188:       if (rl_undo_list == 0)
  189: 	return (0);
  190: 
  191:       _rl_doing_an_undo = 1;
  192:       RL_SETSTATE(RL_STATE_UNDOING);
  193: 
  194:       /* To better support vi-mode, a start or end value of -1 means
  195: 	 rl_point, and a value of -2 means rl_end. */
  196:       if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
  197: 	{
  198: 	  start = TRANS (rl_undo_list->start);
  199: 	  end = TRANS (rl_undo_list->end);
  200: 	}
  201: 
  202:       switch (rl_undo_list->what)
  203: 	{
  204: 	/* Undoing deletes means inserting some text. */
  205: 	case UNDO_DELETE:
  206: 	  rl_point = start;
  207: 	  rl_insert_text (rl_undo_list->text);
  208: 	  xfree (rl_undo_list->text);
  209: 	  break;
  210: 
  211: 	/* Undoing inserts means deleting some text. */
  212: 	case UNDO_INSERT:
  213: 	  rl_delete_text (start, end);
  214: 	  rl_point = start;
  215: 	  break;
  216: 
  217: 	/* Undoing an END means undoing everything 'til we get to a BEGIN. */
  218: 	case UNDO_END:
  219: 	  waiting_for_begin++;
  220: 	  break;
  221: 
  222: 	/* Undoing a BEGIN means that we are done with this group. */
  223: 	case UNDO_BEGIN:
  224: 	  if (waiting_for_begin)
  225: 	    waiting_for_begin--;
  226: 	  else
  227: 	    rl_ding ();
  228: 	  break;
  229: 	}
  230: 
  231:       _rl_doing_an_undo = 0;
  232:       RL_UNSETSTATE(RL_STATE_UNDOING);
  233: 
  234:       release = rl_undo_list;
  235:       rl_undo_list = rl_undo_list->next;
  236: 
  237:       /* If we are editing a history entry, make sure the change is replicated
  238: 	 in the history entry's line */
  239:       cur = current_history ();
  240:       if (cur && cur->data && (UNDO_LIST *)cur->data == release)
  241: 	{
  242: 	  temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
  243: 	  xfree (temp->line);
  244: 	  FREE (temp->timestamp);
  245: 	  xfree (temp);
  246: 	}
  247: 
  248:       replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
  249: 
  250:       xfree (release);
  251:     }
  252:   while (waiting_for_begin);
  253: 
  254:   return (1);
  255: }
  256: #undef TRANS
  257: 
  258: int
  259: _rl_fix_last_undo_of_type (type, start, end)
  260:      int type, start, end;
  261: {
  262:   UNDO_LIST *rl;
  263: 
  264:   for (rl = rl_undo_list; rl; rl = rl->next)
  265:     {
  266:       if (rl->what == type)
  267: 	{
  268: 	  rl->start = start;
  269: 	  rl->end = end;
  270: 	  return 0;
  271: 	}
  272:     }
  273:   return 1;
  274: }
  275: 
  276: /* Begin a group.  Subsequent undos are undone as an atomic operation. */
  277: int
  278: rl_begin_undo_group ()
  279: {
  280:   rl_add_undo (UNDO_BEGIN, 0, 0, 0);
  281:   _rl_undo_group_level++;
  282:   return 0;
  283: }
  284: 
  285: /* End an undo group started with rl_begin_undo_group (). */
  286: int
  287: rl_end_undo_group ()
  288: {
  289:   rl_add_undo (UNDO_END, 0, 0, 0);
  290:   _rl_undo_group_level--;
  291:   return 0;
  292: }
  293: 
  294: /* Save an undo entry for the text from START to END. */
  295: int
  296: rl_modifying (start, end)
  297:      int start, end;
  298: {
  299:   if (start > end)
  300:     {
  301:       SWAP (start, end);
  302:     }
  303: 
  304:   if (start != end)
  305:     {
  306:       char *temp = rl_copy_text (start, end);
  307:       rl_begin_undo_group ();
  308:       rl_add_undo (UNDO_DELETE, start, end, temp);
  309:       rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
  310:       rl_end_undo_group ();
  311:     }
  312:   return 0;
  313: }
  314: 
  315: /* Revert the current line to its previous state. */
  316: int
  317: rl_revert_line (count, key)
  318:      int count, key;
  319: {
  320:   if (rl_undo_list == 0)
  321:     rl_ding ();
  322:   else
  323:     {
  324:       while (rl_undo_list)
  325: 	rl_do_undo ();
  326: #if defined (VI_MODE)
  327:       if (rl_editing_mode == vi_mode)
  328: 	rl_point = rl_mark = 0;		/* rl_end should be set correctly */
  329: #endif
  330:     }
  331:     
  332:   return 0;
  333: }
  334: 
  335: /* Do some undoing of things that were done. */
  336: int
  337: rl_undo_command (count, key)
  338:      int count, key;
  339: {
  340:   if (count < 0)
  341:     return 0;	/* Nothing to do. */
  342: 
  343:   while (count)
  344:     {
  345:       if (rl_do_undo ())
  346: 	count--;
  347:       else
  348: 	{
  349: 	  rl_ding ();
  350: 	  break;
  351: 	}
  352:     }
  353:   return 0;
  354: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>