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