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