1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
36 /* Variables to transpose. */
37 static struct variable **var;
40 /* Variable containing new variable names. */
41 static struct variable *newnames;
43 /* List of variable names. */
50 /* New variable names. */
51 static struct varname *new_names_head, *new_names_tail;
52 static int case_count;
54 static int build_dictionary (void);
56 /* Parses and executes FLIP. */
60 lex_match_id ("FLIP");
62 if (lex_match_id ("VARIABLES"))
65 if (!parse_variables (default_dict, &var, &nvar, PV_NO_DUPLICATE))
70 dict_get_vars (default_dict, &var, &nvar, 1u << DC_SYSTEM);
73 if (lex_match_id ("NEWNAMES"))
76 newnames = parse_variable ();
84 newnames = dict_lookup_var (default_dict, "CASE_LBL");
90 for (i = 0; i < nvar; i++)
91 if (var[i] == newnames)
93 memmove (&var[i], &var[i + 1], sizeof *var * (nvar - i - 1));
100 temp_trns = temporary = 0;
101 vfm_sink = &flip_stream;
102 new_names_tail = NULL;
103 procedure (NULL, NULL, NULL, NULL);
105 dict_clear (default_dict);
106 if (!build_dictionary ())
108 discard_variables ();
114 return lex_end_of_command ();
117 /* Make a new variable with base name NAME, which is bowdlerized and
118 mangled until acceptable, and returns success. */
120 make_new_var (char name[])
122 /* Fix invalid characters. */
126 for (cp = name; *cp && !isspace (*cp); cp++)
128 *cp = toupper ((unsigned char) *cp);
129 if (!isalpha (*cp) && *cp != '@' && *cp != '#'
130 && (cp == name || (*cp != '.' && *cp != '$' && *cp != '_'
134 *cp = 'V'; /* _ not valid in first position. */
142 if (dict_create_var (default_dict, name, 0))
145 /* Add numeric extensions until acceptable. */
147 int len = (int) strlen (name);
151 for (i = 1; i < 10000000; i++)
153 int ofs = min (7 - intlog10 (i), len);
154 memcpy (n, name, ofs);
155 sprintf (&n[ofs], "%d", i);
157 if (dict_create_var (default_dict, n, 0))
162 msg (SE, _("Could not create acceptable variant for variable %s."), name);
166 /* Make a new dictionary for all the new variable names. */
168 build_dictionary (void)
170 dict_create_var_assert (default_dict, "CASE_LBL", 8);
176 if (case_count > 99999)
178 msg (SE, _("Cannot create more than 99999 variable names."));
182 for (i = 0; i < case_count; i++)
187 sprintf (s, "VAR%03d", i);
188 v = dict_create_var_assert (default_dict, s, 0);
193 struct varname *v, *n;
195 new_names_tail->next = NULL;
196 for (v = new_names_head; v; v = n)
199 if (!make_new_var (v->name))
216 /* Each case to be transposed. */
219 struct flip_case *next;
223 /* Sink: Cases during transposition. */
224 static int internal; /* Internal vs. external flipping. */
225 static char *sink_old_names; /* Old variable names. */
226 static unsigned long sink_cases; /* Number of cases. */
227 static struct flip_case *head, *tail; /* internal == 1: Cases. */
228 static FILE *sink_file; /* internal == 0: Temporary file. */
230 /* Source: Cases after transposition. */
231 static struct flip_case *src; /* Internal transposition records. */
232 static char *src_old_names; /* Old variable names. */
233 static unsigned long src_cases; /* Number of cases. */
234 static FILE *src_file; /* src == NULL: Temporary file. */
236 /* Initialize the FLIP stream. */
238 flip_stream_init (void)
249 for (i = 0; i < nvar; i++)
250 n += strlen (var[i]->name);
251 p = sink_old_names = xmalloc (n);
252 for (i = 0; i < nvar; i++)
253 p = stpcpy (p, var[i]->name) + 1;
257 /* Reads the FLIP stream and passes it to write_case(). */
259 flip_stream_read (write_case_func *write_case, write_case_data wc_data)
261 if (src || (src == NULL && src_file == NULL))
263 /* Internal transposition, or empty file. */
265 char *p = src_old_names;
267 for (i = 0; i < nvar; i++)
269 struct flip_case *iter;
271 st_bare_pad_copy (temp_case->data[0].s, p, 8);
272 p = strchr (p, 0) + 1;
274 for (iter = src, j = 1; iter; iter = iter->next, j++)
275 temp_case->data[j].f = iter->v[i];
277 if (!write_case (wc_data))
284 char *p = src_old_names;
286 for (i = 0; i < nvar; i++)
288 st_bare_pad_copy (temp_case->data[0].s, p, 8);
289 p = strchr (p, 0) + 1;
291 if (fread (&temp_case->data[1], sizeof (double), src_cases,
292 src_file) != src_cases)
293 msg (FE, _("Error reading FLIP source file: %s."),
296 if (!write_case (wc_data))
302 /* Writes temp_case to the FLIP stream. */
304 flip_stream_write (void)
310 struct varname *v = xmalloc (sizeof (struct varname));
311 if (newnames->type == NUMERIC)
313 double f = temp_case->data[newnames->fv].f;
316 strcpy (v->name, "VSYSMIS");
317 else if (f < INT_MIN)
318 strcpy (v->name, "VNEGINF");
319 else if (f > INT_MAX)
320 strcpy (v->name, "VPOSINF");
323 char name[INT_DIGITS + 2];
324 sprintf (name, "V%d", (int) f);
325 strncpy (v->name, name, 8);
331 int width = min (newnames->width, 8);
332 memcpy (v->name, temp_case->data[newnames->fv].s, width);
336 if (new_names_tail == NULL)
339 new_names_tail->next = v;
348 flip_case *c = malloc (sizeof (flip_case)
349 + sizeof (double) * (nvar - 1));
353 /* Write to internal file. */
356 for (i = 0; i < nvar; i++)
357 if (var[i]->type == NUMERIC)
358 c->v[i] = temp_case->data[var[i]->fv].f;
373 /* Initialize external file. */
374 struct flip_case *iter, *next;
378 sink_file = tmpfile ();
380 msg (FE, _("Could not create temporary file for FLIP."));
384 for (iter = head; iter; iter = next)
388 if (fwrite (iter->v, sizeof (double), nvar, sink_file)
390 msg (FE, _("Error writing FLIP file: %s."),
397 /* Write to external file. */
399 double *d = local_alloc (sizeof *d * nvar);
402 for (i = 0; i < nvar; i++)
403 if (var[i]->type == NUMERIC)
404 d[i] = temp_case->data[var[i]->fv].f;
408 if (fwrite (d, sizeof *d, nvar, sink_file) != (size_t) nvar)
409 msg (FE, _("Error writing FLIP file: %s."),
416 /* Transpose the external file. */
418 transpose_external_file (void)
420 unsigned long n_cases;
421 unsigned long cur_case;
422 double *case_buf, *temp_buf;
424 n_cases = 4 * 1024 * 1024 / ((nvar + 1) * sizeof *case_buf);
429 assert (n_cases >= 2 /* 1 */);
430 case_buf = ((n_cases <= 2 ? xmalloc : (void *(*)(size_t)) malloc)
431 ((nvar + 1) * sizeof *case_buf * n_cases));
440 /* A temporary buffer that holds n_cases elements. */
441 temp_buf = &case_buf[nvar * n_cases];
443 src_file = tmpfile ();
445 msg (FE, _("Error creating FLIP source file."));
447 if (fseek (sink_file, 0, SEEK_SET) != 0)
448 msg (FE, _("Error rewinding FLIP file: %s."), strerror (errno));
450 for (cur_case = 0; cur_case < sink_cases; )
452 unsigned long read_cases = min (sink_cases - cur_case, n_cases);
455 if (read_cases != fread (case_buf, sizeof *case_buf * nvar,
456 read_cases, sink_file))
457 msg (FE, _("Error reading FLIP file: %s."), strerror (errno));
459 for (i = 0; i < nvar; i++)
463 for (j = 0; j < read_cases; j++)
464 temp_buf[j] = case_buf[i + j * nvar];
467 sizeof *case_buf * (cur_case + i * sink_cases),
469 msg (FE, _("Error seeking FLIP source file: %s."),
472 if (fwrite (temp_buf, sizeof *case_buf, read_cases, src_file)
474 msg (FE, _("Error writing FLIP source file: %s."),
478 cur_case += read_cases;
481 if (fseek (src_file, 0, SEEK_SET) != 0)
482 msg (FE, _("Error rewind FLIP source file: %s."), strerror (errno));
489 /* Change the FLIP stream from sink to source mode. */
491 flip_stream_mode (void)
493 src_cases = sink_cases;
494 src_old_names = sink_old_names;
495 sink_old_names = NULL;
513 transpose_external_file ();
517 /* Destroy source's internal data. */
519 flip_stream_destroy_source (void)
521 free (src_old_names);
524 struct flip_case *iter, *next;
526 for (iter = src; iter; iter = next)
536 /* Destroy sink's internal data. */
538 flip_stream_destroy_sink (void)
540 struct flip_case *iter, *next;
542 free (sink_old_names);
547 for (iter = head; iter; iter = next)
554 struct case_stream flip_stream =
560 flip_stream_destroy_source,
561 flip_stream_destroy_sink,