// Copyright (c) 2014-2017 Thomas Fussell // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, WRISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE // // @license: http://www.opensource.org/licenses/mit-license.php // @author: see AUTHORS file #pragma once #include #include #include #include class test_number_format; namespace xlnt { namespace detail { enum class format_color { black, blue, cyan, green, magenta, red, white, yellow, color1, color2, color3, color4, color5, color6, color7, color8, color9, color10, color11, color12, color13, color14, color15, color16, color17, color18, color19, color20, color21, color22, color23, color24, color25, color26, color27, color28, color29, color30, color31, color32, color33, color34, color35, color36, color37, color38, color39, color40, color41, color42, color43, color44, color45, color46, color47, color48, color49, color50, color51, color52, color53, color54, color55, color56 }; enum class format_locale { arabic_saudi_arabia = 0x401, bulgarian = 0x402, catalan = 0x403, chinese_taiwan = 0x404, czech = 0x405, danish = 0x406, german_germany = 0x407, greek = 0x408, english_united_states = 0x409, italian_italy = 0x410, japanese = 0x411, korean = 0x412, dutch_netherlands = 0x413, norwegian_bokml = 0x414, polish = 0x415, portuguese_brazil = 0x416, raeto_romance = 0x417, romanian_romania = 0x418, russian = 0x419, urdu = 0x420, indonesian = 0x421, ukrainian = 0x422, belarusian = 0x423, slovenian = 0x424, estonian = 0x425, latvian = 0x426, lithuanian = 0x427, tajik = 0x428, farsi_persian = 0x429, sesotho_sutu = 0x430, tsonga = 0x431, setsuana = 0x432, venda = 0x433, xhosa = 0x434, zulu = 0x435, afrikaans = 0x436, georgian = 0x437, faroese = 0x438, hindi = 0x439, kyrgyz_cyrillic = 0x440, swahili = 0x441, turkmen = 0x442, uzbek_latin = 0x443, tatar = 0x444, bengali_india = 0x445, punjabi = 0x446, gujarati = 0x447, oriya = 0x448, tamil = 0x449, mongolian = 0x450, tibetan = 0x451, welsh = 0x452, khmer = 0x453, lao = 0x454, burmese = 0x455, galician = 0x456, konkani = 0x457, manipuri = 0x458, sindhi = 0x459, kashmiri = 0x460, nepali = 0x461, frisian_netherlands = 0x462, filipino = 0x464, divehi_dhivehi_maldivian = 0x465, edo = 0x466, igbo_nigeria = 0x470, guarani_paraguay = 0x474, latin = 0x476, somali = 0x477, maori = 0x481, arabic_iraq = 0x801, chinese_china = 0x804, german_switzerland = 0x807, english_great_britain = 0x809, italian_switzerland = 0x810, dutch_belgium = 0x813, norwegian_nynorsk = 0x814, portuguese_portugal = 0x816, romanian_moldova = 0x818, russian_moldova = 0x819, uzbek_cyrillic = 0x843, bengali_bangladesh = 0x845, mongolian2 = 0x850, arabic_libya = 0x1001, chinese_singapore = 0x1004, german_luxembourg = 0x1007, english_canada = 0x1009, arabic_algeria = 0x1401, chinese_macau_sar = 0x1404, german_liechtenstein = 0x1407, english_new_zealand = 0x1409, arabic_morocco = 0x1801, english_ireland = 0x1809, arabic_oman = 0x2001, english_jamaica = 0x2009, arabic_yemen = 0x2401, english_caribbean = 0x2409, arabic_syria = 0x2801, english_belize = 0x2809, arabic_lebanon = 0x3001, english_zimbabwe = 0x3009, arabic_kuwait = 0x3401, english_phillippines = 0x3409, arabic_united_arab_emirates = 0x3801, arabic_qatar = 0x4001 }; // TODO this really shouldn't be exported... struct XLNT_API format_condition { enum class condition_type { less_than, less_or_equal, equal, not_equal, greater_than, greater_or_equal } type = condition_type::not_equal; long double value = 0; bool satisfied_by(long double number) const; }; struct format_placeholders { enum class placeholders_type { general, text, integer_only, integer_part, fractional_part, fraction_integer, fraction_numerator, fraction_denominator, scientific_significand, scientific_exponent_plus, scientific_exponent_minus } type = placeholders_type::general; bool use_comma_separator = false; bool percentage = false; bool scientific = false; std::size_t num_zeros = 0; // 0 std::size_t num_optionals = 0; // # std::size_t num_spaces = 0; // ? std::size_t thousands_scale = 0; }; struct number_format_token { enum class token_type { color, locale, condition, text, fill, space, number, datetime, end_section, end } type = token_type::end; std::string string; }; struct template_part { enum class template_type { text, fill, space, general, month_number, month_number_leading_zero, month_abbreviation, month_name, month_letter, day_number, day_number_leading_zero, day_abbreviation, day_name, year_short, year_long, hour, hour_leading_zero, minute, minute_leading_zero, second, second_fractional, second_leading_zero, second_leading_zero_fractional, am_pm, a_p, elapsed_hours, elapsed_minutes, elapsed_seconds } type = template_type::general; std::string string; format_placeholders placeholders; }; struct format_code { bool has_color = false; format_color color = format_color::black; bool has_locale = false; format_locale locale = format_locale::english_united_states; bool has_condition = false; format_condition condition; bool is_datetime = false; bool is_timedelta = false; bool twelve_hour = false; std::vector parts; }; class number_format_parser { public: number_format_parser(const std::string &format_string); const std::vector &result() const; void reset(const std::string &format_string); void parse(); private: void finalize(); void validate(); number_format_token parse_next_token(); format_placeholders parse_placeholders(const std::string &placeholders_string); format_color color_from_string(const std::string &color); std::pair locale_from_string(const std::string &locale_string); std::size_t position_ = 0; std::string format_string_; std::vector codes_; }; class XLNT_API number_formatter { public: number_formatter(const std::string &format_string, xlnt::calendar calendar); std::string format_number(long double number); std::string format_text(const std::string &text); private: friend class ::test_number_format; std::string fill_placeholders(const format_placeholders &p, long double number); std::string fill_fraction_placeholders(const format_placeholders &numerator, const format_placeholders &denominator, long double number, bool improper); std::string fill_scientific_placeholders(const format_placeholders &integer_part, const format_placeholders &fractional_part, const format_placeholders &exponent_part, long double number); std::string format_number(const format_code &format, long double number); std::string format_text(const format_code &format, const std::string &text); number_format_parser parser_; std::vector format_; xlnt::calendar calendar_; }; } // namespace detail } // namespace xlnt