advgetopt 2.0.49
Parse complex command line arguments and configuration files in C++.
variables.cpp
Go to the documentation of this file.
1// Copyright (c) 2006-2025 Made to Order Software Corp. All Rights Reserved
2//
3// https://snapwebsites.org/project/advgetopt
4// contact@m2osw.com
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License along
17// with this program; if not, write to the Free Software Foundation, Inc.,
18// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
33// self
34//
35#include "advgetopt/variables.h"
36
37#include "advgetopt/exception.h"
38
39
40// C++
41//
42#include <iostream>
43
44
45// last include
46//
47#include <snapdev/poison.h>
48
49
50
51namespace advgetopt
52{
53
54
55
79std::string variables::canonicalize_variable_name(std::string const & name)
80{
81 std::string result;
82
83 bool first(true);
84 for(char const * n(name.c_str()); *n != '\0'; ++n)
85 {
86 if(*n == ':' || *n == '.')
87 {
88 if(first)
89 {
90 throw getopt_invalid(
91 "found an empty section name in \""
92 + name
93 + "\".");
94 }
95 while(n[1] == ':' || n[1] == '.')
96 {
97 ++n;
98 }
99 result += "::";
100 first = true;
101 }
102 else
103 {
104 if(first && *n >= '0' && *n <= '9')
105 {
106 throw getopt_invalid(
107 "a variable name or section name in \""
108 + name
109 + "\" starts with a digit, which is not allowed.");
110 }
111 first = false;
112 if(*n == '_')
113 {
114 result += '-';
115 }
116 else
117 {
118 result += *n;
119 }
120 }
121 }
122
123 return result;
124}
125
126
138bool variables::has_variable(std::string const & name) const
139{
140 auto it(f_variables.find(canonicalize_variable_name(name)));
141 return it != f_variables.end();
142}
143
144
154std::string variables::get_variable(std::string const & name) const
155{
156 auto it(f_variables.find(canonicalize_variable_name(name)));
157 if(it != f_variables.end())
158 {
159 return it->second;
160 }
161
162 return std::string();
163}
164
165
180{
181 return f_variables;
182}
183
184
213 std::string const & name
214 , std::string const & value
216{
217 std::string const var(canonicalize_variable_name(name));
218 auto it(f_variables.find(var));
219 switch(assignment)
220 {
222 if(it == f_variables.end())
223 {
224 f_variables[var] = value;
225 }
226 break;
227
229 if(it == f_variables.end())
230 {
231 f_variables[var] = value;
232 }
233 else
234 {
235 f_variables[var] = it->second + value;
236 }
237 break;
238
240 if(it == f_variables.end())
241 {
242 f_variables[var] = value;
243 }
244 else
245 {
247 "variable \""
248 + var
249 + "\" is already defined.");
250 }
251 break;
252
253 //case assignment_t::ASSIGNMENT_NONE:
254 //case assignment_t::ASSIGNMENT_SET:
255 default:
256 f_variables[var] = value;
257 break;
258
259 }
260}
261
262
291std::string variables::process_value(std::string const & value) const
292{
293 // to support the recursivity, we call a sub-function which calls itself
294 // whenever a variable is discovered to include another variable; that
295 // recursivity is broken immediately if a variable includes itself;
296 // this function is private
297 //
299 return recursive_process_value(value, names);
300}
301
302
317 std::string const & value
318 , variable_names_t & names) const
319{
320 std::string result;
321
322 for(char const * s(value.c_str()); *s != '\0'; ++s)
323 {
324 char c(*s);
325 if(c == '$' && s[1] == '{') // start variable reference?
326 {
327 s += 2;
328 char const * name(s);
329 for(; *s != '}' && *s != '\0'; ++s);
330 if(*s == '\0')
331 {
332 // invalid variable reference
333 //
334 result += "${";
335 result += name;
336 return result;
337 }
338
339 // TODO: add support for conversions like we have in bash
340 // (i.e. ${var:-extension} ${var%.extension} ...
341 // see man bash section "Parameter Expansion")
342 //
343 // TODO: add support for emitting errors on an undefined
344 // variable
345 //
346 std::string var(std::string(name, s - name));
347 auto allowed(names.insert(var));
348 if(allowed.second)
349 {
351 names.erase(allowed.first);
352 }
353 else
354 {
355 result += "<variable \"" + var + "\" loops>";
356 }
357 }
358 else
359 {
360 result += c;
361 }
362 }
363
364 return result;
365} // LCOV_EXCL_LINE
366
367
368
369} // namespace advgetopt
370// vim: ts=4 sw=4 et
std::string process_value(std::string const &value) const
Process variables against a parameter.
void set_variable(std::string const &name, std::string const &value, assignment_t assignment=assignment_t::ASSIGNMENT_SET)
Set a variable.
variable_t const & get_variables() const
Return a reference to the map of variables.
variable_t f_variables
Definition variables.h:83
std::string recursive_process_value(std::string const &value, variable_names_t &names) const
Internal function processing variables recursively.
string_set_t variable_names_t
Definition variables.h:77
std::map< std::string, std::string > variable_t
Definition variables.h:62
std::string get_variable(std::string const &name) const
Return the value of the named variable.
static std::string canonicalize_variable_name(std::string const &name)
Canonicalize the variable name.
Definition variables.cpp:79
bool has_variable(std::string const &name) const
Check whether a variable is defined.
Definitions of the advanced getopt exceptions.
The advgetopt environment to parse command line options.
Definition version.h:37
constexpr flag_t option_flags_merge()
Definition flags.h:87
Declaration of the variable class.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.