1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 1997-9, 2000, 2006 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
32 #include "identifier.h"
36 #include <libpspp/assertion.h>
37 #include <libpspp/legacy-encoding.h>
38 #include <libpspp/compiler.h>
39 #include <libpspp/integer-format.h>
40 #include <libpspp/message.h>
41 #include <libpspp/misc.h>
42 #include <libpspp/str.h>
49 #define _(msgid) gettext (msgid)
51 /* Information about parsing one data field. */
54 enum legacy_encoding encoding;/* Encoding of source. */
55 struct substring input; /* Source. */
56 enum fmt_type format; /* Input format. */
57 int implied_decimals; /* Number of implied decimal places. */
59 union value *output; /* Destination. */
60 int width; /* Output width. */
62 int first_column; /* First column of field; 0 if inapplicable. */
63 int last_column; /* Last column. */
68 typedef bool data_in_parser_func (struct data_in *);
69 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) \
70 static data_in_parser_func parse_##METHOD;
73 static void vdata_warning (const struct data_in *, const char *, va_list)
75 static void data_warning (const struct data_in *, const char *, ...)
78 static void apply_implied_decimals (struct data_in *);
79 static void default_result (struct data_in *);
80 static bool trim_spaces_and_check_missing (struct data_in *);
82 static int hexit_value (int c);
84 /* Parses the characters in INPUT, which are encoded in the given
85 ENCODING, according to FORMAT. Stores the parsed
86 representation in OUTPUT, which has the given WIDTH (0 for
87 a numeric field, otherwise the string width).
89 If no decimal point is included in a numeric format, then
90 IMPLIED_DECIMALS decimal places are implied. Specify 0 if no
91 decimal places should be implied.
93 If FIRST_COLUMN and LAST_COLUMN are nonzero, then they should
94 be the 1-based column number of the first and
95 one-past-the-last-character in INPUT, for use in error
96 messages. (LAST_COLUMN cannot always be calculated from
97 FIRST_COLUMN plus the length of the input because of the
98 possibility of escaped quotes in strings, etc.) */
100 data_in (struct substring input, enum legacy_encoding encoding,
101 enum fmt_type format, int implied_decimals,
102 int first_column, int last_column, union value *output, int width)
104 static data_in_parser_func *const handlers[FMT_NUMBER_OF_FORMATS] =
106 #define FMT(NAME, METHOD, IMIN, OMIN, IO, CATEGORY) parse_##METHOD,
107 #include "format.def"
114 assert ((width != 0) == fmt_is_string (format));
116 if (encoding == LEGACY_NATIVE
117 || fmt_get_category (format) & (FMT_CAT_BINARY | FMT_CAT_STRING))
120 i.encoding = encoding;
124 ss_alloc_uninit (&i.input, ss_length (input));
125 legacy_recode (encoding, ss_data (input), LEGACY_NATIVE,
126 ss_data (i.input), ss_length (input));
127 i.encoding = LEGACY_NATIVE;
128 copy = ss_data (i.input);
131 i.implied_decimals = implied_decimals;
136 i.first_column = first_column;
137 i.last_column = last_column;
139 if (!ss_is_empty (i.input))
141 ok = handlers[i.format] (&i);
158 /* Format parsers. */
160 /* Parses F, COMMA, DOT, DOLLAR, PCT, and E input formats. */
162 parse_number (struct data_in *i)
164 const struct fmt_number_style *style =
165 settings_get_style (i->format);
169 bool explicit_decimals = false;
173 assert (fmt_get_category (i->format) != FMT_CAT_CUSTOM);
175 /* Trim spaces and check for missing value representation. */
176 if (trim_spaces_and_check_missing (i))
179 ds_init_empty (&tmp);
180 ds_extend (&tmp, 64);
182 /* Prefix character may precede sign. */
183 if (!ss_is_empty (style->prefix))
185 ss_match_char (&i->input, ss_first (style->prefix));
186 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
190 if (ss_match_char (&i->input, '-'))
192 ds_put_char (&tmp, '-');
193 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
197 ss_match_char (&i->input, '+');
198 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
201 /* Prefix character may follow sign. */
202 if (!ss_is_empty (style->prefix))
204 ss_match_char (&i->input, ss_first (style->prefix));
205 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
208 /* Digits before decimal point. */
209 while (c_isdigit (ss_first (i->input)))
211 ds_put_char (&tmp, ss_get_char (&i->input));
212 if (style->grouping != 0)
213 ss_match_char (&i->input, style->grouping);
216 /* Decimal point and following digits. */
217 if (ss_match_char (&i->input, style->decimal))
219 explicit_decimals = true;
220 ds_put_char (&tmp, '.');
221 while (c_isdigit (ss_first (i->input)))
222 ds_put_char (&tmp, ss_get_char (&i->input));
226 if (!ds_is_empty (&tmp)
227 && !ss_is_empty (i->input)
228 && strchr ("eEdD-+", ss_first (i->input)))
230 explicit_decimals = true;
231 ds_put_char (&tmp, 'e');
233 if (strchr ("eEdD", ss_first (i->input)))
235 ss_advance (&i->input, 1);
236 ss_match_char (&i->input, ' ');
239 if (ss_first (i->input) == '-' || ss_first (i->input) == '+')
241 if (ss_get_char (&i->input) == '-')
242 ds_put_char (&tmp, '-');
243 ss_match_char (&i->input, ' ');
246 while (c_isdigit (ss_first (i->input)))
247 ds_put_char (&tmp, ss_get_char (&i->input));
250 /* Suffix character. */
251 if (!ss_is_empty (style->suffix))
252 ss_match_char (&i->input, ss_first (style->suffix));
254 if (!ss_is_empty (i->input))
256 if (ds_is_empty (&tmp))
257 data_warning (i, _("Field contents are not numeric."));
259 data_warning (i, _("Number followed by garbage."));
264 /* Let c_strtod() do the conversion. */
267 i->output->f = c_strtod (ds_cstr (&tmp), &tail);
270 data_warning (i, _("Invalid numeric syntax."));
275 else if (errno == ERANGE)
277 if (fabs (i->output->f) > 1)
279 data_warning (i, _("Too-large number set to system-missing."));
280 i->output->f = SYSMIS;
284 data_warning (i, _("Too-small number set to zero."));
291 if (!explicit_decimals)
292 apply_implied_decimals (i);
299 /* Parses N format. */
301 parse_N (struct data_in *i)
306 while ((c = ss_get_char (&i->input)) != EOF)
310 data_warning (i, _("All characters in field must be digits."));
313 i->output->f = i->output->f * 10.0 + (c - '0');
316 apply_implied_decimals (i);
320 /* Parses PIBHEX format. */
322 parse_PIBHEX (struct data_in *i)
329 while ((c = ss_get_char (&i->input)) != EOF)
333 data_warning (i, _("Unrecognized character in field."));
336 n = n * 16.0 + hexit_value (c);
343 /* Parses RBHEX format. */
345 parse_RBHEX (struct data_in *i)
350 memset (&d, 0, sizeof d);
351 for (j = 0; !ss_is_empty (i->input) && j < sizeof d; j++)
353 int hi = ss_get_char (&i->input);
354 int lo = ss_get_char (&i->input);
357 data_warning (i, _("Field must have even length."));
360 else if (!c_isxdigit (hi) || !c_isxdigit (lo))
362 data_warning (i, _("Field must contain only hex digits."));
365 ((unsigned char *) &d)[j] = 16 * hexit_value (hi) + hexit_value (lo);
373 /* Digits for Z format. */
374 static const char z_digits[] = "0123456789{ABCDEFGHI}JKLMNOPQR";
376 /* Returns true if C is a Z format digit, false otherwise. */
380 return c > 0 && strchr (z_digits, c) != NULL;
383 /* Returns the (absolute value of the) value of C as a Z format
386 z_digit_value (int c)
388 assert (is_z_digit (c));
389 return (strchr (z_digits, c) - z_digits) % 10;
392 /* Returns true if Z format digit C represents a negative value,
395 is_negative_z_digit (int c)
397 assert (is_z_digit (c));
398 return (strchr (z_digits, c) - z_digits) >= 20;
401 /* Parses Z format. */
403 parse_Z (struct data_in *i)
409 bool got_dot = false;
410 bool got_final_digit = false;
412 /* Trim spaces and check for missing value representation. */
413 if (trim_spaces_and_check_missing (i))
416 ds_init_empty (&tmp);
417 ds_extend (&tmp, 64);
419 ds_put_char (&tmp, '+');
420 while (!ss_is_empty (i->input))
422 int c = ss_get_char (&i->input);
423 if (c_isdigit (c) && !got_final_digit)
424 ds_put_char (&tmp, c);
425 else if (is_z_digit (c) && !got_final_digit)
427 ds_put_char (&tmp, z_digit_value (c) + '0');
428 if (is_negative_z_digit (c))
429 ds_data (&tmp)[0] = '-';
430 got_final_digit = true;
432 else if (c == '.' && !got_dot)
434 ds_put_char (&tmp, '.');
444 if (!ss_is_empty (i->input))
446 if (ds_length (&tmp) == 1)
447 data_warning (i, _("Field contents are not numeric."));
449 data_warning (i, _("Number followed by garbage."));
454 /* Let c_strtod() do the conversion. */
457 i->output->f = c_strtod (ds_cstr (&tmp), NULL);
460 if (fabs (i->output->f) > 1)
462 data_warning (i, _("Too-large number set to system-missing."));
463 i->output->f = SYSMIS;
467 data_warning (i, _("Too-small number set to zero."));
475 apply_implied_decimals (i);
482 /* Parses IB format. */
484 parse_IB (struct data_in *i)
490 bytes = MIN (8, ss_length (i->input));
491 value = integer_get (settings_get_input_integer_format (), ss_data (i->input), bytes);
493 sign_bit = UINT64_C(1) << (8 * bytes - 1);
494 if (!(value & sign_bit))
495 i->output->f = value;
498 /* Sign-extend to full 64 bits. */
499 value -= sign_bit << 1;
500 i->output->f = -(double) -value;
503 apply_implied_decimals (i);
508 /* Parses PIB format. */
510 parse_PIB (struct data_in *i)
512 i->output->f = integer_get (settings_get_input_integer_format (), ss_data (i->input),
513 MIN (8, ss_length (i->input)));
515 apply_implied_decimals (i);
520 /* Consumes the first character of S. Stores its high 4 bits in
521 HIGH_NIBBLE and its low 4 bits in LOW_NIBBLE. */
523 get_nibbles (struct substring *s, int *high_nibble, int *low_nibble)
525 int c = ss_get_char (s);
527 *high_nibble = (c >> 4) & 15;
528 *low_nibble = c & 15;
531 /* Parses P format. */
533 parse_P (struct data_in *i)
535 int high_nibble, low_nibble;
539 while (ss_length (i->input) > 1)
541 get_nibbles (&i->input, &high_nibble, &low_nibble);
542 if (high_nibble > 9 || low_nibble > 9)
544 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
547 get_nibbles (&i->input, &high_nibble, &low_nibble);
550 i->output->f = (10 * i->output->f) + high_nibble;
552 i->output->f = (10 * i->output->f) + low_nibble;
553 else if (low_nibble == 0xb || low_nibble == 0xd)
554 i->output->f = -i->output->f;
556 apply_implied_decimals (i);
561 /* Parses PK format. */
563 parse_PK (struct data_in *i)
566 while (!ss_is_empty (i->input))
568 int high_nibble, low_nibble;
570 get_nibbles (&i->input, &high_nibble, &low_nibble);
571 if (high_nibble > 9 || low_nibble > 9)
573 i->output->f = SYSMIS;
576 i->output->f = (100 * i->output->f) + (10 * high_nibble) + low_nibble;
579 apply_implied_decimals (i);
584 /* Parses RB format. */
586 parse_RB (struct data_in *i)
588 enum float_format ff = settings_get_input_float_format ();
589 size_t size = float_get_size (ff);
590 if (ss_length (i->input) >= size)
591 float_convert (ff, ss_data (i->input),
592 FLOAT_NATIVE_DOUBLE, &i->output->f);
594 i->output->f = SYSMIS;
599 /* Parses A format. */
601 parse_A (struct data_in *i)
603 /* This is equivalent to buf_copy_rpad, except that we posibly
604 do a character set recoding in the middle. */
605 char *dst = i->output->s;
606 size_t dst_size = i->width;
607 const char *src = ss_data (i->input);
608 size_t src_size = ss_length (i->input);
610 legacy_recode (i->encoding, src, LEGACY_NATIVE, dst, MIN (src_size, dst_size));
611 if (dst_size > src_size)
612 memset (&dst[src_size], ' ', dst_size - src_size);
617 /* Parses AHEX format. */
619 parse_AHEX (struct data_in *i)
625 int hi = ss_get_char (&i->input);
626 int lo = ss_get_char (&i->input);
631 data_warning (i, _("Field must have even length."));
635 if (i->encoding != LEGACY_NATIVE)
637 hi = legacy_to_native (i->encoding, hi);
638 lo = legacy_to_native (i->encoding, lo);
640 if (!c_isxdigit (hi) || !c_isxdigit (lo))
642 data_warning (i, _("Field must contain only hex digits."));
647 i->output->s[j] = hexit_value (hi) * 16 + hexit_value (lo);
650 memset (i->output->s + j, ' ', i->width - j);
655 /* Date & time format components. */
657 /* Sign of a time value. */
660 SIGN_NO_TIME, /* No time yet encountered. */
661 SIGN_POSITIVE, /* Positive time. */
662 SIGN_NEGATIVE /* Negative time. */
665 /* Parses a signed decimal integer from at most the first
666 MAX_DIGITS characters in I, storing the result into *RESULT.
667 Returns true if successful, false if no integer was
670 parse_int (struct data_in *i, long *result, size_t max_digits)
672 struct substring head = ss_head (i->input, max_digits);
673 size_t n = ss_get_long (&head, result);
676 ss_advance (&i->input, n);
681 data_warning (i, _("Syntax error in date field."));
686 /* Parses a date integer between 1 and 31 from I, storing it into
688 Returns true if successful, false if no date was present. */
690 parse_day (struct data_in *i, long *day)
692 if (!parse_int (i, day, SIZE_MAX))
694 if (*day >= 1 && *day <= 31)
697 data_warning (i, _("Day (%ld) must be between 1 and 31."), *day);
701 /* Parses an integer from the beginning of I.
702 Adds SECONDS_PER_UNIT times the absolute value of the integer
704 If *TIME_SIGN is SIGN_NO_TIME, allows a sign to precede the
705 time and sets *TIME_SIGN. Otherwise, does not allow a sign.
706 Returns true if successful, false if no integer was present. */
708 parse_time_units (struct data_in *i, double seconds_per_unit,
709 enum time_sign *time_sign, double *time)
714 if (*time_sign == SIGN_NO_TIME)
716 if (ss_match_char (&i->input, '-'))
717 *time_sign = SIGN_NEGATIVE;
720 ss_match_char (&i->input, '+');
721 *time_sign = SIGN_POSITIVE;
724 if (!parse_int (i, &units, SIZE_MAX))
728 data_warning (i, _("Syntax error in date field."));
731 *time += units * seconds_per_unit;
735 /* Parses a data delimiter from the beginning of I.
736 Returns true if successful, false if no delimiter was
739 parse_date_delimiter (struct data_in *i)
741 if (ss_ltrim (&i->input, ss_cstr ("-/.," CC_SPACES)))
744 data_warning (i, _("Delimiter expected between fields in date."));
748 /* Parses spaces at the beginning of I. */
750 parse_spaces (struct data_in *i)
752 ss_ltrim (&i->input, ss_cstr (CC_SPACES));
755 static struct substring
756 parse_name_token (struct data_in *i)
758 struct substring token;
759 ss_get_chars (&i->input, ss_span (i->input, ss_cstr (CC_LETTERS)), &token);
763 /* Reads a name from I and sets *OUTPUT to the value associated
764 with that name. If ALLOW_SUFFIXES is true, then names that
765 begin with one of the names are accepted; otherwise, only
766 exact matches (except for case) are allowed.
767 Returns true if successful, false otherwise. */
769 match_name (struct substring token, const char *const *names, long *output)
773 for (i = 1; *names != NULL; i++)
774 if (ss_equals_case (ss_cstr (*names++), token))
783 /* Parses a month name or number from the beginning of I,
784 storing the month (in range 1...12) into *MONTH.
785 Returns true if successful, false if no month was present. */
787 parse_month (struct data_in *i, long *month)
789 if (c_isdigit (ss_first (i->input)))
791 if (!parse_int (i, month, SIZE_MAX))
793 if (*month >= 1 && *month <= 12)
798 static const char *const english_names[] =
800 "jan", "feb", "mar", "apr", "may", "jun",
801 "jul", "aug", "sep", "oct", "nov", "dec",
805 static const char *const roman_names[] =
807 "i", "ii", "iii", "iv", "v", "vi",
808 "vii", "viii", "ix", "x", "xi", "xii",
812 struct substring token = parse_name_token (i);
813 if (match_name (ss_head (token, 3), english_names, month)
814 || match_name (ss_head (token, 4), roman_names, month))
818 data_warning (i, _("Unrecognized month format. Months may be specified "
819 "as Arabic or Roman numerals or as at least 3 letters "
820 "of their English names."));
824 /* Parses a year of at most MAX_DIGITS from the beginning of I,
825 storing a "4-digit" year into *YEAR. */
827 parse_year (struct data_in *i, long *year, size_t max_digits)
829 if (!parse_int (i, year, max_digits))
832 if (*year >= 0 && *year <= 99)
834 int epoch = settings_get_epoch ();
835 int epoch_century = ROUND_DOWN (epoch, 100);
836 int epoch_offset = epoch - epoch_century;
837 if (*year >= epoch_offset)
838 *year += epoch_century;
840 *year += epoch_century + 100;
842 if (*year >= 1582 || *year <= 19999)
845 data_warning (i, _("Year (%ld) must be between 1582 and 19999."), *year);
849 /* Returns true if input in I has been exhausted,
852 parse_trailer (struct data_in *i)
854 if (ss_is_empty (i->input))
857 data_warning (i, _("Trailing garbage \"%.*s\" following date."),
858 (int) ss_length (i->input), ss_data (i->input));
862 /* Parses a 3-digit Julian day-of-year value from I into *YDAY.
863 Returns true if successful, false on failure. */
865 parse_yday (struct data_in *i, long *yday)
867 struct substring num_s;
870 ss_get_chars (&i->input, 3, &num_s);
871 if (ss_span (num_s, ss_cstr (CC_DIGITS)) != 3)
873 data_warning (i, _("Julian day must have exactly three digits."));
876 else if (!ss_get_long (&num_s, &num) || num < 1 || num > 366)
878 data_warning (i, _("Julian day (%ld) must be between 1 and 366."), num);
886 /* Parses a quarter-of-year integer between 1 and 4 from I.
887 Stores the corresponding month into *MONTH.
888 Returns true if successful, false if no quarter was present. */
890 parse_quarter (struct data_in *i, long int *month)
894 if (!parse_int (i, &quarter, SIZE_MAX))
896 if (quarter >= 1 && quarter <= 4)
898 *month = (quarter - 1) * 3 + 1;
902 data_warning (i, _("Quarter (%ld) must be between 1 and 4."), quarter);
906 /* Parses a week-of-year integer between 1 and 53 from I,
907 Stores the corresponding year-of-day into *YDAY.
908 Returns true if successful, false if no week was present. */
910 parse_week (struct data_in *i, long int *yday)
914 if (!parse_int (i, &week, SIZE_MAX))
916 if (week >= 1 && week <= 53)
918 *yday = (week - 1) * 7 + 1;
922 data_warning (i, _("Week (%ld) must be between 1 and 53."), week);
926 /* Parses a time delimiter from the beginning of I.
927 Returns true if successful, false if no delimiter was
930 parse_time_delimiter (struct data_in *i)
932 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) > 0)
935 data_warning (i, _("Delimiter expected between fields in time."));
939 /* Parses minutes and optional seconds from the beginning of I.
940 The time is converted into seconds, which are added to
942 Returns true if successful, false if an error was found. */
944 parse_minute_second (struct data_in *i, double *time)
951 if (!parse_int (i, &minute, SIZE_MAX))
953 if (minute < 0 || minute > 59)
955 data_warning (i, _("Minute (%ld) must be between 0 and 59."), minute);
958 *time += 60. * minute;
960 /* Check for seconds. */
961 if (ss_ltrim (&i->input, ss_cstr (":" CC_SPACES)) == 0
962 || !c_isdigit (ss_first (i->input)))
967 while (c_isdigit (ss_first (i->input)))
968 *cp++ = ss_get_char (&i->input);
969 if (ss_match_char (&i->input, settings_get_decimal_char (FMT_F)))
971 while (c_isdigit (ss_first (i->input)))
972 *cp++ = ss_get_char (&i->input);
975 *time += strtod (buf, NULL);
980 /* Parses a weekday name from the beginning of I,
981 storing a value of 1=Sunday...7=Saturday into *WEEKDAY.
982 Returns true if successful, false if an error was found. */
984 parse_weekday (struct data_in *i, long *weekday)
986 static const char *const weekday_names[] =
988 "su", "mo", "tu", "we", "th", "fr", "sa",
992 struct substring token = parse_name_token (i);
993 bool ok = match_name (ss_head (token, 2), weekday_names, weekday);
995 data_warning (i, _("Unrecognized weekday name. At least the first two "
996 "letters of an English weekday name must be "
1001 /* Date & time formats. */
1003 /* Helper function for passing to
1004 calendar_gregorian_to_offset. */
1006 calendar_error (void *i_, const char *format, ...)
1008 struct data_in *i = i_;
1011 va_start (args, format);
1012 vdata_warning (i, format, args);
1016 /* Parses WKDAY format. */
1018 parse_WKDAY (struct data_in *i)
1022 if (trim_spaces_and_check_missing (i))
1025 if (!parse_weekday (i, &weekday)
1026 || !parse_trailer (i))
1029 i->output->f = weekday;
1033 /* Parses MONTH format. */
1035 parse_MONTH (struct data_in *i)
1039 if (trim_spaces_and_check_missing (i))
1042 if (!parse_month (i, &month)
1043 || !parse_trailer (i))
1046 i->output->f = month;
1050 /* Parses DATE, ADATE, EDATE, JDATE, SDATE, QYR, MOYR, KWYR,
1051 DATETIME, TIME and DTIME formats. */
1053 parse_date (struct data_in *i)
1055 long int year = INT_MIN;
1059 double time = 0, date = 0;
1060 enum time_sign time_sign = SIGN_NO_TIME;
1062 const char *template = fmt_date_template (i->format);
1063 size_t template_width = strlen (template);
1065 if (trim_spaces_and_check_missing (i))
1068 while (*template != '\0')
1070 unsigned char ch = *template;
1074 while (template[count] == ch)
1082 ok = count < 3 ? parse_day (i, &day) : parse_yday (i, &yday);
1085 ok = parse_month (i, &month);
1090 if (!c_isalpha (*template))
1091 max_digits = SIZE_MAX;
1094 if (ss_length (i->input) >= template_width + 2)
1099 ok = parse_year (i, &year, max_digits);
1103 ok = parse_quarter (i, &month);
1106 ok = parse_week (i, &yday);
1109 ok = parse_time_units (i, 60. * 60. * 24., &time_sign, &time);
1112 ok = parse_time_units (i, 60. * 60., &time_sign, &time);
1115 ok = parse_minute_second (i, &time);
1121 ok = parse_date_delimiter (i);
1124 ok = parse_time_delimiter (i);
1129 assert (count == 1);
1130 if (!ss_match_char (&i->input, c_toupper (ch))
1131 && !ss_match_char (&i->input, c_tolower (ch)))
1133 data_warning (i, _("`%c' expected in date field."), ch);
1141 if (!parse_trailer (i))
1144 if (year != INT_MIN)
1146 double ofs = calendar_gregorian_to_offset (year, month, day,
1150 date = (yday - 1 + ofs) * 60. * 60. * 24.;
1154 i->output->f = date + (time_sign == SIGN_NEGATIVE ? -time : time);
1159 /* Utility functions. */
1161 /* Outputs FORMAT with the given ARGS as a warning for input
1164 vdata_warning (const struct data_in *i, const char *format, va_list args)
1169 ds_init_empty (&text);
1170 ds_put_char (&text, '(');
1171 if (i->first_column != 0)
1173 if (i->first_column == i->last_column - 1)
1174 ds_put_format (&text, _("column %d"), i->first_column);
1176 ds_put_format (&text, _("columns %d-%d"),
1177 i->first_column, i->last_column - 1);
1178 ds_put_cstr (&text, ", ");
1180 ds_put_format (&text, _("%s field) "), fmt_name (i->format));
1181 ds_put_vformat (&text, format, args);
1183 m.category = MSG_DATA;
1184 m.severity = MSG_WARNING;
1185 m.text = ds_cstr (&text);
1190 /* Outputs FORMAT with the given ARGS as a warning for input
1193 data_warning (const struct data_in *i, const char *format, ...)
1197 va_start (args, format);
1198 vdata_warning (i, format, args);
1202 /* Apply implied decimal places to output. */
1204 apply_implied_decimals (struct data_in *i)
1206 if (i->implied_decimals > 0)
1207 i->output->f /= pow (10., i->implied_decimals);
1210 /* Sets the default result for I.
1211 For a numeric format, this is the value set on SET BLANKS
1212 (typically system-missing); for a string format, it is all
1215 default_result (struct data_in *i)
1217 if (fmt_is_string (i->format))
1218 memset (i->output->s, ' ', i->width);
1220 i->output->f = settings_get_blanks ();
1223 /* Trims leading and trailing spaces from I.
1224 If the result is empty, or a single period character, then
1225 sets the default result and returns true; otherwise, returns
1228 trim_spaces_and_check_missing (struct data_in *i)
1230 ss_trim (&i->input, ss_cstr (" "));
1231 if (ss_is_empty (i->input) || ss_equals (i->input, ss_cstr (".")))
1239 /* Returns the integer value of hex digit C. */
1243 const char s[] = "0123456789abcdef";
1244 const char *cp = strchr (s, c_tolower ((unsigned char) c));
1246 assert (cp != NULL);