home *** CD-ROM | disk | FTP | other *** search
/ Der Mediaplex Sampler - Die 6 von Plex / 6_v_plex.zip / 6_v_plex / DISK5 / DOS_50 / PVIC.ZIP / UNDO.C < prev    next >
C/C++ Source or Header  |  1993-04-21  |  8KB  |  304 lines

  1. /* $Header: /nw/tony/src/stevie/src/RCS/undo.c,v 1.7 89/08/06 09:51:06 tony Exp $
  2.  *
  3.  * Undo facility
  4.  *
  5.  * The routines in this file comprise a general undo facility for use
  6.  * throughout the rest of the editor. The routine u_save() is called
  7.  * before each edit operation to save the current contents of the lines
  8.  * to be editted. Later, u_undo() can be called to return those lines
  9.  * to their original state. The routine u_clear() should be called
  10.  * whenever a new file is going to be editted to clear the undo buffer.
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include "pvic.h"
  15. #include "locdefs.h"
  16.  
  17. /*
  18.  * The next two variables mark the boundaries of the changed section
  19.  * of the file. Lines BETWEEN the lower and upper bounds are changed
  20.  * and originally contained the lines pointed to by u_lines. To undo
  21.  * the last change, insert the lines in u_lines between the lower and
  22.  * upper bounds.
  23.  */
  24. static  LINE    *u_lbound = NULL; /* line just prior to first changed line */
  25. static  LINE    *u_ubound = NULL; /* line just after the last changed line */
  26.  
  27. static  LINE    *u_lline  = NULL; /* bounds of the saved lines */
  28. static  LINE    *u_uline  = NULL;
  29.  
  30. static  int     u_col;
  31. static  int     u_valid = (0);  /* is the undo buffer valid */
  32.  
  33. /*
  34.  * Local forward declarations
  35.  */
  36. static  LINE    *copyline();
  37. static  void    u_lsave();
  38. static  void    u_lfree();
  39.  
  40. /*
  41.  * u_save(l, u) - save the current contents of part of the file
  42.  *
  43.  * The lines between 'l' and 'u' are about to be changed. This routine
  44.  * saves their current contents into the undo buffer. The range l to u
  45.  * is not inclusive because when we do an open, for example, there aren't
  46.  * any lines in between. If no lines are to be saved, then l->next == u.
  47.  */
  48. void
  49. u_save(l, u)
  50. LINE    *l, *u;
  51. {
  52.     LINE    *nl;                    /* copy of the current line */
  53.  
  54.     /*
  55.      * If l or u is null, there's an error. We don't return an
  56.      * indication to the caller. They should find the problem
  57.      * while trying to perform whatever edit is being requested
  58.      * (e.g. a join on the last line).
  59.      */
  60.     if (l == NULL || u == NULL)
  61.         return;
  62.  
  63.     u_clear();                      /* clear the buffer, first */
  64.  
  65.     u_lsave(l, u);          /* save to the "line undo" buffer, if needed */
  66.  
  67.     u_lbound = l;
  68.     u_ubound = u;
  69.  
  70.     if (l->next != u) {             /* there are lines in the middle */
  71.         l = l->next;
  72.         u = u->prev;
  73.  
  74.         u_lline = nl = copyline(l);     /* copy the first line */
  75.         while (l != u) {
  76.             nl->next = copyline(l->next);
  77.             nl->next->prev = nl;
  78.             l = l->next;
  79.             nl = nl->next;
  80.         }
  81.         u_uline = nl;
  82.     } else
  83.         u_lline = u_uline = NULL;
  84.  
  85.     u_valid = (1);
  86.     u_col = cursor_virtual_column;
  87. }
  88.  
  89. /*
  90.  * u_save_line() - save the current line in the undo buffer
  91.  */
  92. void
  93. u_save_line()
  94. {
  95.     u_save(cursor_char->linep->prev, cursor_char->linep->next);
  96. }
  97.  
  98. /*
  99.  * u_undo() - effect an 'undo' operation
  100.  *
  101.  * The last edit is undone by restoring the modified section of the file
  102.  * to its original state. The lines we're going to trash are copied to
  103.  * the undo buffer so that even an 'undo' can be undone. Rings the bell
  104.  * if the undo buffer is empty.
  105.  */
  106. void
  107. u_undo()
  108. {
  109.     LINE    *tl, *tu;
  110.  
  111.     if (!u_valid) {
  112.         beep();
  113.         return;
  114.     }
  115.  
  116.     /*
  117.      * Get the first line of the thing we're undoing on the screen.
  118.      */
  119.     cursor_char->linep = u_lbound->next;
  120.     cursor_char->index = 0;                    /* for now */
  121.     if (cursor_char->linep == end_of_file->linep)
  122.         cursor_char->linep = cursor_char->linep->prev;
  123.     update_cursor(0);
  124.  
  125.     /*
  126.      * Save pointers to what's in the file now.
  127.      */
  128.     if (u_lbound->next != u_ubound) {       /* there are lines to get */
  129.         tl = u_lbound->next;
  130.         tu = u_ubound->prev;
  131.         tl->prev = NULL;
  132.         tu->next = NULL;
  133.     } else
  134.         tl = tu = NULL;                 /* no lines between bounds */
  135.  
  136.     /*
  137.      * Link the undo buffer into the right place in the file.
  138.      */
  139.     if (u_lline != NULL) {          /* there are lines in the undo buf */
  140.  
  141.         /*
  142.          * If the top line of the screen is being undone, we need to
  143.          * fix up top_char to point to the new line that will be there.
  144.          */
  145.         if (u_lbound->next == top_char->linep)
  146.             top_char->linep = u_lline;
  147.  
  148.         u_lbound->next = u_lline;
  149.         u_lline->prev  = u_lbound;
  150.         u_ubound->prev = u_uline;
  151.         u_uline->next  = u_ubound;
  152.     } else {                        /* no lines... link the bounds */
  153.         if (u_lbound->next == top_char->linep)
  154.             top_char->linep = u_ubound;
  155.         if (u_lbound == top_of_file->linep)
  156.             top_char->linep = u_ubound;
  157.             
  158.         u_lbound->next = u_ubound;
  159.         u_ubound->prev = u_lbound;
  160.     }
  161.  
  162.     /*
  163.      * If we swapped the top line, patch up file_memory appropriately.
  164.      */
  165.     if (u_lbound == top_of_file->linep)
  166.         file_memory->linep = top_of_file->linep->next;
  167.  
  168.     /*
  169.      * Now save the old stuff in the undo buffer.
  170.      */
  171.     u_lline = tl;
  172.     u_uline = tu;
  173.  
  174.     renum();                /* have to renumber everything */
  175.  
  176.     /*
  177.      * Put the cursor on the first line of the 'undo' region.
  178.      */
  179.     cursor_char->linep = u_lbound->next;
  180.     cursor_char->index = 0;
  181.     if (cursor_char->linep == end_of_file->linep)
  182.         cursor_char->linep = cursor_char->linep->prev;
  183.     *cursor_char = *advance_column(cursor_char, u_col);
  184.     update_cursor(0);
  185.     update_screen(0);         /* now show the change */
  186.  
  187.     u_lfree();              /* clear the "line undo" buffer */
  188. }
  189.  
  190. /*
  191.  * u_clear() - clear the undo buffer
  192.  *
  193.  * This routine is called to clear the undo buffer at times when the
  194.  * pointers are about to become invalid, such as when a new file is
  195.  * about to be editted.
  196.  */
  197. void
  198. u_clear()
  199. {
  200.     LINE    *l, *nextl;
  201.  
  202.     if (!u_valid)           /* nothing to do */
  203.         return;
  204.  
  205.     for (l = u_lline; l != NULL ;l = nextl) {
  206.         nextl = l->next;
  207.         free(l->s);
  208.         free((char *)l);
  209.     }
  210.  
  211.     u_lbound = u_ubound = u_lline = u_uline = NULL;
  212.     u_valid = (0);
  213. }
  214.  
  215. /*
  216.  * The following functions and data implement the "line undo" feature
  217.  * performed by the 'U' command.
  218.  */
  219.  
  220. static  LINE    *u_line;                /* pointer to the line we last saved */
  221. static  LINE    *u_lcopy = NULL;        /* local copy of the original line */
  222.  
  223. /*
  224.  * u_lfree() - free the line save buffer
  225.  */
  226. static  void
  227. u_lfree()
  228. {
  229.     if (u_lcopy != NULL) {
  230.         free(u_lcopy->s);
  231.         free((char *)u_lcopy);
  232.         u_lcopy = NULL;
  233.     }
  234.     u_line = NULL;
  235. }
  236.  
  237. /*
  238.  * u_lsave() - save the current line if necessary
  239.  */
  240. static  void
  241. u_lsave(l, u)
  242. LINE    *l, *u;
  243. {
  244.  
  245.     if (l->next != u->prev) {       /* not changing exactly one line */
  246.         u_lfree();
  247.         return;
  248.     }
  249.  
  250.     if (l->next == u_line)          /* more edits on the same line */
  251.         return;
  252.  
  253.     u_lfree();
  254.     u_line = l->next;
  255.     u_lcopy = copyline(l->next);
  256. }
  257.  
  258. /*
  259.  * u_l_undo() - undo the current line (the 'U' command)
  260.  */
  261. void
  262. u_l_undo()
  263. {
  264.     if (u_lcopy != NULL) {
  265.         free(cursor_char->linep->s);
  266.         cursor_char->linep->s = u_lcopy->s;
  267.         cursor_char->linep->size = u_lcopy->size;
  268.         free((char *)u_lcopy);
  269.     } else
  270.         beep();
  271.     cursor_char->index = 0;
  272.  
  273.     update_cursor(0);
  274.     update_screen(0);         /* now show the change */
  275.  
  276.     u_lcopy = NULL; /* can't undo this kind of undo */
  277.     u_line = NULL;
  278. }
  279.  
  280. /*
  281.  * u_l_check() - clear the "line undo" buffer if we've moved to a new line
  282.  */
  283. void
  284. u_l_check()
  285. {
  286.     if (cursor_char->linep != u_line)
  287.         u_lfree();
  288. }
  289.  
  290. /*
  291.  * copyline(l) - copy the given line, and return a pointer to the copy
  292.  */
  293. static LINE *
  294. copyline(l)
  295. LINE    *l;
  296. {
  297.     LINE    *nl;            /* the new line */
  298.  
  299.     nl = newline(strlen(l->s));
  300.     strcpy(nl->s, l->s);
  301.  
  302.     return nl;
  303. }
  304.