1 /* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2    file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3 #include "kwsysPrivate.h"
4 
5 #if defined(_MSC_VER)
6 #pragma warning(disable : 4786)
7 #endif
8 
9 #include KWSYS_HEADER(FStream.hxx)
10 #include KWSYS_HEADER(SystemTools.hxx)
11 
12 // Work-around CMake dependency scanning limitation.  This must
13 // duplicate the above list of headers.
14 #if 0
15 #include "FStream.hxx.in"
16 #include "SystemTools.hxx.in"
17 #endif
18 
19 // Include with <> instead of "" to avoid getting any in-source copy
20 // left on disk.
21 #include <testSystemTools.h>
22 
23 #include <iostream>
24 #include <sstream>
25 #include <stdlib.h> /* free */
26 #include <string.h> /* strcmp */
27 #if defined(_WIN32) && !defined(__CYGWIN__)
28 #include <io.h> /* _umask (MSVC) / umask (Borland) */
29 #ifdef _MSC_VER
30 #define umask _umask // Note this is still umask on Borland
31 #endif
32 #endif
33 #include <sys/stat.h> /* umask (POSIX), _S_I* constants (Windows) */
34 // Visual C++ does not define mode_t (note that Borland does, however).
35 #if defined(_MSC_VER)
36 typedef unsigned short mode_t;
37 #endif
38 
39 static const char* toUnixPaths[][2] = {
40   { "/usr/local/bin/passwd", "/usr/local/bin/passwd" },
41   { "/usr/lo cal/bin/pa sswd", "/usr/lo cal/bin/pa sswd" },
42   { "/usr/lo\\ cal/bin/pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" },
43   { "c:/usr/local/bin/passwd", "c:/usr/local/bin/passwd" },
44   { "c:/usr/lo cal/bin/pa sswd", "c:/usr/lo cal/bin/pa sswd" },
45   { "c:/usr/lo\\ cal/bin/pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" },
46   { "\\usr\\local\\bin\\passwd", "/usr/local/bin/passwd" },
47   { "\\usr\\lo cal\\bin\\pa sswd", "/usr/lo cal/bin/pa sswd" },
48   { "\\usr\\lo\\ cal\\bin\\pa\\ sswd", "/usr/lo/ cal/bin/pa/ sswd" },
49   { "c:\\usr\\local\\bin\\passwd", "c:/usr/local/bin/passwd" },
50   { "c:\\usr\\lo cal\\bin\\pa sswd", "c:/usr/lo cal/bin/pa sswd" },
51   { "c:\\usr\\lo\\ cal\\bin\\pa\\ sswd", "c:/usr/lo/ cal/bin/pa/ sswd" },
52   { "\\\\usr\\local\\bin\\passwd", "//usr/local/bin/passwd" },
53   { "\\\\usr\\lo cal\\bin\\pa sswd", "//usr/lo cal/bin/pa sswd" },
54   { "\\\\usr\\lo\\ cal\\bin\\pa\\ sswd", "//usr/lo/ cal/bin/pa/ sswd" },
55   { KWSYS_NULLPTR, KWSYS_NULLPTR }
56 };
57 
CheckConvertToUnixSlashes(std::string const & input,std::string const & output)58 static bool CheckConvertToUnixSlashes(std::string const& input,
59                                       std::string const& output)
60 {
61   std::string result = input;
62   kwsys::SystemTools::ConvertToUnixSlashes(result);
63   if (result != output) {
64     std::cerr << "Problem with ConvertToUnixSlashes - input: " << input
65               << " output: " << result << " expected: " << output << std::endl;
66     return false;
67   }
68   return true;
69 }
70 
71 static const char* checkEscapeChars[][4] = {
72   { "1 foo 2 bar 2", "12", "\\", "\\1 foo \\2 bar \\2" },
73   { " {} ", "{}", "#", " #{#} " },
74   { KWSYS_NULLPTR, KWSYS_NULLPTR, KWSYS_NULLPTR, KWSYS_NULLPTR }
75 };
76 
CheckEscapeChars(std::string const & input,const char * chars_to_escape,char escape_char,std::string const & output)77 static bool CheckEscapeChars(std::string const& input,
78                              const char* chars_to_escape, char escape_char,
79                              std::string const& output)
80 {
81   std::string result = kwsys::SystemTools::EscapeChars(
82     input.c_str(), chars_to_escape, escape_char);
83   if (result != output) {
84     std::cerr << "Problem with CheckEscapeChars - input: " << input
85               << " output: " << result << " expected: " << output << std::endl;
86     return false;
87   }
88   return true;
89 }
90 
CheckFileOperations()91 static bool CheckFileOperations()
92 {
93   bool res = true;
94   const std::string testNonExistingFile(TEST_SYSTEMTOOLS_SOURCE_DIR
95                                         "/testSystemToolsNonExistingFile");
96   const std::string testDotFile(TEST_SYSTEMTOOLS_SOURCE_DIR "/.");
97   const std::string testBinFile(TEST_SYSTEMTOOLS_SOURCE_DIR
98                                 "/testSystemTools.bin");
99   const std::string testTxtFile(TEST_SYSTEMTOOLS_SOURCE_DIR
100                                 "/testSystemTools.cxx");
101   const std::string testNewDir(TEST_SYSTEMTOOLS_BINARY_DIR
102                                "/testSystemToolsNewDir");
103   const std::string testNewFile(testNewDir + "/testNewFile.txt");
104 
105   if (kwsys::SystemTools::DetectFileType(testNonExistingFile.c_str()) !=
106       kwsys::SystemTools::FileTypeUnknown) {
107     std::cerr << "Problem with DetectFileType - failed to detect type of: "
108               << testNonExistingFile << std::endl;
109     res = false;
110   }
111 
112   if (kwsys::SystemTools::DetectFileType(testDotFile.c_str()) !=
113       kwsys::SystemTools::FileTypeUnknown) {
114     std::cerr << "Problem with DetectFileType - failed to detect type of: "
115               << testDotFile << std::endl;
116     res = false;
117   }
118 
119   if (kwsys::SystemTools::DetectFileType(testBinFile.c_str()) !=
120       kwsys::SystemTools::FileTypeBinary) {
121     std::cerr << "Problem with DetectFileType - failed to detect type of: "
122               << testBinFile << std::endl;
123     res = false;
124   }
125 
126   if (kwsys::SystemTools::DetectFileType(testTxtFile.c_str()) !=
127       kwsys::SystemTools::FileTypeText) {
128     std::cerr << "Problem with DetectFileType - failed to detect type of: "
129               << testTxtFile << std::endl;
130     res = false;
131   }
132 
133   if (kwsys::SystemTools::FileLength(testBinFile) != 766) {
134     std::cerr << "Problem with FileLength - incorrect length for: "
135               << testBinFile << std::endl;
136     res = false;
137   }
138 
139   kwsys::SystemTools::Stat_t buf;
140   if (kwsys::SystemTools::Stat(testTxtFile.c_str(), &buf) != 0) {
141     std::cerr << "Problem with Stat - unable to stat text file: "
142               << testTxtFile << std::endl;
143     res = false;
144   }
145 
146   if (kwsys::SystemTools::Stat(testBinFile, &buf) != 0) {
147     std::cerr << "Problem with Stat - unable to stat bin file: " << testBinFile
148               << std::endl;
149     res = false;
150   }
151 
152   if (!kwsys::SystemTools::MakeDirectory(testNewDir)) {
153     std::cerr << "Problem with MakeDirectory for: " << testNewDir << std::endl;
154     res = false;
155   }
156   // calling it again should just return true
157   if (!kwsys::SystemTools::MakeDirectory(testNewDir)) {
158     std::cerr << "Problem with second call to MakeDirectory for: "
159               << testNewDir << std::endl;
160     res = false;
161   }
162   // calling with 0 pointer should return false
163   if (kwsys::SystemTools::MakeDirectory(KWSYS_NULLPTR)) {
164     std::cerr << "Problem with MakeDirectory(0)" << std::endl;
165     res = false;
166   }
167   // calling with an empty string should return false
168   if (kwsys::SystemTools::MakeDirectory(std::string())) {
169     std::cerr << "Problem with MakeDirectory(std::string())" << std::endl;
170     res = false;
171   }
172   // check existence
173   if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
174     std::cerr << "Problem with FileExists as C string and not file for: "
175               << testNewDir << std::endl;
176     res = false;
177   }
178   // check existence
179   if (!kwsys::SystemTools::PathExists(testNewDir)) {
180     std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
181     res = false;
182   }
183   // remove it
184   if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) {
185     std::cerr << "Problem with RemoveADirectory for: " << testNewDir
186               << std::endl;
187     res = false;
188   }
189   // check existence
190   if (kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
191     std::cerr << "After RemoveADirectory: "
192               << "Problem with FileExists as C string and not file for: "
193               << testNewDir << std::endl;
194     res = false;
195   }
196   // check existence
197   if (kwsys::SystemTools::PathExists(testNewDir)) {
198     std::cerr << "After RemoveADirectory: "
199               << "Problem with PathExists for: " << testNewDir << std::endl;
200     res = false;
201   }
202   // create it using the char* version
203   if (!kwsys::SystemTools::MakeDirectory(testNewDir.c_str())) {
204     std::cerr << "Problem with second call to MakeDirectory as C string for: "
205               << testNewDir << std::endl;
206     res = false;
207   }
208 
209   if (!kwsys::SystemTools::Touch(testNewFile.c_str(), true)) {
210     std::cerr << "Problem with Touch for: " << testNewFile << std::endl;
211     res = false;
212   }
213   // calling MakeDirectory with something that is no file should fail
214   if (kwsys::SystemTools::MakeDirectory(testNewFile)) {
215     std::cerr << "Problem with to MakeDirectory for: " << testNewFile
216               << std::endl;
217     res = false;
218   }
219 
220   // calling with 0 pointer should return false
221   if (kwsys::SystemTools::FileExists(KWSYS_NULLPTR)) {
222     std::cerr << "Problem with FileExists(0)" << std::endl;
223     res = false;
224   }
225   if (kwsys::SystemTools::FileExists(KWSYS_NULLPTR, true)) {
226     std::cerr << "Problem with FileExists(0) as file" << std::endl;
227     res = false;
228   }
229   // calling with an empty string should return false
230   if (kwsys::SystemTools::FileExists(std::string())) {
231     std::cerr << "Problem with FileExists(std::string())" << std::endl;
232     res = false;
233   }
234   // FileExists(x, true) should return false on a directory
235   if (kwsys::SystemTools::FileExists(testNewDir, true)) {
236     std::cerr << "Problem with FileExists as file for: " << testNewDir
237               << std::endl;
238     res = false;
239   }
240   if (kwsys::SystemTools::FileExists(testNewDir.c_str(), true)) {
241     std::cerr << "Problem with FileExists as C string and file for: "
242               << testNewDir << std::endl;
243     res = false;
244   }
245   // FileExists(x, false) should return true even on a directory
246   if (!kwsys::SystemTools::FileExists(testNewDir, false)) {
247     std::cerr << "Problem with FileExists as not file for: " << testNewDir
248               << std::endl;
249     res = false;
250   }
251   if (!kwsys::SystemTools::FileExists(testNewDir.c_str(), false)) {
252     std::cerr << "Problem with FileExists as C string and not file for: "
253               << testNewDir << std::endl;
254     res = false;
255   }
256   // should work, was created as new file before
257   if (!kwsys::SystemTools::FileExists(testNewFile)) {
258     std::cerr << "Problem with FileExists for: " << testNewFile << std::endl;
259     res = false;
260   }
261   if (!kwsys::SystemTools::FileExists(testNewFile.c_str())) {
262     std::cerr << "Problem with FileExists as C string for: " << testNewFile
263               << std::endl;
264     res = false;
265   }
266   if (!kwsys::SystemTools::FileExists(testNewFile, true)) {
267     std::cerr << "Problem with FileExists as file for: " << testNewFile
268               << std::endl;
269     res = false;
270   }
271   if (!kwsys::SystemTools::FileExists(testNewFile.c_str(), true)) {
272     std::cerr << "Problem with FileExists as C string and file for: "
273               << testNewFile << std::endl;
274     res = false;
275   }
276 
277   // calling with an empty string should return false
278   if (kwsys::SystemTools::PathExists(std::string())) {
279     std::cerr << "Problem with PathExists(std::string())" << std::endl;
280     res = false;
281   }
282   // PathExists(x) should return true on a directory
283   if (!kwsys::SystemTools::PathExists(testNewDir)) {
284     std::cerr << "Problem with PathExists for: " << testNewDir << std::endl;
285     res = false;
286   }
287   // should work, was created as new file before
288   if (!kwsys::SystemTools::PathExists(testNewFile)) {
289     std::cerr << "Problem with PathExists for: " << testNewFile << std::endl;
290     res = false;
291   }
292 
293 // Reset umask
294 #if defined(_WIN32) && !defined(__CYGWIN__)
295   // NOTE:  Windows doesn't support toggling _S_IREAD.
296   mode_t fullMask = _S_IWRITE;
297 #else
298   // On a normal POSIX platform, we can toggle all permissions.
299   mode_t fullMask = S_IRWXU | S_IRWXG | S_IRWXO;
300 #endif
301   mode_t orig_umask = umask(fullMask);
302 
303   // Test file permissions without umask
304   mode_t origPerm, thisPerm;
305   if (!kwsys::SystemTools::GetPermissions(testNewFile, origPerm)) {
306     std::cerr << "Problem with GetPermissions (1) for: " << testNewFile
307               << std::endl;
308     res = false;
309   }
310 
311   if (!kwsys::SystemTools::SetPermissions(testNewFile, 0)) {
312     std::cerr << "Problem with SetPermissions (1) for: " << testNewFile
313               << std::endl;
314     res = false;
315   }
316 
317   if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
318     std::cerr << "Problem with GetPermissions (2) for: " << testNewFile
319               << std::endl;
320     res = false;
321   }
322 
323   if ((thisPerm & fullMask) != 0) {
324     std::cerr << "SetPermissions failed to set permissions (1) for: "
325               << testNewFile << ": actual = " << thisPerm
326               << "; expected = " << 0 << std::endl;
327     res = false;
328   }
329 
330   // While we're at it, check proper TestFileAccess functionality.
331   if (kwsys::SystemTools::TestFileAccess(testNewFile,
332                                          kwsys::TEST_FILE_WRITE)) {
333     std::cerr
334       << "TestFileAccess incorrectly indicated that this is a writable file:"
335       << testNewFile << std::endl;
336     res = false;
337   }
338 
339   if (!kwsys::SystemTools::TestFileAccess(testNewFile, kwsys::TEST_FILE_OK)) {
340     std::cerr
341       << "TestFileAccess incorrectly indicated that this file does not exist:"
342       << testNewFile << std::endl;
343     res = false;
344   }
345 
346   // Test restoring/setting full permissions.
347   if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask)) {
348     std::cerr << "Problem with SetPermissions (2) for: " << testNewFile
349               << std::endl;
350     res = false;
351   }
352 
353   if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
354     std::cerr << "Problem with GetPermissions (3) for: " << testNewFile
355               << std::endl;
356     res = false;
357   }
358 
359   if ((thisPerm & fullMask) != fullMask) {
360     std::cerr << "SetPermissions failed to set permissions (2) for: "
361               << testNewFile << ": actual = " << thisPerm
362               << "; expected = " << fullMask << std::endl;
363     res = false;
364   }
365 
366   // Test setting file permissions while honoring umask
367   if (!kwsys::SystemTools::SetPermissions(testNewFile, fullMask, true)) {
368     std::cerr << "Problem with SetPermissions (3) for: " << testNewFile
369               << std::endl;
370     res = false;
371   }
372 
373   if (!kwsys::SystemTools::GetPermissions(testNewFile, thisPerm)) {
374     std::cerr << "Problem with GetPermissions (4) for: " << testNewFile
375               << std::endl;
376     res = false;
377   }
378 
379   if ((thisPerm & fullMask) != 0) {
380     std::cerr << "SetPermissions failed to honor umask for: " << testNewFile
381               << ": actual = " << thisPerm << "; expected = " << 0
382               << std::endl;
383     res = false;
384   }
385 
386   // Restore umask
387   umask(orig_umask);
388 
389   // Restore file permissions
390   if (!kwsys::SystemTools::SetPermissions(testNewFile, origPerm)) {
391     std::cerr << "Problem with SetPermissions (4) for: " << testNewFile
392               << std::endl;
393     res = false;
394   }
395 
396   // Remove the test file
397   if (!kwsys::SystemTools::RemoveFile(testNewFile)) {
398     std::cerr << "Problem with RemoveFile: " << testNewFile << std::endl;
399     res = false;
400   }
401 
402   std::string const testFileMissing(testNewDir + "/testMissingFile.txt");
403   if (!kwsys::SystemTools::RemoveFile(testFileMissing)) {
404     std::string const& msg = kwsys::SystemTools::GetLastSystemError();
405     std::cerr << "RemoveFile(\"" << testFileMissing << "\") failed: " << msg
406               << "\n";
407     res = false;
408   }
409 
410   std::string const testFileMissingDir(testNewDir + "/missing/file.txt");
411   if (!kwsys::SystemTools::RemoveFile(testFileMissingDir)) {
412     std::string const& msg = kwsys::SystemTools::GetLastSystemError();
413     std::cerr << "RemoveFile(\"" << testFileMissingDir << "\") failed: " << msg
414               << "\n";
415     res = false;
416   }
417 
418   kwsys::SystemTools::Touch(testNewFile.c_str(), true);
419   if (!kwsys::SystemTools::RemoveADirectory(testNewDir)) {
420     std::cerr << "Problem with RemoveADirectory for: " << testNewDir
421               << std::endl;
422     res = false;
423   }
424 
425 #ifdef KWSYS_TEST_SYSTEMTOOLS_LONG_PATHS
426   // Perform the same file and directory creation and deletion tests but
427   // with paths > 256 characters in length.
428 
429   const std::string testNewLongDir(
430     TEST_SYSTEMTOOLS_BINARY_DIR
431     "/"
432     "012345678901234567890123456789012345678901234567890123456789"
433     "012345678901234567890123456789012345678901234567890123456789"
434     "012345678901234567890123456789012345678901234567890123456789"
435     "012345678901234567890123456789012345678901234567890123456789"
436     "01234567890123");
437   const std::string testNewLongFile(
438     testNewLongDir +
439     "/"
440     "012345678901234567890123456789012345678901234567890123456789"
441     "012345678901234567890123456789012345678901234567890123456789"
442     "012345678901234567890123456789012345678901234567890123456789"
443     "012345678901234567890123456789012345678901234567890123456789"
444     "0123456789.txt");
445 
446   if (!kwsys::SystemTools::MakeDirectory(testNewLongDir)) {
447     std::cerr << "Problem with MakeDirectory for: " << testNewLongDir
448               << std::endl;
449     res = false;
450   }
451 
452   if (!kwsys::SystemTools::Touch(testNewLongFile.c_str(), true)) {
453     std::cerr << "Problem with Touch for: " << testNewLongFile << std::endl;
454     res = false;
455   }
456 
457   if (!kwsys::SystemTools::RemoveFile(testNewLongFile)) {
458     std::cerr << "Problem with RemoveFile: " << testNewLongFile << std::endl;
459     res = false;
460   }
461 
462   kwsys::SystemTools::Touch(testNewLongFile.c_str(), true);
463   if (!kwsys::SystemTools::RemoveADirectory(testNewLongDir)) {
464     std::cerr << "Problem with RemoveADirectory for: " << testNewLongDir
465               << std::endl;
466     res = false;
467   }
468 #endif
469 
470   return res;
471 }
472 
CheckStringOperations()473 static bool CheckStringOperations()
474 {
475   bool res = true;
476 
477   std::string test = "mary had a little lamb.";
478   if (kwsys::SystemTools::CapitalizedWords(test) !=
479       "Mary Had A Little Lamb.") {
480     std::cerr << "Problem with CapitalizedWords " << '"' << test << '"'
481               << std::endl;
482     res = false;
483   }
484 
485   test = "Mary Had A Little Lamb.";
486   if (kwsys::SystemTools::UnCapitalizedWords(test) !=
487       "mary had a little lamb.") {
488     std::cerr << "Problem with UnCapitalizedWords " << '"' << test << '"'
489               << std::endl;
490     res = false;
491   }
492 
493   test = "MaryHadTheLittleLamb.";
494   if (kwsys::SystemTools::AddSpaceBetweenCapitalizedWords(test) !=
495       "Mary Had The Little Lamb.") {
496     std::cerr << "Problem with AddSpaceBetweenCapitalizedWords " << '"' << test
497               << '"' << std::endl;
498     res = false;
499   }
500 
501   char* cres =
502     kwsys::SystemTools::AppendStrings("Mary Had A", " Little Lamb.");
503   if (strcmp(cres, "Mary Had A Little Lamb.")) {
504     std::cerr << "Problem with AppendStrings "
505               << "\"Mary Had A\" \" Little Lamb.\"" << std::endl;
506     res = false;
507   }
508   delete[] cres;
509 
510   cres = kwsys::SystemTools::AppendStrings("Mary Had", " A ", "Little Lamb.");
511   if (strcmp(cres, "Mary Had A Little Lamb.")) {
512     std::cerr << "Problem with AppendStrings "
513               << "\"Mary Had\" \" A \" \"Little Lamb.\"" << std::endl;
514     res = false;
515   }
516   delete[] cres;
517 
518   if (kwsys::SystemTools::CountChar("Mary Had A Little Lamb.", 'a') != 3) {
519     std::cerr << "Problem with CountChar "
520               << "\"Mary Had A Little Lamb.\"" << std::endl;
521     res = false;
522   }
523 
524   cres = kwsys::SystemTools::RemoveChars("Mary Had A Little Lamb.", "aeiou");
525   if (strcmp(cres, "Mry Hd A Lttl Lmb.")) {
526     std::cerr << "Problem with RemoveChars "
527               << "\"Mary Had A Little Lamb.\"" << std::endl;
528     res = false;
529   }
530   delete[] cres;
531 
532   cres = kwsys::SystemTools::RemoveCharsButUpperHex("Mary Had A Little Lamb.");
533   if (strcmp(cres, "A")) {
534     std::cerr << "Problem with RemoveCharsButUpperHex "
535               << "\"Mary Had A Little Lamb.\"" << std::endl;
536     res = false;
537   }
538   delete[] cres;
539 
540   char* cres2 = strdup("Mary Had A Little Lamb.");
541   kwsys::SystemTools::ReplaceChars(cres2, "aeiou", 'X');
542   if (strcmp(cres2, "MXry HXd A LXttlX LXmb.")) {
543     std::cerr << "Problem with ReplaceChars "
544               << "\"Mary Had A Little Lamb.\"" << std::endl;
545     res = false;
546   }
547   free(cres2);
548 
549   if (!kwsys::SystemTools::StringStartsWith("Mary Had A Little Lamb.",
550                                             "Mary ")) {
551     std::cerr << "Problem with StringStartsWith "
552               << "\"Mary Had A Little Lamb.\"" << std::endl;
553     res = false;
554   }
555 
556   if (!kwsys::SystemTools::StringEndsWith("Mary Had A Little Lamb.",
557                                           " Lamb.")) {
558     std::cerr << "Problem with StringEndsWith "
559               << "\"Mary Had A Little Lamb.\"" << std::endl;
560     res = false;
561   }
562 
563   cres = kwsys::SystemTools::DuplicateString("Mary Had A Little Lamb.");
564   if (strcmp(cres, "Mary Had A Little Lamb.")) {
565     std::cerr << "Problem with DuplicateString "
566               << "\"Mary Had A Little Lamb.\"" << std::endl;
567     res = false;
568   }
569   delete[] cres;
570 
571   test = "Mary Had A Little Lamb.";
572   if (kwsys::SystemTools::CropString(test, 13) != "Mary ...Lamb.") {
573     std::cerr << "Problem with CropString "
574               << "\"Mary Had A Little Lamb.\"" << std::endl;
575     res = false;
576   }
577 
578   std::vector<std::string> lines;
579   kwsys::SystemTools::Split("Mary Had A Little Lamb.", lines, ' ');
580   if (lines[0] != "Mary" || lines[1] != "Had" || lines[2] != "A" ||
581       lines[3] != "Little" || lines[4] != "Lamb.") {
582     std::cerr << "Problem with Split "
583               << "\"Mary Had A Little Lamb.\"" << std::endl;
584     res = false;
585   }
586 
587   if (kwsys::SystemTools::ConvertToWindowsOutputPath(
588         "L://Local Mojo/Hex Power Pack/Iffy Voodoo") !=
589       "\"L:\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") {
590     std::cerr << "Problem with ConvertToWindowsOutputPath "
591               << "\"L://Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
592     res = false;
593   }
594 
595   if (kwsys::SystemTools::ConvertToWindowsOutputPath(
596         "//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo") !=
597       "\"\\\\grayson\\Local Mojo\\Hex Power Pack\\Iffy Voodoo\"") {
598     std::cerr << "Problem with ConvertToWindowsOutputPath "
599               << "\"//grayson/Local Mojo/Hex Power Pack/Iffy Voodoo\""
600               << std::endl;
601     res = false;
602   }
603 
604   if (kwsys::SystemTools::ConvertToUnixOutputPath(
605         "//Local Mojo/Hex Power Pack/Iffy Voodoo") !=
606       "//Local\\ Mojo/Hex\\ Power\\ Pack/Iffy\\ Voodoo") {
607     std::cerr << "Problem with ConvertToUnixOutputPath "
608               << "\"//Local Mojo/Hex Power Pack/Iffy Voodoo\"" << std::endl;
609     res = false;
610   }
611 
612   return res;
613 }
614 
CheckPutEnv(const std::string & env,const char * name,const char * value)615 static bool CheckPutEnv(const std::string& env, const char* name,
616                         const char* value)
617 {
618   if (!kwsys::SystemTools::PutEnv(env)) {
619     std::cerr << "PutEnv(\"" << env << "\") failed!" << std::endl;
620     return false;
621   }
622   std::string v = "(null)";
623   kwsys::SystemTools::GetEnv(name, v);
624   if (v != value) {
625     std::cerr << "GetEnv(\"" << name << "\") returned \"" << v << "\", not \""
626               << value << "\"!" << std::endl;
627     return false;
628   }
629   return true;
630 }
631 
CheckUnPutEnv(const char * env,const char * name)632 static bool CheckUnPutEnv(const char* env, const char* name)
633 {
634   if (!kwsys::SystemTools::UnPutEnv(env)) {
635     std::cerr << "UnPutEnv(\"" << env << "\") failed!" << std::endl;
636     return false;
637   }
638   std::string v;
639   if (kwsys::SystemTools::GetEnv(name, v)) {
640     std::cerr << "GetEnv(\"" << name << "\") returned \"" << v
641               << "\", not (null)!" << std::endl;
642     return false;
643   }
644   return true;
645 }
646 
CheckEnvironmentOperations()647 static bool CheckEnvironmentOperations()
648 {
649   bool res = true;
650   res &= CheckPutEnv("A=B", "A", "B");
651   res &= CheckPutEnv("B=C", "B", "C");
652   res &= CheckPutEnv("C=D", "C", "D");
653   res &= CheckPutEnv("D=E", "D", "E");
654   res &= CheckUnPutEnv("A", "A");
655   res &= CheckUnPutEnv("B=", "B");
656   res &= CheckUnPutEnv("C=D", "C");
657   /* Leave "D=E" in environment so a memory checker can test for leaks.  */
658   return res;
659 }
660 
CheckRelativePath(const std::string & local,const std::string & remote,const std::string & expected)661 static bool CheckRelativePath(const std::string& local,
662                               const std::string& remote,
663                               const std::string& expected)
664 {
665   std::string result = kwsys::SystemTools::RelativePath(local, remote);
666   if (!kwsys::SystemTools::ComparePath(expected, result)) {
667     std::cerr << "RelativePath(" << local << ", " << remote << ")  yielded "
668               << result << " instead of " << expected << std::endl;
669     return false;
670   }
671   return true;
672 }
673 
CheckRelativePaths()674 static bool CheckRelativePaths()
675 {
676   bool res = true;
677   res &= CheckRelativePath("/usr/share", "/bin/bash", "../../bin/bash");
678   res &= CheckRelativePath("/usr/./share/", "/bin/bash", "../../bin/bash");
679   res &= CheckRelativePath("/usr//share/", "/bin/bash", "../../bin/bash");
680   res &=
681     CheckRelativePath("/usr/share/../bin/", "/bin/bash", "../../bin/bash");
682   res &= CheckRelativePath("/usr/share", "/usr/share//bin", "bin");
683   return res;
684 }
685 
CheckCollapsePath(const std::string & path,const std::string & expected)686 static bool CheckCollapsePath(const std::string& path,
687                               const std::string& expected)
688 {
689   std::string result = kwsys::SystemTools::CollapseFullPath(path);
690   if (!kwsys::SystemTools::ComparePath(expected, result)) {
691     std::cerr << "CollapseFullPath(" << path << ")  yielded " << result
692               << " instead of " << expected << std::endl;
693     return false;
694   }
695   return true;
696 }
697 
CheckCollapsePath()698 static bool CheckCollapsePath()
699 {
700   bool res = true;
701   res &= CheckCollapsePath("/usr/share/*", "/usr/share/*");
702   res &= CheckCollapsePath("C:/Windows/*", "C:/Windows/*");
703   res &= CheckCollapsePath("/usr/share/../lib", "/usr/lib");
704   res &= CheckCollapsePath("/usr/share/./lib", "/usr/share/lib");
705   res &= CheckCollapsePath("/usr/share/../../lib", "/lib");
706   res &= CheckCollapsePath("/usr/share/.././../lib", "/lib");
707   res &= CheckCollapsePath("/../lib", "/lib");
708   res &= CheckCollapsePath("/../lib/", "/lib");
709   res &= CheckCollapsePath("/", "/");
710   res &= CheckCollapsePath("C:/", "C:/");
711   res &= CheckCollapsePath("C:/../", "C:/");
712   res &= CheckCollapsePath("C:/../../", "C:/");
713   return res;
714 }
715 
StringVectorToString(const std::vector<std::string> & vec)716 static std::string StringVectorToString(const std::vector<std::string>& vec)
717 {
718   std::stringstream ss;
719   ss << "vector(";
720   for (std::vector<std::string>::const_iterator i = vec.begin();
721        i != vec.end(); ++i) {
722     if (i != vec.begin()) {
723       ss << ", ";
724     }
725     ss << *i;
726   }
727   ss << ")";
728   return ss.str();
729 }
730 
CheckGetPath()731 static bool CheckGetPath()
732 {
733   const char* envName = "S";
734 #ifdef _WIN32
735   const char* envValue = "C:\\Somewhere\\something;D:\\Temp";
736 #else
737   const char* envValue = "/Somewhere/something:/tmp";
738 #endif
739   const char* registryPath = "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MyApp; MyKey]";
740 
741   std::vector<std::string> originalPaths;
742   originalPaths.push_back(registryPath);
743 
744   std::vector<std::string> expectedPaths;
745   expectedPaths.push_back(registryPath);
746 #ifdef _WIN32
747   expectedPaths.push_back("C:/Somewhere/something");
748   expectedPaths.push_back("D:/Temp");
749 #else
750   expectedPaths.push_back("/Somewhere/something");
751   expectedPaths.push_back("/tmp");
752 #endif
753 
754   bool res = true;
755   res &= CheckPutEnv(std::string(envName) + "=" + envValue, envName, envValue);
756 
757   std::vector<std::string> paths = originalPaths;
758   kwsys::SystemTools::GetPath(paths, envName);
759 
760   if (paths != expectedPaths) {
761     std::cerr << "GetPath(" << StringVectorToString(originalPaths) << ", "
762               << envName << ")  yielded " << StringVectorToString(paths)
763               << " instead of " << StringVectorToString(expectedPaths)
764               << std::endl;
765     res = false;
766   }
767 
768   res &= CheckUnPutEnv(envName, envName);
769   return res;
770 }
771 
CheckGetFilenameName()772 static bool CheckGetFilenameName()
773 {
774   const char* windowsFilepath = "C:\\somewhere\\something";
775   const char* unixFilepath = "/somewhere/something";
776 
777 #if defined(_WIN32) || defined(KWSYS_SYSTEMTOOLS_SUPPORT_WINDOWS_SLASHES)
778   std::string expectedWindowsFilename = "something";
779 #else
780   std::string expectedWindowsFilename = "C:\\somewhere\\something";
781 #endif
782   std::string expectedUnixFilename = "something";
783 
784   bool res = true;
785   std::string filename = kwsys::SystemTools::GetFilenameName(windowsFilepath);
786   if (filename != expectedWindowsFilename) {
787     std::cerr << "GetFilenameName(" << windowsFilepath << ") yielded "
788               << filename << " instead of " << expectedWindowsFilename
789               << std::endl;
790     res = false;
791   }
792 
793   filename = kwsys::SystemTools::GetFilenameName(unixFilepath);
794   if (filename != expectedUnixFilename) {
795     std::cerr << "GetFilenameName(" << unixFilepath << ") yielded " << filename
796               << " instead of " << expectedUnixFilename << std::endl;
797     res = false;
798   }
799   return res;
800 }
801 
CheckFind()802 static bool CheckFind()
803 {
804   bool res = true;
805   const std::string testFindFileName("testFindFile.txt");
806   const std::string testFindFile(TEST_SYSTEMTOOLS_BINARY_DIR "/" +
807                                  testFindFileName);
808 
809   if (!kwsys::SystemTools::Touch(testFindFile.c_str(), true)) {
810     std::cerr << "Problem with Touch for: " << testFindFile << std::endl;
811     // abort here as the existence of the file only makes the test meaningful
812     return false;
813   }
814 
815   std::vector<std::string> searchPaths;
816   searchPaths.push_back(TEST_SYSTEMTOOLS_BINARY_DIR);
817   if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, true)
818         .empty()) {
819     std::cerr << "Problem with FindFile without system paths for: "
820               << testFindFileName << std::endl;
821     res = false;
822   }
823   if (kwsys::SystemTools::FindFile(testFindFileName, searchPaths, false)
824         .empty()) {
825     std::cerr << "Problem with FindFile with system paths for: "
826               << testFindFileName << std::endl;
827     res = false;
828   }
829 
830   return res;
831 }
832 
CheckIsSubDirectory()833 static bool CheckIsSubDirectory()
834 {
835   bool res = true;
836 
837   if (kwsys::SystemTools::IsSubDirectory("/foo", "/") == false) {
838     std::cerr << "Problem with IsSubDirectory (root - unix): " << std::endl;
839     res = false;
840   }
841   if (kwsys::SystemTools::IsSubDirectory("c:/foo", "c:/") == false) {
842     std::cerr << "Problem with IsSubDirectory (root - dos): " << std::endl;
843     res = false;
844   }
845   if (kwsys::SystemTools::IsSubDirectory("/foo/bar", "/foo") == false) {
846     std::cerr << "Problem with IsSubDirectory (deep): " << std::endl;
847     res = false;
848   }
849   if (kwsys::SystemTools::IsSubDirectory("/foo", "/foo") == true) {
850     std::cerr << "Problem with IsSubDirectory (identity): " << std::endl;
851     res = false;
852   }
853   if (kwsys::SystemTools::IsSubDirectory("/fooo", "/foo") == true) {
854     std::cerr << "Problem with IsSubDirectory (substring): " << std::endl;
855     res = false;
856   }
857   if (kwsys::SystemTools::IsSubDirectory("/foo/", "/foo") == true) {
858     std::cerr << "Problem with IsSubDirectory (prepended slash): "
859               << std::endl;
860     res = false;
861   }
862 
863   return res;
864 }
865 
CheckGetLineFromStream()866 static bool CheckGetLineFromStream()
867 {
868   const std::string fileWithFiveCharsOnFirstLine(TEST_SYSTEMTOOLS_SOURCE_DIR
869                                                  "/README.rst");
870 
871   kwsys::ifstream file(fileWithFiveCharsOnFirstLine.c_str(), std::ios::in);
872 
873   if (!file) {
874     std::cerr << "Problem opening: " << fileWithFiveCharsOnFirstLine
875               << std::endl;
876     return false;
877   }
878 
879   std::string line;
880   bool has_newline = false;
881   bool result;
882 
883   file.seekg(0, std::ios::beg);
884   result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
885   if (!result || line.size() != 5) {
886     std::cerr << "First line does not have five characters: " << line.size()
887               << std::endl;
888     return false;
889   }
890 
891   file.seekg(0, std::ios::beg);
892   result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline, -1);
893   if (!result || line.size() != 5) {
894     std::cerr << "First line does not have five characters after rewind: "
895               << line.size() << std::endl;
896     return false;
897   }
898 
899   bool ret = true;
900 
901   for (size_t size = 1; size <= 5; ++size) {
902     file.seekg(0, std::ios::beg);
903     result = kwsys::SystemTools::GetLineFromStream(file, line, &has_newline,
904                                                    static_cast<long>(size));
905     if (!result || line.size() != size) {
906       std::cerr << "Should have read " << size << " characters but got "
907                 << line.size() << std::endl;
908       ret = false;
909     }
910   }
911 
912   return ret;
913 }
914 
testSystemTools(int,char * [])915 int testSystemTools(int, char* [])
916 {
917   bool res = true;
918 
919   int cc;
920   for (cc = 0; toUnixPaths[cc][0]; cc++) {
921     res &= CheckConvertToUnixSlashes(toUnixPaths[cc][0], toUnixPaths[cc][1]);
922   }
923 
924   // Special check for ~
925   std::string output;
926   if (kwsys::SystemTools::GetEnv("HOME", output)) {
927     output += "/foo bar/lala";
928     res &= CheckConvertToUnixSlashes("~/foo bar/lala", output);
929   }
930 
931   for (cc = 0; checkEscapeChars[cc][0]; cc++) {
932     res &= CheckEscapeChars(checkEscapeChars[cc][0], checkEscapeChars[cc][1],
933                             *checkEscapeChars[cc][2], checkEscapeChars[cc][3]);
934   }
935 
936   res &= CheckFileOperations();
937 
938   res &= CheckStringOperations();
939 
940   res &= CheckEnvironmentOperations();
941 
942   res &= CheckRelativePaths();
943 
944   res &= CheckCollapsePath();
945 
946   res &= CheckGetPath();
947 
948   res &= CheckFind();
949 
950   res &= CheckIsSubDirectory();
951 
952   res &= CheckGetLineFromStream();
953 
954   res &= CheckGetFilenameName();
955 
956   return res ? 0 : 1;
957 }
958