xref: /csrg-svn/contrib/ed/address.c (revision 60663)
157676Sbostic /*-
2*60663Sbostic  * Copyright (c) 1992, 1993
3*60663Sbostic  *	The Regents of the University of California.  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*60663Sbostic static char sccsid[] = "@(#)address.c	8.1 (Berkeley) 05/31/93";
1357676Sbostic #endif /* not lint */
1457676Sbostic 
1557710Sbostic #include <sys/types.h>
1657710Sbostic 
1757710Sbostic #include <regex.h>
1857710Sbostic #include <setjmp.h>
1957710Sbostic #include <stdio.h>
2057710Sbostic #include <string.h>
2157710Sbostic 
2258315Sbostic #ifdef DBI
2358315Sbostic #include <db.h>
2458315Sbostic #endif
2558315Sbostic 
2657676Sbostic #include "ed.h"
2757710Sbostic #include "extern.h"
2857676Sbostic 
2957676Sbostic /*
3057676Sbostic  * Make sure that address one comes before address two in the buffer
3157676Sbostic  */
3257676Sbostic 
3357676Sbostic int
address_check(one,two)3457676Sbostic address_check(one, two)
3557710Sbostic 	LINE *one, *two;
3657676Sbostic {
3757710Sbostic 	LINE   *l_cl;
3857676Sbostic 
3957710Sbostic 	for (l_cl = one; l_cl != NULL; l_cl = l_cl->below)
4057710Sbostic 		if (l_cl == two)
4157710Sbostic 			return (0);
4257710Sbostic 	return (-1);
4357710Sbostic }
4457676Sbostic 
4557676Sbostic /*
4657676Sbostic  * convert a number given by the user into variable
4757676Sbostic  */
4857676Sbostic int
dig_num_conv(inputt,errnum)4957676Sbostic dig_num_conv(inputt, errnum)
5057710Sbostic 	FILE *inputt;
5157710Sbostic 	int *errnum;
5257676Sbostic {
5357710Sbostic 	int l_line = 0;
5457676Sbostic 
5557710Sbostic 	l_line = ss - '0';
5657710Sbostic 	while ((ss = getc(inputt)) != EOF) {
5757710Sbostic 		if ((ss < '0') || (ss > '9'))
5857710Sbostic 			break;
5957710Sbostic 		l_line = (l_line * 10) + (ss - '0');
6057710Sbostic 	}
6157710Sbostic 	*errnum = 0;
6257710Sbostic 	ungetc(ss, inputt);
6357710Sbostic 	return (l_line);
6457676Sbostic }
6557676Sbostic 
6657676Sbostic /*
6757676Sbostic  * Convert a numeric address into a LINE address (more useful for ed)
6857676Sbostic  */
6957710Sbostic LINE *
num_to_address(num,errnum)7057710Sbostic num_to_address(num, errnum)
7157710Sbostic 	int num, *errnum;
7257676Sbostic {
7357710Sbostic 	int l_line = 1;
7457710Sbostic 	LINE *temp1;
7557676Sbostic 
7658348Sbostic 	if (top) {
7758348Sbostic 		for (temp1 = top; temp1->below != NULL; temp1 = temp1->below) {
7858348Sbostic 			/* find the matching line number in the buffer */
7958348Sbostic 			if (l_line >= num)
8058348Sbostic 				break;
8158348Sbostic 			l_line++;
8258348Sbostic 		}
8357710Sbostic 	}
8457676Sbostic 
8558348Sbostic 	if ((l_line < num) || (!top)) {
8657710Sbostic 		/* the number was wacko */
8757710Sbostic 		*errnum = -1;
8857710Sbostic 		strcpy(help_msg, "bad line number");
8957710Sbostic 		return (NULL);
9057710Sbostic 	} else
9157710Sbostic 		if (num == 0)	/* special case */
9257710Sbostic 			return (NULL);
9357710Sbostic 		else
9457710Sbostic 			return (temp1);
9557710Sbostic }
9657676Sbostic 
9757676Sbostic 
9857676Sbostic /*
9957710Sbostic  * Figure out what the addresses are spec'd by the user.  Note for backward
10057710Sbostic  * compatability the most recent addresses in a chain are used by the commands
10157710Sbostic  * (i.e. 3,5,17,22d deletes lines 17 to 22 inclusive. The two leading addresses
10257710Sbostic  * 3 and 5 are dropped as cmd_loop rolls through here the extra times).  Hence,
10357710Sbostic  * the code may look a little wierder than it should.  The variable l_order is
10457710Sbostic  * used to control for legally constructed addresses as described in ed(1).  So,
10558315Sbostic  * "$-21" and "/RE/++++" are legal but /RE/-$ is not.
10657676Sbostic  */
10757710Sbostic LINE *
address_conv(tempp,inputt,errnum)10857710Sbostic address_conv(tempp, inputt, errnum)
10957710Sbostic 	LINE *tempp;
11057710Sbostic 	FILE *inputt;
11157710Sbostic 	int *errnum;
11257676Sbostic {
11357710Sbostic 	LINE *l_dot;
11457710Sbostic 	int l_last, l_cnt, l_num, l_order, l_pass_flag;
11557676Sbostic 
11657710Sbostic 	l_dot = NULL;
11757710Sbostic 	l_order = 0;
11857710Sbostic 	l_pass_flag = 0;
11957710Sbostic 	address_flag = 0;
12057676Sbostic 
12157710Sbostic 	l_last = ss;
12257710Sbostic 	if (tempp == NULL)
12357710Sbostic 		l_dot = current;
12457710Sbostic 	else
12557710Sbostic 		l_dot = tempp;
12657676Sbostic 
12757710Sbostic 	while ((ss = getc(inputt)) != EOF) {
12857710Sbostic 		switch (ss) {
12957710Sbostic 		case '0': case '1': case '2': case '3': case '4':
13057710Sbostic 		case '5': case '6': case '7': case '8': case '9':
13157710Sbostic 			if (l_order == (l_order | 4)) {
13257710Sbostic 				*errnum = -1;
13357710Sbostic 				strcpy(help_msg, "malformed address");
13457710Sbostic 				return (NULL);
13557710Sbostic 			}
13657710Sbostic 			l_order |= 1;
13757710Sbostic 			l_num = dig_num_conv(inputt, errnum);
13857710Sbostic 			/*
13957710Sbostic 			 * " " (<space>), historically, gets counted as a "+"
14057710Sbostic 			 * if it's between two 'addable' address forms. Goofy,
14157710Sbostic 			 * but it makes it compatible for those strange old
14257710Sbostic 			 * scripts (or users?)
14357710Sbostic 			 */
14457710Sbostic 			if ((l_last == '+') ||
14557710Sbostic 			    ((l_last == ' ') && l_pass_flag)) {
14657710Sbostic 				if (l_last == ' ')
14757710Sbostic 					l_num++;
14857710Sbostic 				for (l_cnt = 0; l_cnt < l_num - 1; l_cnt++) {
14957710Sbostic 					if (l_dot == NULL) {
15057710Sbostic 						*errnum = -1;
15157710Sbostic 						return (NULL);
15257710Sbostic 					}
15357710Sbostic 					l_dot = l_dot->below;
15457710Sbostic 				}
15557710Sbostic 			} else
15657710Sbostic 				if ((l_last == '-') || (l_last == '^')) {
15757710Sbostic 					for (l_cnt = l_num - 1;
15857710Sbostic 					    l_cnt > 0; l_cnt--) {
15957710Sbostic 						if (l_dot == NULL) {
16057710Sbostic 							*errnum = -1;
16157710Sbostic 							return (NULL);
16257710Sbostic 						}
16357710Sbostic 						l_dot = l_dot->above;
16457710Sbostic 					}
16557710Sbostic 				} else
16657710Sbostic 					l_dot = num_to_address(l_num, errnum);
16757710Sbostic 			if (*errnum < 0)
16857710Sbostic 				return (NULL);
16957710Sbostic 			l_pass_flag = 1;
17057710Sbostic 			break;
17157710Sbostic 		case '\'':
17257710Sbostic 		case '$':
17357710Sbostic 		case '?':
17457710Sbostic 		case '/':
17557710Sbostic 		case '.':
17657710Sbostic 			if (l_order != 0) {
17757710Sbostic 				*errnum = -1;
17857710Sbostic 				strcpy(help_msg, "malformed address");
17957710Sbostic 				return (NULL);
18057710Sbostic 			}
18157710Sbostic 			l_order = 4;
18257710Sbostic 			switch (ss) {
18357710Sbostic 			case '\'':
18458315Sbostic 				l_dot = get_mark(inputt, errnum);
18557710Sbostic 				break;
18657710Sbostic 			case '$':
18757710Sbostic 				l_dot = bottom;	/* set to bottom */
18857710Sbostic 				break;
18957710Sbostic 			case '?':
19057710Sbostic 				l_dot = search_r(inputt, errnum);
19157710Sbostic 				break;
19257710Sbostic 			case '/':
19357710Sbostic 				l_dot = search(inputt, errnum);
19457710Sbostic 				break;
19557710Sbostic 			case '.':
19657710Sbostic 				l_dot = current;
19757710Sbostic 				break;
19857710Sbostic 			}
19957710Sbostic 			break;
20057710Sbostic 		case '-':
20157710Sbostic 		case '^':
20257710Sbostic 		case '+':
20357710Sbostic 			l_order = 2;
20457710Sbostic 			if (ss == '+') {
20557710Sbostic 				l_dot = l_dot->below;
20657710Sbostic 				if (l_dot == NULL) {
20757710Sbostic 					strcpy(help_msg, "at end of buffer");
20857710Sbostic 					*errnum = -1;
20957710Sbostic 					return (NULL);
21057710Sbostic 				}
21157710Sbostic 			} else {
21257710Sbostic 				l_dot = l_dot->above;
21357710Sbostic 				if (l_dot == NULL) {
21457710Sbostic 					strcpy(help_msg, "at top of buffer");
21557710Sbostic 					*errnum = -1;
21657710Sbostic 					return (NULL);
21757710Sbostic 				}
21857710Sbostic 			}
21957710Sbostic 			break;
22057710Sbostic 		case ' ':
22157710Sbostic 			break;	/* ignore here, but see comment above */
22257710Sbostic 		default:
22357710Sbostic 			ungetc(ss, inputt);
22457710Sbostic 			return (l_dot);
22557710Sbostic 			break;
22657710Sbostic 		}
22757676Sbostic 
22857710Sbostic 		if (*errnum < 0)
22957710Sbostic 			break;	/* from the while-loop */
23057710Sbostic 		l_last = ss;
23157710Sbostic 	}
23257676Sbostic 
23357710Sbostic 	if (ss == EOF)
23457710Sbostic 		return (l_dot);
23557710Sbostic 	*errnum = -1;
23657710Sbostic 	return (NULL);
23757710Sbostic }
238