cppjieba_rb 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +26 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +81 -0
  8. data/Rakefile +20 -0
  9. data/cppjieba_rb.gemspec +50 -0
  10. data/ext/cppjieba/.gitignore +17 -0
  11. data/ext/cppjieba/.travis.yml +22 -0
  12. data/ext/cppjieba/CMakeLists.txt +28 -0
  13. data/ext/cppjieba/ChangeLog.md +236 -0
  14. data/ext/cppjieba/README.md +285 -0
  15. data/ext/cppjieba/README_EN.md +111 -0
  16. data/ext/cppjieba/appveyor.yml +32 -0
  17. data/ext/cppjieba/deps/CMakeLists.txt +1 -0
  18. data/ext/cppjieba/deps/gtest/CMakeLists.txt +5 -0
  19. data/ext/cppjieba/deps/gtest/include/gtest/gtest-death-test.h +283 -0
  20. data/ext/cppjieba/deps/gtest/include/gtest/gtest-message.h +230 -0
  21. data/ext/cppjieba/deps/gtest/include/gtest/gtest-param-test.h +1421 -0
  22. data/ext/cppjieba/deps/gtest/include/gtest/gtest-param-test.h.pump +487 -0
  23. data/ext/cppjieba/deps/gtest/include/gtest/gtest-printers.h +796 -0
  24. data/ext/cppjieba/deps/gtest/include/gtest/gtest-spi.h +232 -0
  25. data/ext/cppjieba/deps/gtest/include/gtest/gtest-test-part.h +176 -0
  26. data/ext/cppjieba/deps/gtest/include/gtest/gtest-typed-test.h +259 -0
  27. data/ext/cppjieba/deps/gtest/include/gtest/gtest.h +2155 -0
  28. data/ext/cppjieba/deps/gtest/include/gtest/gtest_pred_impl.h +358 -0
  29. data/ext/cppjieba/deps/gtest/include/gtest/gtest_prod.h +58 -0
  30. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-death-test-internal.h +308 -0
  31. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-filepath.h +210 -0
  32. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-internal.h +1226 -0
  33. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-linked_ptr.h +233 -0
  34. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-param-util-generated.h +4822 -0
  35. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-param-util-generated.h.pump +301 -0
  36. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-param-util.h +619 -0
  37. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-port.h +1788 -0
  38. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-string.h +350 -0
  39. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-tuple.h +968 -0
  40. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-tuple.h.pump +336 -0
  41. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-type-util.h +3330 -0
  42. data/ext/cppjieba/deps/gtest/include/gtest/internal/gtest-type-util.h.pump +296 -0
  43. data/ext/cppjieba/deps/gtest/src/.deps/.dirstamp +0 -0
  44. data/ext/cppjieba/deps/gtest/src/.deps/gtest-all.Plo +681 -0
  45. data/ext/cppjieba/deps/gtest/src/.deps/gtest_main.Plo +509 -0
  46. data/ext/cppjieba/deps/gtest/src/.dirstamp +0 -0
  47. data/ext/cppjieba/deps/gtest/src/gtest-all.cc +48 -0
  48. data/ext/cppjieba/deps/gtest/src/gtest-death-test.cc +1234 -0
  49. data/ext/cppjieba/deps/gtest/src/gtest-filepath.cc +380 -0
  50. data/ext/cppjieba/deps/gtest/src/gtest-internal-inl.h +1038 -0
  51. data/ext/cppjieba/deps/gtest/src/gtest-port.cc +746 -0
  52. data/ext/cppjieba/deps/gtest/src/gtest-printers.cc +356 -0
  53. data/ext/cppjieba/deps/gtest/src/gtest-test-part.cc +110 -0
  54. data/ext/cppjieba/deps/gtest/src/gtest-typed-test.cc +110 -0
  55. data/ext/cppjieba/deps/gtest/src/gtest.cc +4898 -0
  56. data/ext/cppjieba/deps/gtest/src/gtest_main.cc +39 -0
  57. data/ext/cppjieba/deps/limonp/ArgvContext.hpp +70 -0
  58. data/ext/cppjieba/deps/limonp/BlockingQueue.hpp +49 -0
  59. data/ext/cppjieba/deps/limonp/BoundedBlockingQueue.hpp +67 -0
  60. data/ext/cppjieba/deps/limonp/BoundedQueue.hpp +65 -0
  61. data/ext/cppjieba/deps/limonp/Closure.hpp +206 -0
  62. data/ext/cppjieba/deps/limonp/Colors.hpp +31 -0
  63. data/ext/cppjieba/deps/limonp/Condition.hpp +38 -0
  64. data/ext/cppjieba/deps/limonp/Config.hpp +103 -0
  65. data/ext/cppjieba/deps/limonp/FileLock.hpp +74 -0
  66. data/ext/cppjieba/deps/limonp/ForcePublic.hpp +7 -0
  67. data/ext/cppjieba/deps/limonp/LocalVector.hpp +139 -0
  68. data/ext/cppjieba/deps/limonp/Logging.hpp +76 -0
  69. data/ext/cppjieba/deps/limonp/Md5.hpp +411 -0
  70. data/ext/cppjieba/deps/limonp/MutexLock.hpp +51 -0
  71. data/ext/cppjieba/deps/limonp/NonCopyable.hpp +21 -0
  72. data/ext/cppjieba/deps/limonp/StdExtension.hpp +159 -0
  73. data/ext/cppjieba/deps/limonp/StringUtil.hpp +365 -0
  74. data/ext/cppjieba/deps/limonp/Thread.hpp +44 -0
  75. data/ext/cppjieba/deps/limonp/ThreadPool.hpp +86 -0
  76. data/ext/cppjieba/dict/README.md +31 -0
  77. data/ext/cppjieba/dict/hmm_model.utf8 +34 -0
  78. data/ext/cppjieba/dict/idf.utf8 +258826 -0
  79. data/ext/cppjieba/dict/jieba.dict.utf8 +348982 -0
  80. data/ext/cppjieba/dict/pos_dict/char_state_tab.utf8 +6653 -0
  81. data/ext/cppjieba/dict/pos_dict/prob_emit.utf8 +166 -0
  82. data/ext/cppjieba/dict/pos_dict/prob_start.utf8 +259 -0
  83. data/ext/cppjieba/dict/pos_dict/prob_trans.utf8 +5222 -0
  84. data/ext/cppjieba/dict/stop_words.utf8 +1534 -0
  85. data/ext/cppjieba/dict/user.dict.utf8 +4 -0
  86. data/ext/cppjieba/include/cppjieba/DictTrie.hpp +227 -0
  87. data/ext/cppjieba/include/cppjieba/FullSegment.hpp +93 -0
  88. data/ext/cppjieba/include/cppjieba/HMMModel.hpp +129 -0
  89. data/ext/cppjieba/include/cppjieba/HMMSegment.hpp +190 -0
  90. data/ext/cppjieba/include/cppjieba/Jieba.hpp +108 -0
  91. data/ext/cppjieba/include/cppjieba/KeywordExtractor.hpp +153 -0
  92. data/ext/cppjieba/include/cppjieba/MPSegment.hpp +137 -0
  93. data/ext/cppjieba/include/cppjieba/MixSegment.hpp +109 -0
  94. data/ext/cppjieba/include/cppjieba/PosTagger.hpp +77 -0
  95. data/ext/cppjieba/include/cppjieba/PreFilter.hpp +54 -0
  96. data/ext/cppjieba/include/cppjieba/QuerySegment.hpp +90 -0
  97. data/ext/cppjieba/include/cppjieba/SegmentBase.hpp +46 -0
  98. data/ext/cppjieba/include/cppjieba/SegmentTagged.hpp +23 -0
  99. data/ext/cppjieba/include/cppjieba/TextRankExtractor.hpp +190 -0
  100. data/ext/cppjieba/include/cppjieba/Trie.hpp +174 -0
  101. data/ext/cppjieba/include/cppjieba/Unicode.hpp +215 -0
  102. data/ext/cppjieba/test/CMakeLists.txt +5 -0
  103. data/ext/cppjieba/test/demo.cpp +80 -0
  104. data/ext/cppjieba/test/load_test.cpp +54 -0
  105. data/ext/cppjieba/test/testdata/curl.res +1 -0
  106. data/ext/cppjieba/test/testdata/extra_dict/jieba.dict.small.utf8 +109750 -0
  107. data/ext/cppjieba/test/testdata/gbk_dict/hmm_model.gbk +34 -0
  108. data/ext/cppjieba/test/testdata/gbk_dict/jieba.dict.gbk +348982 -0
  109. data/ext/cppjieba/test/testdata/jieba.dict.0.1.utf8 +93 -0
  110. data/ext/cppjieba/test/testdata/jieba.dict.0.utf8 +93 -0
  111. data/ext/cppjieba/test/testdata/jieba.dict.1.utf8 +67 -0
  112. data/ext/cppjieba/test/testdata/jieba.dict.2.utf8 +64 -0
  113. data/ext/cppjieba/test/testdata/load_test.urls +2 -0
  114. data/ext/cppjieba/test/testdata/review.100 +100 -0
  115. data/ext/cppjieba/test/testdata/review.100.res +200 -0
  116. data/ext/cppjieba/test/testdata/server.conf +19 -0
  117. data/ext/cppjieba/test/testdata/testlines.gbk +9 -0
  118. data/ext/cppjieba/test/testdata/testlines.utf8 +8 -0
  119. data/ext/cppjieba/test/testdata/userdict.2.utf8 +1 -0
  120. data/ext/cppjieba/test/testdata/userdict.english +2 -0
  121. data/ext/cppjieba/test/testdata/userdict.utf8 +8 -0
  122. data/ext/cppjieba/test/testdata/weicheng.utf8 +247 -0
  123. data/ext/cppjieba/test/unittest/CMakeLists.txt +24 -0
  124. data/ext/cppjieba/test/unittest/gtest_main.cpp +39 -0
  125. data/ext/cppjieba/test/unittest/jieba_test.cpp +133 -0
  126. data/ext/cppjieba/test/unittest/keyword_extractor_test.cpp +79 -0
  127. data/ext/cppjieba/test/unittest/pos_tagger_test.cpp +41 -0
  128. data/ext/cppjieba/test/unittest/pre_filter_test.cpp +43 -0
  129. data/ext/cppjieba/test/unittest/segments_test.cpp +256 -0
  130. data/ext/cppjieba/test/unittest/textrank_test.cpp +86 -0
  131. data/ext/cppjieba/test/unittest/trie_test.cpp +177 -0
  132. data/ext/cppjieba/test/unittest/unicode_test.cpp +43 -0
  133. data/ext/cppjieba_rb/cppjieba_rb.c +10 -0
  134. data/ext/cppjieba_rb/extconf.rb +26 -0
  135. data/ext/cppjieba_rb/internal.cc +148 -0
  136. data/lib/cppjieba_rb/segment.rb +20 -0
  137. data/lib/cppjieba_rb/version.rb +3 -0
  138. data/lib/cppjieba_rb.rb +34 -0
  139. data/test/test_keyword.rb +17 -0
  140. data/test/test_segment.rb +24 -0
  141. data/test/test_tagging.rb +19 -0
  142. metadata +244 -0
@@ -0,0 +1,380 @@
1
+ // Copyright 2008, Google Inc.
2
+ // All rights reserved.
3
+ //
4
+ // Redistribution and use in source and binary forms, with or without
5
+ // modification, are permitted provided that the following conditions are
6
+ // met:
7
+ //
8
+ // * Redistributions of source code must retain the above copyright
9
+ // notice, this list of conditions and the following disclaimer.
10
+ // * Redistributions in binary form must reproduce the above
11
+ // copyright notice, this list of conditions and the following disclaimer
12
+ // in the documentation and/or other materials provided with the
13
+ // distribution.
14
+ // * Neither the name of Google Inc. nor the names of its
15
+ // contributors may be used to endorse or promote products derived from
16
+ // this software without specific prior written permission.
17
+ //
18
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
+ //
30
+ // Authors: keith.ray@gmail.com (Keith Ray)
31
+
32
+ #include "gtest/internal/gtest-filepath.h"
33
+ #include "gtest/internal/gtest-port.h"
34
+
35
+ #include <stdlib.h>
36
+
37
+ #if GTEST_OS_WINDOWS_MOBILE
38
+ # include <windows.h>
39
+ #elif GTEST_OS_WINDOWS
40
+ # include <direct.h>
41
+ # include <io.h>
42
+ #elif GTEST_OS_SYMBIAN || GTEST_OS_NACL
43
+ // Symbian OpenC and NaCl have PATH_MAX in sys/syslimits.h
44
+ # include <sys/syslimits.h>
45
+ #else
46
+ # include <limits.h>
47
+ # include <climits> // Some Linux distributions define PATH_MAX here.
48
+ #endif // GTEST_OS_WINDOWS_MOBILE
49
+
50
+ #if GTEST_OS_WINDOWS
51
+ # define GTEST_PATH_MAX_ _MAX_PATH
52
+ #elif defined(PATH_MAX)
53
+ # define GTEST_PATH_MAX_ PATH_MAX
54
+ #elif defined(_XOPEN_PATH_MAX)
55
+ # define GTEST_PATH_MAX_ _XOPEN_PATH_MAX
56
+ #else
57
+ # define GTEST_PATH_MAX_ _POSIX_PATH_MAX
58
+ #endif // GTEST_OS_WINDOWS
59
+
60
+ #include "gtest/internal/gtest-string.h"
61
+
62
+ namespace testing {
63
+ namespace internal {
64
+
65
+ #if GTEST_OS_WINDOWS
66
+ // On Windows, '\\' is the standard path separator, but many tools and the
67
+ // Windows API also accept '/' as an alternate path separator. Unless otherwise
68
+ // noted, a file path can contain either kind of path separators, or a mixture
69
+ // of them.
70
+ const char kPathSeparator = '\\';
71
+ const char kAlternatePathSeparator = '/';
72
+ const char kPathSeparatorString[] = "\\";
73
+ const char kAlternatePathSeparatorString[] = "/";
74
+ # if GTEST_OS_WINDOWS_MOBILE
75
+ // Windows CE doesn't have a current directory. You should not use
76
+ // the current directory in tests on Windows CE, but this at least
77
+ // provides a reasonable fallback.
78
+ const char kCurrentDirectoryString[] = "\\";
79
+ // Windows CE doesn't define INVALID_FILE_ATTRIBUTES
80
+ const DWORD kInvalidFileAttributes = 0xffffffff;
81
+ # else
82
+ const char kCurrentDirectoryString[] = ".\\";
83
+ # endif // GTEST_OS_WINDOWS_MOBILE
84
+ #else
85
+ const char kPathSeparator = '/';
86
+ const char kPathSeparatorString[] = "/";
87
+ const char kCurrentDirectoryString[] = "./";
88
+ #endif // GTEST_OS_WINDOWS
89
+
90
+ // Returns whether the given character is a valid path separator.
91
+ static bool IsPathSeparator(char c) {
92
+ #if GTEST_HAS_ALT_PATH_SEP_
93
+ return (c == kPathSeparator) || (c == kAlternatePathSeparator);
94
+ #else
95
+ return c == kPathSeparator;
96
+ #endif
97
+ }
98
+
99
+ // Returns the current working directory, or "" if unsuccessful.
100
+ FilePath FilePath::GetCurrentDir() {
101
+ #if GTEST_OS_WINDOWS_MOBILE
102
+ // Windows CE doesn't have a current directory, so we just return
103
+ // something reasonable.
104
+ return FilePath(kCurrentDirectoryString);
105
+ #elif GTEST_OS_WINDOWS
106
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
107
+ return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
108
+ #else
109
+ char cwd[GTEST_PATH_MAX_ + 1] = { '\0' };
110
+ return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd);
111
+ #endif // GTEST_OS_WINDOWS_MOBILE
112
+ }
113
+
114
+ // Returns a copy of the FilePath with the case-insensitive extension removed.
115
+ // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
116
+ // FilePath("dir/file"). If a case-insensitive extension is not
117
+ // found, returns a copy of the original FilePath.
118
+ FilePath FilePath::RemoveExtension(const char* extension) const {
119
+ String dot_extension(String::Format(".%s", extension));
120
+ if (pathname_.EndsWithCaseInsensitive(dot_extension.c_str())) {
121
+ return FilePath(String(pathname_.c_str(), pathname_.length() - 4));
122
+ }
123
+ return *this;
124
+ }
125
+
126
+ // Returns a pointer to the last occurence of a valid path separator in
127
+ // the FilePath. On Windows, for example, both '/' and '\' are valid path
128
+ // separators. Returns NULL if no path separator was found.
129
+ const char* FilePath::FindLastPathSeparator() const {
130
+ const char* const last_sep = strrchr(c_str(), kPathSeparator);
131
+ #if GTEST_HAS_ALT_PATH_SEP_
132
+ const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator);
133
+ // Comparing two pointers of which only one is NULL is undefined.
134
+ if (last_alt_sep != NULL &&
135
+ (last_sep == NULL || last_alt_sep > last_sep)) {
136
+ return last_alt_sep;
137
+ }
138
+ #endif
139
+ return last_sep;
140
+ }
141
+
142
+ // Returns a copy of the FilePath with the directory part removed.
143
+ // Example: FilePath("path/to/file").RemoveDirectoryName() returns
144
+ // FilePath("file"). If there is no directory part ("just_a_file"), it returns
145
+ // the FilePath unmodified. If there is no file part ("just_a_dir/") it
146
+ // returns an empty FilePath ("").
147
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
148
+ FilePath FilePath::RemoveDirectoryName() const {
149
+ const char* const last_sep = FindLastPathSeparator();
150
+ return last_sep ? FilePath(String(last_sep + 1)) : *this;
151
+ }
152
+
153
+ // RemoveFileName returns the directory path with the filename removed.
154
+ // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
155
+ // If the FilePath is "a_file" or "/a_file", RemoveFileName returns
156
+ // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
157
+ // not have a file, like "just/a/dir/", it returns the FilePath unmodified.
158
+ // On Windows platform, '\' is the path separator, otherwise it is '/'.
159
+ FilePath FilePath::RemoveFileName() const {
160
+ const char* const last_sep = FindLastPathSeparator();
161
+ String dir;
162
+ if (last_sep) {
163
+ dir = String(c_str(), last_sep + 1 - c_str());
164
+ } else {
165
+ dir = kCurrentDirectoryString;
166
+ }
167
+ return FilePath(dir);
168
+ }
169
+
170
+ // Helper functions for naming files in a directory for xml output.
171
+
172
+ // Given directory = "dir", base_name = "test", number = 0,
173
+ // extension = "xml", returns "dir/test.xml". If number is greater
174
+ // than zero (e.g., 12), returns "dir/test_12.xml".
175
+ // On Windows platform, uses \ as the separator rather than /.
176
+ FilePath FilePath::MakeFileName(const FilePath& directory,
177
+ const FilePath& base_name,
178
+ int number,
179
+ const char* extension) {
180
+ String file;
181
+ if (number == 0) {
182
+ file = String::Format("%s.%s", base_name.c_str(), extension);
183
+ } else {
184
+ file = String::Format("%s_%d.%s", base_name.c_str(), number, extension);
185
+ }
186
+ return ConcatPaths(directory, FilePath(file));
187
+ }
188
+
189
+ // Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml".
190
+ // On Windows, uses \ as the separator rather than /.
191
+ FilePath FilePath::ConcatPaths(const FilePath& directory,
192
+ const FilePath& relative_path) {
193
+ if (directory.IsEmpty())
194
+ return relative_path;
195
+ const FilePath dir(directory.RemoveTrailingPathSeparator());
196
+ return FilePath(String::Format("%s%c%s", dir.c_str(), kPathSeparator,
197
+ relative_path.c_str()));
198
+ }
199
+
200
+ // Returns true if pathname describes something findable in the file-system,
201
+ // either a file, directory, or whatever.
202
+ bool FilePath::FileOrDirectoryExists() const {
203
+ #if GTEST_OS_WINDOWS_MOBILE
204
+ LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str());
205
+ const DWORD attributes = GetFileAttributes(unicode);
206
+ delete [] unicode;
207
+ return attributes != kInvalidFileAttributes;
208
+ #else
209
+ posix::StatStruct file_stat;
210
+ return posix::Stat(pathname_.c_str(), &file_stat) == 0;
211
+ #endif // GTEST_OS_WINDOWS_MOBILE
212
+ }
213
+
214
+ // Returns true if pathname describes a directory in the file-system
215
+ // that exists.
216
+ bool FilePath::DirectoryExists() const {
217
+ bool result = false;
218
+ #if GTEST_OS_WINDOWS
219
+ // Don't strip off trailing separator if path is a root directory on
220
+ // Windows (like "C:\\").
221
+ const FilePath& path(IsRootDirectory() ? *this :
222
+ RemoveTrailingPathSeparator());
223
+ #else
224
+ const FilePath& path(*this);
225
+ #endif
226
+
227
+ #if GTEST_OS_WINDOWS_MOBILE
228
+ LPCWSTR unicode = String::AnsiToUtf16(path.c_str());
229
+ const DWORD attributes = GetFileAttributes(unicode);
230
+ delete [] unicode;
231
+ if ((attributes != kInvalidFileAttributes) &&
232
+ (attributes & FILE_ATTRIBUTE_DIRECTORY)) {
233
+ result = true;
234
+ }
235
+ #else
236
+ posix::StatStruct file_stat;
237
+ result = posix::Stat(path.c_str(), &file_stat) == 0 &&
238
+ posix::IsDir(file_stat);
239
+ #endif // GTEST_OS_WINDOWS_MOBILE
240
+
241
+ return result;
242
+ }
243
+
244
+ // Returns true if pathname describes a root directory. (Windows has one
245
+ // root directory per disk drive.)
246
+ bool FilePath::IsRootDirectory() const {
247
+ #if GTEST_OS_WINDOWS
248
+ // TODO(wan@google.com): on Windows a network share like
249
+ // \\server\share can be a root directory, although it cannot be the
250
+ // current directory. Handle this properly.
251
+ return pathname_.length() == 3 && IsAbsolutePath();
252
+ #else
253
+ return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]);
254
+ #endif
255
+ }
256
+
257
+ // Returns true if pathname describes an absolute path.
258
+ bool FilePath::IsAbsolutePath() const {
259
+ const char* const name = pathname_.c_str();
260
+ #if GTEST_OS_WINDOWS
261
+ return pathname_.length() >= 3 &&
262
+ ((name[0] >= 'a' && name[0] <= 'z') ||
263
+ (name[0] >= 'A' && name[0] <= 'Z')) &&
264
+ name[1] == ':' &&
265
+ IsPathSeparator(name[2]);
266
+ #else
267
+ return IsPathSeparator(name[0]);
268
+ #endif
269
+ }
270
+
271
+ // Returns a pathname for a file that does not currently exist. The pathname
272
+ // will be directory/base_name.extension or
273
+ // directory/base_name_<number>.extension if directory/base_name.extension
274
+ // already exists. The number will be incremented until a pathname is found
275
+ // that does not already exist.
276
+ // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
277
+ // There could be a race condition if two or more processes are calling this
278
+ // function at the same time -- they could both pick the same filename.
279
+ FilePath FilePath::GenerateUniqueFileName(const FilePath& directory,
280
+ const FilePath& base_name,
281
+ const char* extension) {
282
+ FilePath full_pathname;
283
+ int number = 0;
284
+ do {
285
+ full_pathname.Set(MakeFileName(directory, base_name, number++, extension));
286
+ } while (full_pathname.FileOrDirectoryExists());
287
+ return full_pathname;
288
+ }
289
+
290
+ // Returns true if FilePath ends with a path separator, which indicates that
291
+ // it is intended to represent a directory. Returns false otherwise.
292
+ // This does NOT check that a directory (or file) actually exists.
293
+ bool FilePath::IsDirectory() const {
294
+ return !pathname_.empty() &&
295
+ IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]);
296
+ }
297
+
298
+ // Create directories so that path exists. Returns true if successful or if
299
+ // the directories already exist; returns false if unable to create directories
300
+ // for any reason.
301
+ bool FilePath::CreateDirectoriesRecursively() const {
302
+ if (!this->IsDirectory()) {
303
+ return false;
304
+ }
305
+
306
+ if (pathname_.length() == 0 || this->DirectoryExists()) {
307
+ return true;
308
+ }
309
+
310
+ const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName());
311
+ return parent.CreateDirectoriesRecursively() && this->CreateFolder();
312
+ }
313
+
314
+ // Create the directory so that path exists. Returns true if successful or
315
+ // if the directory already exists; returns false if unable to create the
316
+ // directory for any reason, including if the parent directory does not
317
+ // exist. Not named "CreateDirectory" because that's a macro on Windows.
318
+ bool FilePath::CreateFolder() const {
319
+ #if GTEST_OS_WINDOWS_MOBILE
320
+ FilePath removed_sep(this->RemoveTrailingPathSeparator());
321
+ LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str());
322
+ int result = CreateDirectory(unicode, NULL) ? 0 : -1;
323
+ delete [] unicode;
324
+ #elif GTEST_OS_WINDOWS
325
+ int result = _mkdir(pathname_.c_str());
326
+ #else
327
+ int result = mkdir(pathname_.c_str(), 0777);
328
+ #endif // GTEST_OS_WINDOWS_MOBILE
329
+
330
+ if (result == -1) {
331
+ return this->DirectoryExists(); // An error is OK if the directory exists.
332
+ }
333
+ return true; // No error.
334
+ }
335
+
336
+ // If input name has a trailing separator character, remove it and return the
337
+ // name, otherwise return the name string unmodified.
338
+ // On Windows platform, uses \ as the separator, other platforms use /.
339
+ FilePath FilePath::RemoveTrailingPathSeparator() const {
340
+ return IsDirectory()
341
+ ? FilePath(String(pathname_.c_str(), pathname_.length() - 1))
342
+ : *this;
343
+ }
344
+
345
+ // Removes any redundant separators that might be in the pathname.
346
+ // For example, "bar///foo" becomes "bar/foo". Does not eliminate other
347
+ // redundancies that might be in a pathname involving "." or "..".
348
+ // TODO(wan@google.com): handle Windows network shares (e.g. \\server\share).
349
+ void FilePath::Normalize() {
350
+ if (pathname_.c_str() == NULL) {
351
+ pathname_ = "";
352
+ return;
353
+ }
354
+ const char* src = pathname_.c_str();
355
+ char* const dest = new char[pathname_.length() + 1];
356
+ char* dest_ptr = dest;
357
+ memset(dest_ptr, 0, pathname_.length() + 1);
358
+
359
+ while (*src != '\0') {
360
+ *dest_ptr = *src;
361
+ if (!IsPathSeparator(*src)) {
362
+ src++;
363
+ } else {
364
+ #if GTEST_HAS_ALT_PATH_SEP_
365
+ if (*dest_ptr == kAlternatePathSeparator) {
366
+ *dest_ptr = kPathSeparator;
367
+ }
368
+ #endif
369
+ while (IsPathSeparator(*src))
370
+ src++;
371
+ }
372
+ dest_ptr++;
373
+ }
374
+ *dest_ptr = '\0';
375
+ pathname_ = dest;
376
+ delete[] dest;
377
+ }
378
+
379
+ } // namespace internal
380
+ } // namespace testing