abstraction. Rewrite all references to formats in other files.
See patch #5511.
+Tue Oct 31 19:55:52 2006 Ben Pfaff <blp@gnu.org>
+
+ * Smake (GNULIB_MODULES): Add `mempcpy' module.
+
Tue Oct 31 19:29:05 2006 Ben Pfaff <blp@gnu.org>
* configure.ac: Drop tests for strchr, strrchr because now we
memcmp \
memmem \
memmove \
+ mempcpy \
memset \
progname \
readlink \
+Tue Oct 31 19:58:27 2006 Ben Pfaff <blp@gnu.org>
+
+ * format.c: Completely rewrite, to achieve better abstraction.
+ Rewrite all references to formats in other files.
+
+ * format.def: Rewrite and reorganize.
+
+ * settings.c: Move everything related to custom currency formats
+ into format.[ch], changing them in form, so as to group related
+ code and definitions better. Changed all references to use the
+ new functions.
+ (static var decimal) Removed.
+ (static var grouping) Removed.
+ (static var cc) Removed.
+ (get_decimal) Removed.
+ (set_decimal) Removed.
+ (get_grouping) Removed.
+ (set_grouping) Removed.
+ (get_cc) Removed.
+ (set_cc) Removed.
+
+ * settings.h: (macro CC_CNT) Removed.
+ (macro CC_WIDTH) Removed.
+ (struct custom_currency) Removed.
+
+Tue Oct 31 19:56:19 2006 Ben Pfaff <blp@gnu.org>
+
+ * data-in.c (data_in): Use switch statement instead of table, to
+ avoid dependence on the order of the FMT_* enums.
+
Tue Oct 31 19:35:36 2006 Ben Pfaff <blp@gnu.org>
* data-out.c: (num_to_string) Removed, because it was dead code.
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
#include <config.h>
#include "data-in.h"
-#include <libpspp/message.h>
+#include <libpspp/assertion.h>
#include <math.h>
#include <ctype.h>
#include <stdarg.h>
{
struct msg m;
struct string text;
+ char format_string[FMT_STRING_LEN_MAX + 1];
if (i->flags & DI_IGNORE_ERROR)
return;
ds_put_format (&text, _("(column %d"), i->f1);
else
ds_put_format (&text, _("(columns %d-%d"), i->f1, i->f2);
- ds_put_format (&text, _(", field type %s) "), fmt_to_string (&i->format));
+ ds_put_format (&text, _(", field type %s) "),
+ fmt_to_string (&i->format, format_string));
ds_put_vformat (&text, format, args);
m.category = MSG_DATA;
}
else
sign = 1;
-
- if (type != FMT_DOT)
- {
- decimal = get_decimal();
- grouping = get_grouping();
- }
- else
- {
- decimal = get_grouping();
- grouping = get_decimal();
- }
+
+ decimal = fmt_decimal_char (type);
+ grouping = fmt_grouping_char (type);
i->v->f = SYSMIS;
num = 0.0;
static void
default_result (struct data_in *i)
{
- const struct fmt_desc *const fmt = &formats[i->format.type];
-
/* Default to SYSMIS or blanks. */
- if (fmt->cat & FCAT_STRING)
+ if (fmt_is_string (i->format.type))
memset (i->v->s, ' ', i->format.w);
else
i->v->f = get_blanks();
bool
data_in (struct data_in *i)
{
- const struct fmt_desc *const fmt = &formats[i->format.type];
+ bool success;
- assert (check_input_specifier (&i->format, 0));
+ assert (fmt_check_input (&i->format));
/* Check that we've got a string to work with. */
if (i->e == i->s || i->format.w <= 0)
i->f2 = i->f1 + (i->e - i->s) - 1;
/* Make sure that the string isn't too long. */
- if (i->format.w > fmt->Imax_w)
+ if (i->format.w > fmt_max_input_width (i->format.type))
{
dls_error (i, _("Field too long (%d characters). Truncated after "
- "character %d."),
- i->format.w, fmt->Imax_w);
- i->format.w = fmt->Imax_w;
+ "character %d."),
+ i->format.w, fmt_max_input_width (i->format.type));
+ i->format.w = fmt_max_input_width (i->format.type);
}
- if (fmt->cat & FCAT_BLANKS_SYSMIS)
+ if (!(fmt_get_category (i->format.type)
+ & (FMT_CAT_STRING | FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL)))
{
const char *cp;
}
}
- {
- typedef bool (*handler_t) (struct data_in *);
- static const handler_t handlers[FMT_NUMBER_OF_FORMATS] =
- {
- parse_numeric, parse_N, parse_numeric, parse_numeric,
- parse_numeric, parse_numeric, parse_numeric,
- parse_Z, parse_A, parse_AHEX, parse_IB, parse_P, parse_PIB,
- parse_PIBHEX, parse_PK, parse_RB, parse_RBHEX,
- NULL, NULL, NULL, NULL, NULL,
- parse_DATE, parse_EDATE, parse_SDATE, parse_ADATE, parse_JDATE,
- parse_QYR, parse_MOYR, parse_WKYR,
- parse_DATETIME, parse_TIME, parse_DTIME,
- parse_WKDAY, parse_MONTH,
- };
-
- handler_t handler;
- bool success;
-
- handler = handlers[i->format.type];
- assert (handler != NULL);
-
- success = handler (i);
- if (!success)
- default_result (i);
- return success;
- }
+ switch (i->format.type)
+ {
+ case FMT_F:
+ case FMT_COMMA:
+ case FMT_DOT:
+ case FMT_DOLLAR:
+ case FMT_PCT:
+ case FMT_E:
+ success = parse_numeric (i);
+ break;
+ case FMT_CCA:
+ case FMT_CCB:
+ case FMT_CCC:
+ case FMT_CCD:
+ case FMT_CCE:
+ NOT_REACHED ();
+ case FMT_N:
+ success = parse_N (i);
+ break;
+ case FMT_Z:
+ success = parse_Z (i);
+ break;
+ case FMT_P:
+ success = parse_P (i);
+ break;
+ case FMT_PK:
+ success = parse_PK (i);
+ break;
+ case FMT_IB:
+ success = parse_IB (i);
+ break;
+ case FMT_PIB:
+ success = parse_PIB (i);
+ break;
+ case FMT_PIBHEX:
+ success = parse_PIBHEX (i);
+ break;
+ case FMT_RB:
+ success = parse_RB (i);
+ break;
+ case FMT_RBHEX:
+ success = parse_RBHEX (i);
+ break;
+ case FMT_DATE:
+ success = parse_DATE (i);
+ break;
+ case FMT_ADATE:
+ success = parse_ADATE (i);
+ break;
+ case FMT_EDATE:
+ success = parse_EDATE (i);
+ break;
+ case FMT_JDATE:
+ success = parse_JDATE (i);
+ break;
+ case FMT_SDATE:
+ success = parse_SDATE (i);
+ break;
+ case FMT_QYR:
+ success = parse_QYR (i);
+ break;
+ case FMT_MOYR:
+ success = parse_MOYR (i);
+ break;
+ case FMT_WKYR:
+ success = parse_WKYR (i);
+ break;
+ case FMT_DATETIME:
+ success = parse_DATETIME (i);
+ break;
+ case FMT_TIME:
+ success = parse_TIME (i);
+ break;
+ case FMT_DTIME:
+ success = parse_DTIME (i);
+ break;
+ case FMT_WKDAY:
+ success = parse_WKDAY (i);
+ break;
+ case FMT_MONTH:
+ success = parse_MONTH (i);
+ break;
+ case FMT_A:
+ success = parse_A (i);
+ break;
+ case FMT_AHEX:
+ success = parse_AHEX (i);
+ break;
+ default:
+ NOT_REACHED ();
+ }
+ if (!success)
+ default_result (i);
+
+ return success;
}
\f
/* Utility function. */
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
bool
data_out (char *s, const struct fmt_spec *fp, const union value *v)
{
- int cat = formats[fp->type].cat;
int ok;
- assert (check_output_specifier (fp, 0));
- if (!(cat & FCAT_STRING))
+ assert (fmt_check_output (fp));
+ if (fmt_is_numeric (fp->type))
{
- /* Numeric formatting. */
+ enum fmt_category category = fmt_get_category (fp->type);
double number = v->f;
/* Handle SYSMIS turning into blanks. */
- if ((cat & FCAT_BLANKS_SYSMIS) && number == SYSMIS)
+ if (!(category & (FMT_CAT_CUSTOM | FMT_CAT_BINARY | FMT_CAT_HEXADECIMAL))
+ && number == SYSMIS)
{
memset (s, ' ', fp->w);
s[fp->w - fp->d - 1] = '.';
}
/* Handle decimal shift. */
- if ((cat & FCAT_SHIFT_DECIMAL) && number != SYSMIS && fp->d)
+ if ((category & (FMT_CAT_LEGACY | FMT_CAT_BINARY))
+ && number != SYSMIS
+ && fp->d)
number *= pow (10.0, fp->d);
switch (fp->type)
/* The C locale always uses a period `.' as a decimal point.
Translate to comma if necessary. */
- if ((get_decimal() == ',' && fp->type != FMT_DOT)
- || (get_decimal() == '.' && fp->type == FMT_DOT))
+ if (fmt_decimal_char (fp->type) != '.')
{
char *cp = strchr (buf, '.');
if (cp)
- *cp = ',';
+ *cp = fmt_decimal_char (fp->type);
}
memcpy (dst, buf, fp->w);
if (i % 3 == 0 && n_digits > i && n_items > n_reserved)
{
n_items--;
- *dst++ = fp->type == FMT_COMMA ? get_grouping() : get_decimal();
+ *dst++ = fmt_grouping_char (fp->type);
}
*dst++ = *sp++;
}
static int
try_CCx (char *dst, const struct fmt_spec *fp, double number)
{
- const struct custom_currency *cc = get_cc(fp->type - FMT_CCA);
+ const struct fmt_number_style *style = fmt_get_style (fp->type);
struct fmt_spec f;
/* Determine length available, decimal character for number
proper. */
- f.type = cc->decimal == get_decimal () ? FMT_COMMA : FMT_DOT;
- f.w = fp->w - strlen (cc->prefix) - strlen (cc->suffix);
+ f.type = style->decimal == fmt_decimal_char (FMT_COMMA) ? FMT_COMMA : FMT_DOT;
+ f.w = fp->w - fmt_affix_width (style);
if (number < 0)
- f.w -= strlen (cc->neg_prefix) + strlen (cc->neg_suffix) - 1;
+ f.w -= fmt_neg_affix_width (style) - 1;
else
/* Convert -0 to +0. */
number = fabs (number);
/* Postprocess back into buf. */
cp = buf;
if (number < 0)
- cp = stpcpy (cp, cc->neg_prefix);
- cp = stpcpy (cp, cc->prefix);
+ cp = mempcpy (cp, ss_data (style->neg_prefix),
+ ss_length (style->neg_prefix));
+ cp = mempcpy (cp, ss_data (style->prefix), ss_length (style->prefix));
{
char *bp = buf2;
while (*bp == ' ')
memcpy (cp, bp, f.w - (bp - buf2));
cp += f.w - (bp - buf2);
}
- cp = stpcpy (cp, cc->suffix);
+ cp = mempcpy (cp, ss_data (style->suffix), ss_length (style->suffix));
if (number < 0)
- cp = stpcpy (cp, cc->neg_suffix);
+ cp = mempcpy (cp, ss_data (style->neg_suffix),
+ ss_length (style->neg_suffix));
/* Copy into dst. */
assert (cp - buf <= fp->w);
mv_init (&v->miss, width);
if (v->type == NUMERIC)
{
- v->print = f8_2;
+ v->print = fmt_for_output (FMT_F, 8, 2);
v->alignment = ALIGN_RIGHT;
v->display_width = 8;
v->measure = MEASURE_SCALE;
}
else
{
- v->print = make_output_format (FMT_A, v->width, 0);
+ v->print = fmt_for_output (FMT_A, v->width, 0);
v->alignment = ALIGN_LEFT;
v->display_width = 8;
v->measure = MEASURE_NOMINAL;
02110-1301, USA. */
#include <config.h>
+
#include "format.h"
+
#include <ctype.h>
-#include <libpspp/assertion.h>
-#include <libpspp/message.h>
#include <stdlib.h>
+
+#include <data/identifier.h>
+#include <data/settings.h>
+#include <data/variable.h>
+#include <libpspp/assertion.h>
#include <libpspp/compiler.h>
+#include <libpspp/message.h>
#include <libpspp/misc.h>
-#include "identifier.h"
#include <libpspp/str.h>
-#include "variable.h"
+
+#include "minmax.h"
+#include "xalloc.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
-#define DEFFMT(LABEL, NAME, N_ARGS, IMIN_W, IMAX_W, OMIN_W, OMAX_W, CAT, \
- OUTPUT, SPSS_FMT) \
- {NAME, N_ARGS, IMIN_W, IMAX_W, OMIN_W, OMAX_W, CAT, OUTPUT, SPSS_FMT},
-const struct fmt_desc formats[FMT_NUMBER_OF_FORMATS + 1] =
-{
-#include "format.def"
- {"", -1, -1, -1, -1, -1, 0000, -1, -1},
-};
+static bool is_fmt_type (enum fmt_type);
-/* Common formats. */
-const struct fmt_spec f8_2 = {FMT_F, 8, 2};
+static int min_width (enum fmt_type, bool for_input);
+static int max_width (enum fmt_type);
+static bool valid_width (enum fmt_type, int width, bool for_input);
+static int max_decimals (enum fmt_type, int width, bool for_input);
-/* Tries to parse NAME as a format type.
- If successful, stores the type in *TYPE and returns true.
- On failure, returns false. */
-bool
-fmt_type_from_string (const char *name, int *type)
+static int max_digits_for_bytes (int bytes);
+
+/* Initialize the format module. */
+void
+fmt_init (void)
{
- int i;
+ static bool inited = false;
+ if (!inited)
+ {
+ inited = true;
+ fmt_set_decimal ('.');
+ }
+}
- for (i = 0; i < FMT_NUMBER_OF_FORMATS; i++)
- if (!strcasecmp (name, formats[i].name))
- {
- *type = i;
- return true;
- }
- return false;
+/* Deinitialize the format module. */
+void
+fmt_done (void)
+{
}
-/* Converts F to its string representation (for instance, "F8.2") and
- returns a pointer to a static buffer containing that string.
- If F has decimals, then they are included in the output
- string, even if F's format type does not, so that we can
- accurately present incorrect formats to the user. */
-char *
-fmt_to_string (const struct fmt_spec *f)
+/* Returns an input format specification with type TYPE, width W,
+ and D decimals. */
+struct fmt_spec
+fmt_for_input (enum fmt_type type, int w, int d)
{
- static char buf[32];
+ struct fmt_spec f;
+ f.type = type;
+ f.w = w;
+ f.d = d;
+ assert (fmt_check_input (&f));
+ return f;
+}
- if (formats[f->type].n_args >= 2 || f->d > 0)
- sprintf (buf, "%s%d.%d", formats[f->type].name, f->w, f->d);
- else
- sprintf (buf, "%s%d", formats[f->type].name, f->w);
- return buf;
+/* Returns an output format specification with type TYPE, width
+ W, and D decimals. */
+struct fmt_spec
+fmt_for_output (enum fmt_type type, int w, int d)
+{
+ struct fmt_spec f;
+ f.type = type;
+ f.w = w;
+ f.d = d;
+ assert (fmt_check_output (&f));
+ return f;
}
-/* Does checks in common betwen check_input_specifier() and
- check_output_specifier() and returns true if so. Otherwise,
- emits an error message (if EMIT_ERROR is nonzero) and returns
- false. */
-static bool
-check_common_specifier (const struct fmt_spec *spec, bool emit_error)
+/* Returns the output format specifier corresponding to input
+ format specifier INPUT. */
+struct fmt_spec
+fmt_for_output_from_input (const struct fmt_spec *input)
{
- const struct fmt_desc *f ;
- char *str;
+ struct fmt_spec output;
+
+ assert (fmt_check_input (input));
- assert (spec->type < FMT_NUMBER_OF_FORMATS);
- f = &formats[spec->type];
- str = fmt_to_string (spec);
+ output.type = fmt_input_to_output (input->type);
+ output.w = input->w;
+ if (output.w > fmt_max_output_width (output.type))
+ output.w = fmt_max_output_width (output.type);
+ else if (output.w < fmt_min_output_width (output.type))
+ output.w = fmt_min_output_width (output.type);
+ output.d = input->d;
- if ((f->cat & FCAT_EVEN_WIDTH) && spec->w % 2)
+ switch (input->type)
{
- if (emit_error)
- msg (SE, _("Format %s specifies an odd width %d, but "
- "an even width is required."),
- str, spec->w);
- return false;
+ case FMT_Z:
+ output.w++;
+ if (output.d > 0)
+ output.w++;
+ break;
+
+ case FMT_F:
+ case FMT_COMMA:
+ case FMT_DOT:
+ case FMT_DOLLAR:
+ case FMT_PCT:
+ {
+ const struct fmt_number_style *style = fmt_get_style (input->type);
+ output.w += fmt_affix_width (style);
+ if (style->grouping != 0 && input->w - input->d >= 3)
+ output.w += (input->w - input->d - 1) / 3;
+ if (output.d > 0)
+ output.w++;
+ }
+ break;
+
+ case FMT_N:
+ if (output.d > 0)
+ output.w++;
+ break;
+
+ case FMT_E:
+ output.d = MAX (input->d, 3);
+ output.w = MAX (input->w, output.d + 7);
+ break;
+
+ case FMT_PIBHEX:
+ output.w = max_digits_for_bytes (input->w / 2) + 1;
+ break;
+
+ case FMT_RB:
+ case FMT_RBHEX:
+ output.w = 8;
+ output.d = 2;
+ break;
+
+ case FMT_P:
+ case FMT_PK:
+ output.w = 2 * input->w + (input->d > 0);
+ break;
+
+ case FMT_IB:
+ case FMT_PIB:
+ output.w = max_digits_for_bytes (input->w) + 1;
+ if (output.d > 0)
+ output.w++;
+ break;
+
+ case FMT_CCA:
+ case FMT_CCB:
+ case FMT_CCC:
+ case FMT_CCD:
+ case FMT_CCE:
+ NOT_REACHED ();
+
+ case FMT_A:
+ break;
+
+ case FMT_AHEX:
+ output.w = input->w / 2;
+ break;
+
+ case FMT_DATE:
+ case FMT_EDATE:
+ case FMT_SDATE:
+ case FMT_ADATE:
+ case FMT_JDATE:
+ case FMT_QYR:
+ case FMT_MOYR:
+ case FMT_WKYR:
+ case FMT_TIME:
+ case FMT_DTIME:
+ case FMT_DATETIME:
+ case FMT_WKDAY:
+ case FMT_MONTH:
+ break;
+
+ default:
+ NOT_REACHED ();
}
- if (f->n_args > 1 && (spec->d < 0 || spec->d > 16))
+
+ if (output.w > fmt_max_output_width (output.type))
+ output.w = fmt_max_output_width (output.type);
+
+ assert (fmt_check_output (&output));
+ return output;
+}
+
+/* Checks whether SPEC is valid as an input format (if FOR_INPUT)
+ or an output format (otherwise) and returns nonzero if so.
+ Otherwise, emits an error message and returns zero. */
+bool
+fmt_check (const struct fmt_spec *spec, bool for_input)
+{
+ const char *io_fmt = for_input ? _("Input format") : _("Output format");
+ char str[FMT_STRING_LEN_MAX + 1];
+ int min_w, max_w, max_d;
+
+ assert (is_fmt_type (spec->type));
+ fmt_to_string (spec, str);
+
+ if (for_input && !fmt_usable_for_input (spec->type))
{
- if (emit_error)
- msg (SE, _("Format %s specifies a bad number of "
- "implied decimal places %d. Format type %s allows "
- "up to 16 implied decimal places."), str, spec->d, f->name);
+ msg (SE, _("Format %s may not be used for input."), str);
return false;
}
- if (f->n_args <= 1 && spec->d)
+
+ if (spec->w % fmt_step_width (spec->type))
{
- if (emit_error)
- msg (SE, _("Format %s specifies %d decimal places, but "
- "format type %s does not allow for decimal places."),
- str, spec->d, f->name);
+ assert (fmt_step_width (spec->type) == 2);
+ msg (SE, _("%s specifies width %d, but %s requires an even width."),
+ str, spec->w, fmt_name (spec->type));
return false;
}
- return true;
-}
-/* Checks whether SPEC is valid as an input format and returns
- nonzero if so. Otherwise, emits an error message (if
- EMIT_ERROR is nonzero) and returns zero. */
-int
-check_input_specifier (const struct fmt_spec *spec, int emit_error)
-{
- const struct fmt_desc *f;
- char *str ;
-
- if (!check_common_specifier (spec, emit_error))
- return false;
-
- f = &formats[spec->type];
- str = fmt_to_string (spec);
- if (f->cat & FCAT_OUTPUT_ONLY)
+ min_w = min_width (spec->type, for_input);
+ max_w = max_width (spec->type);
+ if (spec->w < min_w || spec->w > max_w)
{
- if (emit_error)
- msg (SE, _("Format %s may not be used for input."), f->name);
- return 0;
+ msg (SE, _("%s %s specifies width %d, but "
+ "%s requires a width between %d and %d."),
+ io_fmt, str, spec->w, fmt_name (spec->type), min_w, max_w);
+ return false;
}
- if (spec->w < f->Imin_w || spec->w > f->Imax_w)
+
+ max_d = max_decimals (spec->type, spec->w, for_input);
+ if (!fmt_takes_decimals (spec->type) && spec->d != 0)
{
- if (emit_error)
- msg (SE, _("Input format %s specifies a bad width %d. "
- "Format %s requires a width between %d and %d."),
- str, spec->w, f->name, f->Imin_w, f->Imax_w);
- return 0;
+ msg (SE, ngettext ("%s %s specifies %d decimal place, but "
+ "%s does not allow any decimals.",
+ "%s %s specifies %d decimal places, but "
+ "%s does not allow any decimals.",
+ spec->d),
+ io_fmt, str, spec->d, fmt_name (spec->type));
+ return false;
}
- if ((spec->type == FMT_F || spec->type == FMT_COMMA
- || spec->type == FMT_DOLLAR)
- && spec->d > spec->w)
+ else if (spec->d > max_d)
{
- if (emit_error)
- msg (SE, _("Input format %s is invalid because it specifies more "
- "decimal places than the field width."), str);
- return 0;
+ if (max_d > 0)
+ msg (SE, ngettext ("%s %s specifies %d decimal place, but "
+ "the given width allows at most %d decimals.",
+ "%s %s specifies %d decimal places, but "
+ "the given width allows at most %d decimals.",
+ spec->d),
+ io_fmt, str, spec->d, max_d);
+ else
+ msg (SE, ngettext ("%s %s specifies %d decimal place, but "
+ "the given width does not allow for any decimals.",
+ "%s %s specifies %d decimal places, but "
+ "the given width does not allow for any decimals.",
+ spec->d),
+ io_fmt, str, spec->d);
+ return false;
}
- return 1;
+
+ return true;
}
-/* Checks whether SPEC is valid as an output format and returns
- nonzero if so. Otherwise, emits an error message (if
- EMIT_ERROR is nonzero) and returns zero. */
-int
-check_output_specifier (const struct fmt_spec *spec, int emit_error)
+/* Checks whether SPEC is valid as an input format and returns
+ nonzero if so. Otherwise, emits an error message and returns
+ zero. */
+bool
+fmt_check_input (const struct fmt_spec *spec)
{
- const struct fmt_desc *f;
- char *str ;
-
- if (!check_common_specifier (spec, emit_error))
- return false;
+ return fmt_check (spec, true);
+}
- f = &formats[spec->type];
- str = fmt_to_string (spec);
- if (spec->w < f->Omin_w || spec->w > f->Omax_w)
- {
- if (emit_error)
- msg (SE, _("Output format %s specifies a bad width %d. "
- "Format %s requires a width between %d and %d."),
- str, spec->w, f->name, f->Omin_w, f->Omax_w);
- return 0;
- }
- if ((spec->type == FMT_F || spec->type == FMT_COMMA
- || spec->type == FMT_DOLLAR)
- && spec->d >= spec->w)
- {
- if (emit_error)
- msg (SE, _("Output format %s is invalid because it specifies as "
- "many decimal places as the field width, which "
- "fails to allow space for a decimal point. "
- "Try %s%d.%d instead."),
- str, f->name, spec->d + 1, spec->d);
- return 0;
- }
- return 1;
+/* Checks whether SPEC is valid as an output format and returns
+ true if so. Otherwise, emits an error message and returns false. */
+bool
+fmt_check_output (const struct fmt_spec *spec)
+{
+ return fmt_check (spec, false);
}
/* Checks that FORMAT is appropriate for a variable of the given
- TYPE and returns true if so. Otherwise returns false and (if
- EMIT_ERROR is true) emits an error message. */
+ TYPE and returns true if so. Otherwise returns false and
+ emits an error message. */
bool
-check_specifier_type (const struct fmt_spec *format,
- int type, bool emit_error)
+fmt_check_type_compat (const struct fmt_spec *format, int var_type)
{
- const struct fmt_desc *f = &formats[format->type];
- assert (type == NUMERIC || type == ALPHA);
- if ((type == ALPHA) != ((f->cat & FCAT_STRING) != 0))
+ assert (var_type == NUMERIC || var_type == ALPHA);
+ if ((var_type == ALPHA) != (fmt_is_string (format->type) != 0))
{
- if (emit_error)
- msg (SE, _("%s variables are not compatible with %s format %s."),
- type == ALPHA ? _("String") : _("Numeric"),
- type == ALPHA ? _("numeric") : _("string"),
- fmt_to_string (format));
+ char str[FMT_STRING_LEN_MAX + 1];
+ msg (SE, _("%s variables are not compatible with %s format %s."),
+ var_type == ALPHA ? _("String") : _("Numeric"),
+ var_type == ALPHA ? _("numeric") : _("string"),
+ fmt_to_string (format, str));
return false;
}
return true;
}
-
+
/* Checks that FORMAT is appropriate for a variable of the given
- WIDTH and returns true if so. Otherwise returns false and (if
- EMIT_ERROR is true) emits an error message. */
+ WIDTH and returns true if so. Otherwise returns false and
+ emits an error message. */
bool
-check_specifier_width (const struct fmt_spec *format,
- int width, bool emit_error)
+fmt_check_width_compat (const struct fmt_spec *format, int width)
{
- if (!check_specifier_type (format, width != 0 ? ALPHA : NUMERIC, emit_error))
+ if (!fmt_check_type_compat (format, width != 0 ? ALPHA : NUMERIC))
return false;
- if (get_format_var_width (format) != width)
+ if (fmt_var_width (format) != width)
{
- if (emit_error)
- msg (SE, _("String variable with width %d not compatible with "
- "format %s."),
- width, fmt_to_string (format));
+ char str[FMT_STRING_LEN_MAX + 1];
+ msg (SE, _("String variable with width %d is not compatible with "
+ "format %s."),
+ width, fmt_to_string (format, str));
return false;
}
return true;
}
-/* Converts input format specifier INPUT into output format
- specifier OUTPUT. */
-void
-convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output)
+/* Returns the width corresponding to the format specifier. The
+ return value is the value of the `width' member of a `struct
+ variable' for such an input format. */
+int
+fmt_var_width (const struct fmt_spec *spec)
{
- assert (check_input_specifier (input, 0));
+ return (spec->type == FMT_AHEX ? spec->w / 2
+ : spec->type == FMT_A ? spec->w
+ : 0);
+}
- output->type = formats[input->type].output;
- output->w = input->w;
- if (output->w > formats[output->type].Omax_w)
- output->w = formats[output->type].Omax_w;
- output->d = input->d;
+/* Converts F to its string representation (for instance, "F8.2")
+ in BUFFER. Returns BUFFER.
- switch (input->type)
+ If F has decimals, they are included in the output string,
+ even if F's format type does not allow decimals, to allow
+ accurately presenting incorrect formats to the user. */
+char *
+fmt_to_string (const struct fmt_spec *f, char buffer[FMT_STRING_LEN_MAX + 1])
+{
+ if (fmt_takes_decimals (f->type) || f->d > 0)
+ snprintf (buffer, FMT_STRING_LEN_MAX + 1,
+ "%s%d.%d", fmt_name (f->type), f->w, f->d);
+ else
+ snprintf (buffer, FMT_STRING_LEN_MAX + 1,
+ "%s%d", fmt_name (f->type), f->w);
+ return buffer;
+}
+\f
+/* Describes a display format. */
+struct fmt_desc
+ {
+ char name[9];
+ int min_input_width, min_output_width;
+ int io;
+ enum fmt_category category;
+ };
+
+static const struct fmt_desc *get_fmt_desc (enum fmt_type type);
+
+/* Returns the name of the given format TYPE. */
+const char *
+fmt_name (enum fmt_type type)
+{
+ return get_fmt_desc (type)->name;
+}
+
+/* Tries to parse NAME as a format type.
+ If successful, stores the type in *TYPE and returns true.
+ On failure, returns false. */
+bool
+fmt_from_name (const char *name, enum fmt_type *type)
+{
+ int i;
+
+ for (i = 0; i < FMT_NUMBER_OF_FORMATS; i++)
+ if (!strcasecmp (name, get_fmt_desc (i)->name))
+ {
+ *type = i;
+ return true;
+ }
+ return false;
+}
+
+/* Returns true if TYPE accepts decimal places,
+ false otherwise. */
+bool
+fmt_takes_decimals (enum fmt_type type)
+{
+ return fmt_max_output_decimals (type, fmt_max_output_width (type)) > 0;
+}
+
+/* Returns the minimum acceptable width for an input field
+ formatted with the given TYPE. */
+int
+fmt_min_input_width (enum fmt_type type)
+{
+ return get_fmt_desc (type)->min_input_width;
+}
+
+/* Returns the maximum acceptable width for an input field
+ formatted with the given TYPE. */
+int
+fmt_max_input_width (enum fmt_type type)
+{
+ return max_width (type);
+}
+
+/* Returns the maximum number of decimal places allowed in an
+ input field of the given TYPE and WIDTH. */
+int
+fmt_max_input_decimals (enum fmt_type type, int width)
+{
+ assert (valid_width (type, width, true));
+ return max_decimals (type, width, true);
+}
+
+/* Returns the minimum acceptable width for an output field
+ formatted with the given TYPE. */
+int
+fmt_min_output_width (enum fmt_type type)
+{
+ return get_fmt_desc (type)->min_output_width;
+}
+
+/* Returns the maximum acceptable width for an output field
+ formatted with the given TYPE. */
+int
+fmt_max_output_width (enum fmt_type type)
+{
+ return max_width (type);
+}
+
+/* Returns the maximum number of decimal places allowed in an
+ output field of the given TYPE and WIDTH. */
+int
+fmt_max_output_decimals (enum fmt_type type, int width)
+{
+ assert (valid_width (type, width, false));
+ return max_decimals (type, width, false);
+}
+
+/* Returns the width step for a field formatted with the given
+ TYPE. Field width must be a multiple of the width step. */
+int
+fmt_step_width (enum fmt_type type)
+{
+ return fmt_get_category (type) & FMT_CAT_HEXADECIMAL ? 2 : 1;
+}
+
+/* Returns true if TYPE is used for string fields,
+ false if it is used for numeric fields. */
+bool
+fmt_is_string (enum fmt_type type)
+{
+ return fmt_get_category (type) & FMT_CAT_STRING;
+}
+
+/* Returns true if TYPE is used for numeric fields,
+ false if it is used for string fields. */
+bool
+fmt_is_numeric (enum fmt_type type)
+{
+ return !fmt_is_string (type);
+}
+
+/* Returns the format TYPE's category.
+ Each format type is in exactly one category,
+ and each category's value is bitwise disjoint from every other
+ category. Thus, the return value may be tested for equality
+ or compared bitwise against a mask of FMT_CAT_* values. */
+enum fmt_category
+fmt_get_category (enum fmt_type type)
+{
+ return get_fmt_desc (type)->category;
+}
+
+/* Returns the output format selected by default when TYPE is
+ used as an input format. */
+enum fmt_type
+fmt_input_to_output (enum fmt_type type)
+{
+ enum fmt_category category = fmt_get_category (type);
+ return (category & FMT_CAT_STRING ? FMT_A
+ : category & (FMT_CAT_BASIC | FMT_CAT_HEXADECIMAL) ? FMT_F
+ : type);
+}
+
+/* Returns the SPSS format type corresponding to the given PSPP
+ format type. */
+int
+fmt_to_io (enum fmt_type type)
+{
+ return get_fmt_desc (type)->io;
+};
+
+/* Determines the PSPP format corresponding to the given SPSS
+ format type. If successful, sets *FMT_TYPE to the PSPP format
+ and returns true. On failure, return false. */
+bool
+fmt_from_io (int io, enum fmt_type *fmt_type)
+{
+ enum fmt_type type;
+
+ for (type = 0; type < FMT_NUMBER_OF_FORMATS; type++)
+ if (get_fmt_desc (type)->io == io)
+ {
+ *fmt_type = type;
+ return true;
+ }
+ return false;
+}
+
+/* Returns true if TYPE may be used as an input format,
+ false otherwise. */
+bool
+fmt_usable_for_input (enum fmt_type type)
+{
+ assert (is_fmt_type (type));
+ return fmt_get_category (type) != FMT_CAT_CUSTOM;
+}
+
+/* For time and date formats, returns a template used for input
+ and output. */
+const char *
+fmt_date_template (enum fmt_type type)
+{
+ switch (type)
+ {
+ case FMT_DATE:
+ return "dd-mmm-yy";
+ case FMT_ADATE:
+ return "mm/dd/yy";
+ case FMT_EDATE:
+ return "dd.mm.yy";
+ case FMT_JDATE:
+ return "yyddd";
+ case FMT_SDATE:
+ return "yy/mm/dd";
+ case FMT_QYR:
+ return "q Q yy";
+ case FMT_MOYR:
+ return "mmm yy";
+ case FMT_WKYR:
+ return "ww WK yy";
+ case FMT_DATETIME:
+ return "dd-mmm-yyyy HH:MM";
+ case FMT_TIME:
+ return "h:MM";
+ case FMT_DTIME:
+ return "D HH:MM";
+ default:
+ NOT_REACHED ();
+ }
+}
+\f
+/* Returns true if TYPE is a valid format type,
+ false otherwise. */
+static bool
+is_fmt_type (enum fmt_type type)
+{
+ return type < FMT_NUMBER_OF_FORMATS;
+}
+
+/* Returns the minimum width of the given format TYPE,
+ for input if FOR_INPUT is true,
+ for output otherwise. */
+static int
+min_width (enum fmt_type type, bool for_input)
+{
+ return for_input ? fmt_min_input_width (type) : fmt_min_output_width (type);
+}
+
+/* Returns the maximum width of the given format TYPE,
+ which is invariant between input and output. */
+static int
+max_width (enum fmt_type type)
+{
+ assert (is_fmt_type (type));
+ switch (type)
+ {
+ case FMT_P:
+ case FMT_PK:
+ case FMT_PIBHEX:
+ case FMT_RBHEX:
+ return 16;
+
+ case FMT_IB:
+ case FMT_PIB:
+ case FMT_RB:
+ return 8;
+
+ case FMT_A:
+ return MAX_STRING;
+
+ case FMT_AHEX:
+ return 2 * MAX_STRING;
+
+ default:
+ return 40;
+ }
+}
+
+/* Returns true if WIDTH is a valid width for the given format
+ TYPE,
+ for input if FOR_INPUT is true,
+ for output otherwise. */
+static bool
+valid_width (enum fmt_type type, int width, bool for_input)
+{
+ return (width >= min_width (type, for_input)
+ && width <= max_width (type));
+}
+
+/* Returns the maximum number of decimal places allowed for the
+ given format TYPE with a width of WIDTH places,
+ for input if FOR_INPUT is true,
+ for output otherwise. */
+static int
+max_decimals (enum fmt_type type, int width, bool for_input)
+{
+ int max_d;
+
+ switch (type)
{
case FMT_F:
- case FMT_N:
- if (output->d > 0)
- output->w++;
- break;
- case FMT_E:
- output->w = max (max (input->w, input->d+7), 10);
- output->d = max (input->d, 3);
- break;
case FMT_COMMA:
case FMT_DOT:
- /* nothing is necessary */
+ max_d = for_input ? width : width - 1;
break;
+
case FMT_DOLLAR:
case FMT_PCT:
- if (output->w < 2)
- output->w = 2;
+ max_d = for_input ? width : width - 2;
break;
- case FMT_PIBHEX:
- {
- static const int map[] = {4, 6, 9, 11, 14, 16, 18, 21};
- assert (input->w % 2 == 0 && input->w >= 2 && input->w <= 16);
- output->w = map[input->w / 2 - 1];
- break;
- }
- case FMT_RBHEX:
- output->w = 8, output->d = 2; /* FIXME */
- break;
- case FMT_IB:
- case FMT_PIB:
- case FMT_P:
- case FMT_PK:
- case FMT_RB:
- if (input->d < 1)
- output->w = 8, output->d = 2;
- else
- output->w = 9 + input->d;
+
+ case FMT_E:
+ max_d = for_input ? width : width - 7;
break;
+
case FMT_CCA:
case FMT_CCB:
case FMT_CCC:
case FMT_CCD:
case FMT_CCE:
- NOT_REACHED ();
+ assert (!for_input);
+ max_d = width - 1;
+ break;
+
+ case FMT_N:
case FMT_Z:
- case FMT_A:
- /* nothing is necessary */
+ max_d = width;
break;
- case FMT_AHEX:
- output->w = input->w / 2;
+
+ case FMT_P:
+ max_d = width * 2 - 1;
+ break;
+
+ case FMT_PK:
+ max_d = width * 2;
+ break;
+
+ case FMT_IB:
+ case FMT_PIB:
+ max_d = max_digits_for_bytes (width);
break;
+
+ case FMT_PIBHEX:
+ max_d = 0;
+ break;
+
+ case FMT_RB:
+ case FMT_RBHEX:
+ max_d = 16;
+ break;
+
case FMT_DATE:
- case FMT_EDATE:
- case FMT_SDATE:
case FMT_ADATE:
+ case FMT_EDATE:
case FMT_JDATE:
- /* nothing is necessary */
- break;
+ case FMT_SDATE:
case FMT_QYR:
- if (output->w < 6)
- output->w = 6;
- break;
case FMT_MOYR:
- /* nothing is necessary */
- break;
case FMT_WKYR:
- if (output->w < 8)
- output->w = 8;
+ max_d = 0;
+ break;
+
+ case FMT_DATETIME:
+ max_d = width - 21;
break;
+
case FMT_TIME:
+ max_d = width - 9;
+ break;
+
case FMT_DTIME:
- case FMT_DATETIME:
+ max_d = width - 12;
+ break;
+
case FMT_WKDAY:
case FMT_MONTH:
- /* nothing is necessary */
+ case FMT_A:
+ case FMT_AHEX:
+ max_d = 0;
break;
+
default:
NOT_REACHED ();
}
- assert (check_output_specifier (output, 0));
+ if (max_d < 0)
+ max_d = 0;
+ else if (max_d > 16)
+ max_d = 16;
+ return max_d;
}
-/* Returns the width corresponding to the format specifier. The
- return value is the value of the `width' member of a `struct
- variable' for such an input format. */
+/* Returns the maximum number of decimal digits in an unsigned
+ binary number that is BYTES bytes long. */
+static int
+max_digits_for_bytes (int bytes)
+{
+ int map[8] = {3, 5, 8, 10, 13, 15, 17, 20};
+ assert (bytes > 0 && bytes <= sizeof map / sizeof *map);
+ return map[bytes - 1];
+}
+\f
+static struct fmt_number_style *styles[FMT_NUMBER_OF_FORMATS];
+
+/* Creates and returns a new struct fmt_number_style,
+ initializing all affixes to empty strings. */
+struct fmt_number_style *
+fmt_number_style_create (void)
+{
+ struct fmt_number_style *style = xmalloc (sizeof *style);
+ style->neg_prefix = ss_empty ();
+ style->prefix = ss_empty ();
+ style->suffix = ss_empty ();
+ style->neg_suffix = ss_empty ();
+ style->decimal = '.';
+ style->grouping = 0;
+ return style;
+}
+
+/* Destroys a struct fmt_number_style. */
+void
+fmt_number_style_destroy (struct fmt_number_style *style)
+{
+ if (style != NULL)
+ {
+ ss_dealloc (&style->neg_prefix);
+ ss_dealloc (&style->prefix);
+ ss_dealloc (&style->suffix);
+ ss_dealloc (&style->neg_suffix);
+ free (style);
+ }
+}
+
+/* Returns the number formatting style associated with the given
+ format TYPE. */
+const struct fmt_number_style *
+fmt_get_style (enum fmt_type type)
+{
+ assert (is_fmt_type (type));
+ assert (styles[type] != NULL);
+ return styles[type];
+}
+
+/* Sets STYLE as the number formatting style associated with the
+ given format TYPE, transferring ownership of STYLE. */
+void
+fmt_set_style (enum fmt_type type, struct fmt_number_style *style)
+{
+ assert (ss_length (style->neg_prefix) <= FMT_STYLE_AFFIX_MAX);
+ assert (ss_length (style->prefix) <= FMT_STYLE_AFFIX_MAX);
+ assert (ss_length (style->suffix) <= FMT_STYLE_AFFIX_MAX);
+ assert (ss_length (style->neg_suffix) <= FMT_STYLE_AFFIX_MAX);
+ assert (style->decimal == '.' || style->decimal == ',');
+ assert (style->grouping != style->decimal
+ && (style->grouping == '.' || style->grouping == ','
+ || style->grouping == 0));
+
+ assert (fmt_get_category (type) == FMT_CAT_CUSTOM);
+ assert (styles[type] != NULL);
+
+ fmt_number_style_destroy (styles[type]);
+ styles[type] = style;
+}
+
+/* Returns the total width of the standard prefix and suffix for
+ STYLE. */
int
-get_format_var_width (const struct fmt_spec *spec)
+fmt_affix_width (const struct fmt_number_style *style)
{
- if (spec->type == FMT_AHEX)
- return spec->w / 2;
- else if (spec->type == FMT_A)
- return spec->w;
- else
- return 0;
+ return ss_length (style->prefix) + ss_length (style->suffix);
}
-/* Returns the PSPP format corresponding to the given SPSS
- format. */
+/* Returns the total width of the negative prefix and suffix for
+ STYLE. */
int
-translate_fmt (int spss)
+fmt_neg_affix_width (const struct fmt_number_style *style)
{
- int type;
-
- for (type = 0; type < FMT_NUMBER_OF_FORMATS; type++)
- if (formats[type].spss == spss)
- return type;
- return -1;
+ return ss_length (style->neg_prefix) + ss_length (style->neg_suffix);
}
-/* Returns an input format specification with type TYPE, width W,
- and D decimals. */
-struct fmt_spec
-make_input_format (int type, int w, int d)
+/* Returns the decimal point character for the given format
+ TYPE. */
+int
+fmt_decimal_char (enum fmt_type type)
{
- struct fmt_spec f;
- f.type = type;
- f.w = w;
- f.d = d;
- assert (check_input_specifier (&f, 0));
- return f;
+ return fmt_get_style (type)->decimal;
}
-/* Returns an output format specification with type TYPE, width
- W, and D decimals. */
-struct fmt_spec
-make_output_format (int type, int w, int d)
+/* Returns the grouping character for the given format TYPE, or 0
+ if the format type does not group digits. */
+int
+fmt_grouping_char (enum fmt_type type)
{
- struct fmt_spec f;
- f.type = type;
- f.w = w;
- f.d = d;
- assert (check_output_specifier (&f, 0));
- return f;
+ return fmt_get_style (type)->grouping;
}
-/* Returns true if TYPE is a binary format,
- false otherwise. */
-bool
-fmt_is_binary (int type)
+/* Sets the number style for TYPE to have the given standard
+ PREFIX and SUFFIX, "-" as prefix suffix, an empty negative
+ suffix, DECIMAL as the decimal point character, and GROUPING
+ as the grouping character. */
+static void
+set_style (enum fmt_type type,
+ const char *prefix, const char *suffix,
+ char decimal, char grouping)
{
- switch (type)
- {
- case FMT_P:
- case FMT_PK:
- case FMT_IB:
- case FMT_PIB:
- case FMT_RB:
- return true;
+ struct fmt_number_style *style;
- default:
- return false;
- }
+ assert (is_fmt_type (type));
+
+ fmt_number_style_destroy (styles[type]);
+
+ style = styles[type] = fmt_number_style_create ();
+ ss_alloc_substring (&style->neg_prefix, ss_cstr ("-"));
+ ss_alloc_substring (&style->prefix, ss_cstr (prefix));
+ ss_alloc_substring (&style->suffix, ss_cstr (suffix));
+ style->decimal = decimal;
+ style->grouping = grouping;
}
-bool
-measure_is_valid(enum measure m)
+/* Sets the number style for TYPE as with set_style, but only if
+ TYPE has not already been initialized. */
+static void
+init_style (enum fmt_type type,
+ const char *prefix, const char *suffix,
+ char decimal, char grouping)
{
- if ( m <= 0 ) return false;
- if ( m >= n_MEASURES) return false;
- return true;
+ assert (is_fmt_type (type));
+ if (styles[type] == NULL)
+ set_style (type, prefix, suffix, decimal, grouping);
}
-bool
-alignment_is_valid(enum alignment a)
+/* Sets the decimal point character to DECIMAL. */
+void
+fmt_set_decimal (char decimal)
{
- if ( a >= n_ALIGN) return false;
- return true;
+ int grouping = decimal == '.' ? ',' : '.';
+ assert (decimal == '.' || decimal == ',');
+
+ set_style (FMT_F, "", "", decimal, 0);
+ set_style (FMT_E, "", "", decimal, 0);
+ set_style (FMT_COMMA, "", "", decimal, grouping);
+ set_style (FMT_DOT, "", "", grouping, decimal);
+ set_style (FMT_DOLLAR, "$", "", decimal, grouping);
+ set_style (FMT_PCT, "", "%", decimal, 0);
+
+ init_style (FMT_CCA, "", "", decimal, grouping);
+ init_style (FMT_CCB, "", "", decimal, grouping);
+ init_style (FMT_CCC, "", "", decimal, grouping);
+ init_style (FMT_CCD, "", "", decimal, grouping);
+ init_style (FMT_CCE, "", "", decimal, grouping);
+}
+\f
+/* Returns true if M is a valid variable measurement level,
+ false otherwise. */
+bool
+measure_is_valid (enum measure m)
+{
+ return m > 0 && m < n_MEASURES;
+}
+
+/* Returns true if A is a valid alignment,
+ false otherwise. */
+bool
+alignment_is_valid (enum alignment a)
+{
+ return a < n_ALIGN;
+}
+\f
+/* Returns the struct fmt_desc for the given format TYPE. */
+static const struct fmt_desc *
+get_fmt_desc (enum fmt_type type)
+{
+ static const struct fmt_desc formats[FMT_NUMBER_OF_FORMATS] =
+ {
+#define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
+ {#NAME, IMIN, OMIN, IO, CATEGORY},
+#include "format.def"
+ };
+
+ assert (is_fmt_type (type));
+ return &formats[type];
}
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
-/* Numeric and string formats. */
-DEFFMT (FMT_F, "F", 2, 1, 40, 1, 40, 0001, FMT_F, 5)
-DEFFMT (FMT_N, "N", 2, 1, 40, 1, 40, 0011, FMT_F, 16)
-DEFFMT (FMT_E, "E", 2, 1, 40, 6, 40, 0001, FMT_E, 17)
-DEFFMT (FMT_COMMA, "COMMA", 2, 1, 40, 1, 40, 0001, FMT_COMMA, 3)
-DEFFMT (FMT_DOT, "DOT", 2, 1, 40, 1, 40, 0001, FMT_DOT, 32)
-DEFFMT (FMT_DOLLAR, "DOLLAR", 2, 1, 40, 2, 40, 0001, FMT_DOLLAR, 4)
-DEFFMT (FMT_PCT, "PCT", 2, 1, 40, 2, 40, 0001, FMT_PCT, 31)
-DEFFMT (FMT_Z, "Z", 2, 1, 40, 1, 40, 0011, FMT_F, 15)
-DEFFMT (FMT_A, "A", 1, 1, MAX_STRING, 1, MAX_STRING, 0004, FMT_A, 1)
-DEFFMT (FMT_AHEX, "AHEX", 1, 2, 510, 2, 510, 0006, FMT_A, 2)
-DEFFMT (FMT_IB, "IB", 2, 1, 8, 1, 8, 0010, FMT_F, 6)
-DEFFMT (FMT_P, "P", 2, 1, 16, 1, 16, 0011, FMT_F, 8)
-DEFFMT (FMT_PIB, "PIB", 2, 1, 8, 1, 8, 0010, FMT_F, 9)
-DEFFMT (FMT_PIBHEX, "PIBHEX", 2, 2, 16, 2, 16, 0002, FMT_F, 7)
-DEFFMT (FMT_PK, "PK", 2, 1, 16, 1, 16, 0010, FMT_F, 10)
-DEFFMT (FMT_RB, "RB", 1, 2, 8, 2, 8, 0002, FMT_F, 11)
-DEFFMT (FMT_RBHEX, "RBHEX", 1, 4, 16, 4, 16, 0002, FMT_F, 12)
-
-/* Custom currency. */
-DEFFMT (FMT_CCA, "CCA", 2, -1, -1, 1, 40, 0020, FMT_CCA, 33)
-DEFFMT (FMT_CCB, "CCB", 2, -1, -1, 1, 40, 0020, FMT_CCB, 34)
-DEFFMT (FMT_CCC, "CCC", 2, -1, -1, 1, 40, 0020, FMT_CCC, 35)
-DEFFMT (FMT_CCD, "CCD", 2, -1, -1, 1, 40, 0020, FMT_CCD, 36)
-DEFFMT (FMT_CCE, "CCE", 2, -1, -1, 1, 40, 0020, FMT_CCE, 37)
-
-/* Date/time formats. */
-DEFFMT (FMT_DATE, "DATE", 1, 9, 40, 9, 40, 0001, FMT_DATE, 20)
-DEFFMT (FMT_EDATE, "EDATE", 1, 8, 40, 8, 40, 0001, FMT_EDATE, 38)
-DEFFMT (FMT_SDATE, "SDATE", 1, 8, 40, 8, 40, 0001, FMT_SDATE, 39)
-DEFFMT (FMT_ADATE, "ADATE", 1, 8, 40, 8, 40, 0001, FMT_ADATE, 23)
-DEFFMT (FMT_JDATE, "JDATE", 1, 5, 40, 5, 40, 0001, FMT_JDATE, 24)
-DEFFMT (FMT_QYR, "QYR", 1, 4, 40, 6, 40, 0001, FMT_QYR, 29)
-DEFFMT (FMT_MOYR, "MOYR", 1, 6, 40, 6, 40, 0001, FMT_MOYR, 28)
-DEFFMT (FMT_WKYR, "WKYR", 1, 6, 40, 8, 40, 0001, FMT_WKYR, 30)
-DEFFMT (FMT_DATETIME, "DATETIME", 2, 17, 40, 17, 40, 0001, FMT_DATETIME, 22)
-DEFFMT (FMT_TIME, "TIME", 2, 5, 40, 5, 40, 0001, FMT_TIME, 21)
-DEFFMT (FMT_DTIME, "DTIME", 2, 11, 40, 8, 40, 0001, FMT_DTIME, 25)
-DEFFMT (FMT_WKDAY, "WKDAY", 1, 2, 40, 2, 40, 0001, FMT_WKDAY, 26)
-DEFFMT (FMT_MONTH, "MONTH", 1, 3, 40, 3, 40, 0001, FMT_MONTH, 27)
+/* Basic numeric formats. */
+FMT (F, number, 1, 1, 5, FMT_CAT_BASIC)
+FMT (COMMA, number, 1, 1, 3, FMT_CAT_BASIC)
+FMT (DOT, number, 1, 1, 32, FMT_CAT_BASIC)
+FMT (DOLLAR, number, 1, 2, 4, FMT_CAT_BASIC)
+FMT (PCT, number, 1, 2, 31, FMT_CAT_BASIC)
+FMT (E, number, 1, 6, 17, FMT_CAT_BASIC)
+
+/* Custom currency formats. */
+FMT (CCA, number, -1, 2, 33, FMT_CAT_CUSTOM)
+FMT (CCB, number, -1, 2, 34, FMT_CAT_CUSTOM)
+FMT (CCC, number, -1, 2, 35, FMT_CAT_CUSTOM)
+FMT (CCD, number, -1, 2, 36, FMT_CAT_CUSTOM)
+FMT (CCE, number, -1, 2, 37, FMT_CAT_CUSTOM)
+
+/* Legacy numeric formats. */
+FMT (N, N, 1, 1, 16, FMT_CAT_LEGACY)
+FMT (Z, Z, 1, 1, 16, FMT_CAT_LEGACY)
+
+/* Binary and hexadecimal formats. */
+FMT (P, P, 1, 1, 8, FMT_CAT_BINARY)
+FMT (PK, PK, 1, 1, 10, FMT_CAT_BINARY)
+FMT (IB, IB, 1, 1, 6, FMT_CAT_BINARY)
+FMT (PIB, PIB, 1, 1, 9, FMT_CAT_BINARY)
+FMT (PIBHEX, PIBHEX, 2, 2, 7, FMT_CAT_HEXADECIMAL)
+FMT (RB, RB, 2, 2, 11, FMT_CAT_BINARY)
+FMT (RBHEX, RBHEX, 4, 4, 12, FMT_CAT_HEXADECIMAL)
+
+/* Time and date formats. */
+FMT (DATE, date, 8, 9, 20, FMT_CAT_DATE)
+FMT (ADATE, date, 8, 8, 23, FMT_CAT_DATE)
+FMT (EDATE, date, 8, 8, 38, FMT_CAT_DATE)
+FMT (JDATE, date, 5, 5, 24, FMT_CAT_DATE)
+FMT (SDATE, date, 8, 8, 39, FMT_CAT_DATE)
+FMT (QYR, date, 4, 6, 29, FMT_CAT_DATE)
+FMT (MOYR, date, 6, 6, 28, FMT_CAT_DATE)
+FMT (WKYR, date, 6, 8, 30, FMT_CAT_DATE)
+FMT (DATETIME, date, 7, 17, 22, FMT_CAT_DATE)
+FMT (TIME, date, 5, 5, 21, FMT_CAT_TIME)
+FMT (DTIME, date, 8, 8, 25, FMT_CAT_TIME)
+
+/* Date component formats. */
+FMT (WKDAY, WKDAY, 2, 2, 26, FMT_CAT_DATE_COMPONENT)
+FMT (MONTH, MONTH, 3, 3, 27, FMT_CAT_DATE_COMPONENT)
+
+/* String formats. */
+FMT (A, A, 1, 1, 1, FMT_CAT_STRING)
+FMT (AHEX, AHEX, 2, 2, 2, FMT_CAT_STRING)
+
+#undef FMT
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA. */
-#if !format_h
-#define format_h 1
+#ifndef FORMAT_H
+#define FORMAT_H 1
/* Display format types. */
#include <stdbool.h>
+#include <stddef.h>
+#include <libpspp/str.h>
-/* See the definitions of these functions and variables when modifying
- this list:
- misc.c:convert_fmt_ItoO()
- sys-file-reader.c:parse_format_spec()
- data-in.c:parse_string_as_format() */
-#define DEFFMT(LABEL, NAME, N_ARGS, IMIN_W, IMAX_W, OMIN_W, OMAX_W, \
- CAT, OUTPUT, SPSS_FMT) \
- LABEL,
-enum
+/* Format type categories. */
+enum fmt_category
{
+ /* Numeric formats. */
+ FMT_CAT_BASIC = 0x001, /* Basic numeric formats. */
+ FMT_CAT_CUSTOM = 0x002, /* Custom currency formats. */
+ FMT_CAT_LEGACY = 0x004, /* Legacy numeric formats. */
+ FMT_CAT_BINARY = 0x008, /* Binary formats. */
+ FMT_CAT_HEXADECIMAL = 0x010, /* Hexadecimal formats. */
+ FMT_CAT_DATE = 0x020, /* Date formats. */
+ FMT_CAT_TIME = 0x040, /* Time formats. */
+ FMT_CAT_DATE_COMPONENT = 0x080, /* Date component formats. */
+
+ /* String formats. */
+ FMT_CAT_STRING = 0x100 /* String formats. */
+ };
+
+enum fmt_type
+ {
+#define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) FMT_##NAME,
#include "format.def"
- FMT_NUMBER_OF_FORMATS
+ FMT_NUMBER_OF_FORMATS,
};
-#undef DEFFMT
/* Length of longest format specifier name,
not including terminating null. */
#define FMT_TYPE_LEN_MAX 8
-/* Describes one of the display formats above. */
-struct fmt_desc
- {
- char name[FMT_TYPE_LEN_MAX + 1]; /* Name, in all caps. */
- int n_args; /* 1=width; 2=width.decimals. */
- int Imin_w, Imax_w; /* Bounds on input width. */
- int Omin_w, Omax_w; /* Bounds on output width. */
- int cat; /* Categories. */
- int output; /* Output format. */
- int spss; /* Equivalent SPSS output format. */
- };
-
-/* Display format categories. */
-enum
- {
- FCAT_BLANKS_SYSMIS = 001, /* 1=All-whitespace means SYSMIS. */
- FCAT_EVEN_WIDTH = 002, /* 1=Width must be even. */
- FCAT_STRING = 004, /* 1=String input/output format. */
- FCAT_SHIFT_DECIMAL = 010, /* 1=Automatically shift decimal point
- on output--used for fixed-point
- formats. */
- FCAT_OUTPUT_ONLY = 020 /* 1=This is not an input format. */
- };
+/* Length of longest string representation of fmt_spec,
+ not including terminating null. */
+#define FMT_STRING_LEN_MAX 32
/* Display format. */
struct fmt_spec
{
- int type; /* One of the above constants. */
+ enum fmt_type type; /* One of FMT_*. */
int w; /* Width. */
int d; /* Number of implied decimal places. */
};
+union value;
+
+/* Initialization. */
+void fmt_init (void);
+void fmt_done (void);
+
+/* Constructing formats. */
+struct fmt_spec fmt_for_input (enum fmt_type, int w, int d) PURE_FUNCTION;
+struct fmt_spec fmt_for_output (enum fmt_type, int w, int d) PURE_FUNCTION;
+struct fmt_spec fmt_for_output_from_input (const struct fmt_spec *);
+
+/* Verifying formats. */
+bool fmt_check (const struct fmt_spec *, bool for_input);
+bool fmt_check_input (const struct fmt_spec *);
+bool fmt_check_output (const struct fmt_spec *);
+bool fmt_check_type_compat (const struct fmt_spec *, int var_type);
+bool fmt_check_width_compat (const struct fmt_spec *, int width);
+
+/* Working with formats. */
+int fmt_var_width (const struct fmt_spec *);
+char *fmt_to_string (const struct fmt_spec *, char s[FMT_STRING_LEN_MAX + 1]);
+
+/* Format types. */
+const char *fmt_name (enum fmt_type) PURE_FUNCTION;
+bool fmt_from_name (const char *name, enum fmt_type *);
+
+bool fmt_takes_decimals (enum fmt_type) PURE_FUNCTION;
+
+int fmt_min_input_width (enum fmt_type) PURE_FUNCTION;
+int fmt_max_input_width (enum fmt_type) PURE_FUNCTION;
+int fmt_max_input_decimals (enum fmt_type, int width) PURE_FUNCTION;
+int fmt_min_output_width (enum fmt_type) PURE_FUNCTION;
+int fmt_max_output_width (enum fmt_type) PURE_FUNCTION;
+int fmt_max_output_decimals (enum fmt_type, int width) PURE_FUNCTION;
+int fmt_step_width (enum fmt_type) PURE_FUNCTION;
+
+bool fmt_is_string (enum fmt_type) PURE_FUNCTION;
+bool fmt_is_numeric (enum fmt_type) PURE_FUNCTION;
+enum fmt_category fmt_get_category (enum fmt_type) PURE_FUNCTION;
+
+enum fmt_type fmt_input_to_output (enum fmt_type) PURE_FUNCTION;
+
+int fmt_to_io (enum fmt_type) PURE_FUNCTION;
+bool fmt_from_io (int io, enum fmt_type *);
+
+bool fmt_usable_for_input (enum fmt_type) PURE_FUNCTION;
+const char *fmt_date_template (enum fmt_type) PURE_FUNCTION;
+\f
+/* Maximum length of prefix or suffix string in
+ struct fmt_number_style. */
+#define FMT_STYLE_AFFIX_MAX 16
+
+/* A numeric output style. */
+struct fmt_number_style
+ {
+ struct substring neg_prefix; /* Negative prefix. */
+ struct substring prefix; /* Prefix. */
+ struct substring suffix; /* Suffix. */
+ struct substring neg_suffix; /* Negative suffix. */
+ char decimal; /* Decimal point: '.' or ','. */
+ char grouping; /* Grouping character: ',', '.', or 0. */
+ };
+
+struct fmt_number_style *fmt_number_style_create (void);
+void fmt_number_style_destroy (struct fmt_number_style *);
+
+const struct fmt_number_style *fmt_get_style (enum fmt_type);
+void fmt_set_style (enum fmt_type, struct fmt_number_style *);
+
+int fmt_affix_width (const struct fmt_number_style *);
+int fmt_neg_affix_width (const struct fmt_number_style *);
+
+int fmt_decimal_char (enum fmt_type);
+int fmt_grouping_char (enum fmt_type);
+void fmt_set_decimal (char);
+\f
+/* Alignment of data for display. */
enum alignment
{
ALIGN_LEFT = 0,
n_ALIGN
};
-
+/* How data is measured. */
enum measure
{
MEASURE_NOMINAL=1,
bool measure_is_valid(enum measure m);
bool alignment_is_valid(enum alignment a);
+\f
+#include <libpspp/legacy-encoding.h>
-
-/* Descriptions of all the display formats above. */
-extern const struct fmt_desc formats[];
-
-union value;
-
-/* Maximum length of formatted value, in characters. */
-#define MAX_FORMATTED_LEN 256
-
-/* Common formats. */
-extern const struct fmt_spec f8_2; /* F8.2. */
-
-int check_input_specifier (const struct fmt_spec *spec, int emit_error);
-int check_output_specifier (const struct fmt_spec *spec, int emit_error);
-bool check_specifier_type (const struct fmt_spec *, int type, bool emit_error);
-bool check_specifier_width (const struct fmt_spec *,
- int width, bool emit_error);
-void convert_fmt_ItoO (const struct fmt_spec *input, struct fmt_spec *output);
-int get_format_var_width (const struct fmt_spec *);
-int parse_string_as_format (const char *s, int len, const struct fmt_spec *fp,
- int fc, union value *v);
-int translate_fmt (int spss);
bool data_out (char *s, const struct fmt_spec *fp, const union value *v);
-bool fmt_type_from_string (const char *name, int *type);
-char *fmt_to_string (const struct fmt_spec *);
-struct fmt_spec make_input_format (int type, int w, int d);
-struct fmt_spec make_output_format (int type, int w, int d);
-bool fmt_is_binary (int type);
-#endif /* !format_h */
+#endif /* format.h */
convert_format (struct pfm_reader *r, const int portable_format[3],
struct fmt_spec *format, struct variable *v)
{
- format->type = translate_fmt (portable_format[0]);
- if (format->type == -1)
+ bool ok;
+
+ if (!fmt_from_io (portable_format[0], &format->type))
error (r, _("%s: Bad format specifier byte (%d)."),
v->name, portable_format[0]);
format->w = portable_format[1];
format->d = portable_format[2];
- if (!check_output_specifier (format, false)
- || !check_specifier_width (format, v->width, false))
- error (r, _("%s variable %s has invalid format specifier %s."),
- v->type == NUMERIC ? _("Numeric") : _("String"),
- v->name, fmt_to_string (format));
+ msg_disable ();
+ ok = fmt_check_output (format) && fmt_check_width_compat (format, v->width);
+ msg_enable ();
+
+ if (!ok)
+ {
+ char fmt_string[FMT_STRING_LEN_MAX + 1];
+ error (r, _("%s variable %s has invalid format specifier %s."),
+ v->type == NUMERIC ? _("Numeric") : _("String"),
+ v->name, fmt_to_string (format, fmt_string));
+ }
}
static union value parse_value (struct pfm_reader *, struct variable *);
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
static void
write_format (struct pfm_writer *w, struct fmt_spec *f)
{
- write_int (w, formats[f->type].spss);
+ write_int (w, fmt_to_io (f->type));
write_int (w, f->w);
write_int (w, f->d);
}
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
static bool safer_mode = false;
-static char decimal = '.';
-static char grouping = ',';
-
static bool echo = false;
static bool include = true;
static struct fmt_spec default_format = {FMT_F, 8, 2};
-#define CC_INITIALIZER {"-", "", "", "", '.', ','}
-static struct custom_currency cc[CC_CNT] =
- {
- CC_INITIALIZER,
- CC_INITIALIZER,
- CC_INITIALIZER,
- CC_INITIALIZER,
- CC_INITIALIZER,
- };
-
static bool testing_mode = false;
static int global_algorithm = ENHANCED;
safer_mode = true;
}
-/* The character used for a decimal point: ',' or '.'. Only
- respected for data input and output. */
-char
-get_decimal (void)
-{
- return decimal;
-}
-
-/* Sets the character used for a decimal point, which must be
- either ',' or '.'. */
-void
-set_decimal (char decimal_)
-{
- assert (decimal_ == '.' || decimal_ == ',');
- decimal = decimal_;
-}
-
-/* The character used for grouping in numbers: '.' or ','; the
- opposite of set_decimal. Only used in COMMA data input and
- output. */
-char
-get_grouping (void)
-{
- return grouping;
-}
-
-/* Sets the character used for grouping, which must be either ','
- or '.'. */
-void
-set_grouping (char grouping_)
-{
- assert (grouping_ == '.' || grouping_ == ',');
- grouping = grouping_;
-}
-
/* Echo commands to the listing file/printer? */
bool
get_echo (void)
default_format = *default_format_;
}
-/* Gets the custom currency specification with the given IDX. */
-const struct custom_currency *
-get_cc (int idx)
-{
- assert (idx >= 0 && idx < CC_CNT);
- return &cc[idx];
-}
-
-/* Gets custom currency specification IDX to CC. */
-void
-set_cc (int idx, const struct custom_currency *cc_)
-{
- assert (idx >= 0 && idx < CC_CNT);
- cc[idx] = *cc_;
-}
-
/* Are we in testing mode? (e.g. --testing-mode command line
option) */
bool
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
bool get_safer_mode (void);
void set_safer_mode (void);
-char get_decimal (void);
-void set_decimal (char);
-char get_grouping (void);
-void set_grouping (char);
-
bool get_echo (void);
void set_echo (bool);
bool get_include (void);
const struct fmt_spec *get_format (void);
void set_format (const struct fmt_spec *);
-/* Maximum number of custom currency specifications */
-#define CC_CNT 5
-
-/* One custom currency specification. */
-#define CC_WIDTH 16
-struct custom_currency
- {
- char neg_prefix[CC_WIDTH]; /* Negative prefix. */
- char prefix[CC_WIDTH]; /* Prefix. */
- char suffix[CC_WIDTH]; /* Suffix. */
- char neg_suffix[CC_WIDTH]; /* Negative suffix. */
- char decimal; /* Decimal point. */
- char grouping; /* Grouping character. */
- };
-
-const struct custom_currency *get_cc (int idx);
-void set_cc (int idx, const struct custom_currency *);
-
bool get_testing_mode (void);
void set_testing_mode (bool);
parse_format_spec (struct sfm_reader *r, int32_t s,
struct fmt_spec *f, const struct variable *v)
{
- f->type = translate_fmt ((s >> 16) & 0xff);
- if (f->type == -1)
+ bool ok;
+
+ if (!fmt_from_io ((s >> 16) & 0xff, &f->type))
lose ((ME, _("%s: Bad format specifier byte (%d)."),
fh_get_file_name (r->fh), (s >> 16) & 0xff));
f->w = (s >> 8) & 0xff;
f->d = s & 0xff;
- if ((v->type == ALPHA) ^ ((formats[f->type].cat & FCAT_STRING) != 0))
+ if ((v->type == ALPHA) ^ (fmt_is_string (f->type) != 0))
lose ((ME, _("%s: %s variable %s has %s format specifier %s."),
fh_get_file_name (r->fh),
v->type == ALPHA ? _("String") : _("Numeric"),
v->name,
- formats[f->type].cat & FCAT_STRING ? _("string") : _("numeric"),
- formats[f->type].name));
+ fmt_is_string (f->type) ? _("string") : _("numeric"),
+ fmt_name (f->type)));
- if (!check_output_specifier (f, false)
- || !check_specifier_width (f, v->width, false))
+ msg_disable ();
+ ok = fmt_check_output (f) && fmt_check_width_compat (f, v->width);
+ msg_enable ();
+
+ if (!ok)
{
+ char fmt_string[FMT_STRING_LEN_MAX + 1];
msg (ME, _("%s variable %s has invalid format specifier %s."),
v->type == NUMERIC ? _("Numeric") : _("String"),
- v->name, fmt_to_string (f));
- *f = v->type == NUMERIC ? f8_2 : make_output_format (FMT_A, v->width, 0);
+ v->name, fmt_to_string (f, fmt_string));
+ *f = (v->type == NUMERIC
+ ? fmt_for_output (FMT_F, 8, 2)
+ : fmt_for_output (FMT_A, v->width, 0));
}
return 1;
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
02110-1301, USA. */
#include <config.h>
+
#include "sys-file-writer.h"
#include "sfm-private.h"
-#include <libpspp/message.h>
-#include <stdlib.h>
+
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
+
#include <libpspp/alloc.h>
-#include "case.h"
-#include "dictionary.h"
-#include <libpspp/message.h>
-#include "file-handle-def.h"
#include <libpspp/hash.h>
#include <libpspp/magic.h>
+#include <libpspp/message.h>
#include <libpspp/misc.h>
-#include "settings.h"
-#include "stat-macros.h"
#include <libpspp/str.h>
+#include <libpspp/version.h>
+
+#include "case.h"
+#include "dictionary.h"
+#include "file-handle-def.h"
+#include "settings.h"
#include "value-labels.h"
#include "variable.h"
-#include <libpspp/version.h>
-#include <minmax.h>
+
+#include "stat-macros.h"
+#include "minmax.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
static inline void
write_format_spec (const struct fmt_spec *src, int32_t *dest)
{
- assert(check_output_specifier(src, true));
- *dest = (formats[src->type].spss << 16) | (src->w << 8) | src->d;
+ assert (fmt_check_output (src));
+ *dest = (fmt_to_io (src->type) << 16) | (src->w << 8) | src->d;
}
/* Write the variable record(s) for primary variable P and secondary
+Tue Oct 31 20:04:06 2006 Ben Pfaff <blp@gnu.org>
+
+ * placement-parser.c: (PRS_TYPE_T) Now that struct fmt_spec uses
+ an enum fmt_type for its type member, we can't depend on the
+ ability to put negative values into that member as out-of-band
+ values, because enum fmt_type might be an unsigned type. So use
+ values around SCHAR_MAX instead, because we know that SCHAR_MAX
+ will fit into any type, signed or unsigned, and there aren't
+ nearly that many format types.
+ (parse_var_placements) Add for_input parameter to specify whether
+ we're parsing input or output formats. Update all callers.
+ (fixed_parse_columns) Ditto.
+ (fixed_parse_fortran) Ditto.
+
+
Tue Oct 31 18:21:48 2006 Ben Pfaff <blp@gnu.org>
* print-space.c (print_space_trns_proc): Let dfm_put_record add
/* Parse everything. */
if (!parse_record_placement (&record, &column)
|| !parse_DATA_LIST_vars_pool (tmp_pool, &names, &name_cnt, PV_NONE)
- || !parse_var_placements (tmp_pool, name_cnt, &formats, &format_cnt))
+ || !parse_var_placements (tmp_pool, name_cnt, true,
+ &formats, &format_cnt))
return false;
/* Create variables and var specs. */
name = names[name_idx++];
/* Create variable. */
- width = get_format_var_width (f);
+ width = fmt_var_width (f);
v = dict_create_var (dict, name, width);
if (v != NULL)
{
/* Success. */
- struct fmt_spec output;
- convert_fmt_ItoO (f, &output);
+ struct fmt_spec output = fmt_for_output_from_input (f);
v->print = output;
v->write = output;
}
row = 1;
ll_for_each (spec, struct dls_var_spec, ll, specs)
{
+ char fmt_string[FMT_STRING_LEN_MAX + 1];
tab_text (t, 0, row, TAB_LEFT, spec->name);
tab_text (t, 1, row, TAT_PRINTF, "%d", spec->record);
tab_text (t, 2, row, TAT_PRINTF, "%3d-%3d",
spec->first_column, spec->first_column + spec->input.w - 1);
- tab_text (t, 3, row, TAB_LEFT | TAB_FIX, fmt_to_string (&spec->input));
+ tab_text (t, 3, row, TAB_LEFT | TAB_FIX,
+ fmt_to_string (&spec->input, fmt_string));
row++;
}
if (lex_match ('('))
{
if (!parse_format_specifier (&input)
- || !check_input_specifier (&input, 1)
+ || !fmt_check_input (&input)
|| !lex_force_match (')'))
return NULL;
- convert_fmt_ItoO (&input, &output);
+ output = fmt_for_output_from_input (&input);
}
else
{
lex_match ('*');
- input = make_input_format (FMT_F, 8, 0);
+ input = fmt_for_input (FMT_F, 8, 0);
output = *get_format ();
}
struct dls_var_spec *spec;
struct variable *v;
- v = dict_create_var (dict, name[i],
- get_format_var_width (&input));
+ v = dict_create_var (dict, name[i], fmt_var_width (&input));
if (v == NULL)
{
msg (SE, _("%s is a duplicate variable name."), name[i]);
tab_box (t, TAL_1, TAL_1, TAL_0, TAL_1, 0, 0, 1, spec_cnt);
tab_hline (t, TAL_2, 0, 1, 1);
tab_dim (t, tab_natural_dimensions);
-
row = 1;
ll_for_each (spec, struct dls_var_spec, ll, &dls->specs)
{
+ char str[FMT_STRING_LEN_MAX + 1];
tab_text (t, 0, row, TAB_LEFT, spec->name);
- tab_text (t, 1, row, TAB_LEFT | TAB_FIX, fmt_to_string (&spec->input));
+ tab_text (t, 1, row, TAB_LEFT | TAB_FIX,
+ fmt_to_string (&spec->input, str));
row++;
}
spec->name);
ll_for_each_continue (spec, struct dls_var_spec, ll, &dls->specs)
{
- int width = get_format_var_width (&spec->input);
+ int width = fmt_var_width (&spec->input);
if (width == 0)
case_data_rw (c, spec->fv)->f = SYSMIS;
else
goto error;
}
iter->in_var->print = iter->in_var->write
- = make_output_format (FMT_F, 1, 0);
+ = fmt_for_output (FMT_F, 1, 0);
}
/* MATCH FILES performs an n-way merge on all its input files.
strcpy (casenum_var.name, "Case#");
casenum_var.type = NUMERIC;
casenum_var.fv = -1;
- casenum_var.print = make_output_format (FMT_F,
- (cmd.last == LONG_MAX
- ? 5 : intlog10 (cmd.last)), 0);
+ casenum_var.print = fmt_for_output (FMT_F,
+ (cmd.last == LONG_MAX
+ ? 5 : intlog10 (cmd.last)), 0);
/* Add the weight variable at the beginning of the variable list. */
cmd.n_variables++;
ds_put_char_multiple(&line_buffer, ' ', width - v->print.w);
}
- if ((formats[v->print.type].cat & FCAT_STRING) || v->fv != -1)
+ if (fmt_is_string (v->print.type) || v->fv != -1)
{
data_out (ds_put_uninit(&line_buffer, v->print.w),
&v->print, case_data (c, v->fv));
struct variable *v = cmd.v_variables[column];
char buf[256];
- if ((formats[v->print.type].cat & FCAT_STRING) || v->fv != -1)
+ if (fmt_is_string (v->print.type) || v->fv != -1)
data_out (buf, &v->print, case_data (c, v->fv));
else
{
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
di.e = ss_end (s);
di.v = (union value *) &token->number;
di.f1 = dfm_get_column (reader, di.s);
- di.format = make_output_format (FMT_F, token->length, 0);
+ di.format = fmt_for_output (FMT_F, token->length, 0);
data_in (&di);
}
placement. */
enum
{
- PRS_TYPE_T = -1, /* Tab to absolute column. */
- PRS_TYPE_X = -2, /* Skip columns. */
- PRS_TYPE_NEW_REC = -3 /* Next record. */
+ PRS_TYPE_T = SCHAR_MAX - 3, /* Tab to absolute column. */
+ PRS_TYPE_X, /* Skip columns. */
+ PRS_TYPE_NEW_REC /* Next record. */
};
-static bool fixed_parse_columns (struct pool *, size_t var_cnt,
+static bool fixed_parse_columns (struct pool *, size_t var_cnt, bool for_input,
struct fmt_spec **, size_t *);
-static bool fixed_parse_fortran (struct pool *,
+static bool fixed_parse_fortran (struct pool *, bool for_input,
struct fmt_spec **, size_t *);
/* Parses Fortran-like or column-based specifications for placing
Uses POOL for allocation. When the caller is finished
interpreting *FORMATS, POOL may be destroyed. */
bool
-parse_var_placements (struct pool *pool, size_t var_cnt,
+parse_var_placements (struct pool *pool, size_t var_cnt, bool for_input,
struct fmt_spec **formats, size_t *format_cnt)
{
assert (var_cnt > 0);
if (lex_is_number ())
- return fixed_parse_columns (pool, var_cnt, formats, format_cnt);
+ return fixed_parse_columns (pool, var_cnt, for_input, formats, format_cnt);
else if (lex_match ('('))
{
size_t assignment_cnt;
size_t i;
- if (!fixed_parse_fortran (pool, formats, format_cnt))
+ if (!fixed_parse_fortran (pool, for_input, formats, format_cnt))
return false;
assignment_cnt = 0;
for (i = 0; i < *format_cnt; i++)
- assignment_cnt += (*formats)[i].type >= 0;
+ assignment_cnt += (*formats)[i].type < FMT_NUMBER_OF_FORMATS;
if (assignment_cnt != var_cnt)
{
/* Implements parse_var_placements for column-based formats. */
static bool
-fixed_parse_columns (struct pool *pool, size_t var_cnt,
+fixed_parse_columns (struct pool *pool, size_t var_cnt, bool for_input,
struct fmt_spec **formats, size_t *format_cnt)
{
struct fmt_spec format;
format.type = FMT_F;
format.d = 0;
}
- if (!check_input_specifier (&format, 1))
+ if (!fmt_check (&format, for_input))
return false;
*formats = pool_nalloc (pool, var_cnt + 1, sizeof **formats);
/* Implements parse_var_placements for Fortran-like formats. */
static bool
-fixed_parse_fortran (struct pool *pool,
+fixed_parse_fortran (struct pool *pool, bool for_input,
struct fmt_spec **formats, size_t *format_cnt)
{
size_t formats_allocated = 0;
if (lex_match ('('))
{
/* Call ourselves recursively to handle parentheses. */
- if (!fixed_parse_fortran (pool, &new_formats, &new_format_cnt))
+ if (!fixed_parse_fortran (pool, for_input,
+ &new_formats, &new_format_cnt))
return false;
}
else
}
else
{
- if (!fmt_type_from_string (type, &f.type))
+ if (!fmt_from_name (type, &f.type))
{
msg (SE, _("Unknown format type \"%s\"."), type);
return false;
}
- if (!check_input_specifier (&f, 1))
+ if (!fmt_check (&f, for_input))
return false;
}
}
return true;
default:
- assert (format->type >= 0 && format->type < FMT_NUMBER_OF_FORMATS);
+ assert (format->type < FMT_NUMBER_OF_FORMATS);
return false;
}
}
struct pool;
bool parse_record_placement (int *record, int *column);
-bool parse_var_placements (struct pool *, size_t var_cnt,
+bool parse_var_placements (struct pool *, size_t var_cnt, bool for_input,
struct fmt_spec **, size_t *format_cnt);
bool execute_placement_format (const struct fmt_spec *,
int *record, int *column);
if (lex_is_number () || token == '(')
{
- if (!parse_var_placements (tmp_pool, var_cnt, &formats, &format_cnt))
+ if (!parse_var_placements (tmp_pool, var_cnt, false,
+ &formats, &format_cnt))
return false;
add_space = false;
}
struct prt_out_spec *spec;
var = vars[var_idx++];
- if (!check_specifier_width (f, var->width, true))
+ if (!fmt_check_width_compat (f, var->width))
return false;
spec = pool_alloc (trns->pool, sizeof *spec);
that usually contains a period. */
spec->sysmis_as_spaces = (which_formats == WRITE
&& var->type == NUMERIC
- && !fmt_is_binary (spec->format.type));
+ && (fmt_get_category (spec->format.type)
+ != FMT_CAT_BINARY));
ll_push_tail (&trns->specs, &spec->ll);
row = 1;
ll_for_each (spec, struct prt_out_spec, ll, &trns->specs)
{
+ char fmt_string[FMT_STRING_LEN_MAX + 1];
int width;
switch (spec->type)
{
case PRT_VAR:
tab_text (t, 0, row, TAB_LEFT, spec->var->name);
tab_text (t, 3, row, TAB_LEFT | TAB_FIX,
- fmt_to_string (&spec->format));
+ fmt_to_string (&spec->format, fmt_string));
width = spec->format.w;
break;
default:
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
goto fail;
}
if (!parse_format_specifier (&f)
- || !check_output_specifier (&f, true)
- || !check_specifier_type (&f, NUMERIC, true))
+ || !fmt_check_output (&f)
+ || !fmt_check_type_compat (&f, NUMERIC))
goto fail;
if (!lex_match (')'))
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
{
if (!parse_format_specifier (&f))
goto fail;
- if (formats[f.type].cat & FCAT_STRING)
+ if (fmt_is_string (f.type))
{
+ char str[FMT_STRING_LEN_MAX + 1];
msg (SE, _("Format type %s may not be used with a numeric "
- "variable."), fmt_to_string (&f));
+ "variable."), fmt_to_string (&f, str));
goto fail;
}
if (!lex_force_match ('(') || !parse_format_specifier (&f))
goto fail;
- if (!(formats[f.type].cat & FCAT_STRING))
+ if (!fmt_is_string (f.type))
{
+ char str[FMT_STRING_LEN_MAX + 1];
msg (SE, _("Format type %s may not be used with a string "
- "variable."), fmt_to_string (&f));
+ "variable."), fmt_to_string (&f, str));
goto fail;
}
goto fail;
}
- switch (f.type)
- {
- case FMT_A:
- width = f.w;
- break;
- case FMT_AHEX:
- width = f.w / 2;
- break;
- default:
- NOT_REACHED ();
- }
+ width = fmt_var_width (&f);
/* Create each variable. */
for (i = 0; i < nv; i++)
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
&& v->print.w == v->write.w
&& v->print.d == v->write.d)
{
+ char str[FMT_STRING_LEN_MAX + 1];
tab_joint_text (t, 1, r, 2, r, TAB_LEFT | TAT_PRINTF, _("Format: %s"),
- fmt_to_string (&v->print));
+ fmt_to_string (&v->print, str));
r++;
}
else
{
+ char str[FMT_STRING_LEN_MAX + 1];
tab_joint_text (t, 1, r, 2, r, TAB_LEFT | TAT_PRINTF,
- _("Print Format: %s"), fmt_to_string (&v->print));
+ _("Print Format: %s"), fmt_to_string (&v->print, str));
r++;
tab_joint_text (t, 1, r, 2, r, TAB_LEFT | TAT_PRINTF,
- _("Write Format: %s"), fmt_to_string (&v->write));
+ _("Write Format: %s"), fmt_to_string (&v->write, str));
r++;
}
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
op->string.string != NULL ? op->string.string : "");
break;
case OP_format:
- fprintf (stderr, "f<%s%d.%d>",
- formats[op->format->type].name,
- op->format->w, op->format->d);
+ {
+ char str[FMT_STRING_LEN_MAX + 1];
+ fmt_to_string (op->format, str);
+ fprintf (stderr, "f<%s>", str);
+ }
break;
case OP_variable:
fprintf (stderr, "v<%s>", op->variable->name);
// -*- c -*-
+//
+// PSPP - computes sample statistics.
+// Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+// Written by Ben Pfaff <blp@gnu.org>.
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+// 02110-1301, USA. */
operator NEG (x) = -x;
v.f = x;
dst = alloc_string (e, f->w);
- assert ((formats[f->type].cat & FCAT_STRING) == 0);
+ assert (!fmt_is_string (f->type));
data_out (dst.string, f, &v);
return dst;
}
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
02110-1301, USA. */
#include <config.h>
+
#include "private.h"
+
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <stdlib.h>
-#include <libpspp/array.h>
-#include <libpspp/alloc.h>
+
+#include "helpers.h"
#include <data/case.h>
#include <data/dictionary.h>
-#include <libpspp/message.h>
-#include "helpers.h"
+#include <data/settings.h>
+#include <data/variable.h>
#include <language/lexer/format-parser.h>
#include <language/lexer/lexer.h>
#include <language/lexer/variable-parser.h>
+#include <libpspp/alloc.h>
+#include <libpspp/array.h>
#include <libpspp/assertion.h>
+#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/pool.h>
-#include <data/settings.h>
#include <libpspp/str.h>
-#include <data/variable.h>
\f
/* Declarations. */
NOT_REACHED ();
case OP_ni_format:
+ msg_disable ();
if ((*node)->type == OP_format
- && check_input_specifier (&(*node)->format.f, false)
- && check_specifier_type (&(*node)->format.f, NUMERIC, false))
+ && fmt_check_input (&(*node)->format.f)
+ && fmt_check_type_compat (&(*node)->format.f, NUMERIC))
{
+ msg_enable ();
if (do_coercion)
(*node)->type = OP_ni_format;
return true;
}
+ msg_enable ();
break;
case OP_no_format:
+ msg_disable ();
if ((*node)->type == OP_format
- && check_output_specifier (&(*node)->format.f, false)
- && check_specifier_type (&(*node)->format.f, NUMERIC, false))
+ && fmt_check_output (&(*node)->format.f)
+ && fmt_check_type_compat (&(*node)->format.f, NUMERIC))
{
+ msg_enable ();
if (do_coercion)
(*node)->type = OP_no_format;
return true;
}
+ msg_enable ();
break;
case OP_num_var:
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
#include <config.h>
-#include <language/lexer/format-parser.h>
+#include "format-parser.h"
#include <ctype.h>
#include <stdlib.h>
#include "lexer.h"
#include <data/format.h>
#include <data/variable.h>
+#include <language/lexer/format-parser.h>
#include <libpspp/message.h>
#include <libpspp/misc.h>
#include <libpspp/str.h>
if (!parse_abstract_format_specifier (type, &format->w, &format->d))
return false;
- if (!fmt_type_from_string (type, &format->type))
+ if (!fmt_from_name (type, &format->type))
{
msg (SE, _("Unknown format type \"%s\"."), type);
return false;
/* Parses a token containing just the name of a format type and
returns true if successful. */
bool
-parse_format_specifier_name (int *type)
+parse_format_specifier_name (enum fmt_type *type)
{
if (token != T_ID)
{
lex_error (_("expecting format type"));
return false;
}
- if (!fmt_type_from_string (ds_cstr (&tokstr), type))
+ if (!fmt_from_name (ds_cstr (&tokstr), type))
{
msg (SE, _("Unknown format type \"%s\"."), ds_cstr (&tokstr));
return false;
bool parse_abstract_format_specifier (char type[FMT_TYPE_LEN_MAX + 1],
int *width, int *decimals);
bool parse_format_specifier (struct fmt_spec *);
-bool parse_format_specifier_name (int *type);
+bool parse_format_specifier_name (enum fmt_type *type);
#endif /* language/lexer/format-parser.h. */
+/* PSPP - computes sample statistics.
+ Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+ Written by Ben Pfaff <blp@gnu.org>.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
+
#include <config.h>
#include "range-parser.h"
#include <stdbool.h>
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
destvar = dict_create_var (agr->dict, dest[i], 0);
if (destvar != NULL)
{
+ struct fmt_spec f;
if ((func_index == N || func_index == NMISS)
&& dict_get_weight (dict) != NULL)
- destvar->print = destvar->write = f8_2;
+ f = fmt_for_output (FMT_F, 8, 2);
else
- destvar->print = destvar->write = function->format;
+ f = function->format;
+ destvar->print = destvar->write = f;
}
}
} else {
+ struct fmt_spec f;
v->src = NULL;
destvar = dict_create_var (agr->dict, dest[i], 0);
- if (func_index == N_NO_VARS
- && dict_get_weight (dict) != NULL)
- destvar->print = destvar->write = f8_2;
+ if (func_index == N_NO_VARS && dict_get_weight (dict) != NULL)
+ f = fmt_for_output (FMT_F, 8, 2);
else
- destvar->print = destvar->write = function->format;
+ f = function->format;
+ destvar->print = destvar->write = f;
}
if (!destvar)
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
struct fmt_spec fmt_subst;
/* Limit to short string width. */
- if (formats[fp->type].cat & FCAT_STRING)
+ if (fmt_is_string (fp->type))
{
fmt_subst = *fp;
+Tue Oct 31 20:10:24 2006 Ben Pfaff <blp@gnu.org>
+
+ * set.q (cmd_set): Drop the `ok' variable, which didn't do
+ anything useful.
+ (extract_cc_token) Adapt to new fmt_number_style.
+ (do_cc) Ditto.
+ (format_cc) Ditto.
+ (show_cc) Change parameter to be an enum fmt_type. Adjust all
+ callers.
+
Wed Apr 26 15:06:22 2006 Ben Pfaff <blp@gnu.org>
* set.q: Use SN instead of MN for most output from SHOW, because
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
/* (declarations) */
-/* (_functions) */
+/* (functions) */
-static bool do_cc (const char *cc_string, int idx);
+static bool do_cc (const char *cc_string, enum fmt_type);
int
cmd_set (struct dataset *ds)
{
struct cmd_set cmd;
- bool ok = true;
if (!parse_set (ds, &cmd, NULL))
return CMD_FAILURE;
if (cmd.sbc_cca)
- ok = ok && do_cc (cmd.s_cca, 0);
+ do_cc (cmd.s_cca, FMT_CCA);
if (cmd.sbc_ccb)
- ok = ok && do_cc (cmd.s_ccb, 1);
+ do_cc (cmd.s_ccb, FMT_CCB);
if (cmd.sbc_ccc)
- ok = ok && do_cc (cmd.s_ccc, 2);
+ do_cc (cmd.s_ccc, FMT_CCC);
if (cmd.sbc_ccd)
- ok = ok && do_cc (cmd.s_ccd, 3);
+ do_cc (cmd.s_ccd, FMT_CCD);
if (cmd.sbc_cce)
- ok = ok && do_cc (cmd.s_cce, 4);
+ do_cc (cmd.s_cce, FMT_CCE);
if (cmd.sbc_prompt)
getl_set_prompt (GETL_PROMPT_FIRST, cmd.s_prompt);
getl_set_prompt (GETL_PROMPT_DATA, cmd.s_dprompt);
if (cmd.sbc_decimal)
- set_decimal (cmd.dec == STC_DOT ? '.' : ',');
+ fmt_set_decimal (cmd.dec == STC_DOT ? '.' : ',');
if (cmd.sbc_echo)
set_echo (cmd.echo == STC_ON);
if (cmd.sbc_endcmd)
grouping and decimal members appropriately. Returns true if
successful, false otherwise. */
static bool
-find_cc_separators (const char *cc_string, struct custom_currency *cc)
+find_cc_separators (const char *cc_string, struct fmt_number_style *cc)
{
const char *sp;
int comma_cnt, dot_cnt;
return true;
}
-/* Extracts a token from IN into TOKEn. Tokens are delimited by
- GROUPING. The token is truncated to at most CC_WIDTH
- characters (including null terminator). Returns the first
- character following the token. */
+/* Extracts a token from IN into a newly allocated AFFIX. Tokens
+ are delimited by GROUPING. The token is truncated to at most
+ FMT_STYLE_AFFIX_MAX characters. Returns the first character
+ following the token. */
static const char *
-extract_cc_token (const char *in, int grouping, char token[CC_WIDTH])
+extract_cc_token (const char *in, int grouping, struct substring *affix)
{
- char *out = token;
-
+ size_t ofs = 0;
+ ss_alloc_uninit (affix, FMT_STYLE_AFFIX_MAX);
for (; *in != '\0' && *in != grouping; in++)
{
if (*in == '\'' && in[1] == grouping)
in++;
- if (out < &token[CC_WIDTH - 1])
- *out++ = *in;
+ if (ofs < FMT_STYLE_AFFIX_MAX)
+ ss_data (*affix)[ofs++] = *in;
}
- *out = '\0';
+ affix->length = ofs;
if (*in == grouping)
in++;
/* Sets custom currency specifier CC having name CC_NAME ('A' through
'E') to correspond to the settings in CC_STRING. */
static bool
-do_cc (const char *cc_string, int idx)
+do_cc (const char *cc_string, enum fmt_type type)
{
- struct custom_currency cc;
+ struct fmt_number_style *cc = fmt_number_style_create ();
/* Determine separators. */
- if (!find_cc_separators (cc_string, &cc))
+ if (!find_cc_separators (cc_string, cc))
{
- msg (SE, _("CC%c: Custom currency string `%s' does not contain "
- "exactly three periods or commas (not both)."),
- "ABCDE"[idx], cc_string);
+ fmt_number_style_destroy (cc);
+ msg (SE, _("%s: Custom currency string `%s' does not contain "
+ "exactly three periods or commas (or it contains both)."),
+ fmt_name (type), cc_string);
return false;
}
- cc_string = extract_cc_token (cc_string, cc.grouping, cc.neg_prefix);
- cc_string = extract_cc_token (cc_string, cc.grouping, cc.prefix);
- cc_string = extract_cc_token (cc_string, cc.grouping, cc.suffix);
- cc_string = extract_cc_token (cc_string, cc.grouping, cc.neg_suffix);
+ cc_string = extract_cc_token (cc_string, cc->grouping, &cc->neg_prefix);
+ cc_string = extract_cc_token (cc_string, cc->grouping, &cc->prefix);
+ cc_string = extract_cc_token (cc_string, cc->grouping, &cc->suffix);
+ cc_string = extract_cc_token (cc_string, cc->grouping, &cc->neg_suffix);
- set_cc (idx, &cc);
+ fmt_set_style (type, cc);
return true;
}
lex_match ('=');
if (!parse_format_specifier (&fmt))
return 0;
- if ((formats[fmt.type].cat & FCAT_STRING) != 0)
+ if (fmt_is_string (fmt.type))
{
+ char str[FMT_STRING_LEN_MAX + 1];
msg (SE, _("FORMAT requires numeric output format as an argument. "
"Specified format %s is of type string."),
- fmt_to_string (&fmt));
+ fmt_to_string (&fmt, str));
return 0;
}
}
static char *
-format_cc (const char *in, char grouping, char *out)
+format_cc (struct substring in, char grouping, char *out)
{
- while (*in != '\0')
+ while (!ss_is_empty (in))
{
- if (*in == grouping || *in == '\'')
+ char c = ss_get_char (&in);
+ if (c == grouping || c == '\'')
*out++ = '\'';
- *out++ = *in++;
+ else if (c == '"')
+ *out++ = '"';
+ *out++ = c;
}
return out;
}
static void
-show_cc (int idx)
+show_cc (enum fmt_type type)
{
- const struct custom_currency *cc = get_cc (idx);
- char cc_string[CC_WIDTH * 4 * 2 + 3 + 1];
+ const struct fmt_number_style *cc = fmt_get_style (type);
+ char cc_string[FMT_STYLE_AFFIX_MAX * 4 * 2 + 3 + 1];
char *out;
out = format_cc (cc->neg_prefix, cc->grouping, cc_string);
out = format_cc (cc->neg_suffix, cc->grouping, out);
*out = '\0';
- msg (SN, _("CC%c is \"%s\"."), "ABCDE"[idx], cc_string);
+ msg (SN, _("%s is \"%s\"."), fmt_name (type), cc_string);
}
-
static void
show_cca (const struct dataset *ds UNUSED)
{
- show_cc (0);
+ show_cc (FMT_CCA);
}
static void
show_ccb (const struct dataset *ds UNUSED)
{
- show_cc (1);
+ show_cc (FMT_CCB);
}
static void
show_ccc (const struct dataset *ds UNUSED)
{
- show_cc (2);
+ show_cc (FMT_CCC);
}
static void
show_ccd (const struct dataset *ds UNUSED)
{
- show_cc (3);
+ show_cc (FMT_CCD);
}
static void
show_cce (const struct dataset *ds UNUSED)
{
- show_cc (4);
+ show_cc (FMT_CCE);
}
static void
show_decimals (const struct dataset *ds UNUSED)
{
- msg (SN, _("DECIMAL is \"%c\"."), get_decimal ());
+ msg (SN, _("DECIMAL is \"%c\"."), fmt_decimal_char (FMT_F));
}
static void
static void
show_format (const struct dataset *ds UNUSED)
{
- msg (SN, _("FORMAT is %s."), fmt_to_string (get_format ()));
+ char str[FMT_STRING_LEN_MAX + 1];
+ msg (SN, _("FORMAT is %s."), fmt_to_string (get_format (), str));
}
static void
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
02110-1301, USA. */
#include <config.h>
+
#include "table.h"
+
#include <ctype.h>
#include <stdarg.h>
#include <limits.h>
#include <stdlib.h>
+
+#include "output.h"
+#include "manager.h"
+
+#include <data/format.h>
+#include <data/variable.h>
#include <libpspp/alloc.h>
#include <libpspp/assertion.h>
#include <libpspp/compiler.h>
-#include <data/format.h>
#include <libpspp/magic.h>
#include <libpspp/misc.h>
-#include "minmax.h"
-#include "output.h"
#include <libpspp/pool.h>
-#include "manager.h"
-#include <data/variable.h>
+
+#include "minmax.h"
#include "gettext.h"
#define _(msgid) gettext (msgid)
assert (r >= 0);
assert (r < table->nr);
- f = make_output_format (FMT_F, w, d);
+ f = fmt_for_output (FMT_F, w, d);
#if DEBUGGING
if (c + table->col_ofs < 0 || r + table->row_ofs < 0
case FMT_A:
return g_locale_to_utf8(gettext(type_label[VT_STRING]), -1, 0, 0, err);
break;
- default:
- g_warning("Unknown format: \"%s\"\n",
- fmt_to_string(write_spec));
+ default:
+ {
+ char str[FMT_STRING_LEN_MAX + 1];
+ g_warning("Unknown format: \"%s\"\n",
+ fmt_to_string(write_spec, str));
+ }
break;
}
}
/*
PSPPIRE --- A Graphical User Interface for PSPP
- Copyright (C) 2004 Free Software Foundation
+ Copyright (C) 2004, 2006 Free Software Foundation
Written by John Darrington
This program is free software; you can redistribute it and/or modify
#include <data/missing-values.h>
#include <data/value-labels.h>
#include <data/format.h>
+#include <libpspp/message.h>
#include <libpspp/misc.h>
g_return_val_if_fail(pv->dict, FALSE);
g_return_val_if_fail(pv->v, FALSE);
- if ( check_output_specifier(fmt, false)
- &&
- check_specifier_type(fmt, pv->v->type, false)
- &&
- check_specifier_width(fmt, pv->v->width, false)
- )
+ msg_disable ();
+ if ( fmt_check_output(fmt)
+ && fmt_check_type_compat (fmt, pv->v->type)
+ && fmt_check_width_compat (fmt, pv->v->width))
{
+ msg_enable ();
pv->v->write = pv->v->print = *fmt;
psppire_dict_var_changed(pv->dict, pv->v->index);
return TRUE;
}
+ msg_enable ();
return FALSE;
}
#include <libpspp/version.h>
#include <libpspp/copyleft.h>
+#include <data/format.h>
#include <data/settings.h>
#include <getopt.h>
+ fmt_init();
settings_init();
message_dialog_init();
/*
PSPPIRE --- A Graphical User Interface for PSPP
- Copyright (C) 2005 Free Software Foundation
+ Copyright (C) 2005, 2006 Free Software Foundation
Written by John Darrington
This program is free software; you can redistribute it and/or modify
#include <data/variable.h>
#include <data/settings.h>
+#include <libpspp/message.h>
struct tgs
text = gtk_entry_get_text(GTK_ENTRY(dialog->entry_width));
dialog->fmt_l.w = atoi(text);
- if ( ! check_output_specifier(&dialog->fmt_l, 0))
+ msg_disable ();
+ if ( ! fmt_check_output(&dialog->fmt_l))
{
gtk_label_set_text(GTK_LABEL(dialog->label_psample), "---");
gtk_label_set_text(GTK_LABEL(dialog->label_nsample), "---");
gtk_label_set_text(GTK_LABEL(dialog->label_nsample), sample_text);
g_free(sample_text);
}
+ msg_enable ();
}
/* Callback for when a treeview row is changed.
list_store = gtk_list_store_new (2, G_TYPE_STRING,
G_TYPE_POINTER);
- for ( i = 0 ; i < CC_CNT ; ++i )
+ for ( i = 0 ; i < 5 ; ++i )
{
+ enum fmt_type cc_fmts[5] = {FMT_CCA, FMT_CCB, FMT_CCC, FMT_CCD, FMT_CCE};
gchar text[4];
- g_snprintf(text, 4, "CC%c", 'A' + i);
+ g_snprintf(text, 4, "%s", fmt_name (cc_fmts[i]));
gtk_list_store_append (list_store, &iter);
gtk_list_store_set (list_store, &iter,
0, text,
gtk_tree_view_set_cursor(treeview, path, 0, 0);
gtk_tree_path_free(path);
}
- else
- g_warning("Unusual date format: %s\n", fmt_to_string(fmt));
-
+ else
+ {
+ char str[FMT_STRING_LEN_MAX + 1];
+ g_warning("Unusual date format: %s\n", fmt_to_string(fmt, str));
+ }
}
f->type = type;
f->w = w;
f->d = d;
- return check_output_specifier (f, true);
+ return fmt_check_output (f);
}
break;
case BUTTON_DATE:
case BUTTON_CUSTOM:
- g_assert(check_output_specifier(&dialog->fmt_l, TRUE));
+ g_assert(fmt_check_output(&dialog->fmt_l));
result = memcpy(&spec, &dialog->fmt_l, sizeof(struct fmt_spec));
break;
case BUTTON_DOLLAR:
/* PSPP - computes sample statistics.
- Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
Written by Ben Pfaff <blp@gnu.org>.
This program is free software; you can redistribute it and/or
#include <data/dictionary.h>
#include <data/file-handle-def.h>
#include <data/file-name.h>
+#include <data/format.h>
#include <data/procedure.h>
#include <data/settings.h>
#include <data/variable.h>
fpu_init ();
gsl_set_error_handler_off ();
+ fmt_init ();
outp_init ();
msg_ui_init ();
fn_init ();