From 616cf7260a53e302f01bdbfa3a825d01c1138c65 Mon Sep 17 00:00:00 2001 From: Preston Date: Sun, 19 Oct 2025 14:36:48 -0700 Subject: [PATCH 1/4] Fixed coding style issues with watch dog, and began implementing CLI features --- lib/commandLineParser.cpp | 28 +++++++ lib/commandLineParser.h | 69 ++++++++++++++++++ lib/watchDog.cpp | 118 +++++++++++++----------------- lib/watchDog.h | 150 +++++++++++++++++++------------------- src/main.cpp | 10 +-- test/input.md | 2 +- 6 files changed, 228 insertions(+), 149 deletions(-) create mode 100644 lib/commandLineParser.cpp create mode 100644 lib/commandLineParser.h diff --git a/lib/commandLineParser.cpp b/lib/commandLineParser.cpp new file mode 100644 index 0000000..2e70cca --- /dev/null +++ b/lib/commandLineParser.cpp @@ -0,0 +1,28 @@ +#include "commandLineParser.h" +#include + +CLI::CLI(int argc, char** argv){ + if (argc > 0){ + programName = argv[0]; + } + + for (int i = 1; i < argc; i++){ + args.push_back(argv[i]); + } +} + +void CLI::RunCommands(){ + for (int i = 0; i < args.size(); i++){ + + } +} + +void CLI::PrintHelp() const{ + std::cout << "Usage:\n" + << " " << programName << " \n" + << "Flags:\n" + << " --o, --output , optional output filename\n" + << " --w, --watch, enables watchdog\n" + << " --s, --stop, stops watchdog\n"; +} + diff --git a/lib/commandLineParser.h b/lib/commandLineParser.h new file mode 100644 index 0000000..5d595bc --- /dev/null +++ b/lib/commandLineParser.h @@ -0,0 +1,69 @@ +/** + * @file commandLineParser.h + * @brief Parses command line + * @author Preston Shultz + * Sources: + * + */ + +#ifndef COMMAND_LINE_PARSER_H +#define COMMAND_LINE_PARSER_H + +#include +#include + +/** + * @brief CommandLine Helper class + * + * Parse input arguments, sets input and output files + * Lets user use commands with program + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ +class CLI{ +public: + /** + * @brief Takes in argc and argv and converts it to vector + * + * CLI constructor + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + CLI(int argc, char **argv); + + /** + * @brief Runs Commands + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void RunCommands(); + + /** + * @brief Prints a list of commands that can be used + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void PrintHelp() const; + + /** + * @brief Returns input file + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::string GetInputFile() const {return inputFile;} + + /** + * @brief Returns output file + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::string GetOutputFile() const {return outputFile;} + +private: + std::string programName; + std::vector args; + std::string inputFile; + std::string outputFile; +}; + +#endif \ No newline at end of file diff --git a/lib/watchDog.cpp b/lib/watchDog.cpp index e9bec9e..0b0284c 100644 --- a/lib/watchDog.cpp +++ b/lib/watchDog.cpp @@ -1,64 +1,59 @@ -/* - *I don't know how threads work, so I might come back to see how they work. - *Right now you have to manually call the checkfile function to see if any changes have occured - */ - -#include "watchDog.h" +#include "watchdog.h" namespace fs = std::filesystem; //makes it easier to read -void WatchDog::start() + +void Watchdog::Start() { - //checks if file exist + //Checks if file exist if(!fs::exists(path)) { - //returns and sets parameters to false if file doesnt exist + //Returns and sets parameters to false if file doesnt exist watching = false; - hasInitialTime = false; + has_initial_time = false; std::cout << "WatchDog: File does not exists: " << path << std::endl; return; } - //grabs intial write time - lastWriteTime = fs::last_write_time(path); + //Grabs intial write time + last_write_time = fs::last_write_time(path); + //Sets watchdog watching = true; - hasInitialTime = true; + has_initial_time = true; std::cout << "WatchDog: Started" << std::endl; } -void WatchDog::stop(){ - watching = false; -} -bool WatchDog::checkFile(){ + +bool Watchdog::CheckFile(){ //If not watching returns false if (!watching) return false; //Checking if file was deleted if(!fs::exists(path)) { - if (hasInitialTime) { + if (has_initial_time) { std::cout << "WatchDog: File was delete: " << path << std::endl; - hasInitialTime = false; + has_initial_time = false; return true; } return false; } - //Built in function with file system to check last write tim + //Built in function with file system to check last write time fs::file_time_type currentWriteTime = fs::last_write_time(path); //File was just created - if(!hasInitialTime) + if(!has_initial_time) { - lastWriteTime = currentWriteTime; - hasInitialTime = true; + last_write_time = currentWriteTime; + has_initial_time = true; std::cout << "WatchDog: File created: " << path << std::endl; return true; } //File modified - if (currentWriteTime != lastWriteTime) + if (currentWriteTime != last_write_time) { - lastWriteTime = currentWriteTime; + last_write_time = currentWriteTime; std::cout << "WatchDog: File modifed at " - << timePointToString(lastWriteTime) << std::endl; + << TimePointToString(last_write_time) << std::endl; return true; } @@ -66,62 +61,47 @@ bool WatchDog::checkFile(){ return false; } -std::string WatchDog::timePointToString(const fs::file_time_type& timePoint){ - /* - * https://en.cppreference.com/w/cpp/chrono.html - * std::chrono -> name space, system_clock -> c++ clock(computers clock), - * ime_point -> exact instant on system clock, used to cast - * Comments: I had to use a lot of sources and googling to get this work - * We can get rid of this or document my troubles, because tbh this time stuff confuses me +std::string Watchdog::TimePointToString(const fs::file_time_type& timePoint){ + /** + * Step 1: timePoint + * - This is the last write time of the file, returned by std::filesystem. + * - Its clock is platform-dependent (filesystem clock). * - * std::chrono::system_clock::time_point systemTimePoint = - * std::chrono::clock_cast(timePoint); - * This solutions doesn't work as it only works with C++ 20 only :( + * Step 2: fs::file_time_type::clock::now() + * - Current time according to the filesystem clock. + * + * Step 3: std::chrono::system_clock::now() + * - Current time according to the system clock (standard C++ clock). + * + * Conversion formula: + * timePoint - fs::file_time_type::clock::now() + std::chrono::system_clock::now() + * + * Explanation: + * a) timePoint - fs::file_time_type::clock::now() + * - Calculates the duration between the file's last write time and "now" + * according to the filesystem clock. + * b) + std::chrono::system_clock::now() + * - Shifts that duration to align with the system clock timeline. + * c) std::chrono::time_point_cast(...) + * - Ensures the resulting time_point uses the correct duration type + * for std::chrono::system_clock. + * + * Result: + * - systemTime is a std::chrono::system_clock::time_point representing + * the same instant as timePoint, but compatible with system_clock. */ - - //Convert std::filesystem::file_time_type (timePoint) to std::chrono::system_clock::time_point - - /* - * Step 1: timePoint - * - This is the last write time of the file, returned by std::filesystem. - * - Its clock is platform-dependent (filesystem clock). - * - * Step 2: fs::file_time_type::clock::now() - * - Current time according to the filesystem clock. - * - * Step 3: std::chrono::system_clock::now() - * - Current time according to the system clock (standard C++ clock). - * - * Conversion formula: - * timePoint - fs::file_time_type::clock::now() + std::chrono::system_clock::now() - * - * Explanation: - * a) timePoint - fs::file_time_type::clock::now() - * - Calculates the duration between the file's last write time and "now" - * according to the filesystem clock. - * b) + std::chrono::system_clock::now() - * - Shifts that duration to align with the system clock timeline. - * c) std::chrono::time_point_cast(...) - * - Ensures the resulting time_point uses the correct duration type - * for std::chrono::system_clock. - * - * Result: - * - systemTime is a std::chrono::system_clock::time_point representing - * the same instant as timePoint, but compatible with system_clock. - */ std::chrono::system_clock::time_point systemTimePoint = std::chrono::time_point_cast( timePoint - fs::file_time_type::clock::now() + std::chrono::system_clock::now() ); - //converts to seconds + //Converts to seconds std::time_t timeInSeconds = std::chrono::system_clock::to_time_t(systemTimePoint); //Converts to local time, built in function std::tm localTime = *std::localtime(&timeInSeconds); // Format the time into a string using strftime - //https://en.cppreference.com/w/cpp/chrono/c/strftime.html char buffer[20]; std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &localTime); diff --git a/lib/watchDog.h b/lib/watchDog.h index 148d087..3164ac1 100644 --- a/lib/watchDog.h +++ b/lib/watchDog.h @@ -1,19 +1,25 @@ +/** + * @file watchdog.h + * @brief file watcher + * @author Preston Shultz + * Sources: + * https://en.cppreference.com/w/cpp/filesystem.html + * https://en.cppreference.com/w/cpp/chrono.html + * Format the time into a string using strftime + * https://en.cppreference.com/w/cpp/chrono/c/strftime.html + */ + #ifndef WATCHDOG_H #define WATCHDOG_H #include -#include -/* - *https://en.cppreference.com/w/cpp/filesystem.html - *allow access to files platform independent - */ -#include -/* - *https://en.cppreference.com/w/cpp/chrono.html - *makes timestamps easier - *how to do lots of research to get this to work - */ -#include +#include +#include //allow access to files platform independent +#include //makes timestamps easier +#include //Convert time_t to std::tm for local time +#include //Formats std::tim into "YYYY-MM-DD HH-MM-SS" + + /** * @brief watchdog class. * @@ -21,74 +27,70 @@ * * @author Preston Shultz (shultzp1@my.erau.edu) */ -#include //Convert time_t to std::tm for local time -#include //Formats std::tim into "YYYY-MM-DD HH-MM-SS" +class Watchdog{ +public: + Watchdog(const std::string& path) : + path(path), watching(false), has_initial_time(false) {} + /** + * @brief watchdog class. + * + * Starts the watchdog to check of a file is modified + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void Start(); + /** + * @brief watchdog class. + * + * Stops the watchdog + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void Stop() {watching = false;} //Disable -class WatchDog{ - public: - WatchDog(const std::string& path) : - path(path), watching(false), hasInitialTime(false) {} + /** + * @brief watchdog class. + * + * Checks if a file has been modified + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + bool CheckFile(); - /** - * @brief watchdog class. - * - * Starts the watchdog to check of a file is modified - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - void start(); - /** - * @brief watchdog class. - * - * Stops the watchdog - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - void stop(); //Disable + /** + * @brief watchdog class. + * + * Returns files last modified date + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::filesystem::file_time_type GetLastWriteTime() + const {return last_write_time;} - /** - * @brief watchdog class. - * - * Checks if a file has been modified - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - bool checkFile(); + /** + * @brief watchdog class. + * + * Converts time point into a string + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + static std::string TimePointToString(const std::filesystem::file_time_type& timePoint); - /** - * @brief watchdog class. - * - * Returns files last modified date - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - std::filesystem::file_time_type getLastWriteTime() - const {return lastWriteTime;} + /** + * @brief watchdog class. + * + * Returns if the watchDog is on + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + bool IsWatching() const{return watching;} - /** - * @brief watchdog class. - * - * Converts time point into a string - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - static std::string timePointToString(const std::filesystem::file_time_type& timePoint); - - /** - * @brief watchdog class. - * - * Returns if the watchDog is on - * - * @author Preston Shultz (shultzp1@my.erau.edu) - */ - bool isWatching() const{return watching;} - - private: - std::string path; //file path - bool watching; //Is watchdog on? - std::filesystem::file_time_type lastWriteTime; - bool hasInitialTime; //checks if initial time is given +private: + std::string path; //file path + bool watching; //Is watchdog on? + std::filesystem::file_time_type last_write_time; + bool has_initial_time; //checks if initial time is given }; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9a67d41..ceeef67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -39,18 +39,18 @@ void test_nodes() { *Preston: Test to see if watchdog works :) */ void test_watchdog() { - WatchDog wd("test/input.md"); - wd.start(); + Watchdog wd("test/input.md"); + wd.Start(); std::cout << "Initial check (should do nothing if file unchanged):\n"; - wd.checkFile(); + wd.CheckFile(); std::cout << "Now, modify or create the file 'example.txt' manually and " "press Enter:\n"; std::cin.get(); // Wait for user to press Enter // Check again after manual change - wd.checkFile(); + wd.CheckFile(); std::cout << "Done testing.\n"; } @@ -78,4 +78,4 @@ void test_input(int argc, char **argv) { std::cout << std::endl; } -int main(int argc, char **argv) { test_nodes(); } +int main(int argc, char **argv) { test_watchdog(); } diff --git a/test/input.md b/test/input.md index b37a30c..54ed126 100644 --- a/test/input.md +++ b/test/input.md @@ -1,6 +1,6 @@ -# Hello world in a h1 tag +# Hello world in an h1 tag ## This is a h2 tag -- 2.47.2 From d7b7dee6d119d6cc8808ff4c7574915b64aacf75 Mon Sep 17 00:00:00 2001 From: Preston Date: Tue, 28 Oct 2025 17:16:25 -0700 Subject: [PATCH 2/4] missing way to run commands and ensuring valid arguments in command so giberish doesnt run --- lib/commandLineParser.cpp | 67 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 lib/commandLineParser.cpp diff --git a/lib/commandLineParser.cpp b/lib/commandLineParser.cpp new file mode 100644 index 0000000..779e90c --- /dev/null +++ b/lib/commandLineParser.cpp @@ -0,0 +1,67 @@ +#include "commandLineParser.h" +#include +#include // for std::invalid_argument + +//implement hashmap for the code +CLI::CLI(int argc, char** argv){ + try{ + if (arc < 2) { + throw std::invalid_argument("Error: No input file provided.\n + Usage: "); + } + //sets program info + programName = argv[0]; + inputFile = argv[1] + + //checks that file has correct file extension + if(!(CLI::IsMarkupFile(inputFile))) { + throw std::invalid_argument("Error: Invalid file extension. Expected a '.md' (Markdown) file."); + } + //stores remaining arguments + for (int i = 1; i < argc; i++){ + args.push_back(argv[i]); + } + } + catch (const std::invalid_argument& e) { + std::cerr << e.what() << "\n"; + PrintHelp(); + std::exit(EXIT_FAILURE); + } + } + +bool CLI::IsMarkupFile(const std::string& filename) { + //markdown file extension + const std::string requiredExtension = ".md"; + //checks to see if it can even include extension + if (filename.size() <= requiredExtension.size()) { + return false; + } + // Extracts the last N characters of the filename (where N is the length of the required extension) + // and checks if they match the required file extension (e.g., ".md"). + // + // Example: + // filename = "notes.md" + // requiredExtension = ".md" + // filename.substr(filename.size() - requiredExtension.size()) == ".md" → true + // + // Reference: https://en.cppreference.com/w/cpp/string/basic_string/substr + return filename.substr(filename.size() - requiredExtension.size()) == requiredExtension; +} + + +//place to run commands but IDK IF WE SHOULD USE A HASMAP or how we are going to get each method to run +void CLI::RunCommands(){ + for (int i = 0; i < args.size(); i++){ + + } +} + +void CLI::PrintHelp() const{ + std::cout << "Usage:\n" + << " " << programName << " REQUIRED\n" + << "Flags:\n" + << " --o, --output , optional output filename\n" + << " --w, --watch, enables watchdog\n" + << " --s, --stop, stops watchdog\n"; +} + -- 2.47.2 From 8f5a466a590f1778e616ac486132e2a2de5da5a3 Mon Sep 17 00:00:00 2001 From: Preston Date: Tue, 28 Oct 2025 17:18:58 -0700 Subject: [PATCH 3/4] added comments to clarify things --- lib/watchDog.cpp | 88 ++++++++++++++++++++++++++---------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/lib/watchDog.cpp b/lib/watchDog.cpp index e9bec9e..0fc08ff 100644 --- a/lib/watchDog.cpp +++ b/lib/watchDog.cpp @@ -6,63 +6,71 @@ #include "watchDog.h" namespace fs = std::filesystem; //makes it easier to read -void WatchDog::start() -{ - //checks if file exist - if(!fs::exists(path)) - { - //returns and sets parameters to false if file doesnt exist +void WatchDog::start() { + try { + // Try to get the last write time directly + lastWriteTime = fs::last_write_time(path); + + // If successful, start watching + watching = true; + hasInitialTime = true; + std::cout << "WatchDog: Started monitoring " << path << std::endl; + } + catch (const fs::filesystem_error& e) { + // If the file doesn't exist or another filesystem error occurs watching = false; hasInitialTime = false; - std::cout << "WatchDog: File does not exists: " << path << std::endl; - return; + std::cerr << "WatchDog: Cannot start. File error: " << e.what() << std::endl; + } + catch (const std::exception& e) { + // Catch any other unexpected errors + watching = false; + hasInitialTime = false; + std::cerr << "WatchDog: Unexpected error: " << e.what() << std::endl; } - //grabs intial write time - lastWriteTime = fs::last_write_time(path); - watching = true; - hasInitialTime = true; - std::cout << "WatchDog: Started" << std::endl; } void WatchDog::stop(){ watching = false; } -bool WatchDog::checkFile(){ - //If not watching returns false +//this is currently just telling you when the file is edited, the exact time its edited +bool WatchDog::checkFile() { if (!watching) return false; - //Checking if file was deleted - if(!fs::exists(path)) - { + try { + // Try to get last write time + fs::file_time_type currentWriteTime = fs::last_write_time(path); + + // File was just created + if (!hasInitialTime) { + lastWriteTime = currentWriteTime; + hasInitialTime = true; + std::cout << "WatchDog: File created: " << path << std::endl; + return true; + } + + // File modified + if (currentWriteTime != lastWriteTime) { + lastWriteTime = currentWriteTime; + std::cout << "WatchDog: File modified at " + << timePointToString(lastWriteTime) << std::endl; + return true; + } + + } catch (const fs::filesystem_error& e) { + // File deleted, inaccessible, or path invalid if (hasInitialTime) { - std::cout << "WatchDog: File was delete: " << path << std::endl; + std::cout << "WatchDog: File deleted or inaccessible: " << path << std::endl; hasInitialTime = false; return true; } return false; - } - - //Built in function with file system to check last write tim - fs::file_time_type currentWriteTime = fs::last_write_time(path); - //File was just created - if(!hasInitialTime) - { - lastWriteTime = currentWriteTime; - hasInitialTime = true; - std::cout << "WatchDog: File created: " << path << std::endl; - return true; + } catch (const std::exception& e) { + std::cerr << "WatchDog: Unexpected error checking file: " << e.what() << std::endl; + return false; } - //File modified - if (currentWriteTime != lastWriteTime) - { - lastWriteTime = currentWriteTime; - std::cout << "WatchDog: File modifed at " - << timePointToString(lastWriteTime) << std::endl; - return true; - } - - //No change + // No change return false; } -- 2.47.2 From b38bb60e6217576c2a70a8362db0e1e05c36b3a4 Mon Sep 17 00:00:00 2001 From: Preston Date: Tue, 28 Oct 2025 17:19:27 -0700 Subject: [PATCH 4/4] added try and catch --- lib/commandLineParser.h | 80 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 lib/commandLineParser.h diff --git a/lib/commandLineParser.h b/lib/commandLineParser.h new file mode 100644 index 0000000..88c9a09 --- /dev/null +++ b/lib/commandLineParser.h @@ -0,0 +1,80 @@ +/** + * @file commandLineParser.h + * @brief Parses command line + * @author Preston Shultz + * Sources: + * + */ + +#ifndef COMMAND_LINE_PARSER_H +#define COMMAND_LINE_PARSER_H + +#include +#include + +/** + * @brief CommandLine Helper class + * + * Parse input arguments, sets input and output files + * Lets user use commands with program + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ +class CLI{ +public: + /** + * @brief Takes in argc and argv and converts it to vector + * + * CLI constructor + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + CLI(int argc, char **argv); + + /** + * @brief Runs Commands + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void RunCommands(); + + /** + * @brief Prints a list of commands that can be used + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + void PrintHelp() const; + + /** + * @brief Returns input file + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::string GetInputFile() const {return inputFile;} + + /** + * @brief Returns output file + * + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + std::string GetOutputFile() const {return outputFile;} + +private: + + /** + * @brief Ensures the provided filename has a .markup extension + * + * @param filename The file name to validate + * @return true if file ends with .markup + * @return false otherwise + * @author Preston Shultz (shultzp1@my.erau.edu) + */ + static bool IsMarkupFile(const std::string& filename); + + std::string programName; + std::vector args; + std::string inputFile; + std::string outputFile; +}; + +#endif \ No newline at end of file -- 2.47.2