sys-file-reader: Break reading a system file into two stages.
[pspp] / src / language / dictionary / sys-file-info.c
index 6f73d8316595510499de223931ad45698331f9ab..6b74f75a6622d0860b8679496063bbfd02df0806 100644 (file)
@@ -1,5 +1,5 @@
 /* PSPP - a program for statistical analysis.
-   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+   Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2013, 2014 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
@@ -17,6 +17,7 @@
 #include <config.h>
 
 #include <ctype.h>
+#include <float.h>
 #include <stdlib.h>
 
 #include "data/attributes.h"
@@ -67,26 +68,60 @@ static int describe_variable (const struct variable *v, struct tab_table *t,
 int
 cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
 {
+  struct sfm_reader *sfm_reader;
   struct file_handle *h;
   struct dictionary *d;
   struct tab_table *t;
   struct casereader *reader;
   struct sfm_read_info info;
+  char *encoding;
   int r, i;
 
-  lex_match_id (lexer, "FILE");
-  lex_match (lexer, T_EQUALS);
+  h = NULL;
+  encoding = NULL;
+  for (;;)
+    {
+      lex_match (lexer, T_SLASH);
 
-  h = fh_parse (lexer, FH_REF_FILE, NULL);
-  if (!h)
-    return CMD_FAILURE;
+      if (lex_match_id (lexer, "FILE") || lex_is_string (lexer))
+       {
+         lex_match (lexer, T_EQUALS);
 
-  reader = sfm_open_reader (h, NULL, &d, &info);
-  if (!reader)
+          fh_unref (h);
+         h = fh_parse (lexer, FH_REF_FILE, NULL);
+         if (h == NULL)
+            goto error;
+       }
+      else if (lex_match_id (lexer, "ENCODING"))
+        {
+         lex_match (lexer, T_EQUALS);
+
+          if (!lex_force_string (lexer))
+            goto error;
+
+          free (encoding);
+          encoding = ss_xstrdup (lex_tokss (lexer));
+
+          lex_get (lexer);
+        }
+      else
+        break;
+    }
+
+  if (h == NULL)
     {
-      fh_unref (h);
-      return CMD_FAILURE;
+      lex_sbc_missing ("FILE");
+      goto error;
     }
+
+  sfm_reader = sfm_open (h);
+  if (sfm_reader == NULL)
+    goto error;
+
+  reader = sfm_decode (sfm_reader, encoding, &d, &info);
+  if (!reader)
+    goto error;
+
   casereader_destroy (reader);
 
   t = tab_create (2, 11 + (info.product_ext != NULL));
@@ -183,6 +218,11 @@ cmd_sysfile_info (struct lexer *lexer, struct dataset *ds UNUSED)
   fh_unref (h);
   sfm_read_info_destroy (&info);
   return CMD_SUCCESS;
+
+error:
+  fh_unref (h);
+  free (encoding);
+  return CMD_FAILURE;
 }
 \f
 /* DISPLAY utility. */
@@ -560,11 +600,13 @@ describe_variable (const struct variable *v, struct tab_table *t, int r,
           double x, y;
           mv_get_range (mv, &x, &y);
           if (x == LOWEST)
-            cp += sprintf (cp, "LOWEST THRU %g", y);
+            cp += sprintf (cp, "LOWEST THRU %.*g", DBL_DIG + 1, y);
           else if (y == HIGHEST)
-            cp += sprintf (cp, "%g THRU HIGHEST", x);
+            cp += sprintf (cp, "%.*g THRU HIGHEST", DBL_DIG + 1, x);
           else
-            cp += sprintf (cp, "%g THRU %g", x, y);
+            cp += sprintf (cp, "%.*g THRU %.*g",
+                           DBL_DIG + 1, x,
+                           DBL_DIG + 1, y);
           cnt++;
         }
       for (i = 0; i < mv_n_values (mv); i++)
@@ -573,7 +615,7 @@ describe_variable (const struct variable *v, struct tab_table *t, int r,
           if (cnt++ > 0)
             cp += sprintf (cp, "; ");
           if (var_is_numeric (v))
-            cp += sprintf (cp, "%g", value->f);
+            cp += sprintf (cp, "%.*g", DBL_DIG + 1, value->f);
           else
             {
               int width = var_get_width (v);