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:
20: static bool bigmove;
21:
22: /*
23: * Set up addr1 and addr2 for commands whose default address is dot.
24: */
25: setdot()
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: */
37: setdot1()
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: */
54: setcount()
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: */
77: getnum()
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: */
90: setall()
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: */
110: setnoaddr()
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: */
125: line *
126: address(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;
201: doques:
202:
203: do {
204: last = loc1;
205: if (!execute(1))
206: break;
207: } while (loc1 < inline);
208: loc1 = last;
209: break;
210: }
211: }
212: nope:
213: for (;;) {
214: if (c == '/') {
215: addr++;
216: if (addr > dol) {
217: if (value(WRAPSCAN) == 0)
218: error("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)
225: error("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: */
287: setCNL()
288: {
289:
290: setcount();
291: newline();
292: }
293:
294: setNAEOL()
295: {
296:
297: setnoaddr();
298: eol();
299: }
Defined functions
setdot
defined in line
25; used 13 times
Defined variables