BSD 2 development
[unix-history] / src / ex / ex_addr.c
CommitLineData
396f4c28
BJ
1/* Copyright (c) 1979 Regents of the University of California */
2#include "ex.h"
3#include "ex_re.h"
4
5/*
6 * Routines for address parsing and assignment and checking of address bounds
7 * in command mode. The routine address is called from ex_cmds.c
8 * to parse each component of a command (terminated by , ; or the beginning
9 * of the command itself. It is also called by the scanning routine
10 * in ex_voperate.c from within open/visual.
11 *
12 * Other routines here manipulate the externals addr1 and addr2.
13 * These are the first and last lines for the current command.
14 *
15 * The variable bigmove remembers whether a non-local glitch of . was
16 * involved in an address expression, so we can set the previous context
17 * mark '' when such a motion occurs.
18 */
19
20static bool bigmove;
21
22/*
23 * Set up addr1 and addr2 for commands whose default address is dot.
24 */
25setdot()
26{
27
28 setdot1();
29 if (bigmove)
30 markDOT();
31}
32
33/*
34 * Call setdot1 to set up default addresses without ever
35 * setting the previous context mark.
36 */
37setdot1()
38{
39
40 if (addr2 == 0)
41 addr1 = addr2 = dot;
42 if (addr1 > addr2) {
43 notempty();
44 error("Addr1 > addr2|First address exceeds second");
45 }
46}
47
48/*
49 * Ex allows you to say
50 * delete 5
51 * to delete 5 lines, etc.
52 * Such nonsense is implemented by setcount.
53 */
54setcount()
55{
56 register int cnt;
57
58 pastwh();
59 if (!isdigit(peekchar())) {
60 setdot();
61 return;
62 }
63 addr1 = addr2;
64 setdot();
65 cnt = getnum();
66 if (cnt <= 0)
67 error("Bad count|Nonzero count required");
68 addr2 += cnt - 1;
69 if (addr2 > dol)
70 addr2 = dol;
71 nonzero();
72}
73
74/*
75 * Parse a number out of the command input stream.
76 */
77getnum()
78{
79 register int cnt;
80
81 for (cnt = 0; isdigit(peekcd());)
82 cnt = cnt * 10 + getchar() - '0';
83 return (cnt);
84}
85
86/*
87 * Set the default addresses for commands which use the whole
88 * buffer as default, notably write.
89 */
90setall()
91{
92
93 if (addr2 == 0) {
94 addr1 = one;
95 addr2 = dol;
96 if (dol == zero) {
97 dot = zero;
98 return;
99 }
100 }
101 /*
102 * Don't want to set previous context mark so use setdot1().
103 */
104 setdot1();
105}
106
107/*
108 * No address allowed on, e.g. the file command.
109 */
110setnoaddr()
111{
112
113 if (addr2 != 0)
114 error("No address allowed@on this command");
115}
116
117/*
118 * Parse an address.
119 * Just about any sequence of address characters is legal.
120 *
121 * If you are tricky you can use this routine and the = command
122 * to do simple addition and subtraction of cardinals less
123 * than the number of lines in the file.
124 */
125line *
126address()
127{
128 register line *addr;
129 register int offset, c;
130 short lastsign;
131
132 bigmove = 0;
133 lastsign = 0;
134 offset = 0;
135 addr = 0;
136 for (;;) {
137 if (isdigit(peekcd())) {
138 if (addr == 0) {
139 addr = zero;
140 bigmove = 1;
141 }
142 loc1 = 0;
143 addr += offset;
144 offset = getnum();
145 if (lastsign >= 0)
146 addr += offset;
147 else
148 addr -= offset;
149 lastsign = 0;
150 offset = 0;
151 }
152 switch (c = getcd()) {
153
154 case '?':
155 case '/':
156 case '$':
157 case '\'':
158 case '\\':
159 bigmove++;
160 case '.':
161 if (addr || offset)
162 error("Badly formed address");
163 }
164 offset += lastsign;
165 lastsign = 0;
166 switch (c) {
167
168 case ' ':
169 case '\t':
170 continue;
171
172 case '+':
173 lastsign = 1;
174 if (addr == 0)
175 addr = dot;
176 continue;
177
178 case '^':
179 case '-':
180 lastsign = -1;
181 if (addr == 0)
182 addr = dot;
183 continue;
184
185 case '\\':
186 case '?':
187 case '/':
188 c = compile(c, 1);
189 notempty();
190 savere(scanre);
191 addr = dot;
192 for (;;) {
193 if (c == '/') {
194 addr++;
195 if (addr > dol) {
196 if (value(WRAPSCAN) == 0)
197 error("No match to BOTTOM|Address search hit BOTTOM without matching pattern");
198 addr = zero;
199 }
200 } else {
201 addr--;
202 if (addr < zero) {
203 if (value(WRAPSCAN) == 0)
204 error("No match to TOP|Address search hit TOP without matching pattern");
205 addr = dol;
206 }
207 }
208 if (execute(0, addr))
209 break;
210 if (addr == dot)
211 error("Fail|Pattern not found");
212 }
213 continue;
214
215 case '$':
216 addr = dol;
217 continue;
218
219 case '.':
220 addr = dot;
221 continue;
222
223 case '\'':
224 c = markreg(getchar());
225 if (c == 0)
226 error("Marks are ' and a-z");
227 addr = getmark(c);
228 if (addr == 0)
229 error("Undefined mark@referenced");
230 break;
231
232 default:
233 ungetchar(c);
234 if (offset) {
235 if (addr == 0)
236 addr = dot;
237 addr += offset;
238 loc1 = 0;
239 }
240 if (addr == 0) {
241 bigmove = 0;
242 return (0);
243 }
244 if (addr != zero)
245 notempty();
246 addr += lastsign;
247 if (addr < zero)
248 error("Negative address@- first buffer line is 1");
249 if (addr > dol)
250 error("Not that many lines@in buffer");
251 return (addr);
252 }
253 }
254}
255
256/*
257 * Abbreviations to make code smaller
258 * Left over from squashing ex version 1.1 into
259 * 11/34's and 11/40's.
260 */
261setCNL()
262{
263
264 setcount();
265 newline();
266}
267
268setNAEOL()
269{
270
271 setnoaddr();
272 eol();
273}