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