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