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

Revision 14302, 5.4 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.
Line 
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
13static const char sccsid[] = "@(#)v_replace.c   10.17 (Berkeley) 6/30/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 <ctype.h>
22#include <errno.h>
23#include <limits.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "../common/common.h"
29#include "vi.h"
30
31/*
32 * v_replace -- [count]r<char>
33 *
34 * !!!
35 * The r command in historic vi was almost beautiful in its badness.  For
36 * example, "r<erase>" and "r<word erase>" beeped the terminal and deleted
37 * a single character.  "Nr<carriage return>", where N was greater than 1,
38 * inserted a single carriage return.  "r<escape>" did cancel the command,
39 * but "r<literal><escape>" erased a single character.  To enter a literal
40 * <literal> character, it required three <literal> characters after the
41 * command.  This may not be right, but at least it's not insane.
42 *
43 * PUBLIC: int v_replace __P((SCR *, VICMD *));
44 */
45int
46v_replace(sp, vp)
47        SCR *sp;
48        VICMD *vp;
49{
50        EVENT ev;
51        VI_PRIVATE *vip;
52        TEXT *tp;
53        size_t blen, len;
54        u_long cnt;
55        int quote, rval;
56        char *bp, *p;
57
58        vip = VIP(sp);
59
60        /*
61         * If the line doesn't exist, or it's empty, replacement isn't
62         * allowed.  It's not hard to implement, but:
63         *
64         *      1: It's historic practice (vi beeped before the replacement
65         *         character was even entered).
66         *      2: For consistency, this change would require that the more
67         *         general case, "Nr", when the user is < N characters from
68         *         the end of the line, also work, which would be a bit odd.
69         *      3: Replacing with a <newline> has somewhat odd semantics.
70         */
71        if (db_get(sp, vp->m_start.lno, DBG_FATAL, &p, &len))
72                return (1);
73        if (len == 0) {
74                msgq(sp, M_BERR, "186|No characters to replace");
75                return (1);
76        }
77
78        /*
79         * Figure out how many characters to be replace.  For no particular
80         * reason (other than that the semantics of replacing the newline
81         * are confusing) only permit the replacement of the characters in
82         * the current line.  I suppose we could append replacement characters
83         * to the line, but I see no compelling reason to do so.  Check this
84         * before we get the character to match historic practice, where Nr
85         * failed immediately if there were less than N characters from the
86         * cursor to the end of the line.
87         */
88        cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1;
89        vp->m_stop.lno = vp->m_start.lno;
90        vp->m_stop.cno = vp->m_start.cno + cnt - 1;
91        if (vp->m_stop.cno > len - 1) {
92                v_eol(sp, &vp->m_start);
93                return (1);
94        }
95
96        /*
97         * If it's not a repeat, reset the current mode and get a replacement
98         * character.
99         */
100        quote = 0;
101        if (!F_ISSET(vp, VC_ISDOT)) {
102                sp->showmode = SM_REPLACE;
103                if (vs_refresh(sp, 0))
104                        return (1);
105next:           if (v_event_get(sp, &ev, 0, 0))
106                        return (1);
107
108                switch (ev.e_event) {
109                case E_CHARACTER:
110                        /*
111                         * <literal_next> means escape the next character.
112                         * <escape> means they changed their minds.
113                         */
114                        if (!quote) {
115                                if (ev.e_value == K_VLNEXT) {
116                                        quote = 1;
117                                        goto next;
118                                }
119                                if (ev.e_value == K_ESCAPE)
120                                        return (0);
121                        }
122                        vip->rlast = ev.e_c;
123                        vip->rvalue = ev.e_value;
124                        break;
125                case E_ERR:
126                case E_EOF:
127                        F_SET(sp, SC_EXIT_FORCE);
128                        return (1);
129                case E_INTERRUPT:
130                        /* <interrupt> means they changed their minds. */
131                        return (0);
132                case E_WRESIZE:
133                        /* <resize> interrupts the input mode. */
134                        v_emsg(sp, NULL, VIM_WRESIZE);
135                        return (0);
136                case E_REPAINT:
137                        if (vs_repaint(sp, &ev))
138                                return (1);
139                        goto next;
140                default:
141                        v_event_err(sp, &ev);
142                        return (0);
143                }
144        }
145
146        /* Copy the line. */
147        GET_SPACE_RET(sp, bp, blen, len);
148        memmove(bp, p, len);
149        p = bp;
150
151        /*
152         * Versions of nvi before 1.57 created N new lines when they replaced
153         * N characters with <carriage-return> or <newline> characters.  This
154         * is different from the historic vi, which replaced N characters with
155         * a single new line.  Users complained, so we match historic practice.
156         */
157        if (!quote && vip->rvalue == K_CR || vip->rvalue == K_NL) {
158                /* Set return line. */
159                vp->m_stop.lno = vp->m_start.lno + 1;
160                vp->m_stop.cno = 0;
161
162                /* The first part of the current line. */
163                if (db_set(sp, vp->m_start.lno, p, vp->m_start.cno))
164                        goto err_ret;
165
166                /*
167                 * The rest of the current line.  And, of course, now it gets
168                 * tricky.  If there are characters left in the line and if
169                 * the autoindent edit option is set, white space after the
170                 * replaced character is discarded, autoindent is applied, and
171                 * the cursor moves to the last indent character.
172                 */
173                p += vp->m_start.cno + cnt;
174                len -= vp->m_start.cno + cnt;
175                if (len != 0 && O_ISSET(sp, O_AUTOINDENT))
176                        for (; len && isblank(*p); --len, ++p);
177
178                if ((tp = text_init(sp, p, len, len)) == NULL)
179                        goto err_ret;
180
181                if (len != 0 && O_ISSET(sp, O_AUTOINDENT)) {
182                        if (v_txt_auto(sp, vp->m_start.lno, NULL, 0, tp))
183                                goto err_ret;
184                        vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0;
185                } else
186                        vp->m_stop.cno = 0;
187
188                vp->m_stop.cno = tp->ai ? tp->ai - 1 : 0;
189                if (db_append(sp, 1, vp->m_start.lno, tp->lb, tp->len))
190err_ret:                rval = 1;
191                else {
192                        text_free(tp);
193                        rval = 0;
194                }
195        } else {
196                memset(bp + vp->m_start.cno, vip->rlast, cnt);
197                rval = db_set(sp, vp->m_start.lno, bp, len);
198        }
199        FREE_SPACE(sp, bp, blen);
200
201        vp->m_final = vp->m_stop;
202        return (rval);
203}
Note: See TracBrowser for help on using the repository browser.