@@ -2310,8 +2310,7 @@ class parser
23102310 }
23112311 }
23122312
2313- parse_type determine_value_type (const std::string::iterator& it,
2314- const std::string::iterator& end)
2313+ parse_type determine_value_type (const std::string::iterator& it, const std::string::iterator& end)
23152314 {
23162315 if (it == end)
23172316 {
@@ -2352,8 +2351,7 @@ class parser
23522351 throw_parse_exception (" Failed to parse value type" );
23532352 }
23542353
2355- parse_type determine_number_type (const std::string::iterator& it,
2356- const std::string::iterator& end)
2354+ parse_type determine_number_type (const std::string::iterator& it, const std::string::iterator& end)
23572355 {
23582356 // determine if we are an integer or a float
23592357 auto check_it = it;
@@ -2368,7 +2366,7 @@ class parser
23682366
23692367 while (check_it != end && is_number (*check_it))
23702368 ++check_it;
2371- if (check_it != end && *check_it == ' .' )
2369+ if (check_it != end && ( *check_it == ' .' || *check_it == ' e ' || *check_it == ' E ' ) )
23722370 {
23732371 ++check_it;
23742372 while (check_it != end && is_number (*check_it))
@@ -2381,8 +2379,7 @@ class parser
23812379 }
23822380 }
23832381
2384- std::shared_ptr<value<std::string>> parse_string (std::string::iterator& it,
2385- std::string::iterator& end)
2382+ std::shared_ptr<value<std::string>> parse_string (std::string::iterator& it, std::string::iterator& end)
23862383 {
23872384 auto delim = *it;
23882385 assert (delim == ' "' || delim == ' \' ' );
@@ -2400,9 +2397,87 @@ class parser
24002397 return parse_multiline_string (it, end, delim);
24012398 }
24022399 }
2400+ // Check for raw string
2401+ else if (delim == ' "' && check_it != end && *check_it == ' #' )
2402+ {
2403+ return parse_raw_string (it, end);
2404+ }
24032405 return make_value<std::string>(string_literal (it, end, delim));
24042406 }
24052407
2408+ std::shared_ptr<value<std::string>>
2409+ parse_raw_string (std::string::iterator& it, std::string::iterator& end)
2410+ {
2411+ // Skip the opening "
2412+ ++it;
2413+
2414+ // Count the number of # characters
2415+ size_t hash_count = 0 ;
2416+ while (it != end && *it == ' #' )
2417+ {
2418+ ++hash_count;
2419+ ++it;
2420+ }
2421+
2422+ if (it == end)
2423+ throw_parse_exception (" Unterminated raw string" );
2424+
2425+ std::stringstream ss;
2426+
2427+ // Handle the remainder of the current line
2428+ auto handle_line = [&](std::string::iterator& local_it, std::string::iterator& local_end)
2429+ {
2430+ while (local_it != local_end)
2431+ {
2432+ // Check if we've reached the end of the raw string
2433+ if (std::distance (local_it, local_end) >= hash_count + 1 )
2434+ {
2435+ bool found = true ;
2436+ auto check = local_it;
2437+ for (size_t i = 0 ; i < hash_count; ++i)
2438+ {
2439+ if (*check++ != ' #' )
2440+ {
2441+ found = false ;
2442+ break ;
2443+ }
2444+ }
2445+ if (found && *check == ' "' )
2446+ {
2447+ local_it = check + 1 ;
2448+ return true ; // End of raw string
2449+ }
2450+ }
2451+
2452+ ss << *local_it++;
2453+ }
2454+ return false ; // Not end of raw string
2455+ };
2456+
2457+ // Handle the current line
2458+ bool done = handle_line (it, end);
2459+ if (done)
2460+ return make_value<std::string>(ss.str ());
2461+
2462+ // Start eating lines
2463+ while (detail::getline (input_, line_))
2464+ {
2465+ ++line_number_;
2466+
2467+ it = line_.begin ();
2468+ end = line_.end ();
2469+
2470+ done = handle_line (it, end);
2471+ if (done)
2472+ return make_value<std::string>(ss.str ());
2473+
2474+ // Add the newline
2475+ ss << std::endl;
2476+ }
2477+
2478+ throw_parse_exception (" Unterminated raw string" );
2479+ }
2480+
24062481 std::shared_ptr<value<std::string>>
24072482 parse_multiline_string (std::string::iterator& it,
24082483 std::string::iterator& end, char delim)
@@ -3214,7 +3289,7 @@ class parser
32143289
32153290/* *
32163291 * Utility function to parse a file as a TOML file. Returns the root table.
3217- * Throws a parse_exception if the file cannot be opened.
3292+ * Throws a parse_exception if the file cannot be opened or parsed .
32183293 */
32193294inline std::shared_ptr<table> parse_file (const std::string& filename)
32203295{
@@ -3231,6 +3306,66 @@ inline std::shared_ptr<table> parse_file(const std::string& filename)
32313306 return p.parse ();
32323307}
32333308
3309+ /* *
3310+ * Utility function to validate a TOML file. Returns true if the file is valid,
3311+ * false otherwise. If validate_only is true, the function will only validate
3312+ * the file without parsing it completely.
3313+ */
3314+ inline bool validate_file (const std::string& filename, bool validate_only = false )
3315+ {
3316+ try
3317+ {
3318+ #if defined(BOOST_NOWIDE_FSTREAM_INCLUDED_HPP)
3319+ boost::nowide::ifstream file{filename.c_str ()};
3320+ #elif defined(NOWIDE_FSTREAM_INCLUDED_HPP)
3321+ nowide::ifstream file{filename.c_str ()};
3322+ #else
3323+ std::ifstream file{filename};
3324+ #endif
3325+ if (!file.is_open ())
3326+ throw parse_exception{filename + " could not be opened for validation" };
3327+
3328+ parser p{file};
3329+ if (validate_only)
3330+ {
3331+ // Only validate the syntax, not the full parsing
3332+ std::string line;
3333+ while (std::getline (file, line))
3334+ {
3335+ // This is a simple validation, real validation would be more complex
3336+ // For now, just check for basic syntax errors
3337+ size_t comment_pos = line.find (' #' );
3338+ if (comment_pos != std::string::npos)
3339+ line = line.substr (0 , comment_pos);
3340+
3341+ if (!line.empty ())
3342+ {
3343+ // Check for valid key-value pairs or table headers
3344+ if (line.find (' =' ) == std::string::npos &&
3345+ line.find (' [' ) == std::string::npos)
3346+ {
3347+ return false ;
3348+ }
3349+ }
3350+ }
3351+ }
3352+ else
3353+ {
3354+ // Parse the entire file to validate it
3355+ p.parse ();
3356+ }
3357+ return true ;
3358+ }
3359+ catch (const parse_exception&)
3360+ {
3361+ return false ;
3362+ }
3363+ catch (const std::exception&)
3364+ {
3365+ return false ;
3366+ }
3367+ }
3368+
32343369template <class ... Ts>
32353370struct value_accept ;
32363371
0 commit comments