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