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