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