* automake.mk: Add new file.
[pspp-builds.git] / src / language / data-io / data-reader.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-2004, 2006 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <language/data-io/data-reader.h>
20
21 #include <ctype.h>
22 #include <errno.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include <data/casereader.h>
28 #include <data/file-handle-def.h>
29 #include <data/file-name.h>
30 #include <data/procedure.h>
31 #include <language/command.h>
32 #include <language/data-io/file-handle.h>
33 #include <language/lexer/lexer.h>
34 #include <language/prompt.h>
35 #include <libpspp/assertion.h>
36 #include <libpspp/integer-format.h>
37 #include <libpspp/message.h>
38 #include <libpspp/str.h>
39
40 #include "minmax.h"
41 #include "xalloc.h"
42
43 #include "gettext.h"
44 #define _(msgid) gettext (msgid)
45 #define N_(msgid) (msgid)
46
47 /* Flags for DFM readers. */
48 enum dfm_reader_flags
49   {
50     DFM_ADVANCE = 002,          /* Read next line on dfm_get_record() call? */
51     DFM_SAW_BEGIN_DATA = 004,   /* For inline_file only, whether we've
52                                    already read a BEGIN DATA line. */
53     DFM_TABS_EXPANDED = 010,    /* Tabs have been expanded. */
54   };
55
56 /* Data file reader. */
57 struct dfm_reader
58   {
59     struct file_handle *fh;     /* File handle. */
60     struct fh_lock *lock;       /* Mutual exclusion lock for file. */
61     struct msg_locator where;   /* Current location in data file. */
62     struct string line;         /* Current line. */
63     struct string scratch;      /* Extra line buffer. */
64     enum dfm_reader_flags flags; /* Zero or more of DFM_*. */
65     FILE *file;                 /* Associated file. */
66     size_t pos;                 /* Offset in line of current character. */
67     unsigned eof_cnt;           /* # of attempts to advance past EOF. */
68     struct lexer *lexer;        /* The lexer reading the file */
69
70     /* For FH_MODE_360_VARIABLE and FH_MODE_360_SPANNED files only. */
71     size_t block_left;          /* Bytes left in current block. */
72   };
73
74 /* Closes reader R opened by dfm_open_reader(). */
75 void
76 dfm_close_reader (struct dfm_reader *r)
77 {
78   if (r == NULL)
79     return;
80
81   if (fh_unlock (r->lock))
82     {
83       /* File is still locked by another client. */
84       return;
85     }
86
87   /* This was the last client, so close the underlying file. */
88   if (fh_get_referent (r->fh) != FH_REF_INLINE)
89     fn_close (fh_get_file_name (r->fh), r->file);
90   else
91     {
92       /* Skip any remaining data on the inline file. */
93       if (r->flags & DFM_SAW_BEGIN_DATA)
94         {
95           dfm_reread_record (r, 0);
96           while (!dfm_eof (r))
97             dfm_forward_record (r);
98         }
99     }
100
101   fh_unref (r->fh);
102   ds_destroy (&r->line);
103   ds_destroy (&r->scratch);
104   free (r);
105 }
106
107 /* Opens the file designated by file handle FH for reading as a
108    data file.  Providing fh_inline_file() for FH designates the
109    "inline file", that is, data included inline in the command
110    file between BEGIN FILE and END FILE.  Returns a reader if
111    successful, or a null pointer otherwise. */
112 struct dfm_reader *
113 dfm_open_reader (struct file_handle *fh, struct lexer *lexer)
114 {
115   struct dfm_reader *r;
116   struct fh_lock *lock;
117
118   /* TRANSLATORS: this fragment will be interpolated into
119      messages in fh_lock() that identify types of files. */
120   lock = fh_lock (fh, FH_REF_FILE | FH_REF_INLINE, N_("data file"),
121                   FH_ACC_READ, false);
122   if (lock == NULL)
123     return NULL;
124
125   r = fh_lock_get_aux (lock);
126   if (r != NULL)
127     return r;
128
129   r = xmalloc (sizeof *r);
130   r->fh = fh_ref (fh);
131   r->lock = lock;
132   r->lexer = lexer;
133   ds_init_empty (&r->line);
134   ds_init_empty (&r->scratch);
135   r->flags = DFM_ADVANCE;
136   r->eof_cnt = 0;
137   r->block_left = 0;
138   if (fh_get_referent (fh) != FH_REF_INLINE)
139     {
140       r->where.file_name = fh_get_file_name (fh);
141       r->where.line_number = 0;
142       r->file = fn_open (fh_get_file_name (fh),
143                          fh_get_mode (fh) == FH_MODE_TEXT ? "r" : "rb");
144       if (r->file == NULL)
145         {
146           msg (ME, _("Could not open \"%s\" for reading as a data file: %s."),
147                fh_get_file_name (r->fh), strerror (errno));
148           fh_unlock (r->lock);
149           fh_unref (fh);
150           free (r);
151           return NULL;
152         }
153     }
154   fh_lock_set_aux (lock, r);
155
156   return r;
157 }
158
159 /* Returns true if an I/O error occurred on READER, false otherwise. */
160 bool
161 dfm_reader_error (const struct dfm_reader *r)
162 {
163   return fh_get_referent (r->fh) == FH_REF_FILE && ferror (r->file);
164 }
165
166 /* Reads a record from the inline file into R.
167    Returns true if successful, false on failure. */
168 static bool
169 read_inline_record (struct dfm_reader *r)
170 {
171   if ((r->flags & DFM_SAW_BEGIN_DATA) == 0)
172     {
173       r->flags |= DFM_SAW_BEGIN_DATA;
174
175       while (lex_token (r->lexer) == '.')
176         lex_get (r->lexer);
177       if (!lex_force_match_id (r->lexer, "BEGIN") || !lex_force_match_id (r->lexer, "DATA"))
178         return false;
179       prompt_set_style (PROMPT_DATA);
180     }
181
182   if (!lex_get_line_raw (r->lexer))
183     {
184       msg (SE, _("Unexpected end-of-file while reading data in BEGIN "
185                  "DATA.  This probably indicates "
186                  "a missing or misformatted END DATA command.  "
187                  "END DATA must appear by itself on a single line "
188                  "with exactly one space between words."));
189       return false;
190     }
191
192   if (ds_length (lex_entire_line_ds (r->lexer) ) >= 8
193       && !strncasecmp (lex_entire_line (r->lexer), "end data", 8))
194     {
195       lex_discard_line (r->lexer);
196       return false;
197     }
198
199   ds_assign_string (&r->line, lex_entire_line_ds (r->lexer) );
200
201   return true;
202 }
203
204 /* Report a read error or unexpected end-of-file condition on R. */
205 static void
206 read_error (struct dfm_reader *r)
207 {
208   if (ferror (r->file))
209     msg (ME, _("Error reading file %s: %s."),
210          fh_get_name (r->fh), strerror (errno));
211   else if (feof (r->file))
212     msg (ME, _("Unexpected end of file reading %s."), fh_get_name (r->fh));
213   else
214     NOT_REACHED ();
215 }
216
217 /* Report a partial read at end of file reading R. */
218 static void
219 partial_record (struct dfm_reader *r)
220 {
221   msg (ME, _("Unexpected end of file in partial record reading %s."),
222        fh_get_name (r->fh));
223 }
224
225 /* Tries to read SIZE bytes from R into BUFFER.  Returns 1 if
226    successful, 0 if end of file was reached before any bytes
227    could be read, and -1 if some bytes were read but fewer than
228    SIZE due to end of file or an error mid-read.  In the latter
229    case, reports an error. */
230 static int
231 try_to_read_fully (struct dfm_reader *r, void *buffer, size_t size)
232 {
233   size_t bytes_read = fread (buffer, 1, size, r->file);
234   if (bytes_read == size)
235     return 1;
236   else if (bytes_read == 0)
237     return 0;
238   else
239     {
240       partial_record (r);
241       return -1;
242     }
243 }
244
245 /* Type of a descriptor word. */
246 enum descriptor_type
247   {
248     BLOCK,
249     RECORD
250   };
251
252 /* Reads a block descriptor word or record descriptor word
253    (according to TYPE) from R.  Returns 1 if successful, 0 if
254    end of file was reached before any bytes could be read, -1 if
255    an error occurred.  Reports an error in the latter case.
256
257    If successful, stores the number of remaining bytes in the
258    block or record (that is, the block or record length, minus
259    the 4 bytes in the BDW or RDW itself) into *REMAINING_SIZE.
260    If SEGMENT is nonnull, also stores the segment control
261    character (SCC) into *SEGMENT. */
262 static int
263 read_descriptor_word (struct dfm_reader *r, enum descriptor_type type,
264                       size_t *remaining_size, int *segment)
265 {
266   uint8_t raw_descriptor[4];
267   int status;
268
269   status = try_to_read_fully (r, raw_descriptor, sizeof raw_descriptor);
270   if (status <= 0)
271     return status;
272
273   *remaining_size = (raw_descriptor[0] << 8) | raw_descriptor[1];
274   if (segment != NULL)
275     *segment = raw_descriptor[2];
276
277   if (*remaining_size < 4)
278     {
279       msg (ME,
280            (type == BLOCK
281             ? _("Corrupt block descriptor word at offset 0x%lx in %s.")
282             : _("Corrupt record descriptor word at offset 0x%lx in %s.")),
283            (long) ftello (r->file) - 4, fh_get_name (r->fh));
284       return -1;
285     }
286
287   *remaining_size -= 4;
288   return 1;
289 }
290
291 /* Reports that reader R has read a corrupt record size. */
292 static void
293 corrupt_size (struct dfm_reader *r)
294 {
295   msg (ME, _("Corrupt record size at offset 0x%lx in %s."),
296        (long) ftello (r->file) - 4, fh_get_name (r->fh));
297 }
298
299 /* Reads a 32-byte little-endian signed number from R and stores
300    its value into *SIZE_OUT.  Returns 1 if successful, 0 if end
301    of file was reached before any bytes could be read, -1 if an
302    error occurred.  Reports an error in the latter case.  Numbers
303    less than 0 are considered errors. */
304 static int
305 read_size (struct dfm_reader *r, size_t *size_out)
306 {
307   int32_t size;
308   int status;
309
310   status = try_to_read_fully (r, &size, sizeof size);
311   if (status <= 0)
312     return status;
313
314   integer_convert (INTEGER_LSB_FIRST, &size, INTEGER_NATIVE, &size,
315                    sizeof size);
316   if (size < 0)
317     {
318       corrupt_size (r);
319       return -1;
320     }
321
322   *size_out = size;
323   return 1;
324 }
325
326 /* Reads a record from a disk file into R.
327    Returns true if successful, false on error or at end of file. */
328 static bool
329 read_file_record (struct dfm_reader *r)
330 {
331   assert (r->fh != fh_inline_file ());
332
333   ds_clear (&r->line);
334   switch (fh_get_mode (r->fh))
335     {
336     case FH_MODE_TEXT:
337       if (ds_read_line (&r->line, r->file))
338         {
339           ds_chomp (&r->line, '\n');
340           return true;
341         }
342       else
343         {
344           if (ferror (r->file))
345             read_error (r);
346           return false;
347         }
348       return true;
349
350     case FH_MODE_FIXED:
351       if (ds_read_stream (&r->line, 1, fh_get_record_width (r->fh), r->file))
352         return true;
353       else
354         {
355           if (ferror (r->file))
356             read_error (r);
357           else if (!ds_is_empty (&r->line))
358             partial_record (r);
359           return false;
360         }
361       return true;
362
363     case FH_MODE_VARIABLE:
364       {
365         size_t leading_size;
366         size_t trailing_size;
367         int status;
368
369         /* Read leading record size. */
370         status = read_size (r, &leading_size);
371         if (status <= 0)
372           return false;
373
374         /* Read record data. */
375         if (!ds_read_stream (&r->line, leading_size, 1, r->file))
376           {
377             if (ferror (r->file))
378               read_error (r);
379             else
380               partial_record (r);
381             return false;
382           }
383
384         /* Read trailing record size and check that it's the same
385            as the leading record size. */
386         status = read_size (r, &trailing_size);
387         if (status <= 0)
388           {
389             if (status == 0)
390               partial_record (r);
391             return false;
392           }
393         if (leading_size != trailing_size)
394           {
395             corrupt_size (r);
396             return false;
397           }
398
399         return true;
400       }
401
402     case FH_MODE_360_VARIABLE:
403     case FH_MODE_360_SPANNED:
404       for (;;)
405         {
406           size_t record_size;
407           int segment;
408           int status;
409
410           /* If we've exhausted our current block, start another
411              one by reading the new block descriptor word. */
412           if (r->block_left == 0)
413             {
414               status = read_descriptor_word (r, BLOCK, &r->block_left, NULL);
415               if (status < 0)
416                 return false;
417               else if (status == 0)
418                 return !ds_is_empty (&r->line);
419             }
420
421           /* Read record descriptor. */
422           if (r->block_left < 4)
423             {
424               partial_record (r);
425               return false;
426             }
427           r->block_left -= 4;
428           status = read_descriptor_word (r, RECORD, &record_size, &segment);
429           if (status <= 0)
430             {
431               if (status == 0)
432                 partial_record (r);
433               return false;
434             }
435           if (record_size > r->block_left)
436             {
437               msg (ME, _("Record exceeds remaining block length."));
438               return false;
439             }
440
441           /* Read record data. */
442           if (!ds_read_stream (&r->line, record_size, 1, r->file))
443             {
444               if (ferror (r->file))
445                 read_error (r);
446               else
447                 partial_record (r);
448               return false;
449             }
450           r->block_left -= record_size;
451
452           /* In variable mode, read only a single record.
453              In spanned mode, a segment value of 0 should
454              designate a whole record without spanning, 1 the
455              first segment in a record, 2 the last segment in a
456              record, and 3 an intermediate segment in a record.
457              For compatibility, though, we actually pay attention
458              only to whether the segment value is even or odd. */
459           if (fh_get_mode (r->fh) == FH_MODE_360_VARIABLE
460               || (segment & 1) == 0)
461             return true;
462         }
463     }
464
465   NOT_REACHED ();
466 }
467
468 /* Reads a record from R, setting the current position to the
469    start of the line.  If an error occurs or end-of-file is
470    encountered, the current line is set to null. */
471 static bool
472 read_record (struct dfm_reader *r)
473 {
474   if (fh_get_referent (r->fh) == FH_REF_FILE)
475     {
476       bool ok = read_file_record (r);
477       if (ok)
478         r->where.line_number++;
479       return ok;
480     }
481   else
482     return read_inline_record (r);
483 }
484
485 /* Returns the number of attempts, thus far, to advance past
486    end-of-file in reader R.  Reads forward in HANDLE's file, if
487    necessary, to find out.
488
489    Normally, the user stops attempting to read from the file the
490    first time EOF is reached (a return value of 1).  If the user
491    tries to read past EOF again (a return value of 2 or more),
492    an error message is issued, and the caller should more
493    forcibly abort to avoid an infinite loop. */
494 unsigned
495 dfm_eof (struct dfm_reader *r)
496 {
497   if (r->flags & DFM_ADVANCE)
498     {
499       r->flags &= ~DFM_ADVANCE;
500
501       if (r->eof_cnt == 0 && read_record (r) )
502         {
503           r->pos = 0;
504           return 0;
505         }
506
507       r->eof_cnt++;
508       if (r->eof_cnt == 2)
509         {
510           if (r->fh != fh_inline_file ())
511             msg (ME, _("Attempt to read beyond end-of-file on file %s."),
512                  fh_get_name (r->fh));
513           else
514             msg (ME, _("Attempt to read beyond END DATA."));
515         }
516     }
517
518   return r->eof_cnt;
519 }
520
521 /* Returns the current record in the file corresponding to
522    HANDLE.  Aborts if reading from the file is necessary or at
523    end of file, so call dfm_eof() first. */
524 struct substring
525 dfm_get_record (struct dfm_reader *r)
526 {
527   assert ((r->flags & DFM_ADVANCE) == 0);
528   assert (r->eof_cnt == 0);
529
530   return ds_substr (&r->line, r->pos, SIZE_MAX);
531 }
532
533 /* Expands tabs in the current line into the equivalent number of
534    spaces, if appropriate for this kind of file.  Aborts if
535    reading from the file is necessary or at end of file, so call
536    dfm_eof() first.*/
537 void
538 dfm_expand_tabs (struct dfm_reader *r)
539 {
540   size_t ofs, new_pos, tab_width;
541
542   assert ((r->flags & DFM_ADVANCE) == 0);
543   assert (r->eof_cnt == 0);
544
545   if (r->flags & DFM_TABS_EXPANDED)
546     return;
547   r->flags |= DFM_TABS_EXPANDED;
548
549   if (r->fh != fh_inline_file ()
550       && (fh_get_mode (r->fh) != FH_MODE_TEXT
551           || fh_get_tab_width (r->fh) == 0
552           || ds_find_char (&r->line, '\t') == SIZE_MAX))
553     return;
554
555   /* Expand tabs from r->line into r->scratch, and figure out
556      new value for r->pos. */
557   tab_width = fh_get_tab_width (r->fh);
558   ds_clear (&r->scratch);
559   new_pos = SIZE_MAX;
560   for (ofs = 0; ofs < ds_length (&r->line); ofs++)
561     {
562       unsigned char c;
563
564       if (ofs == r->pos)
565         new_pos = ds_length (&r->scratch);
566
567       c = ds_data (&r->line)[ofs];
568       if (c != '\t')
569         ds_put_char (&r->scratch, c);
570       else
571         {
572           do
573             ds_put_char (&r->scratch, ' ');
574           while (ds_length (&r->scratch) % tab_width != 0);
575         }
576     }
577   if (new_pos == SIZE_MAX)
578     {
579       /* Maintain the same relationship between position and line
580          length that we had before.  DATA LIST uses a
581          beyond-the-end position to deal with an empty field at
582          the end of the line. */
583       assert (r->pos >= ds_length (&r->line));
584       new_pos = (r->pos - ds_length (&r->line)) + ds_length (&r->scratch);
585     }
586
587   /* Swap r->line and r->scratch and set new r->pos. */
588   ds_swap (&r->line, &r->scratch);
589   r->pos = new_pos;
590 }
591
592 /* Returns the legacy character encoding of data read from READER. */
593 enum legacy_encoding
594 dfm_reader_get_legacy_encoding (const struct dfm_reader *reader)
595 {
596   return fh_get_legacy_encoding (reader->fh);
597 }
598
599 /* Causes dfm_get_record() or dfm_get_whole_record() to read in
600    the next record the next time it is executed on file
601    HANDLE. */
602 void
603 dfm_forward_record (struct dfm_reader *r)
604 {
605   r->flags |= DFM_ADVANCE;
606 }
607
608 /* Cancels the effect of any previous dfm_fwd_record() executed
609    on file HANDLE.  Sets the current line to begin in the 1-based
610    column COLUMN.  */
611 void
612 dfm_reread_record (struct dfm_reader *r, size_t column)
613 {
614   r->flags &= ~DFM_ADVANCE;
615   r->pos = MAX (column, 1) - 1;
616 }
617
618 /* Sets the current line to begin COLUMNS characters following
619    the current start. */
620 void
621 dfm_forward_columns (struct dfm_reader *r, size_t columns)
622 {
623   dfm_reread_record (r, (r->pos + 1) + columns);
624 }
625
626 /* Returns the 1-based column to which the line pointer in HANDLE
627    is set.  Unless dfm_reread_record() or dfm_forward_columns()
628    have been called, this is 1. */
629 size_t
630 dfm_column_start (const struct dfm_reader *r)
631 {
632   return r->pos + 1;
633 }
634
635 /* Returns the number of columns we are currently beyond the end
636    of the line.  At or before end-of-line, this is 0; one column
637    after end-of-line, this is 1; and so on. */
638 size_t
639 dfm_columns_past_end (const struct dfm_reader *r)
640 {
641   return r->pos < ds_length (&r->line) ? 0 : ds_length (&r->line) - r->pos;
642 }
643
644 /* Returns the 1-based column within the current line that P
645    designates. */
646 size_t
647 dfm_get_column (const struct dfm_reader *r, const char *p)
648 {
649   return ds_pointer_to_position (&r->line, p) + 1;
650 }
651
652 /* Pushes the file name and line number on the fn/ln stack. */
653 void
654 dfm_push (struct dfm_reader *r)
655 {
656   if (r->fh != fh_inline_file ())
657     msg_push_msg_locator (&r->where);
658 }
659
660 /* Pops the file name and line number from the fn/ln stack. */
661 void
662 dfm_pop (struct dfm_reader *r)
663 {
664   if (r->fh != fh_inline_file ())
665     msg_pop_msg_locator (&r->where);
666 }
667 \f
668 /* BEGIN DATA...END DATA procedure. */
669
670 /* Perform BEGIN DATA...END DATA as a procedure in itself. */
671 int
672 cmd_begin_data (struct lexer *lexer, struct dataset *ds)
673 {
674   struct dfm_reader *r;
675   bool ok;
676
677   if (!fh_is_locked (fh_inline_file (), FH_ACC_READ))
678     {
679       msg (SE, _("This command is not valid here since the current "
680                  "input program does not access the inline file."));
681       return CMD_CASCADING_FAILURE;
682     }
683
684   /* Open inline file. */
685   r = dfm_open_reader (fh_inline_file (), lexer);
686   r->flags |= DFM_SAW_BEGIN_DATA;
687
688   /* Input procedure reads from inline file. */
689   prompt_set_style (PROMPT_DATA);
690   casereader_destroy (proc_open (ds));
691   ok = proc_commit (ds);
692   dfm_close_reader (r);
693
694   return ok ? CMD_SUCCESS : CMD_CASCADING_FAILURE;
695 }