@@ -320,15 +320,15 @@ class Config final : public IEarlyConfig
320320
321321 std::map<String, ConfigStorage> defaults;
322322
323- String expandEnvironmentVariables (const String& value ) const
323+ String expandEnvironmentVariablesInRawJSON (const String& jsonText ) const
324324 {
325325 String result;
326- result.reserve (value .length ());
326+ result.reserve (jsonText .length ());
327327
328328 size_t i = 0 ;
329- while (i < value .length ())
329+ while (i < jsonText .length ())
330330 {
331- const char ch = value [i];
331+ const char ch = jsonText [i];
332332
333333 if (ch != ' $' )
334334 {
@@ -337,46 +337,43 @@ class Config final : public IEarlyConfig
337337 continue ;
338338 }
339339
340- if (i + 1 < value .length () && value [i + 1 ] == ' $' )
340+ if (i + 1 < jsonText .length () && jsonText [i + 1 ] == ' $' )
341341 {
342342 result.push_back (' $' );
343343 i += 2 ;
344344 continue ;
345345 }
346346
347- if (i + 1 >= value .length () || value [i + 1 ] != ' {' )
347+ if (i + 1 >= jsonText .length () || jsonText [i + 1 ] != ' {' )
348348 {
349349 result.push_back (ch);
350350 ++i;
351351 continue ;
352352 }
353353
354354 const size_t varStart = i + 2 ;
355- const size_t end = value .find (' }' , varStart);
355+ const size_t end = jsonText .find (' }' , varStart);
356356
357357 if (end == String::npos)
358358 {
359- result.append (value .substr (i));
359+ result.append (jsonText .substr (i));
360360 break ;
361361 }
362362
363- const String fullVar = value .substr (varStart, end - varStart);
363+ const String fullVar = jsonText .substr (varStart, end - varStart);
364364 const size_t defaultPos = fullVar.find (" :-" );
365365
366366 const String varName = (defaultPos != String::npos) ? fullVar.substr (0 , defaultPos) : fullVar;
367+ const String defaultValue = (defaultPos != String::npos) ? fullVar.substr (defaultPos + 2 ) : " " ;
367368 const char * envValue = std::getenv (varName.c_str ());
368369
369- if (envValue)
370+ if (envValue && envValue[ 0 ] != ' \0 ' )
370371 {
371372 result.append (envValue);
372373 }
373- else if (defaultPos != String::npos )
374+ else if (!defaultValue. empty () )
374375 {
375- result.append (fullVar.substr (defaultPos + 2 ));
376- }
377- else
378- {
379- result.append (value.substr (i, end - i + 1 ));
376+ result.append (defaultValue);
380377 }
381378
382379 i = end + 1 ;
@@ -405,8 +402,7 @@ class Config final : public IEarlyConfig
405402 }
406403 else if (v.is_string ())
407404 {
408- String strValue = v.get <String>();
409- processed[key].emplace <String>(expandEnvironmentVariables (strValue));
405+ processed[key].emplace <String>(v.get <String>());
410406 }
411407 else if (v.is_array ())
412408 {
@@ -416,8 +412,7 @@ class Config final : public IEarlyConfig
416412 {
417413 if (arrVal.is_string ())
418414 {
419- String strValue = arrVal.get <String>();
420- vec.emplace_back (expandEnvironmentVariables (strValue));
415+ vec.emplace_back (arrVal.get <String>());
421416 }
422417 }
423418 }
@@ -445,7 +440,10 @@ class Config final : public IEarlyConfig
445440 nlohmann::json props;
446441 try
447442 {
448- props = nlohmann::json::parse (ifs, nullptr , true /* allow_exceptions */ , true /* ignore_comments */ );
443+ String fileContent ((std::istreambuf_iterator<char >(ifs)),
444+ std::istreambuf_iterator<char >());
445+ String expandedContent = expandEnvironmentVariablesInRawJSON (fileContent);
446+ props = nlohmann::json::parse (expandedContent, nullptr , true /* allow_exceptions */ , true /* ignore_comments */ );
449447 }
450448 catch (nlohmann::json::exception const & e)
451449 {
@@ -475,14 +473,76 @@ class Config final : public IEarlyConfig
475473
476474 // Fill any values missing in config with defaults.
477475 // Fill default value if invalid type is provided.
476+ // if the user provided a string but expected type is different
477+ // attempt to parse string to the expected type.
478478 for (const auto & kv : Defaults)
479479 {
480480 auto itr = processed.find (kv.first );
481481 if (itr != processed.end ())
482482 {
483483 if (itr->second .index () != kv.second .index ())
484484 {
485- itr->second = kv.second ;
485+ // check if we can convert from string
486+ bool converted = false ;
487+ if (itr->second .index () == 1 ) // User value is String
488+ {
489+ const String& strVal = std::get<String>(itr->second );
490+ switch (kv.second .index ())
491+ {
492+ case 0 : // Expected int
493+ {
494+ try
495+ {
496+ size_t pos = 0 ;
497+ int intVal = std::stoi (strVal, &pos);
498+ if (pos == strVal.length ())
499+ {
500+ itr->second = intVal;
501+ converted = true ;
502+ }
503+ }
504+ catch (...)
505+ {
506+ }
507+ break ;
508+ }
509+ case 2 : // Expected float
510+ {
511+ try
512+ {
513+ size_t pos = 0 ;
514+ float floatVal = std::stof (strVal, &pos);
515+ if (pos == strVal.length ())
516+ {
517+ itr->second = floatVal;
518+ converted = true ;
519+ }
520+ }
521+ catch (...)
522+ {
523+ }
524+ break ;
525+ }
526+ case 4 : // Expected bool
527+ {
528+ if (strVal == " true" || strVal == " 1" )
529+ {
530+ itr->second = true ;
531+ converted = true ;
532+ }
533+ else if (strVal == " false" || strVal == " 0" )
534+ {
535+ itr->second = false ;
536+ converted = true ;
537+ }
538+ break ;
539+ }
540+ }
541+ }
542+ if (!converted)
543+ {
544+ itr->second = kv.second ;
545+ }
486546 }
487547 continue ;
488548 }
0 commit comments