por-file-reader: Tolerate short lines when detecting portable files.
authorBen Pfaff <blp@gnu.org>
Thu, 18 Jun 2009 04:11:10 +0000 (21:11 -0700)
committerBen Pfaff <blp@gnu.org>
Thu, 18 Jun 2009 04:11:10 +0000 (21:11 -0700)
When the portable file reader reads a file, it assumes that a line
shorter than 80 bytes should actually be padded out on the right with
spaces, because this is a fairly common problem in practice, perhaps
due to text editors or other software that drops spaces at the end of
a line.

However, pfm_detect, the function that is supposed to detect whether
a given file is an SPSS portable file, did not apply this heuristic to
the data that it read at the beginning of the file, and thus files in
which the first few lines were truncated this way were not detected
properly as portable files.

This commit fixes the problem by making pfm_detect a little bit
smarter.  It would probably be better to actually unify the
file-reading logic, instead of implementing it in two separate places,
but this appears to work adequately too.

Thanks to Tony Reardon <tony@sir.com.au> for reporting the problem
and supplying a file that demonstrated it.

src/data/por-file-reader.c

index 52c0cc8edab5dca9a59b142d83cf9c3466489a3e..823361b09593aacc7eb33dae402f1fb31e798bdf 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -867,17 +867,30 @@ pfm_detect (FILE *file)
 {
   unsigned char header[464];
   char trans[256];
-  int cooked_cnt, raw_cnt;
+  int cooked_cnt, raw_cnt, line_len;
   int i;
 
   cooked_cnt = raw_cnt = 0;
+  line_len = 0;
   while (cooked_cnt < sizeof header)
     {
       int c = getc (file);
       if (c == EOF || raw_cnt++ > 512)
         return false;
-      else if (c != '\n' && c != '\r')
-        header[cooked_cnt++] = c;
+      else if (c == '\n')
+        {
+          while (line_len < 80 && cooked_cnt < sizeof header)
+            {
+              header[cooked_cnt++] = ' ';
+              line_len++;
+            }
+          line_len = 0;
+        }
+      else if (c != '\r')
+        {
+          header[cooked_cnt++] = c;
+          line_len++;
+        }
     }
 
   memset (trans, 0, 256);