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