diff options
| author | Mattias Andrée <maandree@kth.se> | 2021-09-07 23:16:18 +0200 | 
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2021-09-07 23:16:18 +0200 | 
| commit | d2ca51992555eedcd140a6e7e6ed5e5d2996ca67 (patch) | |
| tree | d47680f9e7e840ded78eaf34fd49e0c1fda13d3c | |
| parent | Remove leftover code (diff) | |
| download | libnumtext-d2ca51992555eedcd140a6e7e6ed5e5d2996ca67.tar.gz libnumtext-d2ca51992555eedcd140a6e7e6ed5e5d2996ca67.tar.bz2 libnumtext-d2ca51992555eedcd140a6e7e6ed5e5d2996ca67.tar.xz  | |
Simplify code
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to '')
| -rw-r--r-- | common.h | 2 | ||||
| -rw-r--r-- | swedish.c | 317 | 
2 files changed, 157 insertions, 162 deletions
@@ -24,5 +24,7 @@  #define UNICODE_MINUS "−" +#define IS_UTF8_CHAR_CONTINUATION(B) (((B) & 0xC0) == 0x80) +  ssize_t libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num, size_t num_len, uint32_t flags); @@ -2,6 +2,9 @@  #include "common.h" +#define TYPE_INDEX(F)            (ORDINAL(F) | DENOMINATOR(F)) +#define FORM_INDEX(F)            ((PLURAL_FORM(F) | DEFINITE_FORM(F)) / LIBNUMTEXT_N2T_SWEDISH_PLURAL_FORM) +  #define CARDINAL(F)              (!ORDINAL(F))  #define ORDINAL(F)               ((F) & LIBNUMTEXT_N2T_SWEDISH_ORDINAL) @@ -79,7 +82,7 @@ static struct digit {  static struct ten {  	const char *cardinal;  	const char *ordinal; -} tens[] = { +} tens[10] = {  	{NULL,       NULL},  	{NULL,       NULL},  	{"Tju¦go",   "Tju¦gon"}, @@ -92,17 +95,38 @@ static struct ten {  	{"Nit¦tio",  "Nit¦ti¦on"}  }; -static const char *wholes_and_halves[][5] = { -	{"Hel",  "He¦la",  "Hel¦an",  "Hel¦or¦na",  "Hel¦te"}, -	{"Halv", "Hal¦vor", "Halv¦an", "Halv¦or¦na", "Half¦te"} +static struct special_denominator { +	const char *cardinal[4 /* form */]; +	const char *ordinal; +} wholes_and_halves[] = { +	{{"Hel",  "He¦la",  "Hel¦an",  "Hel¦or¦na"},  "Hel¦te"}, +	{{"Halv", "Hal¦vor", "Halv¦an", "Halv¦or¦na"}, "Half¦te"} +}; + +static struct denominator_suffix { +	const char *cardinal[4 /* form */]; +	const char *ordinal; +} denominator_suffixes = {{"||del",  "||del¦ar",  "||del¦en",  "||del¦ar¦na"},  "||del¦te"}; + +static const char *signs[2 /* whether + */][4 /* type */] = { +	{"Min¦us ", "Min¦us-", "Min¦us-", "Min¦us-"}, +	{"Plus ",   "Plus-",   "Plus-",   "Plus-"}  }; -static const char *great_suffixes[] = { +static const char *great_suffixes[2] = {  	"il¦jon",  	"il¦jard"  }; -static const char *greats[][7] = { +static struct great { +	const char *single_digit; +	const char *ones; +	const char *ones_suffixes; +	const char *tens_prefixes; +	const char *tens; +	const char *hundreds_prefixes; +	const char *hundreds; +} greats[] = {  	{NULL,       NULL,          NULL, NULL,  NULL,                NULL,  NULL},  	{"||m",      "||un",        "",   "n",   "||de¦ci",           "nx*", "||cen¦ti"},  	{"||b",      "||duo",       "",   "ms",  "||vi|gin¦ti",       "n",   "||du|cen¦ti"}, @@ -122,6 +146,8 @@ struct state {  	size_t len;  	uint32_t flags;  	char double_char; +	char first; +	const char *append_for_ordinal;  }; @@ -146,15 +172,13 @@ append(struct state *state, const char *appendage)  			shift = appendage[0] == '<';  			appendage = &appendage[shift];  			appendage = &appendage[sizeof("¦") - 1]; -			if (SECONDARY_HYPHENATION(flags)) { +			if (SECONDARY_HYPHENATION(flags))  				p = stpcpy(hyphen, "¦"); -			} else if (SYLLABLE_HYPHENATION(flags)) { +			else if (SYLLABLE_HYPHENATION(flags))  				p = stpcpy(hyphen, "|"); -			} else { -				*hyphen = 0; -				p = NULL; /* silence clang */ -			} -			if (*hyphen) { +			else +				p = NULL; +			if (p) {  				if (shift && state->len <= state->outbuf_size) {  					*p++ = state->outbuf[--state->len];  					*p = '\0'; @@ -178,7 +202,7 @@ append(struct state *state, const char *appendage)  			}  		} -		if (state->len && (HYPHENATED(flags) | HYPHENATION(flags))) { +		if (state->len && (HYPHENATED(flags) || HYPHENATION(flags))) {  			if (isupper(appendage[0]) || (appendage[0] == "Å"[0] && appendage[1] == "Å"[1])) {  				if (state->len < state->outbuf_size)  					state->outbuf[state->len] = HYPHENATED(flags) ? '-' : '|'; @@ -196,41 +220,85 @@ append(struct state *state, const char *appendage)  static void -suffix(struct state *state) +append_final_digit(struct state *state, int digit)  { -	uint32_t flags = state->flags; -	const char *appendage; +	uint32_t f = state->flags; +	struct digit *d = &digits[digit]; -	if (ORDINAL(flags)) { -		if (DENOMINATOR(flags)) -			appendage = "||delte"; +	if (ORDINAL(f) || DENOMINATOR(f)) { +		if (MASCULINE_GENDER(f) && d->ordinal_masculine) +			append(state, d->ordinal_masculine);  		else -			return; -	} else if (DENOMINATOR(flags)) { -		if (PLURAL_FORM(flags)) -			appendage = DEFINITE_FORM(flags) ? "||del¦ar¦na" : "||del¦ar"; +			append(state, d->ordinal_other); +		state->append_for_ordinal = d->ordinal_suffix; +	} else { +		if (COMMON_GENDER(f) || !d->cardinal_other) +			append(state, d->cardinal_common);  		else -			appendage = DEFINITE_FORM(flags) ? "||del¦en" : "||del"; +			append(state, d->cardinal_other); +		state->append_for_ordinal = NULL; +	} +} + + +static void +append_hundreds(struct state *state, int hundreds) +{ +	if (hundreds) { +		if (state->first && hundreds == 1 && IMPLICIT_ONE(state->flags)) { +			append(state, "Hun¦dra"); +		} else { +			append(state, digits[hundreds].cardinal_common); +			append(state, "||hun¦dra"); +		} +		state->append_for_ordinal = "¦de"; +		state->first = 0; +	} +} + + +static void +append_thousands(struct state *state, int ten_thousands, int one_thousands) +{ +	if (state->first && ten_thousands == 0 && one_thousands == 1 && IMPLICIT_ONE(state->flags)) { +		append(state, "Tu¦sen");  	} else { -		return; +		if (tens[ten_thousands].cardinal) +			append(state, tens[ten_thousands].cardinal); +		else +			one_thousands += ten_thousands * 10; +		if (one_thousands) +			append(state, digits[one_thousands].cardinal_common); +		append(state, "||tu¦sen");  	} +	state->append_for_ordinal = "¦de"; +	state->first = 0; +} -	append(state, appendage); + +static char +get_common_affix(const char *suffixes, const char *prefixes) +{ +	const char *s, *p; +	if (suffixes && prefixes) +		for (p = prefixes; *p; p++) +			for (s = suffixes; *s; s++) +				if (*p == *s) +					return *p == '*' ? 's' : *p; +	return '\0';  }  ssize_t  libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num, size_t num_len, uint32_t flags)  { -	int first = 1; -	int hundred_thousands, thousands, orig_thousands, hundreds, ones; +	int hundred_thousands, ten_thousands, one_thousands, hundreds, ones;  	int32_t small_num; -	const char *great_1, *great_1_suffix, *great_last; -	const char *great_10, *great_10_prefix, *gsuffix; -	const char *great_100, *great_100_prefix, *gprefix; +	const char *great_1, *great_1_suffixes, *great_last; +	const char *great_10, *great_10_prefixes; +	const char *great_100, *great_100_prefixes;  	char affix[2] = {[1] = 0};  	size_t great_order, small_order, great_order_suffix, i; -	const char *append_for_ordinal = NULL;  	size_t trailing_zeroes;  	struct state state; @@ -245,16 +313,15 @@ libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num,  	state.len = 0;  	state.flags = flags;  	state.double_char = 0; +	state.first = 1; +	state.append_for_ordinal = NULL;  	if (!isdigit(num[0])) { -		if (ORDINAL(flags) || DENOMINATOR(flags)) -			append(&state, num[0] == '+' ? "Plus-" : "Min¦us-"); -		else -			append(&state, num[0] == '+' ? "Plus " : "Min¦us "); +		append(&state, signs[num[0] == '+'][TYPE_INDEX(flags)]);  		do {  			num++;  			num_len--; -		} while ((*num & 0xC0) == 0x80); +		} while (IS_UTF8_CHAR_CONTINUATION(*num));  	}  	while (num_len > 1 && num[0] == '0') { @@ -264,18 +331,13 @@ libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num,  	if (num_len == 1) {  		if (num[0] == '0') { -			if (ORDINAL(flags) || DENOMINATOR(flags)) -				append(&state, digits[0].ordinal_other); -			else -				append(&state, digits[0].cardinal_common); -			suffix(&state); -			goto out; +			append_final_digit(&state, 0); +			goto out_and_suffix;  		} else if (num[0] <= '2' && DENOMINATOR(flags)) {  			if (ORDINAL(flags)) -				i = 4; +				append(&state, wholes_and_halves[num[0] - '1'].ordinal);  			else -				i = (size_t)((flags / LIBNUMTEXT_N2T_SWEDISH_PLURAL_FORM) & 3); -			append(&state, wholes_and_halves[num[0] - '1'][i]); +				append(&state, wholes_and_halves[num[0] - '1'].cardinal[FORM_INDEX(flags)]);  			goto out;  		}  	} @@ -294,102 +356,65 @@ libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num,  		small_order = num_len % 6;  		great_order_suffix = 0; -		hundred_thousands = thousands = hundreds = ones = 0; -		small_num = 0; +		hundred_thousands = ten_thousands = one_thousands = hundreds = ones = 0;  		if (great_order && small_order >= 3) {  			small_order -= 3;  			great_order_suffix = 1;  		} -		orig_thousands = 0; +		small_num = 0;  		switch (small_order) {  		case 5:  			hundred_thousands = *num++ - '0';  			small_num = (int32_t)hundred_thousands;  			num_len--; -			if (hundred_thousands) { -				if (first && hundred_thousands == 1 && IMPLICIT_ONE(flags)) { -					append(&state, "Hun¦dra"); -				} else { -					append(&state, digits[hundred_thousands].cardinal_common); -					append(&state, "||hun¦dra"); -				} -				append_for_ordinal = "¦de"; -				first = 0; -			} +			append_hundreds(&state, hundred_thousands);  			FALL_THROUGH  			/* fall through */  		case 4: -			thousands = *num++ - '0'; -			orig_thousands = thousands; +			ten_thousands = *num++ - '0'; +			small_num *= 10; +			small_num += (int32_t)ten_thousands;  			num_len--; -			if (tens[thousands].cardinal) { -				append(&state, tens[thousands].cardinal); -				thousands = 0; -				first = 0; -			} else { -				thousands *= 10; -			}  			FALL_THROUGH  			/* fall through */  		case 3: +			one_thousands = *num++ - '0';  			small_num *= 10; -			small_num += (int32_t)(*num - '0'); -			thousands += *num++ - '0'; +			small_num += (int32_t)one_thousands;  			num_len--; -			if (thousands) { -				if (first && thousands == 1 && IMPLICIT_ONE(flags)) { -					append(&state, "Tu¦sen"); -				} else { -					append(&state, digits[thousands].cardinal_common); -					append(&state, "||tu¦sen"); -				} -				append_for_ordinal = "¦de"; -				first = 0; -			} else if (hundred_thousands || orig_thousands) { -				append(&state, "||tu¦sen"); -				append_for_ordinal = "¦de"; -				first = 0; -			} +			if (small_num) +				append_thousands(&state, ten_thousands, one_thousands);  			FALL_THROUGH  			/* fall through */  		case 2: -			small_num *= 10; -			small_num += (int32_t)(*num - '0');  			hundreds = *num++ - '0'; +			small_num *= 10; +			small_num += (int32_t)hundreds;  			num_len--; -			if (hundreds) { -				if (first && hundreds == 1 && IMPLICIT_ONE(flags)) { -					append(&state, "Hun¦dra"); -				} else { -					append(&state, digits[hundreds].cardinal_common); -					append(&state, "||hun¦dra"); -				} -				append_for_ordinal = "¦de"; -				first = 0; -			} +			append_hundreds(&state, hundreds);  			FALL_THROUGH  			/* fall through */  		case 1: -			small_num *= 10; -			small_num += (int32_t)(*num - '0');  			ones = *num++ - '0'; +			small_num *= 10; +			small_num += (int32_t)ones;  			num_len--;  			if (tens[ones].cardinal) {  				if (!great_order && (DENOMINATOR(flags) || ORDINAL(flags)) && *num == '0') {  					append(&state, tens[ones].ordinal); -					append_for_ordinal = "¦de"; +					state.append_for_ordinal = "¦de";  				} else {  					append(&state, tens[ones].cardinal); -					append_for_ordinal = NULL; +					state.append_for_ordinal = NULL;  				}  				ones = 0; -				first = 0; +				state.first = 0;  			} else {  				ones *= 10;  			} @@ -401,83 +426,46 @@ libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num,  			small_num += (int32_t)(*num - '0');  			ones += *num++ - '0';  			if (ones) { -				append_for_ordinal = NULL; -				if (!great_order && (DENOMINATOR(flags) || ORDINAL(flags))) { -					if (MASCULINE_GENDER(flags) && digits[ones].ordinal_masculine) -						append(&state, digits[ones].ordinal_masculine); -					else -						append(&state, digits[ones].ordinal_other); -					append_for_ordinal = digits[ones].ordinal_suffix; -				} else if (!digits[ones].cardinal_other) { -					append(&state, digits[ones].cardinal_common); -				} else if (great_order) { +				state.append_for_ordinal = NULL; +				if (!great_order) +					append_final_digit(&state, ones); +				else if (digits[ones].cardinal_other)  					append(&state, digits[ones].cardinal_other); -				} else if (COMMON_GENDER(flags)) { +				else  					append(&state, digits[ones].cardinal_common); -				} else { -					append(&state, digits[ones].cardinal_other); -				} -				first = 0; +				state.first = 0;  			}  			break;  		}  		if (great_order && small_num) {  			if (great_order < 10) { -				append(&state, greats[great_order][0]); +				append(&state, greats[great_order].single_digit);  			} else if (great_order > 999) {  				errno = EDOM;  				return -1;  			} else { -				great_1          = greats[(great_order / 1) % 10][1]; -				great_1_suffix   = greats[(great_order / 1) % 10][2]; -				great_10_prefix  = greats[(great_order / 10) % 10][3]; -				great_10         = greats[(great_order / 10) % 10][4]; -				great_100_prefix = greats[(great_order / 100) % 10][5]; -				great_100        = greats[(great_order / 100) % 10][6]; +				great_1            = greats[(great_order /   1) % 10].ones; +				great_1_suffixes   = greats[(great_order /   1) % 10].ones_suffixes; +				great_10_prefixes  = greats[(great_order /  10) % 10].tens_prefixes; +				great_10           = greats[(great_order /  10) % 10].tens; +				great_100_prefixes = greats[(great_order / 100) % 10].hundreds_prefixes; +				great_100          = greats[(great_order / 100) % 10].hundreds;  				great_last = NULL;  				if (great_1) {  					append(&state, great_1);  					great_last = great_1;  				}  				if (great_10) { -					if (great_1_suffix && great_10_prefix) { -						gsuffix = NULL; /* silence clang */ -						for (gprefix = great_10_prefix; *gprefix; gprefix++) { -							for (gsuffix = great_1_suffix; *gsuffix; gsuffix++) -								if (*gprefix == *gsuffix) -									break; -							if (*gsuffix) -								break; -						} -						if (*gprefix && *gprefix == *gsuffix) { -							affix[0] = *gprefix; -							if (affix[0] == '*') -								affix[0] = 's'; -							append(&state, affix); -						} -					} +					if ((affix[0] = get_common_affix(great_1_suffixes, great_10_prefixes))) +						append(&state, affix);  					append(&state, great_10);  					great_last = great_10; -					great_1_suffix = NULL; +					great_1_suffixes = NULL;  				}  				if (great_100) { -					if (great_1_suffix && great_100_prefix) { -						gsuffix = NULL; /* silence clang */ -						for (gprefix = great_100_prefix; *gprefix; gprefix++) { -							for (gsuffix = great_1_suffix; *gsuffix; gsuffix++) -								if (*gprefix == *gsuffix) -									break; -							if (*gsuffix) -								break; -						} -						if (*gprefix && *gprefix == *gsuffix) { -							affix[0] = *gprefix; -							if (affix[0] == '*') -								affix[0] = 's'; -							append(&state, affix); -						} -					} +					if ((affix[0] = get_common_affix(great_1_suffixes, great_100_prefixes))) +						append(&state, affix);  					append(&state, great_100);  					great_last = great_100;  				} @@ -487,16 +475,21 @@ libnumtext_num2text_swedish__(char *outbuf, size_t outbuf_size, const char *num,  					state.len -= 1;  			}  			append(&state, great_suffixes[great_order_suffix]); -			append_for_ordinal = great_order_suffix == 0 ? "¦te" : "<¦e"; +			state.append_for_ordinal = great_order_suffix == 0 ? "¦te" : "<¦e";  			if (small_num != 1)  				if (num_len > trailing_zeroes || !(ORDINAL(flags) || DENOMINATOR(flags)))  					append(&state, "¦er");  		}  	} -	if (ORDINAL(flags) && !DENOMINATOR(flags) && append_for_ordinal) -		append(&state, append_for_ordinal); -	suffix(&state); +	if (ORDINAL(flags) && !DENOMINATOR(flags) && state.append_for_ordinal) +		append(&state, state.append_for_ordinal); + +out_and_suffix: +	if (DENOMINATOR(state.flags)) { +		append(&state, ORDINAL(state.flags) ? denominator_suffixes.ordinal +		                                    : denominator_suffixes.cardinal[FORM_INDEX(state.flags)]); +	}  out:  	if (state.len < outbuf_size) @@ -524,7 +517,7 @@ out:  	i = 0;  	if (SENTENCE_CASE(flags)) {  		i = 1; -		while ((outbuf[i] & 0xC0) == 0x80) +		while (IS_UTF8_CHAR_CONTINUATION(outbuf[i]))  			i += 1;  		goto lower_case;  | 
