Commit e318123ba7d7dfb05133dcdc482a35494f82350e
1 parent
25d8d20b
changed stim::filename extensively, but the old class is available in filename_old.h
Showing
1 changed file
with
448 additions
and
0 deletions
Show diff stats
1 | +#ifndef STIM_FILENAME_H | ||
2 | +#define STIM_FILENAME_H | ||
3 | + | ||
4 | +#include <stdio.h> /* defines FILENAME_MAX */ | ||
5 | +#ifdef _WIN32 | ||
6 | + #include <windows.h> | ||
7 | + #include <direct.h> | ||
8 | + #define GetCurrentDir _getcwd | ||
9 | + #define STIM_FILENAME_DIV '/' | ||
10 | +#else | ||
11 | + #include <unistd.h> | ||
12 | + #define GetCurrentDir getcwd | ||
13 | + #define STIM_FILENAME_DIV '/' | ||
14 | + #endif | ||
15 | + | ||
16 | +#include <string> | ||
17 | +#include <sstream> | ||
18 | +#include <iomanip> | ||
19 | +#include <vector> | ||
20 | +#include <stack> | ||
21 | +#include <algorithm> | ||
22 | +#include <iostream> | ||
23 | + | ||
24 | +#include "../parser/parser.h" | ||
25 | +#ifdef BOOST_PRECOMPILED | ||
26 | +#include <boost/filesystem.hpp> | ||
27 | +#endif | ||
28 | +namespace stim{ | ||
29 | + | ||
30 | +//filename class designed to work with both Windows and Unix | ||
31 | + | ||
32 | +class filename{ | ||
33 | + | ||
34 | +private: | ||
35 | + void init(){ | ||
36 | + | ||
37 | + absolute = false; | ||
38 | + | ||
39 | + } | ||
40 | + | ||
41 | +protected: | ||
42 | + | ||
43 | + std::string drive; //drive letter (for Windows) | ||
44 | + std::vector<std::string> path; //directory hierarchy | ||
45 | + std::string pref; //file prefix (without extension) | ||
46 | + std::string ext; //file extension | ||
47 | + | ||
48 | + bool absolute; //filename is an absolute path | ||
49 | + | ||
50 | + //replaces win32 dividers with the Linux standard | ||
51 | + std::string unix_div(std::string s) { | ||
52 | + std::replace( s.begin(), s.end(), '\\', '/'); | ||
53 | + return s; | ||
54 | + } | ||
55 | + | ||
56 | + //break up a filename into a prefix and extension | ||
57 | + void parse_name(std::string fname){ | ||
58 | + | ||
59 | + //find the extension | ||
60 | + size_t xpos = fname.find_last_of('.'); //find the position of the extension period (if there is one) | ||
61 | + if(xpos != std::string::npos){ //split the prefix and extension | ||
62 | + pref = fname.substr(0, xpos); | ||
63 | + ext = fname.substr(xpos + 1); | ||
64 | + } | ||
65 | + else | ||
66 | + pref = fname; | ||
67 | + } | ||
68 | + | ||
69 | + /// Parse a file locator into its component parts | ||
70 | + void parse(std::string &dr, std::vector<std::string> &p, std::string &pre, std::string &ex, bool &abs, std::string loc){ | ||
71 | + dr = ""; //initialize the drive to NULL (in a Unix system, this will always be NULL) | ||
72 | + p.clear(); //empty out the path array | ||
73 | + pre = ""; //initialize the file prefix to NULL (if no file name is given, this will remain NULL) | ||
74 | + ex = ""; //initialize the file extension to NULL (if no extension exists, this will remain NULL) | ||
75 | + abs = false; //the default path is relative | ||
76 | + | ||
77 | + loc = unix_div(loc); //convert to unix style divisions (default representation) | ||
78 | + | ||
79 | + if(loc.size() == 0) return; //if the locator is NULL, just return (everything else will be NULL) | ||
80 | + | ||
81 | + //determine the drive (if Windows) | ||
82 | + #ifdef _WIN32 | ||
83 | + if(loc[1] == ':'){ //if the second character is a colon, the character right before it is the drive | ||
84 | + abs = true; //this is an absolute path | ||
85 | + dr = loc[0]; //copy the drive letter | ||
86 | + loc = loc.substr(3); //remove the drive information from the locator string | ||
87 | + } | ||
88 | + #else | ||
89 | + if(loc[0] == STIM_FILENAME_DIV){ | ||
90 | + absolute = true; | ||
91 | + loc = loc.substr(1); | ||
92 | + } | ||
93 | + #endif | ||
94 | + | ||
95 | + std::string fname = loc.substr( loc.find_last_of('/') + 1 ); //find the file name (including extension) | ||
96 | + | ||
97 | + //find the extension and prefix | ||
98 | + size_t xpos = fname.find_last_of('.'); //find the position of the extension period (if there is one) | ||
99 | + if(xpos != std::string::npos){ //split the prefix and extension | ||
100 | + pre = fname.substr(0, xpos); | ||
101 | + ex = fname.substr(xpos + 1); | ||
102 | + } | ||
103 | + else | ||
104 | + pre = fname; | ||
105 | + } | ||
106 | + | ||
107 | + //parse a file locator string | ||
108 | + void parse(std::string loc){ | ||
109 | + if(loc.size() == 0) return; | ||
110 | + | ||
111 | + loc = unix_div(loc); | ||
112 | + | ||
113 | + //determine the drive (if Windows) | ||
114 | + drive = ""; | ||
115 | + #ifdef _WIN32 | ||
116 | + //if the second character is a colon, the character right before it is the drive | ||
117 | + if(loc[1] == ':'){ | ||
118 | + absolute = true; //this is an absolute path | ||
119 | + drive = loc[0]; //copy the drive letter | ||
120 | + loc = loc.substr(3); //remove the drive information from the locator string | ||
121 | + } | ||
122 | + #else | ||
123 | + if(loc[0] == STIM_FILENAME_DIV){ | ||
124 | + absolute = true; | ||
125 | + loc = loc.substr(1); | ||
126 | + } | ||
127 | + #endif | ||
128 | + | ||
129 | + //determine the file name | ||
130 | + std::string fname = loc.substr( loc.find_last_of('/') + 1 ); //find the file name (including extension) | ||
131 | + | ||
132 | + //parse the file name | ||
133 | + parse_name(fname); | ||
134 | + | ||
135 | + //find the directory hierarchy | ||
136 | + std::string dir = loc.substr(0, loc.find_last_of('/') + 1 ); | ||
137 | + path = stim::parser::split(dir, '/'); | ||
138 | + } | ||
139 | + | ||
140 | +public: | ||
141 | + | ||
142 | + filename(){ | ||
143 | + init(); | ||
144 | + } | ||
145 | + | ||
146 | + filename(std::string loc){ | ||
147 | + init(); | ||
148 | + parse(loc); | ||
149 | + } | ||
150 | + | ||
151 | + | ||
152 | + /// Outputs the file name (including prefix and extension) | ||
153 | + std::string get_name(){ | ||
154 | + if(pref == "" && ext == "") | ||
155 | + return ""; | ||
156 | + else | ||
157 | + return pref + "." + ext; | ||
158 | + } | ||
159 | + | ||
160 | + /// Output the file extension only (usually three characters after a '.') | ||
161 | + std::string get_extension(){ | ||
162 | + return ext; | ||
163 | + } | ||
164 | + | ||
165 | + std::string extension(){ | ||
166 | + return ext; | ||
167 | + } | ||
168 | + | ||
169 | + void extension(std::string e){ | ||
170 | + ext = e; | ||
171 | + } | ||
172 | + | ||
173 | + /// Output the file prefix only (name before the extension) | ||
174 | + std::string get_prefix(){ | ||
175 | + return pref; | ||
176 | + } | ||
177 | + | ||
178 | + std::string prefix(){ | ||
179 | + return pref; | ||
180 | + } | ||
181 | + | ||
182 | + void prefix(std::string p){ | ||
183 | + pref = p; | ||
184 | + } | ||
185 | + | ||
186 | + /// Output the entire path (not including the filename) | ||
187 | + /// ex. "c:\this\is\the\directory\" | ||
188 | + std::string dir(){ | ||
189 | + std::stringstream ss; | ||
190 | + | ||
191 | + //if the path is absolute | ||
192 | + if(absolute){ | ||
193 | + //output the drive letter if in Windows | ||
194 | + #ifdef _WIN32 | ||
195 | + ss<<drive<<":"; | ||
196 | + #endif | ||
197 | + ss<<STIM_FILENAME_DIV; | ||
198 | + } | ||
199 | + | ||
200 | + //output the directory | ||
201 | + for(unsigned int d = 0; d < path.size(); d++) | ||
202 | + ss<<path[d]<<STIM_FILENAME_DIV; | ||
203 | + | ||
204 | + return ss.str(); | ||
205 | + | ||
206 | + } | ||
207 | + | ||
208 | + void clear() | ||
209 | + { | ||
210 | + drive = ""; //drive letter (for Windows) | ||
211 | + path.resize(0); | ||
212 | + pref= ""; //file prefix (without extension) | ||
213 | + ext = ""; //file extension | ||
214 | + } | ||
215 | + | ||
216 | + /// Output the entire string, including the path and filename | ||
217 | + /// ex. "c:\this\is\a\directory\file.txt" | ||
218 | + std::string str(){ | ||
219 | + std::stringstream ss; //create a string stream | ||
220 | + ss<<dir()<<get_name(); //push the directory and filename to that stream | ||
221 | + return ss.str(); //convert the stream to a string and return it | ||
222 | + } | ||
223 | + | ||
224 | + //***************************************************************************************************************** | ||
225 | + // output is the directory and the prefix and the extension of the files, which are looking for in that directory. | ||
226 | + /// David: I have no idea what this is doing. It looks identical to dir() | ||
227 | + std::string dir_fname(){ | ||
228 | + std::stringstream ss; | ||
229 | + | ||
230 | + //if the path is absolute | ||
231 | + if(absolute){ | ||
232 | + //output the drive letter if in Windows | ||
233 | + #ifdef _WIN32 | ||
234 | + ss<<drive<<":"; | ||
235 | + #endif | ||
236 | + ss<<STIM_FILENAME_DIV; | ||
237 | + } | ||
238 | + | ||
239 | + | ||
240 | + for(unsigned int d = 0; d < path.size(); d++) | ||
241 | + ss<<path[d]<<STIM_FILENAME_DIV; | ||
242 | + ss<<get_name(); | ||
243 | + | ||
244 | + return ss.str(); | ||
245 | + | ||
246 | + } | ||
247 | + | ||
248 | + // output is the directory and the name of the file which are found in that given directory | ||
249 | + std::string f_name(std::string file_name){ | ||
250 | + std::stringstream ss; | ||
251 | + | ||
252 | + if(absolute){ //if the path is absolute | ||
253 | + #ifdef _WIN32 | ||
254 | + ss<<drive<<":"; //output the drive letter if in Windows | ||
255 | + #endif | ||
256 | + ss<<STIM_FILENAME_DIV; //output a path divider | ||
257 | + } | ||
258 | + | ||
259 | + for(unsigned int d = 0; d < path.size(); d++) //for each directory in the current path | ||
260 | + ss<<path[d]<<STIM_FILENAME_DIV; //add that directory, interspersing path dividers | ||
261 | + | ||
262 | + stim::filename fn = file_name; | ||
263 | + std::string fn_prefix = fn.pref; | ||
264 | + std::string fn_ext = fn.ext; | ||
265 | + ss<<fn_prefix + '.' + fn_ext; | ||
266 | + | ||
267 | + return ss.str(); | ||
268 | + | ||
269 | + } | ||
270 | + | ||
271 | + /// Returns a list of files using the current filename as a template. | ||
272 | + /// For example: | ||
273 | + /// C:\this\is\a\path\file*.txt | ||
274 | + /// can be used as a template to find a series of files file001.txt, file002.txt, file003.txt, etc. | ||
275 | + std::vector<stim::filename> get_list(){ | ||
276 | + //this is OS dependent, so we're starting with Windows | ||
277 | + //the Unix version requires Boost | ||
278 | + | ||
279 | +#ifdef _WIN32 | ||
280 | + stim::filename filepath(dir_fname()); //initialize filepath with the mask | ||
281 | + | ||
282 | + HANDLE hFind = INVALID_HANDLE_VALUE; //allocate data structures for looping through files | ||
283 | + WIN32_FIND_DATAA FindFileData; | ||
284 | + std::vector<stim::filename> file_list; //initialize a list to hold all matching filenames | ||
285 | + | ||
286 | + hFind = FindFirstFileA((filepath.str().c_str()), &FindFileData); //find the first file that matches the specified file path | ||
287 | + | ||
288 | + if (hFind == INVALID_HANDLE_VALUE) { //if there are no matching files | ||
289 | + printf ("Invalid file handle. Error is %u.\n", GetLastError()); //print an error | ||
290 | + } | ||
291 | + else { | ||
292 | + std::string file_name = FindFileData.cFileName; //save the file name | ||
293 | + std::string file_path = dir(); //the file is in the specified directory, so save it | ||
294 | + stim::filename current_file(file_path + file_name); //create a stim::filename structure representing this file | ||
295 | + file_list.push_back(current_file); //push the new stim::filename to the file list | ||
296 | + | ||
297 | + // List all the other files in the directory. | ||
298 | + while (FindNextFileA(hFind, &FindFileData) != 0){ //iterate until there are no more matching files | ||
299 | + file_name = FindFileData.cFileName; //save the next file | ||
300 | + current_file = (f_name(file_name)); //append the directory | ||
301 | + file_list.push_back(current_file); //push it to the list | ||
302 | + } | ||
303 | + FindClose(hFind); //close the file data structure | ||
304 | + } | ||
305 | + return file_list; //return the list of files | ||
306 | + | ||
307 | +#elif BOOST_PRECOMPILED | ||
308 | + | ||
309 | + boost::filesystem::path p(dir()); //create a path from the current filename | ||
310 | + std::vector<stim::filename> file_list; | ||
311 | + if(boost::filesystem::exists(p)){ | ||
312 | + if(boost::filesystem::is_directory(p)){ | ||
313 | + typedef std::vector<boost::filesystem::path> vec; // store paths, | ||
314 | + vec v; // so we can sort them later | ||
315 | + std::copy(boost::filesystem::directory_iterator(p), boost::filesystem::directory_iterator(), back_inserter(v)); | ||
316 | + std::sort(v.begin(), v.end()); // sort, since directory iteration | ||
317 | + // is not ordered on some file systems | ||
318 | + //compare file names to the current template (look for wild cards) | ||
319 | + for (vec::const_iterator it(v.begin()), it_end(v.end()); it != it_end; ++it) | ||
320 | + { | ||
321 | + //if the filename is a wild card *or* it matches the read file name | ||
322 | + if( prefix == "*" || prefix == (*it).filename().stem().string()){ | ||
323 | + //if the extension is a wild card *or* it matches the read file extension | ||
324 | + if( ext == "*" || "." + ext == (*it).filename().extension().string()){ | ||
325 | + file_list.push_back((*it).string()); //include it in the final list | ||
326 | + } | ||
327 | + | ||
328 | + } | ||
329 | + | ||
330 | + | ||
331 | + | ||
332 | + } | ||
333 | + | ||
334 | + } | ||
335 | + | ||
336 | + } | ||
337 | + return file_list; | ||
338 | +#else | ||
339 | + std::cout<<"ERROR: UNIX systems don't support file lists without the Boost precompiled libraries."<<std::endl; | ||
340 | + exit(1); | ||
341 | +#endif | ||
342 | + | ||
343 | + } | ||
344 | + //************************************************************************************************** | ||
345 | + | ||
346 | + //gets the current working directory | ||
347 | + static stim::filename cwd(){ | ||
348 | + | ||
349 | + | ||
350 | + char cCurrentPath[FILENAME_MAX]; | ||
351 | + | ||
352 | + if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath))){ | ||
353 | + std::cout<<"ERROR getting current working directory."<<std::endl; | ||
354 | + exit(1); | ||
355 | + } | ||
356 | + | ||
357 | + std::cout<<cCurrentPath<<std::endl; | ||
358 | + return stim::filename(std::string(cCurrentPath) + STIM_FILENAME_DIV); | ||
359 | + } | ||
360 | + | ||
361 | + void set_name(std::string fname){ | ||
362 | + parse_name(fname); | ||
363 | + } | ||
364 | + | ||
365 | + //append a string to the filename and return a new filename | ||
366 | + stim::filename append(std::string s){ | ||
367 | + stim::filename result = *this; //create a new filename, copy the current filename | ||
368 | + result.pref = pref + s; //append the string to the filename | ||
369 | + return result; | ||
370 | + } | ||
371 | + | ||
372 | + //get a path relative to the current one | ||
373 | + stim::filename get_relative(std::string rel){ | ||
374 | + | ||
375 | + std::vector<std::string> rel_path = stim::parser::split(rel, STIM_FILENAME_DIV); | ||
376 | + | ||
377 | + //if the relative path doesn't contain a file, add a blank string to be used as the filename | ||
378 | + if(rel[rel.size()-1] == STIM_FILENAME_DIV) | ||
379 | + rel_path.push_back(""); | ||
380 | + | ||
381 | + //create a stack representing the current absolute path | ||
382 | + std::stack<std::string, std::vector<std::string> > s(path); | ||
383 | + | ||
384 | + //for each token in the relative path | ||
385 | + for(int d=0; d<rel_path.size() - 1; d++){ | ||
386 | + | ||
387 | + //if the token is a double-dot, pop a directory off of the stack | ||
388 | + if(rel_path[d] == "..") | ||
389 | + s.pop(); | ||
390 | + else | ||
391 | + s.push(rel_path[d]); | ||
392 | + } | ||
393 | + | ||
394 | + std::string* end = &s.top() + 1; | ||
395 | + std::string* begin = end - s.size(); | ||
396 | + std::vector<std::string> result_path(begin, end); | ||
397 | + | ||
398 | + //create a new path to be returned | ||
399 | + stim::filename result = *this; | ||
400 | + result.path = result_path; | ||
401 | + result.set_name(rel_path.back()); | ||
402 | + | ||
403 | + return result; | ||
404 | + } | ||
405 | + | ||
406 | + /// This function replaces a wildcard in the prefix with the specified string | ||
407 | + stim::filename insert(std::string str){ | ||
408 | + | ||
409 | + stim::filename result = *this; //initialize the result filename to the current filename | ||
410 | + size_t loc = result.pref.find('*'); //find a wild card in the string | ||
411 | + if(loc == std::string::npos) //if a wildcard isn't found | ||
412 | + result.pref += str; //append the value to the prefix | ||
413 | + else | ||
414 | + result.pref.replace(loc, 1, str); //replace the wildcard with the string | ||
415 | + return result; //return the result | ||
416 | + } | ||
417 | + | ||
418 | + stim::filename insert(size_t i, size_t n = 2){ | ||
419 | + | ||
420 | + std::stringstream ss; | ||
421 | + ss << std::setw(n) << std::setfill('0') << i; | ||
422 | + return insert(ss.str()); | ||
423 | + } | ||
424 | + | ||
425 | + bool is_relative(){ | ||
426 | + return !absolute; | ||
427 | + } | ||
428 | + | ||
429 | + bool is_absolute(){ | ||
430 | + return absolute; | ||
431 | + } | ||
432 | + | ||
433 | + | ||
434 | + | ||
435 | + | ||
436 | + | ||
437 | + | ||
438 | + | ||
439 | + | ||
440 | + | ||
441 | +}; | ||
442 | + | ||
443 | + | ||
444 | +} //end namespace stim | ||
445 | + | ||
446 | + | ||
447 | +#endif | ||
448 | + |