1 |
|
|
/* $OpenBSD: ex.c,v 1.21 2016/03/19 00:21:28 mestre Exp $ */ |
2 |
|
|
|
3 |
|
|
/*- |
4 |
|
|
* Copyright (c) 1992, 1993, 1994 |
5 |
|
|
* The Regents of the University of California. All rights reserved. |
6 |
|
|
* Copyright (c) 1992, 1993, 1994, 1995, 1996 |
7 |
|
|
* Keith Bostic. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* See the LICENSE file for redistribution information. |
10 |
|
|
*/ |
11 |
|
|
|
12 |
|
|
#include "config.h" |
13 |
|
|
|
14 |
|
|
#include <sys/types.h> |
15 |
|
|
#include <sys/queue.h> |
16 |
|
|
#include <sys/stat.h> |
17 |
|
|
#include <sys/time.h> |
18 |
|
|
|
19 |
|
|
#include <bitstring.h> |
20 |
|
|
#include <ctype.h> |
21 |
|
|
#include <errno.h> |
22 |
|
|
#include <fcntl.h> |
23 |
|
|
#include <limits.h> |
24 |
|
|
#include <stdio.h> |
25 |
|
|
#include <stdlib.h> |
26 |
|
|
#include <string.h> |
27 |
|
|
#include <unistd.h> |
28 |
|
|
|
29 |
|
|
#include "../common/common.h" |
30 |
|
|
#include "../vi/vi.h" |
31 |
|
|
|
32 |
|
|
#if defined(DEBUG) && defined(COMLOG) |
33 |
|
|
static void ex_comlog(SCR *, EXCMD *); |
34 |
|
|
#endif |
35 |
|
|
static EXCMDLIST const * |
36 |
|
|
ex_comm_search(char *, size_t); |
37 |
|
|
static int ex_discard(SCR *); |
38 |
|
|
static int ex_line(SCR *, EXCMD *, MARK *, int *, int *); |
39 |
|
|
static int ex_load(SCR *); |
40 |
|
|
static void ex_unknown(SCR *, char *, size_t); |
41 |
|
|
|
42 |
|
|
/* |
43 |
|
|
* ex -- |
44 |
|
|
* Main ex loop. |
45 |
|
|
* |
46 |
|
|
* PUBLIC: int ex(SCR **); |
47 |
|
|
*/ |
48 |
|
|
int |
49 |
|
|
ex(SCR **spp) |
50 |
|
|
{ |
51 |
|
|
GS *gp; |
52 |
|
|
MSGS *mp; |
53 |
|
|
SCR *sp; |
54 |
|
|
TEXT *tp; |
55 |
|
|
u_int32_t flags; |
56 |
|
|
|
57 |
|
|
sp = *spp; |
58 |
|
|
gp = sp->gp; |
59 |
|
|
|
60 |
|
|
/* Start the ex screen. */ |
61 |
|
|
if (ex_init(sp)) |
62 |
|
|
return (1); |
63 |
|
|
|
64 |
|
|
/* Flush any saved messages. */ |
65 |
|
|
while ((mp = LIST_FIRST(&gp->msgq)) != NULL) { |
66 |
|
|
gp->scr_msg(sp, mp->mtype, mp->buf, mp->len); |
67 |
|
|
LIST_REMOVE(mp, q); |
68 |
|
|
free(mp->buf); |
69 |
|
|
free(mp); |
70 |
|
|
} |
71 |
|
|
|
72 |
|
|
/* If reading from a file, errors should have name and line info. */ |
73 |
|
|
if (F_ISSET(gp, G_SCRIPTED)) { |
74 |
|
|
gp->excmd.if_lno = 1; |
75 |
|
|
gp->excmd.if_name = "script"; |
76 |
|
|
} |
77 |
|
|
|
78 |
|
|
/* |
79 |
|
|
* !!! |
80 |
|
|
* Initialize the text flags. The beautify edit option historically |
81 |
|
|
* applied to ex command input read from a file. In addition, the |
82 |
|
|
* first time a ^H was discarded from the input, there was a message, |
83 |
|
|
* "^H discarded", that was displayed. We don't bother. |
84 |
|
|
*/ |
85 |
|
|
LF_INIT(TXT_BACKSLASH | TXT_CNTRLD | TXT_CR); |
86 |
|
|
for (;; ++gp->excmd.if_lno) { |
87 |
|
|
/* Display status line and flush. */ |
88 |
|
|
if (F_ISSET(sp, SC_STATUS)) { |
89 |
|
|
if (!F_ISSET(sp, SC_EX_SILENT)) |
90 |
|
|
msgq_status(sp, sp->lno, 0); |
91 |
|
|
F_CLR(sp, SC_STATUS); |
92 |
|
|
} |
93 |
|
|
(void)ex_fflush(sp); |
94 |
|
|
|
95 |
|
|
/* Set the flags the user can reset. */ |
96 |
|
|
if (O_ISSET(sp, O_BEAUTIFY)) |
97 |
|
|
LF_SET(TXT_BEAUTIFY); |
98 |
|
|
if (O_ISSET(sp, O_PROMPT)) |
99 |
|
|
LF_SET(TXT_PROMPT); |
100 |
|
|
|
101 |
|
|
/* Clear any current interrupts, and get a command. */ |
102 |
|
|
CLR_INTERRUPT(sp); |
103 |
|
|
if (ex_txt(sp, &sp->tiq, ':', flags)) |
104 |
|
|
return (1); |
105 |
|
|
if (INTERRUPTED(sp)) { |
106 |
|
|
(void)ex_puts(sp, "\n"); |
107 |
|
|
(void)ex_fflush(sp); |
108 |
|
|
continue; |
109 |
|
|
} |
110 |
|
|
|
111 |
|
|
/* Initialize the command structure. */ |
112 |
|
|
CLEAR_EX_PARSER(&gp->excmd); |
113 |
|
|
|
114 |
|
|
/* |
115 |
|
|
* If the user entered a single carriage return, send |
116 |
|
|
* ex_cmd() a separator -- it discards single newlines. |
117 |
|
|
*/ |
118 |
|
|
tp = TAILQ_FIRST(&sp->tiq); |
119 |
|
|
if (tp->len == 0) { |
120 |
|
|
gp->excmd.cp = " "; /* __TK__ why not |? */ |
121 |
|
|
gp->excmd.clen = 1; |
122 |
|
|
} else { |
123 |
|
|
gp->excmd.cp = tp->lb; |
124 |
|
|
gp->excmd.clen = tp->len; |
125 |
|
|
} |
126 |
|
|
F_INIT(&gp->excmd, E_NRSEP); |
127 |
|
|
|
128 |
|
|
if (ex_cmd(sp) && F_ISSET(gp, G_SCRIPTED)) |
129 |
|
|
return (1); |
130 |
|
|
|
131 |
|
|
if (INTERRUPTED(sp)) { |
132 |
|
|
CLR_INTERRUPT(sp); |
133 |
|
|
msgq(sp, M_ERR, "Interrupted"); |
134 |
|
|
} |
135 |
|
|
|
136 |
|
|
/* |
137 |
|
|
* If the last command caused a restart, or switched screens |
138 |
|
|
* or into vi, return. |
139 |
|
|
*/ |
140 |
|
|
if (F_ISSET(gp, G_SRESTART) || F_ISSET(sp, SC_SSWITCH | SC_VI)) { |
141 |
|
|
*spp = sp; |
142 |
|
|
break; |
143 |
|
|
} |
144 |
|
|
|
145 |
|
|
/* If the last command switched files, we don't care. */ |
146 |
|
|
F_CLR(sp, SC_FSWITCH); |
147 |
|
|
|
148 |
|
|
/* |
149 |
|
|
* If we're exiting this screen, move to the next one. By |
150 |
|
|
* definition, this means returning into vi, so return to the |
151 |
|
|
* main editor loop. The ordering is careful, don't discard |
152 |
|
|
* the contents of sp until the end. |
153 |
|
|
*/ |
154 |
|
|
if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE)) { |
155 |
|
|
if (file_end(sp, NULL, F_ISSET(sp, SC_EXIT_FORCE))) |
156 |
|
|
return (1); |
157 |
|
|
*spp = screen_next(sp); |
158 |
|
|
return (screen_end(sp)); |
159 |
|
|
} |
160 |
|
|
} |
161 |
|
|
return (0); |
162 |
|
|
} |
163 |
|
|
|
164 |
|
|
/* |
165 |
|
|
* ex_cmd -- |
166 |
|
|
* The guts of the ex parser: parse and execute a string containing |
167 |
|
|
* ex commands. |
168 |
|
|
* |
169 |
|
|
* !!! |
170 |
|
|
* This code MODIFIES the string that gets passed in, to delete quoting |
171 |
|
|
* characters, etc. The string cannot be readonly/text space, nor should |
172 |
|
|
* you expect to use it again after ex_cmd() returns. |
173 |
|
|
* |
174 |
|
|
* !!! |
175 |
|
|
* For the fun of it, if you want to see if a vi clone got the ex argument |
176 |
|
|
* parsing right, try: |
177 |
|
|
* |
178 |
|
|
* echo 'foo|bar' > file1; echo 'foo/bar' > file2; |
179 |
|
|
* vi |
180 |
|
|
* :edit +1|s/|/PIPE/|w file1| e file2|1 | s/\//SLASH/|wq |
181 |
|
|
* |
182 |
|
|
* or: vi |
183 |
|
|
* :set|file|append|set|file |
184 |
|
|
* |
185 |
|
|
* For extra credit, try them in a startup .exrc file. |
186 |
|
|
* |
187 |
|
|
* PUBLIC: int ex_cmd(SCR *); |
188 |
|
|
*/ |
189 |
|
|
int |
190 |
|
|
ex_cmd(SCR *sp) |
191 |
|
|
{ |
192 |
|
|
enum nresult nret; |
193 |
|
|
EX_PRIVATE *exp; |
194 |
|
|
EXCMD *ecp; |
195 |
|
|
GS *gp; |
196 |
|
|
MARK cur; |
197 |
|
|
recno_t lno; |
198 |
|
|
size_t arg1_len, discard, len; |
199 |
|
|
u_int32_t flags; |
200 |
|
|
long ltmp; |
201 |
|
|
int at_found, gv_found; |
202 |
|
|
int ch, cnt, delim, isaddr, namelen; |
203 |
|
|
int newscreen, notempty, tmp, vi_address; |
204 |
|
|
char *arg1, *p, *s, *t; |
205 |
|
|
|
206 |
|
|
gp = sp->gp; |
207 |
|
|
exp = EXP(sp); |
208 |
|
|
|
209 |
|
|
/* |
210 |
|
|
* We always start running the command on the top of the stack. |
211 |
|
|
* This means that *everything* must be resolved when we leave |
212 |
|
|
* this function for any reason. |
213 |
|
|
*/ |
214 |
|
|
loop: ecp = LIST_FIRST(&gp->ecq); |
215 |
|
|
|
216 |
|
|
/* If we're reading a command from a file, set up error information. */ |
217 |
|
|
if (ecp->if_name != NULL) { |
218 |
|
|
gp->if_lno = ecp->if_lno; |
219 |
|
|
gp->if_name = ecp->if_name; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
/* |
223 |
|
|
* If a move to the end of the file is scheduled for this command, |
224 |
|
|
* do it now. |
225 |
|
|
*/ |
226 |
|
|
if (F_ISSET(ecp, E_MOVETOEND)) { |
227 |
|
|
if (db_last(sp, &sp->lno)) |
228 |
|
|
goto rfail; |
229 |
|
|
sp->cno = 0; |
230 |
|
|
F_CLR(ecp, E_MOVETOEND); |
231 |
|
|
} |
232 |
|
|
|
233 |
|
|
/* If we found a newline, increment the count now. */ |
234 |
|
|
if (F_ISSET(ecp, E_NEWLINE)) { |
235 |
|
|
++gp->if_lno; |
236 |
|
|
++ecp->if_lno; |
237 |
|
|
F_CLR(ecp, E_NEWLINE); |
238 |
|
|
} |
239 |
|
|
|
240 |
|
|
/* (Re)initialize the EXCMD structure, preserving some flags. */ |
241 |
|
|
CLEAR_EX_CMD(ecp); |
242 |
|
|
|
243 |
|
|
/* Initialize the argument structures. */ |
244 |
|
|
if (argv_init(sp, ecp)) |
245 |
|
|
goto err; |
246 |
|
|
|
247 |
|
|
/* Initialize +cmd, saved command information. */ |
248 |
|
|
arg1 = NULL; |
249 |
|
|
ecp->save_cmdlen = 0; |
250 |
|
|
|
251 |
|
|
/* Skip <blank>s, empty lines. */ |
252 |
|
|
for (notempty = 0; ecp->clen > 0; ++ecp->cp, --ecp->clen) |
253 |
|
|
if ((ch = *ecp->cp) == '\n') { |
254 |
|
|
++gp->if_lno; |
255 |
|
|
++ecp->if_lno; |
256 |
|
|
} else if (isblank(ch)) |
257 |
|
|
notempty = 1; |
258 |
|
|
else |
259 |
|
|
break; |
260 |
|
|
|
261 |
|
|
/* |
262 |
|
|
* !!! |
263 |
|
|
* Permit extra colons at the start of the line. Historically, |
264 |
|
|
* ex/vi allowed a single extra one. It's simpler not to count. |
265 |
|
|
* The stripping is done here because, historically, any command |
266 |
|
|
* could have preceding colons, e.g. ":g/pattern/:p" worked. |
267 |
|
|
*/ |
268 |
|
|
if (ecp->clen != 0 && ch == ':') { |
269 |
|
|
notempty = 1; |
270 |
|
|
while (--ecp->clen > 0 && (ch = *++ecp->cp) == ':'); |
271 |
|
|
} |
272 |
|
|
|
273 |
|
|
/* |
274 |
|
|
* Command lines that start with a double-quote are comments. |
275 |
|
|
* |
276 |
|
|
* !!! |
277 |
|
|
* Historically, there was no escape or delimiter for a comment, e.g. |
278 |
|
|
* :"foo|set was a single comment and nothing was output. Since nvi |
279 |
|
|
* permits users to escape <newline> characters into command lines, we |
280 |
|
|
* have to check for that case. |
281 |
|
|
*/ |
282 |
|
|
if (ecp->clen != 0 && ch == '"') { |
283 |
|
|
while (--ecp->clen > 0 && *++ecp->cp != '\n'); |
284 |
|
|
if (*ecp->cp == '\n') { |
285 |
|
|
F_SET(ecp, E_NEWLINE); |
286 |
|
|
++ecp->cp; |
287 |
|
|
--ecp->clen; |
288 |
|
|
} |
289 |
|
|
goto loop; |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
/* Skip whitespace. */ |
293 |
|
|
for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) { |
294 |
|
|
ch = *ecp->cp; |
295 |
|
|
if (!isblank(ch)) |
296 |
|
|
break; |
297 |
|
|
} |
298 |
|
|
|
299 |
|
|
/* |
300 |
|
|
* The last point at which an empty line can mean do nothing. |
301 |
|
|
* |
302 |
|
|
* !!! |
303 |
|
|
* Historically, in ex mode, lines containing only <blank> characters |
304 |
|
|
* were the same as a single <carriage-return>, i.e. a default command. |
305 |
|
|
* In vi mode, they were ignored. In .exrc files this was a serious |
306 |
|
|
* annoyance, as vi kept trying to treat them as print commands. We |
307 |
|
|
* ignore backward compatibility in this case, discarding lines that |
308 |
|
|
* contain only <blank> characters from .exrc files. |
309 |
|
|
* |
310 |
|
|
* !!! |
311 |
|
|
* This is where you end up when you're done a command, i.e. clen has |
312 |
|
|
* gone to zero. Continue if there are more commands to run. |
313 |
|
|
*/ |
314 |
|
|
if (ecp->clen == 0 && |
315 |
|
|
(!notempty || F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_BLIGNORE))) { |
316 |
|
|
if (ex_load(sp)) |
317 |
|
|
goto rfail; |
318 |
|
|
ecp = LIST_FIRST(&gp->ecq); |
319 |
|
|
if (ecp->clen == 0) |
320 |
|
|
goto rsuccess; |
321 |
|
|
goto loop; |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
/* |
325 |
|
|
* Check to see if this is a command for which we may want to move |
326 |
|
|
* the cursor back up to the previous line. (The command :1<CR> |
327 |
|
|
* wants a <newline> separator, but the command :<CR> wants to erase |
328 |
|
|
* the command line.) If the line is empty except for <blank>s, |
329 |
|
|
* <carriage-return> or <eof>, we'll probably want to move up. I |
330 |
|
|
* don't think there's any way to get <blank> characters *after* the |
331 |
|
|
* command character, but this is the ex parser, and I've been wrong |
332 |
|
|
* before. |
333 |
|
|
*/ |
334 |
|
|
if (F_ISSET(ecp, E_NRSEP) && |
335 |
|
|
ecp->clen != 0 && (ecp->clen != 1 || ecp->cp[0] != '\004')) |
336 |
|
|
F_CLR(ecp, E_NRSEP); |
337 |
|
|
|
338 |
|
|
/* Parse command addresses. */ |
339 |
|
|
if (ex_range(sp, ecp, &tmp)) |
340 |
|
|
goto rfail; |
341 |
|
|
if (tmp) |
342 |
|
|
goto err; |
343 |
|
|
|
344 |
|
|
/* |
345 |
|
|
* Skip <blank>s and any more colons (the command :3,5:print |
346 |
|
|
* worked, historically). |
347 |
|
|
*/ |
348 |
|
|
for (; ecp->clen > 0; ++ecp->cp, --ecp->clen) { |
349 |
|
|
ch = *ecp->cp; |
350 |
|
|
if (!isblank(ch) && ch != ':') |
351 |
|
|
break; |
352 |
|
|
} |
353 |
|
|
|
354 |
|
|
/* |
355 |
|
|
* If no command, ex does the last specified of p, l, or #, and vi |
356 |
|
|
* moves to the line. Otherwise, determine the length of the command |
357 |
|
|
* name by looking for the first non-alphabetic character. (There |
358 |
|
|
* are a few non-alphabetic characters in command names, but they're |
359 |
|
|
* all single character commands.) This isn't a great test, because |
360 |
|
|
* it means that, for the command ":e +cut.c file", we'll report that |
361 |
|
|
* the command "cut" wasn't known. However, it makes ":e+35 file" work |
362 |
|
|
* correctly. |
363 |
|
|
* |
364 |
|
|
* !!! |
365 |
|
|
* Historically, lines with multiple adjacent (or <blank> separated) |
366 |
|
|
* command separators were very strange. For example, the command |
367 |
|
|
* |||<carriage-return>, when the cursor was on line 1, displayed |
368 |
|
|
* lines 2, 3 and 5 of the file. In addition, the command " | " |
369 |
|
|
* would only display the line after the next line, instead of the |
370 |
|
|
* next two lines. No ideas why. It worked reasonably when executed |
371 |
|
|
* from vi mode, and displayed lines 2, 3, and 4, so we do a default |
372 |
|
|
* command for each separator. |
373 |
|
|
*/ |
374 |
|
|
#define SINGLE_CHAR_COMMANDS "\004!#&*<=>@~" |
375 |
|
|
newscreen = 0; |
376 |
|
|
if (ecp->clen != 0 && ecp->cp[0] != '|' && ecp->cp[0] != '\n') { |
377 |
|
|
if (strchr(SINGLE_CHAR_COMMANDS, *ecp->cp)) { |
378 |
|
|
p = ecp->cp; |
379 |
|
|
++ecp->cp; |
380 |
|
|
--ecp->clen; |
381 |
|
|
namelen = 1; |
382 |
|
|
} else { |
383 |
|
|
for (p = ecp->cp; |
384 |
|
|
ecp->clen > 0; --ecp->clen, ++ecp->cp) |
385 |
|
|
if (!isalpha(*ecp->cp)) |
386 |
|
|
break; |
387 |
|
|
if ((namelen = ecp->cp - p) == 0) { |
388 |
|
|
msgq(sp, M_ERR, "Unknown command name"); |
389 |
|
|
goto err; |
390 |
|
|
} |
391 |
|
|
} |
392 |
|
|
|
393 |
|
|
/* |
394 |
|
|
* !!! |
395 |
|
|
* Historic vi permitted flags to immediately follow any |
396 |
|
|
* subset of the 'delete' command, but then did not permit |
397 |
|
|
* further arguments (flag, buffer, count). Make it work. |
398 |
|
|
* Permit further arguments for the few shreds of dignity |
399 |
|
|
* it offers. |
400 |
|
|
* |
401 |
|
|
* Adding commands that start with 'd', and match "delete" |
402 |
|
|
* up to a l, p, +, - or # character can break this code. |
403 |
|
|
* |
404 |
|
|
* !!! |
405 |
|
|
* Capital letters beginning the command names ex, edit, |
406 |
|
|
* next, previous, tag and visual (in vi mode) indicate the |
407 |
|
|
* command should happen in a new screen. |
408 |
|
|
*/ |
409 |
|
|
switch (p[0]) { |
410 |
|
|
case 'd': |
411 |
|
|
for (s = p, |
412 |
|
|
t = cmds[C_DELETE].name; *s == *t; ++s, ++t); |
413 |
|
|
if (s[0] == 'l' || s[0] == 'p' || s[0] == '+' || |
414 |
|
|
s[0] == '-' || s[0] == '^' || s[0] == '#') { |
415 |
|
|
len = (ecp->cp - p) - (s - p); |
416 |
|
|
ecp->cp -= len; |
417 |
|
|
ecp->clen += len; |
418 |
|
|
ecp->rcmd = cmds[C_DELETE]; |
419 |
|
|
ecp->rcmd.syntax = "1bca1"; |
420 |
|
|
ecp->cmd = &ecp->rcmd; |
421 |
|
|
goto skip_srch; |
422 |
|
|
} |
423 |
|
|
break; |
424 |
|
|
case 'E': case 'F': case 'N': case 'P': case 'T': case 'V': |
425 |
|
|
newscreen = 1; |
426 |
|
|
p[0] = tolower(p[0]); |
427 |
|
|
break; |
428 |
|
|
} |
429 |
|
|
|
430 |
|
|
/* |
431 |
|
|
* Search the table for the command. |
432 |
|
|
* |
433 |
|
|
* !!! |
434 |
|
|
* Historic vi permitted the mark to immediately follow the |
435 |
|
|
* 'k' in the 'k' command. Make it work. |
436 |
|
|
* |
437 |
|
|
* !!! |
438 |
|
|
* Historic vi permitted any flag to follow the s command, e.g. |
439 |
|
|
* "s/e/E/|s|sgc3p" was legal. Make the command "sgc" work. |
440 |
|
|
* Since the following characters all have to be flags, i.e. |
441 |
|
|
* alphabetics, we can let the s command routine return errors |
442 |
|
|
* if it was some illegal command string. This code will break |
443 |
|
|
* if an "sg" or similar command is ever added. The substitute |
444 |
|
|
* code doesn't care if it's a "cgr" flag or a "#lp" flag that |
445 |
|
|
* follows the 's', but we limit the choices here to "cgr" so |
446 |
|
|
* that we get unknown command messages for wrong combinations. |
447 |
|
|
*/ |
448 |
|
|
if ((ecp->cmd = ex_comm_search(p, namelen)) == NULL) |
449 |
|
|
switch (p[0]) { |
450 |
|
|
case 'k': |
451 |
|
|
if (namelen == 2) { |
452 |
|
|
ecp->cp -= namelen - 1; |
453 |
|
|
ecp->clen += namelen - 1; |
454 |
|
|
ecp->cmd = &cmds[C_K]; |
455 |
|
|
break; |
456 |
|
|
} |
457 |
|
|
goto unknown; |
458 |
|
|
case 's': |
459 |
|
|
for (s = p + 1, cnt = namelen; --cnt; ++s) |
460 |
|
|
if (s[0] != 'c' && |
461 |
|
|
s[0] != 'g' && s[0] != 'r') |
462 |
|
|
break; |
463 |
|
|
if (cnt == 0) { |
464 |
|
|
ecp->cp -= namelen - 1; |
465 |
|
|
ecp->clen += namelen - 1; |
466 |
|
|
ecp->rcmd = cmds[C_SUBSTITUTE]; |
467 |
|
|
ecp->rcmd.fn = ex_subagain; |
468 |
|
|
ecp->cmd = &ecp->rcmd; |
469 |
|
|
break; |
470 |
|
|
} |
471 |
|
|
/* FALLTHROUGH */ |
472 |
|
|
default: |
473 |
|
|
unknown: if (newscreen) |
474 |
|
|
p[0] = toupper(p[0]); |
475 |
|
|
ex_unknown(sp, p, namelen); |
476 |
|
|
goto err; |
477 |
|
|
} |
478 |
|
|
|
479 |
|
|
/* |
480 |
|
|
* The visual command has a different syntax when called |
481 |
|
|
* from ex than when called from a vi colon command. FMH. |
482 |
|
|
* Make the change now, before we test for the newscreen |
483 |
|
|
* semantic, so that we're testing the right one. |
484 |
|
|
*/ |
485 |
|
|
skip_srch: if (ecp->cmd == &cmds[C_VISUAL_EX] && F_ISSET(sp, SC_VI)) |
486 |
|
|
ecp->cmd = &cmds[C_VISUAL_VI]; |
487 |
|
|
|
488 |
|
|
/* |
489 |
|
|
* !!! |
490 |
|
|
* Historic vi permitted a capital 'P' at the beginning of |
491 |
|
|
* any command that started with 'p'. Probably wanted the |
492 |
|
|
* P[rint] command for backward compatibility, and the code |
493 |
|
|
* just made Preserve and Put work by accident. Nvi uses |
494 |
|
|
* Previous to mean previous-in-a-new-screen, so be careful. |
495 |
|
|
*/ |
496 |
|
|
if (newscreen && !F_ISSET(ecp->cmd, E_NEWSCREEN) && |
497 |
|
|
(ecp->cmd == &cmds[C_PRINT] || |
498 |
|
|
ecp->cmd == &cmds[C_PRESERVE])) |
499 |
|
|
newscreen = 0; |
500 |
|
|
|
501 |
|
|
/* Test for a newscreen associated with this command. */ |
502 |
|
|
if (newscreen && !F_ISSET(ecp->cmd, E_NEWSCREEN)) |
503 |
|
|
goto unknown; |
504 |
|
|
|
505 |
|
|
/* Secure means no shell access. */ |
506 |
|
|
if (F_ISSET(ecp->cmd, E_SECURE) && O_ISSET(sp, O_SECURE)) { |
507 |
|
|
ex_emsg(sp, ecp->cmd->name, EXM_SECURE); |
508 |
|
|
goto err; |
509 |
|
|
} |
510 |
|
|
|
511 |
|
|
/* |
512 |
|
|
* Multiple < and > characters; another "feature". Note, |
513 |
|
|
* The string passed to the underlying function may not be |
514 |
|
|
* nul terminated in this case. |
515 |
|
|
*/ |
516 |
|
|
if ((ecp->cmd == &cmds[C_SHIFTL] && *p == '<') || |
517 |
|
|
(ecp->cmd == &cmds[C_SHIFTR] && *p == '>')) { |
518 |
|
|
for (ch = *p; |
519 |
|
|
ecp->clen > 0; --ecp->clen, ++ecp->cp) |
520 |
|
|
if (*ecp->cp != ch) |
521 |
|
|
break; |
522 |
|
|
if (argv_exp0(sp, ecp, p, ecp->cp - p)) |
523 |
|
|
goto err; |
524 |
|
|
} |
525 |
|
|
|
526 |
|
|
/* Set the format style flags for the next command. */ |
527 |
|
|
if (ecp->cmd == &cmds[C_HASH]) |
528 |
|
|
exp->fdef = E_C_HASH; |
529 |
|
|
else if (ecp->cmd == &cmds[C_LIST]) |
530 |
|
|
exp->fdef = E_C_LIST; |
531 |
|
|
else if (ecp->cmd == &cmds[C_PRINT]) |
532 |
|
|
exp->fdef = E_C_PRINT; |
533 |
|
|
F_CLR(ecp, E_USELASTCMD); |
534 |
|
|
} else { |
535 |
|
|
/* Print is the default command. */ |
536 |
|
|
ecp->cmd = &cmds[C_PRINT]; |
537 |
|
|
|
538 |
|
|
/* Set the saved format flags. */ |
539 |
|
|
F_SET(ecp, exp->fdef); |
540 |
|
|
|
541 |
|
|
/* |
542 |
|
|
* !!! |
543 |
|
|
* If no address was specified, and it's not a global command, |
544 |
|
|
* we up the address by one. (I have no idea why globals are |
545 |
|
|
* exempted, but it's (ahem) historic practice.) |
546 |
|
|
*/ |
547 |
|
|
if (ecp->addrcnt == 0 && !F_ISSET(sp, SC_EX_GLOBAL)) { |
548 |
|
|
ecp->addrcnt = 1; |
549 |
|
|
ecp->addr1.lno = sp->lno + 1; |
550 |
|
|
ecp->addr1.cno = sp->cno; |
551 |
|
|
} |
552 |
|
|
|
553 |
|
|
F_SET(ecp, E_USELASTCMD); |
554 |
|
|
} |
555 |
|
|
|
556 |
|
|
/* |
557 |
|
|
* !!! |
558 |
|
|
* Historically, the number option applied to both ex and vi. One |
559 |
|
|
* strangeness was that ex didn't switch display formats until a |
560 |
|
|
* command was entered, e.g. <CR>'s after the set didn't change to |
561 |
|
|
* the new format, but :1p would. |
562 |
|
|
*/ |
563 |
|
|
if (O_ISSET(sp, O_NUMBER)) { |
564 |
|
|
F_SET(ecp, E_OPTNUM); |
565 |
|
|
FL_SET(ecp->iflags, E_C_HASH); |
566 |
|
|
} else |
567 |
|
|
F_CLR(ecp, E_OPTNUM); |
568 |
|
|
|
569 |
|
|
/* Check for ex mode legality. */ |
570 |
|
|
if (F_ISSET(sp, SC_EX) && (F_ISSET(ecp->cmd, E_VIONLY) || newscreen)) { |
571 |
|
|
msgq(sp, M_ERR, |
572 |
|
|
"%s: command not available in ex mode", ecp->cmd->name); |
573 |
|
|
goto err; |
574 |
|
|
} |
575 |
|
|
|
576 |
|
|
/* Add standard command flags. */ |
577 |
|
|
F_SET(ecp, ecp->cmd->flags); |
578 |
|
|
if (!newscreen) |
579 |
|
|
F_CLR(ecp, E_NEWSCREEN); |
580 |
|
|
|
581 |
|
|
/* |
582 |
|
|
* There are three normal termination cases for an ex command. They |
583 |
|
|
* are the end of the string (ecp->clen), or unescaped (by <literal |
584 |
|
|
* next> characters) <newline> or '|' characters. As we're now past |
585 |
|
|
* possible addresses, we can determine how long the command is, so we |
586 |
|
|
* don't have to look for all the possible terminations. Naturally, |
587 |
|
|
* there are some exciting special cases: |
588 |
|
|
* |
589 |
|
|
* 1: The bang, global, v and the filter versions of the read and |
590 |
|
|
* write commands are delimited by <newline>s (they can contain |
591 |
|
|
* shell pipes). |
592 |
|
|
* 2: The ex, edit, next and visual in vi mode commands all take ex |
593 |
|
|
* commands as their first arguments. |
594 |
|
|
* 3: The s command takes an RE as its first argument, and wants it |
595 |
|
|
* to be specially delimited. |
596 |
|
|
* |
597 |
|
|
* Historically, '|' characters in the first argument of the ex, edit, |
598 |
|
|
* next, vi visual, and s commands didn't delimit the command. And, |
599 |
|
|
* in the filter cases for read and write, and the bang, global and v |
600 |
|
|
* commands, they did not delimit the command at all. |
601 |
|
|
* |
602 |
|
|
* For example, the following commands were legal: |
603 |
|
|
* |
604 |
|
|
* :edit +25|s/abc/ABC/ file.c |
605 |
|
|
* :s/|/PIPE/ |
606 |
|
|
* :read !spell % | columnate |
607 |
|
|
* :global/pattern/p|l |
608 |
|
|
* |
609 |
|
|
* It's not quite as simple as it sounds, however. The command: |
610 |
|
|
* |
611 |
|
|
* :s/a/b/|s/c/d|set |
612 |
|
|
* |
613 |
|
|
* was also legal, i.e. the historic ex parser (using the word loosely, |
614 |
|
|
* since "parser" implies some regularity of syntax) delimited the RE's |
615 |
|
|
* based on its delimiter and not anything so irretrievably vulgar as a |
616 |
|
|
* command syntax. |
617 |
|
|
* |
618 |
|
|
* Anyhow, the following code makes this all work. First, for the |
619 |
|
|
* special cases we move past their special argument(s). Then, we |
620 |
|
|
* do normal command processing on whatever is left. Barf-O-Rama. |
621 |
|
|
*/ |
622 |
|
|
discard = 0; /* Characters discarded from the command. */ |
623 |
|
|
arg1_len = 0; |
624 |
|
|
ecp->save_cmd = ecp->cp; |
625 |
|
|
if (ecp->cmd == &cmds[C_EDIT] || ecp->cmd == &cmds[C_EX] || |
626 |
|
|
ecp->cmd == &cmds[C_NEXT] || ecp->cmd == &cmds[C_VISUAL_VI]) { |
627 |
|
|
/* |
628 |
|
|
* Move to the next non-whitespace character. A '!' |
629 |
|
|
* immediately following the command is eaten as a |
630 |
|
|
* force flag. |
631 |
|
|
*/ |
632 |
|
|
if (ecp->clen > 0 && *ecp->cp == '!') { |
633 |
|
|
++ecp->cp; |
634 |
|
|
--ecp->clen; |
635 |
|
|
FL_SET(ecp->iflags, E_C_FORCE); |
636 |
|
|
|
637 |
|
|
/* Reset, don't reparse. */ |
638 |
|
|
ecp->save_cmd = ecp->cp; |
639 |
|
|
} |
640 |
|
|
for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) |
641 |
|
|
if (!isblank(*ecp->cp)) |
642 |
|
|
break; |
643 |
|
|
/* |
644 |
|
|
* QUOTING NOTE: |
645 |
|
|
* |
646 |
|
|
* The historic implementation ignored all escape characters |
647 |
|
|
* so there was no way to put a space or newline into the +cmd |
648 |
|
|
* field. We do a simplistic job of fixing it by moving to the |
649 |
|
|
* first whitespace character that isn't escaped. The escaping |
650 |
|
|
* characters are stripped as no longer useful. |
651 |
|
|
*/ |
652 |
|
|
if (ecp->clen > 0 && *ecp->cp == '+') { |
653 |
|
|
++ecp->cp; |
654 |
|
|
--ecp->clen; |
655 |
|
|
for (arg1 = p = ecp->cp; |
656 |
|
|
ecp->clen > 0; --ecp->clen, ++ecp->cp) { |
657 |
|
|
ch = *ecp->cp; |
658 |
|
|
if (IS_ESCAPE(sp, ecp, ch) && |
659 |
|
|
ecp->clen > 1) { |
660 |
|
|
++discard; |
661 |
|
|
--ecp->clen; |
662 |
|
|
ch = *++ecp->cp; |
663 |
|
|
} else if (isblank(ch)) |
664 |
|
|
break; |
665 |
|
|
*p++ = ch; |
666 |
|
|
} |
667 |
|
|
arg1_len = ecp->cp - arg1; |
668 |
|
|
|
669 |
|
|
/* Reset, so the first argument isn't reparsed. */ |
670 |
|
|
ecp->save_cmd = ecp->cp; |
671 |
|
|
} |
672 |
|
|
} else if (ecp->cmd == &cmds[C_BANG] || |
673 |
|
|
ecp->cmd == &cmds[C_GLOBAL] || ecp->cmd == &cmds[C_V]) { |
674 |
|
|
/* |
675 |
|
|
* QUOTING NOTE: |
676 |
|
|
* |
677 |
|
|
* We use backslashes to escape <newline> characters, although |
678 |
|
|
* this wasn't historic practice for the bang command. It was |
679 |
|
|
* for the global and v commands, and it's common usage when |
680 |
|
|
* doing text insert during the command. Escaping characters |
681 |
|
|
* are stripped as no longer useful. |
682 |
|
|
*/ |
683 |
|
|
for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) { |
684 |
|
|
ch = *ecp->cp; |
685 |
|
|
if (ch == '\\' && ecp->clen > 1 && ecp->cp[1] == '\n') { |
686 |
|
|
++discard; |
687 |
|
|
--ecp->clen; |
688 |
|
|
ch = *++ecp->cp; |
689 |
|
|
|
690 |
|
|
++gp->if_lno; |
691 |
|
|
++ecp->if_lno; |
692 |
|
|
} else if (ch == '\n') |
693 |
|
|
break; |
694 |
|
|
*p++ = ch; |
695 |
|
|
} |
696 |
|
|
} else if (ecp->cmd == &cmds[C_READ] || ecp->cmd == &cmds[C_WRITE]) { |
697 |
|
|
/* |
698 |
|
|
* For write commands, if the next character is a <blank>, and |
699 |
|
|
* the next non-blank character is a '!', it's a filter command |
700 |
|
|
* and we want to eat everything up to the <newline>. For read |
701 |
|
|
* commands, if the next non-blank character is a '!', it's a |
702 |
|
|
* filter command and we want to eat everything up to the next |
703 |
|
|
* <newline>. Otherwise, we're done. |
704 |
|
|
*/ |
705 |
|
|
for (tmp = 0; ecp->clen > 0; --ecp->clen, ++ecp->cp) { |
706 |
|
|
ch = *ecp->cp; |
707 |
|
|
if (isblank(ch)) |
708 |
|
|
tmp = 1; |
709 |
|
|
else |
710 |
|
|
break; |
711 |
|
|
} |
712 |
|
|
if (ecp->clen > 0 && ch == '!' && |
713 |
|
|
(ecp->cmd == &cmds[C_READ] || tmp)) |
714 |
|
|
for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) |
715 |
|
|
if (ecp->cp[0] == '\n') |
716 |
|
|
break; |
717 |
|
|
} else if (ecp->cmd == &cmds[C_SUBSTITUTE]) { |
718 |
|
|
/* |
719 |
|
|
* Move to the next non-whitespace character, we'll use it as |
720 |
|
|
* the delimiter. If the character isn't an alphanumeric or |
721 |
|
|
* a '|', it's the delimiter, so parse it. Otherwise, we're |
722 |
|
|
* into something like ":s g", so use the special s command. |
723 |
|
|
*/ |
724 |
|
|
for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) |
725 |
|
|
if (!isblank(ecp->cp[0])) |
726 |
|
|
break; |
727 |
|
|
|
728 |
|
|
if (isalnum(ecp->cp[0]) || ecp->cp[0] == '|') { |
729 |
|
|
ecp->rcmd = cmds[C_SUBSTITUTE]; |
730 |
|
|
ecp->rcmd.fn = ex_subagain; |
731 |
|
|
ecp->cmd = &ecp->rcmd; |
732 |
|
|
} else if (ecp->clen > 0) { |
733 |
|
|
/* |
734 |
|
|
* QUOTING NOTE: |
735 |
|
|
* |
736 |
|
|
* Backslashes quote delimiter characters for RE's. |
737 |
|
|
* The backslashes are NOT removed since they'll be |
738 |
|
|
* used by the RE code. Move to the third delimiter |
739 |
|
|
* that's not escaped (or the end of the command). |
740 |
|
|
*/ |
741 |
|
|
delim = *ecp->cp; |
742 |
|
|
++ecp->cp; |
743 |
|
|
--ecp->clen; |
744 |
|
|
for (cnt = 2; ecp->clen > 0 && |
745 |
|
|
cnt != 0; --ecp->clen, ++ecp->cp) |
746 |
|
|
if (ecp->cp[0] == '\\' && |
747 |
|
|
ecp->clen > 1) { |
748 |
|
|
++ecp->cp; |
749 |
|
|
--ecp->clen; |
750 |
|
|
} else if (ecp->cp[0] == delim) |
751 |
|
|
--cnt; |
752 |
|
|
} |
753 |
|
|
} |
754 |
|
|
|
755 |
|
|
/* |
756 |
|
|
* Use normal quoting and termination rules to find the end of this |
757 |
|
|
* command. |
758 |
|
|
* |
759 |
|
|
* QUOTING NOTE: |
760 |
|
|
* |
761 |
|
|
* Historically, vi permitted ^V's to escape <newline>'s in the .exrc |
762 |
|
|
* file. It was almost certainly a bug, but that's what bug-for-bug |
763 |
|
|
* compatibility means, Grasshopper. Also, ^V's escape the command |
764 |
|
|
* delimiters. Literal next quote characters in front of the newlines, |
765 |
|
|
* '|' characters or literal next characters are stripped as they're |
766 |
|
|
* no longer useful. |
767 |
|
|
*/ |
768 |
|
|
vi_address = ecp->clen != 0 && ecp->cp[0] != '\n'; |
769 |
|
|
for (p = ecp->cp; ecp->clen > 0; --ecp->clen, ++ecp->cp) { |
770 |
|
|
ch = ecp->cp[0]; |
771 |
|
|
if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) { |
772 |
|
|
tmp = ecp->cp[1]; |
773 |
|
|
if (tmp == '\n' || tmp == '|') { |
774 |
|
|
if (tmp == '\n') { |
775 |
|
|
++gp->if_lno; |
776 |
|
|
++ecp->if_lno; |
777 |
|
|
} |
778 |
|
|
++discard; |
779 |
|
|
--ecp->clen; |
780 |
|
|
++ecp->cp; |
781 |
|
|
ch = tmp; |
782 |
|
|
} |
783 |
|
|
} else if (ch == '\n' || ch == '|') { |
784 |
|
|
if (ch == '\n') |
785 |
|
|
F_SET(ecp, E_NEWLINE); |
786 |
|
|
--ecp->clen; |
787 |
|
|
break; |
788 |
|
|
} |
789 |
|
|
*p++ = ch; |
790 |
|
|
} |
791 |
|
|
|
792 |
|
|
/* |
793 |
|
|
* Save off the next command information, go back to the |
794 |
|
|
* original start of the command. |
795 |
|
|
*/ |
796 |
|
|
p = ecp->cp + 1; |
797 |
|
|
ecp->cp = ecp->save_cmd; |
798 |
|
|
ecp->save_cmd = p; |
799 |
|
|
ecp->save_cmdlen = ecp->clen; |
800 |
|
|
ecp->clen = ((ecp->save_cmd - ecp->cp) - 1) - discard; |
801 |
|
|
|
802 |
|
|
/* |
803 |
|
|
* QUOTING NOTE: |
804 |
|
|
* |
805 |
|
|
* The "set tags" command historically used a backslash, not the |
806 |
|
|
* user's literal next character, to escape whitespace. Handle |
807 |
|
|
* it here instead of complicating the argv_exp3() code. Note, |
808 |
|
|
* this isn't a particularly complex trap, and if backslashes were |
809 |
|
|
* legal in set commands, this would have to be much more complicated. |
810 |
|
|
*/ |
811 |
|
|
if (ecp->cmd == &cmds[C_SET]) |
812 |
|
|
for (p = ecp->cp, len = ecp->clen; len > 0; --len, ++p) |
813 |
|
|
if (*p == '\\') |
814 |
|
|
*p = CH_LITERAL; |
815 |
|
|
|
816 |
|
|
/* |
817 |
|
|
* Set the default addresses. It's an error to specify an address for |
818 |
|
|
* a command that doesn't take them. If two addresses are specified |
819 |
|
|
* for a command that only takes one, lose the first one. Two special |
820 |
|
|
* cases here, some commands take 0 or 2 addresses. For most of them |
821 |
|
|
* (the E_ADDR2_ALL flag), 0 defaults to the entire file. For one |
822 |
|
|
* (the `!' command, the E_ADDR2_NONE flag), 0 defaults to no lines. |
823 |
|
|
* |
824 |
|
|
* Also, if the file is empty, some commands want to use an address of |
825 |
|
|
* 0, i.e. the entire file is 0 to 0, and the default first address is |
826 |
|
|
* 0. Otherwise, an entire file is 1 to N and the default line is 1. |
827 |
|
|
* Note, we also add the E_ADDR_ZERO flag to the command flags, for the |
828 |
|
|
* case where the 0 address is only valid if it's a default address. |
829 |
|
|
* |
830 |
|
|
* Also, set a flag if we set the default addresses. Some commands |
831 |
|
|
* (ex: z) care if the user specified an address or if we just used |
832 |
|
|
* the current cursor. |
833 |
|
|
*/ |
834 |
|
|
switch (F_ISSET(ecp, E_ADDR1 | E_ADDR2 | E_ADDR2_ALL | E_ADDR2_NONE)) { |
835 |
|
|
case E_ADDR1: /* One address: */ |
836 |
|
|
switch (ecp->addrcnt) { |
837 |
|
|
case 0: /* Default cursor/empty file. */ |
838 |
|
|
ecp->addrcnt = 1; |
839 |
|
|
F_SET(ecp, E_ADDR_DEF); |
840 |
|
|
if (F_ISSET(ecp, E_ADDR_ZERODEF)) { |
841 |
|
|
if (db_last(sp, &lno)) |
842 |
|
|
goto err; |
843 |
|
|
if (lno == 0) { |
844 |
|
|
ecp->addr1.lno = 0; |
845 |
|
|
F_SET(ecp, E_ADDR_ZERO); |
846 |
|
|
} else |
847 |
|
|
ecp->addr1.lno = sp->lno; |
848 |
|
|
} else |
849 |
|
|
ecp->addr1.lno = sp->lno; |
850 |
|
|
ecp->addr1.cno = sp->cno; |
851 |
|
|
break; |
852 |
|
|
case 1: |
853 |
|
|
break; |
854 |
|
|
case 2: /* Lose the first address. */ |
855 |
|
|
ecp->addrcnt = 1; |
856 |
|
|
ecp->addr1 = ecp->addr2; |
857 |
|
|
} |
858 |
|
|
break; |
859 |
|
|
case E_ADDR2_NONE: /* Zero/two addresses: */ |
860 |
|
|
if (ecp->addrcnt == 0) /* Default to nothing. */ |
861 |
|
|
break; |
862 |
|
|
goto two_addr; |
863 |
|
|
case E_ADDR2_ALL: /* Zero/two addresses: */ |
864 |
|
|
if (ecp->addrcnt == 0) { /* Default entire/empty file. */ |
865 |
|
|
F_SET(ecp, E_ADDR_DEF); |
866 |
|
|
ecp->addrcnt = 2; |
867 |
|
|
if (sp->ep == NULL) |
868 |
|
|
ecp->addr2.lno = 0; |
869 |
|
|
else if (db_last(sp, &ecp->addr2.lno)) |
870 |
|
|
goto err; |
871 |
|
|
if (F_ISSET(ecp, E_ADDR_ZERODEF) && |
872 |
|
|
ecp->addr2.lno == 0) { |
873 |
|
|
ecp->addr1.lno = 0; |
874 |
|
|
F_SET(ecp, E_ADDR_ZERO); |
875 |
|
|
} else |
876 |
|
|
ecp->addr1.lno = 1; |
877 |
|
|
ecp->addr1.cno = ecp->addr2.cno = 0; |
878 |
|
|
F_SET(ecp, E_ADDR2_ALL); |
879 |
|
|
break; |
880 |
|
|
} |
881 |
|
|
/* FALLTHROUGH */ |
882 |
|
|
case E_ADDR2: /* Two addresses: */ |
883 |
|
|
two_addr: switch (ecp->addrcnt) { |
884 |
|
|
case 0: /* Default cursor/empty file. */ |
885 |
|
|
ecp->addrcnt = 2; |
886 |
|
|
F_SET(ecp, E_ADDR_DEF); |
887 |
|
|
if (sp->lno == 1 && |
888 |
|
|
F_ISSET(ecp, E_ADDR_ZERODEF)) { |
889 |
|
|
if (db_last(sp, &lno)) |
890 |
|
|
goto err; |
891 |
|
|
if (lno == 0) { |
892 |
|
|
ecp->addr1.lno = ecp->addr2.lno = 0; |
893 |
|
|
F_SET(ecp, E_ADDR_ZERO); |
894 |
|
|
} else |
895 |
|
|
ecp->addr1.lno = |
896 |
|
|
ecp->addr2.lno = sp->lno; |
897 |
|
|
} else |
898 |
|
|
ecp->addr1.lno = ecp->addr2.lno = sp->lno; |
899 |
|
|
ecp->addr1.cno = ecp->addr2.cno = sp->cno; |
900 |
|
|
break; |
901 |
|
|
case 1: /* Default to first address. */ |
902 |
|
|
ecp->addrcnt = 2; |
903 |
|
|
ecp->addr2 = ecp->addr1; |
904 |
|
|
break; |
905 |
|
|
case 2: |
906 |
|
|
break; |
907 |
|
|
} |
908 |
|
|
break; |
909 |
|
|
default: |
910 |
|
|
if (ecp->addrcnt) /* Error. */ |
911 |
|
|
goto usage; |
912 |
|
|
} |
913 |
|
|
|
914 |
|
|
/* |
915 |
|
|
* !!! |
916 |
|
|
* The ^D scroll command historically scrolled the value of the scroll |
917 |
|
|
* option or to EOF. It was an error if the cursor was already at EOF. |
918 |
|
|
* (Leading addresses were permitted, but were then ignored.) |
919 |
|
|
*/ |
920 |
|
|
if (ecp->cmd == &cmds[C_SCROLL]) { |
921 |
|
|
ecp->addrcnt = 2; |
922 |
|
|
ecp->addr1.lno = sp->lno + 1; |
923 |
|
|
ecp->addr2.lno = sp->lno + O_VAL(sp, O_SCROLL); |
924 |
|
|
ecp->addr1.cno = ecp->addr2.cno = sp->cno; |
925 |
|
|
if (db_last(sp, &lno)) |
926 |
|
|
goto err; |
927 |
|
|
if (lno != 0 && lno > sp->lno && ecp->addr2.lno > lno) |
928 |
|
|
ecp->addr2.lno = lno; |
929 |
|
|
} |
930 |
|
|
|
931 |
|
|
ecp->flagoff = 0; |
932 |
|
|
for (p = ecp->cmd->syntax; *p != '\0'; ++p) { |
933 |
|
|
/* |
934 |
|
|
* The force flag is sensitive to leading whitespace, i.e. |
935 |
|
|
* "next !" is different from "next!". Handle it before |
936 |
|
|
* skipping leading <blank>s. |
937 |
|
|
*/ |
938 |
|
|
if (*p == '!') { |
939 |
|
|
if (ecp->clen > 0 && *ecp->cp == '!') { |
940 |
|
|
++ecp->cp; |
941 |
|
|
--ecp->clen; |
942 |
|
|
FL_SET(ecp->iflags, E_C_FORCE); |
943 |
|
|
} |
944 |
|
|
continue; |
945 |
|
|
} |
946 |
|
|
|
947 |
|
|
/* Skip leading <blank>s. */ |
948 |
|
|
for (; ecp->clen > 0; --ecp->clen, ++ecp->cp) |
949 |
|
|
if (!isblank(*ecp->cp)) |
950 |
|
|
break; |
951 |
|
|
if (ecp->clen == 0) |
952 |
|
|
break; |
953 |
|
|
|
954 |
|
|
switch (*p) { |
955 |
|
|
case '1': /* +, -, #, l, p */ |
956 |
|
|
/* |
957 |
|
|
* !!! |
958 |
|
|
* Historically, some flags were ignored depending |
959 |
|
|
* on where they occurred in the command line. For |
960 |
|
|
* example, in the command, ":3+++p--#", historic vi |
961 |
|
|
* acted on the '#' flag, but ignored the '-' flags. |
962 |
|
|
* It's unambiguous what the flags mean, so we just |
963 |
|
|
* handle them regardless of the stupidity of their |
964 |
|
|
* location. |
965 |
|
|
*/ |
966 |
|
|
for (; ecp->clen; --ecp->clen, ++ecp->cp) |
967 |
|
|
switch (*ecp->cp) { |
968 |
|
|
case '+': |
969 |
|
|
++ecp->flagoff; |
970 |
|
|
break; |
971 |
|
|
case '-': |
972 |
|
|
case '^': |
973 |
|
|
--ecp->flagoff; |
974 |
|
|
break; |
975 |
|
|
case '#': |
976 |
|
|
F_CLR(ecp, E_OPTNUM); |
977 |
|
|
FL_SET(ecp->iflags, E_C_HASH); |
978 |
|
|
exp->fdef |= E_C_HASH; |
979 |
|
|
break; |
980 |
|
|
case 'l': |
981 |
|
|
FL_SET(ecp->iflags, E_C_LIST); |
982 |
|
|
exp->fdef |= E_C_LIST; |
983 |
|
|
break; |
984 |
|
|
case 'p': |
985 |
|
|
FL_SET(ecp->iflags, E_C_PRINT); |
986 |
|
|
exp->fdef |= E_C_PRINT; |
987 |
|
|
break; |
988 |
|
|
default: |
989 |
|
|
goto end_case1; |
990 |
|
|
} |
991 |
|
|
end_case1: break; |
992 |
|
|
case '2': /* -, ., +, ^ */ |
993 |
|
|
case '3': /* -, ., +, ^, = */ |
994 |
|
|
for (; ecp->clen; --ecp->clen, ++ecp->cp) |
995 |
|
|
switch (*ecp->cp) { |
996 |
|
|
case '-': |
997 |
|
|
FL_SET(ecp->iflags, E_C_DASH); |
998 |
|
|
break; |
999 |
|
|
case '.': |
1000 |
|
|
FL_SET(ecp->iflags, E_C_DOT); |
1001 |
|
|
break; |
1002 |
|
|
case '+': |
1003 |
|
|
FL_SET(ecp->iflags, E_C_PLUS); |
1004 |
|
|
break; |
1005 |
|
|
case '^': |
1006 |
|
|
FL_SET(ecp->iflags, E_C_CARAT); |
1007 |
|
|
break; |
1008 |
|
|
case '=': |
1009 |
|
|
if (*p == '3') { |
1010 |
|
|
FL_SET(ecp->iflags, E_C_EQUAL); |
1011 |
|
|
break; |
1012 |
|
|
} |
1013 |
|
|
/* FALLTHROUGH */ |
1014 |
|
|
default: |
1015 |
|
|
goto end_case23; |
1016 |
|
|
} |
1017 |
|
|
end_case23: break; |
1018 |
|
|
case 'b': /* buffer */ |
1019 |
|
|
/* |
1020 |
|
|
* !!! |
1021 |
|
|
* Historically, "d #" was a delete with a flag, not a |
1022 |
|
|
* delete into the '#' buffer. If the current command |
1023 |
|
|
* permits a flag, don't use one as a buffer. However, |
1024 |
|
|
* the 'l' and 'p' flags were legal buffer names in the |
1025 |
|
|
* historic ex, and were used as buffers, not flags. |
1026 |
|
|
*/ |
1027 |
|
|
if ((ecp->cp[0] == '+' || ecp->cp[0] == '-' || |
1028 |
|
|
ecp->cp[0] == '^' || ecp->cp[0] == '#') && |
1029 |
|
|
strchr(p, '1') != NULL) |
1030 |
|
|
break; |
1031 |
|
|
/* |
1032 |
|
|
* !!! |
1033 |
|
|
* Digits can't be buffer names in ex commands, or the |
1034 |
|
|
* command "d2" would be a delete into buffer '2', and |
1035 |
|
|
* not a two-line deletion. |
1036 |
|
|
*/ |
1037 |
|
|
if (!isdigit(ecp->cp[0])) { |
1038 |
|
|
ecp->buffer = *ecp->cp; |
1039 |
|
|
++ecp->cp; |
1040 |
|
|
--ecp->clen; |
1041 |
|
|
FL_SET(ecp->iflags, E_C_BUFFER); |
1042 |
|
|
} |
1043 |
|
|
break; |
1044 |
|
|
case 'c': /* count [01+a] */ |
1045 |
|
|
++p; |
1046 |
|
|
/* Validate any signed value. */ |
1047 |
|
|
if (!isdigit(*ecp->cp) && (*p != '+' || |
1048 |
|
|
(*ecp->cp != '+' && *ecp->cp != '-'))) |
1049 |
|
|
break; |
1050 |
|
|
/* If a signed value, set appropriate flags. */ |
1051 |
|
|
if (*ecp->cp == '-') |
1052 |
|
|
FL_SET(ecp->iflags, E_C_COUNT_NEG); |
1053 |
|
|
else if (*ecp->cp == '+') |
1054 |
|
|
FL_SET(ecp->iflags, E_C_COUNT_POS); |
1055 |
|
|
if ((nret = |
1056 |
|
|
nget_slong(<mp, ecp->cp, &t, 10)) != NUM_OK) { |
1057 |
|
|
ex_badaddr(sp, NULL, A_NOTSET, nret); |
1058 |
|
|
goto err; |
1059 |
|
|
} |
1060 |
|
|
if (ltmp == 0 && *p != '0') { |
1061 |
|
|
msgq(sp, M_ERR, "Count may not be zero"); |
1062 |
|
|
goto err; |
1063 |
|
|
} |
1064 |
|
|
ecp->clen -= (t - ecp->cp); |
1065 |
|
|
ecp->cp = t; |
1066 |
|
|
|
1067 |
|
|
/* |
1068 |
|
|
* Counts as address offsets occur in commands taking |
1069 |
|
|
* two addresses. Historic vi practice was to use |
1070 |
|
|
* the count as an offset from the *second* address. |
1071 |
|
|
* |
1072 |
|
|
* Set a count flag; some underlying commands (see |
1073 |
|
|
* join) do different things with counts than with |
1074 |
|
|
* line addresses. |
1075 |
|
|
*/ |
1076 |
|
|
if (*p == 'a') { |
1077 |
|
|
ecp->addr1 = ecp->addr2; |
1078 |
|
|
ecp->addr2.lno = ecp->addr1.lno + ltmp - 1; |
1079 |
|
|
} else |
1080 |
|
|
ecp->count = ltmp; |
1081 |
|
|
FL_SET(ecp->iflags, E_C_COUNT); |
1082 |
|
|
break; |
1083 |
|
|
case 'f': /* file */ |
1084 |
|
|
if (argv_exp2(sp, ecp, ecp->cp, ecp->clen)) |
1085 |
|
|
goto err; |
1086 |
|
|
goto arg_cnt_chk; |
1087 |
|
|
case 'l': /* line */ |
1088 |
|
|
/* |
1089 |
|
|
* Get a line specification. |
1090 |
|
|
* |
1091 |
|
|
* If the line was a search expression, we may have |
1092 |
|
|
* changed state during the call, and we're now |
1093 |
|
|
* searching the file. Push ourselves onto the state |
1094 |
|
|
* stack. |
1095 |
|
|
*/ |
1096 |
|
|
if (ex_line(sp, ecp, &cur, &isaddr, &tmp)) |
1097 |
|
|
goto rfail; |
1098 |
|
|
if (tmp) |
1099 |
|
|
goto err; |
1100 |
|
|
|
1101 |
|
|
/* Line specifications are always required. */ |
1102 |
|
|
if (!isaddr) { |
1103 |
|
|
msgq_str(sp, M_ERR, ecp->cp, |
1104 |
|
|
"%s: bad line specification"); |
1105 |
|
|
goto err; |
1106 |
|
|
} |
1107 |
|
|
/* |
1108 |
|
|
* The target line should exist for these commands, |
1109 |
|
|
* but 0 is legal for them as well. |
1110 |
|
|
*/ |
1111 |
|
|
if (cur.lno != 0 && !db_exist(sp, cur.lno)) { |
1112 |
|
|
ex_badaddr(sp, NULL, A_EOF, NUM_OK); |
1113 |
|
|
goto err; |
1114 |
|
|
} |
1115 |
|
|
ecp->lineno = cur.lno; |
1116 |
|
|
break; |
1117 |
|
|
case 'S': /* string, file exp. */ |
1118 |
|
|
if (ecp->clen != 0) { |
1119 |
|
|
if (argv_exp1(sp, ecp, ecp->cp, |
1120 |
|
|
ecp->clen, ecp->cmd == &cmds[C_BANG])) |
1121 |
|
|
goto err; |
1122 |
|
|
goto addr_verify; |
1123 |
|
|
} |
1124 |
|
|
/* FALLTHROUGH */ |
1125 |
|
|
case 's': /* string */ |
1126 |
|
|
if (argv_exp0(sp, ecp, ecp->cp, ecp->clen)) |
1127 |
|
|
goto err; |
1128 |
|
|
goto addr_verify; |
1129 |
|
|
case 'W': /* word string */ |
1130 |
|
|
/* |
1131 |
|
|
* QUOTING NOTE: |
1132 |
|
|
* |
1133 |
|
|
* Literal next characters escape the following |
1134 |
|
|
* character. Quoting characters are stripped here |
1135 |
|
|
* since they are no longer useful. |
1136 |
|
|
* |
1137 |
|
|
* First there was the word. |
1138 |
|
|
*/ |
1139 |
|
|
for (p = t = ecp->cp; |
1140 |
|
|
ecp->clen > 0; --ecp->clen, ++ecp->cp) { |
1141 |
|
|
ch = *ecp->cp; |
1142 |
|
|
if (IS_ESCAPE(sp, |
1143 |
|
|
ecp, ch) && ecp->clen > 1) { |
1144 |
|
|
--ecp->clen; |
1145 |
|
|
*p++ = *++ecp->cp; |
1146 |
|
|
} else if (isblank(ch)) { |
1147 |
|
|
++ecp->cp; |
1148 |
|
|
--ecp->clen; |
1149 |
|
|
break; |
1150 |
|
|
} else |
1151 |
|
|
*p++ = ch; |
1152 |
|
|
} |
1153 |
|
|
if (argv_exp0(sp, ecp, t, p - t)) |
1154 |
|
|
goto err; |
1155 |
|
|
|
1156 |
|
|
/* Delete intervening whitespace. */ |
1157 |
|
|
for (; ecp->clen > 0; |
1158 |
|
|
--ecp->clen, ++ecp->cp) { |
1159 |
|
|
ch = *ecp->cp; |
1160 |
|
|
if (!isblank(ch)) |
1161 |
|
|
break; |
1162 |
|
|
} |
1163 |
|
|
if (ecp->clen == 0) |
1164 |
|
|
goto usage; |
1165 |
|
|
|
1166 |
|
|
/* Followed by the string. */ |
1167 |
|
|
for (p = t = ecp->cp; ecp->clen > 0; |
1168 |
|
|
--ecp->clen, ++ecp->cp, ++p) { |
1169 |
|
|
ch = *ecp->cp; |
1170 |
|
|
if (IS_ESCAPE(sp, |
1171 |
|
|
ecp, ch) && ecp->clen > 1) { |
1172 |
|
|
--ecp->clen; |
1173 |
|
|
*p = *++ecp->cp; |
1174 |
|
|
} else |
1175 |
|
|
*p = ch; |
1176 |
|
|
} |
1177 |
|
|
if (argv_exp0(sp, ecp, t, p - t)) |
1178 |
|
|
goto err; |
1179 |
|
|
goto addr_verify; |
1180 |
|
|
case 'w': /* word */ |
1181 |
|
|
if (argv_exp3(sp, ecp, ecp->cp, ecp->clen)) |
1182 |
|
|
goto err; |
1183 |
|
|
arg_cnt_chk: if (*++p != 'N') { /* N */ |
1184 |
|
|
/* |
1185 |
|
|
* If a number is specified, must either be |
1186 |
|
|
* 0 or that number, if optional, and that |
1187 |
|
|
* number, if required. |
1188 |
|
|
*/ |
1189 |
|
|
tmp = *p - '0'; |
1190 |
|
|
if ((*++p != 'o' || exp->argsoff != 0) && |
1191 |
|
|
exp->argsoff != tmp) |
1192 |
|
|
goto usage; |
1193 |
|
|
} |
1194 |
|
|
goto addr_verify; |
1195 |
|
|
default: |
1196 |
|
|
msgq(sp, M_ERR, |
1197 |
|
|
"Internal syntax table error (%s: %s)", |
1198 |
|
|
ecp->cmd->name, KEY_NAME(sp, *p)); |
1199 |
|
|
} |
1200 |
|
|
} |
1201 |
|
|
|
1202 |
|
|
/* Skip trailing whitespace. */ |
1203 |
|
|
for (; ecp->clen > 0; --ecp->clen) { |
1204 |
|
|
ch = *ecp->cp++; |
1205 |
|
|
if (!isblank(ch)) |
1206 |
|
|
break; |
1207 |
|
|
} |
1208 |
|
|
|
1209 |
|
|
/* |
1210 |
|
|
* There shouldn't be anything left, and no more required fields, |
1211 |
|
|
* i.e neither 'l' or 'r' in the syntax string. |
1212 |
|
|
*/ |
1213 |
|
|
if (ecp->clen != 0 || strpbrk(p, "lr")) { |
1214 |
|
|
usage: msgq(sp, M_ERR, "Usage: %s", ecp->cmd->usage); |
1215 |
|
|
goto err; |
1216 |
|
|
} |
1217 |
|
|
|
1218 |
|
|
/* |
1219 |
|
|
* Verify that the addresses are legal. Check the addresses here, |
1220 |
|
|
* because this is a place where all ex addresses pass through. |
1221 |
|
|
* (They don't all pass through ex_line(), for instance.) We're |
1222 |
|
|
* assuming that any non-existent line doesn't exist because it's |
1223 |
|
|
* past the end-of-file. That's a pretty good guess. |
1224 |
|
|
* |
1225 |
|
|
* If it's a "default vi command", an address of zero is okay. |
1226 |
|
|
*/ |
1227 |
|
|
addr_verify: |
1228 |
|
|
switch (ecp->addrcnt) { |
1229 |
|
|
case 2: |
1230 |
|
|
/* |
1231 |
|
|
* Historic ex/vi permitted commands with counts to go past |
1232 |
|
|
* EOF. So, for example, if the file only had 5 lines, the |
1233 |
|
|
* ex command "1,6>" would fail, but the command ">300" |
1234 |
|
|
* would succeed. Since we don't want to have to make all |
1235 |
|
|
* of the underlying commands handle random line numbers, |
1236 |
|
|
* fix it here. |
1237 |
|
|
*/ |
1238 |
|
|
if (ecp->addr2.lno == 0) { |
1239 |
|
|
if (!F_ISSET(ecp, E_ADDR_ZERO) && |
1240 |
|
|
(F_ISSET(sp, SC_EX) || |
1241 |
|
|
!F_ISSET(ecp, E_USELASTCMD))) { |
1242 |
|
|
ex_badaddr(sp, ecp->cmd, A_ZERO, NUM_OK); |
1243 |
|
|
goto err; |
1244 |
|
|
} |
1245 |
|
|
} else if (!db_exist(sp, ecp->addr2.lno)) { |
1246 |
|
|
if (FL_ISSET(ecp->iflags, E_C_COUNT)) { |
1247 |
|
|
if (db_last(sp, &lno)) |
1248 |
|
|
goto err; |
1249 |
|
|
ecp->addr2.lno = lno; |
1250 |
|
|
} else { |
1251 |
|
|
ex_badaddr(sp, NULL, A_EOF, NUM_OK); |
1252 |
|
|
goto err; |
1253 |
|
|
} |
1254 |
|
|
} |
1255 |
|
|
/* FALLTHROUGH */ |
1256 |
|
|
case 1: |
1257 |
|
|
if (ecp->addr1.lno == 0) { |
1258 |
|
|
if (!F_ISSET(ecp, E_ADDR_ZERO) && |
1259 |
|
|
(F_ISSET(sp, SC_EX) || |
1260 |
|
|
!F_ISSET(ecp, E_USELASTCMD))) { |
1261 |
|
|
ex_badaddr(sp, ecp->cmd, A_ZERO, NUM_OK); |
1262 |
|
|
goto err; |
1263 |
|
|
} |
1264 |
|
|
} else if (!db_exist(sp, ecp->addr1.lno)) { |
1265 |
|
|
ex_badaddr(sp, NULL, A_EOF, NUM_OK); |
1266 |
|
|
goto err; |
1267 |
|
|
} |
1268 |
|
|
break; |
1269 |
|
|
} |
1270 |
|
|
|
1271 |
|
|
/* |
1272 |
|
|
* If doing a default command and there's nothing left on the line, |
1273 |
|
|
* vi just moves to the line. For example, ":3" and ":'a,'b" just |
1274 |
|
|
* move to line 3 and line 'b, respectively, but ":3|" prints line 3. |
1275 |
|
|
* |
1276 |
|
|
* !!! |
1277 |
|
|
* In addition, IF THE LINE CHANGES, move to the first nonblank of |
1278 |
|
|
* the line. |
1279 |
|
|
* |
1280 |
|
|
* !!! |
1281 |
|
|
* This is done before the absolute mark gets set; historically, |
1282 |
|
|
* "/a/,/b/" did NOT set vi's absolute mark, but "/a/,/b/d" did. |
1283 |
|
|
*/ |
1284 |
|
|
if ((F_ISSET(sp, SC_VI) || F_ISSET(ecp, E_NOPRDEF)) && |
1285 |
|
|
F_ISSET(ecp, E_USELASTCMD) && vi_address == 0) { |
1286 |
|
|
switch (ecp->addrcnt) { |
1287 |
|
|
case 2: |
1288 |
|
|
if (sp->lno != |
1289 |
|
|
(ecp->addr2.lno ? ecp->addr2.lno : 1)) { |
1290 |
|
|
sp->lno = |
1291 |
|
|
ecp->addr2.lno ? ecp->addr2.lno : 1; |
1292 |
|
|
sp->cno = 0; |
1293 |
|
|
(void)nonblank(sp, sp->lno, &sp->cno); |
1294 |
|
|
} |
1295 |
|
|
break; |
1296 |
|
|
case 1: |
1297 |
|
|
if (sp->lno != |
1298 |
|
|
(ecp->addr1.lno ? ecp->addr1.lno : 1)) { |
1299 |
|
|
sp->lno = |
1300 |
|
|
ecp->addr1.lno ? ecp->addr1.lno : 1; |
1301 |
|
|
sp->cno = 0; |
1302 |
|
|
(void)nonblank(sp, sp->lno, &sp->cno); |
1303 |
|
|
} |
1304 |
|
|
break; |
1305 |
|
|
} |
1306 |
|
|
ecp->cp = ecp->save_cmd; |
1307 |
|
|
ecp->clen = ecp->save_cmdlen; |
1308 |
|
|
goto loop; |
1309 |
|
|
} |
1310 |
|
|
|
1311 |
|
|
/* |
1312 |
|
|
* Set the absolute mark -- we have to set it for vi here, in case |
1313 |
|
|
* it's a compound command, e.g. ":5p|6" should set the absolute |
1314 |
|
|
* mark for vi. |
1315 |
|
|
*/ |
1316 |
|
|
if (F_ISSET(ecp, E_ABSMARK)) { |
1317 |
|
|
cur.lno = sp->lno; |
1318 |
|
|
cur.cno = sp->cno; |
1319 |
|
|
F_CLR(ecp, E_ABSMARK); |
1320 |
|
|
if (mark_set(sp, ABSMARK1, &cur, 1)) |
1321 |
|
|
goto err; |
1322 |
|
|
} |
1323 |
|
|
|
1324 |
|
|
#if defined(DEBUG) && defined(COMLOG) |
1325 |
|
|
ex_comlog(sp, ecp); |
1326 |
|
|
#endif |
1327 |
|
|
/* Increment the command count if not called from vi. */ |
1328 |
|
|
if (F_ISSET(sp, SC_EX)) |
1329 |
|
|
++sp->ccnt; |
1330 |
|
|
|
1331 |
|
|
/* |
1332 |
|
|
* If file state available, and not doing a global command, |
1333 |
|
|
* log the start of an action. |
1334 |
|
|
*/ |
1335 |
|
|
if (sp->ep != NULL && !F_ISSET(sp, SC_EX_GLOBAL)) |
1336 |
|
|
(void)log_cursor(sp); |
1337 |
|
|
|
1338 |
|
|
/* |
1339 |
|
|
* !!! |
1340 |
|
|
* There are two special commands for the purposes of this code: the |
1341 |
|
|
* default command (<carriage-return>) or the scrolling commands (^D |
1342 |
|
|
* and <EOF>) as the first non-<blank> characters in the line. |
1343 |
|
|
* |
1344 |
|
|
* If this is the first command in the command line, we received the |
1345 |
|
|
* command from the ex command loop and we're talking to a tty, and |
1346 |
|
|
* and there's nothing else on the command line, and it's one of the |
1347 |
|
|
* special commands, we move back up to the previous line, and erase |
1348 |
|
|
* the prompt character with the output. Since ex runs in canonical |
1349 |
|
|
* mode, we don't have to do anything else, a <newline> has already |
1350 |
|
|
* been echoed by the tty driver. It's OK if vi calls us -- we won't |
1351 |
|
|
* be in ex mode so we'll do nothing. |
1352 |
|
|
*/ |
1353 |
|
|
if (F_ISSET(ecp, E_NRSEP)) { |
1354 |
|
|
if (sp->ep != NULL && |
1355 |
|
|
F_ISSET(sp, SC_EX) && !F_ISSET(gp, G_SCRIPTED) && |
1356 |
|
|
(F_ISSET(ecp, E_USELASTCMD) || ecp->cmd == &cmds[C_SCROLL])) |
1357 |
|
|
gp->scr_ex_adjust(sp, EX_TERM_SCROLL); |
1358 |
|
|
F_CLR(ecp, E_NRSEP); |
1359 |
|
|
} |
1360 |
|
|
|
1361 |
|
|
/* |
1362 |
|
|
* Call the underlying function for the ex command. |
1363 |
|
|
* |
1364 |
|
|
* XXX |
1365 |
|
|
* Interrupts behave like errors, for now. |
1366 |
|
|
*/ |
1367 |
|
|
if (ecp->cmd->fn(sp, ecp) || INTERRUPTED(sp)) { |
1368 |
|
|
if (F_ISSET(gp, G_SCRIPTED)) |
1369 |
|
|
F_SET(sp, SC_EXIT_FORCE); |
1370 |
|
|
goto err; |
1371 |
|
|
} |
1372 |
|
|
|
1373 |
|
|
#ifdef DEBUG |
1374 |
|
|
/* Make sure no function left global temporary space locked. */ |
1375 |
|
|
if (F_ISSET(gp, G_TMP_INUSE)) { |
1376 |
|
|
F_CLR(gp, G_TMP_INUSE); |
1377 |
|
|
msgq(sp, M_ERR, "%s: temporary buffer not released", |
1378 |
|
|
ecp->cmd->name); |
1379 |
|
|
} |
1380 |
|
|
#endif |
1381 |
|
|
/* |
1382 |
|
|
* Ex displayed the number of lines modified immediately after each |
1383 |
|
|
* command, so the command "1,10d|1,10d" would display: |
1384 |
|
|
* |
1385 |
|
|
* 10 lines deleted |
1386 |
|
|
* 10 lines deleted |
1387 |
|
|
* <autoprint line> |
1388 |
|
|
* |
1389 |
|
|
* Executing ex commands from vi only reported the final modified |
1390 |
|
|
* lines message -- that's wrong enough that we don't match it. |
1391 |
|
|
*/ |
1392 |
|
|
if (F_ISSET(sp, SC_EX)) |
1393 |
|
|
mod_rpt(sp); |
1394 |
|
|
|
1395 |
|
|
/* |
1396 |
|
|
* Integrate any offset parsed by the underlying command, and make |
1397 |
|
|
* sure the referenced line exists. |
1398 |
|
|
* |
1399 |
|
|
* XXX |
1400 |
|
|
* May not match historic practice (which I've never been able to |
1401 |
|
|
* completely figure out.) For example, the '=' command from vi |
1402 |
|
|
* mode often got the offset wrong, and complained it was too large, |
1403 |
|
|
* but didn't seem to have a problem with the cursor. If anyone |
1404 |
|
|
* complains, ask them how it's supposed to work, they might know. |
1405 |
|
|
*/ |
1406 |
|
|
if (sp->ep != NULL && ecp->flagoff) { |
1407 |
|
|
if (ecp->flagoff < 0) { |
1408 |
|
|
if (sp->lno <= -ecp->flagoff) { |
1409 |
|
|
msgq(sp, M_ERR, |
1410 |
|
|
"Flag offset to before line 1"); |
1411 |
|
|
goto err; |
1412 |
|
|
} |
1413 |
|
|
} else { |
1414 |
|
|
if (!NPFITS(MAX_REC_NUMBER, sp->lno, ecp->flagoff)) { |
1415 |
|
|
ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); |
1416 |
|
|
goto err; |
1417 |
|
|
} |
1418 |
|
|
if (!db_exist(sp, sp->lno + ecp->flagoff)) { |
1419 |
|
|
msgq(sp, M_ERR, |
1420 |
|
|
"Flag offset past end-of-file"); |
1421 |
|
|
goto err; |
1422 |
|
|
} |
1423 |
|
|
} |
1424 |
|
|
sp->lno += ecp->flagoff; |
1425 |
|
|
} |
1426 |
|
|
|
1427 |
|
|
/* |
1428 |
|
|
* If the command executed successfully, we may want to display a line |
1429 |
|
|
* based on the autoprint option or an explicit print flag. (Make sure |
1430 |
|
|
* that there's a line to display.) Also, the autoprint edit option is |
1431 |
|
|
* turned off for the duration of global commands. |
1432 |
|
|
*/ |
1433 |
|
|
if (F_ISSET(sp, SC_EX) && sp->ep != NULL && sp->lno != 0) { |
1434 |
|
|
/* |
1435 |
|
|
* The print commands have already handled the `print' flags. |
1436 |
|
|
* If so, clear them. |
1437 |
|
|
*/ |
1438 |
|
|
if (FL_ISSET(ecp->iflags, E_CLRFLAG)) |
1439 |
|
|
FL_CLR(ecp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT); |
1440 |
|
|
|
1441 |
|
|
/* If hash set only because of the number option, discard it. */ |
1442 |
|
|
if (F_ISSET(ecp, E_OPTNUM)) |
1443 |
|
|
FL_CLR(ecp->iflags, E_C_HASH); |
1444 |
|
|
|
1445 |
|
|
/* |
1446 |
|
|
* If there was an explicit flag to display the new cursor line, |
1447 |
|
|
* or autoprint is set and a change was made, display the line. |
1448 |
|
|
* If any print flags were set use them, else default to print. |
1449 |
|
|
*/ |
1450 |
|
|
LF_INIT(FL_ISSET(ecp->iflags, E_C_HASH | E_C_LIST | E_C_PRINT)); |
1451 |
|
|
if (!LF_ISSET(E_C_HASH | E_C_LIST | E_C_PRINT | E_NOAUTO) && |
1452 |
|
|
!F_ISSET(sp, SC_EX_GLOBAL) && |
1453 |
|
|
O_ISSET(sp, O_AUTOPRINT) && F_ISSET(ecp, E_AUTOPRINT)) |
1454 |
|
|
LF_INIT(E_C_PRINT); |
1455 |
|
|
|
1456 |
|
|
if (LF_ISSET(E_C_HASH | E_C_LIST | E_C_PRINT)) { |
1457 |
|
|
cur.lno = sp->lno; |
1458 |
|
|
cur.cno = 0; |
1459 |
|
|
(void)ex_print(sp, ecp, &cur, &cur, flags); |
1460 |
|
|
} |
1461 |
|
|
} |
1462 |
|
|
|
1463 |
|
|
/* |
1464 |
|
|
* If the command had an associated "+cmd", it has to be executed |
1465 |
|
|
* before we finish executing any more of this ex command. For |
1466 |
|
|
* example, consider a .exrc file that contains the following lines: |
1467 |
|
|
* |
1468 |
|
|
* :set all |
1469 |
|
|
* :edit +25 file.c|s/abc/ABC/|1 |
1470 |
|
|
* :3,5 print |
1471 |
|
|
* |
1472 |
|
|
* This can happen more than once -- the historic vi simply hung or |
1473 |
|
|
* dropped core, of course. Prepend the + command back into the |
1474 |
|
|
* current command and continue. We may have to add an additional |
1475 |
|
|
* <literal next> character. We know that it will fit because we |
1476 |
|
|
* discarded at least one space and the + character. |
1477 |
|
|
*/ |
1478 |
|
|
if (arg1_len != 0) { |
1479 |
|
|
/* |
1480 |
|
|
* If the last character of the + command was a <literal next> |
1481 |
|
|
* character, it would be treated differently because of the |
1482 |
|
|
* append. Quote it, if necessary. |
1483 |
|
|
*/ |
1484 |
|
|
if (IS_ESCAPE(sp, ecp, arg1[arg1_len - 1])) { |
1485 |
|
|
*--ecp->save_cmd = CH_LITERAL; |
1486 |
|
|
++ecp->save_cmdlen; |
1487 |
|
|
} |
1488 |
|
|
|
1489 |
|
|
ecp->save_cmd -= arg1_len; |
1490 |
|
|
ecp->save_cmdlen += arg1_len; |
1491 |
|
|
memmove(ecp->save_cmd, arg1, arg1_len); |
1492 |
|
|
|
1493 |
|
|
/* |
1494 |
|
|
* Any commands executed from a +cmd are executed starting at |
1495 |
|
|
* the first column of the last line of the file -- NOT the |
1496 |
|
|
* first nonblank.) The main file startup code doesn't know |
1497 |
|
|
* that a +cmd was set, however, so it may have put us at the |
1498 |
|
|
* top of the file. (Note, this is safe because we must have |
1499 |
|
|
* switched files to get here.) |
1500 |
|
|
*/ |
1501 |
|
|
F_SET(ecp, E_MOVETOEND); |
1502 |
|
|
} |
1503 |
|
|
|
1504 |
|
|
/* Update the current command. */ |
1505 |
|
|
ecp->cp = ecp->save_cmd; |
1506 |
|
|
ecp->clen = ecp->save_cmdlen; |
1507 |
|
|
|
1508 |
|
|
/* |
1509 |
|
|
* !!! |
1510 |
|
|
* If we've changed screens or underlying files, any pending global or |
1511 |
|
|
* v command, or @ buffer that has associated addresses, has to be |
1512 |
|
|
* discarded. This is historic practice for globals, and necessary for |
1513 |
|
|
* @ buffers that had associated addresses. |
1514 |
|
|
* |
1515 |
|
|
* Otherwise, if we've changed underlying files, it's not a problem, |
1516 |
|
|
* we continue with the rest of the ex command(s), operating on the |
1517 |
|
|
* new file. However, if we switch screens (either by exiting or by |
1518 |
|
|
* an explicit command), we have no way of knowing where to put output |
1519 |
|
|
* messages, and, since we don't control screens here, we could screw |
1520 |
|
|
* up the upper layers, (e.g. we could exit/reenter a screen multiple |
1521 |
|
|
* times). So, return and continue after we've got a new screen. |
1522 |
|
|
*/ |
1523 |
|
|
if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_FSWITCH | SC_SSWITCH)) { |
1524 |
|
|
at_found = gv_found = 0; |
1525 |
|
|
LIST_FOREACH(ecp, &sp->gp->ecq, q) |
1526 |
|
|
switch (ecp->agv_flags) { |
1527 |
|
|
case 0: |
1528 |
|
|
case AGV_AT_NORANGE: |
1529 |
|
|
break; |
1530 |
|
|
case AGV_AT: |
1531 |
|
|
if (!at_found) { |
1532 |
|
|
at_found = 1; |
1533 |
|
|
msgq(sp, M_ERR, |
1534 |
|
|
"@ with range running when the file/screen changed"); |
1535 |
|
|
} |
1536 |
|
|
break; |
1537 |
|
|
case AGV_GLOBAL: |
1538 |
|
|
case AGV_V: |
1539 |
|
|
if (!gv_found) { |
1540 |
|
|
gv_found = 1; |
1541 |
|
|
msgq(sp, M_ERR, |
1542 |
|
|
"Global/v command running when the file/screen changed"); |
1543 |
|
|
} |
1544 |
|
|
break; |
1545 |
|
|
default: |
1546 |
|
|
abort(); |
1547 |
|
|
} |
1548 |
|
|
if (at_found || gv_found) |
1549 |
|
|
goto discard; |
1550 |
|
|
if (F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE | SC_SSWITCH)) |
1551 |
|
|
goto rsuccess; |
1552 |
|
|
} |
1553 |
|
|
|
1554 |
|
|
goto loop; |
1555 |
|
|
/* NOTREACHED */ |
1556 |
|
|
|
1557 |
|
|
err: /* |
1558 |
|
|
* On command failure, we discard keys and pending commands remaining, |
1559 |
|
|
* as well as any keys that were mapped and waiting. The save_cmdlen |
1560 |
|
|
* test is not necessarily correct. If we fail early enough we don't |
1561 |
|
|
* know if the entire string was a single command or not. Guess, as |
1562 |
|
|
* it's useful to know if commands other than the current one are being |
1563 |
|
|
* discarded. |
1564 |
|
|
*/ |
1565 |
|
|
if (ecp->save_cmdlen == 0) |
1566 |
|
|
for (; ecp->clen; --ecp->clen) { |
1567 |
|
|
ch = *ecp->cp++; |
1568 |
|
|
if (IS_ESCAPE(sp, ecp, ch) && ecp->clen > 1) { |
1569 |
|
|
--ecp->clen; |
1570 |
|
|
++ecp->cp; |
1571 |
|
|
} else if (ch == '\n' || ch == '|') { |
1572 |
|
|
if (ecp->clen > 1) |
1573 |
|
|
ecp->save_cmdlen = 1; |
1574 |
|
|
break; |
1575 |
|
|
} |
1576 |
|
|
} |
1577 |
|
|
if (ecp->save_cmdlen != 0 || LIST_FIRST(&gp->ecq) != &gp->excmd) { |
1578 |
|
|
discard: msgq(sp, M_BERR, |
1579 |
|
|
"Ex command failed: pending commands discarded"); |
1580 |
|
|
ex_discard(sp); |
1581 |
|
|
} |
1582 |
|
|
if (v_event_flush(sp, CH_MAPPED)) |
1583 |
|
|
msgq(sp, M_BERR, |
1584 |
|
|
"Ex command failed: mapped keys discarded"); |
1585 |
|
|
|
1586 |
|
|
rfail: tmp = 1; |
1587 |
|
|
if (0) |
1588 |
|
|
rsuccess: tmp = 0; |
1589 |
|
|
|
1590 |
|
|
/* Turn off any file name error information. */ |
1591 |
|
|
gp->if_name = NULL; |
1592 |
|
|
|
1593 |
|
|
/* Turn off the global bit. */ |
1594 |
|
|
F_CLR(sp, SC_EX_GLOBAL); |
1595 |
|
|
|
1596 |
|
|
return (tmp); |
1597 |
|
|
} |
1598 |
|
|
|
1599 |
|
|
/* |
1600 |
|
|
* ex_range -- |
1601 |
|
|
* Get a line range for ex commands, or perform a vi ex address search. |
1602 |
|
|
* |
1603 |
|
|
* PUBLIC: int ex_range(SCR *, EXCMD *, int *); |
1604 |
|
|
*/ |
1605 |
|
|
int |
1606 |
|
|
ex_range(SCR *sp, EXCMD *ecp, int *errp) |
1607 |
|
|
{ |
1608 |
|
|
enum { ADDR_FOUND, ADDR_NEED, ADDR_NONE } addr; |
1609 |
|
|
MARK m; |
1610 |
|
|
int isaddr; |
1611 |
|
|
|
1612 |
|
|
*errp = 0; |
1613 |
|
|
|
1614 |
|
|
/* |
1615 |
|
|
* Parse comma or semi-colon delimited line specs. |
1616 |
|
|
* |
1617 |
|
|
* Semi-colon delimiters update the current address to be the last |
1618 |
|
|
* address. For example, the command |
1619 |
|
|
* |
1620 |
|
|
* :3;/pattern/ecp->cp |
1621 |
|
|
* |
1622 |
|
|
* will search for pattern from line 3. In addition, if ecp->cp |
1623 |
|
|
* is not a valid command, the current line will be left at 3, not |
1624 |
|
|
* at the original address. |
1625 |
|
|
* |
1626 |
|
|
* Extra addresses are discarded, starting with the first. |
1627 |
|
|
* |
1628 |
|
|
* !!! |
1629 |
|
|
* If any addresses are missing, they default to the current line. |
1630 |
|
|
* This was historically true for both leading and trailing comma |
1631 |
|
|
* delimited addresses as well as for trailing semicolon delimited |
1632 |
|
|
* addresses. For consistency, we make it true for leading semicolon |
1633 |
|
|
* addresses as well. |
1634 |
|
|
*/ |
1635 |
|
|
for (addr = ADDR_NONE, ecp->addrcnt = 0; ecp->clen > 0;) |
1636 |
|
|
switch (*ecp->cp) { |
1637 |
|
|
case '%': /* Entire file. */ |
1638 |
|
|
/* Vi ex address searches didn't permit % signs. */ |
1639 |
|
|
if (F_ISSET(ecp, E_VISEARCH)) |
1640 |
|
|
goto ret; |
1641 |
|
|
|
1642 |
|
|
/* It's an error if the file is empty. */ |
1643 |
|
|
if (sp->ep == NULL) { |
1644 |
|
|
ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); |
1645 |
|
|
*errp = 1; |
1646 |
|
|
return (0); |
1647 |
|
|
} |
1648 |
|
|
/* |
1649 |
|
|
* !!! |
1650 |
|
|
* A percent character addresses all of the lines in |
1651 |
|
|
* the file. Historically, it couldn't be followed by |
1652 |
|
|
* any other address. We do it as a text substitution |
1653 |
|
|
* for simplicity. POSIX 1003.2 is expected to follow |
1654 |
|
|
* this practice. |
1655 |
|
|
* |
1656 |
|
|
* If it's an empty file, the first line is 0, not 1. |
1657 |
|
|
*/ |
1658 |
|
|
if (addr == ADDR_FOUND) { |
1659 |
|
|
ex_badaddr(sp, NULL, A_COMBO, NUM_OK); |
1660 |
|
|
*errp = 1; |
1661 |
|
|
return (0); |
1662 |
|
|
} |
1663 |
|
|
if (db_last(sp, &ecp->addr2.lno)) |
1664 |
|
|
return (1); |
1665 |
|
|
ecp->addr1.lno = ecp->addr2.lno == 0 ? 0 : 1; |
1666 |
|
|
ecp->addr1.cno = ecp->addr2.cno = 0; |
1667 |
|
|
ecp->addrcnt = 2; |
1668 |
|
|
addr = ADDR_FOUND; |
1669 |
|
|
++ecp->cp; |
1670 |
|
|
--ecp->clen; |
1671 |
|
|
break; |
1672 |
|
|
case ',': /* Comma delimiter. */ |
1673 |
|
|
/* Vi ex address searches didn't permit commas. */ |
1674 |
|
|
if (F_ISSET(ecp, E_VISEARCH)) |
1675 |
|
|
goto ret; |
1676 |
|
|
/* FALLTHROUGH */ |
1677 |
|
|
case ';': /* Semi-colon delimiter. */ |
1678 |
|
|
if (sp->ep == NULL) { |
1679 |
|
|
ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); |
1680 |
|
|
*errp = 1; |
1681 |
|
|
return (0); |
1682 |
|
|
} |
1683 |
|
|
if (addr != ADDR_FOUND) |
1684 |
|
|
switch (ecp->addrcnt) { |
1685 |
|
|
case 0: |
1686 |
|
|
ecp->addr1.lno = sp->lno; |
1687 |
|
|
ecp->addr1.cno = sp->cno; |
1688 |
|
|
ecp->addrcnt = 1; |
1689 |
|
|
break; |
1690 |
|
|
case 2: |
1691 |
|
|
ecp->addr1 = ecp->addr2; |
1692 |
|
|
/* FALLTHROUGH */ |
1693 |
|
|
case 1: |
1694 |
|
|
ecp->addr2.lno = sp->lno; |
1695 |
|
|
ecp->addr2.cno = sp->cno; |
1696 |
|
|
ecp->addrcnt = 2; |
1697 |
|
|
break; |
1698 |
|
|
} |
1699 |
|
|
if (*ecp->cp == ';') |
1700 |
|
|
switch (ecp->addrcnt) { |
1701 |
|
|
case 0: |
1702 |
|
|
abort(); |
1703 |
|
|
/* NOTREACHED */ |
1704 |
|
|
case 1: |
1705 |
|
|
sp->lno = ecp->addr1.lno; |
1706 |
|
|
sp->cno = ecp->addr1.cno; |
1707 |
|
|
break; |
1708 |
|
|
case 2: |
1709 |
|
|
sp->lno = ecp->addr2.lno; |
1710 |
|
|
sp->cno = ecp->addr2.cno; |
1711 |
|
|
break; |
1712 |
|
|
} |
1713 |
|
|
addr = ADDR_NEED; |
1714 |
|
|
/* FALLTHROUGH */ |
1715 |
|
|
case ' ': /* Whitespace. */ |
1716 |
|
|
case '\t': /* Whitespace. */ |
1717 |
|
|
++ecp->cp; |
1718 |
|
|
--ecp->clen; |
1719 |
|
|
break; |
1720 |
|
|
default: |
1721 |
|
|
/* Get a line specification. */ |
1722 |
|
|
if (ex_line(sp, ecp, &m, &isaddr, errp)) |
1723 |
|
|
return (1); |
1724 |
|
|
if (*errp) |
1725 |
|
|
return (0); |
1726 |
|
|
if (!isaddr) |
1727 |
|
|
goto ret; |
1728 |
|
|
if (addr == ADDR_FOUND) { |
1729 |
|
|
ex_badaddr(sp, NULL, A_COMBO, NUM_OK); |
1730 |
|
|
*errp = 1; |
1731 |
|
|
return (0); |
1732 |
|
|
} |
1733 |
|
|
switch (ecp->addrcnt) { |
1734 |
|
|
case 0: |
1735 |
|
|
ecp->addr1 = m; |
1736 |
|
|
ecp->addrcnt = 1; |
1737 |
|
|
break; |
1738 |
|
|
case 1: |
1739 |
|
|
ecp->addr2 = m; |
1740 |
|
|
ecp->addrcnt = 2; |
1741 |
|
|
break; |
1742 |
|
|
case 2: |
1743 |
|
|
ecp->addr1 = ecp->addr2; |
1744 |
|
|
ecp->addr2 = m; |
1745 |
|
|
break; |
1746 |
|
|
} |
1747 |
|
|
addr = ADDR_FOUND; |
1748 |
|
|
break; |
1749 |
|
|
} |
1750 |
|
|
|
1751 |
|
|
/* |
1752 |
|
|
* !!! |
1753 |
|
|
* Vi ex address searches are indifferent to order or trailing |
1754 |
|
|
* semi-colons. |
1755 |
|
|
*/ |
1756 |
|
|
ret: if (F_ISSET(ecp, E_VISEARCH)) |
1757 |
|
|
return (0); |
1758 |
|
|
|
1759 |
|
|
if (addr == ADDR_NEED) |
1760 |
|
|
switch (ecp->addrcnt) { |
1761 |
|
|
case 0: |
1762 |
|
|
ecp->addr1.lno = sp->lno; |
1763 |
|
|
ecp->addr1.cno = sp->cno; |
1764 |
|
|
ecp->addrcnt = 1; |
1765 |
|
|
break; |
1766 |
|
|
case 2: |
1767 |
|
|
ecp->addr1 = ecp->addr2; |
1768 |
|
|
/* FALLTHROUGH */ |
1769 |
|
|
case 1: |
1770 |
|
|
ecp->addr2.lno = sp->lno; |
1771 |
|
|
ecp->addr2.cno = sp->cno; |
1772 |
|
|
ecp->addrcnt = 2; |
1773 |
|
|
break; |
1774 |
|
|
} |
1775 |
|
|
|
1776 |
|
|
if (ecp->addrcnt == 2 && ecp->addr2.lno < ecp->addr1.lno) { |
1777 |
|
|
msgq(sp, M_ERR, |
1778 |
|
|
"The second address is smaller than the first"); |
1779 |
|
|
*errp = 1; |
1780 |
|
|
} |
1781 |
|
|
return (0); |
1782 |
|
|
} |
1783 |
|
|
|
1784 |
|
|
/* |
1785 |
|
|
* ex_line -- |
1786 |
|
|
* Get a single line address specifier. |
1787 |
|
|
* |
1788 |
|
|
* The way the "previous context" mark worked was that any "non-relative" |
1789 |
|
|
* motion set it. While ex/vi wasn't totally consistent about this, ANY |
1790 |
|
|
* numeric address, search pattern, '$', or mark reference in an address |
1791 |
|
|
* was considered non-relative, and set the value. Which should explain |
1792 |
|
|
* why we're hacking marks down here. The problem was that the mark was |
1793 |
|
|
* only set if the command was called, i.e. we have to set a flag and test |
1794 |
|
|
* it later. |
1795 |
|
|
* |
1796 |
|
|
* XXX |
1797 |
|
|
* This is probably still not exactly historic practice, although I think |
1798 |
|
|
* it's fairly close. |
1799 |
|
|
*/ |
1800 |
|
|
static int |
1801 |
|
|
ex_line(SCR *sp, EXCMD *ecp, MARK *mp, int *isaddrp, int *errp) |
1802 |
|
|
{ |
1803 |
|
|
enum nresult nret; |
1804 |
|
|
long total, val; |
1805 |
|
|
int isneg; |
1806 |
|
|
int (*sf)(SCR *, MARK *, MARK *, char *, size_t, char **, u_int); |
1807 |
|
|
char *endp; |
1808 |
|
|
|
1809 |
|
|
*isaddrp = *errp = 0; |
1810 |
|
|
F_CLR(ecp, E_DELTA); |
1811 |
|
|
|
1812 |
|
|
/* No addresses permitted until a file has been read in. */ |
1813 |
|
|
if (sp->ep == NULL && strchr("$0123456789'\\/?.+-^", *ecp->cp)) { |
1814 |
|
|
ex_badaddr(sp, NULL, A_EMPTY, NUM_OK); |
1815 |
|
|
*errp = 1; |
1816 |
|
|
return (0); |
1817 |
|
|
} |
1818 |
|
|
|
1819 |
|
|
switch (*ecp->cp) { |
1820 |
|
|
case '$': /* Last line in the file. */ |
1821 |
|
|
*isaddrp = 1; |
1822 |
|
|
F_SET(ecp, E_ABSMARK); |
1823 |
|
|
|
1824 |
|
|
mp->cno = 0; |
1825 |
|
|
if (db_last(sp, &mp->lno)) |
1826 |
|
|
return (1); |
1827 |
|
|
++ecp->cp; |
1828 |
|
|
--ecp->clen; |
1829 |
|
|
break; /* Absolute line number. */ |
1830 |
|
|
case '0': case '1': case '2': case '3': case '4': |
1831 |
|
|
case '5': case '6': case '7': case '8': case '9': |
1832 |
|
|
*isaddrp = 1; |
1833 |
|
|
F_SET(ecp, E_ABSMARK); |
1834 |
|
|
|
1835 |
|
|
if ((nret = nget_slong(&val, ecp->cp, &endp, 10)) != NUM_OK) { |
1836 |
|
|
ex_badaddr(sp, NULL, A_NOTSET, nret); |
1837 |
|
|
*errp = 1; |
1838 |
|
|
return (0); |
1839 |
|
|
} |
1840 |
|
|
if (!NPFITS(MAX_REC_NUMBER, 0, val)) { |
1841 |
|
|
ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); |
1842 |
|
|
*errp = 1; |
1843 |
|
|
return (0); |
1844 |
|
|
} |
1845 |
|
|
mp->lno = val; |
1846 |
|
|
mp->cno = 0; |
1847 |
|
|
ecp->clen -= (endp - ecp->cp); |
1848 |
|
|
ecp->cp = endp; |
1849 |
|
|
break; |
1850 |
|
|
case '\'': /* Use a mark. */ |
1851 |
|
|
*isaddrp = 1; |
1852 |
|
|
F_SET(ecp, E_ABSMARK); |
1853 |
|
|
|
1854 |
|
|
if (ecp->clen == 1) { |
1855 |
|
|
msgq(sp, M_ERR, "No mark name supplied"); |
1856 |
|
|
*errp = 1; |
1857 |
|
|
return (0); |
1858 |
|
|
} |
1859 |
|
|
if (mark_get(sp, ecp->cp[1], mp, M_ERR)) { |
1860 |
|
|
*errp = 1; |
1861 |
|
|
return (0); |
1862 |
|
|
} |
1863 |
|
|
ecp->cp += 2; |
1864 |
|
|
ecp->clen -= 2; |
1865 |
|
|
break; |
1866 |
|
|
case '\\': /* Search: forward/backward. */ |
1867 |
|
|
/* |
1868 |
|
|
* !!! |
1869 |
|
|
* I can't find any difference between // and \/ or between |
1870 |
|
|
* ?? and \?. Mark Horton doesn't remember there being any |
1871 |
|
|
* difference. C'est la vie. |
1872 |
|
|
*/ |
1873 |
|
|
if (ecp->clen < 2 || |
1874 |
|
|
(ecp->cp[1] != '/' && ecp->cp[1] != '?')) { |
1875 |
|
|
msgq(sp, M_ERR, "\\ not followed by / or ?"); |
1876 |
|
|
*errp = 1; |
1877 |
|
|
return (0); |
1878 |
|
|
} |
1879 |
|
|
++ecp->cp; |
1880 |
|
|
--ecp->clen; |
1881 |
|
|
sf = ecp->cp[0] == '/' ? f_search : b_search; |
1882 |
|
|
goto search; |
1883 |
|
|
case '/': /* Search forward. */ |
1884 |
|
|
sf = f_search; |
1885 |
|
|
goto search; |
1886 |
|
|
case '?': /* Search backward. */ |
1887 |
|
|
sf = b_search; |
1888 |
|
|
|
1889 |
|
|
search: mp->lno = sp->lno; |
1890 |
|
|
mp->cno = sp->cno; |
1891 |
|
|
if (sf(sp, mp, mp, ecp->cp, ecp->clen, &endp, |
1892 |
|
|
SEARCH_MSG | SEARCH_PARSE | SEARCH_SET | |
1893 |
|
|
(F_ISSET(ecp, E_SEARCH_WMSG) ? SEARCH_WMSG : 0))) { |
1894 |
|
|
*errp = 1; |
1895 |
|
|
return (0); |
1896 |
|
|
} |
1897 |
|
|
|
1898 |
|
|
/* Fix up the command pointers. */ |
1899 |
|
|
ecp->clen -= (endp - ecp->cp); |
1900 |
|
|
ecp->cp = endp; |
1901 |
|
|
|
1902 |
|
|
*isaddrp = 1; |
1903 |
|
|
F_SET(ecp, E_ABSMARK); |
1904 |
|
|
break; |
1905 |
|
|
case '.': /* Current position. */ |
1906 |
|
|
*isaddrp = 1; |
1907 |
|
|
mp->cno = sp->cno; |
1908 |
|
|
|
1909 |
|
|
/* If an empty file, then '.' is 0, not 1. */ |
1910 |
|
|
if (sp->lno == 1) { |
1911 |
|
|
if (db_last(sp, &mp->lno)) |
1912 |
|
|
return (1); |
1913 |
|
|
if (mp->lno != 0) |
1914 |
|
|
mp->lno = 1; |
1915 |
|
|
} else |
1916 |
|
|
mp->lno = sp->lno; |
1917 |
|
|
|
1918 |
|
|
/* |
1919 |
|
|
* !!! |
1920 |
|
|
* Historically, .<number> was the same as .+<number>, i.e. |
1921 |
|
|
* the '+' could be omitted. (This feature is found in ed |
1922 |
|
|
* as well.) |
1923 |
|
|
*/ |
1924 |
|
|
if (ecp->clen > 1 && isdigit(ecp->cp[1])) |
1925 |
|
|
*ecp->cp = '+'; |
1926 |
|
|
else { |
1927 |
|
|
++ecp->cp; |
1928 |
|
|
--ecp->clen; |
1929 |
|
|
} |
1930 |
|
|
break; |
1931 |
|
|
} |
1932 |
|
|
|
1933 |
|
|
/* Skip trailing <blank>s. */ |
1934 |
|
|
for (; ecp->clen > 0 && |
1935 |
|
|
isblank(ecp->cp[0]); ++ecp->cp, --ecp->clen); |
1936 |
|
|
|
1937 |
|
|
/* |
1938 |
|
|
* Evaluate any offset. If no address yet found, the offset |
1939 |
|
|
* is relative to ".". |
1940 |
|
|
*/ |
1941 |
|
|
total = 0; |
1942 |
|
|
if (ecp->clen != 0 && (isdigit(ecp->cp[0]) || |
1943 |
|
|
ecp->cp[0] == '+' || ecp->cp[0] == '-' || |
1944 |
|
|
ecp->cp[0] == '^')) { |
1945 |
|
|
if (!*isaddrp) { |
1946 |
|
|
*isaddrp = 1; |
1947 |
|
|
mp->lno = sp->lno; |
1948 |
|
|
mp->cno = sp->cno; |
1949 |
|
|
} |
1950 |
|
|
/* |
1951 |
|
|
* Evaluate an offset, defined as: |
1952 |
|
|
* |
1953 |
|
|
* [+-^<blank>]*[<blank>]*[0-9]* |
1954 |
|
|
* |
1955 |
|
|
* The rough translation is any number of signs, optionally |
1956 |
|
|
* followed by numbers, or a number by itself, all <blank> |
1957 |
|
|
* separated. |
1958 |
|
|
* |
1959 |
|
|
* !!! |
1960 |
|
|
* All address offsets were additive, e.g. "2 2 3p" was the |
1961 |
|
|
* same as "7p", or, "/ZZZ/ 2" was the same as "/ZZZ/+2". |
1962 |
|
|
* Note, however, "2 /ZZZ/" was an error. It was also legal |
1963 |
|
|
* to insert signs without numbers, so "3 - 2" was legal, and |
1964 |
|
|
* equal to 4. |
1965 |
|
|
* |
1966 |
|
|
* !!! |
1967 |
|
|
* Offsets were historically permitted for any line address, |
1968 |
|
|
* e.g. the command "1,2 copy 2 2 2 2" copied lines 1,2 after |
1969 |
|
|
* line 8. |
1970 |
|
|
* |
1971 |
|
|
* !!! |
1972 |
|
|
* Offsets were historically permitted for search commands, |
1973 |
|
|
* and handled as addresses: "/pattern/2 2 2" was legal, and |
1974 |
|
|
* referenced the 6th line after pattern. |
1975 |
|
|
*/ |
1976 |
|
|
F_SET(ecp, E_DELTA); |
1977 |
|
|
for (;;) { |
1978 |
|
|
for (; ecp->clen > 0 && isblank(ecp->cp[0]); |
1979 |
|
|
++ecp->cp, --ecp->clen); |
1980 |
|
|
if (ecp->clen == 0 || (!isdigit(ecp->cp[0]) && |
1981 |
|
|
ecp->cp[0] != '+' && ecp->cp[0] != '-' && |
1982 |
|
|
ecp->cp[0] != '^')) |
1983 |
|
|
break; |
1984 |
|
|
if (!isdigit(ecp->cp[0]) && |
1985 |
|
|
!isdigit(ecp->cp[1])) { |
1986 |
|
|
total += ecp->cp[0] == '+' ? 1 : -1; |
1987 |
|
|
--ecp->clen; |
1988 |
|
|
++ecp->cp; |
1989 |
|
|
} else { |
1990 |
|
|
if (ecp->cp[0] == '-' || |
1991 |
|
|
ecp->cp[0] == '^') { |
1992 |
|
|
++ecp->cp; |
1993 |
|
|
--ecp->clen; |
1994 |
|
|
isneg = 1; |
1995 |
|
|
} else |
1996 |
|
|
isneg = 0; |
1997 |
|
|
|
1998 |
|
|
/* Get a signed long, add it to the total. */ |
1999 |
|
|
if ((nret = nget_slong(&val, |
2000 |
|
|
ecp->cp, &endp, 10)) != NUM_OK || |
2001 |
|
|
(nret = NADD_SLONG(total, val)) != NUM_OK) { |
2002 |
|
|
ex_badaddr(sp, NULL, A_NOTSET, nret); |
2003 |
|
|
*errp = 1; |
2004 |
|
|
return (0); |
2005 |
|
|
} |
2006 |
|
|
total += isneg ? -val : val; |
2007 |
|
|
ecp->clen -= (endp - ecp->cp); |
2008 |
|
|
ecp->cp = endp; |
2009 |
|
|
} |
2010 |
|
|
} |
2011 |
|
|
} |
2012 |
|
|
|
2013 |
|
|
/* |
2014 |
|
|
* Any value less than 0 is an error. Make sure that the new value |
2015 |
|
|
* will fit into a recno_t. |
2016 |
|
|
*/ |
2017 |
|
|
if (*isaddrp && total != 0) { |
2018 |
|
|
if (total < 0) { |
2019 |
|
|
if (-total > mp->lno) { |
2020 |
|
|
msgq(sp, M_ERR, |
2021 |
|
|
"Reference to a line number less than 0"); |
2022 |
|
|
*errp = 1; |
2023 |
|
|
return (0); |
2024 |
|
|
} |
2025 |
|
|
} else |
2026 |
|
|
if (!NPFITS(MAX_REC_NUMBER, mp->lno, total)) { |
2027 |
|
|
ex_badaddr(sp, NULL, A_NOTSET, NUM_OVER); |
2028 |
|
|
*errp = 1; |
2029 |
|
|
return (0); |
2030 |
|
|
} |
2031 |
|
|
mp->lno += total; |
2032 |
|
|
} |
2033 |
|
|
return (0); |
2034 |
|
|
} |
2035 |
|
|
|
2036 |
|
|
|
2037 |
|
|
/* |
2038 |
|
|
* ex_load -- |
2039 |
|
|
* Load up the next command, which may be an @ buffer or global command. |
2040 |
|
|
*/ |
2041 |
|
|
static int |
2042 |
|
|
ex_load(SCR *sp) |
2043 |
|
|
{ |
2044 |
|
|
GS *gp; |
2045 |
|
|
EXCMD *ecp; |
2046 |
|
|
RANGE *rp; |
2047 |
|
|
|
2048 |
|
|
F_CLR(sp, SC_EX_GLOBAL); |
2049 |
|
|
|
2050 |
|
|
/* |
2051 |
|
|
* Lose any exhausted commands. We know that the first command |
2052 |
|
|
* can't be an AGV command, which makes things a bit easier. |
2053 |
|
|
*/ |
2054 |
|
|
for (gp = sp->gp;;) { |
2055 |
|
|
/* |
2056 |
|
|
* If we're back to the original structure, leave it around, |
2057 |
|
|
* but discard any allocated source name, we've returned to |
2058 |
|
|
* the beginning of the command stack. |
2059 |
|
|
*/ |
2060 |
|
|
if ((ecp = LIST_FIRST(&gp->ecq)) == &gp->excmd) { |
2061 |
|
|
if (F_ISSET(ecp, E_NAMEDISCARD)) { |
2062 |
|
|
free(ecp->if_name); |
2063 |
|
|
ecp->if_name = NULL; |
2064 |
|
|
} |
2065 |
|
|
return (0); |
2066 |
|
|
} |
2067 |
|
|
|
2068 |
|
|
/* |
2069 |
|
|
* ecp->clen will be 0 for the first discarded command, but |
2070 |
|
|
* may not be 0 for subsequent ones, e.g. if the original |
2071 |
|
|
* command was ":g/xx/@a|s/b/c/", then when we discard the |
2072 |
|
|
* command pushed on the stack by the @a, we have to resume |
2073 |
|
|
* the global command which included the substitute command. |
2074 |
|
|
*/ |
2075 |
|
|
if (ecp->clen != 0) |
2076 |
|
|
return (0); |
2077 |
|
|
|
2078 |
|
|
/* |
2079 |
|
|
* If it's an @, global or v command, we may need to continue |
2080 |
|
|
* the command on a different line. |
2081 |
|
|
*/ |
2082 |
|
|
if (FL_ISSET(ecp->agv_flags, AGV_ALL)) { |
2083 |
|
|
/* Discard any exhausted ranges. */ |
2084 |
|
|
while ((rp = TAILQ_FIRST(&ecp->rq))) { |
2085 |
|
|
if (rp->start > rp->stop) { |
2086 |
|
|
TAILQ_REMOVE(&ecp->rq, rp, q); |
2087 |
|
|
free(rp); |
2088 |
|
|
} else |
2089 |
|
|
break; |
2090 |
|
|
} |
2091 |
|
|
|
2092 |
|
|
/* If there's another range, continue with it. */ |
2093 |
|
|
if (rp) |
2094 |
|
|
break; |
2095 |
|
|
|
2096 |
|
|
/* If it's a global/v command, fix up the last line. */ |
2097 |
|
|
if (FL_ISSET(ecp->agv_flags, |
2098 |
|
|
AGV_GLOBAL | AGV_V) && ecp->range_lno != OOBLNO) { |
2099 |
|
|
if (db_exist(sp, ecp->range_lno)) |
2100 |
|
|
sp->lno = ecp->range_lno; |
2101 |
|
|
else { |
2102 |
|
|
if (db_last(sp, &sp->lno)) |
2103 |
|
|
return (1); |
2104 |
|
|
if (sp->lno == 0) |
2105 |
|
|
sp->lno = 1; |
2106 |
|
|
} |
2107 |
|
|
} |
2108 |
|
|
free(ecp->o_cp); |
2109 |
|
|
} |
2110 |
|
|
|
2111 |
|
|
/* Discard the EXCMD. */ |
2112 |
|
|
LIST_REMOVE(ecp, q); |
2113 |
|
|
free(ecp); |
2114 |
|
|
} |
2115 |
|
|
|
2116 |
|
|
/* |
2117 |
|
|
* We only get here if it's an active @, global or v command. Set |
2118 |
|
|
* the current line number, and get a new copy of the command for |
2119 |
|
|
* the parser. Note, the original pointer almost certainly moved, |
2120 |
|
|
* so we have play games. |
2121 |
|
|
*/ |
2122 |
|
|
ecp->cp = ecp->o_cp; |
2123 |
|
|
memcpy(ecp->cp, ecp->cp + ecp->o_clen, ecp->o_clen); |
2124 |
|
|
ecp->clen = ecp->o_clen; |
2125 |
|
|
ecp->range_lno = sp->lno = rp->start++; |
2126 |
|
|
|
2127 |
|
|
if (FL_ISSET(ecp->agv_flags, AGV_GLOBAL | AGV_V)) |
2128 |
|
|
F_SET(sp, SC_EX_GLOBAL); |
2129 |
|
|
return (0); |
2130 |
|
|
} |
2131 |
|
|
|
2132 |
|
|
/* |
2133 |
|
|
* ex_discard -- |
2134 |
|
|
* Discard any pending ex commands. |
2135 |
|
|
*/ |
2136 |
|
|
static int |
2137 |
|
|
ex_discard(SCR *sp) |
2138 |
|
|
{ |
2139 |
|
|
GS *gp; |
2140 |
|
|
EXCMD *ecp; |
2141 |
|
|
RANGE *rp; |
2142 |
|
|
|
2143 |
|
|
/* |
2144 |
|
|
* We know the first command can't be an AGV command, so we don't |
2145 |
|
|
* process it specially. We do, however, nail the command itself. |
2146 |
|
|
*/ |
2147 |
|
|
for (gp = sp->gp; (ecp = LIST_FIRST(&gp->ecq)) != &gp->excmd;) { |
2148 |
|
|
if (FL_ISSET(ecp->agv_flags, AGV_ALL)) { |
2149 |
|
|
while ((rp = TAILQ_FIRST(&ecp->rq))) { |
2150 |
|
|
TAILQ_REMOVE(&ecp->rq, rp, q); |
2151 |
|
|
free(rp); |
2152 |
|
|
} |
2153 |
|
|
free(ecp->o_cp); |
2154 |
|
|
} |
2155 |
|
|
LIST_REMOVE(ecp, q); |
2156 |
|
|
free(ecp); |
2157 |
|
|
} |
2158 |
|
|
LIST_FIRST(&gp->ecq)->clen = 0; |
2159 |
|
|
return (0); |
2160 |
|
|
} |
2161 |
|
|
|
2162 |
|
|
/* |
2163 |
|
|
* ex_unknown -- |
2164 |
|
|
* Display an unknown command name. |
2165 |
|
|
*/ |
2166 |
|
|
static void |
2167 |
|
|
ex_unknown(SCR *sp, char *cmd, size_t len) |
2168 |
|
|
{ |
2169 |
|
|
size_t blen; |
2170 |
|
|
char *bp; |
2171 |
|
|
|
2172 |
|
|
GET_SPACE_GOTO(sp, bp, blen, len + 1); |
2173 |
|
|
bp[len] = '\0'; |
2174 |
|
|
memcpy(bp, cmd, len); |
2175 |
|
|
msgq_str(sp, M_ERR, bp, "The %s command is unknown"); |
2176 |
|
|
FREE_SPACE(sp, bp, blen); |
2177 |
|
|
|
2178 |
|
|
alloc_err: |
2179 |
|
|
return; |
2180 |
|
|
} |
2181 |
|
|
|
2182 |
|
|
/* |
2183 |
|
|
* ex_is_abbrev - |
2184 |
|
|
* The vi text input routine needs to know if ex thinks this is an |
2185 |
|
|
* [un]abbreviate command, so it can turn off abbreviations. See |
2186 |
|
|
* the usual ranting in the vi/v_txt_ev.c:txt_abbrev() routine. |
2187 |
|
|
* |
2188 |
|
|
* PUBLIC: int ex_is_abbrev(char *, size_t); |
2189 |
|
|
*/ |
2190 |
|
|
int |
2191 |
|
|
ex_is_abbrev(char *name, size_t len) |
2192 |
|
|
{ |
2193 |
|
|
EXCMDLIST const *cp; |
2194 |
|
|
|
2195 |
|
|
return ((cp = ex_comm_search(name, len)) != NULL && |
2196 |
|
|
(cp == &cmds[C_ABBR] || cp == &cmds[C_UNABBREVIATE])); |
2197 |
|
|
} |
2198 |
|
|
|
2199 |
|
|
/* |
2200 |
|
|
* ex_is_unmap - |
2201 |
|
|
* The vi text input routine needs to know if ex thinks this is an |
2202 |
|
|
* unmap command, so it can turn off input mapping. See the usual |
2203 |
|
|
* ranting in the vi/v_txt_ev.c:txt_unmap() routine. |
2204 |
|
|
* |
2205 |
|
|
* PUBLIC: int ex_is_unmap(char *, size_t); |
2206 |
|
|
*/ |
2207 |
|
|
int |
2208 |
|
|
ex_is_unmap(char *name, size_t len) |
2209 |
|
|
{ |
2210 |
|
|
EXCMDLIST const *cp; |
2211 |
|
|
|
2212 |
|
|
/* |
2213 |
|
|
* The command the vi input routines are really interested in |
2214 |
|
|
* is "unmap!", not just unmap. |
2215 |
|
|
*/ |
2216 |
|
|
if (name[len - 1] != '!') |
2217 |
|
|
return (0); |
2218 |
|
|
--len; |
2219 |
|
|
return ((cp = ex_comm_search(name, len)) != NULL && |
2220 |
|
|
cp == &cmds[C_UNMAP]); |
2221 |
|
|
} |
2222 |
|
|
|
2223 |
|
|
/* |
2224 |
|
|
* ex_comm_search -- |
2225 |
|
|
* Search for a command name. |
2226 |
|
|
*/ |
2227 |
|
|
static EXCMDLIST const * |
2228 |
|
|
ex_comm_search(char *name, size_t len) |
2229 |
|
|
{ |
2230 |
|
|
EXCMDLIST const *cp; |
2231 |
|
|
|
2232 |
|
|
for (cp = cmds; cp->name != NULL; ++cp) { |
2233 |
|
|
if (cp->name[0] > name[0]) |
2234 |
|
|
return (NULL); |
2235 |
|
|
if (cp->name[0] != name[0]) |
2236 |
|
|
continue; |
2237 |
|
|
if (!memcmp(name, cp->name, len)) |
2238 |
|
|
return (cp); |
2239 |
|
|
} |
2240 |
|
|
return (NULL); |
2241 |
|
|
} |
2242 |
|
|
|
2243 |
|
|
/* |
2244 |
|
|
* ex_badaddr -- |
2245 |
|
|
* Display a bad address message. |
2246 |
|
|
* |
2247 |
|
|
* PUBLIC: void ex_badaddr |
2248 |
|
|
* PUBLIC:(SCR *, EXCMDLIST const *, enum badaddr, enum nresult); |
2249 |
|
|
*/ |
2250 |
|
|
void |
2251 |
|
|
ex_badaddr(SCR *sp, EXCMDLIST const *cp, enum badaddr ba, enum nresult nret) |
2252 |
|
|
{ |
2253 |
|
|
recno_t lno; |
2254 |
|
|
|
2255 |
|
|
switch (nret) { |
2256 |
|
|
case NUM_OK: |
2257 |
|
|
break; |
2258 |
|
|
case NUM_ERR: |
2259 |
|
|
msgq(sp, M_SYSERR, NULL); |
2260 |
|
|
return; |
2261 |
|
|
case NUM_OVER: |
2262 |
|
|
msgq(sp, M_ERR, "Address value overflow"); |
2263 |
|
|
return; |
2264 |
|
|
case NUM_UNDER: |
2265 |
|
|
msgq(sp, M_ERR, "Address value underflow"); |
2266 |
|
|
return; |
2267 |
|
|
} |
2268 |
|
|
|
2269 |
|
|
/* |
2270 |
|
|
* When encountering an address error, tell the user if there's no |
2271 |
|
|
* underlying file, that's the real problem. |
2272 |
|
|
*/ |
2273 |
|
|
if (sp->ep == NULL) { |
2274 |
|
|
ex_emsg(sp, cp != NULL ? cp->name : NULL, EXM_NOFILEYET); |
2275 |
|
|
return; |
2276 |
|
|
} |
2277 |
|
|
|
2278 |
|
|
switch (ba) { |
2279 |
|
|
case A_COMBO: |
2280 |
|
|
msgq(sp, M_ERR, "Illegal address combination"); |
2281 |
|
|
break; |
2282 |
|
|
case A_EOF: |
2283 |
|
|
if (db_last(sp, &lno)) |
2284 |
|
|
return; |
2285 |
|
|
if (lno != 0) { |
2286 |
|
|
msgq(sp, M_ERR, |
2287 |
|
|
"Illegal address: only %lu lines in the file", |
2288 |
|
|
lno); |
2289 |
|
|
break; |
2290 |
|
|
} |
2291 |
|
|
/* FALLTHROUGH */ |
2292 |
|
|
case A_EMPTY: |
2293 |
|
|
msgq(sp, M_ERR, "Illegal address: the file is empty"); |
2294 |
|
|
break; |
2295 |
|
|
case A_NOTSET: |
2296 |
|
|
abort(); |
2297 |
|
|
/* NOTREACHED */ |
2298 |
|
|
case A_ZERO: |
2299 |
|
|
msgq(sp, M_ERR, |
2300 |
|
|
"The %s command doesn't permit an address of 0", |
2301 |
|
|
cp->name); |
2302 |
|
|
break; |
2303 |
|
|
} |
2304 |
|
|
return; |
2305 |
|
|
} |
2306 |
|
|
|
2307 |
|
|
#if defined(DEBUG) && defined(COMLOG) |
2308 |
|
|
/* |
2309 |
|
|
* ex_comlog -- |
2310 |
|
|
* Log ex commands. |
2311 |
|
|
*/ |
2312 |
|
|
static void |
2313 |
|
|
ex_comlog(SCR *sp, EXCMD *ecp) |
2314 |
|
|
{ |
2315 |
|
|
TRACE(sp, "ecmd: %s", ecp->cmd->name); |
2316 |
|
|
if (ecp->addrcnt > 0) { |
2317 |
|
|
TRACE(sp, " a1 %d", ecp->addr1.lno); |
2318 |
|
|
if (ecp->addrcnt > 1) |
2319 |
|
|
TRACE(sp, " a2: %d", ecp->addr2.lno); |
2320 |
|
|
} |
2321 |
|
|
if (ecp->lineno) |
2322 |
|
|
TRACE(sp, " line %d", ecp->lineno); |
2323 |
|
|
if (ecp->flags) |
2324 |
|
|
TRACE(sp, " flags 0x%x", ecp->flags); |
2325 |
|
|
if (F_ISSET(&exc, E_BUFFER)) |
2326 |
|
|
TRACE(sp, " buffer %c", ecp->buffer); |
2327 |
|
|
if (ecp->argc) |
2328 |
|
|
for (cnt = 0; cnt < ecp->argc; ++cnt) |
2329 |
|
|
TRACE(sp, " arg %d: {%s}", cnt, ecp->argv[cnt]->bp); |
2330 |
|
|
TRACE(sp, "\n"); |
2331 |
|
|
} |
2332 |
|
|
#endif |