Moved the SIGINT handler from casefile.c to main.c
[pspp-builds.git] / src / casefile.c
1 /* PSPP - computes sample statistics.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3    Written by Ben Pfaff <blp@gnu.org>.
4
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.
9
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.
14
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
18    02111-1307, USA. */
19
20 #include <config.h>
21 #include "casefile.h"
22 #include <assert.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include "alloc.h"
30 #include "case.h"
31 #include "error.h"
32 #include "misc.h"
33 #include "settings.h"
34 #include "var.h"
35
36 #ifdef HAVE_VALGRIND_VALGRIND_H
37 #include <valgrind/valgrind.h>
38 #endif
39
40 #define IO_BUF_SIZE (8192 / sizeof (union value))
41
42 /* A casefile is a sequentially accessible array of immutable
43    cases.  It may be stored in memory or on disk as workspace
44    allows.  Cases may be appended to the end of the file.  Cases
45    may be read sequentially starting from the beginning of the
46    file.  Once any cases have been read, no more cases may be
47    appended.  The entire file is discarded at once. */
48
49 /* In-memory cases are arranged in an array of arrays.  The top
50    level is variable size and the size of each bottom level array
51    is fixed at the number of cases defined here.  */
52 #define CASES_PER_BLOCK 128             
53
54 /* A casefile. */
55 struct casefile 
56   {
57     /* Basic data. */
58     struct casefile *next, *prev;       /* Next, prev in global list. */
59     size_t value_cnt;                   /* Case size in `union value's. */
60     size_t case_acct_size;              /* Case size for accounting. */
61     unsigned long case_cnt;             /* Number of cases stored. */
62     enum { MEMORY, DISK } storage;      /* Where cases are stored. */
63     enum { WRITE, READ } mode;          /* Is writing or reading allowed? */
64     struct casereader *readers;         /* List of our readers. */
65     int being_destroyed;                /* Does a destructive reader exist? */
66
67     /* Memory storage. */
68     struct ccase **cases;               /* Pointer to array of cases. */
69
70     /* Disk storage. */
71     int fd;                             /* File descriptor, -1 if none. */
72     char *filename;                     /* Filename. */
73     union value *buffer;                /* I/O buffer, NULL if none. */
74     size_t buffer_used;                 /* Number of values used in buffer. */
75     size_t buffer_size;                 /* Buffer size in values. */
76   };
77
78 /* For reading out the cases in a casefile. */
79 struct casereader 
80   {
81     struct casereader *next, *prev;     /* Next, prev in casefile's list. */
82     struct casefile *cf;                /* Our casefile. */
83     unsigned long case_idx;             /* Case number of current case. */
84     int destructive;                    /* Is this a destructive reader? */
85
86     /* Disk storage. */
87     int fd;                             /* File descriptor. */
88     union value *buffer;                /* I/O buffer. */
89     size_t buffer_pos;                  /* Offset of buffer position. */
90     struct ccase c;                     /* Current case. */
91   };
92
93 /* Return the case number of the current case */
94 unsigned long
95 casereader_cnum(const struct casereader *r)
96 {
97   return r->case_idx;
98 }
99
100 /* Doubly linked list of all casefiles. */
101 static struct casefile *casefiles;
102
103 /* Number of bytes of case allocated in in-memory casefiles. */
104 static size_t case_bytes;
105
106 static void register_atexit (void);
107 static void exit_handler (void);
108
109 static void reader_open_file (struct casereader *reader);
110 static void write_case_to_disk (struct casefile *cf, const struct ccase *c);
111 static void flush_buffer (struct casefile *cf);
112 static void fill_buffer (struct casereader *reader);
113
114 static int safe_open (const char *filename, int flags);
115 static int safe_close (int fd);
116 static int full_read (int fd, void *buffer, size_t size);
117 static int full_write (int fd, const void *buffer, size_t size);
118
119 /* Creates and returns a casefile to store cases of VALUE_CNT
120    `union value's each. */
121 struct casefile *
122 casefile_create (size_t value_cnt) 
123 {
124   struct casefile *cf = xmalloc (sizeof *cf);
125   cf->next = casefiles;
126   cf->prev = NULL;
127   if (cf->next != NULL)
128     cf->next->prev = cf;
129   casefiles = cf;
130   cf->value_cnt = value_cnt;
131   cf->case_acct_size = (cf->value_cnt + 4) * sizeof *cf->buffer;
132   cf->case_cnt = 0;
133   cf->storage = MEMORY;
134   cf->mode = WRITE;
135   cf->readers = NULL;
136   cf->being_destroyed = 0;
137   cf->cases = NULL;
138   cf->fd = -1;
139   cf->filename = NULL;
140   cf->buffer = NULL;
141   cf->buffer_size = ROUND_UP (cf->value_cnt, IO_BUF_SIZE);
142   if (cf->value_cnt > 0 && cf->buffer_size % cf->value_cnt > 64)
143     cf->buffer_size = cf->value_cnt;
144   cf->buffer_used = 0;
145   register_atexit ();
146   return cf;
147 }
148
149 /* Destroys casefile CF. */
150 void
151 casefile_destroy (struct casefile *cf) 
152 {
153   if (cf != NULL) 
154     {
155       if (cf->next != NULL)
156         cf->next->prev = cf->prev;
157       if (cf->prev != NULL)
158         cf->prev->next = cf->next;
159       if (casefiles == cf)
160         casefiles = cf->next;
161
162       while (cf->readers != NULL) 
163         casereader_destroy (cf->readers);
164
165       if (cf->cases != NULL) 
166         {
167           size_t idx, block_cnt;
168
169           case_bytes -= cf->case_cnt * cf->case_acct_size;
170           for (idx = 0; idx < cf->case_cnt; idx++)
171             {
172               size_t block_idx = idx / CASES_PER_BLOCK;
173               size_t case_idx = idx % CASES_PER_BLOCK;
174               struct ccase *c = &cf->cases[block_idx][case_idx];
175               case_destroy (c);
176             }
177
178           block_cnt = DIV_RND_UP (cf->case_cnt, CASES_PER_BLOCK);
179           for (idx = 0; idx < block_cnt; idx++)
180             free (cf->cases[idx]);
181
182           free (cf->cases);
183         }
184
185       if (cf->fd != -1)
186         safe_close (cf->fd);
187           
188       if (cf->filename != NULL && remove (cf->filename) == -1) 
189         msg (ME, _("%s: Removing temporary file: %s."),
190              cf->filename, strerror (errno));
191       free (cf->filename);
192
193       free (cf->buffer);
194
195       free (cf);
196     }
197 }
198
199 /* Returns nonzero only if casefile CF is stored in memory (instead of on
200    disk). */
201 int
202 casefile_in_core (const struct casefile *cf) 
203 {
204   assert (cf != NULL);
205
206   return cf->storage == MEMORY;
207 }
208
209 /* Puts a casefile to "sleep", that is, minimizes the resources
210    needed for it by closing its file descriptor and freeing its
211    buffer.  This is useful if we need so many casefiles that we
212    might not have enough memory and file descriptors to go
213    around.
214
215    For simplicity, this implementation always converts the
216    casefile to reader mode.  If this turns out to be a problem,
217    with a little extra work we could also support sleeping
218    writers. */
219 void
220 casefile_sleep (const struct casefile *cf_) 
221 {
222   struct casefile *cf = (struct casefile *) cf_;
223   assert (cf != NULL);
224
225   casefile_mode_reader (cf);
226   casefile_to_disk (cf);
227   flush_buffer (cf);
228
229   if (cf->fd != -1) 
230     {
231       safe_close (cf->fd);
232       cf->fd = -1;
233     }
234   if (cf->buffer != NULL) 
235     {
236       free (cf->buffer);
237       cf->buffer = NULL;
238     }
239 }
240
241 /* Returns the number of `union value's in a case for CF. */
242 size_t
243 casefile_get_value_cnt (const struct casefile *cf) 
244 {
245   assert (cf != NULL);
246
247   return cf->value_cnt;
248 }
249
250 /* Returns the number of cases in casefile CF. */
251 unsigned long
252 casefile_get_case_cnt (const struct casefile *cf) 
253 {
254   assert (cf != NULL);
255
256   return cf->case_cnt;
257 }
258
259 /* Appends a copy of case C to casefile CF.  Not valid after any
260    reader for CF has been created. */
261 void
262 casefile_append (struct casefile *cf, const struct ccase *c) 
263 {
264   assert (cf != NULL);
265   assert (c != NULL);
266   assert (cf->mode == WRITE);
267
268   /* Try memory first. */
269   if (cf->storage == MEMORY) 
270     {
271       if (case_bytes < get_max_workspace ())
272         {
273           size_t block_idx = cf->case_cnt / CASES_PER_BLOCK;
274           size_t case_idx = cf->case_cnt % CASES_PER_BLOCK;
275           struct ccase new_case;
276
277           case_bytes += cf->case_acct_size;
278           case_clone (&new_case, c);
279           if (case_idx == 0) 
280             {
281               if ((block_idx & (block_idx - 1)) == 0) 
282                 {
283                   size_t block_cap = block_idx == 0 ? 1 : block_idx * 2;
284                   cf->cases = xrealloc (cf->cases,
285                                         sizeof *cf->cases * block_cap);
286                 }
287
288               cf->cases[block_idx] = xmalloc (sizeof **cf->cases
289                                               * CASES_PER_BLOCK);
290             }
291
292           case_move (&cf->cases[block_idx][case_idx], &new_case);
293         }
294       else
295         {
296           casefile_to_disk (cf);
297           assert (cf->storage == DISK);
298           write_case_to_disk (cf, c);
299         }
300     }
301   else
302     write_case_to_disk (cf, c);
303
304   cf->case_cnt++;
305 }
306
307 /* Appends case C to casefile CF, which takes over ownership of
308    C.  Not valid after any reader for CF has been created. */
309 void
310 casefile_append_xfer (struct casefile *cf, struct ccase *c) 
311 {
312   casefile_append (cf, c);
313   case_destroy (c);
314 }
315
316 /* Writes case C to casefile CF's disk buffer, first flushing the buffer to
317    disk if it would otherwise overflow. */
318 static void
319 write_case_to_disk (struct casefile *cf, const struct ccase *c) 
320 {
321   case_to_values (c, cf->buffer + cf->buffer_used, cf->value_cnt);
322   cf->buffer_used += cf->value_cnt;
323   if (cf->buffer_used + cf->value_cnt > cf->buffer_size)
324     flush_buffer (cf);
325 }
326
327 /* If any bytes in CF's output buffer are used, flush them to
328    disk. */
329 static void
330 flush_buffer (struct casefile *cf) 
331 {
332   if (cf->buffer_used > 0) 
333     {
334       if (!full_write (cf->fd, cf->buffer,
335                        cf->buffer_size * sizeof *cf->buffer)) 
336         msg (FE, _("Error writing temporary file: %s."), strerror (errno));
337
338       cf->buffer_used = 0;
339     } 
340 }
341
342 /* Creates a temporary file and stores its name in *FILENAME and
343    a file descriptor for it in *FD.  Returns success.  Caller is
344    responsible for freeing *FILENAME. */
345 static int
346 make_temp_file (int *fd, char **filename)
347 {
348   const char *parent_dir;
349
350   assert (filename != NULL);
351   assert (fd != NULL);
352
353   if (getenv ("TMPDIR") != NULL)
354     parent_dir = getenv ("TMPDIR");
355   else
356     parent_dir = P_tmpdir;
357
358   *filename = xmalloc (strlen (parent_dir) + 32);
359   sprintf (*filename, "%s%cpsppXXXXXX", parent_dir, DIR_SEPARATOR);
360   *fd = mkstemp (*filename);
361   if (*fd < 0)
362     {
363       msg (FE, _("%s: Creating temporary file: %s."),
364            *filename, strerror (errno));
365       free (*filename);
366       *filename = NULL;
367       return 0;
368     }
369   return 1;
370 }
371
372 /* If CF is currently stored in memory, writes it to disk.  Readers, if any,
373    retain their current positions. */
374 void
375 casefile_to_disk (const struct casefile *cf_) 
376 {
377   struct casefile *cf = (struct casefile *) cf_;
378   struct casereader *reader;
379   
380   assert (cf != NULL);
381
382   if (cf->storage == MEMORY)
383     {
384       size_t idx, block_cnt;
385       
386       assert (cf->filename == NULL);
387       assert (cf->fd == -1);
388       assert (cf->buffer_used == 0);
389
390       cf->storage = DISK;
391       if (!make_temp_file (&cf->fd, &cf->filename))
392         err_failure ();
393       cf->buffer = xmalloc (cf->buffer_size * sizeof *cf->buffer);
394       memset (cf->buffer, 0, cf->buffer_size * sizeof *cf->buffer);
395
396       case_bytes -= cf->case_cnt * cf->case_acct_size;
397       for (idx = 0; idx < cf->case_cnt; idx++)
398         {
399           size_t block_idx = idx / CASES_PER_BLOCK;
400           size_t case_idx = idx % CASES_PER_BLOCK;
401           struct ccase *c = &cf->cases[block_idx][case_idx];
402           write_case_to_disk (cf, c);
403           case_destroy (c);
404         }
405
406       block_cnt = DIV_RND_UP (cf->case_cnt, CASES_PER_BLOCK);
407       for (idx = 0; idx < block_cnt; idx++)
408         free (cf->cases[idx]);
409
410       free (cf->cases);
411       cf->cases = NULL;
412
413       if (cf->mode == READ)
414         flush_buffer (cf);
415
416       for (reader = cf->readers; reader != NULL; reader = reader->next)
417         reader_open_file (reader);
418     }
419 }
420
421 /* Changes CF to reader mode, ensuring that no more cases may be
422    added.  Creating a casereader for CF has the same effect. */
423 void
424 casefile_mode_reader (struct casefile *cf) 
425 {
426   assert (cf != NULL);
427   cf->mode = READ;
428 }
429
430 /* Creates and returns a casereader for CF.  A casereader can be used to
431    sequentially read the cases in a casefile. */
432 struct casereader *
433 casefile_get_reader (const struct casefile *cf_) 
434 {
435   struct casefile *cf = (struct casefile *) cf_;
436   struct casereader *reader;
437
438   assert (cf != NULL);
439   assert (!cf->being_destroyed);
440
441   /* Flush the buffer to disk if it's not empty. */
442   if (cf->mode == WRITE && cf->storage == DISK)
443     flush_buffer (cf);
444   
445   cf->mode = READ;
446
447   reader = xmalloc (sizeof *reader);
448   reader->next = cf->readers;
449   if (cf->readers != NULL)
450     reader->next->prev = reader;
451   cf->readers = reader;
452   reader->prev = NULL;
453   reader->cf = cf;
454   reader->case_idx = 0;
455   reader->destructive = 0;
456   reader->fd = -1;
457   reader->buffer = NULL;
458   reader->buffer_pos = 0;
459   case_nullify (&reader->c);
460
461   if (reader->cf->storage == DISK) 
462     reader_open_file (reader);
463
464   return reader;
465 }
466
467 /* Creates and returns a destructive casereader for CF.  Like a
468    normal casereader, a destructive casereader sequentially reads
469    the cases in a casefile.  Unlike a normal casereader, a
470    destructive reader cannot operate concurrently with any other
471    reader.  (This restriction could be relaxed in a few ways, but
472    it is so far unnecessary for other code.) */
473 struct casereader *
474 casefile_get_destructive_reader (struct casefile *cf) 
475 {
476   struct casereader *reader;
477   
478   assert (cf->readers == NULL);
479   reader = casefile_get_reader (cf);
480   reader->destructive = 1;
481   cf->being_destroyed = 1;
482   return reader;
483 }
484
485 /* Opens a disk file for READER and seeks to the current position as indicated
486    by case_idx.  Normally the current position is the beginning of the file,
487    but casefile_to_disk may cause the file to be opened at a different
488    position. */
489 static void
490 reader_open_file (struct casereader *reader) 
491 {
492   struct casefile *cf = reader->cf;
493   off_t file_ofs;
494
495   if (reader->case_idx >= cf->case_cnt)
496     return;
497
498   if (cf->fd != -1) 
499     {
500       reader->fd = cf->fd;
501       cf->fd = -1;
502     }
503   else 
504     {
505       reader->fd = safe_open (cf->filename, O_RDONLY);
506       if (reader->fd < 0)
507         msg (FE, _("%s: Opening temporary file: %s."),
508              cf->filename, strerror (errno));
509     }
510
511   if (cf->buffer != NULL) 
512     {
513       reader->buffer = cf->buffer;
514       cf->buffer = NULL; 
515     }
516   else 
517     {
518       reader->buffer = xmalloc (cf->buffer_size * sizeof *cf->buffer);
519       memset (reader->buffer, 0, cf->buffer_size * sizeof *cf->buffer); 
520     }
521
522   if (cf->value_cnt != 0) 
523     {
524       size_t buffer_case_cnt = cf->buffer_size / cf->value_cnt;
525       file_ofs = ((off_t) reader->case_idx / buffer_case_cnt
526                   * cf->buffer_size * sizeof *cf->buffer);
527       reader->buffer_pos = (reader->case_idx % buffer_case_cnt
528                             * cf->value_cnt);
529     }
530   else 
531     file_ofs = 0;
532   if (lseek (reader->fd, file_ofs, SEEK_SET) != file_ofs)
533     msg (FE, _("%s: Seeking temporary file: %s."),
534          cf->filename, strerror (errno));
535
536   if (cf->case_cnt > 0 && cf->value_cnt > 0)
537     fill_buffer (reader);
538
539   case_create (&reader->c, cf->value_cnt);
540 }
541
542 /* Fills READER's buffer by reading a block from disk. */
543 static void
544 fill_buffer (struct casereader *reader)
545 {
546   int retval = full_read (reader->fd, reader->buffer,
547                           reader->cf->buffer_size * sizeof *reader->buffer);
548   if (retval < 0)
549     msg (FE, _("%s: Reading temporary file: %s."),
550          reader->cf->filename, strerror (errno));
551   else if (retval != reader->cf->buffer_size * sizeof *reader->buffer)
552     msg (FE, _("%s: Temporary file ended unexpectedly."),
553          reader->cf->filename); 
554 }
555
556 /* Returns the casefile that READER reads. */
557 const struct casefile *
558 casereader_get_casefile (const struct casereader *reader) 
559 {
560   assert (reader != NULL);
561   
562   return reader->cf;
563 }
564
565 /* Reads a copy of the next case from READER into C.
566    Caller is responsible for destroying C. */
567 int
568 casereader_read (struct casereader *reader, struct ccase *c) 
569 {
570   assert (reader != NULL);
571   
572   if (reader->case_idx >= reader->cf->case_cnt) 
573     return 0;
574
575   if (reader->cf->storage == MEMORY) 
576     {
577       size_t block_idx = reader->case_idx / CASES_PER_BLOCK;
578       size_t case_idx = reader->case_idx % CASES_PER_BLOCK;
579
580       case_clone (c, &reader->cf->cases[block_idx][case_idx]);
581       reader->case_idx++;
582       return 1;
583     }
584   else 
585     {
586       if (reader->buffer_pos + reader->cf->value_cnt > reader->cf->buffer_size)
587         {
588           fill_buffer (reader);
589           reader->buffer_pos = 0;
590         }
591
592       case_from_values (&reader->c, reader->buffer + reader->buffer_pos,
593                         reader->cf->value_cnt);
594       reader->buffer_pos += reader->cf->value_cnt;
595       reader->case_idx++;
596
597       case_clone (c, &reader->c);
598       return 1;
599     }
600 }
601
602 /* Reads the next case from READER into C and transfers ownership
603    to the caller.  Caller is responsible for destroying C. */
604 int
605 casereader_read_xfer (struct casereader *reader, struct ccase *c)
606 {
607   assert (reader != NULL);
608
609   if (reader->destructive == 0
610       || reader->case_idx >= reader->cf->case_cnt
611       || reader->cf->storage == DISK) 
612     return casereader_read (reader, c);
613   else 
614     {
615       size_t block_idx = reader->case_idx / CASES_PER_BLOCK;
616       size_t case_idx = reader->case_idx % CASES_PER_BLOCK;
617       struct ccase *read_case = &reader->cf->cases[block_idx][case_idx];
618
619       case_move (c, read_case);
620       reader->case_idx++;
621       return 1;
622     }
623 }
624
625 /* Destroys READER. */
626 void
627 casereader_destroy (struct casereader *reader)
628 {
629   assert (reader != NULL);
630
631   if (reader->next != NULL)
632     reader->next->prev = reader->prev;
633   if (reader->prev != NULL)
634     reader->prev->next = reader->next;
635   if (reader->cf->readers == reader)
636     reader->cf->readers = reader->next;
637
638   if (reader->cf->buffer == NULL)
639     reader->cf->buffer = reader->buffer;
640   else
641     free (reader->buffer);
642
643   if (reader->fd != -1) 
644     {
645       if (reader->cf->fd == -1)
646         reader->cf->fd = reader->fd;
647       else
648         safe_close (reader->fd);
649     }
650   
651   case_destroy (&reader->c);
652
653   free (reader);
654 }
655
656 /* Calls open(), passing FILENAME and FLAGS, repeating as necessary
657    to deal with interrupted calls. */
658 static int
659 safe_open (const char *filename, int flags) 
660 {
661   int fd;
662
663   do 
664     {
665       fd = open (filename, flags);
666     }
667   while (fd == -1 && errno == EINTR);
668
669   return fd;
670 }
671
672 /* Calls close(), passing FD, repeating as necessary to deal with
673    interrupted calls. */
674 static int safe_close (int fd) 
675 {
676   int retval;
677
678   do 
679     {
680       retval = close (fd);
681     }
682   while (retval == -1 && errno == EINTR);
683
684   return retval;
685 }
686
687 /* Calls read(), passing FD, BUFFER, and SIZE, repeating as
688    necessary to deal with interrupted calls. */
689 static int
690 full_read (int fd, void *buffer_, size_t size) 
691 {
692   char *buffer = buffer_;
693   size_t bytes_read = 0;
694   
695   while (bytes_read < size)
696     {
697       int retval = read (fd, buffer + bytes_read, size - bytes_read);
698       if (retval > 0) 
699         bytes_read += retval; 
700       else if (retval == 0) 
701         return bytes_read;
702       else if (errno != EINTR)
703         return -1;
704     }
705
706   return bytes_read;
707 }
708
709 /* Calls write(), passing FD, BUFFER, and SIZE, repeating as
710    necessary to deal with interrupted calls. */
711 static int
712 full_write (int fd, const void *buffer_, size_t size) 
713 {
714   const char *buffer = buffer_;
715   size_t bytes_written = 0;
716   
717   while (bytes_written < size)
718     {
719       int retval = write (fd, buffer + bytes_written, size - bytes_written);
720       if (retval >= 0) 
721         bytes_written += retval; 
722       else if (errno != EINTR)
723         return -1;
724     }
725
726   return bytes_written;
727 }
728
729
730 /* Registers our exit handler with atexit() if it has not already
731    been registered. */
732 static void
733 register_atexit (void) 
734 {
735   static int registered = 0;
736   if (!registered) 
737     {
738       registered = 1;
739       atexit (exit_handler);
740     }
741 }
742
743
744
745 /* atexit() handler that closes and deletes our temporary
746    files. */
747 static void
748 exit_handler (void) 
749 {
750   while (casefiles != NULL)
751     casefile_destroy (casefiles);
752 }
753 \f
754 #include <gsl/gsl_rng.h>
755 #include <stdarg.h>
756 #include "command.h"
757 #include "lexer.h"
758
759 static void test_casefile (int pattern, size_t value_cnt, size_t case_cnt);
760 static void get_random_case (struct ccase *, size_t value_cnt,
761                              size_t case_idx);
762 static void write_random_case (struct casefile *cf, size_t case_idx);
763 static void read_and_verify_random_case (struct casefile *cf,
764                                          struct casereader *reader,
765                                          size_t case_idx);
766 static void fail_test (const char *message, ...);
767
768 int
769 cmd_debug_casefile (void) 
770 {
771   static const size_t sizes[] =
772     {
773       1, 2, 3, 4, 5, 6, 7, 14, 15, 16, 17, 31, 55, 73,
774       100, 137, 257, 521, 1031, 2053
775     };
776   int size_max;
777   int case_max;
778   int pattern;
779
780   size_max = sizeof sizes / sizeof *sizes;
781   if (lex_match_id ("SMALL")) 
782     {
783       size_max -= 4;
784       case_max = 511; 
785     }
786   else
787     case_max = 4095;
788   if (token != '.')
789     return lex_end_of_command ();
790     
791   for (pattern = 0; pattern < 6; pattern++) 
792     {
793       const size_t *size;
794
795       for (size = sizes; size < sizes + size_max; size++) 
796         {
797           size_t case_cnt;
798
799           for (case_cnt = 0; case_cnt <= case_max;
800                case_cnt = (case_cnt * 2) + 1)
801             test_casefile (pattern, *size, case_cnt);
802         }
803     }
804   printf ("Casefile tests succeeded.\n");
805   return CMD_SUCCESS;
806 }
807
808 static void
809 test_casefile (int pattern, size_t value_cnt, size_t case_cnt) 
810 {
811   struct casefile *cf;
812   struct casereader *r1, *r2;
813   struct ccase c;
814   gsl_rng *rng;
815   size_t i, j;
816
817   rng = gsl_rng_alloc (gsl_rng_mt19937);
818   cf = casefile_create (value_cnt);
819   if (pattern == 5)
820     casefile_to_disk (cf);
821   for (i = 0; i < case_cnt; i++)
822     write_random_case (cf, i);
823   if (pattern == 5)
824     casefile_sleep (cf);
825   r1 = casefile_get_reader (cf);
826   r2 = casefile_get_reader (cf);
827   switch (pattern) 
828     {
829     case 0:
830     case 5:
831       for (i = 0; i < case_cnt; i++) 
832         {
833           read_and_verify_random_case (cf, r1, i);
834           read_and_verify_random_case (cf, r2, i);
835         } 
836       break;
837     case 1:
838       for (i = 0; i < case_cnt; i++)
839         read_and_verify_random_case (cf, r1, i);
840       for (i = 0; i < case_cnt; i++) 
841         read_and_verify_random_case (cf, r2, i);
842       break;
843     case 2:
844     case 3:
845     case 4:
846       for (i = j = 0; i < case_cnt; i++) 
847         {
848           read_and_verify_random_case (cf, r1, i);
849           if (gsl_rng_get (rng) % pattern == 0) 
850             read_and_verify_random_case (cf, r2, j++); 
851           if (i == case_cnt / 2)
852             casefile_to_disk (cf);
853         }
854       for (; j < case_cnt; j++) 
855         read_and_verify_random_case (cf, r2, j);
856       break;
857     }
858   if (casereader_read (r1, &c))
859     fail_test ("Casereader 1 not at end of file.");
860   if (casereader_read (r2, &c))
861     fail_test ("Casereader 2 not at end of file.");
862   if (pattern != 1)
863     casereader_destroy (r1);
864   if (pattern != 2)
865     casereader_destroy (r2);
866   if (pattern > 2) 
867     {
868       r1 = casefile_get_destructive_reader (cf);
869       for (i = 0; i < case_cnt; i++) 
870         {
871           struct ccase read_case, expected_case;
872           
873           get_random_case (&expected_case, value_cnt, i);
874           if (!casereader_read_xfer (r1, &read_case)) 
875             fail_test ("Premature end of casefile.");
876           for (j = 0; j < value_cnt; j++) 
877             {
878               double a = case_num (&read_case, j);
879               double b = case_num (&expected_case, j);
880               if (a != b)
881                 fail_test ("Case %lu fails comparison.", (unsigned long) i); 
882             }
883           case_destroy (&expected_case);
884           case_destroy (&read_case);
885         }
886       casereader_destroy (r1);
887     }
888   casefile_destroy (cf);
889   gsl_rng_free (rng);
890 }
891
892 static void
893 get_random_case (struct ccase *c, size_t value_cnt, size_t case_idx) 
894 {
895   int i;
896   case_create (c, value_cnt);
897   for (i = 0; i < value_cnt; i++)
898     case_data_rw (c, i)->f = case_idx % 257 + i;
899 }
900
901 static void
902 write_random_case (struct casefile *cf, size_t case_idx) 
903 {
904   struct ccase c;
905   get_random_case (&c, casefile_get_value_cnt (cf), case_idx);
906   casefile_append_xfer (cf, &c);
907 }
908
909 static void
910 read_and_verify_random_case (struct casefile *cf,
911                              struct casereader *reader, size_t case_idx) 
912 {
913   struct ccase read_case, expected_case;
914   size_t value_cnt;
915   size_t i;
916   
917   value_cnt = casefile_get_value_cnt (cf);
918   get_random_case (&expected_case, value_cnt, case_idx);
919   if (!casereader_read (reader, &read_case)) 
920     fail_test ("Premature end of casefile.");
921   for (i = 0; i < value_cnt; i++) 
922     {
923       double a = case_num (&read_case, i);
924       double b = case_num (&expected_case, i);
925       if (a != b)
926         fail_test ("Case %lu fails comparison.", (unsigned long) case_idx); 
927     }
928   case_destroy (&read_case);
929   case_destroy (&expected_case);
930 }
931
932 static void
933 fail_test (const char *message, ...) 
934 {
935   va_list args;
936
937   va_start (args, message);
938   vprintf (message, args);
939   putchar ('\n');
940   va_end (args);
941   
942   exit (1);
943 }