Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmCMakePath.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
4
#include "cmConfigure.h" // IWYU pragma: keep
5
6
#include "cmCMakePath.h"
7
8
#include <string>
9
10
#include "cmStringAlgorithms.h"
11
12
#if defined(_WIN32)
13
#  include <cstdlib>
14
#endif
15
16
#include <cm/filesystem>
17
#include <cm/string_view>
18
19
#if defined(_WIN32)
20
#  include <cmext/string_view>
21
22
#endif
23
24
cmCMakePath& cmCMakePath::ReplaceWideExtension(cm::string_view extension)
25
0
{
26
0
  auto file = this->Path.filename().string();
27
0
  if (!file.empty() && file != "." && file != "..") {
28
0
    auto pos = file.find('.', file[0] == '.' ? 1 : 0);
29
0
    if (pos != std::string::npos) {
30
0
      file.erase(pos);
31
0
    }
32
0
  }
33
0
  if (!extension.empty()) {
34
0
    if (extension[0] != '.') {
35
0
      file += '.';
36
0
    }
37
0
    file = cmStrCat(std::move(file), extension);
38
0
  }
39
0
  this->Path.replace_filename(file);
40
0
  return *this;
41
0
}
42
43
cmCMakePath cmCMakePath::GetWideExtension() const
44
0
{
45
0
  auto file = this->Path.filename().string();
46
0
  if (file.empty() || file == "." || file == "..") {
47
0
    return cmCMakePath{};
48
0
  }
49
50
0
  auto pos = file.find('.', file[0] == '.' ? 1 : 0);
51
0
  if (pos != std::string::npos) {
52
0
    return cm::string_view(file.data() + pos, file.length() - pos);
53
0
  }
54
55
0
  return cmCMakePath{};
56
0
}
57
58
cmCMakePath cmCMakePath::GetNarrowStem() const
59
0
{
60
0
  auto stem = this->Path.stem().string();
61
0
  if (stem.empty() || stem == "." || stem == "..") {
62
0
    return stem;
63
0
  }
64
65
0
  auto pos = stem.find('.', stem[0] == '.' ? 1 : 0);
66
0
  if (pos != std::string::npos) {
67
0
    return stem.substr(0, pos);
68
0
  }
69
0
  return stem;
70
0
}
71
72
cmCMakePath cmCMakePath::Absolute(cm::filesystem::path const& base) const
73
0
{
74
0
  if (this->Path.is_relative()) {
75
0
    auto path = base;
76
0
    path /= this->Path;
77
    // filesystem::path::operator/= use preferred_separator ('\' on Windows)
78
    // so converts back to '/'
79
0
    return path.generic_string();
80
0
  }
81
0
  return *this;
82
0
}
83
84
bool cmCMakePath::IsPrefix(cmCMakePath const& path) const
85
0
{
86
0
  auto prefix_it = this->Path.begin();
87
0
  auto prefix_end = this->Path.end();
88
0
  auto path_it = path.Path.begin();
89
0
  auto path_end = path.Path.end();
90
91
0
  while (prefix_it != prefix_end && path_it != path_end &&
92
0
         *prefix_it == *path_it) {
93
0
    ++prefix_it;
94
0
    ++path_it;
95
0
  }
96
0
  return (prefix_it == prefix_end) ||
97
0
    (prefix_it->empty() && path_it != path_end);
98
0
}
99
100
std::string cmCMakePath::FormatPath(std::string path, format fmt)
101
1.39k
{
102
#if defined(_WIN32)
103
  if (fmt == auto_format || fmt == native_format) {
104
    auto prefix = path.substr(0, 4);
105
    for (auto& c : prefix) {
106
      if (c == '\\') {
107
        c = '/';
108
      }
109
    }
110
    // remove Windows long filename marker
111
    if (prefix == "//?/"_s) {
112
      path.erase(0, 4);
113
    }
114
    if (cmHasPrefix(path, "UNC/"_s) || cmHasPrefix(path, "UNC\\"_s)) {
115
      path.erase(0, 2);
116
      path[0] = '/';
117
    }
118
  }
119
#else
120
1.39k
  static_cast<void>(fmt);
121
1.39k
#endif
122
1.39k
  return path;
123
1.39k
}
124
125
void cmCMakePath::GetNativePath(std::string& path) const
126
0
{
127
0
  cm::filesystem::path tmp(this->Path);
128
0
  tmp.make_preferred();
129
130
0
  path = tmp.string();
131
0
}
132
void cmCMakePath::GetNativePath(std::wstring& path) const
133
0
{
134
0
  cm::filesystem::path tmp(this->Path);
135
0
  tmp.make_preferred();
136
137
0
  path = tmp.wstring();
138
139
#if defined(_WIN32)
140
  // Windows long filename
141
  static std::wstring UNC(L"\\\\?\\UNC");
142
  static std::wstring PREFIX(L"\\\\?\\");
143
144
  if (this->IsAbsolute() && path.length() > _MAX_PATH - 12) {
145
    if (this->HasRootName() && path[0] == L'\\') {
146
      path = UNC + path.substr(1);
147
    } else {
148
      path = PREFIX + path;
149
    }
150
  }
151
#endif
152
0
}