cppjieba_rb 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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