Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/sortlib/vcodex/vcodex.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2005-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
22
/*
23
* sort file io vcodex discipline
24
*/
25
26
static const char usage[] =
27
"[-1lp0s5P?\n@(#)$Id: vcodex (AT&T Research) 2008-06-06 $\n]"
28
USAGE_LICENSE
29
"[+PLUGIN?vcodex - sort io vcodex discipline library]"
30
"[+DESCRIPTION?The \bvcodex\b \bsort\b(1) discipline encodes and/or "
31
"decodes input, output and temporary file data. By default temporary and "
32
"output encoding is the same as the encoding used on the first encoded "
33
"input file. Output encoding is only applied to the standard output or "
34
"to files with a path suffix containing 'z'. If encoding is applied to "
35
"a regular output file and the output file path does not have a suffix "
36
"containing 'z' and the input path has a suffix containing 'z' then the "
37
"output path is renamed by appending the input path suffix.]"
38
"[i:input?Decode the input files using \amethod\a. \b--noinput\b "
39
"disables input encoding.]:[method]"
40
"[o:output?Encode the output file using \amethod\a. \b--nooutput\b "
41
"disables output encoding.]:[method]"
42
"[r:regress?Massage \bverbose\b output for regression testing.]"
43
"[t:temporary?Encode temporary intermediate files using "
44
"\amethod\a. \b--notemporary\b disables temporary encoding.]:[method]"
45
"[T:test?Enable test code defined by \amask\a. Test code is "
46
"implementation specific. Consult the source for details.]#[mask]"
47
"[v:verbose?Enable file and stream encoding messages on the standard "
48
"error.]"
49
"[+SEE ALSO?\bsort\b(1), \bvczip\b(1), \bvcodex\b(3)]"
50
"\n\n--library=vcodex[,option[=value]...]\n\n"
51
;
52
53
#include <ast.h>
54
#include <error.h>
55
#include <ls.h>
56
#include <recsort.h>
57
#include <vcodex.h>
58
59
struct Delay_s;
60
typedef struct Delay_s Delay_t;
61
62
struct Delay_s
63
{
64
Delay_t* next;
65
Sfio_t* sp;
66
char name[1];
67
};
68
69
typedef struct Encoding_s
70
{
71
char* trans;
72
char suffix[16];
73
int use;
74
} Encoding_t;
75
76
typedef struct State_s
77
{
78
Rsdisc_t disc;
79
Encoding_t input;
80
Encoding_t output;
81
Encoding_t temporary;
82
Delay_t* delay;
83
unsigned long test;
84
int regress;
85
int verbose;
86
} State_t;
87
88
#define tempid(s,f) ((s)->regress?(++(s)->regress):sffileno((Sfio_t*)(f)))
89
#define ZIPSUFFIX(p,s) ((s = strrchr(p, '.')) && strchr(s, 'z') && !strchr(s, '/'))
90
91
static int
92
zipit(const char* path)
93
{
94
char* s;
95
96
return !path || ZIPSUFFIX(path, s);
97
}
98
99
static void
100
vcsferror(const char* mesg)
101
{
102
error(2, "%s", mesg);
103
}
104
105
static int
106
push(Sfio_t* sp, Encoding_t* code, const char* trans, int type)
107
{
108
Vcsfdata_t* vcsf;
109
110
if (!trans && !type)
111
return sfraise(sp, VCSF_DISC, NiL) == VCSF_DISC;
112
if (!(vcsf = newof(0, Vcsfdata_t, 1, 0)))
113
return -1;
114
vcsf->trans = (char*)trans;
115
vcsf->type = VCSF_FREE;
116
if (code)
117
vcsf->type |= VCSF_TRANS;
118
if (type)
119
vcsf->errorf = vcsferror;
120
if (!vcsfio(sp, vcsf, type))
121
return -1;
122
if (code && (code->trans = vcsf->trans))
123
code->use = 1;
124
return type ? 1 : vcsf->type;
125
}
126
127
static int
128
encode(State_t* state, Sfio_t* sp, const char* path)
129
{
130
char* p;
131
struct stat st;
132
133
if (!push(sp, NiL, NiL, 0))
134
{
135
if (!state->output.use)
136
state->output = state->input;
137
if (push(sp, NiL, state->output.trans, VC_ENCODE) < 0)
138
{
139
error(2, "%s: cannot push vcodex encode discipline (%s)", path, state->output.trans);
140
return -1;
141
}
142
if (!ZIPSUFFIX(path, p) && *state->input.suffix && !stat(path, &st) && S_ISREG(st.st_mode))
143
{
144
p = sfprints("%s%s", path, state->input.suffix);
145
if (rename(path, p))
146
error(ERROR_SYSTEM|1, "%s: cannot rename to %s", path, p);
147
else
148
path = (const char*)p;
149
}
150
if (state->verbose)
151
error(0, "sort vcodex encode %s (%s)", path, state->output.trans);
152
}
153
return 0;
154
}
155
156
static int
157
vcodex(Rs_t* rs, int op, Void_t* data, Void_t* arg, Rsdisc_t* disc)
158
{
159
int i;
160
char* s;
161
Delay_t* delay;
162
State_t* state = (State_t*)disc;
163
164
if (state->test & 0x10)
165
error(0, "sort vcodex event %s %p %s"
166
, op == RS_FILE_WRITE ? "RS_FILE_WRITE"
167
: op == RS_FILE_READ ? "RS_FILE_READ"
168
: op == RS_TEMP_WRITE ? "RS_TEMP_WRITE"
169
: op == RS_TEMP_READ ? "RS_TEMP_READ"
170
: "UNKNOWN"
171
, data
172
, arg);
173
switch (op)
174
{
175
case RS_FILE_WRITE:
176
if (((Sfio_t*)data == sfstdout || zipit(arg)) && (state->output.use > 0 || !state->output.use && state->input.use > 0))
177
return encode(state, (Sfio_t*)data, (char*)arg);
178
if (!state->output.use && zipit(arg) && (arg || (arg = (Void_t*)"(output-stream)")) && (delay = newof(0, Delay_t, 1, strlen(arg))))
179
{
180
delay->sp = (Sfio_t*)data;
181
strcpy(delay->name, arg);
182
delay->next = state->delay;
183
state->delay = delay;
184
}
185
break;
186
case RS_FILE_READ:
187
if (state->input.use >= 0)
188
{
189
if ((i = push((Sfio_t*)data, &state->input, NiL, VC_DECODE)) < 0)
190
{
191
error(2, "%s: cannot push vcodex decode discipline (%s)", arg, state->input.trans);
192
return -1;
193
}
194
else if (i > 0)
195
{
196
if (state->verbose)
197
error(0, "sort vcodex decode %s (%s)", arg, state->input.trans);
198
if (state->delay)
199
{
200
i = 0;
201
while (delay = state->delay)
202
{
203
if (!i && state->input.use > 0 && !sfseek(delay->sp, (Sfoff_t)0, SEEK_CUR))
204
i = encode(state, delay->sp, delay->name);
205
state->delay = delay->next;
206
free(delay);
207
}
208
return i;
209
}
210
if (!*state->input.suffix && ZIPSUFFIX(arg, s))
211
strncopy(state->input.suffix, s, sizeof(state->input.suffix));
212
}
213
}
214
break;
215
case RS_TEMP_WRITE:
216
if (state->temporary.use > 0 || !state->temporary.use && state->input.use > 0)
217
{
218
if (!state->temporary.use)
219
state->temporary = state->input;
220
if (push((Sfio_t*)data, NiL, state->temporary.trans, VC_ENCODE) < 0)
221
{
222
error(2, "temporary-%d: cannot push vcodex encode discipline (%s)", tempid(state, data), state->temporary.trans);
223
return -1;
224
}
225
if (state->verbose)
226
error(0, "sort vcodex encode temporary-%d (%s)", tempid(state, data), state->temporary.trans);
227
return 1;
228
}
229
break;
230
case RS_TEMP_READ:
231
if (state->temporary.use > 0 || !state->temporary.use && state->input.use > 0)
232
{
233
if (!state->temporary.use)
234
state->temporary = state->input;
235
if (!sfdisc((Sfio_t*)data, SF_POPDISC) || sfseek((Sfio_t*)data, (Sfoff_t)0, SEEK_SET))
236
{
237
error(2, "temporary-%d: cannot rewind temporary data", tempid(state, data));
238
return -1;
239
}
240
if ((i = push((Sfio_t*)data, NiL, NiL, VC_DECODE)) < 0)
241
{
242
error(2, "temporary-%d: cannot push vcodex decode discipline", tempid(state, data));
243
return -1;
244
}
245
else if (i > 0 && state->verbose)
246
error(0, "sort vcodex decode temporary-%d", tempid(state, data));
247
return 1;
248
}
249
break;
250
default:
251
return -1;
252
}
253
return 0;
254
}
255
256
Rsdisc_t*
257
rs_disc(Rskey_t* key, const char* options)
258
{
259
State_t* state;
260
261
if (!(state = newof(0, State_t, 1, 0)))
262
error(ERROR_SYSTEM|3, "out of space");
263
if (options)
264
{
265
for (;;)
266
{
267
switch (optstr(options, usage))
268
{
269
case 0:
270
break;
271
case 'i':
272
if (!opt_info.arg)
273
state->input.use = -1;
274
else if (streq(opt_info.arg, "-"))
275
state->input.use = 0;
276
else
277
{
278
state->input.trans = opt_info.arg;
279
state->input.use = 1;
280
}
281
continue;
282
case 'o':
283
if (!opt_info.arg)
284
state->output.use = -1;
285
else if (streq(opt_info.arg, "-"))
286
state->output.use = 0;
287
else
288
{
289
state->output.trans = opt_info.arg;
290
state->output.use = 1;
291
}
292
continue;
293
case 'r':
294
state->regress = 1;
295
continue;
296
case 't':
297
if (!opt_info.arg)
298
state->temporary.use = -1;
299
else if (streq(opt_info.arg, "-"))
300
state->temporary.use = 0;
301
else
302
{
303
state->temporary.trans = opt_info.arg;
304
state->temporary.use = 1;
305
}
306
continue;
307
case 'v':
308
state->verbose = 1;
309
continue;
310
case 'T':
311
state->test |= opt_info.num;
312
continue;
313
case '?':
314
error(ERROR_USAGE|4, "%s", opt_info.arg);
315
goto drop;
316
case ':':
317
error(2, "%s", opt_info.arg);
318
goto drop;
319
}
320
break;
321
}
322
}
323
if (state->temporary.use >= 0)
324
key->type |= RS_TEXT;
325
state->disc.eventf = vcodex;
326
state->disc.events = RS_FILE_WRITE|RS_FILE_READ|RS_TEMP_WRITE|RS_TEMP_READ;
327
return &state->disc;
328
drop:
329
free(state);
330
return 0;
331
}
332
333
SORTLIB(vcodex)
334
335