1 |
|
|
/* $OpenBSD: v_at.c,v 1.11 2016/05/27 09:18:12 martijn 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/time.h> |
17 |
|
|
|
18 |
|
|
#include <bitstring.h> |
19 |
|
|
#include <ctype.h> |
20 |
|
|
#include <limits.h> |
21 |
|
|
#include <stdio.h> |
22 |
|
|
|
23 |
|
|
#include "../common/common.h" |
24 |
|
|
#include "vi.h" |
25 |
|
|
|
26 |
|
|
/* |
27 |
|
|
* v_at -- @ |
28 |
|
|
* Execute a buffer. |
29 |
|
|
* |
30 |
|
|
* PUBLIC: int v_at(SCR *, VICMD *); |
31 |
|
|
*/ |
32 |
|
|
int |
33 |
|
|
v_at(SCR *sp, VICMD *vp) |
34 |
|
|
{ |
35 |
|
|
CB *cbp; |
36 |
|
|
CHAR_T name; |
37 |
|
|
TEXT *tp; |
38 |
|
|
size_t len; |
39 |
|
|
char nbuf[20]; |
40 |
|
|
|
41 |
|
|
/* |
42 |
|
|
* !!! |
43 |
|
|
* Historically, [@*]<carriage-return> and [@*][@*] executed the most |
44 |
|
|
* recently executed buffer in ex mode. In vi mode, only @@ repeated |
45 |
|
|
* the last buffer. We change historic practice and make @* work from |
46 |
|
|
* vi mode as well, it's simpler and more consistent. |
47 |
|
|
* |
48 |
|
|
* My intent is that *[buffer] will, in the future, pass the buffer to |
49 |
|
|
* whatever interpreter is loaded. |
50 |
|
|
*/ |
51 |
|
|
name = F_ISSET(vp, VC_BUFFER) ? vp->buffer : '@'; |
52 |
|
|
if (name == '@' || name == '*') { |
53 |
|
|
if (!F_ISSET(sp, SC_AT_SET)) { |
54 |
|
|
ex_emsg(sp, NULL, EXM_NOPREVBUF); |
55 |
|
|
return (1); |
56 |
|
|
} |
57 |
|
|
name = sp->at_lbuf; |
58 |
|
|
} |
59 |
|
|
F_SET(sp, SC_AT_SET); |
60 |
|
|
|
61 |
|
|
CBNAME(sp, cbp, name); |
62 |
|
|
if (cbp == NULL) { |
63 |
|
|
ex_emsg(sp, KEY_NAME(sp, name), EXM_EMPTYBUF); |
64 |
|
|
return (1); |
65 |
|
|
} |
66 |
|
|
|
67 |
|
|
/* Save for reuse. */ |
68 |
|
|
sp->at_lbuf = name; |
69 |
|
|
|
70 |
|
|
/* |
71 |
|
|
* The buffer is executed in vi mode, while in vi mode, so simply |
72 |
|
|
* push it onto the terminal queue and continue. |
73 |
|
|
* |
74 |
|
|
* !!! |
75 |
|
|
* Historic practice is that if the buffer was cut in line mode, |
76 |
|
|
* <newlines> were appended to each line as it was pushed onto |
77 |
|
|
* the stack. If the buffer was cut in character mode, <newlines> |
78 |
|
|
* were appended to all lines but the last one. |
79 |
|
|
* |
80 |
|
|
* XXX |
81 |
|
|
* Historic practice is that execution of an @ buffer could be |
82 |
|
|
* undone by a single 'u' command, i.e. the changes were grouped |
83 |
|
|
* together. We don't get this right; I'm waiting for the new DB |
84 |
|
|
* logging code to be available. |
85 |
|
|
*/ |
86 |
|
|
TAILQ_FOREACH_REVERSE(tp, &cbp->textq, _texth, q) |
87 |
|
|
if (((F_ISSET(cbp, CB_LMODE) || TAILQ_NEXT(tp, q)) && |
88 |
|
|
v_event_push(sp, NULL, "\n", 1, 0)) || |
89 |
|
|
v_event_push(sp, NULL, tp->lb, tp->len, 0)) |
90 |
|
|
return (1); |
91 |
|
|
|
92 |
|
|
/* |
93 |
|
|
* !!! |
94 |
|
|
* If any count was supplied, it applies to the first command in the |
95 |
|
|
* at buffer. |
96 |
|
|
*/ |
97 |
|
|
if (F_ISSET(vp, VC_C1SET)) { |
98 |
|
|
len = snprintf(nbuf, sizeof(nbuf), "%lu", vp->count); |
99 |
|
|
if (len >= sizeof(nbuf)) |
100 |
|
|
len = sizeof(nbuf) - 1; |
101 |
|
|
if (v_event_push(sp, NULL, nbuf, len, 0)) |
102 |
|
|
return (1); |
103 |
|
|
} |
104 |
|
|
return (0); |
105 |
|
|
} |