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