• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

STEllAR-GROUP / hpx / #856

28 Dec 2022 02:00AM UTC coverage: 86.602% (+0.05%) from 86.55%
#856

push

StellarBot
Merge #6119

6119: Update CMakeLists.txt r=hkaiser a=khuck

updating the default APEX version


Co-authored-by: Kevin Huck <khuck@cs.uoregon.edu>

174566 of 201573 relevant lines covered (86.6%)

1876093.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.91
/libs/core/ini/src/ini.cpp
1
//  Copyright (c) 2005-2007 Andre Merzky
2
//  Copyright (c) 2005-2022 Hartmut Kaiser
3
//  Copyright (c)      2011 Bryce Lelbach
4
//
5
//  SPDX-License-Identifier: BSL-1.0
6
//  Distributed under the Boost Software License, Version 1.0. (See accompanying
7
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8

9
#include <hpx/config.hpp>
10

11
// System Header Files
12
#include <cerrno>
13
#include <cstddef>
14
#include <cstdint>
15
#include <cstdio>
16
#include <cstdlib>
17
#include <cstring>
18
#include <fstream>
19
#include <iostream>
20
#include <list>
21
#include <mutex>
22
#include <regex>
23
#include <string>
24
#include <type_traits>
25
#include <utility>
26
#include <vector>
27

28
#include <hpx/assert.hpp>
29
#include <hpx/ini/ini.hpp>
30
#include <hpx/modules/errors.hpp>
31
#include <hpx/serialization/map.hpp>
32
#include <hpx/serialization/serialize.hpp>
33
#include <hpx/string_util/classification.hpp>
34
#include <hpx/string_util/split.hpp>
35
#include <hpx/thread_support/unlock_guard.hpp>
36

37
#ifdef __APPLE__
38
#include <crt_externs.h>
39
#define environ (*_NSGetEnviron())
40
#elif !defined(HPX_WINDOWS)
41
extern char** environ;
42
#endif
43

44
///////////////////////////////////////////////////////////////////////////////
45
namespace hpx::util {
46

47
    ///////////////////////////////////////////////////////////////////////////////
48
    // example ini line: line # comment
49
    inline constexpr char const pattern_comment[] = "^([^#]*)(#.*)$";
50
    ///////////////////////////////////////////////////////////////////////////////
51

52
    namespace detail {
53

54
        ///////////////////////////////////////////////////////////////////////////
55
        inline std::string trim_whitespace(std::string const& s)
2,922,890✔
56
        {
57
            typedef std::string::size_type size_type;
58

59
            size_type first = s.find_first_not_of(" \t\r\n");
2,922,890✔
60
            if (std::string::npos == first)
2,922,890✔
61
                return (std::string());
7,103✔
62

63
            size_type last = s.find_last_not_of(" \t\r\n");
2,915,787✔
64
            return s.substr(first, last - first + 1);
2,915,787✔
65
        }
2,922,890✔
66

67
        // MSVC: using std::string::replace triggers ASAN reports
68
        std::string replace_substr(std::string const& str,
299,687✔
69
            std::size_t start_pos, std::size_t oldlen, char const* newstr)
70
        {
71
            std::string result(str.substr(0, start_pos));
299,687✔
72
            result += newstr;
299,687✔
73
            result += str.substr(start_pos + oldlen);
299,687✔
74
            return result;
299,687✔
75
        }
299,687✔
76

77
        std::string replace_substr(std::string const& str,
292,361✔
78
            std::size_t start_pos, std::size_t oldlen,
79
            std::string const& newstr)
80
        {
81
            return replace_substr(str, start_pos, oldlen, newstr.c_str());
292,361✔
82
        }
83
    }    // namespace detail
84

85
    ///////////////////////////////////////////////////////////////////////////////
86
    section::section() noexcept
1,129,104✔
87
      : root_(this_())
1,129,104✔
88
    {
89
    }
1,129,104✔
90

91
    section::section(std::string const& filename, section* root)
×
92
      : root_(nullptr != root ? root : this_())
×
93
      , name_(filename)
×
94
    {
95
        read(filename);
×
96
    }
×
97

98
    section::section(section const& in)
2,045,866✔
99
      : root_(this_())
1,022,933✔
100
      , name_(in.get_name())
1,022,933✔
101
      , parent_name_(in.get_parent_name())
1,022,933✔
102
    {
103
        entry_map const& e = in.get_entries();
1,022,933✔
104
        entry_map::const_iterator end = e.end();
1,022,933✔
105
        for (entry_map::const_iterator i = e.begin(); i != end; ++i)
5,493,188✔
106
            add_entry(i->first, i->second);
4,470,255✔
107

108
        section_map s = in.get_sections();
1,022,933✔
109
        section_map::iterator send = s.end();
1,022,933✔
110
        for (section_map::iterator si = s.begin(); si != send; ++si)
1,540,491✔
111
            add_section(si->first, si->second, get_root());
517,558✔
112
    }
1,022,933✔
113

114
    section& section::operator=(section const& rhs)
1,803✔
115
    {
116
        if (this != &rhs)
1,803✔
117
        {
118
            std::unique_lock<mutex_type> l(mtx_);
1,803✔
119

120
            root_ = this;
1,803✔
121
            parent_name_ = rhs.get_parent_name();
1,803✔
122
            name_ = rhs.get_name();
1,803✔
123

124
            entry_map const& e = rhs.get_entries();
1,803✔
125
            entry_map::const_iterator end = e.end();
1,803✔
126
            for (entry_map::const_iterator i = e.begin(); i != end; ++i)
5,295✔
127
                add_entry(l, i->first, i->first, i->second);
3,492✔
128

129
            section_map s = rhs.get_sections();
1,803✔
130
            section_map::iterator send = s.end();
1,803✔
131
            for (section_map::iterator si = s.begin(); si != send; ++si)
5,466✔
132
                add_section(l, si->first, si->second, get_root());
3,663✔
133
        }
1,803✔
134
        return *this;
1,803✔
135
    }
×
136

137
    section& section::clone_from(section const& rhs, section* root)
1,070,254✔
138
    {
139
        if (this != &rhs)
1,070,254✔
140
        {
141
            std::unique_lock<mutex_type> l(mtx_);
1,070,254✔
142

143
            root_ = root ? root : this;
1,070,254✔
144
            parent_name_ = rhs.get_parent_name();
1,070,254✔
145
            name_ = rhs.get_name();
1,070,254✔
146

147
            entry_map const& e = rhs.get_entries();
1,070,254✔
148
            entry_map::const_iterator end = e.end();
1,070,254✔
149
            for (entry_map::const_iterator i = e.begin(); i != end; ++i)
5,540,509✔
150
                add_entry(l, i->first, i->first, i->second);
4,470,255✔
151

152
            section_map s = rhs.get_sections();
1,070,254✔
153
            section_map::iterator send = s.end();
1,070,254✔
154
            for (section_map::iterator si = s.begin(); si != send; ++si)
1,564,043✔
155
                add_section(l, si->first, si->second, get_root());
493,789✔
156
        }
1,070,254✔
157
        return *this;
1,070,254✔
158
    }
×
159

160
    void section::read(std::string const& filename)
×
161
    {
162
#if defined(__AIX__) && defined(__GNUC__)
163
        // NEVER ask why... seems to be some weird stdlib initialization problem
164
        // If you don't call getline() here the while(getline...) loop below will
165
        // crash with a bad_cast exception. Stupid AIX...
166
        std::string l1;
167
        std::ifstream i1;
168
        i1.open(filename.c_str(), std::ios::in);
169
        std::getline(i1, l1);
170
        i1.close();
171
#endif
172

173
        // build ini - open file and parse each line
174
        std::ifstream input(filename.c_str(), std::ios::in);
×
175
        if (!input.is_open())
×
176
            line_msg("Cannot open file: ", filename);
×
177

178
        // read file
179
        std::string line;
×
180
        std::vector<std::string> lines;
×
181
        while (std::getline(input, line))
×
182
            lines.push_back(line);
×
183

184
        // parse file
185
        parse(filename, lines, false);
×
186
    }
×
187

188
    bool force_entry(std::string& str)
916,549✔
189
    {
190
        std::string::size_type p = str.find_last_of('!');
916,549✔
191
        if (p != std::string::npos &&
916,549✔
192
            str.find_first_not_of(" \t", p + 1) == std::string::npos)
24,967✔
193
        {
194
            str = str.substr(0, p);    // remove forcing modifier ('!')
24,967✔
195
            return true;
24,967✔
196
        }
197
        return false;
891,582✔
198
    }
916,549✔
199

200
    // parse file
201
    void section::parse(std::string const& sourcename,
19,249✔
202
        std::vector<std::string> const& lines, bool verify_existing,
203
        bool weed_out_comments, bool replace_existing)
204
    {
205
        int linenum = 0;
19,249✔
206
        section* current = this;
19,249✔
207

208
        std::regex regex_comment(pattern_comment, std::regex_constants::icase);
19,249✔
209

210
        std::vector<std::string>::const_iterator end = lines.end();
19,249✔
211
        for (std::vector<std::string>::const_iterator it = lines.begin();
1,109,041✔
212
             it != end; ++it)
1,109,041✔
213
        {
214
            ++linenum;
1,089,792✔
215

216
            // remove trailing new lines and white spaces
217
            std::string line(detail::trim_whitespace(*it));
1,089,792✔
218

219
            // skip if empty line
220
            if (line.empty())
1,089,792✔
221
                continue;
2,986✔
222

223
            // weed out comments
224
            if (weed_out_comments)
1,086,806✔
225
            {
226
                std::smatch what_comment;
594✔
227
                if (std::regex_match(line, what_comment, regex_comment))
594✔
228
                {
229
                    HPX_ASSERT(3 == what_comment.size());
×
230

231
                    line = detail::trim_whitespace(what_comment[1]);
×
232
                    if (line.empty())
×
233
                        continue;
×
234
                }
×
235
            }
594✔
236
            // no comments anymore: line is either section, key=val,
237
            // or garbage/empty
238

239
            // Check if we have a section.
240
            // Example: [sec.ssec]
241
            if (line.front() == '[' && line.back() == ']')
1,086,806✔
242
            {
243
                current = this;    // start adding sections at the root
170,257✔
244

245
                // got the section name. It might be hierarchical, so split it up, and
246
                // for each elem, check if we have it.  If not, create it, and add
247
                std::string sec_name(line.substr(1, line.size() - 2));
170,257✔
248
                std::string::size_type pos = 0;
170,257✔
249
                for (std::string::size_type pos1 = sec_name.find_first_of('.');
459,235✔
250
                     std::string::npos != pos1;
459,235✔
251
                     pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
288,978✔
252
                {
253
                    current = current->add_section_if_new(
288,978✔
254
                        sec_name.substr(pos, pos1 - pos));
288,978✔
255
                }
288,978✔
256

257
                current = current->add_section_if_new(sec_name.substr(pos));
170,257✔
258
                continue;
259
            }
170,257✔
260

261
            // Check if we have a key=val entry...
262
            std::string::size_type assign_pos = line.find('=');
916,549✔
263
            if (assign_pos != std::string::npos)
916,549✔
264
            {
265
                std::string sec_key =
266
                    detail::trim_whitespace(line.substr(0, assign_pos));
916,549✔
267
                std::string value = detail::trim_whitespace(
916,549✔
268
                    line.substr(assign_pos + 1, line.size() - assign_pos - 1));
916,549✔
269

270
                section* s = current;    // save the section we're in
916,549✔
271
                current = this;          // start adding sections at the root
916,549✔
272

273
                std::string::size_type pos = 0;
916,549✔
274
                // Check if we have a qualified key name
275
                // Example: hpx.commandline.allow_unknown
276
                for (std::string::size_type dot_pos =
1,068,546✔
277
                         sec_key.find_first_of('.');
916,549✔
278
                     std::string::npos != dot_pos;
1,068,546✔
279
                     dot_pos = sec_key.find_first_of('.', pos = dot_pos + 1))
151,997✔
280
                {
281
                    current = current->add_section_if_new(
151,997✔
282
                        sec_key.substr(pos, dot_pos - pos));
151,997✔
283
                }
151,997✔
284

285
                // if we don't have section qualifiers, restore current...
286
                if (current == this)
916,549✔
287
                {
288
                    current = s;
826,998✔
289
                }
826,998✔
290

291
                std::string key = sec_key.substr(pos);
916,549✔
292

293
                // add key/val to this section
294
                std::unique_lock<mutex_type> l(current->mtx_);
916,549✔
295

296
                if (!force_entry(key) && verify_existing &&
981,133✔
297
                    !current->has_entry(l, key))
64,584✔
298
                {
299
                    line_msg("Attempt to initialize unknown entry: ",
×
300
                        sourcename, linenum, line);
×
301
                }
×
302

303
                if (replace_existing || !current->has_entry(l, key))
916,549✔
304
                {
305
                    current->add_entry(l, key, key, value);
468,115✔
306
                }
468,115✔
307

308
                // restore the old section
309
                current = s;
916,549✔
310
            }
916,549✔
311
            else
312
            {
313
                // Hmm, is not a section, is not an entry, is not empty - must be
314
                // an error!
315
                line_msg("Cannot parse line at: ", sourcename, linenum, line);
×
316
            }
317
        }
1,089,792✔
318
    }
19,249✔
319

320
    ///////////////////////////////////////////////////////////////////////////////
321
    void section::add_section(std::unique_lock<mutex_type>& /* l */,
1,070,254✔
322
        std::string const& sec_name, section& sec, section* root)
323
    {
324
        // setting name and root
325
        sec.name_ = sec_name;
1,070,254✔
326
        sec.parent_name_ = get_full_name();
1,070,254✔
327

328
        section& newsec = sections_[sec_name];
1,070,254✔
329
        newsec.clone_from(sec, (nullptr != root) ? root : get_root());
1,070,254✔
330
    }
1,070,254✔
331

332
    ///////////////////////////////////////////////////////////////////////////
333
    section* section::add_section_if_new(
612,998✔
334
        std::unique_lock<mutex_type>& l, std::string const& sec_name)
335
    {
336
        // do we know this one?
337
        if (!has_section(l, sec_name))
612,998✔
338
        {
339
            // no - add it!
340
            section sec;
55,244✔
341
            add_section(l, sec_name, sec, get_root());
55,244✔
342
        }
55,244✔
343

344
        return get_section(l, sec_name);
612,998✔
345
    }
×
346

347
    bool section::has_section(
739,403✔
348
        std::unique_lock<mutex_type>& l, std::string const& sec_name) const
349
    {
350
        std::string::size_type i = sec_name.find('.');
739,403✔
351
        if (i != std::string::npos)
739,403✔
352
        {
353
            std::string cor_sec_name = sec_name.substr(0, i);
74,990✔
354

355
            section_map::const_iterator it = sections_.find(cor_sec_name);
74,990✔
356
            if (it != sections_.end())
74,990✔
357
            {
358
                std::string sub_sec_name = sec_name.substr(i + 1);
74,990✔
359
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
74,990✔
360
                return (*it).second.has_section(sub_sec_name);
74,990✔
361
            }
74,990✔
362
            return false;
×
363
        }
74,990✔
364
        return sections_.find(sec_name) != sections_.end();
664,413✔
365
    }
739,403✔
366

367
    section* section::get_section(
673,566✔
368
        std::unique_lock<mutex_type>& l, std::string const& sec_name)
369
    {
370
        std::string::size_type i = sec_name.find('.');
673,566✔
371
        if (i != std::string::npos)
673,566✔
372
        {
373
            std::string cor_sec_name = sec_name.substr(0, i);
39,494✔
374
            section_map::iterator it = sections_.find(cor_sec_name);
39,494✔
375
            if (it != sections_.end())
39,494✔
376
            {
377
                std::string sub_sec_name = sec_name.substr(i + 1);
39,494✔
378
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
39,494✔
379
                return (*it).second.get_section(sub_sec_name);
39,494✔
380
            }
39,494✔
381

382
            std::string name(get_name());
×
383
            if (name.empty())
×
384
                name = "<root>";
×
385

386
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
387
                "section::get_section", "No such section ({}) in section: {}",
388
                sec_name, name);
389
            return nullptr;
390
        }
39,494✔
391

392
        section_map::iterator it = sections_.find(sec_name);
634,072✔
393
        if (it != sections_.end())
634,072✔
394
            return &((*it).second);
634,072✔
395

396
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section",
×
397
            "No such section ({}) in section: {}", sec_name, get_name());
398
        return nullptr;
399
    }
673,566✔
400

401
    section const* section::get_section(
162,043✔
402
        std::unique_lock<mutex_type>& l, std::string const& sec_name) const
403
    {
404
        std::string::size_type i = sec_name.find('.');
162,043✔
405
        if (i != std::string::npos)
162,043✔
406
        {
407
            std::string cor_sec_name = sec_name.substr(0, i);
88,236✔
408
            section_map::const_iterator it = sections_.find(cor_sec_name);
88,236✔
409
            if (it != sections_.end())
88,236✔
410
            {
411
                std::string sub_sec_name = sec_name.substr(i + 1);
88,236✔
412
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
88,236✔
413
                return (*it).second.get_section(sub_sec_name);
88,236✔
414
            }
88,236✔
415

416
            std::string name(get_name());
×
417
            if (name.empty())
×
418
                name = "<root>";
×
419

420
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter,
×
421
                "section::get_section", "No such section ({}) in section: {}",
422
                sec_name, name);
423
            return nullptr;
424
        }
88,236✔
425

426
        section_map::const_iterator it = sections_.find(sec_name);
73,807✔
427
        if (it != sections_.end())
73,807✔
428
            return &((*it).second);
73,807✔
429

430
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section",
×
431
            "No such section ({}) in section: {}", sec_name, get_name());
432
        return nullptr;
433
    }
162,043✔
434

435
    void section::add_entry(std::unique_lock<mutex_type>& l,
468,894✔
436
        std::string const& fullkey, std::string const& key, std::string val)
437
    {
438
        // first expand the full property name in the value (avoids infinite recursion)
439
        expand_only(
468,894✔
440
            l, val, std::string::size_type(-1), get_full_name() + "." + key);
468,894✔
441

442
        std::string::size_type i = key.find_last_of('.');
468,894✔
443
        if (i != std::string::npos)
468,894✔
444
        {
445
            section* current = root_;
20✔
446

447
            // make sure all sections in key exist
448
            std::string sec_name = key.substr(0, i);
20✔
449

450
            std::string::size_type pos = 0;
20✔
451
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
44✔
452
                 std::string::npos != pos1;
44✔
453
                 pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
24✔
454
            {
455
                current = current->add_section_if_new(
24✔
456
                    l, sec_name.substr(pos, pos1 - pos));
24✔
457
            }
24✔
458

459
            current = current->add_section_if_new(l, sec_name.substr(pos));
20✔
460

461
            // now add this entry to the section
462
            current->add_entry(l, fullkey, key.substr(i + 1), val);
20✔
463
        }
20✔
464
        else
465
        {
466
            entry_map::iterator it = entries_.find(key);
468,874✔
467
            if (it != entries_.end())
468,874✔
468
            {
469
                auto& e = it->second;
215,640✔
470
                e.first = HPX_MOVE(val);
215,640✔
471
                if (!e.second.empty())
215,640✔
472
                {
473
                    std::string value = e.first;
2✔
474
                    entry_changed_func f = e.second;
2✔
475

476
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
2✔
477
                    f(fullkey, value);
2✔
478
                }
2✔
479
            }
215,640✔
480
            else
481
            {
482
                // just add this entry to the section
483
                entries_[key] = entry_type(val, entry_changed_func());
253,234✔
484
            }
485
        }
486
    }
468,894✔
487

488
    void section::add_entry(std::unique_lock<mutex_type>& l,
8,944,002✔
489
        std::string const& fullkey, std::string const& key,
490
        entry_type const& val)
491
    {
492
        std::string::size_type i = key.find_last_of('.');
8,944,002✔
493
        if (i != std::string::npos)
8,944,002✔
494
        {
495
            section* current = root_;
×
496

497
            // make sure all sections in key exist
498
            std::string sec_name = key.substr(0, i);
×
499

500
            std::string::size_type pos = 0;
×
501
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
×
502
                 std::string::npos != pos1;
×
503
                 pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
×
504
            {
505
                current = current->add_section_if_new(
×
506
                    l, sec_name.substr(pos, pos1 - pos));
×
507
            }
×
508

509
            current = current->add_section_if_new(l, sec_name.substr(pos));
×
510

511
            // now add this entry to the section
512
            current->add_entry(l, fullkey, key.substr(i + 1), val);
×
513
        }
×
514
        else
515
        {
516
            entry_map::iterator it = entries_.find(key);
8,944,002✔
517
            if (it != entries_.end())
8,944,002✔
518
            {
519
                it->second = val;
×
520
                if (!it->second.second.empty())
×
521
                {
522
                    std::string value = it->second.first;
×
523
                    entry_changed_func f = it->second.second;
×
524

525
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
×
526
                    f(fullkey, value);
×
527
                }
×
528
            }
×
529
            else
530
            {
531
                // just add this entry to the section
532
                std::pair<entry_map::iterator, bool> p =
533
                    entries_.insert(entry_map::value_type(key, val));
8,944,002✔
534
                HPX_ASSERT(p.second);
8,944,002✔
535

536
                if (!p.first->second.second.empty())
8,944,002✔
537
                {
538
                    std::string key = p.first->first;
×
539
                    std::string value = p.first->second.first;
×
540
                    entry_changed_func f = p.first->second.second;
×
541

542
                    hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
×
543
                    f(key, value);
×
544
                }
×
545
            }
546
        }
547
    }
8,944,002✔
548

549
    ///////////////////////////////////////////////////////////////////////////////
550
    template <typename F1, typename F2>
551
    class compose_callback_impl
34✔
552
    {
553
    public:
554
        template <typename A1, typename A2>
555
        compose_callback_impl(A1&& f1, A2&& f2)
10✔
556
          : f1_(HPX_FORWARD(A1, f1))
10✔
557
          , f2_(HPX_FORWARD(A2, f2))
10✔
558
        {
559
        }
10✔
560

561
        void operator()(std::string const& k, std::string const& v) const
×
562
        {
563
            f1_(k, v);
×
564
            f2_(k, v);
×
565
        }
×
566

567
    private:
568
        F1 f1_;
569
        F2 f2_;
570
    };
571

572
    template <typename F1, typename F2>
573
    static HPX_FORCEINLINE
574
        hpx::function<void(std::string const&, std::string const&)>
575
        compose_callback(F1&& f1, F2&& f2)
574✔
576
    {
577
        if (!f1)
574✔
578
            return HPX_FORWARD(F2, f2);
×
579
        else if (!f2)
574✔
580
            return HPX_FORWARD(F1, f1);
564✔
581

582
        // otherwise create a combined callback
583
        using result_type =
584
            compose_callback_impl<std::decay_t<F1>, std::decay_t<F2>>;
585
        return result_type(HPX_FORWARD(F1, f1), HPX_FORWARD(F2, f2));
10✔
586
    }
574✔
587

588
    void section::add_notification_callback(std::unique_lock<mutex_type>& l,
1,148✔
589
        std::string const& key, entry_changed_func const& callback)
590
    {
591
        std::string::size_type i = key.find_last_of('.');
1,148✔
592
        if (i != std::string::npos)
1,148✔
593
        {
594
            section* current = root_;
574✔
595

596
            // make sure all sections in key exist
597
            std::string sec_name = key.substr(0, i);
574✔
598

599
            std::string::size_type pos = 0;
574✔
600
            for (std::string::size_type pos1 = sec_name.find_first_of('.');
1,722✔
601
                 std::string::npos != pos1;
1,722✔
602
                 pos1 = sec_name.find_first_of('.', pos = pos1 + 1))
1,148✔
603
            {
604
                current = current->add_section_if_new(
1,148✔
605
                    l, sec_name.substr(pos, pos1 - pos));
1,148✔
606
            }
1,148✔
607

608
            current = current->add_section_if_new(l, sec_name.substr(pos));
574✔
609

610
            // now add this entry to the section
611
            current->add_notification_callback(l, key.substr(i + 1), callback);
574✔
612
        }
574✔
613
        else
614
        {
615
            // just add this entry to the section
616
            entry_map::iterator it = entries_.find(key);
574✔
617
            if (it != entries_.end())
574✔
618
            {
619
                it->second.second =
574✔
620
                    compose_callback(callback, it->second.second);
574✔
621
            }
574✔
622
            else
623
            {
624
                entries_[key] = entry_type("", callback);
×
625
            }
626
        }
627
    }
1,148✔
628

629
    bool section::has_entry(
734,023✔
630
        std::unique_lock<mutex_type>& l, std::string const& key) const
631
    {
632
        std::string::size_type i = key.find('.');
734,023✔
633
        if (i != std::string::npos)
734,023✔
634
        {
635
            std::string sub_sec = key.substr(0, i);
1✔
636
            std::string sub_key = key.substr(i + 1, key.size() - i);
1✔
637
            if (has_section(l, sub_sec))
1✔
638
            {
639
                section_map::const_iterator cit = sections_.find(sub_sec);
1✔
640
                HPX_ASSERT(cit != sections_.end());
1✔
641
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
1✔
642
                return (*cit).second.has_entry(sub_key);
1✔
643
            }
1✔
644
            return false;
×
645
        }
1✔
646
        return entries_.find(key) != entries_.end();
734,022✔
647
    }
734,023✔
648

649
    std::string section::get_entry(
71,469✔
650
        std::unique_lock<mutex_type>& l, std::string const& key) const
651
    {
652
        std::string::size_type i = key.find('.');
71,469✔
653
        if (i != std::string::npos)
71,469✔
654
        {
655
            std::string sub_sec = key.substr(0, i);
14,537✔
656
            std::string sub_key = key.substr(i + 1, key.size() - i);
14,537✔
657
            if (has_section(l, sub_sec))
14,537✔
658
            {
659
                section_map::const_iterator cit = sections_.find(sub_sec);
14,537✔
660
                HPX_ASSERT(cit != sections_.end());
14,537✔
661
                hpx::unlock_guard<std::unique_lock<mutex_type>> ul(l);
14,537✔
662
                return (*cit).second.get_entry(sub_key);
14,537✔
663
            }
14,537✔
664

665
            HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry",
×
666
                "No such key ({}) in section: {}", key, get_name());
667
            return "";
668
        }
14,537✔
669

670
        if (entries_.find(key) != entries_.end())
56,932✔
671
        {
672
            entry_map::const_iterator cit = entries_.find(key);
56,932✔
673
            HPX_ASSERT(cit != entries_.end());
56,932✔
674
            return expand(l, (*cit).second.first);
56,932✔
675
        }
676

677
        HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry",
×
678
            "No such section ({}) in section: {}", key, get_name());
679
        return "";
680
    }
71,469✔
681

682
    std::string section::get_entry(std::unique_lock<mutex_type>& l,
337,567✔
683
        std::string const& key, std::string const& default_val) const
684
    {
685
        typedef std::vector<std::string> string_vector;
686

687
        string_vector split_key;
337,564✔
688
        hpx::string_util::split(
337,564✔
689
            split_key, key, hpx::string_util::is_any_of("."));
337,564✔
690

691
        std::string sk = split_key.back();
337,568✔
692
        split_key.pop_back();
337,563✔
693

694
        section const* cur_section = this;
337,563✔
695
        for (string_vector::const_iterator iter = split_key.begin(),
1,005,925✔
696
                                           end = split_key.end();
337,563✔
697
             iter != end; ++iter)
668,352✔
698
        {
699
            section_map::const_iterator next =
700
                cur_section->sections_.find(*iter);
333,821✔
701
            if (cur_section->sections_.end() == next)
333,823✔
702
                return expand(l, default_val);
3,033✔
703
            cur_section = &next->second;
330,789✔
704
        }
330,789✔
705

706
        entry_map::const_iterator entry = cur_section->entries_.find(sk);
334,530✔
707
        if (cur_section->entries_.end() == entry)
334,534✔
708
            return expand(l, default_val);
37,050✔
709

710
        return expand(l, entry->second.first);
297,484✔
711
    }
337,566✔
712

713
    inline void indent(int ind, std::ostream& strm)
×
714
    {
715
        for (int i = 0; i < ind; ++i)
×
716
            strm << "  ";
×
717
    }
×
718

719
    void section::dump(int ind) const
×
720
    {
721
        return dump(ind, std::cout);
×
722
    }
723

724
    void section::dump(int ind, std::ostream& strm) const
×
725
    {
726
        std::unique_lock<mutex_type> l(mtx_);
×
727

728
        bool header = false;
×
729
        if (0 == ind)
×
730
            header = true;
×
731

732
        ++ind;
×
733
        if (header)
×
734
        {
735
            if (get_root() == this)
×
736
            {
737
                strm << "============================\n";
×
738
            }
×
739
            else
740
            {
741
                strm << "============================[\n"
×
742
                     << get_name() << "\n"
×
743
                     << "]\n";
×
744
            }
745
        }
×
746

747
        entry_map::const_iterator eend = entries_.end();
×
748
        for (entry_map::const_iterator i = entries_.begin(); i != eend; ++i)
×
749
        {
750
            indent(ind, strm);
×
751

752
            const std::string expansion = expand(l, i->second.first);
×
753

754
            // Check if the expanded entry is different from the actual entry.
755
            if (expansion != i->second.first)
×
756
                // If the expansion is different from the real entry, then print
757
                // it out.
758
                strm << "'" << i->first << "' : '" << i->second.first
×
759
                     << "' -> '" << expansion << "'\n";
×
760
            else
761
                strm << "'" << i->first << "' : '" << i->second.first << "'\n";
×
762
        }
×
763

764
        section_map::const_iterator send = sections_.end();
×
765
        for (section_map::const_iterator i = sections_.begin(); i != send; ++i)
×
766
        {
767
            indent(ind, strm);
×
768
            strm << "[" << i->first << "]\n";
×
769
            (*i).second.dump(ind, strm);
×
770
        }
×
771

772
        if (header)
×
773
            strm << "============================\n";
×
774

775
        strm << std::flush;
×
776
    }
×
777

778
    void section::merge(std::string const& filename)
×
779
    {
780
        section tmp(filename, root_);
×
781
        merge(tmp);
×
782
    }
×
783

784
    void section::merge(section& second)
×
785
    {
786
        std::unique_lock<mutex_type> l(mtx_);
×
787

788
        // merge entries: keep own entries, and add other entries
789
        entry_map const& s_entries = second.get_entries();
×
790
        entry_map::const_iterator end = s_entries.end();
×
791
        for (entry_map::const_iterator i = s_entries.begin(); i != end; ++i)
×
792
            entries_[i->first] = i->second;
×
793

794
        // merge subsection known in first section
795
        section_map::iterator send = sections_.end();
×
796
        for (section_map::iterator i = sections_.begin(); i != send; ++i)
×
797
        {
798
            // is there something to merge with?
799
            if (second.has_section(l, i->first))
×
800
                i->second.merge(second.sections_[i->first]);
×
801
        }
×
802

803
        // merge subsection known in second section
804
        section_map s = second.get_sections();
×
805
        section_map::iterator secend = s.end();
×
806
        for (section_map::iterator i = s.begin(); i != secend; ++i)
×
807
        {
808
            // if THIS knows the section, we already merged it above
809
            if (!has_section(l, i->first))
×
810
            {
811
                // it is not known here, so we can't merge, but have to add it.
812
                add_section(l, i->first, i->second, get_root());
×
813
            }
×
814
        }
×
815
    }
×
816

817
    /////////////////////////////////////////////////////////////////////////////////
818
    void section::line_msg(std::string msg, std::string const& file, int lnum,
×
819
        std::string const& line)
820
    {
821
        msg += " " + file;
×
822
        if (lnum > 0)
×
823
            msg += ": line " + std::to_string(lnum);
×
824
        if (!line.empty())
×
825
            msg += " (offending entry: " + line + ")";
×
826

827
        HPX_THROW_EXCEPTION(hpx::error::no_success, "section::line_msg", msg);
×
828
    }
×
829

830
    ///////////////////////////////////////////////////////////////////////////////
831
    // find the matching closing brace starting from 'begin', escaped braces will
832
    // be un-escaped
833
    inline std::string::size_type find_next(char const* ch, std::string& value,
865,196✔
834
        std::string::size_type begin = static_cast<std::string::size_type>(-1))
835
    {
836
        std::string::size_type end = value.find_first_of(ch, begin + 1);
865,196✔
837
        while (end != std::string::npos)
865,196✔
838
        {
839
            if (end != 0 && value[end - 1] != '\\')
674,831✔
840
                break;
674,831✔
841
            value = detail::replace_substr(value, end - 1, 2, ch);
×
842
            end = value.find_first_of(ch, end);
×
843
        }
844
        return end;
865,196✔
845
    }
846

847
    ///////////////////////////////////////////////////////////////////////////////
848
    void section::expand(std::unique_lock<mutex_type>& l, std::string& value,
444,624✔
849
        std::string::size_type begin) const
850
    {
851
        std::string::size_type p = value.find_first_of('$', begin + 1);
444,627✔
852
        while (p != std::string::npos && value.size() - 1 != p)
524,056✔
853
        {
854
            if ('[' == value[p + 1])
79,432✔
855
                expand_bracket(l, value, p);
50,128✔
856
            else if ('{' == value[p + 1])
29,304✔
857
                expand_brace(l, value, p);
×
858
            p = value.find_first_of('$', p + 1);
79,432✔
859
        }
860
    }
444,627✔
861

862
    void section::expand_bracket(std::unique_lock<mutex_type>& l,
50,128✔
863
        std::string& value, std::string::size_type begin) const
864
    {
865
        // expand all keys embedded inside this key
866
        expand(l, value, begin);
50,128✔
867

868
        // now expand the key itself
869
        std::string::size_type end = find_next("]", value, begin + 1);
50,128✔
870
        if (end != std::string::npos)
50,128✔
871
        {
872
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
50,128✔
873
            std::string::size_type colon = find_next(":", to_expand);
50,128✔
874
            if (colon == std::string::npos)
50,128✔
875
            {
876
                value = detail::replace_substr(value, begin, end - begin + 1,
100,256✔
877
                    root_->get_entry(l, to_expand, std::string("")));
50,128✔
878
            }
50,128✔
879
            else
880
            {
881
                value = detail::replace_substr(value, begin, end - begin + 1,
×
882
                    root_->get_entry(l, to_expand.substr(0, colon),
×
883
                        to_expand.substr(colon + 1)));
×
884
            }
885
        }
50,128✔
886
    }
50,128✔
887

888
    void section::expand_brace(std::unique_lock<mutex_type>& l,
×
889
        std::string& value, std::string::size_type begin) const
890
    {
891
        // expand all keys embedded inside this key
892
        expand(l, value, begin);
×
893

894
        // now expand the key itself
895
        std::string::size_type end = find_next("}", value, begin + 1);
×
896
        if (end != std::string::npos)
×
897
        {
898
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
×
899
            std::string::size_type colon = find_next(":", to_expand);
×
900
            if (colon == std::string::npos)
×
901
            {
902
                char* env = getenv(to_expand.c_str());
×
903
                value = detail::replace_substr(
×
904
                    value, begin, end - begin + 1, nullptr != env ? env : "");
×
905
            }
×
906
            else
907
            {
908
                char* env = getenv(to_expand.substr(0, colon).c_str());
×
909
                value = detail::replace_substr(value, begin, end - begin + 1,
×
910
                    nullptr != env ? std::string(env) :
×
911
                                     to_expand.substr(colon + 1));
×
912
            }
913
        }
×
914
    }
×
915

916
    std::string section::expand(
394,496✔
917
        std::unique_lock<mutex_type>& l, std::string value) const
918
    {
919
        expand(l, value, std::string::size_type(-1));
394,496✔
920
        return value;
394,496✔
921
    }
922

923
    ///////////////////////////////////////////////////////////////////////////////
924
    void section::expand_only(std::unique_lock<mutex_type>& l,
851,364✔
925
        std::string& value, std::string::size_type begin,
926
        std::string const& expand_this) const
927
    {
928
        std::string::size_type p = value.find_first_of('$', begin + 1);
851,364✔
929
        while (p != std::string::npos && value.size() - 1 != p)
1,466,874✔
930
        {
931
            if ('[' == value[p + 1])
615,510✔
932
                expand_bracket_only(l, value, p, expand_this);
132,911✔
933
            else if ('{' == value[p + 1])
482,599✔
934
                expand_brace_only(l, value, p, expand_this);
249,559✔
935
            p = value.find_first_of('$', p + 1);
615,510✔
936
        }
937
    }
851,364✔
938

939
    void section::expand_bracket_only(std::unique_lock<mutex_type>& l,
132,911✔
940
        std::string& value, std::string::size_type begin,
941
        std::string const& expand_this) const
942
    {
943
        // expand all keys embedded inside this key
944
        expand_only(l, value, begin, expand_this);
132,911✔
945

946
        // now expand the key itself
947
        std::string::size_type end = find_next("]", value, begin + 1);
132,911✔
948
        if (end != std::string::npos)
132,911✔
949
        {
950
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
132,911✔
951
            std::string::size_type colon = find_next(":", to_expand);
132,911✔
952
            if (colon == std::string::npos)
132,911✔
953
            {
954
                if (to_expand == expand_this)
132,911✔
955
                {
956
                    value =
×
957
                        detail::replace_substr(value, begin, end - begin + 1,
×
958
                            root_->get_entry(l, to_expand, std::string("")));
×
959
                }
×
960
            }
132,911✔
961
            else if (to_expand.substr(0, colon) == expand_this)
×
962
            {
963
                value = detail::replace_substr(value, begin, end - begin + 1,
×
964
                    root_->get_entry(l, to_expand.substr(0, colon),
×
965
                        to_expand.substr(colon + 1)));
×
966
            }
×
967
        }
132,911✔
968
    }
132,911✔
969

970
    void section::expand_brace_only(std::unique_lock<mutex_type>& l,
249,559✔
971
        std::string& value, std::string::size_type begin,
972
        std::string const& expand_this) const
973
    {
974
        // expand all keys embedded inside this key
975
        expand_only(l, value, begin, expand_this);
249,559✔
976

977
        // now expand the key itself
978
        std::string::size_type end = find_next("}", value, begin + 1);
249,559✔
979
        if (end != std::string::npos)
249,559✔
980
        {
981
            std::string to_expand = value.substr(begin + 2, end - begin - 2);
249,559✔
982
            std::string::size_type colon = find_next(":", to_expand);
249,559✔
983
            if (colon == std::string::npos)
249,559✔
984
            {
985
                char* env = getenv(to_expand.c_str());
7,326✔
986
                value = detail::replace_substr(
7,326✔
987
                    value, begin, end - begin + 1, nullptr != env ? env : "");
7,326✔
988
            }
7,326✔
989
            else
990
            {
991
                char* env = getenv(to_expand.substr(0, colon).c_str());
242,233✔
992
                value = detail::replace_substr(value, begin, end - begin + 1,
484,466✔
993
                    nullptr != env ? std::string(env) :
484,463✔
994
                                     to_expand.substr(colon + 1));
242,230✔
995
            }
996
        }
249,559✔
997
    }
249,559✔
998

999
    std::string section::expand_only(std::unique_lock<mutex_type>& l,
×
1000
        std::string value, std::string const& expand_this) const
1001
    {
1002
        expand_only(l, value, std::string::size_type(-1), expand_this);
×
1003
        return value;
×
1004
    }
1005

1006
    ///////////////////////////////////////////////////////////////////////////////
1007
    template <typename Archive>
1008
    void section::save(Archive& ar, unsigned int const /* version */) const
×
1009
    {
1010
        ar << name_;
×
1011
        ar << parent_name_;
×
1012

1013
        std::uint64_t size = entries_.size();
×
1014
        ar << size;
×
1015
        for (auto const& val : entries_)
×
1016
        {
1017
            ar << val.first;
×
1018
        }
1019

1020
        ar << sections_;
×
1021
    }
×
1022

1023
    template <typename Archive>
1024
    void section::load(Archive& ar, unsigned int const /* version */)
×
1025
    {
1026
        ar >> name_;
×
1027
        ar >> parent_name_;
×
1028

1029
        std::uint64_t size;
1030
        ar >> size;    //-V128
×
1031

1032
        entries_.clear();
×
1033
        for (std::size_t i = 0; i < size; ++i)
×
1034
        {
1035
            using value_type = typename entry_map::value_type;
1036

1037
            value_type v;
×
1038
            ar >> const_cast<std::string&>(v.first);
×
1039
            entries_.insert(entries_.end(), HPX_MOVE(v));
×
1040
        }
×
1041

1042
        ar >> sections_;
×
1043

1044
        set_root(this, true);    // make this the current root
×
1045
    }
×
1046

1047
    // explicit instantiation for the correct archive types
1048
    template HPX_CORE_EXPORT void section::save(
1049
        serialization::output_archive&, unsigned int const version) const;
1050

1051
    template HPX_CORE_EXPORT void section::load(
1052
        serialization::input_archive&, unsigned int const version);
1053
}    // namespace hpx::util
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc