home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Spezial / SPEZIAL2_97.zip / SPEZIAL2_97.iso / ANWEND / EDITOR / NVI179B / NVI179B.ZIP / vi / vs_relative.c < prev    next >
C/C++ Source or Header  |  1996-05-13  |  7KB  |  306 lines

  1. /*-
  2.  * Copyright (c) 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  * Copyright (c) 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[] = "@(#)vs_relative.c    10.11 (Berkeley) 5/13/96";
  14. #endif /* not lint */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/queue.h>
  18. #include <sys/time.h>
  19.  
  20. #include <bitstring.h>
  21. #include <limits.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24.  
  25. #include "../common/common.h"
  26. #include "vi.h"
  27.  
  28. /*
  29.  * vs_column --
  30.  *    Return the logical column of the cursor in the line.
  31.  *
  32.  * PUBLIC: int vs_column __P((SCR *, size_t *));
  33.  */
  34. int
  35. vs_column(sp, colp)
  36.     SCR *sp;
  37.     size_t *colp;
  38. {
  39.     VI_PRIVATE *vip;
  40.  
  41.     vip = VIP(sp);
  42.  
  43.     *colp = (O_ISSET(sp, O_LEFTRIGHT) ?
  44.         vip->sc_smap->coff : (vip->sc_smap->soff - 1) * sp->cols) +
  45.         vip->sc_col - (O_ISSET(sp, O_NUMBER) ? O_NUMBER_LENGTH : 0);
  46.     return (0);
  47. }
  48.  
  49. /*
  50.  * vs_screens --
  51.  *    Return the screens necessary to display the line, or if specified,
  52.  *    the physical character column within the line, including space
  53.  *    required for the O_NUMBER and O_LIST options.
  54.  *
  55.  * PUBLIC: size_t vs_screens __P((SCR *, recno_t, size_t *));
  56.  */
  57. size_t
  58. vs_screens(sp, lno, cnop)
  59.     SCR *sp;
  60.     recno_t lno;
  61.     size_t *cnop;
  62. {
  63.     size_t cols, screens;
  64.  
  65.     /* Left-right screens are simple, it's always 1. */
  66.     if (O_ISSET(sp, O_LEFTRIGHT))
  67.         return (1);
  68.  
  69.     /*
  70.      * Check for a cached value.  We maintain a cache because, if the
  71.      * line is large, this routine gets called repeatedly.  One other
  72.      * hack, lots of time the cursor is on column one, which is an easy
  73.      * one.
  74.      */
  75.     if (cnop == NULL) {
  76.         if (VIP(sp)->ss_lno == lno)
  77.             return (VIP(sp)->ss_screens);
  78.     } else if (*cnop == 0)
  79.         return (1);
  80.  
  81.     /* Figure out how many columns the line/column needs. */
  82.     cols = vs_columns(sp, NULL, lno, cnop, NULL);
  83.  
  84.     screens = (cols / sp->cols + (cols % sp->cols ? 1 : 0));
  85.     if (screens == 0)
  86.         screens = 1;
  87.  
  88.     /* Cache the value. */
  89.     if (cnop == NULL) {
  90.         VIP(sp)->ss_lno = lno;
  91.         VIP(sp)->ss_screens = screens;
  92.     }
  93.     return (screens);
  94. }
  95.  
  96. /*
  97.  * vs_columns --
  98.  *    Return the screen columns necessary to display the line, or,
  99.  *    if specified, the physical character column within the line.
  100.  *
  101.  * PUBLIC: size_t vs_columns __P((SCR *, char *, recno_t, size_t *, size_t *));
  102.  */
  103. size_t
  104. vs_columns(sp, lp, lno, cnop, diffp)
  105.     SCR *sp;
  106.     char *lp;
  107.     recno_t lno;
  108.     size_t *cnop, *diffp;
  109. {
  110.     size_t chlen, cno, curoff, last, len, scno;
  111.     int ch, leftright, listset;
  112.     char *p;
  113.  
  114.     /* Need the line to go any further. */
  115.     if (lp == NULL) {
  116.         (void)db_get(sp, lno, 0, &lp, &len);
  117.         if (len == 0)
  118.             goto done;
  119.     }
  120.  
  121.     /* Missing or empty lines are easy. */
  122.     if (lp == NULL) {
  123. done:        if (diffp != NULL)        /* XXX */
  124.             *diffp = 0;
  125.         return (0);
  126.     }
  127.  
  128.     /* Store away the values of the list and leftright edit options. */
  129.     listset = O_ISSET(sp, O_LIST);
  130.     leftright = O_ISSET(sp, O_LEFTRIGHT);
  131.  
  132.     /*
  133.      * Initialize the pointer into the buffer and screen and current
  134.      * offsets.
  135.      */
  136.     p = lp;
  137.     curoff = scno = 0;
  138.  
  139.     /* Leading number if O_NUMBER option set. */
  140.     if (O_ISSET(sp, O_NUMBER))
  141.         scno += O_NUMBER_LENGTH;
  142.  
  143.     /* Macro to return the display length of any signal character. */
  144. #define    CHLEN(val) (ch = *(u_char *)p++) == '\t' &&            \
  145.         !listset ? TAB_OFF(val) : KEY_LEN(sp, ch);
  146.  
  147.     /*
  148.      * If folding screens (the historic vi screen format), past the end
  149.      * of the current screen, and the character was a tab, reset the
  150.      * current screen column to 0, and the total screen columns to the
  151.      * last column of the screen.  Otherwise, display the rest of the
  152.      * character in the next screen.
  153.      */
  154. #define    TAB_RESET {                            \
  155.     curoff += chlen;                        \
  156.     if (!leftright && curoff >= sp->cols)                \
  157.         if (ch == '\t') {                    \
  158.             curoff = 0;                    \
  159.             scno -= scno % sp->cols;            \
  160.         } else                            \
  161.             curoff -= sp->cols;                \
  162. }
  163.     if (cnop == NULL)
  164.         while (len--) {
  165.             chlen = CHLEN(curoff);
  166.             last = scno;
  167.             scno += chlen;
  168.             TAB_RESET;
  169.         }
  170.     else
  171.         for (cno = *cnop;; --cno) {
  172.             chlen = CHLEN(curoff);
  173.             last = scno;
  174.             scno += chlen;
  175.             TAB_RESET;
  176.             if (cno == 0)
  177.                 break;
  178.         }
  179.  
  180.     /* Add the trailing '$' if the O_LIST option set. */
  181.     if (listset && cnop == NULL)
  182.         scno += KEY_LEN(sp, '$');
  183.  
  184.     /*
  185.      * The text input screen code needs to know how much additional
  186.      * room the last two characters required, so that it can handle
  187.      * tab character displays correctly.
  188.      */
  189.     if (diffp != NULL)
  190.         *diffp = scno - last;
  191.     return (scno);
  192. }
  193.  
  194. /*
  195.  * vs_rcm --
  196.  *    Return the physical column from the line that will display a
  197.  *    character closest to the currently most attractive character
  198.  *    position (which is stored as a screen column).
  199.  *
  200.  * PUBLIC: size_t vs_rcm __P((SCR *, recno_t, int));
  201.  */
  202. size_t
  203. vs_rcm(sp, lno, islast)
  204.     SCR *sp;
  205.     recno_t lno;
  206.     int islast;
  207. {
  208.     size_t len;
  209.  
  210.     /* Last character is easy, and common. */
  211.     if (islast) {
  212.         if (db_get(sp, lno, 0, NULL, &len) || len == 0)
  213.             return (0);
  214.         return (len - 1);
  215.     }
  216.  
  217.     /* First character is easy, and common. */
  218.     if (sp->rcm == 0)
  219.         return (0);
  220.  
  221.     return (vs_colpos(sp, lno, sp->rcm));
  222. }
  223.  
  224. /*
  225.  * vs_colpos --
  226.  *    Return the physical column from the line that will display a
  227.  *    character closest to the specified screen column.
  228.  *
  229.  * PUBLIC: size_t vs_colpos __P((SCR *, recno_t, size_t));
  230.  */
  231. size_t
  232. vs_colpos(sp, lno, cno)
  233.     SCR *sp;
  234.     recno_t lno;
  235.     size_t cno;
  236. {
  237.     size_t chlen, curoff, len, llen, off, scno;
  238.     int ch, leftright, listset;
  239.     char *lp, *p;
  240.  
  241.     /* Need the line to go any further. */
  242.     (void)db_get(sp, lno, 0, &lp, &llen);
  243.  
  244.     /* Missing or empty lines are easy. */
  245.     if (lp == NULL || llen == 0)
  246.         return (0);
  247.  
  248.     /* Store away the values of the list and leftright edit options. */
  249.     listset = O_ISSET(sp, O_LIST);
  250.     leftright = O_ISSET(sp, O_LEFTRIGHT);
  251.  
  252.     /* Discard screen (logical) lines. */
  253.     off = cno / sp->cols;
  254.     cno %= sp->cols;
  255.     for (scno = 0, p = lp, len = llen; off--;) {
  256.         for (; len && scno < sp->cols; --len)
  257.             scno += CHLEN(scno);
  258.  
  259.         /*
  260.          * If reached the end of the physical line, return the last
  261.          * physical character in the line.
  262.          */
  263.         if (len == 0)
  264.             return (llen - 1);
  265.  
  266.         /*
  267.          * If folding screens (the historic vi screen format), past
  268.          * the end of the current screen, and the character was a tab,
  269.          * reset the current screen column to 0.  Otherwise, the rest
  270.          * of the character is displayed in the next screen.
  271.          */
  272.         if (leftright && ch == '\t')
  273.             scno = 0;
  274.         else
  275.             scno -= sp->cols;
  276.     }
  277.  
  278.     /* Step through the line until reach the right character or EOL. */
  279.     for (curoff = scno; len--;) {
  280.         chlen = CHLEN(curoff);
  281.  
  282.         /*
  283.          * If we've reached the specific character, there are three
  284.          * cases.
  285.          *
  286.          * 1: scno == cno, i.e. the current character ends at the
  287.          *    screen character we care about.
  288.          *    a: off < llen - 1, i.e. not the last character in
  289.          *       the line, return the offset of the next character.
  290.          *    b: else return the offset of the last character.
  291.          * 2: scno != cno, i.e. this character overruns the character
  292.          *    we care about, return the offset of this character.
  293.          */
  294.         if ((scno += chlen) >= cno) {
  295.             off = p - lp;
  296.             return (scno == cno ?
  297.                 (off < llen - 1 ? off : llen - 1) : off - 1);
  298.         }
  299.  
  300.         TAB_RESET;
  301.     }
  302.  
  303.     /* No such character; return the start of the last character. */
  304.     return (llen - 1);
  305. }
  306.