new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / ex / ex_addr.c
CommitLineData
2791ff57
KB
1/*-
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
19d73a0e
DF
6 */
7
8#ifndef lint
2791ff57
KB
9static char sccsid[] = "@(#)ex_addr.c 7.6 (Berkeley) %G%";
10#endif /* not lint */
19d73a0e 11
f4d38626
MH
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
30static bool bigmove;
31
32/*
33 * Set up addr1 and addr2 for commands whose default address is dot.
34 */
35setdot()
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 */
47setdot1()
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 */
64setcount()
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 */
87getnum()
88{
89 register int cnt;
90
91 for (cnt = 0; isdigit(peekcd());)
5a6c967e 92 cnt = cnt * 10 + ex_getchar() - '0';
f4d38626
MH
93 return (cnt);
94}
95
96/*
97 * Set the default addresses for commands which use the whole
98 * buffer as default, notably write.
99 */
100setall()
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 */
120setnoaddr()
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 */
135line *
13c5231e
KB
136address(inputline)
137 char *inputline;
f4d38626
MH
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;
13c5231e 203 if (inputline && execute(0, dot)) {
f4d38626 204 if (c == '/') {
13c5231e 205 while (loc1 <= inputline) {
d266c416
MH
206 if (loc1 == loc2)
207 loc2++;
f4d38626
MH
208 if (!execute(1))
209 goto nope;
ea87719e
MH
210 }
211 break;
13c5231e 212 } else if (loc1 < inputline) {
ea87719e
MH
213 char *last;
214doques:
215
216 do {
217 last = loc1;
218 if (loc1 == loc2)
219 loc2++;
220 if (!execute(1))
221 break;
13c5231e 222 } while (loc1 < inputline);
ea87719e
MH
223 loc1 = last;
224 break;
225 }
226 }
227nope:
228 for (;;) {
229 if (c == '/') {
230 addr++;
231 if (addr > dol) {
232 if (value(WRAPSCAN) == 0)
233error("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)
240error("No match to TOP|Address search hit TOP without matching pattern");
241 addr = dol;
242 }
243 }
244 if (execute(0, addr)) {
13c5231e
KB
245 if (inputline && c == '?') {
246 inputline = &linebuf[LBSIZE];
ea87719e
MH
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 '\'':
5a6c967e 265 c = markreg(ex_getchar());
ea87719e
MH
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 */
302setCNL()
303{
304
305 setcount();
306 newline();
307}
308
309setNAEOL()
310{
311
312 setnoaddr();
313 eol();
314}