-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathPIPE.C
241 lines (213 loc) · 4.7 KB
/
PIPE.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/* Copyright (c) 1990,1991,1992 Chris and John Downey */
#ifndef lint
static char *sccsid = "@(#)pipe.c 2.1 (Chris & John Downey) 7/29/92";
#endif
/***
* program name:
xvi
* function:
PD version of UNIX "vi" editor, with extensions.
* module name:
pipe.c
* module function:
Handle pipe operators.
* history:
STEVIE - ST Editor for VI Enthusiasts, Version 3.10
Originally by Tim Thompson (twitch!tjt)
Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
Heavily modified by Chris & John Downey
***/
#include "xvi.h"
static int p_write P((FILE *));
static long p_read P((FILE *));
static Xviwin *specwin;
static Line *line1, *line2;
static Line *newlines;
/*
* This function is called when the ! is typed in initially,
* to specify the range; do_pipe() is then called later on
* when the line has been typed in completely.
*
* Note that we record the first and last+1th lines to make the loop easier.
*/
void
specify_pipe_range(window, l1, l2)
Xviwin *window;
Line *l1;
Line *l2;
{
/*
* Ensure that the lines specified are in the right order.
*/
if (l1 != NULL && l2 != NULL && earlier(l2, l1)) {
register Line *tmp;
tmp = l1;
l1 = l2;
l2 = tmp;
}
line1 = (l1 != NULL) ? l1 : window->w_buffer->b_file;
line2 = (l2 != NULL) ? l2->l_next : window->w_buffer->b_lastline;
specwin = window;
}
/*
* Pipe the given sequence of lines through the command,
* replacing the old set with its output.
*/
void
do_pipe(window, command)
Xviwin *window;
char *command;
{
if (line1 == NULL || line2 == NULL || specwin != window) {
show_error(window,
"Internal error: pipe through badly-specified range.");
return;
}
newlines = NULL;
if (sys_pipe(command, p_write, p_read) && newlines != NULL) {
repllines(window, line1, cntllines(line1, line2) - 1, newlines);
update_buffer(window->w_buffer);
begin_line(window, TRUE);
} else {
show_error(window, "Failed to execute \"%s\"", command);
redraw_screen();
}
cursupdate(window);
}
static int
p_write(fp)
FILE *fp;
{
Line *l;
long n;
for (l = line1, n = 0; l != line2; l = l->l_next, n++) {
(void) fputs(l->l_text, fp);
(void) putc('\n', fp);
}
return(n);
}
/*
* Returns the number of lines read, or -1 for failure.
*/
static long
p_read(fp)
FILE *fp;
{
Line *lptr = NULL; /* pointer to list of lines */
Line *last = NULL; /* last complete line read in */
Line *lp; /* line currently being read in */
register enum {
at_soln,
in_line,
at_eoln,
at_eof
} state;
char *buff; /* text of line being read in */
int col; /* current column in line */
unsigned long
nlines; /* number of lines read */
col = 0;
nlines = 0;
state = at_soln;
while (state != at_eof) {
register int c;
c = getc(fp);
/*
* Nulls are special; they can't show up in the file.
*/
if (c == '\0') {
continue;
}
if (c == EOF) {
if (state != at_soln) {
/*
* Reached EOF in the middle of a line; what
* we do here is to pretend we got a properly
* terminated line, and assume that a
* subsequent getc will still return EOF.
*/
state = at_eoln;
} else {
state = at_eof;
}
} else {
if (state == at_soln) {
/*
* We're at the start of a line, &
* we've got at least one character,
* so we have to allocate a new Line
* structure.
*
* If we can't do it, we throw away
* the lines we've read in so far, &
* return gf_NOMEM.
*/
lp = newline(MAX_LINE_LENGTH);
if (lp == NULL) {
if (lptr != NULL)
throw(lptr);
return(-1);
} else {
buff = lp->l_text;
}
}
if (c == '\n') {
state = at_eoln;
}
}
/*
* Fake eoln for lines which are too long.
* Don't lose the input character.
*/
if (col >= MAX_LINE_LENGTH - 1) {
(void) ungetc(c, fp);
state = at_eoln;
}
switch (state) {
/*
* case at_eof:
* break;
*/
case at_soln:
case in_line:
state = in_line;
buff[col++] = c;
break;
case at_eoln:
/*
* First null-terminate the old line.
*/
buff[col] = '\0';
/*
* If this fails, we squeak at the user and
* then throw away the lines read in so far.
*/
buff = realloc(buff, (unsigned) col + 1);
if (buff == NULL) {
if (lptr != NULL)
throw(lptr);
return(-1);
}
lp->l_text = buff;
lp->l_size = col + 1;
/*
* Tack the line onto the end of the list,
* and then point "last" at it.
*/
if (lptr == NULL) {
lptr = lp;
last = lptr;
} else {
last->l_next = lp;
lp->l_prev = last;
last = lp;
}
nlines++;
col = 0;
state = at_soln;
break;
}
}
newlines = lptr;
return(nlines);
}