xref: /csrg-svn/contrib/ed/address.c (revision 57710)
157676Sbostic /*-
257676Sbostic  * Copyright (c) 1992 The Regents of the University of California.
357676Sbostic  * All rights reserved.
457676Sbostic  *
557676Sbostic  * This code is derived from software contributed to Berkeley by
657676Sbostic  * Rodney Ruddock of the University of Guelph.
757676Sbostic  *
857676Sbostic  * %sccs.include.redist.c%
957676Sbostic  */
1057676Sbostic 
1157676Sbostic #ifndef lint
12*57710Sbostic static char sccsid[] = "@(#)address.c	5.2 (Berkeley) 01/23/93";
1357676Sbostic #endif /* not lint */
1457676Sbostic 
15*57710Sbostic #include <sys/types.h>
16*57710Sbostic 
17*57710Sbostic #include <db.h>
18*57710Sbostic #include <regex.h>
19*57710Sbostic #include <setjmp.h>
20*57710Sbostic #include <stdio.h>
21*57710Sbostic #include <string.h>
22*57710Sbostic 
2357676Sbostic #include "ed.h"
24*57710Sbostic #include "extern.h"
2557676Sbostic 
2657676Sbostic /*
2757676Sbostic  * Make sure that address one comes before address two in the buffer
2857676Sbostic  */
2957676Sbostic 
3057676Sbostic int
3157676Sbostic address_check(one, two)
32*57710Sbostic 	LINE *one, *two;
3357676Sbostic {
34*57710Sbostic 	LINE   *l_cl;
3557676Sbostic 
36*57710Sbostic 	for (l_cl = one; l_cl != NULL; l_cl = l_cl->below)
37*57710Sbostic 		if (l_cl == two)
38*57710Sbostic 			return (0);
39*57710Sbostic 	return (-1);
40*57710Sbostic }
4157676Sbostic 
4257676Sbostic /*
4357676Sbostic  * convert a number given by the user into variable
4457676Sbostic  */
4557676Sbostic int
4657676Sbostic dig_num_conv(inputt, errnum)
47*57710Sbostic 	FILE *inputt;
48*57710Sbostic 	int *errnum;
4957676Sbostic {
50*57710Sbostic 	int l_line = 0;
5157676Sbostic 
52*57710Sbostic 	l_line = ss - '0';
53*57710Sbostic 	while ((ss = getc(inputt)) != EOF) {
54*57710Sbostic 		if ((ss < '0') || (ss > '9'))
55*57710Sbostic 			break;
56*57710Sbostic 		l_line = (l_line * 10) + (ss - '0');
57*57710Sbostic 	}
58*57710Sbostic 	*errnum = 0;
59*57710Sbostic 	ungetc(ss, inputt);
60*57710Sbostic 	return (l_line);
6157676Sbostic }
6257676Sbostic 
6357676Sbostic /*
6457676Sbostic  * Convert a numeric address into a LINE address (more useful for ed)
6557676Sbostic  */
66*57710Sbostic LINE *
67*57710Sbostic num_to_address(num, errnum)
68*57710Sbostic 	int num, *errnum;
6957676Sbostic {
70*57710Sbostic 	int l_line = 1;
71*57710Sbostic 	LINE *temp1;
7257676Sbostic 
73*57710Sbostic 	for (temp1 = top; temp1->below != NULL; temp1 = temp1->below) {
74*57710Sbostic 		/* find the matching line number in the buffer */
75*57710Sbostic 		if (l_line >= num)
76*57710Sbostic 			break;
77*57710Sbostic 		l_line++;
78*57710Sbostic 	}
7957676Sbostic 
80*57710Sbostic 	if (l_line < num) {
81*57710Sbostic 		/* the number was wacko */
82*57710Sbostic 		*errnum = -1;
83*57710Sbostic 		strcpy(help_msg, "bad line number");
84*57710Sbostic 		return (NULL);
85*57710Sbostic 	} else
86*57710Sbostic 		if (num == 0)	/* special case */
87*57710Sbostic 			return (NULL);
88*57710Sbostic 		else
89*57710Sbostic 			return (temp1);
90*57710Sbostic }
9157676Sbostic 
9257676Sbostic 
9357676Sbostic /*
94*57710Sbostic  * Figure out what the addresses are spec'd by the user.  Note for backward
95*57710Sbostic  * compatability the most recent addresses in a chain are used by the commands
96*57710Sbostic  * (i.e. 3,5,17,22d deletes lines 17 to 22 inclusive. The two leading addresses
97*57710Sbostic  * 3 and 5 are dropped as cmd_loop rolls through here the extra times).  Hence,
98*57710Sbostic  * the code may look a little wierder than it should.  The variable l_order is
99*57710Sbostic  * used to control for legally constructed addresses as described in ed(1).  So,
100*57710Sbostic  * "$-21" and "/RE/++++" are leagal but /RE/-$ is not.
10157676Sbostic  */
102*57710Sbostic LINE *
103*57710Sbostic address_conv(tempp, inputt, errnum)
104*57710Sbostic 	LINE *tempp;
105*57710Sbostic 	FILE *inputt;
106*57710Sbostic 	int *errnum;
10757676Sbostic {
108*57710Sbostic 	LINE *l_dot;
109*57710Sbostic 	int l_last, l_cnt, l_num, l_order, l_pass_flag;
11057676Sbostic 
111*57710Sbostic 	l_dot = NULL;
112*57710Sbostic 	l_order = 0;
113*57710Sbostic 	l_pass_flag = 0;
114*57710Sbostic 	address_flag = 0;
11557676Sbostic 
116*57710Sbostic 	l_last = ss;
117*57710Sbostic 	if (tempp == NULL)
118*57710Sbostic 		l_dot = current;
119*57710Sbostic 	else
120*57710Sbostic 		l_dot = tempp;
12157676Sbostic 
122*57710Sbostic 	while ((ss = getc(inputt)) != EOF) {
123*57710Sbostic 		switch (ss) {
124*57710Sbostic 		case '0': case '1': case '2': case '3': case '4':
125*57710Sbostic 		case '5': case '6': case '7': case '8': case '9':
126*57710Sbostic 			if (l_order == (l_order | 4)) {
127*57710Sbostic 				*errnum = -1;
128*57710Sbostic 				strcpy(help_msg, "malformed address");
129*57710Sbostic 				return (NULL);
130*57710Sbostic 			}
131*57710Sbostic 			l_order |= 1;
132*57710Sbostic 			l_num = dig_num_conv(inputt, errnum);
133*57710Sbostic 			/*
134*57710Sbostic 			 * " " (<space>), historically, gets counted as a "+"
135*57710Sbostic 			 * if it's between two 'addable' address forms. Goofy,
136*57710Sbostic 			 * but it makes it compatible for those strange old
137*57710Sbostic 			 * scripts (or users?)
138*57710Sbostic 			 */
139*57710Sbostic 			if ((l_last == '+') ||
140*57710Sbostic 			    ((l_last == ' ') && l_pass_flag)) {
141*57710Sbostic 				if (l_last == ' ')
142*57710Sbostic 					l_num++;
143*57710Sbostic 				for (l_cnt = 0; l_cnt < l_num - 1; l_cnt++) {
144*57710Sbostic 					if (l_dot == NULL) {
145*57710Sbostic 						*errnum = -1;
146*57710Sbostic 						return (NULL);
147*57710Sbostic 					}
148*57710Sbostic 					l_dot = l_dot->below;
149*57710Sbostic 				}
150*57710Sbostic 			} else
151*57710Sbostic 				if ((l_last == '-') || (l_last == '^')) {
152*57710Sbostic 					for (l_cnt = l_num - 1;
153*57710Sbostic 					    l_cnt > 0; l_cnt--) {
154*57710Sbostic 						if (l_dot == NULL) {
155*57710Sbostic 							*errnum = -1;
156*57710Sbostic 							return (NULL);
157*57710Sbostic 						}
158*57710Sbostic 						l_dot = l_dot->above;
159*57710Sbostic 					}
160*57710Sbostic 				} else
161*57710Sbostic 					l_dot = num_to_address(l_num, errnum);
162*57710Sbostic 			if (*errnum < 0)
163*57710Sbostic 				return (NULL);
164*57710Sbostic 			l_pass_flag = 1;
165*57710Sbostic 			break;
166*57710Sbostic 		case '\'':
167*57710Sbostic 		case '$':
168*57710Sbostic 		case '?':
169*57710Sbostic 		case '/':
170*57710Sbostic 		case '.':
171*57710Sbostic 			if (l_order != 0) {
172*57710Sbostic 				*errnum = -1;
173*57710Sbostic 				strcpy(help_msg, "malformed address");
174*57710Sbostic 				return (NULL);
175*57710Sbostic 			}
176*57710Sbostic 			l_order = 4;
177*57710Sbostic 			switch (ss) {
178*57710Sbostic 			case '\'':
179*57710Sbostic 				l_dot = get_mark(errnum);
180*57710Sbostic 				break;
181*57710Sbostic 			case '$':
182*57710Sbostic 				l_dot = bottom;	/* set to bottom */
183*57710Sbostic 				break;
184*57710Sbostic 			case '?':
185*57710Sbostic 				l_dot = search_r(inputt, errnum);
186*57710Sbostic 				break;
187*57710Sbostic 			case '/':
188*57710Sbostic 				l_dot = search(inputt, errnum);
189*57710Sbostic 				break;
190*57710Sbostic 			case '.':
191*57710Sbostic 				l_dot = current;
192*57710Sbostic 				break;
193*57710Sbostic 			}
194*57710Sbostic 			break;
195*57710Sbostic 		case '-':
196*57710Sbostic 		case '^':
197*57710Sbostic 		case '+':
198*57710Sbostic 			l_order = 2;
199*57710Sbostic 			if (ss == '+') {
200*57710Sbostic 				l_dot = l_dot->below;
201*57710Sbostic 				if (l_dot == NULL) {
202*57710Sbostic 					strcpy(help_msg, "at end of buffer");
203*57710Sbostic 					*errnum = -1;
204*57710Sbostic 					return (NULL);
205*57710Sbostic 				}
206*57710Sbostic 			} else {
207*57710Sbostic 				l_dot = l_dot->above;
208*57710Sbostic 				if (l_dot == NULL) {
209*57710Sbostic 					strcpy(help_msg, "at top of buffer");
210*57710Sbostic 					*errnum = -1;
211*57710Sbostic 					return (NULL);
212*57710Sbostic 				}
213*57710Sbostic 			}
214*57710Sbostic 			break;
215*57710Sbostic 		case ' ':
216*57710Sbostic 			break;	/* ignore here, but see comment above */
217*57710Sbostic 		default:
218*57710Sbostic 			ungetc(ss, inputt);
219*57710Sbostic 			return (l_dot);
220*57710Sbostic 			break;
221*57710Sbostic 		}
22257676Sbostic 
223*57710Sbostic 		if (*errnum < 0)
224*57710Sbostic 			break;	/* from the while-loop */
225*57710Sbostic 		l_last = ss;
226*57710Sbostic 	}
22757676Sbostic 
228*57710Sbostic 	if (ss == EOF)
229*57710Sbostic 		return (l_dot);
230*57710Sbostic 	*errnum = -1;
231*57710Sbostic 	return (NULL);
232*57710Sbostic }
233