xref: /original-bsd/usr.bin/ex/ex_addr.c (revision e049d966)
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