home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / ex / ex_shift.c < prev    next >
C/C++ Source or Header  |  1996-09-15  |  5KB  |  192 lines

  1. /*-
  2.  * Copyright (c) 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 1992, 1993, 1994, 1995, 1996
  5.  *    Keith Bostic.  All rights reserved.
  6.  *
  7.  * See the LICENSE file for redistribution information.
  8.  */
  9.  
  10. #include "config.h"
  11.  
  12. #ifndef lint
  13. static const char sccsid[] = "@(#)ex_shift.c    10.11 (Berkeley) 9/15/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18.  
  19. #include <bitstring.h>
  20. #include <limits.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24.  
  25. #include "../common/common.h"
  26.  
  27. enum which {LEFT, RIGHT};
  28. static int shift __P((SCR *, EXCMD *, enum which));
  29.  
  30. /*
  31.  * ex_shiftl -- :<[<...]
  32.  *
  33.  *
  34.  * PUBLIC: int ex_shiftl __P((SCR *, EXCMD *));
  35.  */
  36. int
  37. ex_shiftl(sp, cmdp)
  38.     SCR *sp;
  39.     EXCMD *cmdp;
  40. {
  41.     return (shift(sp, cmdp, LEFT));
  42. }
  43.  
  44. /*
  45.  * ex_shiftr -- :>[>...]
  46.  *
  47.  * PUBLIC: int ex_shiftr __P((SCR *, EXCMD *));
  48.  */
  49. int
  50. ex_shiftr(sp, cmdp)
  51.     SCR *sp;
  52.     EXCMD *cmdp;
  53. {
  54.     return (shift(sp, cmdp, RIGHT));
  55. }
  56.  
  57. /*
  58.  * shift --
  59.  *    Ex shift support.
  60.  */
  61. static int
  62. shift(sp, cmdp, rl)
  63.     SCR *sp;
  64.     EXCMD *cmdp;
  65.     enum which rl;
  66. {
  67.     recno_t from, to;
  68.     size_t blen, len, newcol, newidx, oldcol, oldidx, sw;
  69.     int curset;
  70.     char *p, *bp, *tbp;
  71.  
  72.     NEEDFILE(sp, cmdp);
  73.  
  74.     if (O_VAL(sp, O_SHIFTWIDTH) == 0) {
  75.         msgq(sp, M_INFO, "152|shiftwidth option set to 0");
  76.         return (0);
  77.     }
  78.  
  79.     /* Copy the lines being shifted into the unnamed buffer. */
  80.     if (cut(sp, NULL, &cmdp->addr1, &cmdp->addr2, CUT_LINEMODE))
  81.         return (1);
  82.  
  83.     /*
  84.      * The historic version of vi permitted the user to string any number
  85.      * of '>' or '<' characters together, resulting in an indent of the
  86.      * appropriate levels.  There's a special hack in ex_cmd() so that
  87.      * cmdp->argv[0] points to the string of '>' or '<' characters.
  88.      *
  89.      * Q: What's the difference between the people adding features
  90.      *    to vi and the Girl Scouts?
  91.      * A: The Girl Scouts have mint cookies and adult supervision.
  92.      */
  93.     for (p = cmdp->argv[0]->bp, sw = 0; *p == '>' || *p == '<'; ++p)
  94.         sw += O_VAL(sp, O_SHIFTWIDTH);
  95.  
  96.     GET_SPACE_RET(sp, bp, blen, 256);
  97.  
  98.     curset = 0;
  99.     for (from = cmdp->addr1.lno, to = cmdp->addr2.lno; from <= to; ++from) {
  100.         if (db_get(sp, from, DBG_FATAL, &p, &len))
  101.             goto err;
  102.         if (!len) {
  103.             if (sp->lno == from)
  104.                 curset = 1;
  105.             continue;
  106.         }
  107.  
  108.         /*
  109.          * Calculate the old indent amount and the number of
  110.          * characters it used.
  111.          */
  112.         for (oldidx = 0, oldcol = 0; oldidx < len; ++oldidx)
  113.             if (p[oldidx] == ' ')
  114.                 ++oldcol;
  115.             else if (p[oldidx] == '\t')
  116.                 oldcol += O_VAL(sp, O_TABSTOP) -
  117.                     oldcol % O_VAL(sp, O_TABSTOP);
  118.             else
  119.                 break;
  120.  
  121.         /* Calculate the new indent amount. */
  122.         if (rl == RIGHT)
  123.             newcol = oldcol + sw;
  124.         else {
  125.             newcol = oldcol < sw ? 0 : oldcol - sw;
  126.             if (newcol == oldcol) {
  127.                 if (sp->lno == from)
  128.                     curset = 1;
  129.                 continue;
  130.             }
  131.         }
  132.  
  133.         /* Get a buffer that will hold the new line. */
  134.         ADD_SPACE_RET(sp, bp, blen, newcol + len);
  135.  
  136.         /*
  137.          * Build a new indent string and count the number of
  138.          * characters it uses.
  139.          */
  140.         for (tbp = bp, newidx = 0;
  141.             newcol >= O_VAL(sp, O_TABSTOP); ++newidx) {
  142.             *tbp++ = '\t';
  143.             newcol -= O_VAL(sp, O_TABSTOP);
  144.         }
  145.         for (; newcol > 0; --newcol, ++newidx)
  146.             *tbp++ = ' ';
  147.  
  148.         /* Add the original line. */
  149.         memcpy(tbp, p + oldidx, len - oldidx);
  150.  
  151.         /* Set the replacement line. */
  152.         if (db_set(sp, from, bp, (tbp + (len - oldidx)) - bp)) {
  153. err:            FREE_SPACE(sp, bp, blen);
  154.             return (1);
  155.         }
  156.  
  157.         /*
  158.          * !!!
  159.          * The shift command in historic vi had the usual bizarre
  160.          * collection of cursor semantics.  If called from vi, the
  161.          * cursor was repositioned to the first non-blank character
  162.          * of the lowest numbered line shifted.  If called from ex,
  163.          * the cursor was repositioned to the first non-blank of the
  164.          * highest numbered line shifted.  Here, if the cursor isn't
  165.          * part of the set of lines that are moved, move it to the
  166.          * first non-blank of the last line shifted.  (This makes
  167.          * ":3>>" in vi work reasonably.)  If the cursor is part of
  168.          * the shifted lines, it doesn't get moved at all.  This
  169.          * permits shifting of marked areas, i.e. ">'a." shifts the
  170.          * marked area twice, something that couldn't be done with
  171.          * historic vi.
  172.          */
  173.         if (sp->lno == from) {
  174.             curset = 1;
  175.             if (newidx > oldidx)
  176.                 sp->cno += newidx - oldidx;
  177.             else if (sp->cno >= oldidx - newidx)
  178.                 sp->cno -= oldidx - newidx;
  179.         }
  180.     }
  181.     if (!curset) {
  182.         sp->lno = to;
  183.         sp->cno = 0;
  184.         (void)nonblank(sp, to, &sp->cno);
  185.     }
  186.  
  187.     FREE_SPACE(sp, bp, blen);
  188.  
  189.     sp->rptlines[L_SHIFT] += cmdp->addr2.lno - cmdp->addr1.lno + 1;
  190.     return (0);
  191. }
  192.