81 |
vdls_error (i, format, args); |
vdls_error (i, format, args); |
82 |
va_end (args); |
va_end (args); |
83 |
} |
} |
84 |
|
|
85 |
|
/* Parsing utility functions. */ |
86 |
|
|
87 |
/* Excludes leading and trailing whitespace from I by adjusting |
/* Excludes leading and trailing whitespace from I by adjusting |
88 |
pointers. */ |
pointers. */ |
103 |
{ |
{ |
104 |
return i->s < i->e; |
return i->s < i->e; |
105 |
} |
} |
106 |
|
|
107 |
|
/* If implied decimal places are enabled, apply them to |
108 |
|
I->v->f. */ |
109 |
|
static void |
110 |
|
apply_implied_decimals (struct data_in *i) |
111 |
|
{ |
112 |
|
if ((i->flags & DI_IMPLIED_DECIMALS) && i->format.d > 0) |
113 |
|
i->v->f /= pow (10., i->format.d); |
114 |
|
} |
115 |
|
|
116 |
/* Format parsers. */ |
/* Format parsers. */ |
117 |
|
|
121 |
static int |
static int |
122 |
parse_numeric (struct data_in *i) |
parse_numeric (struct data_in *i) |
123 |
{ |
{ |
124 |
short int sign; /* +1 or -1. */ |
int sign; /* +1 or -1. */ |
125 |
double num; /* The number so far. */ |
double num; /* The number so far. */ |
126 |
|
|
127 |
int got_dot; /* Found a decimal point. */ |
int got_dot; /* Found a decimal point. */ |
207 |
i->v->f = SYSMIS; |
i->v->f = SYSMIS; |
208 |
return 1; |
return 1; |
209 |
} |
} |
210 |
goto noconv; |
dls_error (i, _("Field does not form a valid floating-point constant.")); |
211 |
|
i->v->f = SYSMIS; |
212 |
|
return 0; |
213 |
} |
} |
214 |
|
|
215 |
if (have_char (i) |
if (have_char (i) |
222 |
if (isalpha (*i->s)) |
if (isalpha (*i->s)) |
223 |
i->s++; |
i->s++; |
224 |
if (!parse_int (i, &exp)) |
if (!parse_int (i, &exp)) |
225 |
goto noconv; |
{ |
226 |
|
i->v->f = SYSMIS; |
227 |
|
return 0; |
228 |
|
} |
229 |
|
|
230 |
exponent += exp; |
exponent += exp; |
231 |
} |
} |
232 |
else if (!got_dot) |
else if (!got_dot && (i->flags & DI_IMPLIED_DECIMALS)) |
233 |
exponent -= i->format.d; |
exponent -= i->format.d; |
234 |
|
|
235 |
if (type == FMT_PCT && have_char (i) && *i->s == '%') |
if (type == FMT_PCT && have_char (i) && *i->s == '%') |
249 |
|
|
250 |
/* Multiply NUM by 10 to the EXPONENT power, checking for overflow |
/* Multiply NUM by 10 to the EXPONENT power, checking for overflow |
251 |
and underflow. */ |
and underflow. */ |
|
|
|
252 |
if (exponent < 0) |
if (exponent < 0) |
253 |
{ |
{ |
254 |
if (-exponent + got_digit > -(DBL_MIN_10_EXP) + 5 |
if (-exponent + got_digit > -(DBL_MIN_10_EXP) + 5 |
255 |
|| num < DBL_MIN * pow (10.0, (double) -exponent)) |
|| num < DBL_MIN * pow (10.0, (double) -exponent)) |
256 |
goto underflow; |
{ |
257 |
|
dls_error (i, _("Underflow in floating-point constant.")); |
258 |
|
i->v->f = 0.0; |
259 |
|
return 0; |
260 |
|
} |
261 |
|
|
262 |
num *= pow (10.0, (double) exponent); |
num *= pow (10.0, (double) exponent); |
263 |
} |
} |
264 |
else if (exponent > 0) |
else if (exponent > 0) |
265 |
{ |
{ |
266 |
if (num > DBL_MAX * pow (10.0, (double) -exponent)) |
if (num > DBL_MAX * pow (10.0, (double) -exponent)) |
267 |
goto overflow; |
{ |
268 |
|
dls_error (i, _("Overflow in floating-point constant.")); |
269 |
|
i->v->f = SYSMIS; |
270 |
|
return 0; |
271 |
|
} |
272 |
|
|
273 |
num *= pow (10.0, (double) exponent); |
num *= pow (10.0, (double) exponent); |
274 |
} |
} |
275 |
|
|
276 |
i->v->f = sign * num; |
i->v->f = sign > 0 ? num : -num; |
277 |
return 1; |
return 1; |
|
|
|
|
overflow: |
|
|
/* Return an overflow error. */ |
|
|
dls_error (i, _("Overflow in floating-point constant.")); |
|
|
i->v->f = SYSMIS; |
|
|
return 0; |
|
|
|
|
|
underflow: |
|
|
/* Return an underflow error. */ |
|
|
dls_error (i, _("Underflow in floating-point constant.")); |
|
|
i->v->f = 0.0; |
|
|
return 0; |
|
|
|
|
|
noconv: |
|
|
/* There was no number. */ |
|
|
dls_error (i, _("Field does not form a valid floating-point constant.")); |
|
|
i->v->f = SYSMIS; |
|
|
return 0; |
|
278 |
} |
} |
279 |
|
|
280 |
/* Returns the integer value of hex digit C. */ |
/* Returns the integer value of hex digit C. */ |
305 |
i->v->f = i->v->f * 10.0 + *cp - '0'; |
i->v->f = i->v->f * 10.0 + *cp - '0'; |
306 |
} |
} |
307 |
|
|
308 |
if (i->format.d) |
apply_implied_decimals (i); |
|
i->v->f /= pow (10.0, i->format.d); |
|
309 |
return 1; |
return 1; |
310 |
} |
} |
311 |
|
|
380 |
parse_Z (struct data_in *i) |
parse_Z (struct data_in *i) |
381 |
{ |
{ |
382 |
char buf[64]; |
char buf[64]; |
383 |
|
bool got_dot = false; |
384 |
|
|
385 |
/* Warn user that we suck. */ |
/* Warn user that we suck. */ |
386 |
{ |
{ |
420 |
char *dp; |
char *dp; |
421 |
|
|
422 |
for (sp = i->s, dp = buf + 1; sp < i->e - 1; sp++, dp++) |
for (sp = i->s, dp = buf + 1; sp < i->e - 1; sp++, dp++) |
423 |
if (*sp == '.') |
if (*sp == '.') |
424 |
*dp = '.'; |
{ |
425 |
|
*dp = '.'; |
426 |
|
got_dot = true; |
427 |
|
} |
428 |
else if ((*sp & 0xf0) == 0xf0 && (*sp & 0xf) < 10) |
else if ((*sp & 0xf0) == 0xf0 && (*sp & 0xf) < 10) |
429 |
*dp = (*sp & 0xf) + '0'; |
*dp = (*sp & 0xf) + '0'; |
430 |
else |
else |
447 |
return 0; |
return 0; |
448 |
} |
} |
449 |
} |
} |
450 |
|
|
451 |
|
if (!got_dot) |
452 |
|
apply_implied_decimals (i); |
453 |
|
|
454 |
return 1; |
return 1; |
455 |
} |
} |
456 |
|
|
492 |
if (p[0] & 0x80) |
if (p[0] & 0x80) |
493 |
i->v->f = -(i->v->f + 1.0); |
i->v->f = -(i->v->f + 1.0); |
494 |
|
|
495 |
if (i->format.d) |
apply_implied_decimals (i); |
|
i->v->f /= pow (10.0, i->format.d); |
|
496 |
|
|
497 |
return 1; |
return 1; |
498 |
} |
} |
511 |
i->v->f = i->v->f * 256.0 + i->s[j]; |
i->v->f = i->v->f * 256.0 + i->s[j]; |
512 |
#endif |
#endif |
513 |
|
|
514 |
if (i->format.d) |
apply_implied_decimals (i); |
|
i->v->f /= pow (10.0, i->format.d); |
|
515 |
|
|
516 |
return 1; |
return 1; |
517 |
} |
} |
531 |
if ((*cp ^ (*cp >> 1)) & 0x10) |
if ((*cp ^ (*cp >> 1)) & 0x10) |
532 |
i->v->f = -i->v->f; |
i->v->f = -i->v->f; |
533 |
|
|
534 |
if (i->format.d) |
apply_implied_decimals (i); |
|
i->v->f /= pow (10.0, i->format.d); |
|
535 |
|
|
536 |
return 1; |
return 1; |
537 |
} |
} |
548 |
i->v->f = i->v->f * 10 + (*cp & 15); |
i->v->f = i->v->f * 10 + (*cp & 15); |
549 |
} |
} |
550 |
|
|
551 |
if (i->format.d) |
apply_implied_decimals (i); |
|
i->v->f /= pow (10.0, i->format.d); |
|
552 |
|
|
553 |
return 1; |
return 1; |
554 |
} |
} |
723 |
return 0; |
return 0; |
724 |
} |
} |
725 |
|
|
726 |
/* Formats NUMBER as Roman numerals in ROMAN, or as Arabic numerals if |
/* Association between a name and a value. */ |
727 |
the Roman expansion would be too long. */ |
struct enum_name |
|
static void |
|
|
to_roman (int number, char roman[32]) |
|
|
{ |
|
|
int save_number = number; |
|
|
|
|
|
struct roman_digit |
|
|
{ |
|
|
int value; /* Value corresponding to this digit. */ |
|
|
char name; /* Digit name. */ |
|
|
}; |
|
|
|
|
|
static const struct roman_digit roman_tab[7] = |
|
728 |
{ |
{ |
729 |
{1000, 'M'}, |
const char *name; /* Name. */ |
730 |
{500, 'D'}, |
bool can_abbreviate; /* True if name may be abbreviated. */ |
731 |
{100, 'C'}, |
int value; /* Value associated with name. */ |
|
{50, 'L'}, |
|
|
{10, 'X'}, |
|
|
{5, 'V'}, |
|
|
{1, 'I'}, |
|
732 |
}; |
}; |
733 |
|
|
734 |
char *cp = roman; |
/* Reads a name from I and sets *OUTPUT to the value associated |
735 |
|
with that name. Returns true if successful, false otherwise. */ |
736 |
int i, j; |
static bool |
737 |
|
parse_enum (struct data_in *i, const char *what, |
738 |
assert (32 >= INT_DIGITS + 1); |
const struct enum_name *enum_names, |
739 |
if (number == 0) |
long *output) |
740 |
goto arabic; |
{ |
741 |
|
const char *name; |
742 |
|
size_t length; |
743 |
|
const struct enum_name *ep; |
744 |
|
|
745 |
if (number < 0) |
/* Consume alphabetic characters. */ |
746 |
|
name = i->s; |
747 |
|
length = 0; |
748 |
|
while (have_char (i) && isalpha (*i->s)) |
749 |
{ |
{ |
750 |
*cp++ = '-'; |
length++; |
751 |
number = -number; |
i->s++; |
752 |
} |
} |
753 |
|
if (length == 0) |
|
for (i = 0; i < 7; i++) |
|
754 |
{ |
{ |
755 |
int digit = roman_tab[i].value; |
dls_error (i, _("Parse error at `%c' expecting %s."), *i->s, what); |
756 |
while (number >= digit) |
return 0; |
|
{ |
|
|
number -= digit; |
|
|
if (cp > &roman[30]) |
|
|
goto arabic; |
|
|
*cp++ = roman_tab[i].name; |
|
|
} |
|
|
|
|
|
for (j = i + 1; j < 7; j++) |
|
|
{ |
|
|
if (i == 4 && j == 5) /* VX is not a shortened form of V. */ |
|
|
break; |
|
|
|
|
|
digit = roman_tab[i].value - roman_tab[j].value; |
|
|
while (number >= digit) |
|
|
{ |
|
|
number -= digit; |
|
|
if (cp > &roman[29]) |
|
|
goto arabic; |
|
|
*cp++ = roman_tab[j].name; |
|
|
*cp++ = roman_tab[i].name; |
|
|
} |
|
|
} |
|
757 |
} |
} |
|
*cp = 0; |
|
|
return; |
|
|
|
|
|
arabic: |
|
|
sprintf (roman, "%d", save_number); |
|
|
} |
|
758 |
|
|
759 |
/* Returns true if C is a (lowercase) roman numeral. */ |
for (ep = enum_names; ep->name != NULL; ep++) |
760 |
#define CHAR_IS_ROMAN(C) \ |
if ((ep->can_abbreviate |
761 |
((C) == 'x' || (C) == 'v' || (C) == 'i') |
&& lex_id_match_len (ep->name, strlen (ep->name), name, length)) |
762 |
|
|| (!ep->can_abbreviate && length == strlen (ep->name) |
763 |
|
&& !memcmp (name, ep->name, length))) |
764 |
|
{ |
765 |
|
*output = ep->value; |
766 |
|
return 1; |
767 |
|
} |
768 |
|
|
769 |
/* Returns the value of a single (lowercase) roman numeral. */ |
dls_error (i, _("Unknown %s `%.*s'."), what, (int) length, name); |
770 |
#define ROMAN_VALUE(C) \ |
return 0; |
771 |
((C) == 'x' ? 10 : ((C) == 'v' ? 5 : 1)) |
} |
772 |
|
|
773 |
static int |
static int |
774 |
parse_month (struct data_in *i, long *month) |
parse_month (struct data_in *i, long *month) |
775 |
{ |
{ |
776 |
|
static const struct enum_name month_names[] = |
777 |
|
{ |
778 |
|
{"january", true, 1}, |
779 |
|
{"february", true, 2}, |
780 |
|
{"march", true, 3}, |
781 |
|
{"april", true, 4}, |
782 |
|
{"may", true, 5}, |
783 |
|
{"june", true, 6}, |
784 |
|
{"july", true, 7}, |
785 |
|
{"august", true, 8}, |
786 |
|
{"september", true, 9}, |
787 |
|
{"october", true, 10}, |
788 |
|
{"november", true, 11}, |
789 |
|
{"december", true, 12}, |
790 |
|
|
791 |
|
{"i", false, 1}, |
792 |
|
{"ii", false, 2}, |
793 |
|
{"iii", false, 3}, |
794 |
|
{"iv", false, 4}, |
795 |
|
{"iiii", false, 4}, |
796 |
|
{"v", false, 5}, |
797 |
|
{"vi", false, 6}, |
798 |
|
{"vii", false, 7}, |
799 |
|
{"viii", false, 8}, |
800 |
|
{"ix", false, 9}, |
801 |
|
{"viiii", false, 9}, |
802 |
|
{"x", false, 10}, |
803 |
|
{"xi", false, 11}, |
804 |
|
{"xii", false, 12}, |
805 |
|
|
806 |
|
{NULL, false, 0}, |
807 |
|
}; |
808 |
|
|
809 |
if (!force_have_char (i)) |
if (!force_have_char (i)) |
810 |
return 0; |
return 0; |
811 |
|
|
819 |
dls_error (i, _("Month (%ld) must be between 1 and 12."), *month); |
dls_error (i, _("Month (%ld) must be between 1 and 12."), *month); |
820 |
return 0; |
return 0; |
821 |
} |
} |
822 |
|
else |
823 |
if (CHAR_IS_ROMAN (tolower (*i->s))) |
return parse_enum (i, _("month"), month_names, month); |
|
{ |
|
|
int last = ROMAN_VALUE (tolower (*i->s)); |
|
|
|
|
|
*month = 0; |
|
|
for (;;) |
|
|
{ |
|
|
int value; |
|
|
|
|
|
i->s++; |
|
|
if (!have_char || !CHAR_IS_ROMAN (tolower (*i->s))) |
|
|
{ |
|
|
if (last != INT_MAX) |
|
|
*month += last; |
|
|
break; |
|
|
} |
|
|
|
|
|
value = ROMAN_VALUE (tolower (*i->s)); |
|
|
if (last == INT_MAX) |
|
|
*month += value; |
|
|
else if (value > last) |
|
|
{ |
|
|
*month += value - last; |
|
|
last = INT_MAX; |
|
|
} |
|
|
else |
|
|
{ |
|
|
*month += last; |
|
|
last = value; |
|
|
} |
|
|
} |
|
|
|
|
|
if (*month < 1 || *month > 12) |
|
|
{ |
|
|
char buf[32]; |
|
|
|
|
|
to_roman (*month, buf); |
|
|
dls_error (i, _("Month (%s) must be between I and XII."), buf); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
return 1; |
|
|
} |
|
|
|
|
|
{ |
|
|
static const char *months[12] = |
|
|
{ |
|
|
"january", "february", "march", "april", "may", "june", |
|
|
"july", "august", "september", "october", "november", "december", |
|
|
}; |
|
|
|
|
|
char month_buf[32]; |
|
|
char *mp; |
|
|
|
|
|
int j; |
|
|
|
|
|
for (mp = month_buf; |
|
|
have_char (i) && isalpha (*i->s) && mp < &month_buf[31]; |
|
|
i->s++) |
|
|
*mp++ = tolower (*i->s); |
|
|
*mp = '\0'; |
|
|
|
|
|
if (have_char (i) && isalpha (*i->s)) |
|
|
{ |
|
|
dls_error (i, _("Month name (%s...) is too long."), month_buf); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
for (j = 0; j < 12; j++) |
|
|
if (lex_id_match (months[j], month_buf)) |
|
|
{ |
|
|
*month = j + 1; |
|
|
return 1; |
|
|
} |
|
|
|
|
|
dls_error (i, _("Bad month name (%s)."), month_buf); |
|
|
return 0; |
|
|
} |
|
824 |
} |
} |
825 |
|
|
826 |
static int |
static int |
1025 |
|
|
1026 |
|
|
1027 |
static int |
static int |
1028 |
parse_weekday (struct data_in *i, int *weekday) |
parse_weekday (struct data_in *i, long *weekday) |
1029 |
{ |
{ |
1030 |
/* PORTME */ |
static const struct enum_name weekday_names[] = |
|
#define TUPLE(A,B) \ |
|
|
(((A) << 8) + (B)) |
|
|
|
|
|
if (i->s + 1 >= i->e) |
|
1031 |
{ |
{ |
1032 |
dls_error (i, _("Day of the week expected in date value.")); |
{"sunday", true, 1}, |
1033 |
return 0; |
{"su", true, 1}, |
1034 |
} |
{"monday", true, 2}, |
1035 |
|
{"mo", true, 2}, |
1036 |
switch (TUPLE (tolower (i->s[0]), tolower (i->s[1]))) |
{"tuesday", true, 3}, |
1037 |
{ |
{"tu", true, 3}, |
1038 |
case TUPLE ('s', 'u'): |
{"wednesday", true, 4}, |
1039 |
*weekday = 1; |
{"we", true, 4}, |
1040 |
break; |
{"thursday", true, 5}, |
1041 |
|
{"th", true, 5}, |
1042 |
case TUPLE ('m', 'o'): |
{"friday", true, 6}, |
1043 |
*weekday = 2; |
{"fr", true, 6}, |
1044 |
break; |
{"saturday", true, 7}, |
1045 |
|
{"sa", true, 7}, |
1046 |
case TUPLE ('t', 'u'): |
|
1047 |
*weekday = 3; |
{NULL, false, 0}, |
1048 |
break; |
}; |
|
|
|
|
case TUPLE ('w', 'e'): |
|
|
*weekday = 4; |
|
|
break; |
|
|
|
|
|
case TUPLE ('t', 'h'): |
|
|
*weekday = 5; |
|
|
break; |
|
|
|
|
|
case TUPLE ('f', 'r'): |
|
|
*weekday = 6; |
|
|
break; |
|
|
|
|
|
case TUPLE ('s', 'a'): |
|
|
*weekday = 7; |
|
|
break; |
|
|
|
|
|
default: |
|
|
dls_error (i, _("Day of the week expected in date value.")); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
while (have_char (i) && isalpha (*i->s)) |
|
|
i->s++; |
|
|
|
|
|
return 1; |
|
1049 |
|
|
1050 |
#undef TUPLE |
return parse_enum (i, _("weekday"), weekday_names, weekday); |
1051 |
} |
} |
1052 |
|
|
1053 |
static int |
static int |
1320 |
static int |
static int |
1321 |
parse_WKDAY (struct data_in *i) |
parse_WKDAY (struct data_in *i) |
1322 |
{ |
{ |
1323 |
int weekday; |
long weekday; |
1324 |
|
|
1325 |
if (!parse_leader (i) |
if (!parse_leader (i) |
1326 |
|| !parse_weekday (i, &weekday) |
|| !parse_weekday (i, &weekday) |