Fully implement arbitrary delimiters on DATA LIST, extending the half
authorBen Pfaff <blp@gnu.org>
Mon, 31 May 2004 05:50:10 +0000 (05:50 +0000)
committerBen Pfaff <blp@gnu.org>
Mon, 31 May 2004 05:50:10 +0000 (05:50 +0000)
implementation that was already there.

Update our string ADTs, struct string and struct len_string.  Get rid
of pool support, which was largely unused.  Rename lots of functions
to have more obvious or consistent names.

Fix a few miscellaneous bugs.

49 files changed:
ChangeLog
TODO
configure.ac
doc/ChangeLog
doc/pspp.texi
src/ChangeLog
src/aggregate.c
src/ascii.c
src/casefile.c
src/command.c
src/count.c
src/data-in.c
src/data-list.c
src/devind.c
src/dfm.c
src/dfm.h
src/error.c
src/expr-prs.c
src/file-handle.h
src/file-handle.q
src/file-type.c
src/filename.c
src/format.c
src/getline.c
src/glob.c
src/html.c
src/include.c
src/inpt-pgm.c
src/lexer.c
src/matrix-data.c
src/mis-val.c
src/output.c
src/postscript.c
src/print.c
src/q2c.c
src/recode.c
src/repeat.c
src/set.q
src/str.c
src/str.h
src/t-test.q
src/tab.c
src/title.c
src/val-labs.c
src/var-labs.c
tests/ChangeLog
tests/Makefile.am
tests/command/data-list.sh [new file with mode: 0755]
tests/command/tabs.sh

index 429564f0b923a64b90f2801454fbf5a2ab4f0446..66714b68112f8c75752650e178a1822a5f451d9b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sun May 30 18:19:03 2004  Ben Pfaff  <blp@gnu.org>
+
+       * config.ac: Check for valgrind/valgrind.h.
+
 Mon Mar 29 15:22:48 2004  Ben Pfaff  <blp@gnu.org>
 
        * TODO: Updated.
 Mon Mar 29 15:22:48 2004  Ben Pfaff  <blp@gnu.org>
 
        * TODO: Updated.
diff --git a/TODO b/TODO
index 5a77a93081c5cea4cdfa01519bc237811d2f0f4f..fb3d8c7e98978ec6c19e130c3fe1e8a3b743e09b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,8 +1,10 @@
-Time-stamp: <2004-04-24 22:23:04 blp>
+Time-stamp: <2004-05-30 18:09:06 blp>
 
 What Ben's working on now.
 --------------------------
 
 
 What Ben's working on now.
 --------------------------
 
+Does SET work correctly?
+
 Update q2c input format description.
 
 Rewrite output subsystem, break into multiple processes.
 Update q2c input format description.
 
 Rewrite output subsystem, break into multiple processes.
index 69ac564b509133b0b7e13004cebe6dcd9bd76d54..4859d654476625f6da53ab8cd14f8eb63349d1ed 100644 (file)
@@ -58,7 +58,8 @@ fi
 
 dnl Checks for header files.
 AC_CHECK_HEADERS([limits.h memory.h sys/stat.h sys/time.h sys/types.h \
 
 dnl Checks for header files.
 AC_CHECK_HEADERS([limits.h memory.h sys/stat.h sys/time.h sys/types.h \
-                  fpu_control.h sys/mman.h sys/wait.h ieeefp.h fenv.h])
+                  fpu_control.h sys/mman.h sys/wait.h ieeefp.h fenv.h \
+                 valgrind/valgrind.h])
 AC_HEADER_STAT
 AC_HEADER_STDC
 AC_HEADER_TIME
 AC_HEADER_STAT
 AC_HEADER_STDC
 AC_HEADER_TIME
index de43ca95dbc0960621557158aaa940dfafe12824..ceaaacfab103a0b5f26a6a100e680c48ae37e771 100644 (file)
@@ -1,3 +1,8 @@
+Sun May 30 22:44:25 2004  Ben Pfaff  <blp@gnu.org>
+
+       * pspp.texi: Update FILE HANDLE, DATA LIST FREE, DATA LIST LIST
+       documentation to reflect latest changes.
+
 Mon Apr 19 22:46:37 2004  Ben Pfaff  <blp@gnu.org>
 
        * pspp.texi: Minor updates to data file and portable file
 Mon Apr 19 22:46:37 2004  Ben Pfaff  <blp@gnu.org>
 
        * pspp.texi: Minor updates to data file and portable file
index eb1d01488fb72dfe699834c9ed4b711ffc8b4be0..d15792b389f7ff987e0bf3b5d962017c6296a982 100644 (file)
@@ -5122,6 +5122,7 @@ This example shows keywords abbreviated to their first 3 letters.
 
 @display
 DATA LIST FREE
 
 @display
 DATA LIST FREE
+        [(@{TAB,'c'@}, @dots{})]
         [@{NOTABLE,TABLE@}]
         FILE='filename'
         END=end_var
         [@{NOTABLE,TABLE@}]
         FILE='filename'
         END=end_var
@@ -5132,16 +5133,23 @@ where each var_spec takes one of the forms
         var_list *
 @end display
 
         var_list *
 @end display
 
-In free format, the input data is structured as a series of comma- or
-whitespace-delimited fields (end of line is one form of whitespace; it
-is not treated specially).  Field contents may be surrounded by matched
-pairs of apostrophes (@samp{'}) or quotes (@samp{"}), or they may be
-unenclosed.  For any type of field leading white space (up to the
-apostrophe or quote, if any) is not included in the field.
-
-Multiple consecutive delimiters are equivalent to a single delimiter.
-To specify an empty field, write an empty set of single or double
-quotes; for instance, @samp{""}.
+In free format, the input data is, by default, structured as a series
+of fields separated by spaces, tabs, commas, or line breaks.  Each
+field's content may be unquoted, or it may be quoted with a pairs of
+apostrophes (@samp{'}) or double quotes (@samp{"}).  Unquoted white
+space separates fields but is not part of any field.  Any mix of
+spaces, tabs, and line breaks is equivalent to a single space for the
+purpose of separating fields, but consecutive commas will skip a
+field.
+
+Alternatively, delimiters can be specified explicitly, as a
+parenthesized, comma-separated list of single-character strings
+immediately following FREE.  The word TAB may also be used to specify
+a tab character as a delimiter.  When delimiters are specified
+explicitly, only the given characters, plus line breaks, separate
+fields.  Furthermore, leading spaces at the beginnings of fields are
+not trimmed, consecutive delimiters define empty fields, and no form
+of quoting is allowed.
 
 The NOTABLE and TABLE subcommands are as in @cmd{DATA LIST FIXED} above.
 NOTABLE is the default.
 
 The NOTABLE and TABLE subcommands are as in @cmd{DATA LIST FIXED} above.
 NOTABLE is the default.
@@ -5166,6 +5174,7 @@ on field width apply, but they are honored on output.
 
 @display
 DATA LIST LIST
 
 @display
 DATA LIST LIST
+        [(@{TAB,'c'@}, @dots{})]
         [@{NOTABLE,TABLE@}]
         FILE='filename'
         END=end_var
         [@{NOTABLE,TABLE@}]
         FILE='filename'
         END=end_var
@@ -5211,14 +5220,19 @@ the current input program.  @xref{INPUT PROGRAM}.
 @display
 FILE HANDLE handle_name
         /NAME='filename'
 @display
 FILE HANDLE handle_name
         /NAME='filename'
-        /RECFORM=@{VARIABLE,FIXED,SPANNED@}
+        /MODE=@{CHARACTER,IMAGE@}
         /LRECL=rec_len
         /LRECL=rec_len
-        /MODE=@{CHARACTER,IMAGE,BINARY,MULTIPUNCH,360@}
+        /TABWIDTH=tab_width
 @end display
 
 @end display
 
-Use @cmd{FILE HANDLE} to define the attributes of a file that does
-not use conventional variable-length records terminated by new-line
-characters.
+Use @cmd{FILE HANDLE} to associate a file handle name with a file and
+its attributes, so that later commands can refer to the file by its
+handle name.  Because names of text files can be specified directly on
+commands that access files, @cmd{FILE HANDLE} is only needed when a
+file is not an ordinary file containing lines of text.  However,
+@cmd{FILE HANDLE} may be used even for text files, and it may be
+easier to specify a file's name once and later refer to it by an
+abstract handle.
 
 Specify the file handle name as an identifier.  Any given identifier may
 only appear once in a PSPP run.  File handles may not be reassigned to a
 
 Specify the file handle name as an identifier.  Any given identifier may
 only appear once in a PSPP run.  File handles may not be reassigned to a
@@ -5228,18 +5242,19 @@ HANDLE} command name.
 The NAME subcommand specifies the name of the file associated with the
 handle.  It is the only required subcommand.
 
 The NAME subcommand specifies the name of the file associated with the
 handle.  It is the only required subcommand.
 
-The RECFORM subcommand specifies how the file is laid out.  VARIABLE
-specifies variable-length lines terminated with new-lines, and it is the
-default.  FIXED specifies fixed-length records.  SPANNED is not
-supported.
-
-LRECL specifies the length of fixed-length records.  It is required if
-@code{/RECFORM FIXED} is specified.  
+MODE specifies a file mode.  In CHARACTER mode, the default, the data
+file is opened in ANSI C text mode, so that local end of line
+conventions are followed, and each text line is read as one record.
+In CHARACTER mode, most input programs will expand tabs to spaces
+(@cmd{DATA LIST FREE} with explicitly specified delimiters is an
+exception).  By default, each tab is 4 characters wide, but an
+alternate width may be specified on TABWIDTH.  A tab width of 0
+suppresses tab expansion entirely.
 
 
-MODE specifies a file mode.  CHARACTER, the default, causes the data
-file to be opened in ANSI C text mode.  BINARY causes the data file to
-be opened in ANSI C binary mode.  The other possibilities are not
-supported.
+By contrast, in BINARY mode, the data file is opened in ANSI C binary
+mode and records are a fixed length.  In BINARY mode, LRECL specifies
+the record length in bytes, with a default of 1024.  Tab characters
+are never expanded to spaces in binary mode.
 
 @node INPUT PROGRAM, LIST, FILE HANDLE, Data Input and Output
 @section INPUT PROGRAM
 
 @node INPUT PROGRAM, LIST, FILE HANDLE, Data Input and Output
 @section INPUT PROGRAM
@@ -6624,7 +6639,7 @@ character codes.  On most modern computers, this is a form of ASCII.
 The aggregation functions listed above exclude all user-missing values
 from calculations.  To include user-missing values, insert a period
 (@samp{.}) between the function name and left parenthesis
 The aggregation functions listed above exclude all user-missing values
 from calculations.  To include user-missing values, insert a period
 (@samp{.}) between the function name and left parenthesis
-(e.g.~@samp{SUM.}).
+(e.g.@: @samp{SUM.}).
 
 Normally, only a single case (for SD and SD., two cases) need be
 non-missing in each group for the aggregate variable to be
 
 Normally, only a single case (for SD and SD., two cases) need be
 non-missing in each group for the aggregate variable to be
@@ -9418,7 +9433,7 @@ character set translation table, followed by an 8-byte tag string.
 The 200-byte segment is divided into five 40-byte sections, each of
 which represents the string @code{@var{charset} SPSS PORT FILE} in a
 different character set encoding, where @var{charset} is the name of
 The 200-byte segment is divided into five 40-byte sections, each of
 which represents the string @code{@var{charset} SPSS PORT FILE} in a
 different character set encoding, where @var{charset} is the name of
-the character set used in the file, e.g. @code{ASCII} or
+the character set used in the file, e.g.@: @code{ASCII} or
 @code{EBCDIC}.  Each string is padded on the right with spaces in its
 respective character set.
 
 @code{EBCDIC}.  Each string is padded on the right with spaces in its
 respective character set.
 
index 9691ad7c7ca006130ba3df167f6b2ccc24862393..13b90dcc3b38ee50bd1eb971972d622fdf8707d6 100644 (file)
@@ -1,3 +1,132 @@
+Sun May 30 18:35:19 2004  Ben Pfaff  <blp@gnu.org>
+
+       Fully implement arbitrary delimiters on DATA LIST, extending the
+       half implementation that was already there.
+
+       * data-list.c: (struct data_list_pgm) Remove `delim', add
+       `delims', `delim_cnt'.
+       (cmd_data_list) Initialize new members.  Parse delimiters and
+       clean up code a bit.
+       (cut_field) Extract fields with arbitrary delimiters.  Also, fix
+       handling of leading commas.
+       (read_from_data_list_fixed) Expand tabs.  Adapt to new DFM
+       interfaces.
+       (read_from_data_list_free) Adapt to new DFM interfaces.
+       (read_from_data_list_list) Ditto.
+       (repeating_data_trns_proc) Ditto.
+
+       * dfm.c: Split up reader and writer into separate code, because
+       they do different things.  Use struct string instead of explicit
+       allocation code, for clarity.
+       (enum dfm_reader_flags) New enum.
+       (struct dfm_fhuser_ext) Removed.
+       (struct dfm_reader_ext) New.
+       (get_reader) New function, used by just about all the reader
+       functions.
+       (dfm_close) Removed.
+       (close_reader) New function.
+       (dfm_open_for_reading) Rewrite initialization of dfm_fhuser_ext.
+       (dfm_open_for_writing) Ditto.
+       (macro force_line_buffer_expansion) Removed.
+       (count_tabs) Removed.
+       (tabs_to_spaces) Removed.
+       (read_record) Deal with new dfm_reader_ext.  Use struct string
+       functions.  Don't convert tabs to spaces.
+       (dfm_eof) New function.
+       (dfm_get_record) Changed interface, rewrote.
+       (dfm_expand_tabs) New function.
+       (dfm_fwd_record) Renamed dfm_forward_record(), updated to new
+       dfm_reader_ext, rewritten.
+       (dfm_bkwd_record) Renamed dfm_reread_record(), updated to new
+       dfm_reader_ext, rewritten.
+       (dfm_set_record) Removed in favor of dfm_forward_columns().
+       (dfm_forward_columns) New function.
+       (dfm_get_cur_col) Renamed dfm_column_start, updated to new
+       dfm_reader_ext, rewritten.
+       (static var dfm_r_class) Use close_reader for the destructor.
+       (struct dfm_writer_ext) New.
+       (dfm_put_record) Updated to new dfm_writer_ext, rewritten.  Uses
+       bounce buffer now instead of local allocation.
+       (close_writer) New function.
+       (static var dfm_writer_ext) Use close_writer for destructor.
+       (cmd_begin_data) Adapt to new dfm_reader_ext.
+
+       * file-handle.q: Add support for per-file tab width.
+       (struct private_file_handle) Add tab_width member.
+       (q2c specifications) Add tabwidth subcommand.
+       (cmd_file_handle) Put parsed tab width into private_file_handle.
+       (create_file_handle) Set default tab width.
+       (handle_get_tab_width) New function.
+
+       * file-type.c: (file_type_source_read) Adapt to new DFM interface.
+
+       * inpt-pgm.c: (reread_trns_proc) Ditto.
+
+       * matrix-data.c: (context) Ditto.
+       (another_token) Ditto.
+       (mget_token) Ditto.
+       (force_eol) Ditto.
+
+Sun May 30 18:33:59 2004  Ben Pfaff  <blp@gnu.org>
+
+       * casefile.c: (casefile_destroy) Fix memory leak by freeing
+       cf->filename.
+       (casereader_destroy) Don't close file descriptor -1.
+
+       * recode.c: (cmd_recode) Fix memory leak.
+
+       * set.q: (q2c specifications) Fix typo in user message.
+
+       * str.c: (st_bare_pad_len_copy) Change memcpy to memmove to avoid
+       undefined behavior for overlapping arguments.
+
+Sun May 30 18:31:48 2004  Ben Pfaff  <blp@gnu.org>
+
+       * casefile.c: valgrind doesn't implement posix_fadvise() yet, so
+       don't call it when we're running under valgrind.
+       (call_posix_fadvise) New function.
+       (casefile_to_disk) Use call_posix_fadvise().
+       (reader_open_file) Ditto.
+       
+Sun May 30 18:20:12 2004  Ben Pfaff  <blp@gnu.org>
+
+       Update our string ADTs, struct string and struct len_string.  Get
+       rid of pool support, which was largely unused.  Rename lots of
+       functions to have more obvious or consistent names.
+       
+       * ascii.c: Get rid of ascii_pool.  It was only used for string
+       allocations.
+       (ascii_open_global) Don't create ascii_pool.
+       (ascii_close_driver) Don't destroy ascii_pool.
+       (ascii_postopen_driver) Don't use pool.
+       (ascii_close_driver) Destroy strings manually.
+
+       * str.c: (ds_create) Remove pool argument, all references updated.
+       (ds_init) Ditto.
+       (ds_replace) Remove pool support, make more efficient when we
+       don't need to reallocate.
+       (ds_destroy) Remove pool support.
+       (ds_rpad) New function.
+       (ds_size) Renamed ds_capacity(), all references updated.
+       (ds_value) Renamed ds_c_str(), all references updated.
+       (ds_concat) Renamed ds_puts(), all references updated.
+       (ds_concat_buffer) Renamed ds_concat(), all references updated.
+       (ds_putchar) Renamed ds_putc(), all references updated.
+       (ds_getline) Renamed ds_gets(), all references updated.
+       (ls_create) Remove pool argument, all references updated.
+       (ls_create_buffer) Ditto.
+       (ls_destroy) Removed pool support.
+       (ls_value) Renamed ls_c_str(), all references updated.
+
+       * str.h: (ls_length) [__GNUC__] Add inline version.
+       (ls_c_str) [__GNUC__] Add inline version.
+       (ls_end) [__GNUC__] Add inline version.
+       (struct string) Remove pool member.  Rename `size' to `capacity',
+       all references updated.
+
+       * tab.c: (text_format) Instead of using pool argument to
+       ls_create_buffer(), call pool_register() on allocated data.
+
 Mon Apr 26 22:40:07 2004  Ben Pfaff  <blp@gnu.org>
 
        We're abusing the current ASCII driver by telling it to allocate a
 Mon Apr 26 22:40:07 2004  Ben Pfaff  <blp@gnu.org>
 
        We're abusing the current ASCII driver by telling it to allocate a
index 32de72ef05f77a431caefd3851487f2db0c9fb96..4f2f1f45800fad3ad719ba32e57e1421b3c4c77d 100644 (file)
@@ -388,7 +388,7 @@ parse_aggregate_functions (struct agr_proc *agr)
          if (token == T_STRING)
            {
              ds_truncate (&tokstr, 255);
          if (token == T_STRING)
            {
              ds_truncate (&tokstr, 255);
-             dest_label[n_dest - 1] = xstrdup (ds_value (&tokstr));
+             dest_label[n_dest - 1] = xstrdup (ds_c_str (&tokstr));
              lex_get ();
            }
        }
              lex_get ();
            }
        }
@@ -454,7 +454,7 @@ parse_aggregate_functions (struct agr_proc *agr)
                lex_match (',');
                if (token == T_STRING)
                  {
                lex_match (',');
                if (token == T_STRING)
                  {
-                   arg[i].c = xstrdup (ds_value (&tokstr));
+                   arg[i].c = xstrdup (ds_c_str (&tokstr));
                    type = ALPHA;
                  }
                else if (token == T_NUM)
                    type = ALPHA;
                  }
                else if (token == T_NUM)
index bdaac410566cdf55a5ef26e7bb0e4a319ac6db31..6fa1573be050ae5ade4cf94ad947f03be6f8a266 100644 (file)
@@ -184,22 +184,19 @@ struct ascii_driver_ext
 #endif
   };
 
 #endif
   };
 
-static struct pool *ascii_pool;
-
 static int postopen (struct file_ext *);
 static int preclose (struct file_ext *);
 
 static int
 ascii_open_global (struct outp_class *this UNUSED)
 {
 static int postopen (struct file_ext *);
 static int preclose (struct file_ext *);
 
 static int
 ascii_open_global (struct outp_class *this UNUSED)
 {
-  ascii_pool = pool_create ();
   return 1;
 }
 
   return 1;
 }
 
+
 static int
 ascii_close_global (struct outp_class *this UNUSED)
 {
 static int
 ascii_close_global (struct outp_class *this UNUSED)
 {
-  pool_destroy (ascii_pool);
   return 1;
 }
 
   return 1;
 }
 
@@ -288,11 +285,11 @@ ascii_postopen_driver (struct outp_driver *this)
   this->length = x->l * this->vert;
   
   if (ls_null_p (&x->ops[OPS_FORMFEED]))
   this->length = x->l * this->vert;
   
   if (ls_null_p (&x->ops[OPS_FORMFEED]))
-    ls_create (ascii_pool, &x->ops[OPS_FORMFEED], "\f");
+    ls_create (&x->ops[OPS_FORMFEED], "\f");
   if (ls_null_p (&x->ops[OPS_NEWLINE])
   if (ls_null_p (&x->ops[OPS_NEWLINE])
-      || !strcmp (ls_value (&x->ops[OPS_NEWLINE]), "default"))
+      || !strcmp (ls_c_str (&x->ops[OPS_NEWLINE]), "default"))
     {
     {
-      ls_create (ascii_pool, &x->ops[OPS_NEWLINE], "\n");
+      ls_create (&x->ops[OPS_NEWLINE], "\n");
       x->file.mode = "wt";
     }
   
       x->file.mode = "wt";
     }
   
@@ -351,7 +348,7 @@ ascii_postopen_driver (struct outp_driver *this)
              c[0] = '+';
            break;
          }
              c[0] = '+';
            break;
          }
-       ls_create (ascii_pool, &x->box[i], c);
+       ls_create (&x->box[i], c);
       }
   }
   
       }
   }
   
@@ -389,11 +386,18 @@ static int
 ascii_close_driver (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
 ascii_close_driver (struct outp_driver *this)
 {
   struct ascii_driver_ext *x = this->ext;
+  int i;
   
   assert (this->driver_open == 1);
   msg (VM (2), _("%s: Beginning closing..."), this->name);
   
   x = this->ext;
   
   assert (this->driver_open == 1);
   msg (VM (2), _("%s: Beginning closing..."), this->name);
   
   x = this->ext;
+  for (i = 0; i < OPS_COUNT; i++)
+    ls_destroy (&x->ops[i]);
+  for (i = 0; i < LNS_COUNT; i++)
+    ls_destroy (&x->box[i]);
+  for (i = 0; i < FSTY_COUNT; i++)
+    ls_destroy (&x->fonts[i]);
   if (x->lines != NULL) 
     {
       int line;
   if (x->lines != NULL) 
     {
       int line;
@@ -462,7 +466,7 @@ ascii_option (struct outp_driver *this, const char *key,
   int cat, subcat;
   const char *value;
 
   int cat, subcat;
   const char *value;
 
-  value = ds_value (val);
+  value = ds_c_str (val);
   if (!strncmp (key, "box[", 4))
     {
       char *tail;
   if (!strncmp (key, "box[", 4))
     {
       char *tail;
@@ -476,7 +480,7 @@ ascii_option (struct outp_driver *this, const char *key,
        }
       if (!ls_null_p (&x->box[indx]))
        msg (SW, _("Duplicate value for key `%s'."), key);
        }
       if (!ls_null_p (&x->box[indx]))
        msg (SW, _("Duplicate value for key `%s'."), key);
-      ls_create (ascii_pool, &x->box[indx], value);
+      ls_create (&x->box[indx], value);
       return;
     }
 
       return;
     }
 
@@ -605,17 +609,17 @@ ascii_option (struct outp_driver *this, const char *key,
            assert (0);
             abort ();
          }
            assert (0);
             abort ();
          }
-       ls_create (ascii_pool, s, value);
+       ls_create (s, value);
       }
       break;
     case font_string_arg:
       {
        if (!strcmp (value, "overstrike"))
          {
       }
       break;
     case font_string_arg:
       {
        if (!strcmp (value, "overstrike"))
          {
-           ls_destroy (ascii_pool, &x->fonts[subcat]);
+           ls_destroy (&x->fonts[subcat]);
            return;
          }
            return;
          }
-       ls_create (ascii_pool, &x->fonts[subcat], value);
+       ls_create (&x->fonts[subcat], value);
       }
       break;
     case boolean_arg:
       }
       break;
     case boolean_arg:
@@ -659,7 +663,7 @@ postopen (struct file_ext *f)
   struct ascii_driver_ext *x = f->param;
   struct len_string *s = &x->ops[OPS_INIT];
 
   struct ascii_driver_ext *x = f->param;
   struct len_string *s = &x->ops[OPS_INIT];
 
-  if (!ls_empty_p (s) && fwrite (ls_value (s), ls_length (s), 1, f->file) < 1)
+  if (!ls_empty_p (s) && fwrite (ls_c_str (s), ls_length (s), 1, f->file) < 1)
     {
       msg (ME, _("ASCII output driver: %s: %s"),
           f->filename, strerror (errno));
     {
       msg (ME, _("ASCII output driver: %s: %s"),
           f->filename, strerror (errno));
@@ -674,7 +678,7 @@ preclose (struct file_ext *f)
   struct ascii_driver_ext *x = f->param;
   struct len_string *d = &x->ops[OPS_DONE];
 
   struct ascii_driver_ext *x = f->param;
   struct len_string *d = &x->ops[OPS_DONE];
 
-  if (!ls_empty_p (d) && fwrite (ls_value (d), ls_length (d), 1, f->file) < 1)
+  if (!ls_empty_p (d) && fwrite (ls_c_str (d), ls_length (d), 1, f->file) < 1)
     {
       msg (ME, _("ASCII output driver: %s: %s"),
           f->filename, strerror (errno));
     {
       msg (ME, _("ASCII output driver: %s: %s"),
           f->filename, strerror (errno));
@@ -971,7 +975,7 @@ delineate (struct outp_driver *this, struct outp_text *t, int draw)
   int max_y;
 
   /* Current position in string, character following end of string. */
   int max_y;
 
   /* Current position in string, character following end of string. */
-  const char *s = ls_value (&t->s);
+  const char *s = ls_c_str (&t->s);
   const char *end = ls_end (&t->s);
 
   /* Temporary struct outp_text to pass to low-level function. */
   const char *end = ls_end (&t->s);
 
   /* Temporary struct outp_text to pass to low-level function. */
@@ -1103,7 +1107,7 @@ text_draw (struct outp_driver *this, struct outp_text *t)
   int x = t->x;
   int y = t->y;
 
   int x = t->x;
   int y = t->y;
 
-  char *s = ls_value (&t->s);
+  char *s = ls_c_str (&t->s);
 
   /* Expand the line with the assumption that S takes up LEN character
      spaces (sometimes it takes up less). */
 
   /* Expand the line with the assumption that S takes up LEN character
      spaces (sometimes it takes up less). */
@@ -1201,7 +1205,7 @@ output_shorts (struct outp_driver *this,
 
          if (remaining >= len)
            {
 
          if (remaining >= len)
            {
-             memcpy (line_p, ls_value (box), len);
+             memcpy (line_p, ls_c_str (box), len);
              line_p += len;
              remaining -= len;
            }
              line_p += len;
              remaining -= len;
            }
@@ -1209,7 +1213,7 @@ output_shorts (struct outp_driver *this,
            {
              if (!commit_line_buf (this))
                return 0;
            {
              if (!commit_line_buf (this))
                return 0;
-             output_string (this, ls_value (box), ls_end (box));
+             output_string (this, ls_c_str (box), ls_end (box));
              remaining = LINE_BUF_SIZE - (line_p - line_buf);
            }
        }
              remaining = LINE_BUF_SIZE - (line_p - line_buf);
            }
        }
@@ -1426,7 +1430,7 @@ output_lines (struct outp_driver *this, int first, int count)
                   abort ();
                }
              if (off)
                   abort ();
                }
              if (off)
-               output_string (this, ls_value (off), ls_end (off));
+               output_string (this, ls_c_str (off), ls_end (off));
            }
 
          /* Turn on new font. */
            }
 
          /* Turn on new font. */
@@ -1451,7 +1455,7 @@ output_lines (struct outp_driver *this, int first, int count)
                   abort ();
                }
              if (on)
                   abort ();
                }
              if (on)
-               output_string (this, ls_value (on), ls_end (on));
+               output_string (this, ls_c_str (on), ls_end (on));
            }
 
          ep = bp + 1;
            }
 
          ep = bp + 1;
@@ -1510,7 +1514,7 @@ output_lines (struct outp_driver *this, int first, int count)
            }
        }
 
            }
        }
 
-      output_string (this, ls_value (newline), ls_end (newline));
+      output_string (this, ls_c_str (newline), ls_end (newline));
     }
 }
 
     }
 }
 
@@ -1542,7 +1546,7 @@ ascii_close_page (struct outp_driver *this)
        }
       for (cp = s, i = 0; i < x->top_margin; i++)
        {
        }
       for (cp = s, i = 0; i < x->top_margin; i++)
        {
-         memcpy (cp, ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+         memcpy (cp, ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
          cp += nl_len;
        }
       output_string (this, s, &s[total_len]);
          cp += nl_len;
        }
       output_string (this, s, &s[total_len]);
@@ -1572,7 +1576,7 @@ ascii_close_page (struct outp_driver *this)
          len = min ((int) strlen (outp_title), x->w);
          memcpy (s, outp_title, len);
        }
          len = min ((int) strlen (outp_title), x->w);
          memcpy (s, outp_title, len);
        }
-      memcpy (&s[x->w], ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+      memcpy (&s[x->w], ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
       output_string (this, s, &s[total_len]);
 
       memset (s, ' ', x->w);
       output_string (this, s, &s[total_len]);
 
       memset (s, ' ', x->w);
@@ -1585,7 +1589,7 @@ ascii_close_page (struct outp_driver *this)
          len = min ((int) strlen (string), x->w);
          memcpy (s, string, len);
        }
          len = min ((int) strlen (string), x->w);
          memcpy (s, string, len);
        }
-      memcpy (&s[x->w], ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+      memcpy (&s[x->w], ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
       output_string (this, s, &s[total_len]);
       output_string (this, &s[x->w], &s[total_len]);
     }
       output_string (this, s, &s[total_len]);
       output_string (this, &s[x->w], &s[total_len]);
     }
@@ -1600,10 +1604,10 @@ ascii_close_page (struct outp_driver *this)
     s = xrealloc (s, total_len);
   for (cp = s, i = 0; i < x->bottom_margin; i++)
     {
     s = xrealloc (s, total_len);
   for (cp = s, i = 0; i < x->bottom_margin; i++)
     {
-      memcpy (cp, ls_value (&x->ops[OPS_NEWLINE]), nl_len);
+      memcpy (cp, ls_c_str (&x->ops[OPS_NEWLINE]), nl_len);
       cp += nl_len;
     }
       cp += nl_len;
     }
-  memcpy (cp, ls_value (&x->ops[OPS_FORMFEED]), ff_len);
+  memcpy (cp, ls_c_str (&x->ops[OPS_FORMFEED]), ff_len);
   if ( x->paginate ) 
          output_string (this, s, &s[total_len]);
   if (line_p != line_buf && !commit_line_buf (this))
   if ( x->paginate ) 
          output_string (this, s, &s[total_len]);
   if (line_p != line_buf && !commit_line_buf (this))
index 9c889b64226e726e88917e98f5024b5509022059..d2c1038330018da29e2b2a90463e97372d96c3dd 100644 (file)
 #include "var.h"
 #include "workspace.h"
 
 #include "var.h"
 #include "workspace.h"
 
+#ifdef HAVE_VALGRIND_VALGRIND_H
+#include <valgrind/valgrind.h>
+#endif
+
 #define IO_BUF_SIZE 8192
 
 /* A casefile is a sequentially accessible array of immutable
 #define IO_BUF_SIZE 8192
 
 /* A casefile is a sequentially accessible array of immutable
@@ -153,6 +157,7 @@ casefile_destroy (struct casefile *cf)
       if (cf->filename != NULL && remove (cf->filename) == -1) 
         msg (ME, _("%s: Removing temporary file: %s."),
              cf->filename, strerror (errno));
       if (cf->filename != NULL && remove (cf->filename) == -1) 
         msg (ME, _("%s: Removing temporary file: %s."),
              cf->filename, strerror (errno));
+      free (cf->filename);
 
       free (cf->buffer);
 
 
       free (cf->buffer);
 
@@ -280,6 +285,23 @@ make_temp_file (int *fd, char **filename)
   return 1;
 }
 
   return 1;
 }
 
+static void
+call_posix_fadvise (int fd UNUSED,
+                    off_t offset UNUSED, off_t len UNUSED,
+                    int advice UNUSED) 
+{
+#ifdef HAVE_VALGRIND_VALGRIND_H
+  /* Valgrind doesn't know about posix_fadvise() as of this
+     writing. */
+  if (RUNNING_ON_VALGRIND)
+    return; 
+#endif
+
+#ifdef HAVE_POSIX_FADVISE
+  posix_fadvise (fd, offset, len, advice);
+#endif
+}
+
 /* If CF is currently stored in memory, writes it to disk.  Readers, if any,
    retain their current positions. */
 void
 /* If CF is currently stored in memory, writes it to disk.  Readers, if any,
    retain their current positions. */
 void
@@ -299,9 +321,7 @@ casefile_to_disk (struct casefile *cf)
       cf->storage = DISK;
       if (!make_temp_file (&cf->fd, &cf->filename))
         err_failure ();
       cf->storage = DISK;
       if (!make_temp_file (&cf->fd, &cf->filename))
         err_failure ();
-#if HAVE_POSIX_FADVISE
-      posix_fadvise (cf->fd, 0, 0, POSIX_FADV_SEQUENTIAL);
-#endif
+      call_posix_fadvise (cf->fd, 0, 0, POSIX_FADV_SEQUENTIAL);
       cf->buffer = xmalloc (cf->buffer_size);
       memset (cf->buffer, 0, cf->buffer_size);
 
       cf->buffer = xmalloc (cf->buffer_size);
       memset (cf->buffer, 0, cf->buffer_size);
 
@@ -493,9 +513,7 @@ reader_open_file (struct casereader *reader)
     }
   else 
     file_ofs = 0;
     }
   else 
     file_ofs = 0;
-#if HAVE_POSIX_FADVISE
-  posix_fadvise (reader->fd, file_ofs, 0, POSIX_FADV_SEQUENTIAL);
-#endif
+  call_posix_fadvise (reader->fd, file_ofs, 0, POSIX_FADV_SEQUENTIAL);
   if (lseek (reader->fd, file_ofs, SEEK_SET) != file_ofs)
     msg (FE, _("%s: Seeking temporary file: %s."),
          reader->cf->filename, strerror (errno));
   if (lseek (reader->fd, file_ofs, SEEK_SET) != file_ofs)
     msg (FE, _("%s: Seeking temporary file: %s."),
          reader->cf->filename, strerror (errno));
@@ -567,11 +585,14 @@ casereader_destroy (struct casereader *reader)
   else
     free (reader->buffer);
 
   else
     free (reader->buffer);
 
-  if (reader->cf->fd == -1)
-    reader->cf->fd = reader->fd;
-  else
-    safe_close (reader->fd);
-
+  if (reader->fd != -1) 
+    {
+      if (reader->cf->fd == -1)
+        reader->cf->fd = reader->fd;
+      else
+        safe_close (reader->fd);
+    }
+  
   free (reader);
 }
 
   free (reader);
 }
 
index cd2b2038163b41f85d67394d35ed01fa54cefd1e..5ff4f0de2c0e746cfac3c81b28cb05e9f6380cb6 100644 (file)
@@ -486,7 +486,7 @@ parse_command_name (void)
       
       assert (word_cnt < sizeof words / sizeof *words);
       if (token == T_ID)
       
       assert (word_cnt < sizeof words / sizeof *words);
       if (token == T_ID)
-        words[word_cnt++] = xstrdup (ds_value (&tokstr));
+        words[word_cnt++] = xstrdup (ds_c_str (&tokstr));
       else
         words[word_cnt++] = xstrdup ("-");
 
       else
         words[word_cnt++] = xstrdup ("-");
 
@@ -632,10 +632,10 @@ cmd_erase (void)
   if (!lex_force_string ())
     return CMD_FAILURE;
 
   if (!lex_force_string ())
     return CMD_FAILURE;
 
-  if (remove (ds_value (&tokstr)) == -1)
+  if (remove (ds_c_str (&tokstr)) == -1)
     {
       msg (SW, _("Error removing `%s': %s."),
     {
       msg (SW, _("Error removing `%s': %s."),
-          ds_value (&tokstr), strerror (errno));
+          ds_c_str (&tokstr), strerror (errno));
       return CMD_FAILURE;
     }
 
       return CMD_FAILURE;
     }
 
@@ -713,7 +713,7 @@ run_command (void)
        lex_get ();
        if (!lex_force_string ())
          return CMD_FAILURE;
        lex_get ();
        if (!lex_force_string ())
          return CMD_FAILURE;
-       cmd = ds_value (&tokstr);
+       cmd = ds_c_str (&tokstr);
        string = 1;
       }
     else
        string = 1;
       }
     else
index 058d60d539d81f71c7880b703fc9f1a1c62e06ad..dd88e01a62aeac8d4bf845af1ae0f9c06584c524 100644 (file)
@@ -347,7 +347,7 @@ parse_string_criteria (struct counting * c)
       cur = &c->crit.s[n++];
       cur->type = CNT_SINGLE;
       cur->s = malloc (len + 1);
       cur = &c->crit.s[n++];
       cur->type = CNT_SINGLE;
       cur->s = malloc (len + 1);
-      st_pad_copy (cur->s, ds_value (&tokstr), len + 1);
+      st_pad_copy (cur->s, ds_c_str (&tokstr), len + 1);
       lex_get ();
 
       lex_match (',');
       lex_get ();
 
       lex_match (',');
index 3931067daabe0f002dc9365c8873af2a72c13b89..c082516d664efe45f39f6eaf31a1b439c0cdfb3b 100644 (file)
@@ -64,9 +64,9 @@ dls_error (const struct data_in *i, const char *format, ...)
     struct error e;
     struct string title;
 
     struct error e;
     struct string title;
 
-    ds_init (NULL, &title, 64);
+    ds_init (&title, 64);
     if (!getl_reading_script)
     if (!getl_reading_script)
-      ds_concat (&title, _("data-file error: "));
+      ds_puts (&title, _("data-file error: "));
     if (i->f1 == i->f2)
       ds_printf (&title, _("(column %d"), i->f1);
     else
     if (i->f1 == i->f2)
       ds_printf (&title, _("(column %d"), i->f1);
     else
@@ -75,7 +75,7 @@ dls_error (const struct data_in *i, const char *format, ...)
     
     e.class = DE;
     err_location (&e.where);
     
     e.class = DE;
     err_location (&e.where);
-    e.title = ds_value (&title);
+    e.title = ds_c_str (&title);
     e.text = buf;
 
     err_vmsg (&e);
     e.text = buf;
 
     err_vmsg (&e);
index 62734de1d191f3b5eb3649c0e403b9ee1e92ee1e..c9203122134f87eac200e04b6fc984520c5486ec 100644 (file)
@@ -88,7 +88,8 @@ struct data_list_pgm
     int eof;                   /* End of file encountered. */
     int nrec;                  /* Number of records. */
     size_t case_size;           /* Case size in bytes. */
     int eof;                   /* End of file encountered. */
     int nrec;                  /* Number of records. */
     size_t case_size;           /* Case size in bytes. */
-    int delim;                  /* Specified delimeter */
+    char *delims;               /* Delimiters if any; not null-terminated. */
+    size_t delim_cnt;           /* Number of delimiter, or 0 for spaces. */
   };
 
 static int parse_fixed (struct data_list_pgm *);
   };
 
 static int parse_fixed (struct data_list_pgm *);
@@ -121,7 +122,8 @@ cmd_data_list (void)
   dls->end = NULL;
   dls->eof = 0;
   dls->nrec = 0;
   dls->end = NULL;
   dls->eof = 0;
   dls->nrec = 0;
-  dls->delim=0;
+  dls->delims = NULL;
+  dls->delim_cnt = 0;
   dls->first = dls->last = NULL;
 
   while (token != '/')
   dls->first = dls->last = NULL;
 
   while (token != '/')
@@ -168,45 +170,58 @@ cmd_data_list (void)
        }
       else if (token == T_ID)
        {
        }
       else if (token == T_ID)
        {
-         /* Must match DLS_* constants. */
-         static const char *id[] = {"FIXED", "FREE", "LIST", "NOTABLE",
-                                    "TABLE", NULL};
-         const char **p;
-         int index;
-
-         for (p = id; *p; p++)
-           if (lex_id_match (*p, tokid))
-             break;
-         if (*p == NULL)
-           {
-             lex_error (NULL);
-             goto error;
-           }
-         
-         lex_get ();
+          if (lex_match_id ("NOTABLE"))
+            table = 0;
+          else if (lex_match_id ("TABLE"))
+            table = 1;
+          else 
+            {
+              int type;
+              if (lex_match_id ("FIXED"))
+                type = DLS_FIXED;
+              else if (lex_match_id ("FREE"))
+                type = DLS_FREE;
+              else if (lex_match_id ("LIST"))
+                type = DLS_LIST;
+              else 
+                {
+                  lex_error (NULL);
+                  goto error;
+                }
 
 
-         index = p - id;
-         if (index < 3)
-           {
              if (dls->type != -1)
                {
                  msg (SE, _("Only one of FIXED, FREE, or LIST may "
              if (dls->type != -1)
                {
                  msg (SE, _("Only one of FIXED, FREE, or LIST may "
-                           "be specified."));
+                             "be specified."));
                  goto error;
                }
                  goto error;
                }
-             
-             dls->type = index;
-           }
-         else
-           table = index - 3;
-       }
-      else if (token=='(') {
-        lex_get();
-        if (lex_match_id ("TAB")) {
-          dls->delim='\t';
+             dls->type = type;
+
+              if ((dls->type == DLS_FREE || dls->type == DLS_LIST)
+                  && lex_match ('(')) 
+                {
+                  while (!lex_match (')'))
+                    {
+                      int delim;
+
+                      if (lex_match_id ("TAB"))
+                        delim = '\t';
+                      else if (token == T_STRING && tokstr.length == 1)
+                        delim = tokstr.string[0];
+                      else 
+                        {
+                          lex_error (NULL);
+                          goto error;
+                        }
+
+                      dls->delims = xrealloc (dls->delims, dls->delim_cnt + 1);
+                      dls->delims[dls->delim_cnt++] = delim;
+
+                      lex_match (',');
+                    }
+                }
+            }
         }
         }
-        lex_get();
-      }
       else
        {
          lex_error (NULL);
       else
        {
          lex_error (NULL);
@@ -938,90 +953,111 @@ dump_free_table (const struct data_list_pgm *dls)
 \f
 /* Input procedure. */ 
 
 \f
 /* Input procedure. */ 
 
-/* Extracts a field from the current position in the current record.
-   Fields can be unquoted or quoted with single- or double-quote
-   characters.  *RET_LEN is set to the field length, *RET_CP is set to
-   the field itself.  After parsing the field, sets the current
-   position in the record to just past the field.  Returns 0 on
-   failure or a 1-based column number indicating the beginning of the
-   field on success. */
+/* Extracts a field from the current position in the current
+   record.  Fields can be unquoted or quoted with single- or
+   double-quote characters.  *FIELD is set to the field content.
+   After parsing the field, sets the current position in the
+   record to just past the field and any trailing delimiter.
+   END_BLANK is used internally; it should be initialized by the
+   caller to 0 and left alone afterward.  Returns 0 on failure or
+   a 1-based column number indicating the beginning of the field
+   on success. */
 static int
 static int
-cut_field (const struct data_list_pgm *dls, char **ret_cp, int *ret_len)
+cut_field (const struct data_list_pgm *dls, struct len_string *field,
+           int *end_blank)
 {
 {
-  char *cp, *ep;
-  int len;
-
-  cp = dfm_get_record (dls->handle, &len);
-  if (!cp)
-    return 0;
-
-  ep = cp + len;
-  if (dls->delim != 0) {
-    if (*cp==dls->delim) {
-      cp++;
-    }
-  } else {
+  struct len_string line;
+  char *cp;
+  size_t column_start;
 
 
-    /* Skip leading whitespace and commas. */
-    while ((isspace ((unsigned char) *cp) || *cp == ',') && cp < ep)
-      cp++;
-  }
-  if (cp >= ep)
+  if (dfm_eof (dls->handle))
     return 0;
     return 0;
+  if (dls->delim_cnt == 0)
+    dfm_expand_tabs (dls->handle);
+  dfm_get_record (dls->handle, &line);
 
 
-  /* Three types of fields: quoted with ', quoted with ", unquoted. */
-  /* Quoting does not escape the effects of delimiters for explicitly */
-  /* specified delims */
-  /* (consistency with SPSS doco: */
-  /*  For data with explicitly specified value delimiters (for example,  */
-  /*  DATA LIST FREE (","):                                              */
-  /*   - Multiple delimiters without any intervening space can be used   */
-  /*     to specify missing data.                                        */
-  /*   - The specified delimiters cannot occur within a data value, even */
-  /*     if you enclose the value in quotation marks or apostrophes.     */
-  if (dls->delim==0 && (*cp == '\'' || *cp == '"'))
+  cp = ls_c_str (&line);
+  if (dls->delim_cnt == 0) 
     {
     {
-      int quote = *cp;
-
-      *ret_cp = ++cp;
-      while (cp < ep && *cp != quote)
-       cp++;
-      if (dls->delim!=0) {
-        while(cp<ep && *cp!=dls->delim) {
-          cp++;
+      /* Skip leading whitespace. */
+      while (cp < ls_end (&line) && isspace ((unsigned char) *cp))
+        cp++;
+      if (cp >= ls_end (&line))
+        return 0;
+      
+      /* Handle actual data, whether quoted or unquoted. */
+      if (*cp == '\'' || *cp == '"')
+        {
+          int quote = *cp;
+
+          field->string = ++cp;
+          while (cp < ls_end (&line) && *cp != quote)
+            cp++;
+          field->length = cp - field->string;
+          if (cp < ls_end (&line))
+            cp++;
+          else
+            msg (SW, _("Quoted string missing terminating `%c'."), quote);
         }
         }
-      } 
-      *ret_len = cp - *ret_cp;
-      if (cp < ep)
-       cp++;
       else
       else
-       msg (SW, _("Scope of string exceeds line."));      
+        {
+          field->string = cp;
+          while (cp < ls_end (&line)
+                 && !isspace ((unsigned char) *cp) && *cp != ',')
+            cp++;
+          field->length = cp - field->string;
+        }
+
+      /* Skip trailing whitespace and a single comma if present. */
+      while (cp < ls_end (&line) && isspace ((unsigned char) *cp))
+        cp++;
+      if (cp < ls_end (&line) && *cp == ',')
+        cp++;
     }
     }
-  else
+  else 
     {
     {
-      *ret_cp = cp;
-      if (dls->delim!=0) {
-       while(cp<ep && *cp!=dls->delim) {
-          cp++;
+      if (cp >= ls_end (&line)) 
+        {
+          int column = dfm_column_start (dls->handle);
+               /* A blank line or a line that ends in \t has a
+             trailing blank field. */
+          if (column == 1 || (column > 1 && cp[-1] == '\t'))
+            {
+              if (*end_blank == 0)
+                {
+                  *end_blank = 1;
+                  field->string = ls_end (&line);
+                  field->length = 0;
+                  dfm_forward_record (dls->handle);
+                  return column;
+                }
+              else 
+                {
+                  *end_blank = 0;
+                  return 0;
+                }
+            }
+          else 
+            return 0;
+        }
+      else 
+        {
+          field->string = cp;
+          while (cp < ls_end (&line)
+                 && memchr (dls->delims, *cp, dls->delim_cnt) == NULL)
+            cp++; 
+          field->length = cp - field->string;
+          if (cp < ls_end (&line)) 
+            cp++;
         }
         }
-      } else {
-
-       while (cp < ep && !isspace ((unsigned char) *cp) && *cp != ',')
-         cp++;
-      }
-      *ret_len = cp - *ret_cp;
     }
     }
-
-  {
-    int beginning_column;
-    
-    dfm_set_record (dls->handle, *ret_cp);
-    beginning_column = dfm_get_cur_col (dls->handle) + 1;
+  
+  dfm_forward_columns (dls->handle, field->string - line.string);
+  column_start = dfm_column_start (dls->handle);
     
     
-    dfm_set_record (dls->handle, cp);
+  dfm_forward_columns (dls->handle, cp - field->string);
     
     
-    return beginning_column;
-  }
+  return column_start;
 }
 
 typedef int data_list_read_func (const struct data_list_pgm *, struct ccase *);
 }
 
 typedef int data_list_read_func (const struct data_list_pgm *, struct ccase *);
@@ -1061,26 +1097,28 @@ read_from_data_list_fixed (const struct data_list_pgm *dls,
   struct dls_var_spec *var_spec = dls->first;
   int i;
 
   struct dls_var_spec *var_spec = dls->first;
   int i;
 
-  if (!dfm_get_record (dls->handle, NULL))
+  if (dfm_eof (dls->handle))
     return -2;
   for (i = 1; i <= dls->nrec; i++)
     {
     return -2;
   for (i = 1; i <= dls->nrec; i++)
     {
-      int len;
-      char *line = dfm_get_record (dls->handle, &len);
+      struct len_string line;
       
       
-      if (!line)
+      if (dfm_eof (dls->handle))
        {
          /* Note that this can't occur on the first record. */
          msg (SW, _("Partial case of %d of %d records discarded."),
               i - 1, dls->nrec);
          return -2;
        }
        {
          /* Note that this can't occur on the first record. */
          msg (SW, _("Partial case of %d of %d records discarded."),
               i - 1, dls->nrec);
          return -2;
        }
+      dfm_expand_tabs (dls->handle);
+      dfm_get_record (dls->handle, &line);
 
       for (; var_spec && i == var_spec->rec; var_spec = var_spec->next)
        {
          struct data_in di;
 
 
       for (; var_spec && i == var_spec->rec; var_spec = var_spec->next)
        {
          struct data_in di;
 
-         data_in_finite_line (&di, line, len, var_spec->fc, var_spec->lc);
+         data_in_finite_line (&di, ls_c_str (&line), ls_length (&line),
+                               var_spec->fc, var_spec->lc);
          di.v = &c->data[var_spec->fv];
          di.flags = 0;
          di.f1 = var_spec->fc;
          di.v = &c->data[var_spec->fv];
          di.flags = 0;
          di.f1 = var_spec->fc;
@@ -1089,7 +1127,7 @@ read_from_data_list_fixed (const struct data_list_pgm *dls,
          data_in (&di);
        }
 
          data_in (&di);
        }
 
-      dfm_fwd_record (dls->handle);
+      dfm_forward_record (dls->handle);
     }
 
   return -1;
     }
 
   return -1;
@@ -1103,27 +1141,27 @@ read_from_data_list_free (const struct data_list_pgm *dls,
                           struct ccase *c)
 {
   struct dls_var_spec *var_spec;
                           struct ccase *c)
 {
   struct dls_var_spec *var_spec;
-  char *field;
-  int len;
+  int end_blank = 0;
 
   for (var_spec = dls->first; var_spec; var_spec = var_spec->next)
     {
 
   for (var_spec = dls->first; var_spec; var_spec = var_spec->next)
     {
+      struct len_string field;
       int column;
       
       /* Cut out a field and read in a new record if necessary. */
       for (;;)
        {
       int column;
       
       /* Cut out a field and read in a new record if necessary. */
       for (;;)
        {
-         column = cut_field (dls, &field, &len);
+         column = cut_field (dls, &field, &end_blank);
          if (column != 0)
            break;
 
          if (column != 0)
            break;
 
-         if (dfm_get_record (dls->handle, NULL))
-           dfm_fwd_record (dls->handle);
-         if (!dfm_get_record (dls->handle, NULL))
+         if (!dfm_eof (dls->handle)) 
+            dfm_forward_record (dls->handle);
+         if (dfm_eof (dls->handle))
            {
              if (var_spec != dls->first)
                msg (SW, _("Partial case discarded.  The first variable "
            {
              if (var_spec != dls->first)
                msg (SW, _("Partial case discarded.  The first variable "
-                    "missing was %s."), var_spec->name);
+                           "missing was %s."), var_spec->name);
              return -2;
            }
        }
              return -2;
            }
        }
@@ -1131,8 +1169,8 @@ read_from_data_list_free (const struct data_list_pgm *dls,
       {
        struct data_in di;
 
       {
        struct data_in di;
 
-       di.s = field;
-       di.e = field + len;
+       di.s = ls_c_str (&field);
+       di.e = ls_end (&field);
        di.v = &c->data[var_spec->fv];
        di.flags = 0;
        di.f1 = column;
        di.v = &c->data[var_spec->fv];
        di.flags = 0;
        di.f1 = column;
@@ -1151,25 +1189,26 @@ read_from_data_list_list (const struct data_list_pgm *dls,
                           struct ccase *c)
 {
   struct dls_var_spec *var_spec;
                           struct ccase *c)
 {
   struct dls_var_spec *var_spec;
-  char *field;
-  int len;
+  int end_blank = 0;
 
 
-  if (!dfm_get_record (dls->handle, NULL))
+  if (dfm_eof (dls->handle))
     return -2;
 
   for (var_spec = dls->first; var_spec; var_spec = var_spec->next)
     {
     return -2;
 
   for (var_spec = dls->first; var_spec; var_spec = var_spec->next)
     {
+      struct len_string field;
+      int column;
+
       /* Cut out a field and check for end-of-line. */
       /* Cut out a field and check for end-of-line. */
-      int column = cut_field (dls, &field, &len);
-      
+      column = cut_field (dls, &field, &end_blank);
       if (column == 0)
        {
       if (column == 0)
        {
-         if (get_undefined() )
+         if (get_undefined ())
            msg (SW, _("Missing value(s) for all variables from %s onward.  "
            msg (SW, _("Missing value(s) for all variables from %s onward.  "
-                "These will be filled with the system-missing value "
-                "or blanks, as appropriate."),
+                       "These will be filled with the system-missing value "
+                       "or blanks, as appropriate."),
                 var_spec->name);
                 var_spec->name);
-         for (; var_spec; var_spec = var_spec->next) 
+         for (; var_spec; var_spec = var_spec->next)
             {
               int width = get_format_var_width (&var_spec->input);
               if (width == 0)
             {
               int width = get_format_var_width (&var_spec->input);
               if (width == 0)
@@ -1183,8 +1222,8 @@ read_from_data_list_list (const struct data_list_pgm *dls,
       {
        struct data_in di;
 
       {
        struct data_in di;
 
-       di.s = field;
-       di.e = field + len;
+       di.s = ls_c_str (&field);
+       di.e = ls_end (&field);
        di.v = &c->data[var_spec->fv];
        di.flags = 0;
        di.f1 = column;
        di.v = &c->data[var_spec->fv];
        di.flags = 0;
        di.f1 = column;
@@ -1193,7 +1232,7 @@ read_from_data_list_list (const struct data_list_pgm *dls,
       }
     }
 
       }
     }
 
-  dfm_fwd_record (dls->handle);
+  dfm_forward_record (dls->handle);
   return -1;
 }
 
   return -1;
 }
 
@@ -1882,15 +1921,14 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
 {
   struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
     
 {
   struct repeating_data_trns *t = (struct repeating_data_trns *) trns;
     
-  char *line;          /* Current record. */
-  int len;             /* Length of current record. */
+  struct len_string line;       /* Current record. */
 
   int starts_beg;      /* Starting column. */
   int starts_end;      /* Ending column. */
   int occurs;          /* Number of repetitions. */
   int length;          /* Length of each occurrence. */
 
   int starts_beg;      /* Starting column. */
   int starts_end;      /* Ending column. */
   int occurs;          /* Number of repetitions. */
   int length;          /* Length of each occurrence. */
-  int cont_beg;        /* Starting column for continuation lines. */
-  int cont_end;        /* Ending column for continuation lines. */
+  int cont_beg;         /* Starting column for continuation lines. */
+  int cont_end;         /* Ending column for continuation lines. */
 
   int occurs_left;     /* Number of occurrences remaining. */
 
 
   int occurs_left;     /* Number of occurrences remaining. */
 
@@ -1901,11 +1939,12 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
   dfm_push (t->handle);
   
   /* Read the current record. */
   dfm_push (t->handle);
   
   /* Read the current record. */
-  dfm_bkwd_record (t->handle, 1);
-  line = dfm_get_record (t->handle, &len);
-  if (line == NULL)
+  dfm_reread_record (t->handle, 1);
+  dfm_expand_tabs (t->handle);
+  if (dfm_eof (t->handle))
     return -2;
     return -2;
-  dfm_fwd_record (t->handle);
+  dfm_get_record (t->handle, &line);
+  dfm_forward_record (t->handle);
 
   /* Calculate occurs, length. */
   occurs_left = occurs = realize_value (&t->occurs, c);
 
   /* Calculate occurs, length. */
   occurs_left = occurs = realize_value (&t->occurs, c);
@@ -1959,8 +1998,8 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
     {
       struct rpd_parse_info info;
       info.trns = t;
     {
       struct rpd_parse_info info;
       info.trns = t;
-      info.line = line;
-      info.len = len;
+      info.line = ls_c_str (&line);
+      info.len = ls_length (&line);
       info.beg = starts_beg;
       info.end = starts_end;
       info.ofs = length;
       info.beg = starts_beg;
       info.end = starts_end;
       info.ofs = length;
@@ -1995,8 +2034,7 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
       assert (occurs_left >= 0);
 
       /* Read in another record. */
       assert (occurs_left >= 0);
 
       /* Read in another record. */
-      line = dfm_get_record (t->handle, &len);
-      if (line == NULL)
+      if (dfm_eof (t->handle))
         {
           tmsg (SE, RPD_ERR,
                 _("Unexpected end of file with %d repetitions "
         {
           tmsg (SE, RPD_ERR,
                 _("Unexpected end of file with %d repetitions "
@@ -2004,12 +2042,14 @@ repeating_data_trns_proc (struct trns_header *trns, struct ccase *c,
                 occurs_left, occurs);
           return -2;
         }
                 occurs_left, occurs);
           return -2;
         }
-      dfm_fwd_record (t->handle);
+      dfm_expand_tabs (t->handle);
+      dfm_get_record (t->handle, &line);
+      dfm_forward_record (t->handle);
 
       /* Parse this record. */
       info.trns = t;
 
       /* Parse this record. */
       info.trns = t;
-      info.line = line;
-      info.len = len;
+      info.line = ls_c_str (&line);
+      info.len = ls_length (&line);
       info.beg = cont_beg;
       info.end = cont_end;
       info.ofs = length;
       info.beg = cont_beg;
       info.end = cont_end;
       info.ofs = length;
index 834e96e03be7c1edbd8efcaac88f5ea060193294..ad0cbeae0437389a821b6db03efdf9b9f0f82121 100644 (file)
@@ -220,7 +220,7 @@ devind_option (struct outp_driver *this, const char *key, const struct string *v
       break;
     case 1:
       free (x->file.filename);
       break;
     case 1:
       free (x->file.filename);
-      x->file.filename = xstrdup (ds_value (val));
+      x->file.filename = xstrdup (ds_c_str (val));
       break;
     default:
       assert (0);
       break;
     default:
       assert (0);
@@ -320,7 +320,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
   if (t->nr == 1 && t->nc == 1)
     {
       fputs ("p:", x->file.file);
   if (t->nr == 1 && t->nc == 1)
     {
       fputs ("p:", x->file.file);
-      escape_string (x->file.file, ls_value (t->cc), ls_length (t->cc));
+      escape_string (x->file.file, ls_c_str (t->cc), ls_length (t->cc));
       putc ('\n', x->file.file);
       
       return;
       putc ('\n', x->file.file);
       
       return;
@@ -347,7 +347,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
   if (!ls_empty_p (&t->title))
     {
       putc ('T', x->file.file);
   if (!ls_empty_p (&t->title))
     {
       putc ('T', x->file.file);
-      escape_string (x->file.file, ls_value (&t->title),
+      escape_string (x->file.file, ls_c_str (&t->title),
                     ls_length (&t->title));
       putc ('\n', x->file.file);
     }
                     ls_length (&t->title));
       putc ('\n', x->file.file);
     }
@@ -376,7 +376,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
             cc = t->cc + c + r * t->nc;
            if (*ct & TAB_JOIN) 
               {
             cc = t->cc + c + r * t->nc;
            if (*ct & TAB_JOIN) 
               {
-                j = (struct tab_joined_cell *) ls_value (cc);
+                j = (struct tab_joined_cell *) ls_c_str (cc);
                 cc = &j->contents;
                 if (c != j->x1 || r != j->y1)
                   continue;
                 cc = &j->contents;
                 if (c != j->x1 || r != j->y1)
                   continue;
@@ -399,7 +399,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
             else
               putc ('c', x->file.file);
             putc ('t', x->file.file);
             else
               putc ('c', x->file.file);
             putc ('t', x->file.file);
-            escape_string (x->file.file, ls_value (cc), ls_length (cc));
+            escape_string (x->file.file, ls_c_str (cc), ls_length (cc));
             putc ('\n', x->file.file);
           }
       }
             putc ('\n', x->file.file);
           }
       }
index 910bb32c160627cb421f2d53c2dfb16c12b48ec3..786c33e4b1f05727357b6b80c561a1c69cbc2f48 100644 (file)
--- a/src/dfm.c
+++ b/src/dfm.c
 
 #include "debug-print.h"
 
 
 #include "debug-print.h"
 
+/* Flags for DFM readers. */
+enum dfm_reader_flags
+  {
+    DFM_EOF = 001,              /* At end-of-file? */
+    DFM_ADVANCE = 002,          /* Read next line on dfm_get_record() call? */
+    DFM_SAW_BEGIN_DATA = 004,   /* For inline_file only, whether we've 
+                                   already read a BEGIN DATA line. */
+    DFM_TABS_EXPANDED = 010,    /* Tabs have been expanded. */
+  };
+
 /* file_handle extension structure. */
 /* file_handle extension structure. */
-struct dfm_fhuser_ext
+struct dfm_reader_ext
   {
     struct file_ext file;      /* Associated file. */
 
     struct file_locator where;  /* Current location in data file. */
   {
     struct file_ext file;      /* Associated file. */
 
     struct file_locator where;  /* Current location in data file. */
-    char *line;                        /* Current line, not null-terminated. */
-    size_t size;               /* Number of bytes allocated for line. */
-    size_t len;                        /* Length of line. */
-
-    char *ptr;                 /* Pointer into line that is returned by
-                                  dfm_get_record(). */
-    int advance;               /* Nonzero=dfm_get_record() reads a new
-                                  record; otherwise returns current record. */
-    int saw_begin_data;         /* For inline_file only, whether we've 
-                                   already read a BEGIN DATA line. */
+    struct string line;         /* Current line. */
+    size_t pos;                 /* Offset in line of current character. */
+    struct string scratch;      /* Extra line buffer. */
+    enum dfm_reader_flags flags; /* Zero or more of DFM_*. */
   };
 
   };
 
-/* These are defined at the end of this file. */
 static struct fh_ext_class dfm_r_class;
 static struct fh_ext_class dfm_r_class;
-static struct fh_ext_class dfm_w_class;
 
 static void read_record (struct file_handle *h);
 
 static void read_record (struct file_handle *h);
-\f
-/* Internal (low level). */
 
 
-/* Closes the file handle H which was opened by open_file_r() or
-   open_file_w(). */
+/* Asserts that H represents a DFM reader and returns H->ext
+   converted to a struct dfm_reader_ext *. */
+static inline struct dfm_reader_ext *
+get_reader (struct file_handle *h) 
+{
+  assert (h != NULL);
+  assert (h->class == &dfm_r_class);
+  assert (h->ext != NULL);
+
+  return h->ext;
+}
+
+/* Closes file handle H opened by dfm_open_for_reading(). */
 static void
 static void
-dfm_close (struct file_handle *h)
+close_reader (struct file_handle *h)
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_reader_ext *ext = get_reader (h);
 
   /* Skip any remaining data on the inline file. */
   if (h == inline_file)
 
   /* Skip any remaining data on the inline file. */
   if (h == inline_file)
-    while (ext->line != NULL)
+    while ((ext->flags & DFM_EOF) == 0)
       read_record (h);
       
   msg (VM (2), _("%s: Closing data-file handle %s."),
        handle_get_filename (h), handle_get_name (h));
       read_record (h);
       
   msg (VM (2), _("%s: Closing data-file handle %s."),
        handle_get_filename (h), handle_get_name (h));
-  assert (h->class == &dfm_r_class || h->class == &dfm_w_class);
+  assert (h->class == &dfm_r_class);
   if (ext->file.file)
     {
       fn_close_ext (&ext->file);
       free (ext->file.filename);
       ext->file.filename = NULL;
     }
   if (ext->file.file)
     {
       fn_close_ext (&ext->file);
       free (ext->file.filename);
       ext->file.filename = NULL;
     }
-  free (ext->line);
+  ds_destroy (&ext->line);
+  ds_destroy (&ext->scratch);
   free (ext);
 }
 
   free (ext);
 }
 
@@ -92,7 +104,7 @@ dfm_close (struct file_handle *h)
 int
 dfm_open_for_reading (struct file_handle *h)
 {
 int
 dfm_open_for_reading (struct file_handle *h)
 {
-  struct dfm_fhuser_ext *ext;
+  struct dfm_reader_ext *ext;
 
   if (h->class != NULL)
     {
 
   if (h->class != NULL)
     {
@@ -110,12 +122,9 @@ dfm_open_for_reading (struct file_handle *h)
   ext->where.filename = handle_get_filename (h);
   ext->where.line_number = 0;
   ext->file.file = NULL;
   ext->where.filename = handle_get_filename (h);
   ext->where.line_number = 0;
   ext->file.file = NULL;
-  ext->line = xmalloc (128);
-  ext->len = 0;
-  ext->ptr = NULL;
-  ext->size = 128;
-  ext->advance = 1;
-  ext->saw_begin_data = 0;
+  ds_init (&ext->line, 64);
+  ds_init (&ext->scratch, 0);
+  ext->flags = DFM_ADVANCE;
 
   msg (VM (1), _("%s: Opening data-file handle %s for reading."),
        handle_get_filename (h), handle_get_name (h));
 
   msg (VM (1), _("%s: Opening data-file handle %s for reading."),
        handle_get_filename (h), handle_get_name (h));
@@ -149,190 +158,6 @@ dfm_open_for_reading (struct file_handle *h)
   return 0;
 }
 
   return 0;
 }
 
-/* Opens a file handle for writing as a data file. */
-int
-dfm_open_for_writing (struct file_handle *h)
-{
-  struct dfm_fhuser_ext *ext;
-  
-  if (h->class != NULL)
-    {
-      if (h->class == &dfm_w_class)
-        return 1;
-      else
-        {
-          msg (ME, _("Cannot write to file %s already opened for %s."),
-               handle_get_name (h), gettext (h->class->name));
-          err_cond_fail ();
-          return 0;
-        }
-    }
-
-  ext = xmalloc (sizeof *ext);
-  ext->where.filename = handle_get_filename (h);
-  ext->where.line_number = 0;
-  ext->file.file = NULL;
-  ext->line = NULL;
-  ext->len = 0;
-  ext->ptr = NULL;
-  ext->size = 0;
-  ext->advance = 0;
-
-  msg (VM (1), _("%s: Opening data-file handle %s for writing."),
-       handle_get_filename (h), handle_get_name (h));
-  
-  assert (h != NULL);
-  if (h == inline_file)
-    {
-      msg (ME, _("Cannot open the inline file for writing."));
-      goto error;
-    }
-
-  ext->file.filename = xstrdup (handle_get_filename (h));
-  ext->file.mode = "wb";
-  ext->file.file = NULL;
-  ext->file.sequence_no = NULL;
-  ext->file.param = NULL;
-  ext->file.postopen = NULL;
-  ext->file.preclose = NULL;
-      
-  if (!fn_open_ext (&ext->file))
-    {
-      msg (ME, _("An error occurred while opening \"%s\" for writing "
-                 "as a data file: %s."),
-           handle_get_filename (h), strerror (errno));
-      goto error;
-    }
-
-  h->class = &dfm_w_class;
-  h->ext = ext;
-  return 1;
-
- error:
-  free (ext);
-  err_cond_fail ();
-  return 0;
-}
-
-/* Ensures that the line buffer in file handle with extension EXT is
-   big enough to hold a line of length EXT->LEN characters not
-   including null terminator. */
-#define force_line_buffer_expansion()                          \
-       do                                                      \
-         {                                                     \
-           if (ext->len + 1 > ext->size)                       \
-             {                                                 \
-               ext->size = ext->len * 2;                       \
-               ext->line = xrealloc (ext->line, ext->size);    \
-             }                                                 \
-         }                                                     \
-       while (0)
-
-/* Counts the number of tabs in string STRING of length LEN. */
-static inline int
-count_tabs (char *s, size_t len)
-{
-  int n_tabs = 0;
-  
-  for (;;)
-    {
-      char *cp = memchr (s, '\t', len);
-      if (cp == NULL)
-       return n_tabs;
-      n_tabs++;
-      len -= cp - s + 1;
-      s = cp + 1;
-    }
-}
-   
-/* Converts all the tabs in H->EXT->LINE to an equivalent number of
-   spaces, if necessary. */
-static void
-tabs_to_spaces (struct file_handle *h)
-{
-  struct dfm_fhuser_ext *ext = h->ext;
-  
-  char *first_tab;             /* Location of first tab (if any). */
-  char *second_tab;            /* Location of second tab (if any). */
-  size_t orig_len;     /* Line length at function entry. */
-
-  /* If there aren't any tabs then there's nothing to do. */
-  first_tab = memchr (ext->line, '\t', ext->len);
-  if (first_tab == NULL)
-    return;
-  orig_len = ext->len;
-  
-  /* If there's just one tab then expand it inline.  Otherwise do a
-     full string copy to another buffer. */
-  second_tab = memchr (first_tab + 1, '\t',
-                      ext->len - (first_tab - ext->line + 1));
-  if (second_tab == NULL)
-    {
-      int n_spaces = 8 - (first_tab - ext->line) % 8;
-
-      ext->len += n_spaces - 1;
-
-      /* Expand the line if necessary, keeping the first_tab pointer
-         valid. */
-      {
-       size_t ofs = first_tab - ext->line;
-       force_line_buffer_expansion ();
-       first_tab = ext->line + ofs;
-      }
-      
-      memmove (first_tab + n_spaces, first_tab + 1,
-              orig_len - (first_tab - ext->line + 1));
-      memset (first_tab, ' ', n_spaces);
-    } else {
-      /* Make a local copy of original text. */
-      char *orig_line = local_alloc (ext->len + 1);
-      memcpy (orig_line, ext->line, ext->len);
-             
-      /* Allocate memory assuming we need to add 8 spaces for every tab. */
-      ext->len += 2 + count_tabs (second_tab + 1,
-                                 ext->len - (second_tab - ext->line + 1));
-      
-      /* Expand the line if necessary, keeping the first_tab pointer
-         valid. */
-      {
-       size_t ofs = first_tab - ext->line;
-       force_line_buffer_expansion ();
-       first_tab = ext->line + ofs;
-      }
-
-      /* Walk through orig_line, expanding tabs into ext->line. */
-      {
-       char *src_p = orig_line + (first_tab - ext->line);
-       char *dest_p = first_tab;
-
-       for (; src_p < orig_line + orig_len; src_p++)
-         {
-           /* Most characters simply pass through untouched. */
-           if (*src_p != '\t')
-             {
-               *dest_p++ = *src_p;
-               continue;
-             }
-
-           /* Tabs are expanded into an equivalent number of
-               spaces. */
-           {
-             int n_spaces = 8 - (dest_p - ext->line) % 8;
-
-             memset (dest_p, ' ', n_spaces);
-             dest_p += n_spaces;
-           }
-         }
-
-       /* Supply null terminator and actual string length. */
-       *dest_p = 0;
-       ext->len = dest_p - ext->line;
-      }
-
-      local_free (orig_line);
-    }
-}
-
 /* Reads a record from H->EXT->FILE into H->EXT->LINE, setting
    H->EXT->PTR to H->EXT->LINE, and setting H->EXT-LEN to the length
    of the line.  The line is not null-terminated.  If an error occurs
 /* Reads a record from H->EXT->FILE into H->EXT->LINE, setting
    H->EXT->PTR to H->EXT->LINE, and setting H->EXT-LEN to the length
    of the line.  The line is not null-terminated.  If an error occurs
@@ -340,15 +165,15 @@ tabs_to_spaces (struct file_handle *h)
 static void
 read_record (struct file_handle *h)
 {
 static void
 read_record (struct file_handle *h)
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_reader_ext *ext = get_reader (h);
 
   if (h == inline_file)
     {
 
   if (h == inline_file)
     {
-      if (!ext->saw_begin_data)
+      if ((ext->flags & DFM_SAW_BEGIN_DATA) == 0)
         {
           char *s;
 
         {
           char *s;
 
-          ext->saw_begin_data = 1;
+          ext->flags |= DFM_SAW_BEGIN_DATA;
 
           /* FIXME: WTF can't this just be done with tokens?
              Is this really a special case? */
 
           /* FIXME: WTF can't this just be done with tokens?
              Is this really a special case? */
@@ -362,9 +187,10 @@ read_record (struct file_handle *h)
                   err_failure ();
                 }
 
                   err_failure ();
                 }
 
-              /* Skip leading whitespace, separate out first word, so that
-                 S points to a single word reduced to lowercase. */
-              s = ds_value (&getl_buf);
+              /* Skip leading whitespace, separate out first
+                 word, so that S points to a single word reduced
+                 to lowercase. */
+              s = ds_c_str (&getl_buf);
               while (isspace ((unsigned char) *s))
                 s++;
               for (cp = s; isalpha ((unsigned char) *cp); cp++)
               while (isspace ((unsigned char) *s))
                 s++;
               for (cp = s; isalpha ((unsigned char) *cp); cp++)
@@ -385,36 +211,31 @@ read_record (struct file_handle *h)
       if (!getl_read_line ())
        {
          msg (SE, _("Unexpected end-of-file while reading data in BEGIN "
       if (!getl_read_line ())
        {
          msg (SE, _("Unexpected end-of-file while reading data in BEGIN "
-              "DATA.  This probably indicates "
-              "a missing or misformatted END DATA command.  "
-              "END DATA must appear by itself on a single line "
-              "with exactly one space between words."));
+                     "DATA.  This probably indicates "
+                     "a missing or misformatted END DATA command.  "
+                     "END DATA must appear by itself on a single line "
+                     "with exactly one space between words."));
          err_failure ();
        }
 
       ext->where.line_number++;
 
       if (ds_length (&getl_buf) >= 8
          err_failure ();
        }
 
       ext->where.line_number++;
 
       if (ds_length (&getl_buf) >= 8
-         && !strncasecmp (ds_value (&getl_buf), "end data", 8))
+         && !strncasecmp (ds_c_str (&getl_buf), "end data", 8))
        {
        {
-         lex_set_prog (ds_value (&getl_buf) + ds_length (&getl_buf));
+         lex_set_prog (ds_c_str (&getl_buf) + ds_length (&getl_buf));
          goto eof;
        }
 
          goto eof;
        }
 
-      ext->len = ds_length (&getl_buf);
-      force_line_buffer_expansion ();
-      strcpy (ext->line, ds_value (&getl_buf));
+      ds_replace (&ext->line, ds_c_str (&getl_buf));
     }
   else
     {
       if (handle_get_mode (h) == MODE_TEXT)
        {
     }
   else
     {
       if (handle_get_mode (h) == MODE_TEXT)
        {
-         /* PORTME: here you should adapt the routine to your
-            system's concept of a "line" of text. */
-         int read_len = getline (&ext->line, &ext->size, ext->file.file);
-
-         if (read_len == -1)
-           {
+          ds_clear (&ext->line);
+          if (!ds_gets (&ext->line, ext->file.file)) 
+            {
              if (ferror (ext->file.file))
                {
                  msg (ME, _("Error reading file %s: %s."),
              if (ferror (ext->file.file))
                {
                  msg (ME, _("Error reading file %s: %s."),
@@ -423,19 +244,17 @@ read_record (struct file_handle *h)
                }
              goto eof;
            }
                }
              goto eof;
            }
-         ext->len = (size_t) read_len;
        }
       else if (handle_get_mode (h) == MODE_BINARY)
        {
           size_t record_width = handle_get_record_width (h);
          size_t amt;
 
        }
       else if (handle_get_mode (h) == MODE_BINARY)
        {
           size_t record_width = handle_get_record_width (h);
          size_t amt;
 
-         if (ext->size < record_width)
-           {
-             ext->size = record_width;
-             ext->line = xmalloc (ext->size);
-           }
-         amt = fread (ext->line, 1, record_width, ext->file.file);
+          if (ds_length (&ext->line) < record_width) 
+            ds_rpad (&ext->line, record_width, 0);
+          
+         amt = fread (ds_c_str (&ext->line), 1, record_width,
+                       ext->file.file);
          if (record_width != amt)
            {
              if (ferror (ext->file.file))
          if (record_width != amt)
            {
              if (ferror (ext->file.file))
@@ -457,117 +276,246 @@ read_record (struct file_handle *h)
       ext->where.line_number++;
     }
 
       ext->where.line_number++;
     }
 
-  /* Strip trailing whitespace, I forget why.  But there's a good
-     reason, I'm sure.  I'm too scared to eliminate this code.  */
-  if (handle_get_mode (h) == MODE_TEXT)
-    {
-      /*      while (ext->len && isspace ((unsigned char) ext->line[ext->len - 1]))
-             ext->len--;*/
-      
-      /* Convert tabs to spaces. */
-               
-        ext->ptr = ext->line;
-      }
+  ext->pos = 0;
   return;
 
 eof:
   /* Hit eof or an error, clean up everything. */
   return;
 
 eof:
   /* Hit eof or an error, clean up everything. */
-  if (ext->line)
-    free (ext->line);
-  ext->size = 0;
-  ext->line = ext->ptr = NULL;
-  return;
+  ext->flags |= DFM_EOF;
 }
 }
-\f
-/* Public (high level). */
-
-/* Returns the current record in the file corresponding to HANDLE.
-   Opens files and reads records, etc., as necessary.  Sets *LEN to
-   the length of the line.  The line returned is not null-terminated.
-   Returns NULL at end of file.  Calls fail() on attempt to read past
-   end of file.  */
-char *
-dfm_get_record (struct file_handle *h, int *len)
-{
-  struct dfm_fhuser_ext *ext;
-  
-  assert (h != NULL);
-  assert (h->class == &dfm_r_class);
-  assert (h->ext != NULL);
 
 
-  ext = h->ext;
-  if (ext->advance)
+/* Returns nonzero if end of file has been reached on HANDLE.
+   Reads forward in HANDLE's file, if necessary to tell. */
+int
+dfm_eof (struct file_handle *h) 
+{
+  struct dfm_reader_ext *ext = get_reader (h);
+  if (ext->flags & DFM_ADVANCE)
     {
     {
-      if (ext->line)
+      ext->flags &= ~DFM_ADVANCE;
+      if ((ext->flags & DFM_EOF) == 0)
         read_record (h);
       else
         {
           msg (SE, _("Attempt to read beyond end-of-file on file %s."),
                handle_get_name (h));
         read_record (h);
       else
         {
           msg (SE, _("Attempt to read beyond end-of-file on file %s."),
                handle_get_name (h));
-          goto lossage;
+          err_cond_fail ();
         }
     }
 
         }
     }
 
-  ext->advance = 0;
-  if (len)
-    *len = ext->len - (ext->ptr - ext->line);
-  return ext->ptr;
+  return (ext->flags & DFM_EOF) != 0;
+}
 
 
-lossage:
-  /* Come here on reading beyond eof or reading from a file already
-     open for something else. */
-  err_cond_fail ();
+/* Returns the current record in the file corresponding to
+   HANDLE.  Aborts if reading from the file is necessary or at
+   end of file, so call dfm_eof() first.  Sets *LINE to the line,
+   which is not null-terminated.  The caller must not free or
+   modify the returned string.  */
+void
+dfm_get_record (struct file_handle *h, struct len_string *line)
+{
+  struct dfm_reader_ext *ext = get_reader (h);
+  assert ((ext->flags & DFM_ADVANCE) == 0);
+  assert ((ext->flags & DFM_EOF) == 0);
+  assert (ext->pos <= ds_length (&ext->line));
+
+  line->string = ds_data (&ext->line) + ext->pos;
+  line->length = ds_length (&ext->line) - ext->pos;
+}
+
+/* Expands tabs in the current line into the equivalent number of
+   spaces, if appropriate for this kind of file.  Aborts if
+   reading from the file is necessary or at end of file, so call
+   dfm_eof() first.*/
+void
+dfm_expand_tabs (struct file_handle *h) 
+{
+  struct dfm_reader_ext *ext = get_reader (h);
+  struct string temp;
+  size_t ofs, new_pos, tab_width;
+
+  assert ((ext->flags & DFM_ADVANCE) == 0);
+  assert ((ext->flags & DFM_EOF) == 0);
+  assert (ext->pos <= ds_length (&ext->line));
+
+  if (ext->flags & DFM_TABS_EXPANDED)
+    return;
+  ext->flags |= DFM_TABS_EXPANDED;
+
+  if (handle_get_mode (h) == MODE_BINARY
+      || handle_get_tab_width (h) == 0
+      || memchr (ds_c_str (&ext->line), '\t', ds_length (&ext->line)) == NULL)
+    return;
+
+  /* Expand tabs from ext->line into ext->scratch, and figure out
+     new value for ext->pos. */
+  tab_width = handle_get_tab_width (h);
+  ds_clear (&ext->scratch);
+  new_pos = 0;
+  for (ofs = 0; ofs < ds_length (&ext->line); ofs++)
+    {
+      unsigned char c;
+      
+      if (ofs == ext->pos)
+        new_pos = ds_length (&ext->scratch);
+
+      c = ds_c_str (&ext->line)[ofs];
+      if (c != '\t')
+        ds_putc (&ext->scratch, c);
+      else 
+        {
+          do
+            ds_putc (&ext->scratch, ' ');
+          while (ds_length (&ext->scratch) % tab_width != 0);
+        }
+    }
 
 
-  return NULL;
+  /* Swap ext->line and ext->scratch and set new ext->pos. */
+  temp = ext->line;
+  ext->line = ext->scratch;
+  ext->scratch = temp;
+  ext->pos = new_pos;
 }
 
 /* Causes dfm_get_record() to read in the next record the next time it
    is executed on file HANDLE. */
 void
 }
 
 /* Causes dfm_get_record() to read in the next record the next time it
    is executed on file HANDLE. */
 void
-dfm_fwd_record (struct file_handle *h)
+dfm_forward_record (struct file_handle *h)
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_reader_ext *ext = get_reader (h);
+  ext->flags |= DFM_ADVANCE;
+}
 
 
-  assert (h->class == &dfm_r_class);
-  ext->advance = 1;
+/* Cancels the effect of any previous dfm_fwd_record() executed
+   on file HANDLE.  Sets the current line to begin in the 1-based
+   column COLUMN.  */
+void
+dfm_reread_record (struct file_handle *h, size_t column)
+{
+  struct dfm_reader_ext *ext = get_reader (h);
+  ext->flags &= ~DFM_ADVANCE;
+  if (column < 1)
+    ext->pos = 0;
+  else if (column > ds_length (&ext->line))
+    ext->pos = ds_length (&ext->line);
+  else
+    ext->pos = column - 1;
 }
 
 }
 
-/* Cancels the effect of any previous dfm_fwd_record() executed on
-   file HANDLE.  Sets the current line to begin in the 1-based column
-   COLUMN, as with dfm_set_record but based on a column number instead
-   of a character pointer. */
+/* Sets the current line to begin COLUMNS characters following
+   the current start. */
 void
 void
-dfm_bkwd_record (struct file_handle *h, int column)
+dfm_forward_columns (struct file_handle *h, size_t columns)
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_reader_ext *ext = get_reader (h);
+  dfm_reread_record (h, (ext->pos + 1) + columns);
+}
 
 
-  assert (h->class == &dfm_r_class);
-  ext->advance = 0;
-  ext->ptr = ext->line + min ((int) ext->len + 1, column) - 1;
+/* Returns the 1-based column to which the line pointer in HANDLE
+   is set.  Unless dfm_reread_record() or dfm_forward_columns()
+   have been called, this is 1. */
+size_t
+dfm_column_start (struct file_handle *h)
+{
+  struct dfm_reader_ext *ext = get_reader (h);
+  return ext->pos + 1;
 }
 
 }
 
-/* Sets the current line in HANDLE to NEW_LINE, which must point
-   somewhere in the line last returned by dfm_get_record().  Used by
-   DATA LIST FREE to strip the leading portion off the current line.  */
+/* Pushes the filename and line number on the fn/ln stack. */
 void
 void
-dfm_set_record (struct file_handle *h, char *new_line)
+dfm_push (struct file_handle *h)
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_reader_ext *ext = get_reader (h);
+  if (h != inline_file)
+    err_push_file_locator (&ext->where);
+}
 
 
-  assert (h->class == &dfm_r_class);
-  ext->ptr = new_line;
+/* Pops the filename and line number from the fn/ln stack. */
+void
+dfm_pop (struct file_handle *h)
+{
+  struct dfm_reader_ext *ext = get_reader (h);
+  if (h != inline_file)
+    err_pop_file_locator (&ext->where);
 }
 
 }
 
-/* Returns the 0-based current column to which the line pointer in
-   HANDLE is set.  Unless dfm_set_record() or dfm_bkwd_record() have
-   been called, this is 0. */
+/* DFM reader class. */
+static struct fh_ext_class dfm_r_class =
+{
+  1,
+  N_("reading as a data file"),
+  close_reader,
+};
+\f
+/* file_handle extension structure. */
+struct dfm_writer_ext
+  {
+    struct file_ext file;      /* Associated file. */
+    struct file_locator where;  /* Current location in data file. */
+    char *bounce;               /* Bounce buffer for fixed-size fields. */
+  };
+
+static struct fh_ext_class dfm_w_class;
+
+/* Opens a file handle for writing as a data file. */
 int
 int
-dfm_get_cur_col (struct file_handle *h)
+dfm_open_for_writing (struct file_handle *h)
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_writer_ext *ext;
+  
+  if (h->class != NULL)
+    {
+      if (h->class == &dfm_w_class)
+        return 1;
+      else
+        {
+          msg (ME, _("Cannot write to file %s already opened for %s."),
+               handle_get_name (h), gettext (h->class->name));
+          err_cond_fail ();
+          return 0;
+        }
+    }
 
 
-  assert (h->class == &dfm_r_class);
-  return ext->ptr - ext->line;
+  ext = xmalloc (sizeof *ext);
+  ext->where.filename = handle_get_filename (h);
+  ext->where.line_number = 0;
+  ext->file.file = NULL;
+  ext->bounce = NULL;
+
+  msg (VM (1), _("%s: Opening data-file handle %s for writing."),
+       handle_get_filename (h), handle_get_name (h));
+  
+  assert (h != NULL);
+  if (h == inline_file)
+    {
+      msg (ME, _("Cannot open the inline file for writing."));
+      goto error;
+    }
+
+  ext->file.filename = xstrdup (handle_get_filename (h));
+  ext->file.mode = "wb";
+  ext->file.file = NULL;
+  ext->file.sequence_no = NULL;
+  ext->file.param = NULL;
+  ext->file.postopen = NULL;
+  ext->file.preclose = NULL;
+      
+  if (!fn_open_ext (&ext->file))
+    {
+      msg (ME, _("An error occurred while opening \"%s\" for writing "
+                 "as a data file: %s."),
+           handle_get_filename (h), strerror (errno));
+      goto error;
+    }
+
+  h->class = &dfm_w_class;
+  h->ext = ext;
+  return 1;
+
+ error:
+  free (ext);
+  err_cond_fail ();
+  return 0;
 }
 
 /* Writes record REC having length LEN to the file corresponding to
 }
 
 /* Writes record REC having length LEN to the file corresponding to
@@ -576,9 +524,7 @@ dfm_get_cur_col (struct file_handle *h)
 int
 dfm_put_record (struct file_handle *h, const char *rec, size_t len)
 {
 int
 dfm_put_record (struct file_handle *h, const char *rec, size_t len)
 {
-  struct dfm_fhuser_ext *ext;
-  char *ptr;
-  size_t amt;
+  struct dfm_writer_ext *ext;
 
   assert (h != NULL);
   assert (h->class == &dfm_w_class);
 
   assert (h != NULL);
   assert (h->class == &dfm_w_class);
@@ -587,18 +533,16 @@ dfm_put_record (struct file_handle *h, const char *rec, size_t len)
   ext = h->ext;
   if (handle_get_mode (h) == MODE_BINARY && len < handle_get_record_width (h))
     {
   ext = h->ext;
   if (handle_get_mode (h) == MODE_BINARY && len < handle_get_record_width (h))
     {
-      amt = handle_get_record_width (h);
-      ptr = local_alloc (amt);
-      memcpy (ptr, rec, len);
-      memset (&ptr[len], 0, amt - len);
-    }
-  else
-    {
-      ptr = (char *) rec;
-      amt = len;
+      size_t rec_width = handle_get_record_width (h);
+      if (ext->bounce == NULL)
+        ext->bounce = xmalloc (rec_width);
+      memcpy (ext->bounce, rec, len);
+      memset (&ext->bounce[len], 0, rec_width - len);
+      rec = ext->bounce;
+      len = rec_width;
     }
 
     }
 
-  if (1 != fwrite (ptr, amt, 1, ext->file.file))
+  if (fwrite (rec, len, 1, ext->file.file) != 1)
     {
       msg (ME, _("Error writing file %s: %s."),
            handle_get_name (h), strerror (errno));
     {
       msg (ME, _("Error writing file %s: %s."),
            handle_get_name (h), strerror (errno));
@@ -606,35 +550,37 @@ dfm_put_record (struct file_handle *h, const char *rec, size_t len)
       return 0;
     }
 
       return 0;
     }
 
-  if (ptr != rec)
-    local_free (ptr);
-
   return 1;
 }
 
   return 1;
 }
 
-/* Pushes the filename and line number on the fn/ln stack. */
-void
-dfm_push (struct file_handle *h)
+/* Closes file handle H opened by dfm_open_for_writing(). */
+static void
+close_writer (struct file_handle *h)
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
+  struct dfm_writer_ext *ext;
 
 
-  assert (h->class == &dfm_r_class || h->class == &dfm_w_class);
-  assert (ext != NULL);
-  if (h != inline_file)
-    err_push_file_locator (&ext->where);
+  assert (h->class == &dfm_w_class);
+  ext = h->ext;
+
+  msg (VM (2), _("%s: Closing data-file handle %s."),
+       handle_get_filename (h), handle_get_name (h));
+  if (ext->file.file)
+    {
+      fn_close_ext (&ext->file);
+      free (ext->file.filename);
+      ext->file.filename = NULL;
+    }
+  free (ext->bounce);
+  free (ext);
 }
 
 }
 
-/* Pops the filename and line number from the fn/ln stack. */
-void
-dfm_pop (struct file_handle *h)
+/* DFM writer class. */
+static struct fh_ext_class dfm_w_class =
 {
 {
-  struct dfm_fhuser_ext *ext = h->ext;
-
-  assert (h->class == &dfm_r_class || h->class == &dfm_w_class);
-  assert (ext != NULL);
-  if (h != inline_file)
-    err_pop_file_locator (&ext->where);
-}
+  2,
+  N_("writing as a data file"),
+  close_writer,
+};
 \f
 /* BEGIN DATA...END DATA procedure. */
 
 \f
 /* BEGIN DATA...END DATA procedure. */
 
@@ -642,7 +588,7 @@ dfm_pop (struct file_handle *h)
 int
 cmd_begin_data (void)
 {
 int
 cmd_begin_data (void)
 {
-  struct dfm_fhuser_ext *ext;
+  struct dfm_reader_ext *ext;
 
   /* FIXME: figure out the *exact* conditions, not these really
      lenient conditions. */
 
   /* FIXME: figure out the *exact* conditions, not these really
      lenient conditions. */
@@ -651,7 +597,7 @@ cmd_begin_data (void)
       || case_source_is_class (vfm_source, &sort_source_class))
     {
       msg (SE, _("This command is not valid here since the current "
       || case_source_is_class (vfm_source, &sort_source_class))
     {
       msg (SE, _("This command is not valid here since the current "
-          "input program does not access the inline file."));
+                 "input program does not access the inline file."));
       err_cond_fail ();
       return CMD_FAILURE;
     }
       err_cond_fail ();
       return CMD_FAILURE;
     }
@@ -660,7 +606,7 @@ cmd_begin_data (void)
   msg (VM (1), _("inline file: Opening for reading."));
   dfm_open_for_reading (inline_file);
   ext = inline_file->ext;
   msg (VM (1), _("inline file: Opening for reading."));
   dfm_open_for_reading (inline_file);
   ext = inline_file->ext;
-  ext->saw_begin_data = 1;
+  ext->flags |= DFM_SAW_BEGIN_DATA;
 
   /* We don't actually read from the inline file.  The input procedure
      is what reads from it. */
 
   /* We don't actually read from the inline file.  The input procedure
      is what reads from it. */
@@ -668,27 +614,13 @@ cmd_begin_data (void)
   procedure (NULL, NULL);
   
   ext = inline_file->ext;
   procedure (NULL, NULL);
   
   ext = inline_file->ext;
-  if (ext && ext->line)
+  if (ext && (ext->flags & DFM_EOF) == 0)
     {
       msg (MW, _("Skipping remaining inline data."));
     {
       msg (MW, _("Skipping remaining inline data."));
-      for (read_record (inline_file); ext->line; read_record (inline_file))
-       ;
+      while ((ext->flags & DFM_EOF) == 0)
+        read_record (inline_file);
     }
   assert (inline_file->ext == NULL);
 
   return CMD_SUCCESS;
 }
     }
   assert (inline_file->ext == NULL);
 
   return CMD_SUCCESS;
 }
-
-static struct fh_ext_class dfm_r_class =
-{
-  1,
-  N_("reading as a data file"),
-  dfm_close,
-};
-
-static struct fh_ext_class dfm_w_class =
-{
-  2,
-  N_("writing as a data file"),
-  dfm_close,
-};
index 30f12846a808b7869ff134afcb4a25bed2549ed6..df2307c816195f9df022d1e2338ce30fa3ffb726 100644 (file)
--- a/src/dfm.h
+++ b/src/dfm.h
 
 #include <stddef.h>
 
 
 #include <stddef.h>
 
-/* I/O utilities. */
 struct file_handle;
 struct file_handle;
-int dfm_open_for_reading (struct file_handle *handle);
-int dfm_open_for_writing (struct file_handle *handle);
-char *dfm_get_record (struct file_handle *handle, int *len);
-int dfm_put_record (struct file_handle *handle, const char *rec, size_t len);
-
-/* Motion control. */
-void dfm_fwd_record (struct file_handle *handle);
-void dfm_bkwd_record (struct file_handle *handle, int column);
-
-/* Weirdness. */
-void dfm_set_record (struct file_handle *handle, char *new_line);
-int dfm_get_cur_col (struct file_handle *handle);
-void dfm_push (struct file_handle *handle);
-void dfm_pop (struct file_handle *handle);
+struct len_string;
+
+/* Input. */
+int dfm_open_for_reading (struct file_handle *);
+int dfm_eof (struct file_handle *);
+void dfm_get_record (struct file_handle *, struct len_string *);
+void dfm_expand_tabs (struct file_handle *);
+
+void dfm_forward_record (struct file_handle *);
+void dfm_reread_record (struct file_handle *, size_t column);
+void dfm_forward_columns (struct file_handle *, size_t columns);
+size_t dfm_column_start (struct file_handle *);
+
+/* Output. */
+int dfm_open_for_writing (struct file_handle *);
+int dfm_put_record (struct file_handle *, const char *rec, size_t len);
+
+/* File stack. */
+void dfm_push (struct file_handle *);
+void dfm_pop (struct file_handle *);
 
 #endif /* dfm_h */
 
 #endif /* dfm_h */
index 7a7e997d9c397717cafc8f3110cf9665d59cb548..2e012b4bedea3768ad51a1be265789d654e219df 100644 (file)
@@ -81,7 +81,7 @@ msg (int class, const char *format, ...)
 {
   struct string buf;
   
 {
   struct string buf;
   
-  ds_init (NULL, &buf, 1024);
+  ds_init (&buf, 1024);
 
   /* Format the message into BUF. */
   {
 
   /* Format the message into BUF. */
   {
@@ -283,13 +283,13 @@ err_vmsg (const struct error *e)
   assert (class >= 0 && class < ERR_CLASS_COUNT);
   assert (e->text != NULL);
   
   assert (class >= 0 && class < ERR_CLASS_COUNT);
   assert (e->text != NULL);
   
-  ds_init (NULL, &msg, 64);
+  ds_init (&msg, 64);
   if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
     {
       ds_printf (&msg, "%s:", e->where.filename);
       if (e->where.line_number != -1)
        ds_printf (&msg, "%d:", e->where.line_number);
   if (e->where.filename && (error_classes[class].flags & ERR_WITH_FILE))
     {
       ds_printf (&msg, "%s:", e->where.filename);
       if (e->where.line_number != -1)
        ds_printf (&msg, "%d:", e->where.line_number);
-      ds_putchar (&msg, ' ');
+      ds_putc (&msg, ' ');
     }
 
   ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
     }
 
   ds_printf (&msg, "%s: ", gettext (error_classes[class].banner));
@@ -304,9 +304,9 @@ err_vmsg (const struct error *e)
     ds_printf (&msg, "%s: ", cur_proc);
 
   if (e->title)
     ds_printf (&msg, "%s: ", cur_proc);
 
   if (e->title)
-    ds_concat (&msg, e->title);
+    ds_puts (&msg, e->title);
 
 
-  ds_concat (&msg, e->text);
+  ds_puts (&msg, e->text);
 
   /* FIXME: Check set_messages and set_errors to determine where to
      send errors and messages.
 
   /* FIXME: Check set_messages and set_errors to determine where to
      send errors and messages.
@@ -314,7 +314,7 @@ err_vmsg (const struct error *e)
      Please note that this is not trivial.  We have to avoid an
      infinite loop in reporting errors that originate in the output
      section. */
      Please note that this is not trivial.  We have to avoid an
      infinite loop in reporting errors that originate in the output
      section. */
-  dump_message (ds_value (&msg), 8, puts_stdout, get_viewwidth());
+  dump_message (ds_c_str (&msg), 8, puts_stdout, get_viewwidth());
 
   ds_destroy (&msg);
 
 
   ds_destroy (&msg);
 
index a6a4a7d680c8bb4d2f870e2057306b8dd0e70c40..05395bc461902aaca79929cd8116aebaa425c7e4 100644 (file)
@@ -615,7 +615,7 @@ parse_primary (union any_node **n)
 
     case T_STRING:
       {
 
     case T_STRING:
       {
-        *n = allocate_str_con (ds_value (&tokstr), ds_length (&tokstr));
+        *n = allocate_str_con (ds_c_str (&tokstr), ds_length (&tokstr));
        lex_get ();
        return EXPR_STRING;
       }
        lex_get ();
        return EXPR_STRING;
       }
@@ -1223,7 +1223,7 @@ parse_function (union any_node ** n)
     }
 
   ds_truncate (&tokstr, 31);
     }
 
   ds_truncate (&tokstr, 31);
-  strcpy (fname, ds_value (&tokstr));
+  strcpy (fname, ds_c_str (&tokstr));
   cp = strrchr (fname, '.');
   if (cp && isdigit ((unsigned char) cp[1]))
     {
   cp = strrchr (fname, '.');
   if (cp && isdigit ((unsigned char) cp[1]))
     {
index 145d520228cb644f3308014299b3040a8e24f15d..5f18202a48069eff675c36c0c17d604333ccc5f0 100644 (file)
@@ -72,5 +72,6 @@ const char *handle_get_name (const struct file_handle *handle);
 const char *handle_get_filename (const struct file_handle *handle);
 enum file_handle_mode handle_get_mode (const struct file_handle *);
 size_t handle_get_record_width (const struct file_handle *);
 const char *handle_get_filename (const struct file_handle *handle);
 enum file_handle_mode handle_get_mode (const struct file_handle *);
 size_t handle_get_record_width (const struct file_handle *);
+size_t handle_get_tab_width (const struct file_handle *);
 
 #endif /* !file_handle.h */
 
 #endif /* !file_handle.h */
index 1133fd31286367695eecf4c815d7eeabf96de2f8..96aa9486cd894e18b2c1f5dfb33a3b478458191f 100644 (file)
@@ -41,6 +41,7 @@ struct private_file_handle
     struct file_locator where; /* Used for reporting error messages. */
     enum file_handle_mode mode;        /* File mode. */
     size_t length;             /* Length of fixed-format records. */
     struct file_locator where; /* Used for reporting error messages. */
     enum file_handle_mode mode;        /* File mode. */
     size_t length;             /* Length of fixed-format records. */
+    size_t tab_width;           /* Tab width, 0=do not expand tabs. */
   };
 
 /* Linked list of file handles. */
   };
 
 /* Linked list of file handles. */
@@ -59,9 +60,9 @@ static struct file_handle *create_file_handle (const char *handle_name,
 /* (specification)
    "FILE HANDLE" (fh_):
      name=string;
 /* (specification)
    "FILE HANDLE" (fh_):
      name=string;
-     recform=recform:fixed/!variable/spanned;
      lrecl=integer;
      lrecl=integer;
-     mode=mode:!character/image/binary/multipunch/_360.
+     tabwidth=integer "x>=0" "%s must be nonnegative";
+     mode=mode:!character/image.
 */
 /* (declarations) */
 /* (functions) */
 */
 /* (declarations) */
 /* (functions) */
@@ -153,6 +154,10 @@ cmd_file_handle (void)
     {
     case FH_CHARACTER:
       handle->private->mode = MODE_TEXT;
     {
     case FH_CHARACTER:
       handle->private->mode = MODE_TEXT;
+      if (cmd.sbc_tabwidth)
+        handle->private->tab_width = cmd.n_tabwidth;
+      else
+        handle->private->tab_width = 4;
       break;
     case FH_IMAGE:
       handle->private->mode = MODE_BINARY;
       break;
     case FH_IMAGE:
       handle->private->mode = MODE_BINARY;
@@ -204,6 +209,7 @@ create_file_handle (const char *handle_name, const char *filename)
   handle->private->where.line_number = 0;
   handle->private->mode = MODE_TEXT;
   handle->private->length = 1024;
   handle->private->where.line_number = 0;
   handle->private->mode = MODE_TEXT;
   handle->private->length = 1024;
+  handle->private->tab_width = 4;
   handle->ext = NULL;
   handle->class = NULL;
 
   handle->ext = NULL;
   handle->class = NULL;
 
@@ -262,10 +268,10 @@ fh_parse_file_handle (void)
   if (token == T_ID) 
     handle = get_handle_with_name (tokid);
   if (handle == NULL)
   if (token == T_ID) 
     handle = get_handle_with_name (tokid);
   if (handle == NULL)
-    handle = get_handle_for_filename (ds_value (&tokstr));
+    handle = get_handle_for_filename (ds_c_str (&tokstr));
   if (handle == NULL) 
     {
   if (handle == NULL) 
     {
-      char *filename = ds_value (&tokstr);
+      char *filename = ds_c_str (&tokstr);
       char *handle_name = xmalloc (strlen (filename) + 3);
       sprintf (handle_name, "\"%s\"", filename);
       handle = create_file_handle (handle_name, filename);
       char *handle_name = xmalloc (strlen (filename) + 3);
       sprintf (handle_name, "\"%s\"", filename);
       handle = create_file_handle (handle_name, filename);
@@ -304,7 +310,8 @@ handle_get_mode (const struct file_handle *handle)
   return handle->private->mode;
 }
 
   return handle->private->mode;
 }
 
-/* Returns the width of a logical record on HANDLE. */
+/* Returns the width of a logical record on HANDLE.  Applicable
+   only to MODE_BINARY files.  */
 size_t
 handle_get_record_width (const struct file_handle *handle)
 {
 size_t
 handle_get_record_width (const struct file_handle *handle)
 {
@@ -312,6 +319,16 @@ handle_get_record_width (const struct file_handle *handle)
   return handle->private->length;
 }
 
   return handle->private->length;
 }
 
+/* Returns the number of characters per tab stop for HANDLE, or
+   zero if tabs are not to be expanded.  Applicable only to
+   MODE_TEXT files. */
+size_t
+handle_get_tab_width (const struct file_handle *handle) 
+{
+  assert (handle != NULL);
+  return handle->private->tab_width;
+}
+
 /*
    Local variables:
    mode: c
 /*
    Local variables:
    mode: c
index bc33599da97db2d33a0171c00f438aaba1f57799..2b11a4abd21ce4deb551a893ad6d2e1a6c7efb41 100644 (file)
@@ -444,7 +444,7 @@ cmd_record_type (void)
              if (!lex_force_string ())
                goto error;
              rct->v[rct->nv].c = xmalloc (fty->record.nc + 1);
              if (!lex_force_string ())
                goto error;
              rct->v[rct->nv].c = xmalloc (fty->record.nc + 1);
-             st_bare_pad_copy (rct->v[rct->nv].c, ds_value (&tokstr),
+             st_bare_pad_copy (rct->v[rct->nv].c, ds_c_str (&tokstr),
                                fty->record.nc + 1);
            }
          else
                                fty->record.nc + 1);
            }
          else
@@ -623,9 +623,6 @@ file_type_source_read (struct case_source *source,
                        write_case_data wc_data UNUSED)
 {
   struct file_type_pgm *fty = source->aux;
                        write_case_data wc_data UNUSED)
 {
   struct file_type_pgm *fty = source->aux;
-  char *line;
-  int len;
-
   struct fmt_spec format;
 
   dfm_push (fty->handle);
   struct fmt_spec format;
 
   dfm_push (fty->handle);
@@ -633,19 +630,22 @@ file_type_source_read (struct case_source *source,
   format.type = fty->record.fmt;
   format.w = fty->record.nc;
   format.d = 0;
   format.type = fty->record.fmt;
   format.w = fty->record.nc;
   format.d = 0;
-  while (NULL != (line = dfm_get_record (fty->handle, &len)))
+  while (!dfm_eof (fty->handle))
     {
     {
+      struct len_string line;
       struct record_type *iter;
       union value v;
       int i;
 
       struct record_type *iter;
       union value v;
       int i;
 
+      dfm_expand_tabs (fty->handle);
+      dfm_get_record (fty->handle, &line);
       if (formats[fty->record.fmt].cat & FCAT_STRING)
        {
          struct data_in di;
          
          v.c = c->data[fty->record.v->fv].s;
 
       if (formats[fty->record.fmt].cat & FCAT_STRING)
        {
          struct data_in di;
          
          v.c = c->data[fty->record.v->fv].s;
 
-         data_in_finite_line (&di, line, len,
+         data_in_finite_line (&di, ls_c_str (&line), ls_length (&line),
                               fty->record.fc, fty->record.fc + fty->record.nc);
          di.v = (union value *) v.c;
          di.flags = 0;
                               fty->record.fc, fty->record.fc + fty->record.nc);
          di.v = (union value *) v.c;
          di.flags = 0;
@@ -668,7 +668,7 @@ file_type_source_read (struct case_source *source,
        {
          struct data_in di;
 
        {
          struct data_in di;
 
-         data_in_finite_line (&di, line, len,
+         data_in_finite_line (&di, ls_c_str (&line), ls_length (&line),
                               fty->record.fc, fty->record.fc + fty->record.nc);
          di.v = &v;
          di.flags = 0;
                               fty->record.fc, fty->record.fc + fty->record.nc);
          di.v = &v;
          di.flags = 0;
@@ -688,13 +688,13 @@ file_type_source_read (struct case_source *source,
          if (fty->wild)
            msg (SW, _("Unknown record type %g."), v.f);
        }
          if (fty->wild)
            msg (SW, _("Unknown record type %g."), v.f);
        }
-      dfm_fwd_record (fty->handle);
+      dfm_forward_record (fty->handle);
       continue;
 
     found:
       /* Arrive here if there is a matching record_type, which is in
          iter. */
       continue;
 
     found:
       /* Arrive here if there is a matching record_type, which is in
          iter. */
-      dfm_fwd_record (fty->handle);
+      dfm_forward_record (fty->handle);
     }
 
 /*  switch(fty->type)
     }
 
 /*  switch(fty->type)
index aa92a323c83946e9686c84f46595dc70b4c67bb9..a07b7d18f9033a9de8ae3f263e1c1b8bd55827f2 100644 (file)
@@ -75,20 +75,20 @@ fn_interp_vars (const char *input, const char *(*getenv) (const char *))
   if (NULL == strchr (input, '$'))
     return xstrdup (input);
 
   if (NULL == strchr (input, '$'))
     return xstrdup (input);
 
-  ds_init (NULL, &output, strlen (input));
+  ds_init (&output, strlen (input));
 
   for (;;)
     switch (*input)
       {
       case '\0':
 
   for (;;)
     switch (*input)
       {
       case '\0':
-       return ds_value (&output);
+       return ds_c_str (&output);
        
       case '$':
        input++;
 
        if (*input == '$')
          {
        
       case '$':
        input++;
 
        if (*input == '$')
          {
-           ds_putchar (&output, '$');
+           ds_putc (&output, '$');
            input++;
          }
        else
            input++;
          }
        else
@@ -114,18 +114,18 @@ fn_interp_vars (const char *input, const char *(*getenv) (const char *))
 
            while (*input && *input != stop
                   && (stop || isalpha ((unsigned char) *input)))
 
            while (*input && *input != stop
                   && (stop || isalpha ((unsigned char) *input)))
-             ds_putchar (&output, *input++);
+             ds_putc (&output, *input++);
            
            
-           value = getenv (ds_value (&output) + start);
+           value = getenv (ds_c_str (&output) + start);
            ds_truncate (&output, start);
            ds_truncate (&output, start);
-           ds_concat (&output, value);
+           ds_puts (&output, value);
 
            if (stop && *input == stop)
              input++;
          }
 
       default:
 
            if (stop && *input == stop)
              input++;
          }
 
       default:
-       ds_putchar (&output, *input++);
+       ds_putc (&output, *input++);
       }
 }
 
       }
 }
 
@@ -140,13 +140,13 @@ fn_tilde_expand (const char *input)
 
   if (NULL == strchr (input, '~'))
     return xstrdup (input);
 
   if (NULL == strchr (input, '~'))
     return xstrdup (input);
-  ds_init (NULL, &output, strlen (input));
+  ds_init (&output, strlen (input));
 
   ip = input;
 
   for (ip = input; *ip; )
     if (*ip != '~' || (ip != input && ip[-1] != PATH_DELIMITER))
 
   ip = input;
 
   for (ip = input; *ip; )
     if (*ip != '~' || (ip != input && ip[-1] != PATH_DELIMITER))
-      ds_putchar (&output, *ip++);
+      ds_putc (&output, *ip++);
     else
       {
        static const char stop_set[3] = {DIR_SEPARATOR, PATH_DELIMITER, 0};
     else
       {
        static const char stop_set[3] = {DIR_SEPARATOR, PATH_DELIMITER, 0};
@@ -166,23 +166,23 @@ fn_tilde_expand (const char *input)
            pwd = getpwnam (username);
 
            if (!pwd || !pwd->pw_dir)
            pwd = getpwnam (username);
 
            if (!pwd || !pwd->pw_dir)
-             ds_putchar (&output, *ip++);
+             ds_putc (&output, *ip++);
            else
            else
-             ds_concat (&output, pwd->pw_dir);
+             ds_puts (&output, pwd->pw_dir);
          }
        else
          {
            const char *home = fn_getenv ("HOME");
            if (!home)
          }
        else
          {
            const char *home = fn_getenv ("HOME");
            if (!home)
-             ds_putchar (&output, *ip++);
+             ds_putc (&output, *ip++);
            else
            else
-             ds_concat (&output, home);
+             ds_puts (&output, home);
          }
 
        ip = cp;
       }
 
          }
 
        ip = cp;
       }
 
-  return ds_value (&output);
+  return ds_c_str (&output);
 }
 #else /* !unix */
 char *
 }
 #else /* !unix */
 char *
@@ -219,7 +219,7 @@ fn_search_path (const char *basename, const char *path, const char *prepend)
   }
 
   msg (VM (4), _("Searching for `%s'..."), basename);
   }
 
   msg (VM (4), _("Searching for `%s'..."), basename);
-  ds_init (NULL, &filename, 64);
+  ds_init (&filename, 64);
 
   for (;;)
     {
 
   for (;;)
     {
@@ -239,21 +239,21 @@ fn_search_path (const char *basename, const char *path, const char *prepend)
       ds_clear (&filename);
       if (prepend && !fn_absolute_p (bp))
        {
       ds_clear (&filename);
       if (prepend && !fn_absolute_p (bp))
        {
-         ds_concat (&filename, prepend);
-         ds_putchar (&filename, DIR_SEPARATOR);
+         ds_puts (&filename, prepend);
+         ds_putc (&filename, DIR_SEPARATOR);
        }
        }
-      ds_concat_buffer (&filename, bp, ep - bp);
+      ds_concat (&filename, bp, ep - bp);
       if (ep - bp
       if (ep - bp
-         && ds_value (&filename)[ds_length (&filename) - 1] != DIR_SEPARATOR)
-       ds_putchar (&filename, DIR_SEPARATOR);
-      ds_concat (&filename, basename);
+         && ds_c_str (&filename)[ds_length (&filename) - 1] != DIR_SEPARATOR)
+       ds_putc (&filename, DIR_SEPARATOR);
+      ds_puts (&filename, basename);
       
       
-      msg (VM (5), " - %s", ds_value (&filename));
-      if (fn_exists_p (ds_value (&filename)))
+      msg (VM (5), " - %s", ds_c_str (&filename));
+      if (fn_exists_p (ds_c_str (&filename)))
        {
        {
-         msg (VM (4), _("Found `%s'."), ds_value (&filename));
+         msg (VM (4), _("Found `%s'."), ds_c_str (&filename));
          free (subst_path);
          free (subst_path);
-         return ds_value (&filename);
+         return ds_c_str (&filename);
        }
 
       if (0 == *ep)
        }
 
       if (0 == *ep)
index 44fbff4638d2338921a9b6463b273aa32bc8c592..744cd6feccaf3644fb118cc9cdfb0c51c4f6a3f3 100644 (file)
@@ -49,7 +49,7 @@ parse_format_specifier_name (const char **cp, int allow_xt)
   char *sp, *ep;
   int idx;
 
   char *sp, *ep;
   int idx;
 
-  sp = ep = ds_value (&tokstr);
+  sp = ep = ds_c_str (&tokstr);
   while (isalpha ((unsigned char) *ep))
     ep++;
 
   while (isalpha ((unsigned char) *ep))
     ep++;
 
@@ -74,7 +74,7 @@ parse_format_specifier_name (const char **cp, int allow_xt)
         {
           /* No match. */
           msg (SE, _("%.*s is not a valid data format."),
         {
           /* No match. */
           msg (SE, _("%.*s is not a valid data format."),
-               (int) (ep - sp), ds_value (&tokstr));
+               (int) (ep - sp), ds_c_str (&tokstr));
           idx = -1; 
         }
     }
           idx = -1; 
         }
     }
@@ -338,7 +338,7 @@ parse_format_specifier (struct fmt_spec *input, int allow_xt)
   if (cp2 == cp && type != FMT_X)
     {
       msg (SE, _("Data format %s does not specify a width."),
   if (cp2 == cp && type != FMT_X)
     {
       msg (SE, _("Data format %s does not specify a width."),
-          ds_value (&tokstr));
+          ds_c_str (&tokstr));
       return 0;
     }
 
       return 0;
     }
 
@@ -354,7 +354,7 @@ parse_format_specifier (struct fmt_spec *input, int allow_xt)
 
   if (*cp)
     {
 
   if (*cp)
     {
-      msg (SE, _("Data format %s is not valid."), ds_value (&tokstr));
+      msg (SE, _("Data format %s is not valid."), ds_c_str (&tokstr));
       return 0;
     }
   lex_get ();
       return 0;
     }
   lex_get ();
index f55cd9f9b438b38d8f6ee9a1771b13b62ea8f6bb..a5b0148e1dedb4203d7b736079c057a2387b85f1 100644 (file)
@@ -72,9 +72,9 @@ static int read_console (void);
 void
 getl_initialize (void)
 {
 void
 getl_initialize (void)
 {
-  ds_create (NULL, &getl_include_path,
+  ds_create (&getl_include_path,
             fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
             fn_getenv_default ("STAT_INCLUDE_PATH", include_path));
-  ds_init (NULL, &getl_buf, 256);
+  ds_init (&getl_buf, 256);
 }
 
 /* Close getline. */
 }
 
 /* Close getline. */
@@ -109,9 +109,9 @@ void
 getl_add_include_dir (const char *path)
 {
   if (ds_length (&getl_include_path))
 getl_add_include_dir (const char *path)
 {
   if (ds_length (&getl_include_path))
-    ds_putchar (&getl_include_path, PATH_DELIMITER);
+    ds_putc (&getl_include_path, PATH_DELIMITER);
 
 
-  ds_concat (&getl_include_path, path);
+  ds_puts (&getl_include_path, path);
 }
 
 /* Adds FN to the tail end of the list of script files to execute.
 }
 
 /* Adds FN to the tail end of the list of script files to execute.
@@ -154,7 +154,7 @@ getl_include (const char *fn)
 
   {
     char *cur_dir = getl_get_current_directory ();
 
   {
     char *cur_dir = getl_get_current_directory ();
-    real_fn = fn_search_path (fn, ds_value (&getl_include_path), cur_dir);
+    real_fn = fn_search_path (fn, ds_c_str (&getl_include_path), cur_dir);
     free (cur_dir);
   }
 
     free (cur_dir);
   }
 
@@ -273,7 +273,7 @@ handle_line_buffer (void)
     }
   while (s->cur_line == NULL);
 
     }
   while (s->cur_line == NULL);
 
-  ds_concat_buffer (&getl_buf, s->cur_line->line, s->cur_line->len);
+  ds_concat (&getl_buf, s->cur_line->line, s->cur_line->len);
 
   /* Advance pointers. */
   s->cur_line = s->cur_line->next;
 
   /* Advance pointers. */
   s->cur_line = s->cur_line->next;
@@ -309,7 +309,7 @@ getl_read_line (void)
          perform_DO_REPEAT_substitutions ();
          if (getl_head->print)
            tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
          perform_DO_REPEAT_substitutions ();
          if (getl_head->print)
            tab_output_text (TAB_LEFT | TAT_FIX | TAT_PRINTF, "+%s",
-                            ds_value (&getl_buf));
+                            ds_c_str (&getl_buf));
          return 1;
        }
       
          return 1;
        }
       
@@ -326,7 +326,7 @@ getl_read_line (void)
            }
        }
 
            }
        }
 
-      if (!ds_getline (&getl_buf, s->f))
+      if (!ds_gets (&getl_buf, s->f))
        {
          if (ferror (s->f))
            msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
        {
          if (ferror (s->f))
            msg (ME, _("Reading `%s': %s."), s->fn, strerror (errno));
@@ -337,13 +337,13 @@ getl_read_line (void)
        ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
 
       if (get_echo())
        ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
 
       if (get_echo())
-       tab_output_text (TAB_LEFT | TAT_FIX, ds_value (&getl_buf));
+       tab_output_text (TAB_LEFT | TAT_FIX, ds_c_str (&getl_buf));
 
       getl_head->ln++;
 
       /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
 
       getl_head->ln++;
 
       /* Allows shebang invocation: `#! /usr/local/bin/pspp'. */
-      if (ds_value (&getl_buf)[0] == '#'
-         && ds_value (&getl_buf)[1] == '!')
+      if (ds_c_str (&getl_buf)[0] == '#'
+         && ds_c_str (&getl_buf)[1] == '!')
        continue;
 
       return 1;
        continue;
 
       return 1;
@@ -464,7 +464,7 @@ read_console (void)
 #endif
 
   ds_clear (&getl_buf);
 #endif
 
   ds_clear (&getl_buf);
-  ds_concat (&getl_buf, line);
+  ds_puts (&getl_buf, line);
 
   return 1;
 }
 
   return 1;
 }
@@ -477,7 +477,7 @@ read_console (void)
 
   fputs (getl_prompt ? get_cprompt() : get_prompt(), stdout);
   ds_clear (&getl_buf);
 
   fputs (getl_prompt ? get_cprompt() : get_prompt(), stdout);
   ds_clear (&getl_buf);
-  if (ds_getline (&getl_buf, stdin))
+  if (ds_gets (&getl_buf, stdin))
     return 1;
 
   if (ferror (stdin))
     return 1;
 
   if (ferror (stdin))
index e1d5bba0b303214cac0a2e224c5c505e9b605569..83dd2b66ef49ac75ed1b8592469022dfe3958c37 100644 (file)
@@ -151,7 +151,7 @@ init_glob (int argc UNUSED, char **argv)
   last_vfm_invocation = time (NULL);
 
   /* lexer.h */
   last_vfm_invocation = time (NULL);
 
   /* lexer.h */
-  ds_init (NULL, &tokstr, 64);
+  ds_init (&tokstr, 64);
 
   /* common.h */
   {
 
   /* common.h */
   {
index f0b4f5fdfb0f5698de0030bd30371b7e2715cfba..ea11459d132d642449c348227a9d623a65829760 100644 (file)
@@ -156,7 +156,7 @@ html_option (struct outp_driver *this, const char *key, const struct string *val
       break;
     case 1:
       free (x->file.filename);
       break;
     case 1:
       free (x->file.filename);
-      x->file.filename = xstrdup (ds_value (val));
+      x->file.filename = xstrdup (ds_c_str (val));
       break;
     case string_arg:
       {
       break;
     case string_arg:
       {
@@ -172,7 +172,7 @@ html_option (struct outp_driver *this, const char *key, const struct string *val
          }
        if (*dest)
          free (*dest);
          }
        if (*dest)
          free (*dest);
-       *dest = xstrdup (ds_value (val));
+       *dest = xstrdup (ds_c_str (val));
       }
       break;
     default:
       }
       break;
     default:
@@ -454,7 +454,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
     {
       fputs ("<P>", x->file.file);
       if (!ls_empty_p (t->cc))
     {
       fputs ("<P>", x->file.file);
       if (!ls_empty_p (t->cc))
-       escape_string (x->file.file, ls_value (t->cc), ls_length (t->cc));
+       escape_string (x->file.file, ls_c_str (t->cc), ls_length (t->cc));
       fputs ("</P>\n", x->file.file);
       
       return;
       fputs ("</P>\n", x->file.file);
       
       return;
@@ -465,7 +465,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
   if (!ls_empty_p (&t->title))
     {
       fprintf (x->file.file, "  <TR>\n    <TH COLSPAN=%d>", t->nc);
   if (!ls_empty_p (&t->title))
     {
       fprintf (x->file.file, "  <TR>\n    <TH COLSPAN=%d>", t->nc);
-      escape_string (x->file.file, ls_value (&t->title),
+      escape_string (x->file.file, ls_c_str (&t->title),
                     ls_length (&t->title));
       fputs ("</TH>\n  </TR>\n", x->file.file);
     }
                     ls_length (&t->title));
       fputs ("</TH>\n  </TR>\n", x->file.file);
     }
@@ -490,7 +490,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
             cc = t->cc + c + r * t->nc;
            if (*ct & TAB_JOIN) 
               {
             cc = t->cc + c + r * t->nc;
            if (*ct & TAB_JOIN) 
               {
-                j = (struct tab_joined_cell *) ls_value (cc);
+                j = (struct tab_joined_cell *) ls_c_str (cc);
                 cc = &j->contents;
                 if (j->x1 != c || j->y1 != r)
                   continue; 
                 cc = &j->contents;
                 if (j->x1 != c || j->y1 != r)
                   continue; 
@@ -533,7 +533,7 @@ output_tab_table (struct outp_driver *this, struct tab_table *t)
            
            if ( ! (*ct & TAB_EMPTY)  ) 
              {
            
            if ( ! (*ct & TAB_EMPTY)  ) 
              {
-               char *s = ls_value (cc);
+               char *s = ls_c_str (cc);
                size_t l = ls_length (cc);
 
                while (l && isspace ((unsigned char) *s))
                size_t l = ls_length (cc);
 
                while (l && isspace ((unsigned char) *s))
index 19f5ca1b8f6f645219725e6993821d04fe788a53..3ea80ef04b352926d1dc7295da2824b592d04f70 100644 (file)
@@ -40,7 +40,7 @@ cmd_include (void)
       lex_error (_("expecting filename")); 
       return CMD_FAILURE;
     }
       lex_error (_("expecting filename")); 
       return CMD_FAILURE;
     }
-  getl_include (ds_value (&tokstr));
+  getl_include (ds_c_str (&tokstr));
 
   lex_get ();
   return lex_end_of_command ();
 
   lex_get ();
   return lex_end_of_command ();
index 69f5b0483db015877d4942ef5ec15196cbed4763..3d8ef88ab4ec313f9e5498a05e2cd629cad9ad25 100644 (file)
@@ -383,7 +383,7 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c,
   struct reread_trns *t = (struct reread_trns *) pt;
 
   if (t->column == NULL)
   struct reread_trns *t = (struct reread_trns *) pt;
 
   if (t->column == NULL)
-    dfm_bkwd_record (t->handle, 1);
+    dfm_reread_record (t->handle, 1);
   else
     {
       union value column;
   else
     {
       union value column;
@@ -393,10 +393,10 @@ reread_trns_proc (struct trns_header * pt, struct ccase * c,
        {
          msg (SE, _("REREAD: Column numbers must be positive finite "
               "numbers.  Column set to 1."));
        {
          msg (SE, _("REREAD: Column numbers must be positive finite "
               "numbers.  Column set to 1."));
-         dfm_bkwd_record (t->handle, 1);
+         dfm_reread_record (t->handle, 1);
        }
       else
        }
       else
-       dfm_bkwd_record (t->handle, column.f);
+       dfm_reread_record (t->handle, column.f);
     }
   return -1;
 }
     }
   return -1;
 }
index df48d4eca5499c5fbaf82cfd8b2ba6ea70a4c586..97e6510103447c96b5aca6ee8806967ae59aa7b6 100644 (file)
@@ -95,7 +95,7 @@ static void dump_token (void);
 void
 lex_init (void)
 {
 void
 lex_init (void)
 {
-  ds_init (NULL, &put_tokstr, 64);
+  ds_init (&put_tokstr, 64);
   if (!lex_get_line ())
     unexpected_eof ();
 }
   if (!lex_get_line ())
     unexpected_eof ();
 }
@@ -109,8 +109,8 @@ restore_token (void)
 {
   assert (put_token != 0);
   token = put_token;
 {
   assert (put_token != 0);
   token = put_token;
-  ds_replace (&tokstr, ds_value (&put_tokstr));
-  strncpy (tokid, ds_value (&put_tokstr), 8);
+  ds_replace (&tokstr, ds_c_str (&put_tokstr));
+  strncpy (tokid, ds_c_str (&put_tokstr), 8);
   tokid[8] = 0;
   tokval = put_tokval;
   put_token = 0;
   tokid[8] = 0;
   tokval = put_tokval;
   put_token = 0;
@@ -122,7 +122,7 @@ static void
 save_token (void) 
 {
   put_token = token;
 save_token (void) 
 {
   put_token = token;
-  ds_replace (&put_tokstr, ds_value (&tokstr));
+  ds_replace (&put_tokstr, ds_c_str (&tokstr));
   put_tokval = tokval;
 }
 
   put_tokval = tokval;
 }
 
@@ -208,7 +208,7 @@ lex_get (void)
               negative numbers into two tokens. */
            if (*cp == '-')
              {
               negative numbers into two tokens. */
            if (*cp == '-')
              {
-               ds_putchar (&tokstr, *prog++);
+               ds_putc (&tokstr, *prog++);
                while (isspace ((unsigned char) *prog))
                  prog++;
 
                while (isspace ((unsigned char) *prog))
                  prog++;
 
@@ -221,32 +221,32 @@ lex_get (void)
 
            /* Parse the number, copying it into tokstr. */
            while (isdigit ((unsigned char) *prog))
 
            /* Parse the number, copying it into tokstr. */
            while (isdigit ((unsigned char) *prog))
-             ds_putchar (&tokstr, *prog++);
+             ds_putc (&tokstr, *prog++);
            if (*prog == '.')
              {
            if (*prog == '.')
              {
-               ds_putchar (&tokstr, *prog++);
+               ds_putc (&tokstr, *prog++);
                while (isdigit ((unsigned char) *prog))
                while (isdigit ((unsigned char) *prog))
-                 ds_putchar (&tokstr, *prog++);
+                 ds_putc (&tokstr, *prog++);
              }
            if (*prog == 'e' || *prog == 'E')
              {
              }
            if (*prog == 'e' || *prog == 'E')
              {
-               ds_putchar (&tokstr, *prog++);
+               ds_putc (&tokstr, *prog++);
                if (*prog == '+' || *prog == '-')
                if (*prog == '+' || *prog == '-')
-                 ds_putchar (&tokstr, *prog++);
+                 ds_putc (&tokstr, *prog++);
                while (isdigit ((unsigned char) *prog))
                while (isdigit ((unsigned char) *prog))
-                 ds_putchar (&tokstr, *prog++);
+                 ds_putc (&tokstr, *prog++);
              }
 
            /* Parse as floating point. */
              }
 
            /* Parse as floating point. */
-           tokval = strtod (ds_value (&tokstr), &tail);
+           tokval = strtod (ds_c_str (&tokstr), &tail);
            if (*tail)
              {
                msg (SE, _("%s does not form a valid number."),
            if (*tail)
              {
                msg (SE, _("%s does not form a valid number."),
-                    ds_value (&tokstr));
+                    ds_c_str (&tokstr));
                tokval = 0.0;
 
                ds_clear (&tokstr);
                tokval = 0.0;
 
                ds_clear (&tokstr);
-               ds_putchar (&tokstr, '0');
+               ds_putc (&tokstr, '0');
              }
 
            token = T_NUM;
              }
 
            token = T_NUM;
@@ -346,15 +346,15 @@ lex_get (void)
            }
 
          /* Copy id to tokstr. */
            }
 
          /* Copy id to tokstr. */
-         ds_putchar (&tokstr, toupper ((unsigned char) *prog++));
+         ds_putc (&tokstr, toupper ((unsigned char) *prog++));
          while (CHAR_IS_IDN (*prog))
          while (CHAR_IS_IDN (*prog))
-           ds_putchar (&tokstr, toupper ((unsigned char) *prog++));
+           ds_putc (&tokstr, toupper ((unsigned char) *prog++));
 
          /* Copy tokstr to tokid, truncating it to 8 characters. */
 
          /* Copy tokstr to tokid, truncating it to 8 characters. */
-         strncpy (tokid, ds_value (&tokstr), 8);
+         strncpy (tokid, ds_c_str (&tokstr), 8);
          tokid[8] = 0;
 
          tokid[8] = 0;
 
-         token = check_id (ds_value (&tokstr), ds_length (&tokstr));
+         token = check_id (ds_c_str (&tokstr), ds_length (&tokstr));
          break;
 
        default:
          break;
 
        default:
@@ -690,7 +690,7 @@ lex_put_back_id (const char *id)
   save_token ();
   token = T_ID;
   ds_replace (&tokstr, id);
   save_token ();
   token = T_ID;
   ds_replace (&tokstr, id);
-  strncpy (tokid, ds_value (&tokstr), 8);
+  strncpy (tokid, ds_c_str (&tokstr), 8);
   tokid[8] = 0;
 }
 \f
   tokid[8] = 0;
 }
 \f
@@ -700,7 +700,7 @@ lex_put_back_id (const char *id)
 const char *
 lex_entire_line (void)
 {
 const char *
 lex_entire_line (void)
 {
-  return ds_value (&getl_buf);
+  return ds_c_str (&getl_buf);
 }
 
 /* As lex_entire_line(), but only returns the part of the current line
 }
 
 /* As lex_entire_line(), but only returns the part of the current line
@@ -764,7 +764,7 @@ lex_preprocess_line (void)
     /* Remove C-style comments begun by slash-star and terminated by
      star-slash or newline. */
     quote = comment = 0;
     /* Remove C-style comments begun by slash-star and terminated by
      star-slash or newline. */
     quote = comment = 0;
-    for (cp = ds_value (&getl_buf); *cp; )
+    for (cp = ds_c_str (&getl_buf); *cp; )
       {
        /* If we're not commented out, toggle quoting. */
        if (!comment)
       {
        /* If we're not commented out, toggle quoting. */
        if (!comment)
@@ -805,7 +805,7 @@ lex_preprocess_line (void)
   /* Strip trailing whitespace and terminal dot. */
   {
     size_t len = ds_length (&getl_buf);
   /* Strip trailing whitespace and terminal dot. */
   {
     size_t len = ds_length (&getl_buf);
-    char *s = ds_value (&getl_buf);
+    char *s = ds_c_str (&getl_buf);
     
     /* Strip trailing whitespace. */
     while (len > 0 && isspace ((unsigned char) s[len - 1]))
     
     /* Strip trailing whitespace. */
     while (len > 0 && isspace ((unsigned char) s[len - 1]))
@@ -830,7 +830,7 @@ lex_preprocess_line (void)
      as necessary. */
   if (getl_interactive != 2 && getl_mode == GETL_MODE_BATCH)
     {
      as necessary. */
   if (getl_interactive != 2 && getl_mode == GETL_MODE_BATCH)
     {
-      char *s = ds_value (&getl_buf);
+      char *s = ds_c_str (&getl_buf);
       
       if (s[0] == '+' || s[0] == '-' || s[0] == '.')
        s[0] = ' ';
       
       if (s[0] == '+' || s[0] == '-' || s[0] == '.')
        s[0] = ' ';
@@ -838,7 +838,7 @@ lex_preprocess_line (void)
        put_token = '.';
     }
 
        put_token = '.';
     }
 
-  prog = ds_value (&getl_buf);
+  prog = ds_c_str (&getl_buf);
 }
 \f
 /* Token names. */
 }
 \f
 /* Token names. */
@@ -871,7 +871,7 @@ lex_token_representation (void)
     {
     case T_ID:
     case T_NUM:
     {
     case T_ID:
     case T_NUM:
-      return xstrdup (ds_value (&tokstr));
+      return xstrdup (ds_c_str (&tokstr));
       break;
 
     case T_STRING:
       break;
 
     case T_STRING:
@@ -879,7 +879,7 @@ lex_token_representation (void)
        int hexstring = 0;
        char *sp, *dp;
 
        int hexstring = 0;
        char *sp, *dp;
 
-       for (sp = ds_value (&tokstr); sp < ds_end (&tokstr); sp++)
+       for (sp = ds_c_str (&tokstr); sp < ds_end (&tokstr); sp++)
          if (!isprint ((unsigned char) *sp))
            {
              hexstring = 1;
          if (!isprint ((unsigned char) *sp))
            {
              hexstring = 1;
@@ -894,14 +894,14 @@ lex_token_representation (void)
        *dp++ = '\'';
 
        if (!hexstring)
        *dp++ = '\'';
 
        if (!hexstring)
-         for (sp = ds_value (&tokstr); *sp; )
+         for (sp = ds_c_str (&tokstr); *sp; )
            {
              if (*sp == '\'')
                *dp++ = '\'';
              *dp++ = (unsigned char) *sp++;
            }
        else
            {
              if (*sp == '\'')
                *dp++ = '\'';
              *dp++ = (unsigned char) *sp++;
            }
        else
-         for (sp = ds_value (&tokstr); sp < ds_end (&tokstr); sp++)
+         for (sp = ds_c_str (&tokstr); sp < ds_end (&tokstr); sp++)
            {
              *dp++ = (((unsigned char) *sp) >> 4)["0123456789ABCDEF"];
              *dp++ = (((unsigned char) *sp) & 15)["0123456789ABCDEF"];
            {
              *dp++ = (((unsigned char) *sp) >> 4)["0123456789ABCDEF"];
              *dp++ = (((unsigned char) *sp) & 15)["0123456789ABCDEF"];
@@ -949,7 +949,7 @@ lex_negative_to_dash (void)
     {
       token = T_NUM;
       tokval = -tokval;
     {
       token = T_NUM;
       tokval = -tokval;
-      ds_replace (&tokstr, ds_value (&tokstr) + 1);
+      ds_replace (&tokstr, ds_c_str (&tokstr) + 1);
       save_token ();
       token = '-';
     }
       save_token ();
       token = '-';
     }
@@ -1034,7 +1034,7 @@ convert_numeric_string_to_char_string (int type)
               "multiple of %d."),
         gettext (base_name), ds_length (&tokstr), cpb);
 
               "multiple of %d."),
         gettext (base_name), ds_length (&tokstr), cpb);
 
-  p = ds_value (&tokstr);
+  p = ds_c_str (&tokstr);
   for (i = 0; i < nb; i++)
     {
       int value;
   for (i = 0; i < nb; i++)
     {
       int value;
@@ -1064,7 +1064,7 @@ convert_numeric_string_to_char_string (int type)
          value = value * base + v;
        }
 
          value = value * base + v;
        }
 
-      ds_value (&tokstr)[i] = (unsigned char) value;
+      ds_c_str (&tokstr)[i] = (unsigned char) value;
     }
 
   ds_truncate (&tokstr, nb);
     }
 
   ds_truncate (&tokstr, nb);
@@ -1103,7 +1103,7 @@ parse_string (int type)
                break;
            }
 
                break;
            }
 
-         ds_putchar (&tokstr, *prog++);
+         ds_putc (&tokstr, *prog++);
        }
       prog++;
 
        }
       prog++;
 
@@ -1173,7 +1173,7 @@ finish:
     int warned = 0;
 
     for (i = 0; i < ds_length (&tokstr); i++)
     int warned = 0;
 
     for (i = 0; i < ds_length (&tokstr); i++)
-      if (ds_value (&tokstr)[i] == 0)
+      if (ds_c_str (&tokstr)[i] == 0)
        {
          if (!warned)
            {
        {
          if (!warned)
            {
@@ -1181,7 +1181,7 @@ finish:
                         "characters.  Replacing with spaces."));
              warned = 1;
            }
                         "characters.  Replacing with spaces."));
              warned = 1;
            }
-         ds_value (&tokstr)[i] = ' ';
+         ds_c_str (&tokstr)[i] = ' ';
        }
   }
 
        }
   }
 
@@ -1214,7 +1214,7 @@ dump_token (void)
       break;
 
     case T_STRING:
       break;
 
     case T_STRING:
-      fprintf (stderr, "STRING\t\"%s\"\n", ds_value (&tokstr));
+      fprintf (stderr, "STRING\t\"%s\"\n", ds_c_str (&tokstr));
       break;
 
     case T_STOP:
       break;
 
     case T_STOP:
index 6f3d58ade7a6d1c06988c848cb9263b890ccb1bd..4d7c5d733cebb110e0703b5b5ac84af638a3b395 100644 (file)
@@ -831,22 +831,34 @@ static const char *
 context (struct file_handle *data_file)
 {
   static char buf[32];
 context (struct file_handle *data_file)
 {
   static char buf[32];
-  int len;
-  char *p = dfm_get_record (data_file, &len);
-  
-  if (!p || !len)
-    strcpy (buf, "at end of line");
-  else
+
+  if (dfm_eof (data_file))
+    strcpy (buf, "at end of file");
+  else 
     {
     {
-      char *cp = buf;
-      int n_copy = min (10, len);
-      cp = stpcpy (buf, "before `");
-      while (n_copy && isspace ((unsigned char) *p))
-       p++, n_copy++;
-      while (n_copy && !isspace ((unsigned char) *p))
-       *cp++ = *p++, n_copy--;
-      *cp++ = '\'';
-      *cp = 0;
+      struct len_string line;
+      const char *sp;
+      
+      dfm_get_record (data_file, &line);
+      sp = ls_c_str (&line);
+      while (sp < ls_end (&line) && isspace ((unsigned char) *sp))
+        sp++;
+      if (sp >= ls_end (&line))
+        strcpy (buf, "at end of line");
+      else
+        {
+          char *dp;
+          size_t copy_cnt = 0;
+
+          dp = stpcpy (buf, "before `");
+          while (sp < ls_end (&line) && !isspace ((unsigned char) *sp)
+                 && copy_cnt < 10) 
+            {
+              *dp++ = *sp++;
+              copy_cnt++; 
+            }
+          strcpy (dp, "'");
+        }
     }
   
   return buf;
     }
   
   return buf;
@@ -856,68 +868,55 @@ context (struct file_handle *data_file)
 static int
 another_token (struct file_handle *data_file)
 {
 static int
 another_token (struct file_handle *data_file)
 {
-  char *cp, *ep;
-  int len;
-
   for (;;)
     {
   for (;;)
     {
-      cp = dfm_get_record (data_file, &len);
-      if (!cp)
-       return 0;
+      struct len_string line;
+      const char *cp;
+      
+      if (dfm_eof (data_file))
+        return 0;
+      dfm_get_record (data_file, &line);
 
 
-      ep = cp + len;
-      while (isspace ((unsigned char) *cp) && cp < ep)
+      cp = ls_c_str (&line);
+      while (isspace ((unsigned char) *cp) && cp < ls_end (&line))
        cp++;
 
        cp++;
 
-      if (cp < ep)
-       break;
+      if (cp < ls_end (&line)) 
+        {
+          dfm_forward_columns (data_file, cp - ls_c_str (&line));
+          return 1;
+        }
 
 
-      dfm_fwd_record (data_file);
+      dfm_forward_record (data_file);
     }
     }
-  
-  dfm_set_record (data_file, cp);
-
-  return 1;
 }
 
 /* Parse a MATRIX DATA token from mx->data_file into TOKEN. */
 static int
 (mget_token) (struct matrix_token *token, struct file_handle *data_file)
 {
 }
 
 /* Parse a MATRIX DATA token from mx->data_file into TOKEN. */
 static int
 (mget_token) (struct matrix_token *token, struct file_handle *data_file)
 {
-  char *cp, *ep;
-  int len;
+  struct len_string line;
   int first_column;
   int first_column;
-    
-  for (;;)
-    {
-      cp = dfm_get_record (data_file, &len);
-      if (!cp)
-        return 0;
+  char *cp;
 
 
-      ep = cp + len;
-      while (isspace ((unsigned char) *cp) && cp < ep)
-       cp++;
+  if (!another_token (data_file))
+    return 0;
 
 
-      if (cp < ep)
-       break;
-
-      dfm_fwd_record (data_file);
-    }
-  
-  dfm_set_record (data_file, cp);
-  first_column = dfm_get_cur_col (data_file) + 1;
+  dfm_get_record (data_file, &line);
+  first_column = dfm_column_start (data_file);
 
   /* Three types of fields: quoted with ', quoted with ", unquoted. */
 
   /* Three types of fields: quoted with ', quoted with ", unquoted. */
+  cp = ls_c_str (&line);
   if (*cp == '\'' || *cp == '"')
     {
       int quote = *cp;
 
       token->type = MSTR;
       token->string = ++cp;
   if (*cp == '\'' || *cp == '"')
     {
       int quote = *cp;
 
       token->type = MSTR;
       token->string = ++cp;
-      while (cp < ep && *cp != quote)
+      while (cp < ls_end (&line) && *cp != quote)
        cp++;
       token->length = cp - token->string;
        cp++;
       token->length = cp - token->string;
-      if (cp < ep)
+      if (cp < ls_end (&line))
        cp++;
       else
        msg (SW, _("Scope of string exceeds line."));
        cp++;
       else
        msg (SW, _("Scope of string exceeds line."));
@@ -927,7 +926,8 @@ static int
       int is_num = isdigit ((unsigned char) *cp) || *cp == '.';
 
       token->string = cp++;
       int is_num = isdigit ((unsigned char) *cp) || *cp == '.';
 
       token->string = cp++;
-      while (cp < ep && !isspace ((unsigned char) *cp) && *cp != ','
+      while (cp < ls_end (&line)
+             && !isspace ((unsigned char) *cp) && *cp != ','
             && *cp != '-' && *cp != '+')
        {
          if (isdigit ((unsigned char) *cp))
             && *cp != '-' && *cp != '+')
        {
          if (isdigit ((unsigned char) *cp))
@@ -963,7 +963,7 @@ static int
        token->type = MSTR;
     }
 
        token->type = MSTR;
     }
 
-  dfm_set_record (data_file, cp);
+  dfm_forward_columns (data_file, cp - ls_c_str (&line));
     
   return 1;
 }
     
   return 1;
 }
@@ -973,24 +973,25 @@ static int
 static int
 force_eol (struct file_handle *data_file, const char *content)
 {
 static int
 force_eol (struct file_handle *data_file, const char *content)
 {
-  char *cp;
-  int len;
-  
-  cp = dfm_get_record (data_file, &len);
-  if (!cp)
+  struct len_string line;
+  const char *cp;
+
+  if (dfm_eof (data_file))
     return 0;
     return 0;
-  while (len && isspace (*cp))
-    cp++, len--;
+  dfm_get_record (data_file, &line);
+
+  cp = ls_c_str (&line);
+  while (isspace ((unsigned char) *cp) && cp < ls_end (&line))
+    cp++;
   
   
-  if (len)
+  if (cp < ls_end (&line))
     {
       msg (SE, _("End of line expected %s while reading %s."),
           context (data_file), content);
       return 0;
     }
   
     {
       msg (SE, _("End of line expected %s while reading %s."),
           context (data_file), content);
       return 0;
     }
   
-  dfm_fwd_record (data_file);
-  
+  dfm_forward_record (data_file);
   return 1;
 }
 \f
   return 1;
 }
 \f
index 66ceb9ce0886c1d92103de8d860cabecaf4aace3..f388583a33483d73f35d4366ece8b3b44ffbc5e7 100644 (file)
@@ -315,7 +315,7 @@ parse_alpha (void)
          msg (SE, _("String is not of proper length."));
          return 0;
        }
          msg (SE, _("String is not of proper length."));
          return 0;
        }
-      strncpy (missing[miss_type].s, ds_value (&tokstr), MAX_SHORT_STRING);
+      strncpy (missing[miss_type].s, ds_c_str (&tokstr), MAX_SHORT_STRING);
       lex_get ();
       lex_match (',');
     }
       lex_get ();
       lex_match (',');
     }
index c0c4e0b022339f4e1f1a978b611dca96d00925ad..e33172e21d39c50e4bb54f309d02beb0a9faa2f2 100644 (file)
@@ -288,7 +288,7 @@ outp_read_devices (void)
   where.line_number = 0;
   err_push_file_locator (&where);
 
   where.line_number = 0;
   err_push_file_locator (&where);
 
-  ds_init (NULL, &line, 128);
+  ds_init (&line, 128);
 
   if (init_fn == NULL)
     {
 
   if (init_fn == NULL)
     {
@@ -315,7 +315,7 @@ outp_read_devices (void)
            msg (ME, _("Reading %s: %s."), init_fn, strerror (errno));
          break;
        }
            msg (ME, _("Reading %s: %s."), init_fn, strerror (errno));
          break;
        }
-      for (cp = ds_value (&line); isspace ((unsigned char) *cp); cp++);
+      for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++);
       if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
        outp_configure_macro (&cp[7]);
       else if (*cp)
       if (!strncmp ("define", cp, 6) && isspace ((unsigned char) cp[6]))
        outp_configure_macro (&cp[7]);
       else if (*cp)
@@ -511,7 +511,7 @@ tokener (void)
          while (*prog && *prog != quote)
            {
              if (*prog != '\\')
          while (*prog && *prog != quote)
            {
              if (*prog != '\\')
-               ds_putchar (&op_tokstr, *prog++);
+               ds_putc (&op_tokstr, *prog++);
              else
                {
                  int c;
              else
                {
                  int c;
@@ -590,14 +590,14 @@ tokener (void)
                      msg (IS, _("Syntax error in string constant."));
                       continue;
                    }
                      msg (IS, _("Syntax error in string constant."));
                       continue;
                    }
-                 ds_putchar (&op_tokstr, (unsigned char) c);
+                 ds_putc (&op_tokstr, (unsigned char) c);
                }
            }
          prog++;
        }
       else
        while (*prog && !isspace ((unsigned char) *prog) && *prog != '=')
                }
            }
          prog++;
        }
       else
        while (*prog && !isspace ((unsigned char) *prog) && *prog != '=')
-         ds_putchar (&op_tokstr, *prog++);
+         ds_putc (&op_tokstr, *prog++);
       op_token = 'a';
     }
 
       op_token = 'a';
     }
 
@@ -612,7 +612,7 @@ parse_options (char *s, struct outp_driver * d)
   prog = s;
   op_token = -1;
 
   prog = s;
   op_token = -1;
 
-  ds_init (NULL, &op_tokstr, 64);
+  ds_init (&op_tokstr, 64);
   while (tokener ())
     {
       char key[65];
   while (tokener ())
     {
       char key[65];
@@ -624,7 +624,7 @@ parse_options (char *s, struct outp_driver * d)
        }
 
       ds_truncate (&op_tokstr, 64);
        }
 
       ds_truncate (&op_tokstr, 64);
-      strcpy (key, ds_value (&op_tokstr));
+      strcpy (key, ds_c_str (&op_tokstr));
 
       tokener ();
       if (op_token != '=')
 
       tokener ();
       if (op_token != '=')
@@ -1150,7 +1150,7 @@ outp_get_paper_size (char *size, int *h, int *v)
   where.filename = pprsz_fn;
   where.line_number = 0;
   err_push_file_locator (&where);
   where.filename = pprsz_fn;
   where.line_number = 0;
   err_push_file_locator (&where);
-  ds_init (NULL, &line, 128);
+  ds_init (&line, 128);
 
   if (pprsz_fn == NULL)
     {
 
   if (pprsz_fn == NULL)
     {
@@ -1176,7 +1176,7 @@ outp_get_paper_size (char *size, int *h, int *v)
            msg (ME, _("Reading %s: %s."), pprsz_fn, strerror (errno));
          break;
        }
            msg (ME, _("Reading %s: %s."), pprsz_fn, strerror (errno));
          break;
        }
-      for (cp = ds_value (&line); isspace ((unsigned char) *cp); cp++);
+      for (cp = ds_c_str (&line); isspace ((unsigned char) *cp); cp++);
       if (*cp == 0)
        continue;
       if (*cp != '"')
       if (*cp == 0)
        continue;
       if (*cp != '"')
index 8a4c9acb7d5bf44ad3097ac55051f5e8ef5854a4..4a2fab0b5848e82f45adec32feb7fb36c5dc8eea 100644 (file)
@@ -567,7 +567,7 @@ ps_option (struct outp_driver *this, const char *key, const struct string *val)
 {
   struct ps_driver_ext *x = this->ext;
   int cat, subcat;
 {
   struct ps_driver_ext *x = this->ext;
   int cat, subcat;
-  char *value = ds_value (val);
+  char *value = ds_c_str (val);
 
   cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
 
 
   cat = outp_match_keyword (key, option_tab, &option_info, &subcat);
 
@@ -898,8 +898,8 @@ output_encodings (struct outp_driver *this)
 
   struct string line, buf;
 
 
   struct string line, buf;
 
-  ds_init (NULL, &line, 128);
-  ds_init (NULL, &buf, 128);
+  ds_init (&line, 128);
+  ds_init (&buf, 128);
   for (pe = hsh_first (x->encodings, &iter); pe != NULL;
        pe = hsh_next (x->encodings, &iter)) 
     {
   for (pe = hsh_first (x->encodings, &iter); pe != NULL;
        pe = hsh_next (x->encodings, &iter)) 
     {
@@ -946,7 +946,7 @@ output_encodings (struct outp_driver *this)
              if (buf.length == 0) 
                continue;
 
              if (buf.length == 0) 
                continue;
 
-             pschar = strtok_r (ds_value (&buf), " \t\r\n", &sp);
+             pschar = strtok_r (ds_c_str (&buf), " \t\r\n", &sp);
              code = strtok_r (NULL, " \t\r\n", &sp);
              if (*pschar == 0 || *code == 0)
                continue;
              code = strtok_r (NULL, " \t\r\n", &sp);
              if (*pschar == 0 || *code == 0)
                continue;
@@ -984,14 +984,14 @@ output_encodings (struct outp_driver *this)
              
              if (ds_length (&line) + strlen (temp) > 70)
                {
              
              if (ds_length (&line) + strlen (temp) > 70)
                {
-                 ds_concat (&line, x->eol);
-                 fputs (ds_value (&line), x->file.file);
+                 ds_puts (&line, x->eol);
+                 fputs (ds_c_str (&line), x->file.file);
                  ds_clear (&line);
                }
                  ds_clear (&line);
                }
-             ds_concat (&line, temp);
+             ds_puts (&line, temp);
            }
            }
-         ds_concat (&line, x->eol);
-         fputs (ds_value (&line), x->file.file);
+         ds_puts (&line, x->eol);
+         fputs (ds_c_str (&line), x->file.file);
 
          if (fclose (f) == EOF)
            msg (MW, _("PostScript driver: Error closing encoding file `%s'."),
 
          if (fclose (f) == EOF)
            msg (MW, _("PostScript driver: Error closing encoding file `%s'."),
@@ -1104,7 +1104,7 @@ read_ps_encodings (struct outp_driver *this)
   where.line_number = 0;
   err_push_file_locator (&where);
 
   where.line_number = 0;
   err_push_file_locator (&where);
 
-  ds_init (NULL, &line, 128);
+  ds_init (&line, 128);
     
   for (;;)
     {
     
   for (;;)
     {
@@ -2543,7 +2543,7 @@ text (struct outp_driver *this, struct outp_text *t, int draw)
   buf_loc = buf;
 
   assert (!ls_null_p (&t->s));
   buf_loc = buf;
 
   assert (!ls_null_p (&t->s));
-  cp = ls_value (&t->s);
+  cp = ls_c_str (&t->s);
   end = ls_end (&t->s);
   if (draw)
     {
   end = ls_end (&t->s);
   if (draw)
     {
index 273ab2914c817faaeb4465604575f8ff276de66f..b3098d673a1bc5b6ac8dacf2df493156fb47a312 100644 (file)
@@ -338,7 +338,7 @@ parse_string_argument (void)
 {
   fx.spec.type = PRT_CONST;
   fx.spec.fc = fx.sc - 1;
 {
   fx.spec.type = PRT_CONST;
   fx.spec.fc = fx.sc - 1;
-  fx.spec.u.c = xstrdup (ds_value (&tokstr));
+  fx.spec.u.c = xstrdup (ds_c_str (&tokstr));
   lex_get ();
 
   /* Parse the included column range. */
   lex_get ();
 
   /* Parse the included column range. */
index 707cf2728bc09028e627f3ba159858ad2546ecc7..1c0ddb79669d73e99760e5b40c0b8bd77457ed09 100644 (file)
--- a/src/q2c.c
+++ b/src/q2c.c
@@ -1570,7 +1570,7 @@ dump_subcommand (const subcommand *sbc)
          outdent ();
        }
       dump (0, "free(p->s_%s);", st_lower(sbc->name) );
          outdent ();
        }
       dump (0, "free(p->s_%s);", st_lower(sbc->name) );
-      dump (0, "p->s_%s = xstrdup (ds_value (&tokstr));",
+      dump (0, "p->s_%s = xstrdup (ds_c_str (&tokstr));",
            st_lower (sbc->name));
       dump (0, "lex_get ();");
       if (sbc->restriction)
            st_lower (sbc->name));
       dump (0, "lex_get ();");
       if (sbc->restriction)
index f2158f4f77147dfa3deae5270a49318ae3f59cdf..a4abc534933b700a9a6d9317134b215c6fe39f61 100644 (file)
@@ -388,14 +388,14 @@ cmd_recode (void)
          
        }
 
          
        }
 
+      free (v);
+      v = NULL;
+
       if (!lex_match ('/'))
        break;
       while (rcd->next)
        rcd = rcd->next;
       rcd = rcd->next = xmalloc (sizeof *rcd);
       if (!lex_match ('/'))
        break;
       while (rcd->next)
        rcd = rcd->next;
       rcd = rcd->next = xmalloc (sizeof *rcd);
-
-      free (v);
-      v = NULL;
     }
 
   if (token != '.')
     }
 
   if (token != '.')
@@ -461,7 +461,7 @@ parse_dest_spec (struct rcd_var * rcd, union value * v, size_t *max_dst_width)
       if (toklen > max)
        max = toklen;
       v->c = xmalloc (max + 1);
       if (toklen > max)
        max = toklen;
       v->c = xmalloc (max + 1);
-      st_pad_copy (v->c, ds_value (&tokstr), max + 1);
+      st_pad_copy (v->c, ds_c_str (&tokstr), max + 1);
       flags = RCD_DEST_STRING;
       *max_dst_width = max;
       lex_get ();
       flags = RCD_DEST_STRING;
       *max_dst_width = max;
       lex_get ();
@@ -624,7 +624,7 @@ parse_src_spec (struct rcd_var * rcd, int type, size_t max_src_width)
              if (!lex_force_string ())
                return 0;
              c->f1.c = xmalloc (max_src_width + 1);
              if (!lex_force_string ())
                return 0;
              c->f1.c = xmalloc (max_src_width + 1);
-             st_pad_copy (c->f1.c, ds_value (&tokstr), max_src_width + 1);
+             st_pad_copy (c->f1.c, ds_c_str (&tokstr), max_src_width + 1);
              lex_get ();
            }
        }
              lex_get ();
            }
        }
@@ -810,7 +810,7 @@ recode_trns_proc (struct trns_header * t, struct ccase * c,
                                  c->data[v->src->fv].s,
                                  v->dest->width, v->src->width);
          else
                                  c->data[v->src->fv].s,
                                  v->dest->width, v->src->width);
          else
-           memcpy (c->data[v->dest->fv].s, cp->t.c, v->dest->width);
+           memmove (c->data[v->dest->fv].s, cp->t.c, v->dest->width);
        }
     }
 
        }
     }
 
index dad14549864f8035eea2bc4b627c4331defa3cd5..e992b29fa112def232c92c131d663d826f75deca 100644 (file)
@@ -245,7 +245,7 @@ internal_cmd_do_repeat (void)
           command names must appear on a single line--they can't be
           spread out. */
        {
           command names must appear on a single line--they can't be
           spread out. */
        {
-         char *cp = ds_value (&getl_buf);
+         char *cp = ds_c_str (&getl_buf);
 
          /* Skip leading indentors and any whitespace. */
          if (*cp == '+' || *cp == '-' || *cp == '.')
 
          /* Skip leading indentors and any whitespace. */
          if (*cp == '+' || *cp == '-' || *cp == '.')
@@ -291,7 +291,7 @@ internal_cmd_do_repeat (void)
        line_buf_tail->len = ds_length (&getl_buf);
        line_buf_tail->line = xmalloc (ds_length (&getl_buf) + 1);
        memcpy (line_buf_tail->line,
        line_buf_tail->len = ds_length (&getl_buf);
        line_buf_tail->line = xmalloc (ds_length (&getl_buf) + 1);
        memcpy (line_buf_tail->line,
-               ds_value (&getl_buf), ds_length (&getl_buf) + 1);
+               ds_c_str (&getl_buf), ds_length (&getl_buf) + 1);
       }
   }
 
       }
   }
 
@@ -539,7 +539,7 @@ perform_DO_REPEAT_substitutions (void)
   /* Terminal dot. */
   int dot = 0;
 
   /* Terminal dot. */
   int dot = 0;
 
-  ds_init (NULL, &output, ds_size (&getl_buf));
+  ds_init (&output, ds_capacity (&getl_buf));
 
   /* Strip trailing whitespace, check for & remove terminal dot. */
   while (ds_length (&getl_buf) > 0
 
   /* Strip trailing whitespace, check for & remove terminal dot. */
   while (ds_length (&getl_buf) > 0
@@ -551,7 +551,7 @@ perform_DO_REPEAT_substitutions (void)
       ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
     }
   
       ds_truncate (&getl_buf, ds_length (&getl_buf) - 1);
     }
   
-  for (cp = ds_value (&getl_buf); cp < ds_end (&getl_buf); )
+  for (cp = ds_c_str (&getl_buf); cp < ds_end (&getl_buf); )
     {
       if (*cp == '\'' && !in_quote)
        in_apos ^= 1;
     {
       if (*cp == '\'' && !in_quote)
        in_apos ^= 1;
@@ -560,7 +560,7 @@ perform_DO_REPEAT_substitutions (void)
       
       if (in_quote || in_apos || !CHAR_IS_ID1 (*cp))
        {
       
       if (in_quote || in_apos || !CHAR_IS_ID1 (*cp))
        {
-         ds_putchar (&output, *cp++);
+         ds_putc (&output, *cp++);
          continue;
        }
 
          continue;
        }
 
@@ -580,16 +580,16 @@ perform_DO_REPEAT_substitutions (void)
        substitution = find_DO_REPEAT_substitution (name);
        if (!substitution)
          {
        substitution = find_DO_REPEAT_substitution (name);
        if (!substitution)
          {
-           ds_concat_buffer (&output, start, cp - start);
+           ds_concat (&output, start, cp - start);
            continue;
          }
 
        /* Force output buffer size, copy substitution. */
            continue;
          }
 
        /* Force output buffer size, copy substitution. */
-       ds_concat (&output, substitution);
+       ds_puts (&output, substitution);
       }
     }
   if (dot)
       }
     }
   if (dot)
-    ds_putchar (&output, get_endcmd() );
+    ds_putc (&output, get_endcmd() );
 
   ds_destroy (&getl_buf);
   getl_buf = output;
 
   ds_destroy (&getl_buf);
   getl_buf = output;
index 8d9afd61cf455776a12992a7ae2327d9d96e6cc2..3c1b38d5af50f77170c22efbae9cae1b33fb53f4 100644 (file)
--- a/src/set.q
+++ b/src/set.q
@@ -158,7 +158,7 @@ static int set_ccx (const char *cc_string, struct set_cust_currency * cc,
      listing=custom;
      log=custom;
      lowres=lores:auto/on/off;
      listing=custom;
      log=custom;
      lowres=lores:auto/on/off;
-     lpi=integer "x>0" "% must be greater than 0";
+     lpi=integer "x>0" "%s must be greater than 0";
      menus=menus:standard/extended;
      messages=messages:on/off/terminal/listing/both/none;
      mexpand=mexp:on/off;
      menus=menus:standard/extended;
      messages=messages:on/off/terminal/listing/both/none;
      mexpand=mexp:on/off;
@@ -595,7 +595,7 @@ stc_custom_pager (struct cmd_set *cmd UNUSED)
        return 0;
       if (set_pager)
        free (set_pager);
        return 0;
       if (set_pager)
        free (set_pager);
-      set_pager = xstrdup (ds_value (&tokstr));
+      set_pager = xstrdup (ds_c_str (&tokstr));
       lex_get ();
     }
   return 1;
       lex_get ();
     }
   return 1;
@@ -776,7 +776,7 @@ stc_custom_journal (struct cmd_set *cmd UNUSED)
     set_journaling = 0;
   if (token == T_STRING)
     {
     set_journaling = 0;
   if (token == T_STRING)
     {
-      set_journal = xstrdup (ds_value (&tokstr));
+      set_journal = xstrdup (ds_c_str (&tokstr));
       lex_get ();
     }
   return 1;
       lex_get ();
     }
   return 1;
index 056ef6fc934a79ecf753ab06ef84fec594d3127b..9d2d0b3c4023226cb08b57dcb9f4b222057b8347 100644 (file)
--- a/src/str.c
+++ b/src/str.c
@@ -163,10 +163,10 @@ void
 st_bare_pad_len_copy (char *dest, const char *src, size_t n, size_t len)
 {
   if (len >= n)
 st_bare_pad_len_copy (char *dest, const char *src, size_t n, size_t len)
 {
   if (len >= n)
-    memcpy (dest, src, n);
+    memmove (dest, src, n);
   else
     {
   else
     {
-      memcpy (dest, src, len);
+      memmove (dest, src, len);
       memset (&dest[len], ' ', n - len);
     }
 }
       memset (&dest[len], ' ', n - len);
     }
 }
@@ -195,30 +195,26 @@ st_pad_copy (char *dest, const char *src, size_t n)
     }
 }
 \f
     }
 }
 \f
-/* Initializes ST inside pool POOL (which may be a null pointer) with
-   initial contents S. */
+/* Initializes ST with initial contents S. */
 void
 void
-ds_create (struct pool *pool, struct string *st, const char *s)
+ds_create (struct string *st, const char *s)
 {
 {
-  st->pool = pool;
   st->length = strlen (s);
   st->length = strlen (s);
-  st->size = 8 + st->length * 2;
-  st->string = pool_malloc (pool, st->size + 1);
+  st->capacity = 8 + st->length * 2;
+  st->string = xmalloc (st->capacity + 1);
   strcpy (st->string, s);
 }
 
   strcpy (st->string, s);
 }
 
-/* Initializes ST inside POOL (which may be null), making room for at
-   least SIZE characters. */
+/* Initializes ST, making room for at least CAPACITY characters. */
 void
 void
-ds_init (struct pool *pool, struct string *st, size_t size)
+ds_init (struct string *st, size_t capacity)
 {
 {
-  st->pool = pool;
   st->length = 0;
   st->length = 0;
-  if (size > 8)
-    st->size = size;
+  if (capacity > 8)
+    st->capacity = capacity;
   else
   else
-    st->size = 8;
-  st->string = pool_malloc (pool, st->size + 1);
+    st->capacity = 8;
+  st->string = xmalloc (st->capacity + 1);
 }
 
 /* Replaces the contents of ST with STRING.  STRING may overlap with
 }
 
 /* Replaces the contents of ST with STRING.  STRING may overlap with
@@ -226,17 +222,28 @@ ds_init (struct pool *pool, struct string *st, size_t size)
 void
 ds_replace (struct string *st, const char *string)
 {
 void
 ds_replace (struct string *st, const char *string)
 {
-  char *s = st->string;
-  st->string = NULL;
-  ds_create (st->pool, st, string);
-  pool_free (st->pool, s);
+  size_t new_length = strlen (string);
+  if (new_length > st->capacity) 
+    {
+      /* The new length is longer than the allocated length, so
+         there can be no overlap. */
+      st->length = 0;
+      ds_concat (st, string, new_length);
+    }
+  else
+    {
+      /* Overlap is possible, but the new string will fit in the
+         allocated space, so we can just copy data. */
+      st->length = new_length;
+      memmove (st->string, string, st->length);
+    }
 }
 
 /* Frees ST. */
 void
 ds_destroy (struct string *st)
 {
 }
 
 /* Frees ST. */
 void
 ds_destroy (struct string *st)
 {
-  pool_free (st->pool, st->string);
+  free (st->string);
 }
 
 /* Truncates ST to zero length. */
 }
 
 /* Truncates ST to zero length. */
@@ -246,29 +253,45 @@ ds_clear (struct string *st)
   st->length = 0;
 }
 
   st->length = 0;
 }
 
-/* Ensures that ST can hold at least MIN_SIZE characters plus a null
+/* Pad ST on the right with copies of PAD until ST is at least
+   LENGTH characters in size.  If ST is initially LENGTH
+   characters or longer, this is a no-op. */
+void
+ds_rpad (struct string *st, size_t length, char pad) 
+{
+  assert (st != NULL);
+  if (st->length < length) 
+    {
+      if (st->capacity < length)
+        ds_extend (st, length);
+      memset (&st->string[st->length], pad, length - st->length);
+      st->length = length;
+    }
+}
+
+/* Ensures that ST can hold at least MIN_CAPACITY characters plus a null
    terminator. */
 void
    terminator. */
 void
-ds_extend (struct string *st, size_t min_size)
+ds_extend (struct string *st, size_t min_capacity)
 {
 {
-  if (min_size > st->size)
+  if (min_capacity > st->capacity)
     {
     {
-      st->size *= 2;
-      if (st->size < min_size)
-       st->size = min_size * 2;
+      st->capacity *= 2;
+      if (st->capacity < min_capacity)
+       st->capacity = min_capacity * 2;
       
       
-      st->string = pool_realloc (st->pool, st->string, st->size + 1);
+      st->string = xrealloc (st->string, st->capacity + 1);
     }
 }
 
     }
 }
 
-/* Shrink ST to the minimum size need to contain its content. */
+/* Shrink ST to the minimum capacity need to contain its content. */
 void
 ds_shrink (struct string *st)
 {
 void
 ds_shrink (struct string *st)
 {
-  if (st->size != st->length)
+  if (st->capacity != st->length)
     {
     {
-      st->size = st->length;
-      st->string = pool_realloc (st->pool, st->string, st->size + 1);
+      st->capacity = st->length;
+      st->string = xrealloc (st->string, st->capacity + 1);
     }
 }
 
     }
 }
 
@@ -290,21 +313,21 @@ ds_length (const struct string *st)
 
 /* Returns the allocation size of ST. */
 size_t
 
 /* Returns the allocation size of ST. */
 size_t
-ds_size (const struct string *st)
+ds_capacity (const struct string *st)
 {
 {
-  return st->size;
+  return st->capacity;
 }
 
 /* Returns the value of ST as a null-terminated string. */
 char *
 }
 
 /* Returns the value of ST as a null-terminated string. */
 char *
-ds_value (const struct string *st)
+ds_c_str (const struct string *st)
 {
   ((char *) st->string)[st->length] = '\0';
   return st->string;
 }
 
 /* Returns a pointer to the null terminator ST.
 {
   ((char *) st->string)[st->length] = '\0';
   return st->string;
 }
 
 /* Returns a pointer to the null terminator ST.
-   This might not be an actual null character unless ds_value() has
+   This might not be an actual null character unless ds_c_str() has
    been called since the last modification to ST. */
 char *
 ds_end (const struct string *st)
    been called since the last modification to ST. */
 char *
 ds_end (const struct string *st)
@@ -314,7 +337,7 @@ ds_end (const struct string *st)
 
 /* Concatenates S onto ST. */
 void
 
 /* Concatenates S onto ST. */
 void
-ds_concat (struct string *st, const char *s)
+ds_puts (struct string *st, const char *s)
 {
   size_t s_len;
 
 {
   size_t s_len;
 
@@ -328,7 +351,7 @@ ds_concat (struct string *st, const char *s)
 
 /* Concatenates LEN characters from BUF onto ST. */
 void
 
 /* Concatenates LEN characters from BUF onto ST. */
 void
-ds_concat_buffer (struct string *st, const char *buf, size_t len)
+ds_concat (struct string *st, const char *buf, size_t len)
 {
   ds_extend (st, st->length + len);
   memcpy (st->string + st->length, buf, len);
 {
   ds_extend (st, st->length + len);
   memcpy (st->string + st->length, buf, len);
@@ -361,7 +384,7 @@ ds_vprintf (struct string *st, const char *format, va_list args)
 
   int avail, needed;
 
 
   int avail, needed;
 
-  avail = st->size - st->length + 1;
+  avail = st->capacity - st->length + 1;
   needed = vsnprintf (st->string + st->length, avail, format, args);
 
 
   needed = vsnprintf (st->string + st->length, avail, format, args);
 
 
@@ -374,8 +397,8 @@ ds_vprintf (struct string *st, const char *format, va_list args)
   else
     while (needed == -1)
       {
   else
     while (needed == -1)
       {
-       ds_extend (st, (st->size + 1) * 2);
-       avail = st->size - st->length + 1;
+       ds_extend (st, (st->capacity + 1) * 2);
+       avail = st->capacity - st->length + 1;
 
        needed = vsnprintf (st->string + st->length, avail, format, args);
 
 
        needed = vsnprintf (st->string + st->length, avail, format, args);
 
@@ -386,21 +409,21 @@ ds_vprintf (struct string *st, const char *format, va_list args)
 
 /* Appends character CH to ST. */
 void
 
 /* Appends character CH to ST. */
 void
-ds_putchar (struct string *st, int ch)
+ds_putc (struct string *st, int ch)
 {
 {
-  if (st->length == st->size)
+  if (st->length == st->capacity)
     ds_extend (st, st->length + 1);
   st->string[st->length++] = ch;
 }
 
     ds_extend (st, st->length + 1);
   st->string[st->length++] = ch;
 }
 
-/* Reads a newline-terminated line from STREAM into ST.
+/* Appends to ST a newline-terminated line read from STREAM.
    Newline is the last character of ST on return, unless an I/O error
    or end of file is encountered after reading some characters.
    Returns 1 if a line is successfully read, or 0 if no characters at
    all were read before an I/O error or end of file was
    encountered. */
 int
    Newline is the last character of ST on return, unless an I/O error
    or end of file is encountered after reading some characters.
    Returns 1 if a line is successfully read, or 0 if no characters at
    all were read before an I/O error or end of file was
    encountered. */
 int
-ds_getline (struct string *st, FILE *stream)
+ds_gets (struct string *st, FILE *stream)
 {
   int c;
 
 {
   int c;
 
@@ -410,7 +433,7 @@ ds_getline (struct string *st, FILE *stream)
 
   for (;;)
     {
 
   for (;;)
     {
-      ds_putchar (st, c);
+      ds_putc (st, c);
       if (c == '\n')
        return 1;
 
       if (c == '\n')
        return 1;
 
@@ -438,7 +461,7 @@ ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
   /* Read the first line. */
   ds_clear (st);
   where->line_number++;
   /* Read the first line. */
   ds_clear (st);
   where->line_number++;
-  if (!ds_getline (st, stream))
+  if (!ds_gets (st, stream))
     return 0;
 
   /* Read additional lines, if any. */
     return 0;
 
   /* Read additional lines, if any. */
@@ -446,7 +469,7 @@ ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
     {
       /* Remove trailing whitespace. */
       {
     {
       /* Remove trailing whitespace. */
       {
-       char *s = ds_value (st);
+       char *s = ds_c_str (st);
        size_t len = ds_length (st);
       
        while (len > 0 && isspace ((unsigned char) s[len - 1]))
        size_t len = ds_length (st);
       
        while (len > 0 && isspace ((unsigned char) s[len - 1]))
@@ -455,13 +478,13 @@ ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
       }
 
       /* Check for trailing \.  Remove if found, bail otherwise. */
       }
 
       /* Check for trailing \.  Remove if found, bail otherwise. */
-      if (ds_length (st) == 0 || ds_value (st)[ds_length (st) - 1] != '\\')
+      if (ds_length (st) == 0 || ds_c_str (st)[ds_length (st) - 1] != '\\')
        break;
       ds_truncate (st, ds_length (st) - 1);
 
       /* Append another line and go around again. */
       {
        break;
       ds_truncate (st, ds_length (st) - 1);
 
       /* Append another line and go around again. */
       {
-       int success = ds_getline (st, stream);
+       int success = ds_gets (st, stream);
        where->line_number++;
        if (!success)
          return 1;
        where->line_number++;
        if (!success)
          return 1;
@@ -473,7 +496,7 @@ ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
     char *cp;
     int quote = 0;
       
     char *cp;
     int quote = 0;
       
-    for (cp = ds_value (st); *cp; cp++)
+    for (cp = ds_c_str (st); *cp; cp++)
       if (quote)
        {
          if (*cp == quote)
       if (quote)
        {
          if (*cp == quote)
@@ -485,7 +508,7 @@ ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
        quote = *cp;
       else if (*cp == '#')
        {
        quote = *cp;
       else if (*cp == '#')
        {
-         ds_truncate (st, cp - ds_value (st));
+         ds_truncate (st, cp - ds_c_str (st));
          break;
        }
   }
          break;
        }
   }
@@ -495,24 +518,24 @@ ds_get_config_line (FILE *stream, struct string *st, struct file_locator *where)
 \f
 /* Lengthed strings. */
 
 \f
 /* Lengthed strings. */
 
-/* Creates a new lengthed string LS in POOL with contents as a copy of
+/* Creates a new lengthed string LS with contents as a copy of
    S. */
 void
    S. */
 void
-ls_create (struct pool *pool, struct len_string *ls, const char *s)
+ls_create (struct len_string *ls, const char *s)
 {
   ls->length = strlen (s);
 {
   ls->length = strlen (s);
-  ls->string = pool_alloc (pool, ls->length + 1);
+  ls->string = xmalloc (ls->length + 1);
   memcpy (ls->string, s, ls->length + 1);
 }
 
   memcpy (ls->string, s, ls->length + 1);
 }
 
-/* Creates a new lengthed string LS in POOL with contents as a copy of
+/* Creates a new lengthed string LS with contents as a copy of
    BUFFER with length LEN. */
 void
    BUFFER with length LEN. */
 void
-ls_create_buffer (struct pool *pool, struct len_string *ls,
+ls_create_buffer (struct len_string *ls,
                  const char *buffer, size_t len)
 {
   ls->length = len;
                  const char *buffer, size_t len)
 {
   ls->length = len;
-  ls->string = pool_malloc (pool, len + 1);
+  ls->string = xmalloc (len + 1);
   memcpy (ls->string, buffer, len);
   ls->string[len] = '\0';
 }
   memcpy (ls->string, buffer, len);
   ls->string[len] = '\0';
 }
@@ -532,11 +555,11 @@ ls_shallow_copy (struct len_string *dst, const struct len_string *src)
   *dst = *src;
 }
 
   *dst = *src;
 }
 
-/* Frees the memory in POOL backing LS. */
+/* Frees the memory backing LS. */
 void
 void
-ls_destroy (struct pool *pool, struct len_string *ls)
+ls_destroy (struct len_string *ls)
 {
 {
-  pool_free (pool, ls->string);
+  free (ls->string);
 }
 
 /* Sets LS to a null pointer value. */
 }
 
 /* Sets LS to a null pointer value. */
@@ -569,7 +592,7 @@ ls_length (const struct len_string *ls)
 
 /* Returns a pointer to the character string in LS. */
 char *
 
 /* Returns a pointer to the character string in LS. */
 char *
-ls_value (const struct len_string *ls)
+ls_c_str (const struct len_string *ls)
 {
   return (char *) ls->string;
 }
 {
   return (char *) ls->string;
 }
index 3520e28027eb1fa5d48e1d681bded9d8923c6450..b1a44e22c24b6f709b113444467e634107e5e49b 100644 (file)
--- a/src/str.h
+++ b/src/str.h
@@ -134,61 +134,90 @@ struct len_string
     size_t length;
   };
 
     size_t length;
   };
 
-struct pool;
-void ls_create (struct pool *, struct len_string *, const char *);
-void ls_create_buffer (struct pool *, struct len_string *,
+void ls_create (struct len_string *, const char *);
+void ls_create_buffer (struct len_string *,
                       const char *, size_t len);
 void ls_init (struct len_string *, const char *, size_t);
 void ls_shallow_copy (struct len_string *, const struct len_string *);
                       const char *, size_t len);
 void ls_init (struct len_string *, const char *, size_t);
 void ls_shallow_copy (struct len_string *, const struct len_string *);
-void ls_destroy (struct pool *, struct len_string *);
+void ls_destroy (struct len_string *);
 
 void ls_null (struct len_string *);
 int ls_null_p (const struct len_string *);
 int ls_empty_p (const struct len_string *);
 
 size_t ls_length (const struct len_string *);
 
 void ls_null (struct len_string *);
 int ls_null_p (const struct len_string *);
 int ls_empty_p (const struct len_string *);
 
 size_t ls_length (const struct len_string *);
-char *ls_value (const struct len_string *);
+char *ls_c_str (const struct len_string *);
 char *ls_end (const struct len_string *);
 char *ls_end (const struct len_string *);
+
+#if __GNUC__ > 1
+extern inline size_t
+ls_length (const struct len_string *st)
+{
+  return st->length;
+}
+
+extern inline char *
+ls_c_str (const struct len_string *st)
+{
+  return st->string;
+}
+
+extern inline char *
+ls_end (const struct len_string *st)
+{
+  return st->string + st->length;
+}
+#endif
 \f
 /* Dynamic strings. */
 
 struct string
   {
 \f
 /* Dynamic strings. */
 
 struct string
   {
-    struct pool *pool;
-    size_t length;
-    size_t size;
-    char *string;
+    size_t length;      /* Length, not including a null terminator. */
+    size_t capacity;    /* Allocated capacity, not including one
+                           extra byte allocated for null terminator. */
+    char *string;       /* String data, not necessarily null
+                           terminated. */
   };
 
   };
 
-void ds_create (struct pool *, struct string *, const char *);
-void ds_init (struct pool *, struct string *, size_t size);
-void ds_replace (struct string *, const char *);
+/* Constructors, destructors. */
+void ds_create (struct string *, const char *);
+void ds_init (struct string *, size_t);
 void ds_destroy (struct string *);
 void ds_destroy (struct string *);
+
+/* Copy, shrink, extend. */
+void ds_replace (struct string *, const char *);
 void ds_clear (struct string *);
 void ds_clear (struct string *);
-void ds_extend (struct string *, size_t min_size);
+void ds_extend (struct string *, size_t);
 void ds_shrink (struct string *);
 void ds_shrink (struct string *);
-void ds_truncate (struct string *, size_t length);
+void ds_truncate (struct string *, size_t);
+void ds_rpad (struct string *, size_t length, char pad);
 
 
+/* Inspectors. */
 size_t ds_length (const struct string *);
 size_t ds_length (const struct string *);
-char *ds_value (const struct string *);
+char *ds_c_str (const struct string *);
+char *ds_data (const struct string *);
 char *ds_end (const struct string *);
 char *ds_end (const struct string *);
-size_t ds_size (const struct string *);
+size_t ds_capacity (const struct string *);
 
 
+/* File input. */
 struct file_locator;
 struct file_locator;
-int ds_getline (struct string *st, FILE *stream);
+int ds_gets (struct string *, FILE *);
 int ds_get_config_line (FILE *, struct string *, struct file_locator *);
 int ds_get_config_line (FILE *, struct string *, struct file_locator *);
-void ds_putchar (struct string *, int ch);
-void ds_concat (struct string *, const char *);
-void ds_concat_buffer (struct string *, const char *buf, size_t len);
-void ds_vprintf (struct string *st, const char *format, va_list args);
+
+/* Append. */
+void ds_putc (struct string *, int ch);
+void ds_puts (struct string *, const char *);
+void ds_concat (struct string *, const char *, size_t);
+void ds_vprintf (struct string *st, const char *, va_list);
 void ds_printf (struct string *, const char *, ...)
      PRINTF_FORMAT (2, 3);
 
 #if __GNUC__ > 1
 extern inline void
 void ds_printf (struct string *, const char *, ...)
      PRINTF_FORMAT (2, 3);
 
 #if __GNUC__ > 1
 extern inline void
-ds_putchar (struct string *st, int ch)
+ds_putc (struct string *st, int ch)
 {
 {
-  if (st->length == st->size)
+  if (st->length == st->capacity)
     ds_extend (st, st->length + 1);
   st->string[st->length++] = ch;
 }
     ds_extend (st, st->length + 1);
   st->string[st->length++] = ch;
 }
@@ -200,12 +229,18 @@ ds_length (const struct string *st)
 }
 
 extern inline char *
 }
 
 extern inline char *
-ds_value (const struct string *st)
+ds_c_str (const struct string *st)
 {
   ((char *) st->string)[st->length] = '\0';
   return st->string;
 }
 
 {
   ((char *) st->string)[st->length] = '\0';
   return st->string;
 }
 
+extern inline char *
+ds_data (const struct string *st)
+{
+  return st->string;
+}
+
 extern inline char *
 ds_end (const struct string *st)
 {
 extern inline char *
 ds_end (const struct string *st)
 {
index 4c4135ba732d97f4f5f75c095bd03c7a3bf8da54..376477c3f52fbf48877204c40f727fe9935c4324 100644 (file)
@@ -532,7 +532,7 @@ parse_value (union value * v, int type )
     {
       if (!lex_force_string ())
        return 0;
     {
       if (!lex_force_string ())
        return 0;
-      strncpy (v->s, ds_value (&tokstr), ds_length (&tokstr));
+      strncpy (v->s, ds_c_str (&tokstr), ds_length (&tokstr));
     }
 
   lex_get ();
     }
 
   lex_get ();
index 82df4cd23ab8d54d6e46327faee124eeaaa5597b..084c5873b91f118f1f914341024ba05b49c3f917 100644 (file)
--- a/src/tab.c
+++ b/src/tab.c
@@ -433,7 +433,8 @@ text_format (struct tab_table *table, int opt, const char *text, va_list args,
   else
     len = strlen (text);
 
   else
     len = strlen (text);
 
-  ls_create_buffer (table->container, s, text, len);
+  ls_create_buffer (s, text, len);
+  pool_register (table->container, free, s->string);
   
   if (opt & TAT_PRINTF)
     local_free (text);
   
   if (opt & TAT_PRINTF)
     local_free (text);
@@ -1162,7 +1163,7 @@ tabi_title (int x, int y)
   cp = stpcpy (cp, ".  ");
   if (!ls_empty_p (&t->title))
     {
   cp = stpcpy (cp, ".  ");
   if (!ls_empty_p (&t->title))
     {
-      memcpy (cp, ls_value (&t->title), ls_length (&t->title));
+      memcpy (cp, ls_c_str (&t->title), ls_length (&t->title));
       cp += ls_length (&t->title);
     }
   *cp = 0;
       cp += ls_length (&t->title);
     }
   *cp = 0;
@@ -1337,7 +1338,7 @@ render_strip (int x, int y, int r, int c1, int c2, int r1 UNUSED, int r2)
                    }
                } else {
                  struct tab_joined_cell *j =
                    }
                } else {
                  struct tab_joined_cell *j =
-                   (struct tab_joined_cell *) ls_value (&t->cc[index]);
+                   (struct tab_joined_cell *) ls_c_str (&t->cc[index]);
 
                  if (j->hit != tab_hit)
                    {
 
                  if (j->hit != tab_hit)
                    {
index cb56f84db2db7e38a57b2b7d543b83ac93b3bca7..e0191acc8bdf3880421e76c34304c0ee2f93856f 100644 (file)
@@ -60,7 +60,7 @@ get_title (const char *cmd, char **title)
        return CMD_FAILURE;
       if (*title)
        free (*title);
        return CMD_FAILURE;
       if (*title)
        free (*title);
-      *title = xstrdup (ds_value (&tokstr));
+      *title = xstrdup (ds_c_str (&tokstr));
       lex_get ();
       if (token != '.')
        {
       lex_get ();
       if (token != '.')
        {
index 9d05e77f83c528a067f300bb2d0c384b029f3b58..1af46a2c5d81496e5bc5f5156805a395d3002883 100644 (file)
@@ -151,7 +151,7 @@ get_label (struct variable **vars, int var_cnt)
               lex_error (_("expecting string"));
              return 0;
            }
               lex_error (_("expecting string"));
              return 0;
            }
-         st_bare_pad_copy (value.s, ds_value (&tokstr), MAX_SHORT_STRING);
+         st_bare_pad_copy (value.s, ds_c_str (&tokstr), MAX_SHORT_STRING);
        }
       else
        {
        }
       else
        {
@@ -174,7 +174,7 @@ get_label (struct variable **vars, int var_cnt)
          msg (SW, _("Truncating value label to 60 characters."));
          ds_truncate (&tokstr, 60);
        }
          msg (SW, _("Truncating value label to 60 characters."));
          ds_truncate (&tokstr, 60);
        }
-      label = ds_value (&tokstr);
+      label = ds_c_str (&tokstr);
 
       for (i = 0; i < var_cnt; i++)
         val_labs_replace (vars[i]->val_labs, value, label);
 
       for (i = 0; i < var_cnt; i++)
         val_labs_replace (vars[i]->val_labs, value, label);
index 48ef56a064499e8307cdff0b778cd2da111840f0..a62ec95e21fa4d638b9ac0233463b87e1939793a 100644 (file)
@@ -61,7 +61,7 @@ cmd_variable_labels (void)
        {
          if (v[i]->label)
            free (v[i]->label);
        {
          if (v[i]->label)
            free (v[i]->label);
-         v[i]->label = xstrdup (ds_value (&tokstr));
+         v[i]->label = xstrdup (ds_c_str (&tokstr));
        }
 
       lex_get ();
        }
 
       lex_get ();
index 22053d6a9d6540b132045c3792caa385a7a5784d..cf91b148824196ad8e873d7530f31f4b0ce78b05 100644 (file)
@@ -1,3 +1,11 @@
+Sun May 30 19:18:26 2004  Ben Pfaff  <blp@gnu.org>
+
+       * command/tabs.sh: Default tab width is now 4.
+
+       * command/data-list.sh: New test.
+
+       * Makefile.am: (TESTS) Add command/data-list.sh.
+
 Sun Apr 11 14:21:16 2004  Ben Pfaff  <blp@gnu.org>
 
        * stats/moments.sh: Now that our one-pass moments algorithm is
 Sun Apr 11 14:21:16 2004  Ben Pfaff  <blp@gnu.org>
 
        * stats/moments.sh: Now that our one-pass moments algorithm is
index 8020127f0297e81a0941c15439bbf5c3034a3b5e..ac622c1b074b74cd31b79590013ed7e3f904f667 100644 (file)
@@ -7,6 +7,7 @@ TESTS = \
        command/beg-data.sh \
        command/bignum.sh \
        command/count.sh \
        command/beg-data.sh \
        command/bignum.sh \
        command/count.sh \
+       command/data-list.sh \
        command/erase.sh \
        command/file-label.sh \
        command/filter.sh \
        command/erase.sh \
        command/file-label.sh \
        command/filter.sh \
diff --git a/tests/command/data-list.sh b/tests/command/data-list.sh
new file mode 100755 (executable)
index 0000000..814a9d2
--- /dev/null
@@ -0,0 +1,128 @@
+#!/bin/sh
+
+# This program tests the DATA LIST input program.
+
+TEMPDIR=/tmp/pspp-tst-$$
+
+here=`pwd`;
+
+# ensure that top_srcdir is absolute
+cd $top_srcdir; top_srcdir=`pwd`
+
+export STAT_CONFIG_PATH=$top_srcdir/config
+
+
+cleanup()
+{
+     rm -rf $TEMPDIR
+}
+
+
+fail()
+{
+    echo $activity
+    echo FAILED
+    cleanup;
+    exit 1;
+}
+
+
+no_result()
+{
+    echo $activity
+    echo NO RESULT;
+    cleanup;
+    exit 2;
+}
+
+pass()
+{
+    cleanup;
+    exit 0;
+}
+
+mkdir -p $TEMPDIR
+
+cd $TEMPDIR
+
+# Create command file.
+activity="create program"
+cat > $TEMPDIR/data-list.stat << EOF
+data list free/A B C D.
+begin data.
+,1,2,3
+,4,,5
+6
+7,
+8 9
+0,1,,,
+,,,,
+2
+
+3
+4
+5
+end data.
+list.
+
+data list free (tab)/A B C D.
+begin data.
+1      2       3       4
+1      2       3       
+1      2               4
+1      2               
+1              3       4
+1              3       
+1                      4
+1                      
+       2       3       4
+       2       3       
+       2               4
+       2               
+               3       4
+               3       
+                       4
+                       
+end data.
+list.
+EOF
+if [ $? -ne 0 ] ; then no_result ; fi
+
+
+activity="run program"
+$SUPERVISOR $here/../src/pspp --testing-mode -o raw-ascii --testing-mode $TEMPDIR/data-list.stat # > $TEMPDIR/errs
+if [ $? -ne 0 ] ; then fail ; fi
+
+activity="compare output"
+diff -b -B $TEMPDIR/pspp.list - << EOF
+       A        B        C        D
+-------- -------- -------- --------
+     .       1.00     2.00     3.00 
+     .       4.00      .       5.00 
+    6.00     7.00     8.00     9.00 
+     .00     1.00      .        .   
+     .        .        .        .   
+    2.00     3.00     4.00     5.00 
+
+       A        B        C        D
+-------- -------- -------- --------
+    1.00     2.00     3.00     4.00 
+    1.00     2.00     3.00      .   
+    1.00     2.00      .       4.00 
+    1.00     2.00      .        .   
+    1.00      .       3.00     4.00 
+    1.00      .       3.00      .   
+    1.00      .        .       4.00 
+    1.00      .        .        .   
+     .       2.00     3.00     4.00 
+     .       2.00     3.00      .   
+     .       2.00      .       4.00 
+     .       2.00      .        .   
+     .        .       3.00     4.00 
+     .        .       3.00      .   
+     .        .        .       4.00 
+     .        .        .        .   
+EOF
+if [ $? -ne 0 ] ; then fail ; fi
+
+pass;
index 9d57c0082e94ec2b6cafd94edf01ea045fcef69f..05178199efbde1b0575191123e9c631bb996773a 100755 (executable)
@@ -53,7 +53,7 @@ EOF
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
 if [ $? -ne 0 ] ; then no_result ; fi
 
 activity="create program 2"
-printf  "\t1\t12\t123\t1234\t12345\t123456\t\t1234567\t12345678\tasdf\tjkl\n" >> $TEMPDIR/tabs.stat
+printf  "\t1\t12\t123\t1234\t12345\n" >> $TEMPDIR/tabs.stat
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
 if [ $? -ne 0 ] ; then no_result ; fi
 
 
@@ -78,7 +78,7 @@ diff -B -b $TEMPDIR/pspp.list - << EOF
 #========#======#=======#======#
 |X       |     1|  1- 80|A80   |
 +--------+------+-------+------+
 #========#======#=======#======#
 |X       |     1|  1- 80|A80   |
 +--------+------+-------+------+
-        1       12      123     1234    12345   123456          1234567 12345678 
+    1   12  123 1234    12345
 EOF
 if [ $? -ne 0 ] ; then fail ; fi
 
 EOF
 if [ $? -ne 0 ] ; then fail ; fi