source: trunk/third/nvi/vi/vs_relative.c @ 14302

Revision 14302, 7.1 KB checked in by ghudson, 25 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14301, which included commits to RCS files with non-trunk default branches.
RevLine 
[14301]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
13static 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 */
34int
35vs_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 */
57size_t
58vs_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 */
103size_t
104vs_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) {
123done:           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 */
202size_t
203vs_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 */
231size_t
232vs_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}
Note: See TracBrowser for help on using the repository browser.