1cd8169f0Sbostic /*-
2*e049d966Sbostic * Copyright (c) 1980, 1993
3*e049d966Sbostic * The Regents of the University of California. All rights reserved.
4cd8169f0Sbostic *
5cd8169f0Sbostic * %sccs.include.proprietary.c%
6c3a35c03Sdist */
7c3a35c03Sdist
8c3a35c03Sdist #ifndef lint
9*e049d966Sbostic static char sccsid[] = "@(#)ex_addr.c 8.1 (Berkeley) 06/09/93";
10cd8169f0Sbostic #endif /* not lint */
11c3a35c03Sdist
12d0cad150Smark #include "ex.h"
13d0cad150Smark #include "ex_re.h"
14d0cad150Smark
15d0cad150Smark /*
16d0cad150Smark * Routines for address parsing and assignment and checking of address bounds
17d0cad150Smark * in command mode. The routine address is called from ex_cmds.c
18d0cad150Smark * to parse each component of a command (terminated by , ; or the beginning
19d0cad150Smark * of the command itself. It is also called by the scanning routine
20d0cad150Smark * in ex_voperate.c from within open/visual.
21d0cad150Smark *
22d0cad150Smark * Other routines here manipulate the externals addr1 and addr2.
23d0cad150Smark * These are the first and last lines for the current command.
24d0cad150Smark *
25d0cad150Smark * The variable bigmove remembers whether a non-local glitch of . was
26d0cad150Smark * involved in an address expression, so we can set the previous context
27d0cad150Smark * mark '' when such a motion occurs.
28d0cad150Smark */
29d0cad150Smark
30d0cad150Smark static bool bigmove;
31d0cad150Smark
32d0cad150Smark /*
33d0cad150Smark * Set up addr1 and addr2 for commands whose default address is dot.
34d0cad150Smark */
setdot()35d0cad150Smark setdot()
36d0cad150Smark {
37d0cad150Smark
38d0cad150Smark setdot1();
39d0cad150Smark if (bigmove)
40d0cad150Smark markDOT();
41d0cad150Smark }
42d0cad150Smark
43d0cad150Smark /*
44d0cad150Smark * Call setdot1 to set up default addresses without ever
45d0cad150Smark * setting the previous context mark.
46d0cad150Smark */
setdot1()47d0cad150Smark setdot1()
48d0cad150Smark {
49d0cad150Smark
50d0cad150Smark if (addr2 == 0)
51d0cad150Smark addr1 = addr2 = dot;
52d0cad150Smark if (addr1 > addr2) {
53d0cad150Smark notempty();
54d0cad150Smark error("Addr1 > addr2|First address exceeds second");
55d0cad150Smark }
56d0cad150Smark }
57d0cad150Smark
58d0cad150Smark /*
59d0cad150Smark * Ex allows you to say
60d0cad150Smark * delete 5
61d0cad150Smark * to delete 5 lines, etc.
62d0cad150Smark * Such nonsense is implemented by setcount.
63d0cad150Smark */
setcount()64d0cad150Smark setcount()
65d0cad150Smark {
66d0cad150Smark register int cnt;
67d0cad150Smark
68d0cad150Smark pastwh();
69d0cad150Smark if (!isdigit(peekchar())) {
70d0cad150Smark setdot();
71d0cad150Smark return;
72d0cad150Smark }
73d0cad150Smark addr1 = addr2;
74d0cad150Smark setdot();
75d0cad150Smark cnt = getnum();
76d0cad150Smark if (cnt <= 0)
77d0cad150Smark error("Bad count|Nonzero count required");
78d0cad150Smark addr2 += cnt - 1;
79d0cad150Smark if (addr2 > dol)
80d0cad150Smark addr2 = dol;
81d0cad150Smark nonzero();
82d0cad150Smark }
83d0cad150Smark
84d0cad150Smark /*
85d0cad150Smark * Parse a number out of the command input stream.
86d0cad150Smark */
getnum()87d0cad150Smark getnum()
88d0cad150Smark {
89d0cad150Smark register int cnt;
90d0cad150Smark
91d0cad150Smark for (cnt = 0; isdigit(peekcd());)
92c0a5300eSconrad cnt = cnt * 10 + ex_getchar() - '0';
93d0cad150Smark return (cnt);
94d0cad150Smark }
95d0cad150Smark
96d0cad150Smark /*
97d0cad150Smark * Set the default addresses for commands which use the whole
98d0cad150Smark * buffer as default, notably write.
99d0cad150Smark */
setall()100d0cad150Smark setall()
101d0cad150Smark {
102d0cad150Smark
103d0cad150Smark if (addr2 == 0) {
104d0cad150Smark addr1 = one;
105d0cad150Smark addr2 = dol;
106d0cad150Smark if (dol == zero) {
107d0cad150Smark dot = zero;
108d0cad150Smark return;
109d0cad150Smark }
110d0cad150Smark }
111d0cad150Smark /*
112d0cad150Smark * Don't want to set previous context mark so use setdot1().
113d0cad150Smark */
114d0cad150Smark setdot1();
115d0cad150Smark }
116d0cad150Smark
117d0cad150Smark /*
118d0cad150Smark * No address allowed on, e.g. the file command.
119d0cad150Smark */
setnoaddr()120d0cad150Smark setnoaddr()
121d0cad150Smark {
122d0cad150Smark
123d0cad150Smark if (addr2 != 0)
124d0cad150Smark error("No address allowed@on this command");
125d0cad150Smark }
126d0cad150Smark
127d0cad150Smark /*
128d0cad150Smark * Parse an address.
129d0cad150Smark * Just about any sequence of address characters is legal.
130d0cad150Smark *
131d0cad150Smark * If you are tricky you can use this routine and the = command
132d0cad150Smark * to do simple addition and subtraction of cardinals less
133d0cad150Smark * than the number of lines in the file.
134d0cad150Smark */
135d0cad150Smark line *
address(inputline)136b86c17a7Sbostic address(inputline)
137b86c17a7Sbostic char *inputline;
138d0cad150Smark {
139d0cad150Smark register line *addr;
140d0cad150Smark register int offset, c;
141d0cad150Smark short lastsign;
142d0cad150Smark
143d0cad150Smark bigmove = 0;
144d0cad150Smark lastsign = 0;
145d0cad150Smark offset = 0;
146d0cad150Smark addr = 0;
147d0cad150Smark for (;;) {
148d0cad150Smark if (isdigit(peekcd())) {
149d0cad150Smark if (addr == 0) {
150d0cad150Smark addr = zero;
151d0cad150Smark bigmove = 1;
152d0cad150Smark }
153d0cad150Smark loc1 = 0;
154d0cad150Smark addr += offset;
155d0cad150Smark offset = getnum();
156d0cad150Smark if (lastsign >= 0)
157d0cad150Smark addr += offset;
158d0cad150Smark else
159d0cad150Smark addr -= offset;
160d0cad150Smark lastsign = 0;
161d0cad150Smark offset = 0;
162d0cad150Smark }
163d0cad150Smark switch (c = getcd()) {
164d0cad150Smark
165d0cad150Smark case '?':
166d0cad150Smark case '/':
167d0cad150Smark case '$':
168d0cad150Smark case '\'':
169d0cad150Smark case '\\':
170d0cad150Smark bigmove++;
171d0cad150Smark case '.':
172d0cad150Smark if (addr || offset)
173d0cad150Smark error("Badly formed address");
174d0cad150Smark }
175d0cad150Smark offset += lastsign;
176d0cad150Smark lastsign = 0;
177d0cad150Smark switch (c) {
178d0cad150Smark
179d0cad150Smark case ' ':
180d0cad150Smark case '\t':
181d0cad150Smark continue;
182d0cad150Smark
183d0cad150Smark case '+':
184d0cad150Smark lastsign = 1;
185d0cad150Smark if (addr == 0)
186d0cad150Smark addr = dot;
187d0cad150Smark continue;
188d0cad150Smark
189d0cad150Smark case '^':
190d0cad150Smark case '-':
191d0cad150Smark lastsign = -1;
192d0cad150Smark if (addr == 0)
193d0cad150Smark addr = dot;
194d0cad150Smark continue;
195d0cad150Smark
196d0cad150Smark case '\\':
197d0cad150Smark case '?':
198d0cad150Smark case '/':
199d0cad150Smark c = compile(c, 1);
200d0cad150Smark notempty();
201d0cad150Smark savere(scanre);
202d0cad150Smark addr = dot;
203b86c17a7Sbostic if (inputline && execute(0, dot)) {
204d0cad150Smark if (c == '/') {
205b86c17a7Sbostic while (loc1 <= inputline) {
20633f18e4dSmark if (loc1 == loc2)
20733f18e4dSmark loc2++;
208d0cad150Smark if (!execute(1))
209d0cad150Smark goto nope;
21025f8d52cSmark }
21125f8d52cSmark break;
212b86c17a7Sbostic } else if (loc1 < inputline) {
21325f8d52cSmark char *last;
21425f8d52cSmark doques:
21525f8d52cSmark
21625f8d52cSmark do {
21725f8d52cSmark last = loc1;
21825f8d52cSmark if (loc1 == loc2)
21925f8d52cSmark loc2++;
22025f8d52cSmark if (!execute(1))
22125f8d52cSmark break;
222b86c17a7Sbostic } while (loc1 < inputline);
22325f8d52cSmark loc1 = last;
22425f8d52cSmark break;
22525f8d52cSmark }
22625f8d52cSmark }
22725f8d52cSmark nope:
22825f8d52cSmark for (;;) {
22925f8d52cSmark if (c == '/') {
23025f8d52cSmark addr++;
23125f8d52cSmark if (addr > dol) {
23225f8d52cSmark if (value(WRAPSCAN) == 0)
23325f8d52cSmark error("No match to BOTTOM|Address search hit BOTTOM without matching pattern");
23425f8d52cSmark addr = zero;
23525f8d52cSmark }
23625f8d52cSmark } else {
23725f8d52cSmark addr--;
23825f8d52cSmark if (addr < zero) {
23925f8d52cSmark if (value(WRAPSCAN) == 0)
24025f8d52cSmark error("No match to TOP|Address search hit TOP without matching pattern");
24125f8d52cSmark addr = dol;
24225f8d52cSmark }
24325f8d52cSmark }
24425f8d52cSmark if (execute(0, addr)) {
245b86c17a7Sbostic if (inputline && c == '?') {
246b86c17a7Sbostic inputline = &linebuf[LBSIZE];
24725f8d52cSmark goto doques;
24825f8d52cSmark }
24925f8d52cSmark break;
25025f8d52cSmark }
25125f8d52cSmark if (addr == dot)
25225f8d52cSmark error("Fail|Pattern not found");
25325f8d52cSmark }
25425f8d52cSmark continue;
25525f8d52cSmark
25625f8d52cSmark case '$':
25725f8d52cSmark addr = dol;
25825f8d52cSmark continue;
25925f8d52cSmark
26025f8d52cSmark case '.':
26125f8d52cSmark addr = dot;
26225f8d52cSmark continue;
26325f8d52cSmark
26425f8d52cSmark case '\'':
265c0a5300eSconrad c = markreg(ex_getchar());
26625f8d52cSmark if (c == 0)
26725f8d52cSmark error("Marks are ' and a-z");
26825f8d52cSmark addr = getmark(c);
26925f8d52cSmark if (addr == 0)
27025f8d52cSmark error("Undefined mark@referenced");
27125f8d52cSmark break;
27225f8d52cSmark
27325f8d52cSmark default:
27425f8d52cSmark ungetchar(c);
27525f8d52cSmark if (offset) {
27625f8d52cSmark if (addr == 0)
27725f8d52cSmark addr = dot;
27825f8d52cSmark addr += offset;
27925f8d52cSmark loc1 = 0;
28025f8d52cSmark }
28125f8d52cSmark if (addr == 0) {
28225f8d52cSmark bigmove = 0;
28325f8d52cSmark return (0);
28425f8d52cSmark }
28525f8d52cSmark if (addr != zero)
28625f8d52cSmark notempty();
28725f8d52cSmark addr += lastsign;
28825f8d52cSmark if (addr < zero)
28925f8d52cSmark error("Negative address@- first buffer line is 1");
29025f8d52cSmark if (addr > dol)
29125f8d52cSmark error("Not that many lines@in buffer");
29225f8d52cSmark return (addr);
29325f8d52cSmark }
29425f8d52cSmark }
29525f8d52cSmark }
29625f8d52cSmark
29725f8d52cSmark /*
29825f8d52cSmark * Abbreviations to make code smaller
29925f8d52cSmark * Left over from squashing ex version 1.1 into
30025f8d52cSmark * 11/34's and 11/40's.
30125f8d52cSmark */
setCNL()30225f8d52cSmark setCNL()
30325f8d52cSmark {
30425f8d52cSmark
30525f8d52cSmark setcount();
30625f8d52cSmark newline();
30725f8d52cSmark }
30825f8d52cSmark
setNAEOL()30925f8d52cSmark setNAEOL()
31025f8d52cSmark {
31125f8d52cSmark
31225f8d52cSmark setnoaddr();
31325f8d52cSmark eol();
31425f8d52cSmark }
315