60 |
OP_EXPORT /* EXPORT. */ |
OP_EXPORT /* EXPORT. */ |
61 |
}; |
}; |
62 |
|
|
63 |
static bool trim_dictionary (struct dictionary *, |
static bool parse_dict_trim (struct dictionary *); |
|
enum operation, int *compress); |
|
64 |
|
|
65 |
/* GET input program. */ |
/* GET input program. */ |
66 |
struct get_pgm |
struct get_pgm |
100 |
case_create (&pgm->bounce, dict_get_next_value_idx (dict)); |
case_create (&pgm->bounce, dict_get_next_value_idx (dict)); |
101 |
|
|
102 |
start_case_map (dict); |
start_case_map (dict); |
103 |
if (!trim_dictionary (dict, OP_READ, NULL)) |
while (lex_match ('/')) |
104 |
goto error; |
if (!parse_dict_trim (dict)) |
105 |
|
goto error; |
106 |
|
|
107 |
|
if (!lex_end_of_command ()) |
108 |
|
return false; |
109 |
|
|
110 |
|
dict_compact_values (dict); |
111 |
pgm->map = finish_case_map (dict); |
pgm->map = finish_case_map (dict); |
112 |
|
|
113 |
dict_destroy (default_dict); |
dict_destroy (default_dict); |
119 |
|
|
120 |
error: |
error: |
121 |
get_pgm_free (pgm); |
get_pgm_free (pgm); |
122 |
if (dict != NULL) |
if (dict != NULL) |
123 |
dict_destroy (dict); |
dict_destroy (dict); |
124 |
return CMD_FAILURE; |
return CMD_FAILURE; |
125 |
} |
} |
180 |
get_source_destroy, |
get_source_destroy, |
181 |
}; |
}; |
182 |
|
|
183 |
/* XSAVE transformation and SAVE procedure. */ |
/* Type of output file. */ |
184 |
struct save_trns |
enum writer_type |
185 |
{ |
{ |
186 |
struct trns_header h; |
SYSFILE_WRITER, /* System file. */ |
187 |
struct sfm_writer *writer; /* System file writer. */ |
PORFILE_WRITER /* Portable file. */ |
188 |
struct case_map *map; /* Map from active file to system file dict. */ |
}; |
189 |
struct ccase bounce; /* Bounce buffer. */ |
|
190 |
|
/* Type of a command. */ |
191 |
|
enum command_type |
192 |
|
{ |
193 |
|
XFORM_CMD, /* Transformation. */ |
194 |
|
PROC_CMD /* Procedure. */ |
195 |
|
}; |
196 |
|
|
197 |
|
/* Portable or system file writer plus a case map. */ |
198 |
|
struct any_writer |
199 |
|
{ |
200 |
|
enum writer_type writer_type; |
201 |
|
void *writer; |
202 |
|
struct case_map *map; /* Map to output file dictionary |
203 |
|
(null pointer for identity mapping). */ |
204 |
|
struct ccase bounce; /* Bounce buffer for mapping (if needed). */ |
205 |
}; |
}; |
206 |
|
|
207 |
static int save_write_case_func (struct ccase *, void *); |
/* Destroys AW. */ |
208 |
static trns_proc_func save_trns_proc; |
static void |
209 |
static trns_free_func save_trns_free; |
any_writer_destroy (struct any_writer *aw) |
|
|
|
|
/* Parses the SAVE or XSAVE command |
|
|
and returns the parsed transformation. */ |
|
|
static struct save_trns * |
|
|
cmd_save_internal (void) |
|
210 |
{ |
{ |
211 |
struct file_handle *fh = NULL; |
if (aw != NULL) |
212 |
struct dictionary *dict = NULL; |
{ |
213 |
struct save_trns *t = NULL; |
switch (aw->writer_type) |
214 |
int compress = get_scompression (); |
{ |
215 |
const int default_version = 3; |
case PORFILE_WRITER: |
216 |
int version = default_version; |
pfm_close_writer (aw->writer); |
217 |
short no_name_table = 0; |
break; |
218 |
|
case SYSFILE_WRITER: |
219 |
t = xmalloc (sizeof *t); |
sfm_close_writer (aw->writer); |
220 |
t->h.proc = save_trns_proc; |
break; |
221 |
t->h.free = save_trns_free; |
} |
222 |
t->writer = NULL; |
destroy_case_map (aw->map); |
223 |
t->map = NULL; |
case_destroy (&aw->bounce); |
224 |
case_nullify (&t->bounce); |
free (aw); |
225 |
|
} |
226 |
|
} |
227 |
|
|
228 |
|
/* Parses SAVE or XSAVE or EXPORT or XEXPORT command. |
229 |
|
WRITER_TYPE identifies the type of file to write, |
230 |
|
and COMMAND_TYPE identifies the type of command. |
231 |
|
|
232 |
|
On success, returns a writer. |
233 |
|
For procedures only, sets *RETAIN_UNSELECTED to true if cases |
234 |
|
that would otherwise be excluded by FILTER or USE should be |
235 |
|
included. |
236 |
|
|
237 |
|
On failure, returns a null pointer. */ |
238 |
|
static struct any_writer * |
239 |
|
parse_write_command (enum writer_type writer_type, |
240 |
|
enum command_type command_type, |
241 |
|
bool *retain_unselected) |
242 |
|
{ |
243 |
|
/* Common data. */ |
244 |
|
struct file_handle *handle; /* Output file. */ |
245 |
|
struct dictionary *dict; /* Dictionary for output file. */ |
246 |
|
struct any_writer *aw; /* Writer. */ |
247 |
|
|
248 |
|
/* Common options. */ |
249 |
|
bool print_map; /* Print map? TODO. */ |
250 |
|
bool print_short_names; /* Print long-to-short name map. TODO. */ |
251 |
|
struct sfm_write_options sysfile_opts; |
252 |
|
struct pfm_write_options porfile_opts; |
253 |
|
|
254 |
|
assert (writer_type == SYSFILE_WRITER || writer_type == PORFILE_WRITER); |
255 |
|
assert (command_type == XFORM_CMD || command_type == PROC_CMD); |
256 |
|
assert ((retain_unselected != NULL) == (command_type == PROC_CMD)); |
257 |
|
|
258 |
|
if (command_type == PROC_CMD) |
259 |
|
*retain_unselected = true; |
260 |
|
|
261 |
|
handle = NULL; |
262 |
|
dict = dict_clone (default_dict); |
263 |
|
aw = xmalloc (sizeof *aw); |
264 |
|
aw->writer_type = writer_type; |
265 |
|
aw->writer = NULL; |
266 |
|
aw->map = NULL; |
267 |
|
case_nullify (&aw->bounce); |
268 |
|
print_map = false; |
269 |
|
print_short_names = false; |
270 |
|
sysfile_opts = sfm_writer_default_options (); |
271 |
|
porfile_opts = pfm_writer_default_options (); |
272 |
|
|
273 |
|
start_case_map (dict); |
274 |
|
dict_delete_scratch_vars (dict); |
275 |
|
|
276 |
/* Read most of the subcommands. */ |
lex_match ('/'); |
277 |
for (;;) |
for (;;) |
278 |
{ |
{ |
279 |
if (lex_match_id ("VERSION")) |
if (lex_match_id ("OUTFILE")) |
280 |
{ |
{ |
281 |
|
if (handle != NULL) |
282 |
|
{ |
283 |
|
lex_sbc_only_once ("OUTFILE"); |
284 |
|
goto error; |
285 |
|
} |
286 |
|
|
287 |
lex_match ('='); |
lex_match ('='); |
288 |
if (lex_force_int ()) |
|
289 |
{ |
handle = fh_parse (); |
290 |
version = lex_integer (); |
if (handle == NULL) |
291 |
lex_get (); |
goto error; |
|
|
|
|
if (lex_match_id ("X")) |
|
|
no_name_table = 1; |
|
|
} |
|
292 |
} |
} |
293 |
else if (lex_match_id ("OUTFILE")) |
else if (lex_match_id ("NAMES")) |
294 |
|
print_short_names = true; |
295 |
|
else if (lex_match_id ("PERMISSIONS")) |
296 |
|
{ |
297 |
|
bool cw; |
298 |
|
|
299 |
|
lex_match ('='); |
300 |
|
if (lex_match_id ("READONLY")) |
301 |
|
cw = false; |
302 |
|
else if (lex_match_id ("WRITEABLE")) |
303 |
|
cw = true; |
304 |
|
else |
305 |
|
{ |
306 |
|
lex_error (_("expecting %s or %s"), "READONLY", "WRITEABLE"); |
307 |
|
goto error; |
308 |
|
} |
309 |
|
sysfile_opts.create_writeable = porfile_opts.create_writeable = cw; |
310 |
|
} |
311 |
|
else if (command_type == PROC_CMD && lex_match_id ("UNSELECTED")) |
312 |
|
{ |
313 |
|
lex_match ('='); |
314 |
|
if (lex_match_id ("RETAIN")) |
315 |
|
*retain_unselected = true; |
316 |
|
else if (lex_match_id ("DELETE")) |
317 |
|
*retain_unselected = false; |
318 |
|
else |
319 |
|
{ |
320 |
|
lex_error (_("expecting %s or %s"), "RETAIN", "DELETE"); |
321 |
|
goto error; |
322 |
|
} |
323 |
|
} |
324 |
|
else if (writer_type == SYSFILE_WRITER && lex_match_id ("COMPRESSED")) |
325 |
|
sysfile_opts.compress = true; |
326 |
|
else if (writer_type == SYSFILE_WRITER && lex_match_id ("UNCOMPRESSED")) |
327 |
|
sysfile_opts.compress = false; |
328 |
|
else if (writer_type == SYSFILE_WRITER && lex_match_id ("VERSION")) |
329 |
{ |
{ |
330 |
lex_match ('='); |
lex_match ('='); |
331 |
|
if (!lex_force_int ()) |
332 |
fh = fh_parse (); |
goto error; |
333 |
if (fh == NULL) |
sysfile_opts.version = lex_integer (); |
334 |
goto error; |
lex_get (); |
|
|
|
335 |
} |
} |
336 |
if ( ! lex_match('/') ) |
else if (writer_type == PORFILE_WRITER && lex_match_id ("TYPE")) |
337 |
|
{ |
338 |
|
lex_match ('='); |
339 |
|
if (lex_match_id ("COMMUNICATIONS")) |
340 |
|
porfile_opts.type = PFM_COMM; |
341 |
|
else if (lex_match_id ("TAPE")) |
342 |
|
porfile_opts.type = PFM_TAPE; |
343 |
|
else |
344 |
|
{ |
345 |
|
lex_error (_("expecting %s or %s"), "COMM", "TAPE"); |
346 |
|
goto error; |
347 |
|
} |
348 |
|
} |
349 |
|
else if (writer_type == PORFILE_WRITER && lex_match_id ("DIGITS")) |
350 |
|
{ |
351 |
|
lex_match ('='); |
352 |
|
if (!lex_force_int ()) |
353 |
|
goto error; |
354 |
|
porfile_opts.digits = lex_integer (); |
355 |
|
lex_get (); |
356 |
|
} |
357 |
|
else if (!parse_dict_trim (dict)) |
358 |
|
goto error; |
359 |
|
|
360 |
|
if (!lex_match ('/')) |
361 |
break; |
break; |
|
|
|
362 |
} |
} |
363 |
|
if (lex_end_of_command () != CMD_SUCCESS) |
364 |
|
goto error; |
365 |
|
|
366 |
if (token != '.') |
if (handle == NULL) |
367 |
{ |
{ |
368 |
lex_error (_("expecting end of command")); |
lex_sbc_missing ("OUTFILE"); |
369 |
goto error; |
goto error; |
370 |
} |
} |
371 |
|
|
372 |
if ( fh == NULL ) |
dict_compact_values (dict); |
373 |
{ |
aw->map = finish_case_map (dict); |
374 |
msg ( ME, _("The required %s subcommand was not present"), "OUTFILE"); |
if (aw->map != NULL) |
375 |
goto error; |
case_create (&aw->bounce, dict_get_next_value_idx (dict)); |
|
} |
|
376 |
|
|
377 |
if ( version != default_version ) |
switch (writer_type) |
378 |
{ |
{ |
379 |
msg (MW, _("Unsupported sysfile version: %d. Using version %d instead."), |
case SYSFILE_WRITER: |
380 |
version, default_version); |
aw->writer = sfm_open_writer (handle, dict, sysfile_opts); |
381 |
|
break; |
382 |
version = default_version; |
case PORFILE_WRITER: |
383 |
|
aw->writer = pfm_open_writer (handle, dict, porfile_opts); |
384 |
|
break; |
385 |
} |
} |
386 |
|
|
387 |
dict = dict_clone (default_dict); |
return aw; |
|
start_case_map (dict); |
|
|
if (!trim_dictionary (dict, OP_SAVE, &compress)) |
|
|
goto error; |
|
|
t->map = finish_case_map (dict); |
|
|
if (t->map != NULL) |
|
|
case_create (&t->bounce, dict_get_next_value_idx (dict)); |
|
|
|
|
|
t->writer = sfm_open_writer (fh, dict, compress, no_name_table); |
|
|
if (t->writer == NULL) |
|
|
goto error; |
|
|
|
|
|
dict_destroy (dict); |
|
|
|
|
|
return t; |
|
388 |
|
|
389 |
error: |
error: |
390 |
assert (t != NULL); |
any_writer_destroy (aw); |
391 |
dict_destroy (dict); |
dict_destroy (dict); |
|
save_trns_free (&t->h); |
|
392 |
return NULL; |
return NULL; |
393 |
} |
} |
394 |
|
|
395 |
/* Parses and performs the SAVE procedure. */ |
/* Writes case C to writer AW. */ |
396 |
int |
static void |
397 |
cmd_save (void) |
any_writer_write_case (struct any_writer *aw, struct ccase *c) |
398 |
{ |
{ |
399 |
struct save_trns *t = cmd_save_internal (); |
if (aw->map != NULL) |
|
if (t != NULL) |
|
400 |
{ |
{ |
401 |
procedure (save_write_case_func, t); |
map_case (aw->map, c, &aw->bounce); |
402 |
save_trns_free (&t->h); |
c = &aw->bounce; |
|
free(t); |
|
|
return CMD_SUCCESS; |
|
403 |
} |
} |
404 |
else |
|
405 |
|
switch (aw->writer_type) |
406 |
|
{ |
407 |
|
case SYSFILE_WRITER: |
408 |
|
sfm_write_case (aw->writer, c); |
409 |
|
break; |
410 |
|
case PORFILE_WRITER: |
411 |
|
pfm_write_case (aw->writer, c); |
412 |
|
break; |
413 |
|
} |
414 |
|
} |
415 |
|
|
416 |
|
/* SAVE and EXPORT. */ |
417 |
|
|
418 |
|
static int output_proc (struct ccase *, void *); |
419 |
|
|
420 |
|
/* Parses and performs the SAVE or EXPORT procedure. */ |
421 |
|
static int |
422 |
|
parse_output_proc (enum writer_type writer_type) |
423 |
|
{ |
424 |
|
bool retain_unselected; |
425 |
|
struct variable *saved_filter_variable; |
426 |
|
struct any_writer *aw; |
427 |
|
|
428 |
|
aw = parse_write_command (writer_type, PROC_CMD, &retain_unselected); |
429 |
|
if (aw == NULL) |
430 |
return CMD_FAILURE; |
return CMD_FAILURE; |
431 |
|
|
432 |
|
saved_filter_variable = dict_get_filter (default_dict); |
433 |
|
if (retain_unselected) |
434 |
|
dict_set_filter (default_dict, NULL); |
435 |
|
procedure (output_proc, aw); |
436 |
|
dict_set_filter (default_dict, saved_filter_variable); |
437 |
|
|
438 |
|
any_writer_destroy (aw); |
439 |
|
return CMD_SUCCESS; |
440 |
|
} |
441 |
|
|
442 |
|
/* Writes case C to file. */ |
443 |
|
static int |
444 |
|
output_proc (struct ccase *c, void *aw_) |
445 |
|
{ |
446 |
|
struct any_writer *aw = aw_; |
447 |
|
any_writer_write_case (aw, c); |
448 |
|
return 0; |
449 |
} |
} |
450 |
|
|
|
/* Parses the XSAVE transformation command. */ |
|
451 |
int |
int |
452 |
cmd_xsave (void) |
cmd_save (void) |
453 |
{ |
{ |
454 |
struct save_trns *t = cmd_save_internal (); |
return parse_output_proc (SYSFILE_WRITER); |
|
if (t != NULL) |
|
|
{ |
|
|
add_transformation (&t->h); |
|
|
return CMD_SUCCESS; |
|
|
} |
|
|
else |
|
|
return CMD_FAILURE; |
|
455 |
} |
} |
456 |
|
|
457 |
/* Writes the given C to the file specified by T. */ |
int |
458 |
static void |
cmd_export (void) |
|
do_write_case (struct save_trns *t, struct ccase *c) |
|
459 |
{ |
{ |
460 |
if (t->map == NULL) |
return parse_output_proc (PORFILE_WRITER); |
|
sfm_write_case (t->writer, c); |
|
|
else |
|
|
{ |
|
|
map_case (t->map, c, &t->bounce); |
|
|
sfm_write_case (t->writer, &t->bounce); |
|
|
} |
|
461 |
} |
} |
462 |
|
|
463 |
|
/* XSAVE and XEXPORT. */ |
464 |
|
|
465 |
|
/* Transformation. */ |
466 |
|
struct output_trns |
467 |
|
{ |
468 |
|
struct trns_header h; /* Header. */ |
469 |
|
struct any_writer *aw; /* Writer. */ |
470 |
|
}; |
471 |
|
|
472 |
|
static trns_proc_func output_trns_proc; |
473 |
|
static trns_free_func output_trns_free; |
474 |
|
|
475 |
/* Writes case C to the system file specified on SAVE. */ |
/* Parses the XSAVE or XEXPORT transformation command. */ |
476 |
static int |
static int |
477 |
save_write_case_func (struct ccase *c, void *aux UNUSED) |
parse_output_trns (enum writer_type writer_type) |
478 |
{ |
{ |
479 |
do_write_case (aux, c); |
struct output_trns *t = xmalloc (sizeof *t); |
480 |
return 1; |
t->h.proc = output_trns_proc; |
481 |
|
t->h.free = output_trns_free; |
482 |
|
t->aw = parse_write_command (writer_type, XFORM_CMD, NULL); |
483 |
|
if (t->aw == NULL) |
484 |
|
{ |
485 |
|
free (t); |
486 |
|
return CMD_FAILURE; |
487 |
|
} |
488 |
|
|
489 |
|
add_transformation (&t->h); |
490 |
|
return CMD_SUCCESS; |
491 |
} |
} |
492 |
|
|
493 |
/* Writes case C to the system file specified on XSAVE. */ |
/* Writes case C to the system file specified on XSAVE or XEXPORT. */ |
494 |
static int |
static int |
495 |
save_trns_proc (struct trns_header *h, struct ccase *c, int case_num UNUSED) |
output_trns_proc (struct trns_header *h, struct ccase *c, int case_num UNUSED) |
496 |
{ |
{ |
497 |
struct save_trns *t = (struct save_trns *) h; |
struct output_trns *t = (struct output_trns *) h; |
498 |
do_write_case (t, c); |
any_writer_write_case (t->aw, c); |
499 |
return -1; |
return -1; |
500 |
} |
} |
501 |
|
|
502 |
/* Frees a SAVE transformation. */ |
/* Frees an XSAVE or XEXPORT transformation. */ |
503 |
static void |
static void |
504 |
save_trns_free (struct trns_header *t_) |
output_trns_free (struct trns_header *h) |
505 |
{ |
{ |
506 |
struct save_trns *t = (struct save_trns *) t_; |
struct output_trns *t = (struct output_trns *) h; |
507 |
|
|
508 |
if (t != NULL) |
if (t != NULL) |
509 |
{ |
{ |
510 |
sfm_close_writer (t->writer); |
any_writer_destroy (t->aw); |
511 |
destroy_case_map (t->map); |
free (t); |
|
case_destroy (&t->bounce); |
|
512 |
} |
} |
513 |
} |
} |
514 |
|
|
515 |
|
/* XSAVE command. */ |
516 |
|
int |
517 |
|
cmd_xsave (void) |
518 |
|
{ |
519 |
|
return parse_output_trns (SYSFILE_WRITER); |
520 |
|
} |
521 |
|
|
522 |
|
/* XEXPORT command. */ |
523 |
|
int |
524 |
|
cmd_xexport (void) |
525 |
|
{ |
526 |
|
return parse_output_trns (PORFILE_WRITER); |
527 |
|
} |
528 |
|
|
529 |
static bool rename_variables (struct dictionary *dict); |
static bool rename_variables (struct dictionary *dict); |
530 |
static bool drop_variables (struct dictionary *dict); |
static bool drop_variables (struct dictionary *dict); |
531 |
static bool keep_variables (struct dictionary *dict); |
static bool keep_variables (struct dictionary *dict); |
533 |
/* Commands that read and write system files share a great deal |
/* Commands that read and write system files share a great deal |
534 |
of common syntactic structure for rearranging and dropping |
of common syntactic structure for rearranging and dropping |
535 |
variables. This function parses this syntax and modifies DICT |
variables. This function parses this syntax and modifies DICT |
536 |
appropriately. |
appropriately. Returns true on success, false on failure. */ |
|
|
|
|
OP is the operation being performed. For operations that |
|
|
write a system file, *COMPRESS is set to 1 if the system file |
|
|
should be compressed, 0 otherwise. |
|
|
|
|
|
Returns true on success, false on failure. */ |
|
537 |
static bool |
static bool |
538 |
trim_dictionary (struct dictionary *dict, enum operation op, int *compress) |
parse_dict_trim (struct dictionary *dict) |
539 |
{ |
{ |
540 |
assert ((compress != NULL) == (op == OP_SAVE)); |
if (lex_match_id ("MAP")) |
541 |
if (get_scompression()) |
{ |
542 |
*compress = 1; |
/* FIXME. */ |
543 |
|
return true; |
|
if (op == OP_SAVE || op == OP_EXPORT) |
|
|
{ |
|
|
/* Delete all the scratch variables. */ |
|
|
struct variable **v; |
|
|
size_t nv; |
|
|
size_t i; |
|
|
|
|
|
v = xmalloc (sizeof *v * dict_get_var_cnt (dict)); |
|
|
nv = 0; |
|
|
for (i = 0; i < dict_get_var_cnt (dict); i++) |
|
|
if (dict_class_from_id (dict_get_var (dict, i)->name) == DC_SCRATCH) |
|
|
v[nv++] = dict_get_var (dict, i); |
|
|
dict_delete_vars (dict, v, nv); |
|
|
free (v); |
|
544 |
} |
} |
545 |
|
else if (lex_match_id ("DROP")) |
546 |
while (lex_match ('/')) |
return drop_variables (dict); |
547 |
|
else if (lex_match_id ("KEEP")) |
548 |
|
return keep_variables (dict); |
549 |
|
else if (lex_match_id ("RENAME")) |
550 |
|
return rename_variables (dict); |
551 |
|
else |
552 |
{ |
{ |
553 |
bool ok = true; |
lex_error (_("expecting a valid subcommand")); |
554 |
|
return false; |
|
if (op == OP_SAVE && lex_match_id ("COMPRESSED")) |
|
|
*compress = 1; |
|
|
else if (op == OP_SAVE && lex_match_id ("UNCOMPRESSED")) |
|
|
*compress = 0; |
|
|
else if (lex_match_id ("DROP")) |
|
|
ok = drop_variables (dict); |
|
|
else if (lex_match_id ("KEEP")) |
|
|
ok = keep_variables (dict); |
|
|
else if (lex_match_id ("RENAME")) |
|
|
ok = rename_variables (dict); |
|
|
else |
|
|
{ |
|
|
lex_error (_("expecting a valid subcommand")); |
|
|
ok = false; |
|
|
} |
|
|
|
|
|
if (!ok) |
|
|
return false; |
|
555 |
} |
} |
|
|
|
|
if (!lex_end_of_command ()) |
|
|
return false; |
|
|
|
|
|
dict_compact_values (dict); |
|
|
return true; |
|
556 |
} |
} |
557 |
|
|
558 |
/* Parses and performs the RENAME subcommand of GET and SAVE. */ |
/* Parses and performs the RENAME subcommand of GET and SAVE. */ |
616 |
if (nn != nv) |
if (nn != nv) |
617 |
{ |
{ |
618 |
msg (SE, _("Number of variables on left side of `=' (%d) does not " |
msg (SE, _("Number of variables on left side of `=' (%d) does not " |
619 |
"match number of variables on right side (%d), in " |
"match number of variables on right side (%d), in " |
620 |
"parenthesized group %d of RENAME subcommand."), |
"parenthesized group %d of RENAME subcommand."), |
621 |
nv - old_nv, nn - old_nv, group); |
nv - old_nv, nn - old_nv, group); |
622 |
goto done; |
goto done; |
623 |
} |
} |
633 |
} |
} |
634 |
success = 1; |
success = 1; |
635 |
|
|
636 |
done: |
done: |
637 |
for (i = 0; i < nn; i++) |
for (i = 0; i < nn; i++) |
638 |
free (new_names[i]); |
free (new_names[i]); |
639 |
free (new_names); |
free (new_names); |
690 |
return true; |
return true; |
691 |
} |
} |
692 |
|
|
|
/* EXPORT procedure. */ |
|
|
struct export_proc |
|
|
{ |
|
|
struct pfm_writer *writer; /* System file writer. */ |
|
|
struct case_map *map; /* Map from active file to system file dict. */ |
|
|
struct ccase bounce; /* Bounce buffer. */ |
|
|
}; |
|
|
|
|
|
static int export_write_case_func (struct ccase *, void *); |
|
|
static void export_proc_free (struct export_proc *); |
|
|
|
|
|
/* Parses the EXPORT command. */ |
|
|
/* FIXME: same as cmd_save_internal(). */ |
|
|
int |
|
|
cmd_export (void) |
|
|
{ |
|
|
struct file_handle *fh; |
|
|
struct dictionary *dict; |
|
|
struct export_proc *proc; |
|
|
|
|
|
proc = xmalloc (sizeof *proc); |
|
|
proc->writer = NULL; |
|
|
proc->map = NULL; |
|
|
case_nullify (&proc->bounce); |
|
|
|
|
|
lex_match ('/'); |
|
|
if (lex_match_id ("OUTFILE")) |
|
|
lex_match ('='); |
|
|
fh = fh_parse (); |
|
|
if (fh == NULL) |
|
|
return CMD_FAILURE; |
|
|
|
|
|
dict = dict_clone (default_dict); |
|
|
start_case_map (dict); |
|
|
if (!trim_dictionary (dict, OP_EXPORT, NULL)) |
|
|
goto error; |
|
|
proc->map = finish_case_map (dict); |
|
|
if (proc->map != NULL) |
|
|
case_create (&proc->bounce, dict_get_next_value_idx (dict)); |
|
|
|
|
|
proc->writer = pfm_open_writer (fh, dict); |
|
|
if (proc->writer == NULL) |
|
|
goto error; |
|
|
|
|
|
dict_destroy (dict); |
|
|
|
|
|
procedure (export_write_case_func, proc); |
|
|
export_proc_free (proc); |
|
|
free (proc); |
|
|
|
|
|
return CMD_SUCCESS; |
|
|
|
|
|
error: |
|
|
dict_destroy (dict); |
|
|
export_proc_free (proc); |
|
|
free (proc); |
|
|
return CMD_FAILURE; |
|
|
} |
|
|
|
|
|
/* Writes case C to the EXPORT file. */ |
|
|
static int |
|
|
export_write_case_func (struct ccase *c, void *aux) |
|
|
{ |
|
|
struct export_proc *proc = aux; |
|
|
if (proc->map == NULL) |
|
|
pfm_write_case (proc->writer, c); |
|
|
else |
|
|
{ |
|
|
map_case (proc->map, c, &proc->bounce); |
|
|
pfm_write_case (proc->writer, &proc->bounce); |
|
|
} |
|
|
return 1; |
|
|
} |
|
|
|
|
|
static void |
|
|
export_proc_free (struct export_proc *proc) |
|
|
{ |
|
|
if (proc != NULL) |
|
|
{ |
|
|
pfm_close_writer (proc->writer); |
|
|
destroy_case_map (proc->map); |
|
|
case_destroy (&proc->bounce); |
|
|
} |
|
|
} |
|
|
|
|
693 |
/* MATCH FILES. */ |
/* MATCH FILES. */ |
694 |
|
|
695 |
#include "debug-print.h" |
#include "debug-print.h" |
704 |
/* One of the files on MATCH FILES. */ |
/* One of the files on MATCH FILES. */ |
705 |
struct mtf_file |
struct mtf_file |
706 |
{ |
{ |
707 |
struct mtf_file *next, *prev; |
struct mtf_file *next, *prev; /* Next, previous in the list of files. */ |
|
/* Next, previous in the list of files. */ |
|
708 |
struct mtf_file *next_min; /* Next in the chain of minimums. */ |
struct mtf_file *next_min; /* Next in the chain of minimums. */ |
709 |
|
|
710 |
int type; /* One of MTF_*. */ |
int type; /* One of MTF_*. */ |
726 |
struct mtf_file *head; /* First file mentioned on FILE or TABLE. */ |
struct mtf_file *head; /* First file mentioned on FILE or TABLE. */ |
727 |
struct mtf_file *tail; /* Last file mentioned on FILE or TABLE. */ |
struct mtf_file *tail; /* Last file mentioned on FILE or TABLE. */ |
728 |
|
|
729 |
size_t by_cnt; /* Number of variables on BY subcommand. */ |
int by_cnt; /* Number of variables on BY subcommand. */ |
730 |
|
|
731 |
/* Names of FIRST, LAST variables. */ |
/* Names of FIRST, LAST variables. */ |
732 |
char first[LONG_NAME_LEN + 1], last[LONG_NAME_LEN + 1]; |
char first[LONG_NAME_LEN + 1], last[LONG_NAME_LEN + 1]; |
1100 |
mtf_free (&mtf); |
mtf_free (&mtf); |
1101 |
return CMD_SUCCESS; |
return CMD_SUCCESS; |
1102 |
|
|
1103 |
error: |
error: |
1104 |
mtf_free (&mtf); |
mtf_free (&mtf); |
1105 |
return CMD_FAILURE; |
return CMD_FAILURE; |
1106 |
} |
} |
1520 |
struct import_pgm *pgm = NULL; |
struct import_pgm *pgm = NULL; |
1521 |
struct file_handle *fh = NULL; |
struct file_handle *fh = NULL; |
1522 |
struct dictionary *dict = NULL; |
struct dictionary *dict = NULL; |
1523 |
int type; |
enum pfm_type type; |
|
|
|
|
pgm = xmalloc (sizeof *pgm); |
|
|
pgm->reader = NULL; |
|
|
pgm->map = NULL; |
|
|
case_nullify (&pgm->bounce); |
|
1524 |
|
|
1525 |
|
lex_match ('/'); |
1526 |
for (;;) |
for (;;) |
1527 |
{ |
{ |
1528 |
lex_match ('/'); |
if (pgm == NULL && (lex_match_id ("FILE") || token == T_STRING)) |
|
|
|
|
if (lex_match_id ("FILE") || token == T_STRING) |
|
1529 |
{ |
{ |
1530 |
lex_match ('='); |
lex_match ('='); |
1531 |
|
|
1532 |
fh = fh_parse (); |
fh = fh_parse (); |
1533 |
if (fh == NULL) |
if (fh == NULL) |
1534 |
return CMD_FAILURE; |
goto error; |
1535 |
} |
} |
1536 |
else if (lex_match_id ("TYPE")) |
else if (pgm == NULL && lex_match_id ("TYPE")) |
1537 |
{ |
{ |
1538 |
lex_match ('='); |
lex_match ('='); |
1539 |
|
|
1544 |
else |
else |
1545 |
{ |
{ |
1546 |
lex_error (_("expecting COMM or TAPE")); |
lex_error (_("expecting COMM or TAPE")); |
1547 |
return CMD_FAILURE; |
goto error; |
1548 |
} |
} |
1549 |
} |
} |
1550 |
else break; |
else |
1551 |
|
{ |
1552 |
|
if (pgm == NULL) |
1553 |
|
{ |
1554 |
|
if (fh == NULL) |
1555 |
|
{ |
1556 |
|
lex_sbc_missing ("FILE"); |
1557 |
|
goto error; |
1558 |
|
} |
1559 |
|
|
1560 |
|
discard_variables (); |
1561 |
|
|
1562 |
|
pgm = xmalloc (sizeof *pgm); |
1563 |
|
pgm->reader = pfm_open_reader (fh, &dict, NULL); |
1564 |
|
pgm->map = NULL; |
1565 |
|
case_nullify (&pgm->bounce); |
1566 |
|
if (pgm->reader == NULL) |
1567 |
|
goto error; |
1568 |
|
|
1569 |
|
case_create (&pgm->bounce, dict_get_next_value_idx (dict)); |
1570 |
|
|
1571 |
|
start_case_map (dict); |
1572 |
|
} |
1573 |
|
|
1574 |
|
if (token == '.') |
1575 |
|
break; |
1576 |
|
|
1577 |
|
if (!parse_dict_trim (dict)) |
1578 |
|
goto error; |
1579 |
|
} |
1580 |
|
|
1581 |
|
lex_match ('/'); |
1582 |
} |
} |
1583 |
if (!lex_match ('/') && token != '.') |
if (pgm == NULL) |
1584 |
{ |
{ |
1585 |
lex_error (NULL); |
lex_error (NULL); |
1586 |
return CMD_FAILURE; |
goto error; |
1587 |
} |
} |
1588 |
|
|
|
discard_variables (); |
|
|
|
|
|
pgm->reader = pfm_open_reader (fh, &dict, NULL); |
|
|
if (pgm->reader == NULL) |
|
|
return CMD_FAILURE; |
|
|
case_create (&pgm->bounce, dict_get_next_value_idx (dict)); |
|
|
|
|
|
start_case_map (dict); |
|
|
if (!trim_dictionary (dict, OP_READ, NULL)) |
|
|
goto error; |
|
1589 |
pgm->map = finish_case_map (dict); |
pgm->map = finish_case_map (dict); |
1590 |
|
|
1591 |
dict_destroy (default_dict); |
dict_destroy (default_dict); |
1680 |
at will before using finish_case_map() to produce the case |
at will before using finish_case_map() to produce the case |
1681 |
map. |
map. |
1682 |
|
|
1683 |
Uses D's aux members, which may not otherwise be in use. */ |
Uses D's aux members, which must otherwise not be in use. */ |
1684 |
static void |
static void |
1685 |
start_case_map (struct dictionary *d) |
start_case_map (struct dictionary *d) |
1686 |
{ |
{ |