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