From: John Darrington Date: Mon, 6 Jul 2009 11:51:34 +0000 (+0800) Subject: data_out function to dynamically allocate return value. X-Git-Tag: build37~53^2~23 X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?p=pspp-builds.git;a=commitdiff_plain;h=f15c854d8500105766b2f5666bb62b983ff24f88 data_out function to dynamically allocate return value. 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. --- diff --git a/perl-module/PSPP.xs b/perl-module/PSPP.xs index 8179d29a..e80b3cf2 100644 --- a/perl-module/PSPP.xs +++ b/perl-module/PSPP.xs @@ -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); diff --git a/src/data/data-out.c b/src/data/data-out.c index fa8d59e7..7f15e5b2 100644 --- a/src/data/data-out.c +++ b/src/data/data-out.c @@ -36,6 +36,7 @@ #include #include #include +#include #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 *); -/* 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); } diff --git a/src/data/data-out.h b/src/data/data-out.h index 7972f6a9..71cbbac3 100644 --- a/src/data/data-out.h +++ b/src/data/data-out.h @@ -25,9 +25,11 @@ 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 */ diff --git a/src/data/variable.c b/src/data/variable.c index 8d85b518..a60adcaf 100644 --- a/src/data/variable.c +++ b/src/data/variable.c @@ -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); diff --git a/src/language/data-io/list.q b/src/language/data-io/list.q index 28820a85..b5a16f26 100644 --- a/src/language/data-io/list.q +++ b/src/language/data-io/list.q @@ -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 (" ", 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 ("\n", x->file); } diff --git a/src/language/dictionary/split-file.c b/src/language/dictionary/split-file.c index 155cfa12..11fa0974 100644 --- a/src/language/dictionary/split-file.c +++ b/src/language/dictionary/split-file.c @@ -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); diff --git a/src/language/expressions/operations.def b/src/language/expressions/operations.def index 2d31bd47..db71d277 100644 --- a/src/language/expressions/operations.def +++ b/src/language/expressions/operations.def @@ -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; } diff --git a/src/language/stats/crosstabs.q b/src/language/stats/crosstabs.q index 70bbe5cc..a83a8647 100644 --- a/src/language/stats/crosstabs.q +++ b/src/language/stats/crosstabs.q @@ -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--; diff --git a/src/output/table.c b/src/output/table.c index 9e925a44..a86f407d 100644 --- a/src/output/table.c +++ b/src/output/table.c @@ -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); } diff --git a/src/ui/gui/helper.c b/src/ui/gui/helper.c index a4c07ca4..bec67166 100644 --- a/src/ui/gui/helper.c +++ b/src/ui/gui/helper.c @@ -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; diff --git a/src/ui/gui/psppire-data-editor.c b/src/ui/gui/psppire-data-editor.c index e02cf730..b48ad233 100644 --- a/src/ui/gui/psppire-data-editor.c +++ b/src/ui/gui/psppire-data-editor.c @@ -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 * diff --git a/src/ui/gui/psppire-data-store.c b/src/ui/gui/psppire-data-store.c index 0e378bbe..13ad0cc6 100644 --- a/src/ui/gui/psppire-data-store.c +++ b/src/ui/gui/psppire-data-store.c @@ -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); diff --git a/src/ui/gui/text-data-import-dialog.c b/src/ui/gui/text-data-import-dialog.c index dac8b4c1..8eebf977 100644 --- a/src/ui/gui/text-data-import-dialog.c +++ b/src/ui/gui/text-data-import-dialog.c @@ -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)); diff --git a/src/ui/syntax-gen.c b/src/ui/syntax-gen.c index bf1ee12f..e853c569 100644 --- a/src/ui/syntax-gen.c +++ b/src/ui/syntax-gen.c @@ -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)