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