]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* |
2 | * | |
3 | * Copyright (c) 1998-2002 | |
4 | * John Maddock | |
5 | * | |
6 | * Use, modification and distribution are subject to the | |
7 | * Boost Software License, Version 1.0. (See accompanying file | |
8 | * LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
9 | * | |
10 | */ | |
11 | ||
12 | /* | |
13 | * LOCATION: see http://www.boost.org for most recent version. | |
14 | * FILE: fileiter.cpp | |
15 | * VERSION: see <boost/version.hpp> | |
16 | * DESCRIPTION: Implements file io primitives + directory searching for class boost::RegEx. | |
17 | */ | |
18 | ||
19 | ||
20 | #define BOOST_REGEX_SOURCE | |
21 | ||
22 | #include <boost/config.hpp> | |
23 | #include <climits> | |
24 | #include <stdexcept> | |
25 | #include <string> | |
26 | #include <boost/throw_exception.hpp> | |
27 | #include <boost/regex/v4/fileiter.hpp> | |
28 | #include <boost/regex/v4/regex_workaround.hpp> | |
29 | #include <boost/regex/pattern_except.hpp> | |
30 | ||
31 | #include <cstdio> | |
32 | #if defined(BOOST_NO_STDC_NAMESPACE) | |
33 | namespace std{ | |
34 | using ::sprintf; | |
35 | using ::fseek; | |
36 | using ::fread; | |
37 | using ::ftell; | |
38 | using ::fopen; | |
39 | using ::fclose; | |
40 | using ::FILE; | |
41 | using ::strcpy; | |
42 | using ::strcpy; | |
43 | using ::strcat; | |
44 | using ::strcmp; | |
45 | using ::strlen; | |
46 | } | |
47 | #endif | |
48 | ||
49 | ||
50 | #ifndef BOOST_REGEX_NO_FILEITER | |
51 | ||
52 | #if defined(__CYGWIN__) || defined(__CYGWIN32__) | |
53 | #include <sys/cygwin.h> | |
54 | #endif | |
55 | ||
56 | #ifdef BOOST_MSVC | |
57 | # pragma warning(disable: 4800) | |
58 | #endif | |
59 | ||
60 | namespace boost{ | |
61 | namespace BOOST_REGEX_DETAIL_NS{ | |
62 | // start with the operating system specific stuff: | |
63 | ||
20effc67 | 64 | #if (defined(BOOST_BORLANDC) || defined(BOOST_REGEX_FI_WIN32_DIR) || defined(BOOST_MSVC)) && !defined(BOOST_RE_NO_WIN32) |
7c673cae FG |
65 | |
66 | // platform is DOS or Windows | |
67 | // directories are separated with '\\' | |
68 | // and names are insensitive of case | |
69 | ||
70 | BOOST_REGEX_DECL const char* _fi_sep = "\\"; | |
71 | const char* _fi_sep_alt = "/"; | |
72 | #define BOOST_REGEX_FI_TRANSLATE(c) std::tolower(c) | |
73 | ||
74 | #else | |
75 | ||
76 | // platform is not DOS or Windows | |
77 | // directories are separated with '/' | |
78 | // and names are sensitive of case | |
79 | ||
80 | BOOST_REGEX_DECL const char* _fi_sep = "/"; | |
81 | const char* _fi_sep_alt = _fi_sep; | |
82 | #define BOOST_REGEX_FI_TRANSLATE(c) c | |
83 | ||
84 | #endif | |
85 | ||
86 | #ifdef BOOST_REGEX_FI_WIN32_MAP | |
87 | ||
88 | void mapfile::open(const char* file) | |
89 | { | |
90 | #if defined(BOOST_NO_ANSI_APIS) | |
91 | int filename_size = strlen(file); | |
92 | LPWSTR wide_file = (LPWSTR)_alloca( (filename_size + 1) * sizeof(WCHAR) ); | |
93 | if(::MultiByteToWideChar(CP_ACP, 0, file, filename_size, wide_file, filename_size + 1) == 0) | |
94 | hfile = INVALID_HANDLE_VALUE; | |
95 | else | |
96 | hfile = CreateFileW(wide_file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
97 | #elif defined(__CYGWIN__)||defined(__CYGWIN32__) | |
98 | char win32file[ MAX_PATH ]; | |
99 | cygwin_conv_to_win32_path( file, win32file ); | |
100 | hfile = CreateFileA(win32file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
101 | #else | |
102 | hfile = CreateFileA(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); | |
103 | #endif | |
104 | if(hfile != INVALID_HANDLE_VALUE) | |
105 | { | |
106 | hmap = CreateFileMapping(hfile, 0, PAGE_READONLY, 0, 0, 0); | |
107 | if((hmap == INVALID_HANDLE_VALUE) || (hmap == NULL)) | |
108 | { | |
109 | CloseHandle(hfile); | |
110 | hmap = 0; | |
111 | hfile = 0; | |
112 | std::runtime_error err("Unable to create file mapping."); | |
113 | boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); | |
114 | } | |
20effc67 | 115 | else |
7c673cae | 116 | { |
20effc67 TL |
117 | _first = static_cast<const char*>(MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0)); |
118 | if (_first == 0) | |
119 | { | |
120 | CloseHandle(hmap); | |
121 | CloseHandle(hfile); | |
122 | hmap = 0; | |
123 | hfile = 0; | |
124 | std::runtime_error err("Unable to create file mapping."); | |
125 | boost::BOOST_REGEX_DETAIL_NS::raise_runtime_error(err); | |
126 | } | |
127 | else | |
128 | _last = _first + GetFileSize(hfile, 0); | |
7c673cae | 129 | } |
7c673cae FG |
130 | } |
131 | else | |
132 | { | |
133 | hfile = 0; | |
134 | #ifndef BOOST_NO_EXCEPTIONS | |
135 | throw std::runtime_error("Unable to open file."); | |
136 | #else | |
137 | BOOST_REGEX_NOEH_ASSERT(hfile != INVALID_HANDLE_VALUE); | |
138 | #endif | |
139 | } | |
140 | } | |
141 | ||
142 | void mapfile::close() | |
143 | { | |
144 | if(hfile != INVALID_HANDLE_VALUE) | |
145 | { | |
146 | UnmapViewOfFile((void*)_first); | |
147 | CloseHandle(hmap); | |
148 | CloseHandle(hfile); | |
149 | hmap = hfile = 0; | |
150 | _first = _last = 0; | |
151 | } | |
152 | } | |
153 | ||
154 | #elif !defined(BOOST_RE_NO_STL) | |
155 | ||
156 | mapfile_iterator& mapfile_iterator::operator = (const mapfile_iterator& i) | |
157 | { | |
158 | if(file && node) | |
159 | file->unlock(node); | |
160 | file = i.file; | |
161 | node = i.node; | |
162 | offset = i.offset; | |
163 | if(file) | |
164 | file->lock(node); | |
165 | return *this; | |
166 | } | |
167 | ||
168 | mapfile_iterator& mapfile_iterator::operator++ () | |
169 | { | |
170 | if((++offset == mapfile::buf_size) && file) | |
171 | { | |
172 | ++node; | |
173 | offset = 0; | |
174 | file->lock(node); | |
175 | file->unlock(node-1); | |
176 | } | |
177 | return *this; | |
178 | } | |
179 | ||
180 | mapfile_iterator mapfile_iterator::operator++ (int) | |
181 | { | |
182 | mapfile_iterator temp(*this); | |
183 | if((++offset == mapfile::buf_size) && file) | |
184 | { | |
185 | ++node; | |
186 | offset = 0; | |
187 | file->lock(node); | |
188 | file->unlock(node-1); | |
189 | } | |
190 | return temp; | |
191 | } | |
192 | ||
193 | mapfile_iterator& mapfile_iterator::operator-- () | |
194 | { | |
195 | if((offset == 0) && file) | |
196 | { | |
197 | --node; | |
198 | offset = mapfile::buf_size - 1; | |
199 | file->lock(node); | |
200 | file->unlock(node + 1); | |
201 | } | |
202 | else | |
203 | --offset; | |
204 | return *this; | |
205 | } | |
206 | ||
207 | mapfile_iterator mapfile_iterator::operator-- (int) | |
208 | { | |
209 | mapfile_iterator temp(*this); | |
210 | if((offset == 0) && file) | |
211 | { | |
212 | --node; | |
213 | offset = mapfile::buf_size - 1; | |
214 | file->lock(node); | |
215 | file->unlock(node + 1); | |
216 | } | |
217 | else | |
218 | --offset; | |
219 | return temp; | |
220 | } | |
221 | ||
222 | mapfile_iterator operator + (const mapfile_iterator& i, long off) | |
223 | { | |
224 | mapfile_iterator temp(i); | |
225 | temp += off; | |
226 | return temp; | |
227 | } | |
228 | ||
229 | mapfile_iterator operator - (const mapfile_iterator& i, long off) | |
230 | { | |
231 | mapfile_iterator temp(i); | |
232 | temp -= off; | |
233 | return temp; | |
234 | } | |
235 | ||
236 | mapfile::iterator mapfile::begin()const | |
237 | { | |
238 | return mapfile_iterator(this, 0); | |
239 | } | |
240 | ||
241 | mapfile::iterator mapfile::end()const | |
242 | { | |
243 | return mapfile_iterator(this, _size); | |
244 | } | |
245 | ||
246 | void mapfile::lock(pointer* node)const | |
247 | { | |
248 | BOOST_ASSERT(node >= _first); | |
249 | BOOST_ASSERT(node <= _last); | |
250 | if(node < _last) | |
251 | { | |
252 | if(*node == 0) | |
253 | { | |
254 | if(condemed.empty()) | |
255 | { | |
256 | *node = new char[sizeof(int) + buf_size]; | |
257 | *(reinterpret_cast<int*>(*node)) = 1; | |
258 | } | |
259 | else | |
260 | { | |
261 | pointer* p = condemed.front(); | |
262 | condemed.pop_front(); | |
263 | *node = *p; | |
264 | *p = 0; | |
265 | *(reinterpret_cast<int*>(*node)) = 1; | |
266 | } | |
267 | ||
268 | std::size_t read_size = 0; | |
269 | int read_pos = std::fseek(hfile, (node - _first) * buf_size, SEEK_SET); | |
270 | ||
271 | if(0 == read_pos && node == _last - 1) | |
272 | read_size = std::fread(*node + sizeof(int), _size % buf_size, 1, hfile); | |
273 | else | |
274 | read_size = std::fread(*node + sizeof(int), buf_size, 1, hfile); | |
275 | if((read_size == 0) || (std::ferror(hfile))) | |
276 | { | |
277 | #ifndef BOOST_NO_EXCEPTIONS | |
278 | unlock(node); | |
279 | throw std::runtime_error("Unable to read file."); | |
280 | #else | |
281 | BOOST_REGEX_NOEH_ASSERT((0 == std::ferror(hfile)) && (read_size != 0)); | |
282 | #endif | |
283 | } | |
284 | } | |
285 | else | |
286 | { | |
287 | if(*reinterpret_cast<int*>(*node) == 0) | |
288 | { | |
289 | *reinterpret_cast<int*>(*node) = 1; | |
290 | condemed.remove(node); | |
291 | } | |
292 | else | |
293 | ++(*reinterpret_cast<int*>(*node)); | |
294 | } | |
295 | } | |
296 | } | |
297 | ||
298 | void mapfile::unlock(pointer* node)const | |
299 | { | |
300 | BOOST_ASSERT(node >= _first); | |
301 | BOOST_ASSERT(node <= _last); | |
302 | if(node < _last) | |
303 | { | |
304 | if(--(*reinterpret_cast<int*>(*node)) == 0) | |
305 | { | |
306 | condemed.push_back(node); | |
307 | } | |
308 | } | |
309 | } | |
310 | ||
311 | long int get_file_length(std::FILE* hfile) | |
312 | { | |
313 | long int result; | |
314 | std::fseek(hfile, 0, SEEK_END); | |
315 | result = std::ftell(hfile); | |
316 | std::fseek(hfile, 0, SEEK_SET); | |
317 | return result; | |
318 | } | |
319 | ||
320 | ||
321 | void mapfile::open(const char* file) | |
322 | { | |
323 | hfile = std::fopen(file, "rb"); | |
324 | #ifndef BOOST_NO_EXCEPTIONS | |
325 | try{ | |
326 | #endif | |
327 | if(hfile != 0) | |
328 | { | |
329 | _size = get_file_length(hfile); | |
330 | long cnodes = (_size + buf_size - 1) / buf_size; | |
331 | ||
332 | // check that number of nodes is not too high: | |
333 | if(cnodes > (long)((INT_MAX) / sizeof(pointer*))) | |
334 | { | |
335 | std::fclose(hfile); | |
336 | hfile = 0; | |
337 | _size = 0; | |
338 | return; | |
339 | } | |
340 | ||
341 | _first = new pointer[(int)cnodes]; | |
342 | _last = _first + cnodes; | |
343 | std::memset(_first, 0, cnodes*sizeof(pointer)); | |
344 | } | |
345 | else | |
346 | { | |
347 | std::runtime_error err("Unable to open file."); | |
348 | } | |
349 | #ifndef BOOST_NO_EXCEPTIONS | |
350 | }catch(...) | |
351 | { close(); throw; } | |
352 | #endif | |
353 | } | |
354 | ||
355 | void mapfile::close() | |
356 | { | |
357 | if(hfile != 0) | |
358 | { | |
359 | pointer* p = _first; | |
360 | while(p != _last) | |
361 | { | |
362 | if(*p) | |
363 | delete[] *p; | |
364 | ++p; | |
365 | } | |
366 | delete[] _first; | |
367 | _size = 0; | |
368 | _first = _last = 0; | |
369 | std::fclose(hfile); | |
370 | hfile = 0; | |
371 | condemed.erase(condemed.begin(), condemed.end()); | |
372 | } | |
373 | } | |
374 | ||
375 | ||
376 | #endif | |
377 | ||
378 | inline _fi_find_handle find_first_file(const char* wild, _fi_find_data& data) | |
379 | { | |
380 | #ifdef BOOST_NO_ANSI_APIS | |
381 | std::size_t wild_size = std::strlen(wild); | |
382 | LPWSTR wide_wild = (LPWSTR)_alloca( (wild_size + 1) * sizeof(WCHAR) ); | |
383 | if (::MultiByteToWideChar(CP_ACP, 0, wild, wild_size, wide_wild, wild_size + 1) == 0) | |
384 | return _fi_invalid_handle; | |
385 | ||
386 | return FindFirstFileW(wide_wild, &data); | |
387 | #else | |
388 | return FindFirstFileA(wild, &data); | |
389 | #endif | |
390 | } | |
391 | ||
392 | inline bool find_next_file(_fi_find_handle hf, _fi_find_data& data) | |
393 | { | |
394 | #ifdef BOOST_NO_ANSI_APIS | |
395 | return FindNextFileW(hf, &data); | |
396 | #else | |
397 | return FindNextFileA(hf, &data); | |
398 | #endif | |
399 | } | |
400 | ||
401 | inline void copy_find_file_result_with_overflow_check(const _fi_find_data& data, char* path, size_t max_size) | |
402 | { | |
403 | #ifdef BOOST_NO_ANSI_APIS | |
404 | if (::WideCharToMultiByte(CP_ACP, 0, data.cFileName, -1, path, max_size, NULL, NULL) == 0) | |
405 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(1); | |
406 | #else | |
407 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(path, max_size, data.cFileName)); | |
408 | #endif | |
409 | } | |
410 | ||
411 | inline bool is_not_current_or_parent_path_string(const _fi_find_data& data) | |
412 | { | |
413 | #ifdef BOOST_NO_ANSI_APIS | |
414 | return (std::wcscmp(data.cFileName, L".") && std::wcscmp(data.cFileName, L"..")); | |
415 | #else | |
416 | return (std::strcmp(data.cFileName, ".") && std::strcmp(data.cFileName, "..")); | |
417 | #endif | |
418 | } | |
419 | ||
420 | ||
421 | file_iterator::file_iterator() | |
422 | { | |
423 | _root = _path = 0; | |
424 | ref = 0; | |
425 | #ifndef BOOST_NO_EXCEPTIONS | |
426 | try{ | |
427 | #endif | |
428 | _root = new char[MAX_PATH]; | |
429 | BOOST_REGEX_NOEH_ASSERT(_root) | |
430 | _path = new char[MAX_PATH]; | |
431 | BOOST_REGEX_NOEH_ASSERT(_path) | |
432 | ptr = _path; | |
433 | *_path = 0; | |
434 | *_root = 0; | |
435 | ref = new file_iterator_ref(); | |
436 | BOOST_REGEX_NOEH_ASSERT(ref) | |
437 | ref->hf = _fi_invalid_handle; | |
438 | ref->count = 1; | |
439 | #ifndef BOOST_NO_EXCEPTIONS | |
440 | } | |
441 | catch(...) | |
442 | { | |
443 | delete[] _root; | |
444 | delete[] _path; | |
445 | delete ref; | |
446 | throw; | |
447 | } | |
448 | #endif | |
449 | } | |
450 | ||
451 | file_iterator::file_iterator(const char* wild) | |
452 | { | |
453 | _root = _path = 0; | |
454 | ref = 0; | |
455 | #ifndef BOOST_NO_EXCEPTIONS | |
456 | try{ | |
457 | #endif | |
458 | _root = new char[MAX_PATH]; | |
459 | BOOST_REGEX_NOEH_ASSERT(_root) | |
460 | _path = new char[MAX_PATH]; | |
461 | BOOST_REGEX_NOEH_ASSERT(_path) | |
462 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, wild)); | |
463 | ptr = _root; | |
464 | while(*ptr)++ptr; | |
465 | while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr; | |
466 | if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) ) | |
467 | { | |
468 | _root[1]='\0'; | |
469 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); | |
470 | } | |
471 | else | |
472 | { | |
473 | *ptr = 0; | |
474 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); | |
475 | if(*_path == 0) | |
476 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, ".")); | |
477 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(_path, MAX_PATH, _fi_sep)); | |
478 | } | |
479 | ptr = _path + std::strlen(_path); | |
480 | ||
481 | ref = new file_iterator_ref(); | |
482 | BOOST_REGEX_NOEH_ASSERT(ref) | |
483 | ref->hf = find_first_file(wild, ref->_data); | |
484 | ref->count = 1; | |
485 | ||
486 | if(ref->hf == _fi_invalid_handle) | |
487 | { | |
488 | *_path = 0; | |
489 | ptr = _path; | |
490 | } | |
491 | else | |
492 | { | |
493 | copy_find_file_result_with_overflow_check(ref->_data, ptr, (MAX_PATH - (ptr - _path))); | |
494 | if(ref->_data.dwFileAttributes & _fi_dir) | |
495 | next(); | |
496 | } | |
497 | #ifndef BOOST_NO_EXCEPTIONS | |
498 | } | |
499 | catch(...) | |
500 | { | |
501 | delete[] _root; | |
502 | delete[] _path; | |
503 | delete ref; | |
504 | throw; | |
505 | } | |
506 | #endif | |
507 | } | |
508 | ||
509 | file_iterator::file_iterator(const file_iterator& other) | |
510 | { | |
511 | _root = _path = 0; | |
512 | ref = 0; | |
513 | #ifndef BOOST_NO_EXCEPTIONS | |
514 | try{ | |
515 | #endif | |
516 | _root = new char[MAX_PATH]; | |
517 | BOOST_REGEX_NOEH_ASSERT(_root) | |
518 | _path = new char[MAX_PATH]; | |
519 | BOOST_REGEX_NOEH_ASSERT(_path) | |
520 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); | |
521 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); | |
522 | ptr = _path + (other.ptr - other._path); | |
523 | ref = other.ref; | |
524 | #ifndef BOOST_NO_EXCEPTIONS | |
525 | } | |
526 | catch(...) | |
527 | { | |
528 | delete[] _root; | |
529 | delete[] _path; | |
530 | throw; | |
531 | } | |
532 | #endif | |
533 | ++(ref->count); | |
534 | } | |
535 | ||
536 | file_iterator& file_iterator::operator=(const file_iterator& other) | |
537 | { | |
538 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); | |
539 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); | |
540 | ptr = _path + (other.ptr - other._path); | |
541 | if(--(ref->count) == 0) | |
542 | { | |
543 | if(ref->hf != _fi_invalid_handle) | |
544 | FindClose(ref->hf); | |
545 | delete ref; | |
546 | } | |
547 | ref = other.ref; | |
548 | ++(ref->count); | |
549 | return *this; | |
550 | } | |
551 | ||
552 | ||
553 | file_iterator::~file_iterator() | |
554 | { | |
555 | delete[] _root; | |
556 | delete[] _path; | |
557 | if(--(ref->count) == 0) | |
558 | { | |
559 | if(ref->hf != _fi_invalid_handle) | |
560 | FindClose(ref->hf); | |
561 | delete ref; | |
562 | } | |
563 | } | |
564 | ||
565 | file_iterator file_iterator::operator++(int) | |
566 | { | |
567 | file_iterator temp(*this); | |
568 | next(); | |
569 | return temp; | |
570 | } | |
571 | ||
572 | ||
573 | void file_iterator::next() | |
574 | { | |
575 | if(ref->hf != _fi_invalid_handle) | |
576 | { | |
577 | bool cont = true; | |
578 | while(cont) | |
579 | { | |
580 | cont = find_next_file(ref->hf, ref->_data); | |
581 | if(cont && ((ref->_data.dwFileAttributes & _fi_dir) == 0)) | |
582 | break; | |
583 | } | |
584 | if(!cont) | |
585 | { | |
586 | // end of sequence | |
587 | FindClose(ref->hf); | |
588 | ref->hf = _fi_invalid_handle; | |
589 | *_path = 0; | |
590 | ptr = _path; | |
591 | } | |
592 | else | |
593 | copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); | |
594 | } | |
595 | } | |
596 | ||
597 | ||
598 | ||
599 | directory_iterator::directory_iterator() | |
600 | { | |
601 | _root = _path = 0; | |
602 | ref = 0; | |
603 | #ifndef BOOST_NO_EXCEPTIONS | |
604 | try{ | |
605 | #endif | |
606 | _root = new char[MAX_PATH]; | |
607 | BOOST_REGEX_NOEH_ASSERT(_root) | |
608 | _path = new char[MAX_PATH]; | |
609 | BOOST_REGEX_NOEH_ASSERT(_path) | |
610 | ptr = _path; | |
611 | *_path = 0; | |
612 | *_root = 0; | |
613 | ref = new file_iterator_ref(); | |
614 | BOOST_REGEX_NOEH_ASSERT(ref) | |
615 | ref->hf = _fi_invalid_handle; | |
616 | ref->count = 1; | |
617 | #ifndef BOOST_NO_EXCEPTIONS | |
618 | } | |
619 | catch(...) | |
620 | { | |
621 | delete[] _root; | |
622 | delete[] _path; | |
623 | delete ref; | |
624 | throw; | |
625 | } | |
626 | #endif | |
627 | } | |
628 | ||
629 | directory_iterator::directory_iterator(const char* wild) | |
630 | { | |
631 | _root = _path = 0; | |
632 | ref = 0; | |
633 | #ifndef BOOST_NO_EXCEPTIONS | |
634 | try{ | |
635 | #endif | |
636 | _root = new char[MAX_PATH]; | |
637 | BOOST_REGEX_NOEH_ASSERT(_root) | |
638 | _path = new char[MAX_PATH]; | |
639 | BOOST_REGEX_NOEH_ASSERT(_path) | |
640 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, wild)); | |
641 | ptr = _root; | |
642 | while(*ptr)++ptr; | |
643 | while((ptr > _root) && (*ptr != *_fi_sep) && (*ptr != *_fi_sep_alt))--ptr; | |
644 | ||
645 | if((ptr == _root) && ( (*ptr== *_fi_sep) || (*ptr==*_fi_sep_alt) ) ) | |
646 | { | |
647 | _root[1]='\0'; | |
648 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); | |
649 | } | |
650 | else | |
651 | { | |
652 | *ptr = 0; | |
653 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, _root)); | |
654 | if(*_path == 0) | |
655 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, ".")); | |
656 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcat_s(_path, MAX_PATH, _fi_sep)); | |
657 | } | |
658 | ptr = _path + std::strlen(_path); | |
659 | ||
660 | ref = new file_iterator_ref(); | |
661 | BOOST_REGEX_NOEH_ASSERT(ref) | |
662 | ref->count = 1; | |
663 | ref->hf = find_first_file(wild, ref->_data); | |
664 | if(ref->hf == _fi_invalid_handle) | |
665 | { | |
666 | *_path = 0; | |
667 | ptr = _path; | |
668 | } | |
669 | else | |
670 | { | |
671 | copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); | |
672 | if(((ref->_data.dwFileAttributes & _fi_dir) == 0) || (std::strcmp(ptr, ".") == 0) || (std::strcmp(ptr, "..") == 0)) | |
673 | next(); | |
674 | } | |
675 | #ifndef BOOST_NO_EXCEPTIONS | |
676 | } | |
677 | catch(...) | |
678 | { | |
679 | delete[] _root; | |
680 | delete[] _path; | |
681 | delete ref; | |
682 | throw; | |
683 | } | |
684 | #endif | |
685 | } | |
686 | ||
687 | directory_iterator::~directory_iterator() | |
688 | { | |
689 | delete[] _root; | |
690 | delete[] _path; | |
691 | if(--(ref->count) == 0) | |
692 | { | |
693 | if(ref->hf != _fi_invalid_handle) | |
694 | FindClose(ref->hf); | |
695 | delete ref; | |
696 | } | |
697 | } | |
698 | ||
699 | directory_iterator::directory_iterator(const directory_iterator& other) | |
700 | { | |
701 | _root = _path = 0; | |
702 | ref = 0; | |
703 | #ifndef BOOST_NO_EXCEPTIONS | |
704 | try{ | |
705 | #endif | |
706 | _root = new char[MAX_PATH]; | |
707 | BOOST_REGEX_NOEH_ASSERT(_root) | |
708 | _path = new char[MAX_PATH]; | |
709 | BOOST_REGEX_NOEH_ASSERT(_path) | |
710 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); | |
711 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); | |
712 | ptr = _path + (other.ptr - other._path); | |
713 | ref = other.ref; | |
714 | #ifndef BOOST_NO_EXCEPTIONS | |
715 | } | |
716 | catch(...) | |
717 | { | |
718 | delete[] _root; | |
719 | delete[] _path; | |
720 | throw; | |
721 | } | |
722 | #endif | |
723 | ++(ref->count); | |
724 | } | |
725 | ||
726 | directory_iterator& directory_iterator::operator=(const directory_iterator& other) | |
727 | { | |
728 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_root, MAX_PATH, other._root)); | |
729 | BOOST_REGEX_DETAIL_NS::overflow_error_if_not_zero(BOOST_REGEX_DETAIL_NS::strcpy_s(_path, MAX_PATH, other._path)); | |
730 | ptr = _path + (other.ptr - other._path); | |
731 | if(--(ref->count) == 0) | |
732 | { | |
733 | if(ref->hf != _fi_invalid_handle) | |
734 | FindClose(ref->hf); | |
735 | delete ref; | |
736 | } | |
737 | ref = other.ref; | |
738 | ++(ref->count); | |
739 | return *this; | |
740 | } | |
741 | ||
742 | directory_iterator directory_iterator::operator++(int) | |
743 | { | |
744 | directory_iterator temp(*this); | |
745 | next(); | |
746 | return temp; | |
747 | } | |
748 | ||
749 | void directory_iterator::next() | |
750 | { | |
751 | if(ref->hf != _fi_invalid_handle) | |
752 | { | |
753 | bool cont = true; | |
754 | while(cont) | |
755 | { | |
756 | cont = find_next_file(ref->hf, ref->_data); | |
757 | if(cont && (ref->_data.dwFileAttributes & _fi_dir)) | |
758 | { | |
759 | if(is_not_current_or_parent_path_string(ref->_data)) | |
760 | break; | |
761 | } | |
762 | } | |
763 | if(!cont) | |
764 | { | |
765 | // end of sequence | |
766 | FindClose(ref->hf); | |
767 | ref->hf = _fi_invalid_handle; | |
768 | *_path = 0; | |
769 | ptr = _path; | |
770 | } | |
771 | else | |
772 | copy_find_file_result_with_overflow_check(ref->_data, ptr, MAX_PATH - (ptr - _path)); | |
773 | } | |
774 | } | |
775 | ||
776 | ||
777 | #ifdef BOOST_REGEX_FI_POSIX_DIR | |
778 | ||
779 | struct _fi_priv_data | |
780 | { | |
781 | char root[MAX_PATH]; | |
782 | char* mask; | |
783 | DIR* d; | |
784 | _fi_priv_data(const char* p); | |
785 | }; | |
786 | ||
787 | _fi_priv_data::_fi_priv_data(const char* p) | |
788 | { | |
789 | std::strcpy(root, p); | |
790 | mask = root; | |
791 | while(*mask) ++mask; | |
792 | while((mask > root) && (*mask != *_fi_sep) && (*mask != *_fi_sep_alt)) --mask; | |
793 | if(mask == root && ((*mask== *_fi_sep) || (*mask == *_fi_sep_alt)) ) | |
794 | { | |
795 | root[1] = '\0'; | |
796 | std::strcpy(root+2, p+1); | |
797 | mask = root+2; | |
798 | } | |
799 | else if(mask == root) | |
800 | { | |
801 | root[0] = '.'; | |
802 | root[1] = '\0'; | |
803 | std::strcpy(root+2, p); | |
804 | mask = root+2; | |
805 | } | |
806 | else | |
807 | { | |
808 | *mask = 0; | |
809 | ++mask; | |
810 | } | |
811 | } | |
812 | ||
813 | bool iswild(const char* mask, const char* name) | |
814 | { | |
815 | while(*mask && *name) | |
816 | { | |
817 | switch(*mask) | |
818 | { | |
819 | case '?': | |
820 | ++name; | |
821 | ++mask; | |
822 | continue; | |
823 | case '*': | |
824 | ++mask; | |
825 | if(*mask == 0) | |
826 | return true; | |
827 | while(*name) | |
828 | { | |
829 | if(iswild(mask, name)) | |
830 | return true; | |
831 | ++name; | |
832 | } | |
833 | return false; | |
834 | case '.': | |
835 | if(0 == *name) | |
836 | { | |
837 | ++mask; | |
838 | continue; | |
839 | } | |
92f5a8d4 | 840 | // fall through |
7c673cae FG |
841 | default: |
842 | if(BOOST_REGEX_FI_TRANSLATE(*mask) != BOOST_REGEX_FI_TRANSLATE(*name)) | |
843 | return false; | |
844 | ++mask; | |
845 | ++name; | |
846 | continue; | |
847 | } | |
848 | } | |
849 | if(*mask != *name) | |
850 | return false; | |
851 | return true; | |
852 | } | |
853 | ||
854 | unsigned _fi_attributes(const char* root, const char* name) | |
855 | { | |
856 | char buf[MAX_PATH]; | |
857 | // verify that we can not overflow: | |
858 | if(std::strlen(root) + std::strlen(_fi_sep) + std::strlen(name) >= MAX_PATH) | |
859 | return 0; | |
860 | int r; | |
861 | if( ( (root[0] == *_fi_sep) || (root[0] == *_fi_sep_alt) ) && (root[1] == '\0') ) | |
862 | r = (std::sprintf)(buf, "%s%s", root, name); | |
863 | else | |
864 | r = (std::sprintf)(buf, "%s%s%s", root, _fi_sep, name); | |
865 | if(r < 0) | |
866 | return 0; // sprintf failed | |
867 | DIR* d = opendir(buf); | |
868 | if(d) | |
869 | { | |
870 | closedir(d); | |
871 | return _fi_dir; | |
872 | } | |
873 | return 0; | |
874 | } | |
875 | ||
876 | _fi_find_handle _fi_FindFirstFile(const char* lpFileName, _fi_find_data* lpFindFileData) | |
877 | { | |
878 | _fi_find_handle dat = new _fi_priv_data(lpFileName); | |
879 | ||
880 | DIR* h = opendir(dat->root); | |
881 | dat->d = h; | |
882 | if(h != 0) | |
883 | { | |
884 | if(_fi_FindNextFile(dat, lpFindFileData)) | |
885 | return dat; | |
886 | closedir(h); | |
887 | } | |
888 | delete dat; | |
889 | return 0; | |
890 | } | |
891 | ||
892 | bool _fi_FindNextFile(_fi_find_handle dat, _fi_find_data* lpFindFileData) | |
893 | { | |
894 | dirent* d; | |
895 | do | |
896 | { | |
897 | d = readdir(dat->d); | |
898 | } while(d && !iswild(dat->mask, d->d_name)); | |
899 | ||
900 | if(d) | |
901 | { | |
902 | std::strcpy(lpFindFileData->cFileName, d->d_name); | |
903 | lpFindFileData->dwFileAttributes = _fi_attributes(dat->root, d->d_name); | |
904 | return true; | |
905 | } | |
906 | return false; | |
907 | } | |
908 | ||
909 | bool _fi_FindClose(_fi_find_handle dat) | |
910 | { | |
911 | closedir(dat->d); | |
912 | delete dat; | |
913 | return true; | |
914 | } | |
915 | ||
916 | #endif | |
917 | ||
918 | } // namespace BOOST_REGEX_DETAIL_NS | |
919 | } // namspace boost | |
920 | ||
921 | #endif // BOOST_REGEX_NO_FILEITER | |
922 | ||
923 | ||
924 | ||
925 | ||
926 | ||
927 | ||
928 | ||
929 | ||
930 | ||
931 | ||
932 | ||
933 |