data_out function to dynamically allocate return value.
authorJohn Darrington <john@darrington.wattle.id.au>
Mon, 6 Jul 2009 11:51:34 +0000 (19:51 +0800)
committerJohn Darrington <john@darrington.wattle.id.au>
Mon, 6 Jul 2009 11:51:34 +0000 (19:51 +0800)
Preparation for i18n of values.  Instead of asking the
caller to prepare the buffer for output, data_out now
dynamically allocates the output value, and expects the
caller to free it.  This is necessary since for utf8
strings, the caller cannot reasonably know the length of
the required output buffer.  It also simplifies some uses
of data_out.

14 files changed:
perl-module/PSPP.xs
src/data/data-out.c
src/data/data-out.h
src/data/variable.c
src/language/data-io/list.q
src/language/dictionary/split-file.c
src/language/expressions/operations.def
src/language/stats/crosstabs.q
src/output/table.c
src/ui/gui/helper.c
src/ui/gui/psppire-data-editor.c
src/ui/gui/psppire-data-store.c
src/ui/gui/text-data-import-dialog.c
src/ui/syntax-gen.c

index 8179d29a3721aa27b0b0e7417085a515eb65c591..e80b3cf22baf01ecd6c63cab928f7230a317a611 100644 (file)
@@ -177,9 +177,7 @@ CODE:
  union value uv;
  char *s;
  make_value_from_scalar (&uv, val, var);
- s = malloc (fmt->w);
- memset (s, '\0', fmt->w);
- data_out (&uv, fmt, s);
+ s = data_out (&uv, fmt);
  value_destroy (&uv, var_get_width (var));
  ret = newSVpv (s, fmt->w);
  free (s);
index fa8d59e74ced3dd4df1c0977a5f25b6d70fe76c9..7f15e5b24a8a42caafe8ad48d5dd809b467d1cd6 100644 (file)
@@ -36,6 +36,7 @@
 #include <libpspp/message.h>
 #include <libpspp/misc.h>
 #include <libpspp/str.h>
+#include <libpspp/pool.h>
 
 #include "minmax.h"
 
@@ -83,18 +84,22 @@ static void output_binary_integer (uint64_t, int bytes, enum integer_format,
                                    char *);
 static void output_hex (const void *, size_t bytes, char *);
 \f
-/* Same as data_out, and additionally recodes the output from
-   native form into the given legacy character ENCODING. */
-void
-data_out_legacy (const union value *input, const char *encoding,
-                 const struct fmt_spec *format, char *output)
-{
-  static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] =
+
+static data_out_converter_func *const converters[FMT_NUMBER_OF_FORMATS] =
     {
 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) output_##METHOD,
 #include "format.def"
     };
 
+/* Similar to data_out. Additionally recodes the output from
+   native form into the given legacy character ENCODING.
+   OUTPUT must be provided by the caller and must be at least
+   FORMAT->w long. No null terminator is appended to OUTPUT.
+*/
+void
+data_out_legacy (const union value *input, const char *encoding,
+                 const struct fmt_spec *format, char *output)
+{
   assert (fmt_check_output (format));
 
   converters[format->type] (input, format, output);
@@ -103,18 +108,32 @@ data_out_legacy (const union value *input, const char *encoding,
     legacy_recode (LEGACY_NATIVE, output, encoding, output, format->w);
 }
 
-/* Converts the INPUT value into printable form in the exactly
-   FORMAT->W characters in OUTPUT according to format
-   specification FORMAT. No null terminator is appended to the
-   buffer.
+/* Converts the INPUT value into printable form, according to format
+   specification FORMAT. 
 
    VALUE must be the correct width for FORMAT, that is, its
-   width must be fmt_var_width(FORMAT). */
-void
-data_out (const union value *input, const struct fmt_spec *format,
-          char *output)
+   width must be fmt_var_width(FORMAT).
+
+   The return value is dynamically allocated, and must be freed
+   by the caller.  If POOL is non-null, then the return value is
+   allocated on that pool.
+*/
+char *
+data_out_pool (const union value *input, const struct fmt_spec *format,
+         struct pool *pool)
+{
+  char *output = pool_malloc (pool, format->w + 1);
+  assert (fmt_check_output (format));
+
+  converters[format->type] (input, format, output);
+  output[format->w] = '\0';
+  return output;
+}
+
+char *
+data_out (const union value *input, const struct fmt_spec *format)
 {
-  return data_out_legacy (input, LEGACY_NATIVE, format, output);
+  return data_out_pool (input, format, NULL);
 }
 
 \f
index 7972f6a90eafe5050e2c219ecb2e45888ce20981..71cbbac3d5307e1c6bbba422443ea494e930e26e 100644 (file)
 struct fmt_spec;
 union value;
 
-void data_out (const union value *, const struct fmt_spec *, char *);
+char * data_out (const union value *, const struct fmt_spec *);
 
-void data_out_legacy (const union value *, const char *encoding,
-                      const struct fmt_spec *, char *);
+char * data_out_pool (const union value *, const struct fmt_spec *, struct pool *pool);
+
+void data_out_legacy (const union value *input, const char *encoding,
+                     const struct fmt_spec *format, char *output);
 
 #endif /* data-out.h */
index 8d85b518a5f8325dbef9c257e8af20d2ca21ab3a..a60adcafcd8d25422f7be32d8f870059c2c028f3 100644 (file)
@@ -592,8 +592,9 @@ var_append_value_name (const struct variable *v, const union value *value,
   const char *name = var_lookup_value_label (v, value);
   if (name == NULL)
     {
-      char *s = ds_put_uninit (str, v->print.w);
-      data_out (value, &v->print, s);
+      char *s = data_out (value, &v->print);
+      ds_put_cstr (str, s);
+      free (s);
     }
   else
     ds_put_cstr (str, name);
index 28820a8504b5fdfc15c8ede3338439ab0f1b4d7a..b5a16f265481e8d4d5bc0c957a3412235da3e039 100644 (file)
@@ -706,18 +706,21 @@ list_case (const struct ccase *c, casenumber case_idx,
             if (fmt_is_string (print->type)
                 || dict_contains_var (dict, v))
              {
-                data_out (case_data (c, v), print,
-                          ds_put_uninit (&line_buffer, print->w));
+               char *s = data_out (case_data (c, v), print);
+               ds_put_cstr (&line_buffer, s);
+               free (s);
              }
             else
               {
+               char *s;
                 union value case_idx_value;
                 case_idx_value.f = case_idx;
-                data_out (&case_idx_value, print,
-                          ds_put_uninit (&line_buffer,print->w));
+                s = data_out (&case_idx_value, print);
+               ds_put_cstr (&line_buffer, s);
+               free (s);
               }
 
-           ds_put_char(&line_buffer, ' ');
+           ds_put_char (&line_buffer, ' ');
          }
 
        if (!n_lines_remaining (d))
@@ -740,20 +743,21 @@ list_case (const struct ccase *c, casenumber case_idx,
          {
            const struct variable *v = cmd.v_variables[column];
             const struct fmt_spec *print = var_get_print_format (v);
-           char buf[256];
+           char *s = NULL;
 
             if (fmt_is_string (print->type)
                 || dict_contains_var (dict, v))
-             data_out (case_data (c, v), print, buf);
+             s = data_out (case_data (c, v), print);
             else
               {
                 union value case_idx_value;
                 case_idx_value.f = case_idx;
-                data_out (&case_idx_value, print, buf);
+                s = data_out (&case_idx_value, print);
               }
 
             fputs ("    <TD>", x->file);
-            html_put_cell_contents (d, TAB_FIX, ss_buffer (buf, print->w));
+            html_put_cell_contents (d, TAB_FIX, ss_buffer (s, print->w));
+           free (s);
             fputs ("</TD>\n", x->file);
          }
 
index 155cfa1208c23a035a2f9058eceb3c10de6d241d..11fa097493340d5c9d38b49dd2215d3a3bdad4f0 100644 (file)
@@ -88,17 +88,17 @@ output_split_file_values (const struct dataset *ds, const struct ccase *c)
   for (i = 0; i < split_cnt; i++)
     {
       const struct variable *v = split[i];
-      char temp_buf[80];
+      char *s;
       const char *val_lab;
       const struct fmt_spec *print = var_get_print_format (v);
 
       tab_text (t, 0, i + 1, TAB_LEFT | TAT_PRINTF, "%s", var_get_name (v));
 
-      data_out (case_data (c, v), print, temp_buf);
-      temp_buf[print->w] = 0;
-
-      tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", print->w, temp_buf);
+      s = data_out (case_data (c, v), print);
 
+      tab_text (t, 1, i + 1, TAT_PRINTF, "%.*s", print->w, s);
+      free (s);
+      
       val_lab = var_lookup_value_label (v, case_data (c, v));
       if (val_lab)
        tab_text (t, 2, i + 1, TAB_LEFT, val_lab);
index 2d31bd47182dcb158d9f9c50e644fb03bb7b07bf..db71d2770339db273fa5114fe456afb83f106411 100644 (file)
@@ -582,11 +582,15 @@ absorb_miss string function STRING (x, no_format f)
 {
   union value v;
   struct substring dst;
+  char *s;
 
   v.f = x;
-  dst = alloc_string (e, f->w);
+
   assert (!fmt_is_string (f->type));
-  data_out (&v, f, dst.string);
+  s = data_out (&v, f);
+  dst = alloc_string (e, strlen (s));
+  strcpy (dst.string, s);
+  free (s);
   return dst;
 }
 
index 70bbe5cc95b31857214fa50f21e3070466b9a80f..a83a86472f33c74189ed81421f66953197af1711 100644 (file)
@@ -1184,14 +1184,16 @@ create_crosstab_table (struct crosstabs_proc *proc, struct pivot_table *pt)
     {
       const struct variable *var = pt->const_vars[i];
       size_t ofs;
+      char *s = NULL;
 
       ds_put_format (&title, ", %s=", var_get_name (var));
 
       /* Insert the formatted value of the variable, then trim
          leading spaces in what was just inserted. */
       ofs = ds_length (&title);
-      data_out (&pt->const_values[i], var_get_print_format (var),
-                ds_put_uninit (&title, var_get_width (var)));
+      s = data_out (&pt->const_values[i], var_get_print_format (var));
+      ds_put_cstr (&title, s);
+      free (s);
       ds_remove (&title, ofs, ss_cspan (ds_substr (&title, ofs, SIZE_MAX),
                                         ss_cstr (" ")));
     }
@@ -1510,6 +1512,7 @@ table_value_missing (struct crosstabs_proc *proc,
                     const union value *v, const struct variable *var)
 {
   struct substring s;
+  char *ss;
   const struct fmt_spec *print = var_get_print_format (var);
 
   const char *label = var_lookup_value_label (var, v);
@@ -1520,7 +1523,9 @@ table_value_missing (struct crosstabs_proc *proc,
     }
 
   s.string = tab_alloc (table, print->w);
-  data_out (v, print, s.string);
+  ss = data_out (v, print);
+  strcpy (s.string, ss);
+  free (ss);
   s.length = print->w;
   if (proc->exclude == MV_NEVER && var_is_num_missing (var, v->f, MV_USER))
     s.string[s.length++] = 'M';
@@ -1559,11 +1564,14 @@ format_cell_entry (struct tab_table *table, int c, int r, double value,
   const struct fmt_spec f = {FMT_F, 10, 1};
   union value v;
   struct substring s;
+  char *ss;
 
   s.length = 10;
   s.string = tab_alloc (table, 16);
   v.f = value;
-  data_out (&v, &f, s.string);
+  ss = data_out (&v, &f);
+  strcpy (s.string, ss);
+  free (ss);
   while (*s.string == ' ')
     {
       s.length--;
index 9e925a44df12300bb35446ae700bef29ace5083c..a86f407d5f3aa18cab0bbc0376a7eb603de3ceb9 100644 (file)
@@ -537,11 +537,10 @@ tab_value (struct tab_table *table, int c, int r, unsigned char opt,
     }
 #endif
 
-  contents = pool_alloc (table->container, f->w);
-  table->cc[c + r * table->cf] = ss_buffer (contents, f->w);
-  table->ct[c + r * table->cf] = opt;
+  contents = data_out_pool (v, f, table->container);
 
-  data_out (v, f, contents);
+  table->cc[c + r * table->cf] = ss_cstr (contents);
+  table->ct[c + r * table->cf] = opt;
 }
 
 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL
@@ -550,8 +549,7 @@ void
 tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
           double val, int w, int d)
 {
-  char *contents;
-  char buf[40], *cp;
+  char *s, *cp;
 
   struct fmt_spec f;
   union value double_value;
@@ -580,17 +578,15 @@ tab_fixed (struct tab_table *table, int c, int r, unsigned char opt,
 #endif
 
   double_value.f = val;
-  data_out (&double_value, &f, buf);
+  s = data_out_pool (&double_value, &f, table->container);
 
-  cp = buf;
-  while (isspace ((unsigned char) *cp) && cp < &buf[w])
+  cp = s;
+  while (isspace ((unsigned char) *cp) && cp < &s[w])
     cp++;
-  f.w = w - (cp - buf);
+  f.w = w - (cp - s);
 
-  contents = pool_alloc (table->container, f.w);
-  table->cc[c + r * table->cf] = ss_buffer (contents, f.w);
+  table->cc[c + r * table->cf] = ss_buffer (cp, f.w);
   table->ct[c + r * table->cf] = opt;
-  memcpy (contents, cp, f.w);
 }
 
 /* Sets cell (C,R) in TABLE, with options OPT, to have value VAL as
@@ -602,10 +598,9 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
           double val, const struct fmt_spec *fmt)
 {
   int w;
-  char *contents;
-  char buf[40], *cp;
+  char *s, *cp;
 
-  union value double_value;
+  union value double_value ;
 
   assert (table != NULL);
 
@@ -634,17 +629,17 @@ tab_double (struct tab_table *table, int c, int r, unsigned char opt,
 #endif
 
   double_value.f = val;
-  data_out (&double_value, fmt, buf);
+  s = data_out_pool (&double_value, fmt, table->container);
 
-  cp = buf;
-  while (isspace ((unsigned char) *cp) && cp < &buf[fmt->w])
-    cp++;
-  w = fmt->w - (cp - buf);
-
-  contents = pool_alloc (table->container, w);
-  table->cc[c + r * table->cf] = ss_buffer (contents, w);
+  cp = s;
+  while (isspace ((unsigned char) *cp) && cp < s + fmt->w)
+    {
+      cp++;
+    }
+  w = fmt->w - (cp - s);
+  
+  table->cc[c + r * table->cf] = ss_buffer (cp, w);
   table->ct[c + r * table->cf] = opt;
-  memcpy (contents, cp, w);
 }
 
 
index a4c07ca46d78ae74efd5317f3a7b87216578b1ee..bec6716689a9501561ced5fe0edcdb4451fd6b01 100644 (file)
@@ -53,9 +53,7 @@ value_to_text (union value v, struct fmt_spec format)
 {
   gchar *s = 0;
 
-  s = g_new (gchar, format.w + 1);
-  data_out (&v, &format, s);
-  s[format.w]='\0';
+  s = data_out (&v, &format);
   g_strchug (s);
 
   return s;
index e02cf730c7f381b1e7c81ef3b2bea247c0b92af8..b48ad2338b6ccb8e49ca1e8726383885aab1e17d 100644 (file)
@@ -1649,17 +1649,14 @@ static void
 data_out_g_string (GString *string, const struct variable *v,
                   const struct ccase *cc)
 {
-  char *buf ;
-
   const struct fmt_spec *fs = var_get_print_format (v);
   const union value *val = case_data (cc, v);
-  buf = xzalloc (fs->w);
 
-  data_out (val, fs, buf);
+  char *s = data_out (val, fs);
 
-  g_string_append_len (string, buf, fs->w);
+  g_string_append_len (string, s, fs->w);
 
-  g_free (buf);
+  g_free (s);
 }
 
 static GString *
index 0e378bbec1f989cea8b6c94e971e262ab69d9db5..13ad0cc6cd283edfb9656a67f4eb2b3f7ae7873b 100644 (file)
@@ -585,7 +585,6 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
   const struct variable *pv ;
   union value v;
   int width;
-  GString *s;
 
   g_return_val_if_fail (store->dict, NULL);
   g_return_val_if_fail (store->datasheet, NULL);
@@ -622,21 +621,10 @@ psppire_data_store_get_string (PsppireDataStore *store, glong row, glong column)
 
   fp = var_get_write_format (pv);
 
-  s = g_string_sized_new (fp->w + 1);
-  g_string_set_size (s, fp->w);
-
-  memset (s->str, 0, fp->w);
-
-  g_assert (fp->w == s->len);
-
   /* Converts binary value V into printable form in the exactly
      FP->W character in buffer S according to format specification
      FP.  No null terminator is appended to the buffer.  */
-  data_out (&v, fp, s->str);
-
-  text = recode_string (UTF8, psppire_dict_encoding (store->dict),
-                       s->str, fp->w);
-  g_string_free (s, TRUE);
+  text = data_out (&v, fp);
 
   g_strchomp (text);
 
index dac8b4c1e0a5c0ad8cb22ef0887b85375eefe94b..8eebf9775677954e17f0a19f73ca9a8273a16e45 100644 (file)
@@ -1768,10 +1768,7 @@ parse_field (struct import_assistant *ia,
     }
   if (outputp != NULL)
     {
-      char *output = xmalloc (out.w + 1);
-      data_out (&val, &out, output);
-      output[out.w] = '\0';
-      *outputp = output;
+      *outputp = data_out (&val, &out);
     }
   value_destroy (&val, var_get_width (var));
 
index bf1ee12f244caadbfc4197c0b7be466c7660a51e..e853c5692780463beed4a27887ffdda079dd93df 100644 (file)
@@ -146,20 +146,22 @@ syntax_gen_number (struct string *output,
           & (FMT_CAT_DATE | FMT_CAT_TIME | FMT_CAT_DATE_COMPONENT)))
     {
       union value v_in, v_out;
-      char buffer[FMT_MAX_NUMERIC_WIDTH];
+      char *s;
       bool ok;
 
       v_in.f = number;
-      data_out (&v_in, format, buffer);
+      s = data_out (&v_in, format);
       msg_disable ();
-      ok = data_in (ss_buffer (buffer, format->w), LEGACY_NATIVE,
+      ok = data_in (ss_cstr (s), LEGACY_NATIVE,
                     format->type, false, 0, 0, &v_out, 0);
       msg_enable ();
       if (ok && v_out.f == number)
         {
-          syntax_gen_string (output, ss_buffer (buffer, format->w));
+          syntax_gen_string (output, ss_cstr (s));
+         free (s);
           return;
         }
+      free (s);
     }
 
   if (number == SYSMIS)