improve exit status handling for program map code
[unix-history] / usr / src / contrib / ed / address.c
CommitLineData
23dd5004 1/*-
ba5e8546
KB
2 * Copyright (c) 1992, 1993
3 * The Regents of the University of California. All rights reserved.
23dd5004
KB
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rodney Ruddock of the University of Guelph.
7 *
8 * %sccs.include.redist.c%
9 */
10
11#ifndef lint
ba5e8546 12static char sccsid[] = "@(#)address.c 8.1 (Berkeley) %G%";
23dd5004
KB
13#endif /* not lint */
14
ecbf4ad0
KB
15#include <sys/types.h>
16
ecbf4ad0
KB
17#include <regex.h>
18#include <setjmp.h>
19#include <stdio.h>
20#include <string.h>
21
e692f66f
KB
22#ifdef DBI
23#include <db.h>
24#endif
25
23dd5004 26#include "ed.h"
ecbf4ad0 27#include "extern.h"
23dd5004
KB
28
29/*
30 * Make sure that address one comes before address two in the buffer
31 */
32
33int
34address_check(one, two)
ecbf4ad0 35 LINE *one, *two;
23dd5004 36{
ecbf4ad0 37 LINE *l_cl;
23dd5004 38
ecbf4ad0
KB
39 for (l_cl = one; l_cl != NULL; l_cl = l_cl->below)
40 if (l_cl == two)
41 return (0);
42 return (-1);
43}
23dd5004
KB
44
45/*
46 * convert a number given by the user into variable
47 */
23dd5004
KB
48int
49dig_num_conv(inputt, errnum)
ecbf4ad0
KB
50 FILE *inputt;
51 int *errnum;
23dd5004 52{
ecbf4ad0
KB
53 int l_line = 0;
54
55 l_line = ss - '0';
56 while ((ss = getc(inputt)) != EOF) {
57 if ((ss < '0') || (ss > '9'))
58 break;
59 l_line = (l_line * 10) + (ss - '0');
60 }
61 *errnum = 0;
62 ungetc(ss, inputt);
63 return (l_line);
23dd5004
KB
64}
65
66/*
67 * Convert a numeric address into a LINE address (more useful for ed)
68 */
ecbf4ad0
KB
69LINE *
70num_to_address(num, errnum)
71 int num, *errnum;
23dd5004 72{
ecbf4ad0
KB
73 int l_line = 1;
74 LINE *temp1;
75
0644173e
KB
76 if (top) {
77 for (temp1 = top; temp1->below != NULL; temp1 = temp1->below) {
78 /* find the matching line number in the buffer */
79 if (l_line >= num)
80 break;
81 l_line++;
82 }
ecbf4ad0
KB
83 }
84
0644173e 85 if ((l_line < num) || (!top)) {
ecbf4ad0
KB
86 /* the number was wacko */
87 *errnum = -1;
88 strcpy(help_msg, "bad line number");
89 return (NULL);
90 } else
91 if (num == 0) /* special case */
92 return (NULL);
93 else
94 return (temp1);
95}
23dd5004
KB
96
97
98/*
ecbf4ad0
KB
99 * Figure out what the addresses are spec'd by the user. Note for backward
100 * compatability the most recent addresses in a chain are used by the commands
101 * (i.e. 3,5,17,22d deletes lines 17 to 22 inclusive. The two leading addresses
102 * 3 and 5 are dropped as cmd_loop rolls through here the extra times). Hence,
103 * the code may look a little wierder than it should. The variable l_order is
104 * used to control for legally constructed addresses as described in ed(1). So,
e692f66f 105 * "$-21" and "/RE/++++" are legal but /RE/-$ is not.
23dd5004 106 */
ecbf4ad0
KB
107LINE *
108address_conv(tempp, inputt, errnum)
109 LINE *tempp;
110 FILE *inputt;
111 int *errnum;
23dd5004 112{
ecbf4ad0
KB
113 LINE *l_dot;
114 int l_last, l_cnt, l_num, l_order, l_pass_flag;
115
116 l_dot = NULL;
117 l_order = 0;
118 l_pass_flag = 0;
119 address_flag = 0;
120
121 l_last = ss;
122 if (tempp == NULL)
123 l_dot = current;
124 else
125 l_dot = tempp;
126
127 while ((ss = getc(inputt)) != EOF) {
128 switch (ss) {
129 case '0': case '1': case '2': case '3': case '4':
130 case '5': case '6': case '7': case '8': case '9':
131 if (l_order == (l_order | 4)) {
132 *errnum = -1;
133 strcpy(help_msg, "malformed address");
134 return (NULL);
135 }
136 l_order |= 1;
137 l_num = dig_num_conv(inputt, errnum);
138 /*
139 * " " (<space>), historically, gets counted as a "+"
140 * if it's between two 'addable' address forms. Goofy,
141 * but it makes it compatible for those strange old
142 * scripts (or users?)
143 */
144 if ((l_last == '+') ||
145 ((l_last == ' ') && l_pass_flag)) {
146 if (l_last == ' ')
147 l_num++;
148 for (l_cnt = 0; l_cnt < l_num - 1; l_cnt++) {
149 if (l_dot == NULL) {
150 *errnum = -1;
151 return (NULL);
152 }
153 l_dot = l_dot->below;
154 }
155 } else
156 if ((l_last == '-') || (l_last == '^')) {
157 for (l_cnt = l_num - 1;
158 l_cnt > 0; l_cnt--) {
159 if (l_dot == NULL) {
160 *errnum = -1;
161 return (NULL);
162 }
163 l_dot = l_dot->above;
164 }
165 } else
166 l_dot = num_to_address(l_num, errnum);
167 if (*errnum < 0)
168 return (NULL);
169 l_pass_flag = 1;
170 break;
171 case '\'':
172 case '$':
173 case '?':
174 case '/':
175 case '.':
176 if (l_order != 0) {
177 *errnum = -1;
178 strcpy(help_msg, "malformed address");
179 return (NULL);
180 }
181 l_order = 4;
182 switch (ss) {
183 case '\'':
e692f66f 184 l_dot = get_mark(inputt, errnum);
ecbf4ad0
KB
185 break;
186 case '$':
187 l_dot = bottom; /* set to bottom */
188 break;
189 case '?':
190 l_dot = search_r(inputt, errnum);
191 break;
192 case '/':
193 l_dot = search(inputt, errnum);
194 break;
195 case '.':
196 l_dot = current;
197 break;
198 }
199 break;
200 case '-':
201 case '^':
202 case '+':
203 l_order = 2;
204 if (ss == '+') {
205 l_dot = l_dot->below;
206 if (l_dot == NULL) {
207 strcpy(help_msg, "at end of buffer");
208 *errnum = -1;
209 return (NULL);
210 }
211 } else {
212 l_dot = l_dot->above;
213 if (l_dot == NULL) {
214 strcpy(help_msg, "at top of buffer");
215 *errnum = -1;
216 return (NULL);
217 }
218 }
219 break;
220 case ' ':
221 break; /* ignore here, but see comment above */
222 default:
223 ungetc(ss, inputt);
224 return (l_dot);
225 break;
226 }
227
228 if (*errnum < 0)
229 break; /* from the while-loop */
230 l_last = ss;
231 }
232
233 if (ss == EOF)
234 return (l_dot);
235 *errnum = -1;
236 return (NULL);
237}