Skip to content

Commit 6fdae0a

Browse files
committed
fix: enhance file handling.
- Improved validation and directory creation
1 parent 06d19cb commit 6fdae0a

File tree

2 files changed

+135
-111
lines changed

2 files changed

+135
-111
lines changed

scanner/include/file_handler.hpp

Lines changed: 53 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#ifndef FILE_HANDLER_HPP
1010
#define FILE_HANDLER_HPP
1111

12+
#include <filesystem>
1213
#include <fstream>
1314
#include <iostream>
1415
#include <sstream>
@@ -25,63 +26,60 @@
2526
* The `TINY` namespace organizes all classes, functions, and utilities
2627
* related to the lexical analysis of the TINY programming language.
2728
*/
28-
namespace TINY
29-
{
29+
namespace TINY {
30+
/**
31+
* @namespace SCANNER
32+
* @brief Contains all components related to the lexical analysis (scanning) of TINY language.
33+
*/
34+
namespace SCANNER {
35+
36+
/**
37+
* @class FileHandler
38+
* @brief Provides utility functions for file input and output.
39+
*
40+
* The `FileHandler` class offers static methods to perform file operations,
41+
* including reading files, writing tokens to files, and writing content to files.
42+
*/
43+
class FileHandler {
44+
public:
3045
/**
31-
* @namespace SCANNER
32-
* @brief Contains all components related to the lexical analysis (scanning) of TINY language.
46+
* @brief Reads the entire content of a file into a string.
47+
*
48+
* This method opens the file at the specified path and reads its contents into a single string.
49+
* If the file cannot be opened, it throws a runtime exception.
50+
*
51+
* @param filePath Path to the file to be read.
52+
* @return A string containing the file's content.
53+
* @throws std::runtime_error if the file cannot be opened.
3354
*/
34-
namespace SCANNER
35-
{
55+
static std::string readFile(const std::string &filePath);
3656

37-
/**
38-
* @class FileHandler
39-
* @brief Provides utility functions for file input and output.
40-
*
41-
* The `FileHandler` class offers static methods to perform file operations,
42-
* including reading files, writing tokens to files, and writing content to files.
43-
*/
44-
class FileHandler
45-
{
46-
public:
47-
/**
48-
* @brief Reads the entire content of a file into a string.
49-
*
50-
* This method opens the file at the specified path and reads its contents into a single string.
51-
* If the file cannot be opened, it throws a runtime exception.
52-
*
53-
* @param filePath Path to the file to be read.
54-
* @return A string containing the file's content.
55-
* @throws std::runtime_error if the file cannot be opened.
56-
*/
57-
static std::string readFile(const std::string &filePath);
58-
59-
/**
60-
* @brief Writes a vector of tokens to a file, each token on a new line.
61-
*
62-
* This method takes a vector of `Token` objects and writes their string representation to the file.
63-
* If the `includePosition` flag is true, the position of each token is also included in the output.
64-
*
65-
* @param filePath Path to the file to be written.
66-
* @param tokens A vector of `Token` objects to write to the file.
67-
* @param includePosition Whether to include token position in the output (default is false).
68-
* @throws std::runtime_error if the file cannot be opened.
69-
*/
70-
static void writeTokens(const std::string &filePath, const std::vector<Token> &tokens, bool includePosition = false);
57+
/**
58+
* @brief Writes a vector of tokens to a file, each token on a new line.
59+
*
60+
* This method takes a vector of `Token` objects and writes their string representation to the file.
61+
* If the `includePosition` flag is true, the position of each token is also included in the output.
62+
*
63+
* @param filePath Path to the file to be written.
64+
* @param tokens A vector of `Token` objects to write to the file.
65+
* @param includePosition Whether to include token position in the output (default is false).
66+
* @throws std::runtime_error if the file cannot be opened.
67+
*/
68+
static void writeTokens(const std::string &filePath, const std::vector<Token> &tokens, bool includePosition = false);
7169

72-
/**
73-
* @brief Writes a string to a file.
74-
*
75-
* This method writes the provided string to the file at the specified path.
76-
* If the file cannot be opened, it throws a runtime exception.
77-
*
78-
* @param filePath Path to the file to be written.
79-
* @param content A string to write to the file.
80-
* @throws std::runtime_error if the file cannot be opened.
81-
*/
82-
static void writeFile(const std::string &filePath, const std::string &content);
83-
};
84-
} // namespace SCANNER
85-
} // namespace TINY
70+
/**
71+
* @brief Writes a string to a file.
72+
*
73+
* This method writes the provided string to the file at the specified path.
74+
* If the file cannot be opened, it throws a runtime exception.
75+
*
76+
* @param filePath Path to the file to be written.
77+
* @param content A string to write to the file.
78+
* @throws std::runtime_error if the file cannot be opened.
79+
*/
80+
static void writeFile(const std::string &filePath, const std::string &content);
81+
};
82+
} // namespace SCANNER
83+
} // namespace TINY
8684

87-
#endif // FILE_HANDLER_HPP
85+
#endif // FILE_HANDLER_HPP

scanner/src/file_handler.cpp

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -12,59 +12,85 @@
1212

1313
#include "file_handler.hpp"
1414

15-
namespace TINY
16-
{
17-
/**
18-
* @namespace SCANNER
19-
* @brief Contains all components related to the lexical analysis (scanning) of TINY language.
20-
*/
21-
namespace SCANNER
22-
{
23-
24-
std::string FileHandler::readFile(const std::string &filePath)
25-
{
26-
// Open the file at the given path
27-
std::ifstream file(filePath);
28-
29-
// Check if the file was opened successfully
30-
if (!file.is_open())
31-
{
32-
throw std::runtime_error("Failed to open file: " + filePath);
33-
}
34-
35-
// Read the entire file content into a string
36-
return std::string(
37-
(std::istreambuf_iterator<char>(file)),
38-
std::istreambuf_iterator<char>());
39-
}
40-
41-
void FileHandler::writeTokens(const std::string &filePath, const std::vector<Token> &tokens,
42-
bool includePosition)
43-
{
44-
// Create a string file content from the tokens
45-
std::ostringstream contentStream;
46-
for (const Token &token : tokens)
47-
{
48-
contentStream << token.toString(includePosition) << "\n";
49-
}
50-
51-
// Write the file content to the file at the given path
52-
FileHandler::writeFile(filePath, contentStream.str());
53-
}
54-
55-
void FileHandler::writeFile(const std::string &filePath, const std::string &content)
56-
{
57-
// Open the file at the given path
58-
std::ofstream file(filePath);
59-
60-
// Check if the file was opened successfully
61-
if (!file.is_open())
62-
{
63-
throw std::runtime_error("Failed to open file: " + filePath);
64-
}
65-
66-
// Write the content to the file
67-
file << content;
68-
}
69-
} // namespace SCANNER
70-
} // namespace TINY
15+
namespace TINY {
16+
/**
17+
* @namespace SCANNER
18+
* @brief Contains all components related to the lexical analysis (scanning) of TINY language.
19+
*/
20+
namespace SCANNER {
21+
22+
std::string FileHandler::readFile(const std::string &filePath) {
23+
// file path cannot be empty
24+
if (filePath.empty()) {
25+
throw std::invalid_argument("File path cannot be empty.");
26+
}
27+
28+
// file path must exist
29+
if (!std::filesystem::exists(filePath)) {
30+
throw std::invalid_argument("File does not exist: " + filePath);
31+
}
32+
33+
// Open the file at the given path
34+
std::ifstream file(filePath);
35+
36+
// Check if the file was opened successfully
37+
if (!file.is_open()) {
38+
throw std::runtime_error("Failed to open file: " + filePath);
39+
}
40+
41+
// Read the entire file content into a string
42+
return std::string(
43+
(std::istreambuf_iterator<char>(file)),
44+
std::istreambuf_iterator<char>());
45+
}
46+
47+
void FileHandler::writeTokens(const std::string &filePath, const std::vector<Token> &tokens,
48+
bool includePosition) {
49+
// Create a string file content from the tokens
50+
std::ostringstream contentStream;
51+
for (const Token &token : tokens) {
52+
contentStream << token.toString(includePosition) << "\n";
53+
}
54+
55+
// Write the file content to the file at the given path
56+
FileHandler::writeFile(filePath, contentStream.str());
57+
}
58+
59+
void FileHandler::writeFile(const std::string &filePath, const std::string &content) {
60+
// if the file path is empty, throw an invalid argument exception
61+
if (filePath.empty()) {
62+
throw std::invalid_argument("File path cannot be empty.");
63+
}
64+
65+
// if the path is a directory, throw an invalid argument exception
66+
if (std::filesystem::is_directory(filePath)) {
67+
throw std::invalid_argument("File path is a directory: " + filePath);
68+
}
69+
70+
// Extract the parent directory from the file path
71+
std::filesystem::path fileParentPath = std::filesystem::path(filePath).parent_path();
72+
73+
// if the path have unmade folders, create them
74+
if (!fileParentPath.empty() && !std::filesystem::exists(fileParentPath)) {
75+
std::filesystem::create_directories(fileParentPath);
76+
// set color to orange
77+
std::cout << "\033[1;33m";
78+
// print the message with the full path from the root
79+
std::cout << "Creating directory: " << std::filesystem::absolute(fileParentPath) << std::endl;
80+
// reset color
81+
std::cout << "\033[0m";
82+
}
83+
84+
// Open the file at the given path
85+
std::ofstream file(filePath);
86+
87+
// Check if the file was opened successfully
88+
if (!file.is_open()) {
89+
throw std::runtime_error("Failed to open file: " + filePath);
90+
}
91+
92+
// Write the content to the file
93+
file << content;
94+
}
95+
} // namespace SCANNER
96+
} // namespace TINY

0 commit comments

Comments
 (0)