424{
425 std::string configPath = GetConfigFilePath();
426 std::ifstream configFile(configPath);
427
428 if (!configFile.is_open()) {
429
430 return false;
431 }
432
433
434
435 bool portable = IsPortableMode();
436
437 std::string line;
438 std::string currentSection = "";
439
440 while (std::getline(configFile, line)) {
441
442 if (line.empty() || line[0] == '#') {
443 continue;
444 }
445
446
447 if (line[0] == '[' && line[line.length()-1] == ']') {
448 currentSection = line.substr(1, line.length()-2);
449 continue;
450 }
451
452
453 size_t equalPos = line.find('=');
454 if (equalPos == std::string::npos) {
455 continue;
456 }
457
458 std::string key = line.substr(0, equalPos);
459 std::string value = line.substr(equalPos + 1);
460
461
462 key.erase(0, key.find_first_not_of(" \t"));
463 key.erase(key.find_last_not_of(" \t") + 1);
464 value.erase(0, value.find_first_not_of(" \t"));
465 value.erase(value.find_last_not_of(" \t") + 1);
466
467
468 if (currentSection == "") {
469
470 if (portable) {
471 if (key == "experiment_directory" || key == "workspace_path" ||
472 key == "battery_path" || key == "pebl_executable_path" ||
473 key == "data_output_path") {
474 continue;
475 }
476
477 }
478
479 if (key == "experiment_directory") {
480 mExperimentDirectory = value;
481 } else if (key == "subject_code") {
482 mSubjectCode = value;
483 } else if (key == "language") {
484 mLanguage = value;
485 } else if (key == "fullscreen") {
486 mFullscreen = (value == "true" || value == "1");
487 } else if (key == "auto_upload") {
488 mAutoUpload = (value == "true" || value == "1");
489 } else if (key == "upload_token") {
490 mUploadToken = value;
491 } else if (key == "upload_url") {
492 mUploadURL = value;
493 } else if (key == "workspace_path") {
494 mWorkspacePath = value;
495 } else if (key == "battery_path") {
496 mBatteryPath = value;
497 } else if (key == "pebl_executable_path") {
498 mPeblExecutablePath = value;
499 } else if (key == "data_output_path") {
500 mDataOutputPath = value;
501 } else if (key == "font_size") {
502 try {
503 mFontSize = std::stoi(value);
504 } catch (...) {
505 printf("Warning: Invalid font_size value, using default\n");
506 }
507 } else if (key == "window_width") {
508 try {
509 mWindowWidth = std::stoi(value);
510 } catch (...) {
511 printf("Warning: Invalid window_width value, using default\n");
512 }
513 } else if (key == "window_height") {
514 try {
515 mWindowHeight = std::stoi(value);
516 } catch (...) {
517 printf("Warning: Invalid window_height value, using default\n");
518 }
519 } else if (key == "current_study_path") {
520 if (portable && !value.empty()) {
521
522
523 if (value[0] != '/' && !(value.length() > 1 && value[1] == ':')) {
524
525 try {
526 fs::path relativePath(value);
527 fs::path absolutePath = fs::absolute(fs::path(mWorkspacePath) / relativePath);
528 mCurrentStudyPath = absolutePath.string();
529 } catch (...) {
530 mCurrentStudyPath = value;
531 }
532 } else {
533
534 mCurrentStudyPath = "";
535 }
536 } else {
537 mCurrentStudyPath = value;
538 }
539 } else if (key == "current_chain_name") {
540 mCurrentChainName = value;
541 } else if (key == "external_editor") {
542 mExternalEditor = value;
543 }
544 } else if (currentSection == "recent") {
545
546 size_t pipe1 = value.find('|');
547 if (pipe1 != std::string::npos) {
548 size_t pipe2 = value.find('|', pipe1 + 1);
549 if (pipe2 != std::string::npos) {
550 try {
551 std::string timestampStr = value.substr(pipe2 + 1);
552
553 if (timestampStr.empty()) {
554 continue;
555 }
556
558 recent.
name = value.substr(0, pipe1);
559 recent.
path = value.substr(pipe1 + 1, pipe2 - pipe1 - 1);
560 recent.
lastRun = std::stol(timestampStr);
561 mRecentExperiments.push_back(recent);
562 } catch (const std::invalid_argument& e) {
563
564 printf("Warning: Skipping malformed recent experiment entry: %s\n", value.c_str());
565 } catch (const std::out_of_range& e) {
566
567 printf("Warning: Skipping out-of-range timestamp in recent experiment entry: %s\n", value.c_str());
568 }
569 }
570 }
571 }
572 }
573
574 configFile.close();
575
576
577
578
579
580 struct stat st;
581 if (!mBatteryPath.empty() &&
582 !(stat(mBatteryPath.c_str(), &st) == 0 && S_ISDIR(st.st_mode)))
583 {
584 printf("Warning: Saved battery_path no longer exists: %s\n", mBatteryPath.c_str());
585 printf("Re-detecting PEBL installation...\n");
586 mBatteryPath = DetectPEBLInstallation();
587 if (!mBatteryPath.empty()) {
588 printf("Re-detected battery at: %s\n", mBatteryPath.c_str());
589 } else {
590 printf("Warning: Could not auto-detect battery path.\n");
591 }
592 }
593
594 if (!mPeblExecutablePath.empty() &&
595 !(stat(mPeblExecutablePath.c_str(), &st) == 0 && S_ISREG(st.st_mode)))
596 {
597 printf("Warning: Saved pebl_executable_path no longer exists: %s\n", mPeblExecutablePath.c_str());
598
599 if (!mBatteryPath.empty()) {
600#ifdef _WIN32
601 std::string candidate = mBatteryPath + "\\..\\bin\\pebl2.exe";
602#else
603 std::string candidate = mBatteryPath + "/../bin/pebl2";
604#endif
605 if (stat(candidate.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
606 mPeblExecutablePath = candidate;
607 printf("Re-detected PEBL executable at: %s\n", mPeblExecutablePath.c_str());
608 } else {
609 printf("Warning: Could not auto-detect PEBL executable path.\n");
610 mPeblExecutablePath = "";
611 }
612 }
613 }
614
615 return true;
616}