Coverage Report

Created: 2026-03-12 06:35

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmPkgConfigResolver.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 "cmPkgConfigResolver.h"
5
6
#include <algorithm>
7
#include <cstring>
8
#include <iterator>
9
#include <string>
10
#include <unordered_map>
11
#include <utility>
12
#include <vector>
13
14
#include <cm/optional>
15
#include <cm/string_view>
16
17
#include "cmsys/String.h"
18
19
#include "cmPkgConfigParser.h"
20
#include "cmStringAlgorithms.h"
21
22
namespace {
23
24
void TrimBack(std::string& str)
25
0
{
26
0
  if (!str.empty()) {
27
0
    auto it = str.end() - 1;
28
0
    for (; cmsysString_isspace(*it); --it) {
29
0
      if (it == str.begin()) {
30
0
        str.clear();
31
0
        return;
32
0
      }
33
0
    }
34
0
    str.erase(++it, str.end());
35
0
  }
36
0
}
37
38
std::string AppendAndTrim(std::string& str, cm::string_view sv)
39
0
{
40
0
  auto size = str.length();
41
0
  str += sv;
42
0
  if (str.empty()) {
43
0
    return {};
44
0
  }
45
46
0
  auto begin = str.begin() + size;
47
0
  auto cur = str.end() - 1;
48
49
0
  while (cur != begin && cmsysString_isspace(*cur)) {
50
0
    --cur;
51
0
  }
52
53
0
  if (cmsysString_isspace(*cur)) {
54
0
    return {};
55
0
  }
56
57
0
  return { &*begin, static_cast<std::size_t>(cur - begin) + 1 };
58
0
}
59
60
cm::string_view TrimFlag(cm::string_view flag)
61
0
{
62
0
  std::size_t trim_size = 2;
63
0
  for (auto c = flag.rbegin(); c != flag.rend() && cmsysString_isspace(*c);
64
0
       ++c) {
65
0
    ++trim_size;
66
0
  }
67
0
  return { flag.data() + 2, flag.size() - trim_size };
68
0
}
69
70
} // namespace
71
72
std::string cmPkgConfigVersionReq::string() const
73
0
{
74
0
  switch (Operation) {
75
0
    case ANY:
76
0
      return "";
77
0
    case LT:
78
0
      return cmStrCat('<', Version);
79
0
    case LT_EQ:
80
0
      return cmStrCat("<=", Version);
81
0
    case EQ:
82
0
      return cmStrCat('=', Version);
83
0
    case NEQ:
84
0
      return cmStrCat("!=", Version);
85
0
    case GT_EQ:
86
0
      return cmStrCat(">=", Version);
87
0
    case GT:
88
0
      return cmStrCat('>', Version);
89
0
  }
90
0
  return "";
91
0
}
92
93
std::string cmPkgConfigResult::StrOrDefault(std::string const& key,
94
                                            cm::string_view def)
95
0
{
96
0
  auto it = Keywords.find(key);
97
0
  return it == Keywords.end() ? std::string{ def } : it->second;
98
0
};
99
100
std::string cmPkgConfigResult::Name()
101
0
{
102
0
  return StrOrDefault("Name");
103
0
}
104
105
std::string cmPkgConfigResult::Description()
106
0
{
107
0
  return StrOrDefault("Description");
108
0
}
109
110
std::string cmPkgConfigResult::Version()
111
0
{
112
0
  return StrOrDefault("Version");
113
0
}
114
115
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Conflicts()
116
0
{
117
0
  auto it = Keywords.find("Conflicts");
118
0
  if (it == Keywords.end()) {
119
0
    return {};
120
0
  }
121
122
0
  return cmPkgConfigResolver::ParseDependencies(it->second);
123
0
}
124
125
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Provides()
126
0
{
127
0
  auto it = Keywords.find("Provides");
128
0
  if (it == Keywords.end()) {
129
0
    return {};
130
0
  }
131
132
0
  return cmPkgConfigResolver::ParseDependencies(it->second);
133
0
}
134
135
std::vector<cmPkgConfigDependency> cmPkgConfigResult::Requires(bool priv)
136
0
{
137
0
  auto it = Keywords.find(priv ? "Requires.private" : "Requires");
138
0
  if (it == Keywords.end()) {
139
0
    return {};
140
0
  }
141
142
0
  return cmPkgConfigResolver::ParseDependencies(it->second);
143
0
}
144
145
cmPkgConfigCflagsResult cmPkgConfigResult::Cflags(bool priv)
146
0
{
147
0
  std::string cflags;
148
0
  auto it = Keywords.find(priv ? "Cflags.private" : "Cflags");
149
0
  if (it != Keywords.end()) {
150
0
    cflags += it->second;
151
0
  }
152
153
0
  it = Keywords.find(priv ? "CFlags.private" : "CFlags");
154
0
  if (it != Keywords.end()) {
155
0
    if (!cflags.empty()) {
156
0
      cflags += " ";
157
0
    }
158
0
    cflags += it->second;
159
0
  }
160
161
0
  auto tokens = cmPkgConfigResolver::TokenizeFlags(cflags);
162
163
0
  if (env->AllowSysCflags) {
164
0
    if (env->SysrootDir) {
165
0
      return cmPkgConfigResolver::MangleCflags(tokens, *env->SysrootDir);
166
0
    }
167
0
    return cmPkgConfigResolver::MangleCflags(tokens);
168
0
  }
169
170
0
  if (env->SysCflags) {
171
0
    if (env->SysrootDir) {
172
0
      return cmPkgConfigResolver::MangleCflags(tokens, *env->SysrootDir,
173
0
                                               *env->SysCflags);
174
0
    }
175
0
    return cmPkgConfigResolver::MangleCflags(tokens, *env->SysCflags);
176
0
  }
177
178
0
  if (env->SysrootDir) {
179
0
    return cmPkgConfigResolver::MangleCflags(
180
0
      tokens, *env->SysrootDir, std::vector<std::string>{ "/usr/include" });
181
0
  }
182
183
0
  return cmPkgConfigResolver::MangleCflags(
184
0
    tokens, std::vector<std::string>{ "/usr/include" });
185
0
}
186
187
cmPkgConfigLibsResult cmPkgConfigResult::Libs(bool priv)
188
0
{
189
0
  auto it = Keywords.find(priv ? "Libs.private" : "Libs");
190
0
  if (it == Keywords.end()) {
191
0
    return cmPkgConfigLibsResult();
192
0
  }
193
194
0
  auto tokens = cmPkgConfigResolver::TokenizeFlags(it->second);
195
196
0
  if (env->AllowSysLibs) {
197
0
    if (env->SysrootDir) {
198
0
      return cmPkgConfigResolver::MangleLibs(tokens, *env->SysrootDir);
199
0
    }
200
0
    return cmPkgConfigResolver::MangleLibs(tokens);
201
0
  }
202
203
0
  if (env->SysLibs) {
204
0
    if (env->SysrootDir) {
205
0
      return cmPkgConfigResolver::MangleLibs(tokens, *env->SysrootDir,
206
0
                                             *env->SysLibs);
207
0
    }
208
0
    return cmPkgConfigResolver::MangleLibs(tokens, *env->SysLibs);
209
0
  }
210
211
0
  if (env->SysrootDir) {
212
0
    return cmPkgConfigResolver::MangleLibs(
213
0
      tokens, *env->SysrootDir, std::vector<std::string>{ "/usr/lib" });
214
0
  }
215
216
0
  return cmPkgConfigResolver::MangleLibs(
217
0
    tokens, std::vector<std::string>{ "/usr/lib" });
218
0
}
219
220
void cmPkgConfigResolver::ReplaceSep(std::string& list)
221
0
{
222
0
#ifndef _WIN32
223
0
  std::replace(list.begin(), list.end(), ':', ';');
224
#else
225
  static_cast<void>(list); // Unused parameter
226
#endif
227
0
}
228
229
cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolveStrict(
230
  std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv env)
231
0
{
232
0
  cm::optional<cmPkgConfigResult> result;
233
0
  cmPkgConfigResult config;
234
0
  auto& keys = config.Keywords;
235
236
0
  if (env.SysrootDir) {
237
0
    config.Variables["pc_sysrootdir"] = *env.SysrootDir;
238
0
  } else {
239
0
    config.Variables["pc_sysrootdir"] = "/";
240
0
  }
241
242
0
  if (env.TopBuildDir) {
243
0
    config.Variables["pc_top_builddir"] = *env.TopBuildDir;
244
0
  }
245
246
0
  config.env = &env;
247
248
0
  for (auto const& entry : entries) {
249
0
    std::string key(entry.Key);
250
0
    if (entry.IsVariable) {
251
0
      if (config.Variables.find(key) != config.Variables.end()) {
252
0
        return result;
253
0
      }
254
0
      auto var = HandleVariableStrict(entry, config.Variables);
255
0
      if (!var) {
256
0
        return result;
257
0
      }
258
0
      config.Variables[key] = *var;
259
0
    } else {
260
0
      if (key == "Cflags" && keys.find("CFlags") != keys.end()) {
261
0
        return result;
262
0
      }
263
0
      if (key == "CFlags" && keys.find("Cflags") != keys.end()) {
264
0
        return result;
265
0
      }
266
0
      if (key == "Cflags.private" &&
267
0
          keys.find("CFlags.private") != keys.end()) {
268
0
        return result;
269
0
      }
270
0
      if (key == "CFlags.private" &&
271
0
          keys.find("Cflags.private") != keys.end()) {
272
0
        return result;
273
0
      }
274
0
      if (keys.find(key) != keys.end()) {
275
0
        return result;
276
0
      }
277
0
      keys[key] = HandleKeyword(entry, config.Variables);
278
0
    }
279
0
  }
280
281
0
  if (keys.find("Name") == keys.end() ||
282
0
      keys.find("Description") == keys.end() ||
283
0
      keys.find("Version") == keys.end()) {
284
0
    return result;
285
0
  }
286
287
0
  result = std::move(config);
288
0
  return result;
289
0
}
290
291
cm::optional<cmPkgConfigResult> cmPkgConfigResolver::ResolvePermissive(
292
  std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv env)
293
0
{
294
0
  cm::optional<cmPkgConfigResult> result;
295
296
0
  cmPkgConfigResult config = ResolveBestEffort(entries, std::move(env));
297
0
  auto const& keys = config.Keywords;
298
299
0
  if (keys.find("Name") == keys.end() ||
300
0
      keys.find("Description") == keys.end() ||
301
0
      keys.find("Version") == keys.end()) {
302
0
    return result;
303
0
  }
304
305
0
  result = std::move(config);
306
0
  return result;
307
0
}
308
309
cmPkgConfigResult cmPkgConfigResolver::ResolveBestEffort(
310
  std::vector<cmPkgConfigEntry> const& entries, cmPkgConfigEnv env)
311
0
{
312
0
  cmPkgConfigResult result;
313
314
0
  if (env.SysrootDir) {
315
0
    result.Variables["pc_sysrootdir"] = *env.SysrootDir;
316
0
  } else {
317
0
    result.Variables["pc_sysrootdir"] = "/";
318
0
  }
319
320
0
  if (env.TopBuildDir) {
321
0
    result.Variables["pc_top_builddir"] = *env.TopBuildDir;
322
0
  }
323
324
0
  result.env = &env;
325
326
0
  for (auto const& entry : entries) {
327
0
    std::string key(entry.Key);
328
0
    if (entry.IsVariable) {
329
0
      result.Variables[key] =
330
0
        HandleVariablePermissive(entry, result.Variables);
331
0
    } else {
332
0
      result.Keywords[key] += HandleKeyword(entry, result.Variables);
333
0
    }
334
0
  }
335
0
  return result;
336
0
}
337
338
std::string cmPkgConfigResolver::HandleVariablePermissive(
339
  cmPkgConfigEntry const& entry,
340
  std::unordered_map<std::string, std::string> const& variables)
341
0
{
342
0
  std::string result;
343
0
  for (auto const& segment : entry.Val) {
344
0
    if (!segment.IsVariable) {
345
0
      result += segment.Data;
346
0
    } else if (entry.Key != segment.Data) {
347
0
      auto it = variables.find(std::string{ segment.Data });
348
0
      if (it != variables.end()) {
349
0
        result += it->second;
350
0
      }
351
0
    }
352
0
  }
353
354
0
  TrimBack(result);
355
0
  return result;
356
0
}
357
358
cm::optional<std::string> cmPkgConfigResolver::HandleVariableStrict(
359
  cmPkgConfigEntry const& entry,
360
  std::unordered_map<std::string, std::string> const& variables)
361
0
{
362
0
  cm::optional<std::string> result;
363
364
0
  std::string value;
365
0
  for (auto const& segment : entry.Val) {
366
0
    if (!segment.IsVariable) {
367
0
      value += segment.Data;
368
0
    } else if (entry.Key == segment.Data) {
369
0
      return result;
370
0
    } else {
371
0
      auto it = variables.find(std::string{ segment.Data });
372
0
      if (it != variables.end()) {
373
0
        value += it->second;
374
0
      } else {
375
0
        return result;
376
0
      }
377
0
    }
378
0
  }
379
380
0
  TrimBack(value);
381
0
  result = std::move(value);
382
0
  return result;
383
0
}
384
385
std::string cmPkgConfigResolver::HandleKeyword(
386
  cmPkgConfigEntry const& entry,
387
  std::unordered_map<std::string, std::string> const& variables)
388
0
{
389
0
  std::string result;
390
0
  for (auto const& segment : entry.Val) {
391
0
    if (!segment.IsVariable) {
392
0
      result += segment.Data;
393
0
    } else {
394
0
      auto it = variables.find(std::string{ segment.Data });
395
0
      if (it != variables.end()) {
396
0
        result += it->second;
397
0
      }
398
0
    }
399
0
  }
400
401
0
  TrimBack(result);
402
0
  return result;
403
0
}
404
405
std::vector<cm::string_view> cmPkgConfigResolver::TokenizeFlags(
406
  std::string const& flagline)
407
0
{
408
0
  std::vector<cm::string_view> result;
409
410
0
  auto it = flagline.begin();
411
0
  while (it != flagline.end() && cmsysString_isspace(*it)) {
412
0
    ++it;
413
0
  }
414
415
0
  while (it != flagline.end()) {
416
0
    char const* start = &(*it);
417
0
    std::size_t len = 0;
418
419
0
    for (; it != flagline.end() && !cmsysString_isspace(*it); ++it) {
420
0
      ++len;
421
0
    }
422
423
0
    for (; it != flagline.end() && cmsysString_isspace(*it); ++it) {
424
0
      ++len;
425
0
    }
426
427
0
    result.emplace_back(start, len);
428
0
  }
429
430
0
  return result;
431
0
}
432
433
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
434
  std::vector<cm::string_view> const& flags)
435
0
{
436
0
  cmPkgConfigCflagsResult result;
437
438
0
  for (auto flag : flags) {
439
0
    if (flag.rfind("-I", 0) == 0) {
440
0
      result.Includes.emplace_back(AppendAndTrim(result.Flagline, flag));
441
0
    } else {
442
0
      result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
443
0
    }
444
0
  }
445
446
0
  return result;
447
0
}
448
449
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
450
  std::vector<cm::string_view> const& flags, std::string const& sysroot)
451
0
{
452
0
  cmPkgConfigCflagsResult result;
453
454
0
  for (auto flag : flags) {
455
0
    if (flag.rfind("-I", 0) == 0) {
456
0
      std::string reroot = Reroot(flag, "-I", sysroot);
457
0
      result.Includes.emplace_back(AppendAndTrim(result.Flagline, reroot));
458
0
    } else {
459
0
      result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
460
0
    }
461
0
  }
462
463
0
  return result;
464
0
}
465
466
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
467
  std::vector<cm::string_view> const& flags,
468
  std::vector<std::string> const& syspaths)
469
0
{
470
0
  cmPkgConfigCflagsResult result;
471
472
0
  for (auto flag : flags) {
473
0
    if (flag.rfind("-I", 0) == 0) {
474
0
      cm::string_view trimmed = TrimFlag(flag);
475
0
      if (std::all_of(
476
0
            syspaths.begin(), syspaths.end(),
477
0
            [&](std::string const& path) { return path != trimmed; })) {
478
0
        result.Includes.emplace_back(AppendAndTrim(result.Flagline, flag));
479
0
      }
480
481
0
    } else {
482
0
      result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
483
0
    }
484
0
  }
485
486
0
  return result;
487
0
}
488
489
cmPkgConfigCflagsResult cmPkgConfigResolver::MangleCflags(
490
  std::vector<cm::string_view> const& flags, std::string const& sysroot,
491
  std::vector<std::string> const& syspaths)
492
0
{
493
0
  cmPkgConfigCflagsResult result;
494
495
0
  for (auto flag : flags) {
496
0
    if (flag.rfind("-I", 0) == 0) {
497
0
      std::string reroot = Reroot(flag, "-I", sysroot);
498
0
      cm::string_view trimmed = TrimFlag(reroot);
499
0
      if (std::all_of(
500
0
            syspaths.begin(), syspaths.end(),
501
0
            [&](std::string const& path) { return path != trimmed; })) {
502
0
        result.Includes.emplace_back(AppendAndTrim(result.Flagline, reroot));
503
0
      }
504
505
0
    } else {
506
0
      result.CompileOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
507
0
    }
508
0
  }
509
510
0
  return result;
511
0
}
512
513
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
514
  std::vector<cm::string_view> const& flags)
515
0
{
516
0
  cmPkgConfigLibsResult result;
517
518
0
  for (auto flag : flags) {
519
0
    if (flag.rfind("-L", 0) == 0) {
520
0
      result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, flag));
521
0
    } else if (flag.rfind("-l", 0) == 0) {
522
0
      result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
523
0
    } else {
524
0
      result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
525
0
    }
526
0
  }
527
528
0
  return result;
529
0
}
530
531
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
532
  std::vector<cm::string_view> const& flags, std::string const& sysroot)
533
0
{
534
0
  cmPkgConfigLibsResult result;
535
536
0
  for (auto flag : flags) {
537
0
    if (flag.rfind("-L", 0) == 0) {
538
0
      std::string reroot = Reroot(flag, "-L", sysroot);
539
0
      result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, reroot));
540
0
    } else if (flag.rfind("-l", 0) == 0) {
541
0
      result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
542
0
    } else {
543
0
      result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
544
0
    }
545
0
  }
546
547
0
  return result;
548
0
}
549
550
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
551
  std::vector<cm::string_view> const& flags,
552
  std::vector<std::string> const& syspaths)
553
0
{
554
0
  cmPkgConfigLibsResult result;
555
556
0
  for (auto flag : flags) {
557
0
    if (flag.rfind("-L", 0) == 0) {
558
0
      cm::string_view trimmed = TrimFlag(flag);
559
0
      if (std::all_of(
560
0
            syspaths.begin(), syspaths.end(),
561
0
            [&](std::string const& path) { return path != trimmed; })) {
562
0
        result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, flag));
563
0
      }
564
565
0
    } else if (flag.rfind("-l", 0) == 0) {
566
0
      result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
567
0
    } else {
568
0
      result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
569
0
    }
570
0
  }
571
572
0
  return result;
573
0
}
574
575
cmPkgConfigLibsResult cmPkgConfigResolver::MangleLibs(
576
  std::vector<cm::string_view> const& flags, std::string const& sysroot,
577
  std::vector<std::string> const& syspaths)
578
0
{
579
0
  cmPkgConfigLibsResult result;
580
581
0
  for (auto flag : flags) {
582
0
    if (flag.rfind("-L", 0) == 0) {
583
0
      std::string reroot = Reroot(flag, "-L", sysroot);
584
0
      cm::string_view trimmed = TrimFlag(reroot);
585
0
      if (std::all_of(
586
0
            syspaths.begin(), syspaths.end(),
587
0
            [&](std::string const& path) { return path != trimmed; })) {
588
0
        result.LibDirs.emplace_back(AppendAndTrim(result.Flagline, reroot));
589
0
      }
590
591
0
    } else if (flag.rfind("-l", 0) == 0) {
592
0
      result.LibNames.emplace_back(AppendAndTrim(result.Flagline, flag));
593
0
    } else {
594
0
      result.LinkOptions.emplace_back(AppendAndTrim(result.Flagline, flag));
595
0
    }
596
0
  }
597
598
0
  return result;
599
0
}
600
601
std::string cmPkgConfigResolver::Reroot(cm::string_view flag,
602
                                        cm::string_view prefix,
603
                                        std::string const& sysroot)
604
0
{
605
0
  std::string result = std::string{ prefix };
606
0
  result += sysroot;
607
0
  result += cm::string_view{ flag.data() + prefix.length(),
608
0
                             flag.size() - prefix.length() };
609
0
  return result;
610
0
}
611
612
cmPkgConfigVersionReq cmPkgConfigResolver::ParseVersion(
613
  std::string::const_iterator& cur, std::string::const_iterator end)
614
0
{
615
0
  cmPkgConfigVersionReq result;
616
0
  if (*cur == '=') {
617
0
    result.Operation = result.EQ;
618
0
    ++cur;
619
0
  } else if (*cur == '>') {
620
0
    ++cur;
621
622
0
    if (cur == end) {
623
0
      result.Operation = result.GT;
624
0
      return result;
625
0
    }
626
627
0
    if (*cur == '=') {
628
0
      result.Operation = result.GT_EQ;
629
0
      ++cur;
630
0
    } else {
631
0
      result.Operation = result.GT;
632
0
    }
633
634
0
  } else if (*cur == '<') {
635
0
    ++cur;
636
637
0
    if (cur == end) {
638
0
      result.Operation = result.LT;
639
0
      return result;
640
0
    }
641
642
0
    if (*cur == '=') {
643
0
      result.Operation = result.LT_EQ;
644
0
      ++cur;
645
0
    } else {
646
0
      result.Operation = result.LT;
647
0
    }
648
649
0
  } else if (*cur == '!') {
650
0
    ++cur;
651
652
0
    if (cur == end) {
653
0
      result.Operation = result.ANY;
654
0
      return result;
655
0
    }
656
657
0
    if (*cur == '=') {
658
0
      result.Operation = result.NEQ;
659
0
      ++cur;
660
0
    } else {
661
0
      result.Operation = result.ANY;
662
0
    }
663
0
  }
664
665
0
  for (;; ++cur) {
666
0
    if (cur == end) {
667
0
      return result;
668
0
    }
669
670
0
    if (!cmsysString_isspace(*cur)) {
671
0
      break;
672
0
    }
673
0
  }
674
675
0
  for (; cur != end && !cmsysString_isspace(*cur) && *cur != ','; ++cur) {
676
0
    result.Version += *cur;
677
0
  }
678
679
0
  return result;
680
0
}
681
682
std::vector<cmPkgConfigDependency> cmPkgConfigResolver::ParseDependencies(
683
  std::string const& deps)
684
0
{
685
686
0
  std::vector<cmPkgConfigDependency> result;
687
688
0
  auto cur = deps.begin();
689
0
  auto end = deps.end();
690
691
0
  while (cur != end) {
692
0
    while ((cmsysString_isspace(*cur) || *cur == ',')) {
693
0
      if (++cur == end) {
694
0
        return result;
695
0
      }
696
0
    }
697
698
0
    result.emplace_back();
699
0
    auto& dep = result.back();
700
701
0
    while (!cmsysString_isspace(*cur) && *cur != ',') {
702
0
      dep.Name += *cur;
703
0
      if (++cur == end) {
704
0
        return result;
705
0
      }
706
0
    }
707
708
0
    auto in_operator = [&]() -> bool {
709
0
      for (;; ++cur) {
710
0
        if (cur == end) {
711
0
          return false;
712
0
        }
713
714
0
        if (*cur == '>' || *cur == '=' || *cur == '<' || *cur == '!') {
715
0
          return true;
716
0
        }
717
718
0
        if (!cmsysString_isspace(*cur)) {
719
0
          return false;
720
0
        }
721
0
      }
722
0
    };
723
724
0
    if (!in_operator()) {
725
0
      continue;
726
0
    }
727
728
0
    dep.VerReq = ParseVersion(cur, end);
729
0
  }
730
731
0
  return result;
732
0
}
733
734
bool cmPkgConfigResolver::CheckVersion(cmPkgConfigVersionReq const& desired,
735
                                       std::string const& provided)
736
0
{
737
738
0
  if (desired.Operation == cmPkgConfigVersionReq::ANY) {
739
0
    return true;
740
0
  }
741
742
  // https://blog.jasonantman.com/2014/07/how-yum-and-rpm-compare-versions/
743
744
0
  auto check_with_op = [&](int comp) -> bool {
745
0
    switch (desired.Operation) {
746
0
      case cmPkgConfigVersionReq::EQ:
747
0
        return comp == 0;
748
0
      case cmPkgConfigVersionReq::NEQ:
749
0
        return comp != 0;
750
0
      case cmPkgConfigVersionReq::GT:
751
0
        return comp < 0;
752
0
      case cmPkgConfigVersionReq::GT_EQ:
753
0
        return comp <= 0;
754
0
      case cmPkgConfigVersionReq::LT:
755
0
        return comp > 0;
756
0
      case cmPkgConfigVersionReq::LT_EQ:
757
0
        return comp >= 0;
758
0
      default:
759
0
        return true;
760
0
    }
761
0
  };
762
763
0
  if (desired.Version == provided) {
764
0
    return check_with_op(0);
765
0
  }
766
767
0
  auto a_cur = desired.Version.begin();
768
0
  auto a_end = desired.Version.end();
769
770
0
  auto b_cur = provided.begin();
771
0
  auto b_end = provided.end();
772
773
0
  while (a_cur != a_end && b_cur != b_end) {
774
0
    while (a_cur != a_end && !cmsysString_isalnum(*a_cur) && *a_cur != '~') {
775
0
      ++a_cur;
776
0
    }
777
778
0
    while (b_cur != b_end && !cmsysString_isalnum(*b_cur) && *b_cur != '~') {
779
0
      ++b_cur;
780
0
    }
781
782
0
    if (a_cur == a_end || b_cur == b_end) {
783
0
      break;
784
0
    }
785
786
0
    if (*a_cur == '~' || *b_cur == '~') {
787
0
      if (*a_cur != '~') {
788
0
        return check_with_op(1);
789
0
      }
790
791
0
      if (*b_cur != '~') {
792
0
        return check_with_op(-1);
793
0
      }
794
795
0
      ++a_cur;
796
0
      ++b_cur;
797
0
      continue;
798
0
    }
799
800
0
    auto a_seg = a_cur;
801
0
    auto b_seg = b_cur;
802
0
    bool is_num;
803
804
0
    if (cmsysString_isdigit(*a_cur)) {
805
0
      is_num = true;
806
0
      while (a_cur != a_end && cmsysString_isdigit(*a_cur)) {
807
0
        ++a_cur;
808
0
      }
809
810
0
      while (b_cur != b_end && cmsysString_isdigit(*b_cur)) {
811
0
        ++b_cur;
812
0
      }
813
814
0
    } else {
815
0
      is_num = false;
816
0
      while (a_cur != a_end && cmsysString_isalpha(*a_cur)) {
817
0
        ++a_cur;
818
0
      }
819
820
0
      while (b_cur != b_end && cmsysString_isalpha(*b_cur)) {
821
0
        ++b_cur;
822
0
      }
823
0
    }
824
825
0
    auto a_len = std::distance(a_seg, a_cur);
826
0
    auto b_len = std::distance(b_seg, b_cur);
827
828
0
    if (!b_len) {
829
0
      return check_with_op(is_num ? 1 : -1);
830
0
    }
831
832
0
    if (is_num) {
833
0
      while (a_seg != a_cur && *a_seg == '0') {
834
0
        ++a_seg;
835
0
      }
836
837
0
      while (b_seg != b_cur && *b_seg == '0') {
838
0
        ++b_seg;
839
0
      }
840
841
0
      a_len = std::distance(a_seg, a_cur);
842
0
      b_len = std::distance(b_seg, b_cur);
843
844
0
      if (a_len != b_len) {
845
0
        return check_with_op(a_len > b_len ? 1 : -1);
846
0
      }
847
848
0
      auto cmp = std::memcmp(&*a_seg, &*b_seg, a_len);
849
0
      if (cmp) {
850
0
        return check_with_op(cmp);
851
0
      }
852
0
    } else {
853
0
      auto cmp = std::memcmp(&*a_seg, &*b_seg, std::min(a_len, b_len));
854
0
      if (cmp) {
855
0
        return check_with_op(cmp);
856
0
      }
857
858
0
      if (a_len != b_len) {
859
0
        return check_with_op(a_len > b_len ? 1 : -1);
860
0
      }
861
0
    }
862
0
  }
863
864
0
  if (a_cur == a_end) {
865
0
    if (b_cur == b_end) {
866
0
      return check_with_op(0);
867
0
    }
868
0
    return check_with_op(-1);
869
0
  }
870
871
0
  return check_with_op(1);
872
0
}
873
874
cmPkgConfigVersionReq cmPkgConfigResolver::ParseVersion(
875
  std::string const& version)
876
0
{
877
0
  cmPkgConfigVersionReq result;
878
879
0
  auto cur = version.begin();
880
0
  auto end = version.end();
881
882
0
  if (cur == end) {
883
0
    result.Operation = cmPkgConfigVersionReq::EQ;
884
0
    return result;
885
0
  }
886
887
0
  result = ParseVersion(cur, end);
888
0
  cur = version.begin();
889
890
0
  if (*cur != '=' && *cur != '!' && *cur != '<' && *cur != '>') {
891
0
    result.Operation = cmPkgConfigVersionReq::EQ;
892
0
  }
893
894
0
  return result;
895
0
}