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