Line data Source code
1 : #include "cfd/core/filesystem.h"
2 : #include "cfd/core/logging.h"
3 :
4 : #include <stdio.h>
5 : #include <stdlib.h>
6 : #include <string.h>
7 : #include <time.h>
8 :
9 : #ifdef _WIN32
10 : #include <direct.h>
11 : #else
12 : #include <sys/stat.h>
13 : #include <unistd.h>
14 : #endif
15 :
16 : //=============================================================================
17 : // FILE SYSTEM
18 : //=============================================================================
19 :
20 76 : int ensure_directory_exists(const char* path) {
21 : #ifdef _WIN32
22 : if (_access(path, 0) == 0) {
23 : return 1; // Directory exists
24 : }
25 : return _mkdir(path) == 0;
26 : #else
27 76 : struct stat st = {0};
28 76 : if (stat(path, &st) == 0) {
29 : return 1; // Directory exists
30 : }
31 15 : return mkdir(path, 0755) == 0;
32 : #endif
33 : }
34 :
35 : //=============================================================================
36 : // OUTPUT PATH CONFIGURATION
37 : //=============================================================================
38 :
39 : static char artifacts_base_path[512] = "";
40 : static cfd_default_path_mode_t default_path_mode = CFD_PATH_CURRENT_DIR;
41 :
42 0 : void cfd_set_output_base_dir(const char* path) {
43 0 : if (path && strlen(path) > 0) {
44 0 : snprintf(artifacts_base_path, sizeof(artifacts_base_path), "%s", path);
45 : } else {
46 0 : artifacts_base_path[0] = '\0'; // Reset to default
47 : }
48 0 : }
49 :
50 0 : void cfd_set_default_path_mode(cfd_default_path_mode_t mode) {
51 0 : default_path_mode = mode;
52 0 : }
53 :
54 :
55 65 : void cfd_get_artifacts_path(char* buffer, size_t size) {
56 65 : if (!buffer || size == 0) {
57 : return;
58 : }
59 :
60 65 : if (strlen(artifacts_base_path) > 0) {
61 0 : snprintf(buffer, size, "%s", artifacts_base_path);
62 0 : return;
63 : }
64 :
65 : // Generate default path based on mode
66 65 : switch (default_path_mode) {
67 : case CFD_PATH_CURRENT_DIR:
68 65 : snprintf(buffer, size, ".");
69 65 : break;
70 :
71 0 : case CFD_PATH_TEMP_DIR:
72 : #ifdef _WIN32
73 : {
74 : char* temp_dir = getenv("TEMP");
75 : if (!temp_dir) {
76 : temp_dir = getenv("TMP");
77 : }
78 : if (!temp_dir) {
79 : temp_dir = "C:\\temp";
80 : }
81 : snprintf(buffer, size, "%s", temp_dir);
82 : }
83 : #else
84 : {
85 0 : char* temp_dir = getenv("TMPDIR");
86 0 : if (!temp_dir)
87 0 : temp_dir = "/tmp";
88 0 : snprintf(buffer, size, "%s", temp_dir);
89 : }
90 : #endif
91 0 : break;
92 :
93 : case CFD_PATH_RELATIVE_BUILD:
94 : #ifdef _WIN32
95 : snprintf(buffer, size, "..\\..\\artifacts");
96 : #else
97 0 : snprintf(buffer, size, "../../artifacts");
98 : #endif
99 0 : break;
100 :
101 : default:
102 0 : snprintf(buffer, size, ".");
103 0 : break;
104 : }
105 65 : buffer[size - 1] = '\0';
106 : }
107 :
108 0 : void cfd_reset_artifacts_path(void) {
109 0 : artifacts_base_path[0] = '\0';
110 0 : }
111 :
112 : //=============================================================================
113 : // PATH CONSTRUCTION
114 : //=============================================================================
115 32 : void make_output_path(char* buffer, size_t buffer_size, const char* filename) {
116 32 : char base_path[512];
117 32 : cfd_get_artifacts_path(base_path, sizeof(base_path));
118 :
119 : #ifdef _WIN32
120 : snprintf(buffer, buffer_size, "%s\\output\\%s", base_path, filename);
121 : #else
122 32 : snprintf(buffer, buffer_size, "%s/output/%s", base_path, filename);
123 : #endif
124 32 : }
125 :
126 33 : void make_artifacts_path(char* buffer, size_t buffer_size, const char* subdir) {
127 33 : char base_path[512];
128 33 : cfd_get_artifacts_path(base_path, sizeof(base_path));
129 :
130 33 : if (subdir && strlen(subdir) > 0) {
131 : #ifdef _WIN32
132 : snprintf(buffer, buffer_size, "%s\\%s", base_path, subdir);
133 : #else
134 31 : snprintf(buffer, buffer_size, "%s/%s", base_path, subdir);
135 : #endif
136 : } else {
137 2 : snprintf(buffer, buffer_size, "%s", base_path);
138 : }
139 33 : }
140 :
141 : //=============================================================================
142 : // RUN DIRECTORY MANAGEMENT
143 : //=============================================================================
144 :
145 : static char current_run_directory[512] = {0}; // Keep state, but no direct access
146 :
147 5 : static void create_run_directory_internal(char* buffer, size_t buffer_size, const char* base_dir,
148 : const char* timestamp_name) {
149 : // Use provided base directory
150 5 : const char* root_path = (base_dir && strlen(base_dir) > 0) ? base_dir : ".";
151 :
152 : #ifdef _WIN32
153 : snprintf(buffer, buffer_size, "%s\\output\\%s", root_path, timestamp_name);
154 : #else
155 5 : snprintf(buffer, buffer_size, "%s/output/%s", root_path, timestamp_name);
156 : #endif
157 :
158 : // Ensure base output directory exists
159 5 : char output_base[512];
160 : #ifdef _WIN32
161 : snprintf(output_base, sizeof(output_base), "%s\\output", root_path);
162 : #else
163 5 : snprintf(output_base, sizeof(output_base), "%s/output", root_path);
164 : #endif
165 5 : ensure_directory_exists(output_base);
166 :
167 : // Create run-specific directory
168 5 : if (!ensure_directory_exists(buffer)) {
169 3 : cfd_warning("Failed to create run directory, using base output directory");
170 3 : snprintf(buffer, buffer_size, "%s", output_base);
171 : }
172 5 : }
173 :
174 0 : void cfd_create_run_directory(char* buffer, size_t buffer_size) {
175 0 : cfd_create_run_directory_with_prefix(buffer, buffer_size, "run");
176 0 : }
177 :
178 0 : void cfd_create_run_directory_with_prefix(char* buffer, size_t buffer_size, const char* prefix) {
179 0 : time_t now = time(NULL);
180 0 : struct tm* t = localtime(&now);
181 :
182 : // Format: prefix_YYYYMMDD_HHMMSS
183 0 : char timestamp[64];
184 0 : snprintf(timestamp, sizeof(timestamp), "%s_%04d%02d%02d_%02d%02d%02d", prefix,
185 0 : t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
186 :
187 : // Create full path
188 0 : char base_path[512];
189 0 : cfd_get_artifacts_path(base_path, sizeof(base_path));
190 :
191 : #ifdef _WIN32
192 : snprintf(buffer, buffer_size, "%s\\output\\%s", base_path, timestamp);
193 : #else
194 0 : snprintf(buffer, buffer_size, "%s/output/%s", base_path, timestamp);
195 : #endif
196 :
197 : // Ensure base output directory exists
198 0 : char output_base[512];
199 : #ifdef _WIN32
200 : snprintf(output_base, sizeof(output_base), "%s\\output", base_path);
201 : #else
202 0 : snprintf(output_base, sizeof(output_base), "%s/output", base_path);
203 : #endif
204 0 : ensure_directory_exists(output_base);
205 :
206 : // Create run-specific directory
207 0 : if (!ensure_directory_exists(buffer)) {
208 0 : cfd_warning("Failed to create run directory, using base output directory");
209 0 : snprintf(buffer, buffer_size, "%s", output_base);
210 : }
211 :
212 : // Store in global state
213 0 : snprintf(current_run_directory, sizeof(current_run_directory), "%s", buffer);
214 0 : }
215 :
216 0 : void cfd_create_run_directory_ex(char* buffer, size_t buffer_size, const char* solver_name,
217 : size_t nx, size_t ny) {
218 0 : time_t now = time(NULL);
219 0 : struct tm* t = localtime(&now);
220 :
221 : // Format: solvername_gridsize_YYYYMMDD_HHMMSS
222 0 : char timestamp[128];
223 0 : snprintf(timestamp, sizeof(timestamp), "%s_%zux%zu_%04d%02d%02d_%02d%02d%02d",
224 0 : solver_name ? solver_name : "sim", nx, ny, t->tm_year + 1900, t->tm_mon + 1,
225 : t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
226 :
227 : // Create full path
228 0 : char base_path[512];
229 0 : cfd_get_artifacts_path(base_path, sizeof(base_path));
230 :
231 : #ifdef _WIN32
232 : snprintf(buffer, buffer_size, "%s\\output\\%s", base_path, timestamp);
233 : #else
234 0 : snprintf(buffer, buffer_size, "%s/output/%s", base_path, timestamp);
235 : #endif
236 :
237 : // Ensure base output directory exists
238 0 : char output_base[512];
239 : #ifdef _WIN32
240 : snprintf(output_base, sizeof(output_base), "%s\\output", base_path);
241 : #else
242 0 : snprintf(output_base, sizeof(output_base), "%s/output", base_path);
243 : #endif
244 0 : ensure_directory_exists(output_base);
245 :
246 : // Create run-specific directory
247 0 : if (!ensure_directory_exists(buffer)) {
248 0 : cfd_warning("Failed to create run directory, using base output directory");
249 0 : snprintf(buffer, buffer_size, "%s", output_base);
250 : }
251 :
252 : // Store in global state
253 0 : snprintf(current_run_directory, sizeof(current_run_directory), "%s", buffer);
254 0 : }
255 :
256 0 : void cfd_create_run_directory_with_base(char* buffer, size_t buffer_size, const char* base_dir,
257 : const char* prefix) {
258 0 : time_t now = time(NULL);
259 0 : struct tm* t = localtime(&now);
260 :
261 : // Format: prefix_YYYYMMDD_HHMMSS
262 0 : char timestamp[64];
263 0 : snprintf(timestamp, sizeof(timestamp), "%s_%04d%02d%02d_%02d%02d%02d", prefix,
264 0 : t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
265 :
266 0 : create_run_directory_internal(buffer, buffer_size, base_dir, timestamp);
267 0 : }
268 :
269 5 : void cfd_create_run_directory_ex_with_base(char* buffer, size_t buffer_size, const char* base_dir,
270 : const char* solver_name, size_t nx, size_t ny) {
271 5 : time_t now = time(NULL);
272 5 : struct tm* t = localtime(&now);
273 :
274 : // Format: solvername_gridsize_YYYYMMDD_HHMMSS
275 5 : char timestamp[128];
276 10 : snprintf(timestamp, sizeof(timestamp), "%s_%zux%zu_%04d%02d%02d_%02d%02d%02d",
277 5 : solver_name ? solver_name : "sim", nx, ny, t->tm_year + 1900, t->tm_mon + 1,
278 : t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
279 :
280 5 : create_run_directory_internal(buffer, buffer_size, base_dir, timestamp);
281 5 : }
282 :
283 0 : void cfd_get_run_directory(char* buffer, size_t size) {
284 0 : if (!buffer || size == 0) {
285 : return;
286 : }
287 :
288 0 : if (current_run_directory[0] != '\0') {
289 0 : snprintf(buffer, size, "%s", current_run_directory);
290 : } else {
291 0 : buffer[0] = '\0';
292 : }
293 0 : buffer[size - 1] = '\0';
294 : }
295 :
296 0 : void cfd_reset_run_directory(void) {
297 0 : current_run_directory[0] = '\0';
298 0 : }
|