Merge lp:~zorba-coders/zorba/bug-986580 into lp:zorba

Proposed by Paul J. Lucas
Status: Merged
Approved by: Rodolfo Ochoa
Approved revision: 10794
Merged at revision: 10801
Proposed branch: lp:~zorba-coders/zorba/bug-986580
Merge into: lp:zorba
Diff against target: 1326 lines (+298/-764)
16 files modified
CMakeLists.txt (+7/-0)
NOTICE.txt (+0/-18)
NOTICE.xml (+0/-16)
src/api/fileimpl.cpp (+6/-17)
src/api/fileimpl.h (+3/-4)
src/unit_tests/CMakeLists.txt (+1/-0)
src/unit_tests/test_fs_iterator.cpp (+54/-0)
src/unit_tests/unit_test_list.h (+1/-0)
src/unit_tests/unit_tests.cpp (+1/-0)
src/util/CMakeLists.txt (+0/-1)
src/util/dir.cpp (+0/-175)
src/util/dir.h (+0/-100)
src/util/file.cpp (+3/-1)
src/util/fs_util.cpp (+129/-31)
src/util/fs_util.h (+93/-29)
src/util/win32/dirent.h (+0/-372)
To merge this branch: bzr merge lp:~zorba-coders/zorba/bug-986580
Reviewer Review Type Date Requested Status
Rodolfo Ochoa Approve
Cezar Andrei Approve
Review via email: mp+103552@code.launchpad.net

This proposal supersedes a proposal from 2012-04-25.

Commit message

Better implementation of listing files in a directory.

Description of the change

Better implementation of listing files in a directory.

To post a comment you must log in.
Revision history for this message
Rodolfo Ochoa (rodolfo-ochoa) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Cezar Andrei (cezar-andrei) wrote : Posted in a previous version of this proposal

Looks good, please do remove the dirent.h copyright/license from NOTICE.txt/xml files since you removed dirent.h.

review: Needs Fixing
Revision history for this message
Cezar Andrei (cezar-andrei) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Rodolfo Ochoa (rodolfo-ochoa) : Posted in a previous version of this proposal
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote : Posted in a previous version of this proposal
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote : Posted in a previous version of this proposal

The attempt to merge lp:~zorba-coders/zorba/bug-986580 into lp:zorba failed. Below is the output from the failed tests.

CMake Error at /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake:274 (message):
  Validation queue job bug-986580-2012-04-25T18-26-18.651Z is finished. The
  final status was:

  No tests were run - build or configure step must have failed.

  Not commiting changes.

Error in read script: /home/ceej/zo/testing/zorbatest/tester/TarmacLander.cmake

Revision history for this message
Paul J. Lucas (paul-lucas) wrote :

I didn't realize that the util-jvm module used file::lsdir(), so I put that function back. However, I think that API ought to change as well, but that can be done separately.

Revision history for this message
Cezar Andrei (cezar-andrei) :
review: Approve
Revision history for this message
Rodolfo Ochoa (rodolfo-ochoa) :
review: Approve
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :
Revision history for this message
Zorba Build Bot (zorba-buildbot) wrote :

Validation queue job bug-986580-2012-04-25T20-43-03.061Z is finished. The final status was:

All tests succeeded!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2012-04-24 12:39:38 +0000
3+++ CMakeLists.txt 2012-04-25 19:52:28 +0000
4@@ -309,6 +309,13 @@
5 MESSAGE (STATUS "")
6
7 #
8+# shlwapi
9+#
10+IF(WIN32)
11+ SET(requiredlibs ${requiredlibs} "shlwapi")
12+ENDIF(WIN32)
13+
14+#
15 # SWIG
16 #
17 IF (NOT ZORBA_SUPPRESS_SWIG)
18
19=== modified file 'NOTICE.txt'
20--- NOTICE.txt 2012-04-18 15:34:39 +0000
21+++ NOTICE.txt 2012-04-25 19:52:28 +0000
22@@ -459,24 +459,6 @@
23 suitability of this software for any purpose. It is provided "as is"
24 without express or implied warranty.
25
26-----------------------------------------------------
27-
28-src/util/win32/dirent.h
29-
30-Copyright: 2006 Toni Ronkko
31-
32-
33- Permission is hereby granted, free of charge, to any person obtaining
34- a copy of this software and associated documentation files (the
35- ``Software''), to deal in the Software without restriction, including
36- without limitation the rights to use, copy, modify, merge, publish,
37- distribute, sublicense, and/or sell copies of the Software, and to
38- permit persons to whom the Software is furnished to do so, subject to
39- the following conditions:
40-
41- The above copyright notice and this permission notice shall be included
42- in all copies or substantial portions of the Software.
43-
44
45 External libraries used by this project:
46 ----------------------------------------------------
47
48=== modified file 'NOTICE.xml'
49--- NOTICE.xml 2012-04-24 12:39:38 +0000
50+++ NOTICE.xml 2012-04-25 19:52:28 +0000
51@@ -423,22 +423,6 @@
52 without express or implied warranty.
53 </foreign-notice>
54 </foreign-files>
55- <foreign-files>
56- <file>src/util/win32/dirent.h</file>
57- <copyright>2006 Toni Ronkko</copyright>
58- <foreign-notice>
59- Permission is hereby granted, free of charge, to any person obtaining
60- a copy of this software and associated documentation files (the
61- ``Software''), to deal in the Software without restriction, including
62- without limitation the rights to use, copy, modify, merge, publish,
63- distribute, sublicense, and/or sell copies of the Software, and to
64- permit persons to whom the Software is furnished to do so, subject to
65- the following conditions:
66-
67- The above copyright notice and this permission notice shall be included
68- in all copies or substantial portions of the Software.
69- </foreign-notice>
70- </foreign-files>
71
72 <external-lib mandatory="true">
73 <name>LIBXML2</name>
74
75=== modified file 'src/api/fileimpl.cpp'
76--- src/api/fileimpl.cpp 2012-04-24 12:39:38 +0000
77+++ src/api/fileimpl.cpp 2012-04-25 19:52:28 +0000
78@@ -29,44 +29,33 @@
79 #ifdef WIN32
80 #include <util/ascii_util.h>
81 #endif
82-#include <util/dir.h>
83
84 #include "util/uri_util.h"
85 #include "zorbaimpl.h"
86
87 namespace zorba {
88
89-DirectoryIteratorImpl::DirectoryIteratorImpl(std::string const& aPath)
90-{
91- theInternalDirIter = new dir_iterator(aPath);
92-}
93-
94-DirectoryIteratorImpl::~DirectoryIteratorImpl()
95-{
96- delete theInternalDirIter;
97+DirectoryIteratorImpl::DirectoryIteratorImpl(std::string const& aPath) :
98+ theInternalDirIter( aPath.c_str() )
99+{
100 }
101
102 bool
103 DirectoryIteratorImpl::next(std::string& aPathStr) const
104 {
105- if (theInternalDirIter->end()) {
106+ if (!theInternalDirIter.next()) {
107 return false;
108 }
109
110 // get the current pointed entry
111- aPathStr = *(*theInternalDirIter);
112-
113- // advance to the next entry
114- ++(*theInternalDirIter);
115+ aPathStr = theInternalDirIter.entry_name();
116
117 return true;
118 }
119
120 void DirectoryIteratorImpl::reset()
121 {
122- std::string aPath = theInternalDirIter->dirpath;
123- delete theInternalDirIter;
124- theInternalDirIter = new dir_iterator(aPath);
125+ theInternalDirIter.reset();
126 }
127
128 FileImpl::FileImpl(std::string const& path)
129
130=== modified file 'src/api/fileimpl.h'
131--- src/api/fileimpl.h 2012-04-24 12:39:38 +0000
132+++ src/api/fileimpl.h 2012-04-25 19:52:28 +0000
133@@ -20,10 +20,11 @@
134 #include <iostream>
135 #include <zorba/file.h>
136
137+#include "util/fs_util.h"
138+
139 namespace zorba {
140
141 class file;
142- class dir_iterator;
143 class DiagnosticHandler;
144
145
146@@ -31,14 +32,12 @@
147 {
148 private:
149
150- dir_iterator* theInternalDirIter;
151+ mutable fs::iterator theInternalDirIter;
152
153 public:
154
155 DirectoryIteratorImpl(std::string const& aPath);
156
157- ~DirectoryIteratorImpl();
158-
159 bool next(std::string& aPathStr) const;
160 void reset();
161 };
162
163=== modified file 'src/unit_tests/CMakeLists.txt'
164--- src/unit_tests/CMakeLists.txt 2012-04-24 12:39:38 +0000
165+++ src/unit_tests/CMakeLists.txt 2012-04-25 19:52:28 +0000
166@@ -20,6 +20,7 @@
167 unit_tests.cpp
168 test_uri.cpp
169 json_parser.cpp
170+ test_fs_iterator.cpp
171 )
172
173 IF (NOT ZORBA_NO_FULL_TEXT)
174
175=== added file 'src/unit_tests/test_fs_iterator.cpp'
176--- src/unit_tests/test_fs_iterator.cpp 1970-01-01 00:00:00 +0000
177+++ src/unit_tests/test_fs_iterator.cpp 2012-04-25 19:52:28 +0000
178@@ -0,0 +1,54 @@
179+/*
180+ * Copyright 2006-2010 The FLWOR Foundation.
181+ *
182+ * Licensed under the Apache License, Version 2.0 (the "License");
183+ * you may not use this file except in compliance with the License.
184+ * You may obtain a copy of the License at
185+ *
186+ * http://www.apache.org/licenses/LICENSE-2.0
187+ *
188+ * Unless required by applicable law or agreed to in writing, software
189+ * distributed under the License is distributed on an "AS IS" BASIS,
190+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
191+ * See the License for the specific language governing permissions and
192+ * limitations under the License.
193+ */
194+
195+#include "stdafx.h"
196+
197+#include <iostream>
198+#include <zorba/zorba_exception.h>
199+
200+#include "util/fs_util.h"
201+
202+using namespace std;
203+using namespace zorba;
204+
205+///////////////////////////////////////////////////////////////////////////////
206+
207+namespace zorba {
208+namespace UnitTests {
209+
210+int test_fs_iterator( int argc, char *argv[] ) {
211+ int result = 0;
212+ try {
213+#ifndef WIN32
214+ fs::iterator dir_iter( "/" );
215+#else
216+ fs::iterator dir_iter( "C:\\" );
217+#endif /* WIN32 */
218+ while ( dir_iter.next() )
219+ cout << dir_iter.entry_name() << " (" << dir_iter.entry_type() << ')' << endl;
220+ }
221+ catch ( ZorbaException const &e ) {
222+ cerr << e << endl;
223+ result = 2;
224+ }
225+
226+ return result;
227+}
228+
229+} // namespace UnitTests
230+} // namespace zorba
231+
232+/* vim:set et sw=2 ts=2: */
233
234=== modified file 'src/unit_tests/unit_test_list.h'
235--- src/unit_tests/unit_test_list.h 2012-04-24 12:39:38 +0000
236+++ src/unit_tests/unit_test_list.h 2012-04-25 19:52:28 +0000
237@@ -28,6 +28,7 @@
238 int runDebuggerProtocolTest(int argc, char* argv[]);
239 int test_string( int, char*[] );
240 int test_unique_ptr( int, char*[] );
241+ int test_fs_iterator( int, char*[] );
242 #ifndef ZORBA_NO_FULL_TEXT
243 int test_stemmer( int, char*[] );
244 int test_thesaurus( int, char*[] );
245
246=== modified file 'src/unit_tests/unit_tests.cpp'
247--- src/unit_tests/unit_tests.cpp 2012-04-24 12:39:38 +0000
248+++ src/unit_tests/unit_tests.cpp 2012-04-25 19:52:28 +0000
249@@ -39,6 +39,7 @@
250 void initializeTestList() {
251 libunittests["string"] = test_string;
252 libunittests["uri"] = runUriTest;
253+ libunittests["fs_iterator"] = test_fs_iterator;
254 #ifndef ZORBA_NO_ICU
255 libunittests["icu_streambuf"] = test_icu_streambuf;
256 #endif /* ZORBA_NO_ICU */
257
258=== modified file 'src/util/CMakeLists.txt'
259--- src/util/CMakeLists.txt 2012-04-24 12:39:38 +0000
260+++ src/util/CMakeLists.txt 2012-04-25 19:52:28 +0000
261@@ -17,7 +17,6 @@
262 dynamic_bitset.cpp
263 error_util.cpp
264 file.cpp
265- dir.cpp
266 fs_util.cpp
267 indent.cpp
268 json_parser.cpp
269
270=== removed file 'src/util/dir.cpp'
271--- src/util/dir.cpp 2012-04-24 12:39:38 +0000
272+++ src/util/dir.cpp 1970-01-01 00:00:00 +0000
273@@ -1,175 +0,0 @@
274-/*
275- * Copyright 2006-2008 The FLWOR Foundation.
276- *
277- * Licensed under the Apache License, Version 2.0 (the "License");
278- * you may not use this file except in compliance with the License.
279- * You may obtain a copy of the License at
280- *
281- * http://www.apache.org/licenses/LICENSE-2.0
282- *
283- * Unless required by applicable law or agreed to in writing, software
284- * distributed under the License is distributed on an "AS IS" BASIS,
285- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
286- * See the License for the specific language governing permissions and
287- * limitations under the License.
288- */
289-#include "stdafx.h"
290-
291-#include "util/dir.h"
292-
293-#ifndef _WIN32_WCE
294-#include <errno.h>
295-#include <sys/stat.h>
296-#include <sys/types.h>
297-#else
298-#include <types.h>
299-#endif
300-#include <stdio.h>
301-
302-#if defined (WIN32)
303-#include <tchar.h>
304-#ifndef _WIN32_WCE
305-#include <io.h>
306-#include <direct.h>
307-#endif
308-#else
309-#include <sys/param.h>
310-#include <unistd.h>
311-#endif
312-
313-#ifndef _WIN32_WCE
314-#include <fcntl.h>
315-#endif
316-#include <sstream>
317-
318-#include "diagnostics/xquery_diagnostics.h"
319-
320-using namespace std;
321-
322-namespace zorba {
323-
324-// dir_iterator
325-
326-#define END true
327-
328-dir_iterator
329-directory::begin()
330-{
331- return dir_iterator(getPathString());
332-}
333-
334-dir_iterator
335-directory::end()
336-{
337- return dir_iterator(getPathString(), END);
338-}
339-
340-dir_iterator::dir_iterator(
341- string const& path,
342- bool end_iterator)
343-:
344- dirpath(path)
345-#ifndef WIN32
346- ,dirent(0)
347-#endif
348-{
349-#ifndef WIN32
350- dir = opendir(path.c_str());
351- if (dir==0) {
352- throw ZORBA_IO_EXCEPTION( "opendir()", path );
353- }
354- if (!end_iterator) operator++();
355-#else
356- if(!end_iterator) {
357- std::string path_star = path + "\\*.*";
358- WCHAR wpath_str[1024];
359- wpath_str[0] = 0;
360- if(MultiByteToWideChar(CP_UTF8,
361- 0, path_star.c_str(), -1,
362- wpath_str, sizeof(wpath_str)/sizeof(WCHAR)) == 0)
363- {//probably there is some invalid utf8 char, try the Windows ACP
364- MultiByteToWideChar(CP_ACP,
365- 0, path_star.c_str(), -1,
366- wpath_str, sizeof(wpath_str)/sizeof(WCHAR));
367- }
368- win32_dir = FindFirstFileW(wpath_str, &win32_direntry);
369- if(win32_dir == INVALID_HANDLE_VALUE) {
370- throw ZORBA_IO_EXCEPTION( "FindFirstFile()", path );
371- }
372- if (wcscmp(win32_direntry.cFileName, L".") == 0 ||
373- wcscmp(win32_direntry.cFileName, L"..") == 0) {
374- operator ++();
375- }
376- } else {
377- win32_dir = INVALID_HANDLE_VALUE;
378- wcscpy(win32_direntry.cFileName, L"");
379- }
380-#endif
381-
382-}
383-
384-dir_iterator::~dir_iterator()
385-{
386-#if ! defined (WIN32)
387- if (dir!=0) closedir(dir);
388-#else
389- if(win32_dir != INVALID_HANDLE_VALUE) {
390- FindClose(win32_dir);
391- }
392-#endif
393-}
394-
395-
396-void
397-dir_iterator::operator++()
398-{
399-#ifndef WIN32
400- if (dir!=0) {
401- while (true) {
402- dirent = readdir(dir);
403- if (dirent==0) {
404- closedir(dir);
405- dir = 0;
406- break;
407- }
408- if (strcmp(dirent->d_name,".") &&
409- strcmp(dirent->d_name,"..")) {
410- break;
411- }
412- }
413- }
414-#else
415- if(win32_dir != INVALID_HANDLE_VALUE) {
416- while(true) {
417- if(!FindNextFileW(win32_dir, &win32_direntry)) {
418- FindClose(win32_dir);
419- win32_dir = INVALID_HANDLE_VALUE;
420- wcscpy(win32_direntry.cFileName, L"");
421- break;
422- }
423- if (wcscmp(win32_direntry.cFileName, L".") &&
424- wcscmp(win32_direntry.cFileName, L"..")) {
425- break;
426- }
427- }
428- }
429-#endif
430-}
431-
432-bool operator!=(
433- dir_iterator const& x,
434- dir_iterator const& y)
435-{
436-#ifndef WIN32
437- if (x.dirpath==y.dirpath) return false;
438- if (x.dirent==y.dirent) return false;
439- return true;
440-#else
441- if (x.dirpath==y.dirpath) return false;
442- if (!wcscmp(x.win32_direntry.cFileName, y.win32_direntry.cFileName)) return false;
443- return true;
444-#endif
445-}
446-
447-} // namespace
448-/* vim:set et sw=2 ts=2: */
449
450=== removed file 'src/util/dir.h'
451--- src/util/dir.h 2012-04-24 12:39:38 +0000
452+++ src/util/dir.h 1970-01-01 00:00:00 +0000
453@@ -1,100 +0,0 @@
454-/*
455- * Copyright 2006-2008 The FLWOR Foundation.
456- *
457- * Licensed under the Apache License, Version 2.0 (the "License");
458- * you may not use this file except in compliance with the License.
459- * You may obtain a copy of the License at
460- *
461- * http://www.apache.org/licenses/LICENSE-2.0
462- *
463- * Unless required by applicable law or agreed to in writing, software
464- * distributed under the License is distributed on an "AS IS" BASIS,
465- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
466- * See the License for the specific language governing permissions and
467- * limitations under the License.
468- */
469-#pragma once
470-#ifndef ZORBA_UTIL_DIR_H
471-#define ZORBA_UTIL_DIR_H
472-
473-#include "zorba/util/file.h"
474-#include "zorbatypes/rchandle.h"
475-
476-#ifdef UNIX
477-#include <dirent.h>
478-#endif
479-
480-namespace zorba {
481-
482- class dir_iterator : public SimpleRCObject
483- {
484-
485- public:
486-
487- std::string dirpath;
488- std::string path;
489-#ifndef WIN32
490- DIR *dir;
491- struct dirent *dirent;
492-#else
493- HANDLE win32_dir;
494- WIN32_FIND_DATAW win32_direntry;
495- mutable char temp_file_name[1024];
496-#endif
497-
498- public:
499-
500- dir_iterator(const std::string& path, bool end_iterator = false);
501- ~dir_iterator();
502-
503- public: // iterator interface
504-
505- void operator++();
506-
507- bool end() const {
508-#ifndef WIN32
509- return dir == 0;
510-#else
511- return win32_dir == INVALID_HANDLE_VALUE;
512-#endif
513- }
514-
515-#ifndef WIN32
516- const char* operator*() {
517- return dirent->d_name;
518- }
519-#else
520- const char* operator*() {
521- WideCharToMultiByte(CP_UTF8, 0, win32_direntry.cFileName, -1, temp_file_name, sizeof(temp_file_name), NULL, NULL);
522- return temp_file_name;
523- }
524-#endif
525-
526- public:
527-#ifndef WIN32
528- const char* get_name() const {
529- return dirent?dirent->d_name:0;
530- }
531-#else
532- const char* get_name() const {
533- if (win32_dir == INVALID_HANDLE_VALUE)
534- return NULL;
535- WideCharToMultiByte(CP_UTF8, 0, win32_direntry.cFileName, -1, temp_file_name, sizeof(temp_file_name), NULL, NULL);
536- return temp_file_name;
537- }
538-#endif
539- };
540-
541- class directory : public file {
542-
543- public:
544- dir_iterator begin();
545- dir_iterator end();
546-
547- friend bool operator!=(dir_iterator const& x, dir_iterator const& y);
548-
549- };
550-
551-}
552-#endif
553-/* vim:set et sw=2 ts=2: */
554
555=== modified file 'src/util/file.cpp'
556--- src/util/file.cpp 2012-04-24 12:39:38 +0000
557+++ src/util/file.cpp 2012-04-25 19:52:28 +0000
558@@ -280,7 +280,9 @@
559 void file::lsdir(std::vector<std::string> &list) {
560 #ifdef ZORBA_WITH_FILE_ACCESS
561 try {
562- fs::lsdir( c_str(), list );
563+ fs::iterator dir_iter( c_str() );
564+ while ( dir_iter.next() )
565+ list.push_back( dir_iter.entry_name() );
566 set_filetype( type_directory );
567 }
568 catch ( fs::exception const &e ) {
569
570=== modified file 'src/util/fs_util.cpp'
571--- src/util/fs_util.cpp 2012-04-24 12:39:38 +0000
572+++ src/util/fs_util.cpp 2012-04-25 19:52:28 +0000
573@@ -23,6 +23,8 @@
574 # include <sys/types.h>
575 # include <sys/stat.h>
576 # include <unistd.h> /* for chdir(2) */
577+#else
578+# include <shlwapi.h>
579 #endif /* WIN32 */
580
581 #include "diagnostics/xquery_diagnostics.h"
582@@ -38,6 +40,17 @@
583 namespace zorba {
584 namespace fs {
585
586+///////////////////////////////////////////////////////////////////////////////
587+
588+char const *const type_string[] = {
589+ "non_existant",
590+ "directory",
591+ "file",
592+ "link",
593+ "volume",
594+ "other"
595+};
596+
597 ////////// helper functions ///////////////////////////////////////////////////
598
599 inline void replace_foreign( zstring *path ) {
600@@ -56,16 +69,21 @@
601
602 #ifdef ZORBA_WITH_FILE_ACCESS
603
604+static type map_type( DWORD dwFileAttributes ) {
605+ if ( dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
606+ return directory;
607+ if ( dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
608+ return link;
609+ return file;
610+}
611+
612 static type get_type( LPCWSTR wpath, size_type *size = nullptr ) {
613 WIN32_FILE_ATTRIBUTE_DATA data;
614 if ( ::GetFileAttributesEx( wpath, GetFileExInfoStandard, (void*)&data ) ) {
615- if ( data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
616- return directory;
617- if ( data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT )
618- return link;
619- if ( size )
620+ type const t = map_type( data.dwFileAttributes );
621+ if ( t == file && size )
622 *size = ((size_type)data.nFileSizeHigh << 32) | data.nFileSizeLow;
623- return file;
624+ return t;
625 }
626 return non_existent;
627 }
628@@ -90,11 +108,13 @@
629 to_wchar( path, wpath );
630 WCHAR wfull_path[ MAX_PATH ];
631 DWORD const result = ::GetFullPathName(
632- wpath, sizeof( wpath ) / sizeof( wpath[0] ), wfull_path, NULL
633+ wpath, sizeof( wfull_path ) / sizeof( wfull_path[0] ), wfull_path, NULL
634 );
635 if ( !result )
636 throw ZORBA_IO_EXCEPTION( "GetFullPathName()", path );
637 to_char( wfull_path, abs_path );
638+#else
639+ ::strcpy( abs_path, path );
640 #endif /* WINCE */
641 }
642
643@@ -153,7 +173,7 @@
644 win32::to_char( wpath, path );
645 if ( !is_absolute( path ) ) {
646 // GetCurrentDirectory() sometimes misses drive letter.
647- filesystem_path fspath( path );
648+ filesystem_path fspath( path );
649 fspath.resolve_relative();
650 return fspath.get_path();
651 }
652@@ -277,29 +297,107 @@
653 #endif
654 }
655
656-void lsdir( char const *path, std::vector<std::string> &list )
657-{
658- DIR *dir;
659- struct dirent *ent;
660-
661- dir = opendir (path);
662- if (dir != NULL)
663- {
664- /* print all the files and directories within directory */
665- while ((ent = readdir (dir)) != NULL)
666- {
667- //printf ("%s\n", ent->d_name);
668- std::string item(ent->d_name);
669- list.push_back(item);
670- }
671- closedir (dir);
672- }
673- else
674- {
675- /* could not open directory */
676- throw fs::exception( "lsdir()", path );
677- }
678-}
679+iterator::iterator( char const *path ) : dir_path_( path ) {
680+ make_absolute( dir_path_ );
681+#ifndef WIN32
682+ if ( !(dir_ = ::opendir( dir_path_.c_str() )) )
683+ throw fs::exception( "iterator()", dir_path_.c_str() );
684+#else
685+ win32_opendir( dir_path_.c_str() );
686+#endif /* WIN32 */
687+}
688+
689+iterator::~iterator() {
690+#ifndef WIN32
691+ if ( ::closedir( dir_ ) != 0 )
692+ throw fs::exception( "closedir()", path() );
693+#else
694+ win32_closedir();
695+#endif /* WIN32 */
696+}
697+
698+bool iterator::next() {
699+ while ( true ) {
700+#ifndef WIN32
701+ if ( (ent_ = ::readdir( dir_ )) ) {
702+ switch ( ent_->d_type ) {
703+ case DT_DIR: {
704+ char const *const name = ent_->d_name;
705+ // skip "." and ".." entries
706+ if ( name[0] == '.' && (!name[1] || name[1] == '.' && !name[2]) )
707+ continue;
708+ ent_type_ = directory;
709+ break;
710+ }
711+ case DT_LNK:
712+ ent_type_ = link;
713+ break;
714+ case DT_REG:
715+ ent_type_ = file;
716+ break;
717+ default:
718+ ent_type_ = other;
719+ }
720+ return true;
721+ }
722+#else
723+ if ( !dir_is_empty_ ) {
724+ if ( use_first_ )
725+ use_first_ = false;
726+ else
727+ if ( !::FindNextFile( dir_, &ent_data_ ) ) {
728+ if ( ::GetLastError() != ERROR_NO_MORE_FILES )
729+ throw fs::exception( "FindNextFile()", path() );
730+ return false;
731+ }
732+
733+ LPCWSTR const wname = ent_data_.cFileName;
734+ // skip "." and ".." entries
735+ if ( wname[0] == TEXT('.') &&
736+ (!wname[1] || wname[1] == TEXT('.') && !wname[2]) )
737+ continue;
738+
739+ win32::to_char( wname, ent_name_ );
740+ ent_type_ = win32::map_type( ent_data_.dwFileAttributes );
741+ return true;
742+ }
743+#endif /* WIN32 */
744+ return false;
745+ } // while
746+}
747+
748+void iterator::reset() {
749+#ifndef WIN32
750+ ::rewinddir( dir_ );
751+#else
752+ win32_closedir();
753+ win32_opendir( dir_path_.c_str() );
754+#endif /* WIN32 */
755+}
756+
757+#ifdef WIN32
758+void iterator::win32_closedir() {
759+ if ( dir_ != INVALID_HANDLE_VALUE && !::FindClose( dir_ ) )
760+ throw fs::exception( "FindClose()", path() );
761+}
762+
763+void iterator::win32_opendir( char const *path ) {
764+ WCHAR wpath[ MAX_PATH ];
765+ win32::to_wchar( path, wpath );
766+ WCHAR wpattern[ MAX_PATH ];
767+ ::wcscpy( wpattern, wpath );
768+ ::PathAppend( wpattern, TEXT("*") );
769+ dir_ = ::FindFirstFile( wpattern, &ent_data_ );
770+ if ( dir_ == INVALID_HANDLE_VALUE ) {
771+ if ( ::GetLastError() != ERROR_FILE_NOT_FOUND )
772+ throw fs::exception( "FindFirstFile()", path );
773+ dir_is_empty_ = true;
774+ } else {
775+ dir_is_empty_ = false;
776+ use_first_ = true;
777+ }
778+}
779+#endif /* WIN32 */
780
781 bool remove( char const *path ) {
782 #ifndef WIN32
783
784=== modified file 'src/util/fs_util.h'
785--- src/util/fs_util.h 2012-04-24 12:39:38 +0000
786+++ src/util/fs_util.h 2012-04-25 19:52:28 +0000
787@@ -17,20 +17,14 @@
788 #ifndef ZORBA_FS_UTIL_H
789 #define ZORBA_FS_UTIL_H
790
791-#include <vector>
792-
793-#ifdef WIN32
794-# include "win32/dirent.h"
795-#else
796-# include <dirent.h> /* for implementing lsdir */
797-#endif /* WIN32 */
798-
799 #include <zorba/config.h>
800
801+#include <iostream>
802 #include <stdexcept>
803 #ifdef WIN32
804 # include <windows.h>
805 #else
806+# include <dirent.h>
807 # include <sys/types.h> /* for off_t */
808 #endif /* WIN32 */
809
810@@ -82,6 +76,11 @@
811 volume,
812 other // named pipe, character/block special, socket, etc.
813 };
814+extern char const *const type_string[];
815+
816+inline std::ostream& operator<<( std::ostream &o, type t ) {
817+ return o << type_string[ t ];
818+}
819
820 ////////// Windows ////////////////////////////////////////////////////////////
821
822@@ -152,25 +151,89 @@
823 mkdir( path.c_str() );
824 }
825
826-/**
827- * List files in dir
828- *
829- * @param path The full path of the directory to list.
830- * @throws fs::exception if the list fails.
831- */
832-void lsdir( char const *path, std::vector<std::string> & list );
833-
834-/**
835- * List files in dir
836- *
837- * @tparam PathStringType The \a path string type.
838- * @param path The full path of the directory to list.
839- * @throws fs::exception if the list fails.
840- */
841-template<class PathStringType> inline
842-void lsdir( PathStringType const &path, std::vector<std::string> & list ) {
843- lsdir( path.c_str(), list );
844-}
845+////////// Directory iteration ////////////////////////////////////////////////
846+
847+/**
848+ * An fs::iterator iterates over the entries in a directory.
849+ */
850+class iterator {
851+public:
852+ /**
853+ * Constructs an %itertor.
854+ *
855+ * @throws fs::exception if the construction failed, e.g., path not found.
856+ */
857+ iterator( char const *path );
858+
859+ /**
860+ * Destroys this %iterator.
861+ */
862+ ~iterator();
863+
864+ /**
865+ * Attempts to get the next directory entry.
866+ *
867+ * @return Returns \c true only if there is a next directory.
868+ */
869+ bool next();
870+
871+ /**
872+ * Gets the name of the curent directory entry.
873+ *
874+ * @return Returns said name.
875+ */
876+ char const* entry_name() const {
877+# ifndef WIN32
878+ return ent_->d_name;
879+# else
880+ return ent_name_;
881+# endif /* WIN32 */
882+ }
883+
884+ /**
885+ * Gets the type of the current directory entry.
886+ *
887+ * @return Returns said type.
888+ */
889+ type entry_type() const {
890+ return ent_type_;
891+ }
892+
893+ /**
894+ * Gets the directory's path.
895+ *
896+ * @return Returns said path.
897+ */
898+ char const* path() const {
899+ return dir_path_.c_str();
900+ }
901+
902+ /**
903+ * Resets this iterator to the beginning.
904+ */
905+ void reset();
906+
907+private:
908+ zstring dir_path_;
909+ type ent_type_;
910+#ifndef WIN32
911+ DIR *dir_;
912+ struct dirent *ent_;
913+#else
914+ HANDLE dir_;
915+ bool dir_is_empty_;
916+ WIN32_FIND_DATA ent_data_;
917+ char ent_name_[ MAX_PATH ];
918+ bool use_first_;
919+
920+ void win32_opendir( char const *path );
921+ void win32_closedir();
922+#endif /* WIN32 */
923+
924+ // forbid
925+ iterator( iterator const& );
926+ iterator& operator=( iterator const& );
927+};
928
929 #endif /* ZORBA_WITH_FILE_ACCESS */
930
931@@ -182,7 +245,7 @@
932 * Creates the given file.
933 *
934 * @param path The full path of the file to create.
935- * *throws fs::exception if the creation failed.
936+ * @throws fs::exception if the creation failed.
937 */
938 void create( char const *path );
939
940@@ -572,7 +635,8 @@
941 void make_absolute( PathStringType &path ) {
942 if ( !is_absolute( path ) ) {
943 #ifndef WIN32
944- path.insert( 0, 1, '/' );
945+ typedef typename PathStringType::size_type size_type;
946+ path.insert( static_cast<size_type>(0), static_cast<size_type>(1), '/' );
947 path.insert( 0, curdir().c_str() );
948 #else
949 char temp[ MAX_PATH ];
950
951=== removed file 'src/util/win32/dirent.h'
952--- src/util/win32/dirent.h 2012-03-08 23:20:54 +0000
953+++ src/util/win32/dirent.h 1970-01-01 00:00:00 +0000
954@@ -1,372 +0,0 @@
955-/*****************************************************************************
956- * dirent.h - dirent API for Microsoft Visual Studio
957- *
958- * Copyright (C) 2006 Toni Ronkko
959- *
960- * Permission is hereby granted, free of charge, to any person obtaining
961- * a copy of this software and associated documentation files (the
962- * ``Software''), to deal in the Software without restriction, including
963- * without limitation the rights to use, copy, modify, merge, publish,
964- * distribute, sublicense, and/or sell copies of the Software, and to
965- * permit persons to whom the Software is furnished to do so, subject to
966- * the following conditions:
967- *
968- * The above copyright notice and this permission notice shall be included
969- * in all copies or substantial portions of the Software.
970- *
971- * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
972- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
973- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
974- * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
975- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
976- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
977- * OTHER DEALINGS IN THE SOFTWARE.
978- *
979- * Mar 15, 2011, Toni Ronkko
980- * Defined FILE_ATTRIBUTE_DEVICE for MSVC 6.0.
981- *
982- * Aug 11, 2010, Toni Ronkko
983- * Added d_type and d_namlen fields to dirent structure. The former is
984- * especially useful for determining whether directory entry represents a
985- * file or a directory. For more information, see
986- * http://www.delorie.com/gnu/docs/glibc/libc_270.html
987- *
988- * Aug 11, 2010, Toni Ronkko
989- * Improved conformance to the standards. For example, errno is now set
990- * properly on failure and assert() is never used. Thanks to Peter Brockam
991- * for suggestions.
992- *
993- * Aug 11, 2010, Toni Ronkko
994- * Fixed a bug in rewinddir(): when using relative directory names, change
995- * of working directory no longer causes rewinddir() to fail.
996- *
997- * Dec 15, 2009, John Cunningham
998- * Added rewinddir member function
999- *
1000- * Jan 18, 2008, Toni Ronkko
1001- * Using FindFirstFileA and WIN32_FIND_DATAA to avoid converting string
1002- * between multi-byte and unicode representations. This makes the
1003- * code simpler and also allows the code to be compiled under MingW. Thanks
1004- * to Azriel Fasten for the suggestion.
1005- *
1006- * Mar 4, 2007, Toni Ronkko
1007- * Bug fix: due to the strncpy_s() function this file only compiled in
1008- * Visual Studio 2005. Using the new string functions only when the
1009- * compiler version allows.
1010- *
1011- * Nov 2, 2006, Toni Ronkko
1012- * Major update: removed support for Watcom C, MS-DOS and Turbo C to
1013- * simplify the file, updated the code to compile cleanly on Visual
1014- * Studio 2005 with both unicode and multi-byte character strings,
1015- * removed rewinddir() as it had a bug.
1016- *
1017- * Aug 20, 2006, Toni Ronkko
1018- * Removed all remarks about MSVC 1.0, which is antiqued now. Simplified
1019- * comments by removing SGML tags.
1020- *
1021- * May 14 2002, Toni Ronkko
1022- * Embedded the function definitions directly to the header so that no
1023- * source modules need to be included in the Visual Studio project. Removed
1024- * all the dependencies to other projects so that this very header can be
1025- * used independently.
1026- *
1027- * May 28 1998, Toni Ronkko
1028- * First version.
1029- *****************************************************************************/
1030-#ifndef DIRENT_H
1031-#define DIRENT_H
1032-
1033-#define WIN32_LEAN_AND_MEAN
1034-#include <windows.h>
1035-#include <string.h>
1036-#include <stdlib.h>
1037-#include <sys/types.h>
1038-#include <sys/stat.h>
1039-#include <errno.h>
1040-
1041-/* Entries missing from MSVC 6.0 */
1042-#if !defined(FILE_ATTRIBUTE_DEVICE)
1043-# define FILE_ATTRIBUTE_DEVICE 0x40
1044-#endif
1045-
1046-/* File type and permission flags for stat() */
1047-#if defined(_MSC_VER) && !defined(S_IREAD)
1048-# define S_IFMT _S_IFMT /* file type mask */
1049-# define S_IFDIR _S_IFDIR /* directory */
1050-# define S_IFCHR _S_IFCHR /* character device */
1051-# define S_IFFIFO _S_IFFIFO /* pipe */
1052-# define S_IFREG _S_IFREG /* regular file */
1053-# define S_IREAD _S_IREAD /* read permission */
1054-# define S_IWRITE _S_IWRITE /* write permission */
1055-# define S_IEXEC _S_IEXEC /* execute permission */
1056-#endif
1057-#define S_IFBLK 0 /* block device */
1058-#define S_IFLNK 0 /* link */
1059-#define S_IFSOCK 0 /* socket */
1060-
1061-#if defined(_MSC_VER)
1062-# define S_IRUSR S_IREAD /* read, user */
1063-# define S_IWUSR S_IWRITE /* write, user */
1064-# define S_IXUSR 0 /* execute, user */
1065-# define S_IRGRP 0 /* read, group */
1066-# define S_IWGRP 0 /* write, group */
1067-# define S_IXGRP 0 /* execute, group */
1068-# define S_IROTH 0 /* read, others */
1069-# define S_IWOTH 0 /* write, others */
1070-# define S_IXOTH 0 /* execute, others */
1071-#endif
1072-
1073-/* Indicates that d_type field is available in dirent structure */
1074-#define _DIRENT_HAVE_D_TYPE
1075-
1076-/* File type flags for d_type */
1077-#define DT_UNKNOWN 0
1078-#define DT_REG S_IFREG
1079-#define DT_DIR S_IFDIR
1080-#define DT_FIFO S_IFFIFO
1081-#define DT_SOCK S_IFSOCK
1082-#define DT_CHR S_IFCHR
1083-#define DT_BLK S_IFBLK
1084-
1085-/* Macros for converting between st_mode and d_type */
1086-#define IFTODT(mode) ((mode) & S_IFMT)
1087-#define DTTOIF(type) (type)
1088-
1089-/*
1090- * File type macros. Note that block devices, sockets and links cannot be
1091- * distinguished on Windows and the macros S_ISBLK, S_ISSOCK and S_ISLNK are
1092- * only defined for compatibility. These macros should always return false
1093- * on Windows.
1094- */
1095-#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFFIFO)
1096-#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
1097-#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
1098-#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
1099-#define S_ISSOCK(mode) (((mode) & S_IFMT) == S_IFSOCK)
1100-#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)
1101-#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)
1102-
1103-#ifdef __cplusplus
1104-extern "C" {
1105-#endif
1106-
1107-
1108-typedef struct dirent
1109-{
1110- char d_name[MAX_PATH + 1]; /* File name */
1111- size_t d_namlen; /* Length of name without \0 */
1112- int d_type; /* File type */
1113-} dirent;
1114-
1115-
1116-typedef struct DIR
1117-{
1118- dirent curentry; /* Current directory entry */
1119- WIN32_FIND_DATAA find_data; /* Private file data */
1120- int cached; /* True if data is valid */
1121- HANDLE search_handle; /* Win32 search handle */
1122- char patt[MAX_PATH + 3]; /* Initial directory name */
1123-} DIR;
1124-
1125-
1126-/* Forward declarations */
1127-static DIR *opendir(const char *dirname);
1128-static struct dirent *readdir(DIR *dirp);
1129-static int closedir(DIR *dirp);
1130-static void rewinddir(DIR* dirp);
1131-
1132-
1133-/* Use the new safe string functions introduced in Visual Studio 2005 */
1134-#if defined(_MSC_VER) && _MSC_VER >= 1400
1135-# define DIRENT_STRNCPY(dest,src,size) strncpy_s((dest),(size),(src),_TRUNCATE)
1136-#else
1137-# define DIRENT_STRNCPY(dest,src,size) strncpy((dest),(src),(size))
1138-#endif
1139-
1140-/* Set errno variable */
1141-#if defined(_MSC_VER)
1142-#define DIRENT_SET_ERRNO(x) _set_errno (x)
1143-#else
1144-#define DIRENT_SET_ERRNO(x) (errno = (x))
1145-#endif
1146-
1147-
1148-/*****************************************************************************
1149- * Open directory stream DIRNAME for read and return a pointer to the
1150- * internal working area that is used to retrieve individual directory
1151- * entries.
1152- */
1153-static DIR *opendir(const char *dirname)
1154-{
1155- DIR *dirp;
1156-
1157- /* ensure that the resulting search pattern will be a valid file name */
1158- if (dirname == NULL) {
1159- DIRENT_SET_ERRNO (ENOENT);
1160- return NULL;
1161- }
1162- if (strlen (dirname) + 3 >= MAX_PATH) {
1163- DIRENT_SET_ERRNO (ENAMETOOLONG);
1164- return NULL;
1165- }
1166-
1167- /* construct new DIR structure */
1168- dirp = (DIR*) malloc (sizeof (struct DIR));
1169- if (dirp != NULL) {
1170- int error;
1171-
1172- /*
1173- * Convert relative directory name to an absolute one. This
1174- * allows rewinddir() to function correctly when the current working
1175- * directory is changed between opendir() and rewinddir().
1176- */
1177- if (GetFullPathNameA (dirname, MAX_PATH, dirp->patt, NULL)) {
1178- char *p;
1179-
1180- /* append the search pattern "\\*\0" to the directory name */
1181- p = strchr (dirp->patt, '\0');
1182- if (dirp->patt < p && *(p-1) != '\\' && *(p-1) != ':') {
1183- *p++ = '\\';
1184- }
1185- *p++ = '*';
1186- *p = '\0';
1187-
1188- /* open directory stream and retrieve the first entry */
1189- dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
1190- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
1191- /* a directory entry is now waiting in memory */
1192- dirp->cached = 1;
1193- error = 0;
1194- } else {
1195- /* search pattern is not a directory name? */
1196- DIRENT_SET_ERRNO (ENOENT);
1197- error = 1;
1198- }
1199- } else {
1200- /* buffer too small */
1201- DIRENT_SET_ERRNO (ENOMEM);
1202- error = 1;
1203- }
1204-
1205- if (error) {
1206- free (dirp);
1207- dirp = NULL;
1208- }
1209- }
1210-
1211- return dirp;
1212-}
1213-
1214-
1215-/*****************************************************************************
1216- * Read a directory entry, and return a pointer to a dirent structure
1217- * containing the name of the entry in d_name field. Individual directory
1218- * entries returned by this very function include regular files,
1219- * sub-directories, pseudo-directories "." and "..", but also volume labels,
1220- * hidden files and system files may be returned.
1221- */
1222-static struct dirent *readdir(DIR *dirp)
1223-{
1224- DWORD attr;
1225- if (dirp == NULL) {
1226- /* directory stream did not open */
1227- DIRENT_SET_ERRNO (EBADF);
1228- return NULL;
1229- }
1230-
1231- /* get next directory entry */
1232- if (dirp->cached != 0) {
1233- /* a valid directory entry already in memory */
1234- dirp->cached = 0;
1235- } else {
1236- /* get the next directory entry from stream */
1237- if (dirp->search_handle == INVALID_HANDLE_VALUE) {
1238- return NULL;
1239- }
1240- if (FindNextFileA (dirp->search_handle, &dirp->find_data) == FALSE) {
1241- /* the very last entry has been processed or an error occured */
1242- FindClose (dirp->search_handle);
1243- dirp->search_handle = INVALID_HANDLE_VALUE;
1244- return NULL;
1245- }
1246- }
1247-
1248- /* copy as a multibyte character string */
1249- DIRENT_STRNCPY ( dirp->curentry.d_name,
1250- dirp->find_data.cFileName,
1251- sizeof(dirp->curentry.d_name) );
1252- dirp->curentry.d_name[MAX_PATH] = '\0';
1253-
1254- /* compute the length of name */
1255- dirp->curentry.d_namlen = strlen (dirp->curentry.d_name);
1256-
1257- /* determine file type */
1258- attr = dirp->find_data.dwFileAttributes;
1259- if ((attr & FILE_ATTRIBUTE_DEVICE) != 0) {
1260- dirp->curentry.d_type = DT_CHR;
1261- } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) != 0) {
1262- dirp->curentry.d_type = DT_DIR;
1263- } else {
1264- dirp->curentry.d_type = DT_REG;
1265- }
1266- return &dirp->curentry;
1267-}
1268-
1269-
1270-/*****************************************************************************
1271- * Close directory stream opened by opendir() function. Close of the
1272- * directory stream invalidates the DIR structure as well as any previously
1273- * read directory entry.
1274- */
1275-static int closedir(DIR *dirp)
1276-{
1277- if (dirp == NULL) {
1278- /* invalid directory stream */
1279- DIRENT_SET_ERRNO (EBADF);
1280- return -1;
1281- }
1282-
1283- /* release search handle */
1284- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
1285- FindClose (dirp->search_handle);
1286- dirp->search_handle = INVALID_HANDLE_VALUE;
1287- }
1288-
1289- /* release directory structure */
1290- free (dirp);
1291- return 0;
1292-}
1293-
1294-
1295-/*****************************************************************************
1296- * Resets the position of the directory stream to which dirp refers to the
1297- * beginning of the directory. It also causes the directory stream to refer
1298- * to the current state of the corresponding directory, as a call to opendir()
1299- * would have done. If dirp does not refer to a directory stream, the effect
1300- * is undefined.
1301- */
1302-static void rewinddir(DIR* dirp)
1303-{
1304- if (dirp != NULL) {
1305- /* release search handle */
1306- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
1307- FindClose (dirp->search_handle);
1308- }
1309-
1310- /* open new search handle and retrieve the first entry */
1311- dirp->search_handle = FindFirstFileA (dirp->patt, &dirp->find_data);
1312- if (dirp->search_handle != INVALID_HANDLE_VALUE) {
1313- /* a directory entry is now waiting in memory */
1314- dirp->cached = 1;
1315- } else {
1316- /* failed to re-open directory: no directory entry in memory */
1317- dirp->cached = 0;
1318- }
1319- }
1320-}
1321-
1322-
1323-#ifdef __cplusplus
1324-}
1325-#endif
1326-#endif /*DIRENT_H*/

Subscribers

People subscribed via source and target branches