Commit | Line | Data |
---|---|---|
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 | 12 | static 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 | ||
33 | int | |
34 | address_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 |
48 | int |
49 | dig_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 |
69 | LINE * |
70 | num_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 |
107 | LINE * |
108 | address_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 | } |