1 /*
2 * This code contains changes by
3 * Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4 *
5 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6 * to these changes.
7 *
8 *
9 * Copyright (c) 1980, 1993
10 * The Regents of the University of California. All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *
41 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * Redistributions of source code and documentation must retain the
47 * above copyright notice, this list of conditions and the following
48 * disclaimer.
49 * Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the distribution.
52 * All advertising materials mentioning features or use of this software
53 * must display the following acknowledgement:
54 * This product includes software developed or owned by Caldera
55 * International, Inc.
56 * Neither the name of Caldera International, Inc. nor the names of
57 * other contributors may be used to endorse or promote products
58 * derived from this software without specific prior written permission.
59 *
60 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72 */
73
74 #ifndef lint
75 #ifdef DOSCCS
76 static char sccsid[] = "@(#)ex_addr.c 1.10 (gritter) 2/17/05";
77 #endif
78 #endif /* not lint */
79
80 /* from ex_addr.c 7.3 (Berkeley) 6/7/85 */
81
82 #include "ex.h"
83 #include "ex_re.h"
84
85 /*
86 * Routines for address parsing and assignment and checking of address bounds
87 * in command mode. The routine address is called from ex_cmds.c
88 * to parse each component of a command (terminated by , ; or the beginning
89 * of the command itself. It is also called by the scanning routine
90 * in ex_voperate.c from within open/visual.
91 *
92 * Other routines here manipulate the externals addr1 and addr2.
93 * These are the first and last lines for the current command.
94 *
95 * The variable bigmove remembers whether a non-local glitch of . was
96 * involved in an address expression, so we can set the previous context
97 * mark '' when such a motion occurs.
98 */
99
100 static bool bigmove;
101
102 /*
103 * Set up addr1 and addr2 for commands whose default address is dot.
104 */
105 void
setdot(void)106 setdot(void)
107 {
108
109 setdot1();
110 if (bigmove)
111 markDOT();
112 }
113
114 /*
115 * Call setdot1 to set up default addresses without ever
116 * setting the previous context mark.
117 */
118 void
setdot1(void)119 setdot1(void)
120 {
121
122 if (addr2 == 0)
123 addr1 = addr2 = dot;
124 if (addr1 > addr2) {
125 notempty();
126 failed = 1;
127 error(catgets(catd, 1, 6,
128 "Addr1 > addr2|First address exceeds second"));
129 }
130 }
131
132 /*
133 * Ex allows you to say
134 * delete 5
135 * to delete 5 lines, etc.
136 * Such nonsense is implemented by setcount.
137 */
138 void
setcount(void)139 setcount(void)
140 {
141 register int cnt;
142
143 pastwh();
144 if (!isdigit(peekchar())) {
145 setdot();
146 return;
147 }
148 addr1 = addr2;
149 setdot();
150 cnt = getnum();
151 if (cnt <= 0)
152 error(catgets(catd, 1, 7, "Bad count|Nonzero count required"));
153 addr2 += cnt - 1;
154 if (addr2 > dol)
155 addr2 = dol;
156 nonzero();
157 }
158
159 /*
160 * Parse a number out of the command input stream.
161 */
162 int
getnum(void)163 getnum(void)
164 {
165 register int cnt;
166
167 for (cnt = 0; isdigit(peekcd());)
168 cnt = cnt * 10 + getchar() - '0';
169 return (cnt);
170 }
171
172 /*
173 * Set the default addresses for commands which use the whole
174 * buffer as default, notably write.
175 */
176 void
setall(void)177 setall(void)
178 {
179
180 if (addr2 == 0) {
181 addr1 = one;
182 addr2 = dol;
183 if (dol == zero) {
184 dot = zero;
185 return;
186 }
187 }
188 /*
189 * Don't want to set previous context mark so use setdot1().
190 */
191 setdot1();
192 }
193
194 /*
195 * No address allowed on, e.g. the file command.
196 */
197 void
setnoaddr(void)198 setnoaddr(void)
199 {
200
201 if (addr2 != 0) {
202 failed = 1;
203 error(catgets(catd, 1, 8,
204 "No address allowed@on this command"));
205 }
206 }
207
208 /*
209 * Parse an address.
210 * Just about any sequence of address characters is legal.
211 *
212 * If you are tricky you can use this routine and the = command
213 * to do simple addition and subtraction of cardinals less
214 * than the number of lines in the file.
215 */
216 line *
address(char * in_line)217 address(char *in_line)
218 {
219 register line *addr;
220 register int offset, c;
221 short lastsign;
222
223 bigmove = 0;
224 lastsign = 0;
225 offset = 0;
226 addr = 0;
227 for (;;) {
228 if (isdigit(peekcd())) {
229 if (addr == 0) {
230 addr = zero;
231 bigmove = 1;
232 }
233 loc1 = 0;
234 addr += offset;
235 offset = getnum();
236 if (lastsign >= 0)
237 addr += offset;
238 else
239 addr -= offset;
240 lastsign = 0;
241 offset = 0;
242 }
243 switch (c = getcd()) {
244
245 case '?':
246 case '/':
247 case '$':
248 case '\'':
249 case '\\':
250 bigmove++;
251 case '.':
252 if (addr || offset)
253 error(catgets(catd, 1, 9,
254 "Badly formed address"));
255 }
256 offset += lastsign;
257 lastsign = 0;
258 switch (c) {
259
260 case ' ':
261 case '\t':
262 continue;
263
264 case '+':
265 lastsign = 1;
266 if (addr == 0)
267 addr = dot;
268 continue;
269
270 case '^':
271 case '-':
272 lastsign = -1;
273 if (addr == 0)
274 addr = dot;
275 continue;
276
277 case '\\':
278 case '?':
279 case '/':
280 c = compile(c, 1);
281 notempty();
282 savere(&scanre);
283 addr = dot;
284 if (in_line && execute(0, dot)) {
285 if (c == '/') {
286 while (loc1 <= in_line) {
287 if (loc1 == loc2)
288 loc2++;
289 if (!execute(1, NULL))
290 goto nope;
291 }
292 break;
293 } else if (loc1 < in_line) {
294 char *last;
295 doques:
296
297 do {
298 last = loc1;
299 if (loc1 == loc2)
300 loc2++;
301 if (!execute(1, NULL))
302 break;
303 } while (loc1 < in_line);
304 loc1 = last;
305 break;
306 }
307 }
308 nope:
309 for (;;) {
310 if (c == '/') {
311 addr++;
312 if (addr > dol) {
313 if (value(WRAPSCAN) == 0)
314 error(catgets(catd, 1, 10, "No match to BOTTOM|Address search hit BOTTOM without matching pattern"));
315 addr = zero;
316 }
317 } else {
318 addr--;
319 if (addr < zero) {
320 if (value(WRAPSCAN) == 0)
321 error(catgets(catd, 1, 11, "No match to TOP|Address search hit TOP without matching pattern"));
322 addr = dol;
323 }
324 }
325 if (execute(0, addr)) {
326 if (in_line && c == '?') {
327 in_line = &linebuf[LBSIZE];
328 goto doques;
329 }
330 break;
331 }
332 if (addr == dot)
333 error(catgets(catd, 1, 12,
334 "Fail|Pattern not found"));
335 }
336 continue;
337
338 case '$':
339 addr = dol;
340 continue;
341
342 case '.':
343 addr = dot;
344 continue;
345
346 case '\'':
347 c = markreg(getchar());
348 if (c == 0)
349 error(catgets(catd, 1, 13,
350 "Marks are ' and a-z"));
351 addr = getmark(c);
352 if (addr == 0)
353 error(catgets(catd, 1, 14,
354 "Undefined mark@referenced"));
355 break;
356
357 default:
358 ungetchar(c);
359 if (offset) {
360 if (addr == 0)
361 addr = dot;
362 addr += offset;
363 loc1 = 0;
364 }
365 if (addr == 0) {
366 bigmove = 0;
367 return (0);
368 }
369 if (addr != zero)
370 notempty();
371 addr += lastsign;
372 if (addr < zero) {
373 failed = 1;
374 error(catgets(catd, 1, 15,
375 "Negative address@- first buffer line is 1"));
376 }
377 if (addr > dol) {
378 failed = 1;
379 error(catgets(catd, 1, 16,
380 "Not that many lines@in buffer"));
381 }
382 return (addr);
383 }
384 }
385 }
386
387 /*
388 * Abbreviations to make code smaller
389 * Left over from squashing ex version 1.1 into
390 * 11/34's and 11/40's.
391 */
392 void
setCNL(void)393 setCNL(void)
394 {
395
396 setcount();
397 newline();
398 }
399
400 void
setNAEOL(void)401 setNAEOL(void)
402 {
403
404 setnoaddr();
405 eol();
406 }
407