#9 TI-1: Move static functions (un)setConfigVariable(...) to Rules

This commit is contained in:
Thomas Lauf 2018-07-24 08:07:10 +02:00
parent 9d29a14d64
commit 0688e3ba07
3 changed files with 233 additions and 223 deletions

View file

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez. // Copyright 2015 - 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -34,6 +34,7 @@
#include <cassert> #include <cassert>
#include <cerrno> #include <cerrno>
#include <inttypes.h> #include <inttypes.h>
#include <JSON.h>
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Rules::Rules () Rules::Rules ()
@ -492,3 +493,219 @@ std::string Rules::parseGroup (const std::vector <std::string>& tokens)
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Note that because this function does not recurse with includes, it therefore
// only sees the top-level settings. This has the desirable effect of adding as
// an override any setting which resides in an imported file.
bool Rules::setConfigVariable (
Database& database,
const Rules& rules,
std::string name,
std::string value,
bool confirmation /* = false */)
{
// Read config file as lines of text.
std::vector <std::string> lines;
File::read (rules.file (), lines);
bool change = false;
if (rules.has (name))
{
// No change.
if (rules.get (name) == value)
return false;
// If there is a non-comment line containing the entry in flattened form:
// a.b.c = value
bool found = false;
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (name);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Modify value
if (! confirmation ||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
name,
rules.get (name),
value)))
{
auto before = line;
line = line.substr (0, pos) + name + " = " + value;
database.recordConfigAction (before, line);
change = true;
}
}
}
// If it was not found, then retry in hierarchical form∴
// a:
// b:
// c = value
if (! found)
{
auto leaf = split (name, '.').back () + ":";
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (leaf);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
name,
rules.get (name),
value)))
{
auto before = line;
line = line.substr (0, pos) + leaf + " " + value;
database.recordConfigAction (before, line);
change = true;
}
}
}
}
if (! found)
{
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
name,
rules.get (name),
value)))
{
// Add blank line required by rules.
if (lines.empty () || lines.back ().empty ())
lines.push_back ("");
// Add new line.
lines.push_back (name + " = " + json::encode (value));
database.recordConfigAction ("", lines.back ());
change = true;
}
}
}
else
{
if (! confirmation ||
confirm (format ("Are you sure you want to add '{1}' with a value of '{2}'?", name, value)))
{
// TODO Ideally, this would locate an existing hierarchy and insert the
// new leaf/value properly. But that's non-trivial.
// Add blank line required by rules.
if (lines.empty () || lines.back ().empty ())
lines.push_back ("");
// Add new line.
lines.push_back (name + " = " + json::encode (value));
database.recordConfigAction ("", lines.back ());
change = true;
}
}
if (change)
File::write (rules.file (), lines);
return change;
}
////////////////////////////////////////////////////////////////////////////////
// Removes lines from configuration but leaves comments intact.
//
// Return codes:
// 0 - found and removed
// 1 - found and not removed
// 2 - not found
int Rules::unsetConfigVariable (
Database& database,
const Rules& rules,
std::string name,
bool confirmation /* = false */)
{
// Setting not found.
if (! rules.has (name))
return 2;
// Read config file as lines of text.
std::vector <std::string> lines;
File::read (rules.file (), lines);
// If there is a non-comment line containing the entry in flattened form:
// a.b.c = value
bool found = false;
bool change = false;
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (name);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
{
database.recordConfigAction (line, "");
line = "";
change = true;
}
}
}
// If it was not found, then retry in hierarchical form∴
// a:
// b:
// c = value
if (! found)
{
auto leaf = split (name, '.').back () + ":";
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (leaf);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
{
line = "";
change = true;
}
}
}
}
if (change)
File::write (rules.file (), lines);
if (change && found)
return 0;
else if (found)
return 1;
return 2;
}

View file

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez. // Copyright 2015 - 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -31,6 +31,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <string> #include <string>
#include <Database.h>
class Rules class Rules
{ {
@ -54,6 +55,16 @@ public:
std::string dump () const; std::string dump () const;
static bool setConfigVariable (Database& database,
const Rules& rules,
std::string name,
std::string value,
bool confirmation /* = false */);
static int unsetConfigVariable (Database& database,
const Rules& rules,
std::string name,
bool confirmation /* = false */);
private: private:
void parse (const std::string&, int next = 1); void parse (const std::string&, int next = 1);
void parseRule (const std::string&); void parseRule (const std::string&);

View file

@ -1,6 +1,6 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// //
// Copyright 2015 - 2018, Paul Beckingham, Federico Hernandez. // Copyright 2015 - 2018, Thomas Lauf, Paul Beckingham, Federico Hernandez.
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy // Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal // of this software and associated documentation files (the "Software"), to deal
@ -32,224 +32,6 @@
#include <commands.h> #include <commands.h>
#include <iostream> #include <iostream>
////////////////////////////////////////////////////////////////////////////////
// Note that because this function does not recurse with includes, it therefore
// only sees the top-level settings. This has the desirable effect of adding as
// an override any setting which resides in an imported file.
static bool setConfigVariable (
Database& database,
const Rules& rules,
std::string name,
std::string value,
bool confirmation /* = false */)
{
// Read config file as lines of text.
std::vector <std::string> lines;
File::read (rules.file (), lines);
bool change = false;
if (rules.has (name))
{
// No change.
if (rules.get (name) == value)
return false;
// If there is a non-comment line containing the entry in flattened form:
// a.b.c = value
bool found = false;
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (name);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Modify value
if (! confirmation ||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
name,
rules.get (name),
value)))
{
auto before = line;
line = line.substr (0, pos) + name + " = " + value;
database.recordConfigAction (before, line);
change = true;
}
}
}
// If it was not found, then retry in hierarchical form∴
// a:
// b:
// c = value
if (! found)
{
auto leaf = split (name, '.').back () + ":";
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (leaf);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
name,
rules.get (name),
value)))
{
auto before = line;
line = line.substr (0, pos) + leaf + " " + value;
database.recordConfigAction (before, line);
change = true;
}
}
}
}
if (! found)
{
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to change the value of '{1}' from '{2}' to '{3}'?",
name,
rules.get (name),
value)))
{
// Add blank line required by rules.
if (lines.empty () || lines.back ().empty ())
lines.push_back ("");
// Add new line.
lines.push_back (name + " = " + json::encode (value));
database.recordConfigAction ("", lines.back ());
change = true;
}
}
}
else
{
if (! confirmation ||
confirm (format ("Are you sure you want to add '{1}' with a value of '{2}'?", name, value)))
{
// TODO Ideally, this would locate an existing hierarchy and insert the
// new leaf/value properly. But that's non-trivial.
// Add blank line required by rules.
if (lines.empty () || lines.back ().empty ())
lines.push_back ("");
// Add new line.
lines.push_back (name + " = " + json::encode (value));
database.recordConfigAction ("", lines.back ());
change = true;
}
}
if (change)
File::write (rules.file (), lines);
return change;
}
////////////////////////////////////////////////////////////////////////////////
// Removes lines from configuration but leaves comments intact.
//
// Return codes:
// 0 - found and removed
// 1 - found and not removed
// 2 - not found
static int unsetConfigVariable (
Database& database,
const Rules& rules,
std::string name,
bool confirmation /* = false */)
{
// Setting not found.
if (! rules.has (name))
return 2;
// Read config file as lines of text.
std::vector <std::string> lines;
File::read (rules.file (), lines);
// If there is a non-comment line containing the entry in flattened form:
// a.b.c = value
bool found = false;
bool change = false;
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (name);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
{
database.recordConfigAction (line, "");
line = "";
change = true;
}
}
}
// If it was not found, then retry in hierarchical form∴
// a:
// b:
// c = value
if (! found)
{
auto leaf = split (name, '.').back () + ":";
for (auto& line : lines)
{
auto comment = line.find ('#');
auto pos = line.find (leaf);
if (pos != std::string::npos &&
(comment == std::string::npos || comment > pos))
{
found = true;
// Remove name
if (! confirmation ||
confirm (format ("Are you sure you want to remove '{1}'?", name)))
{
line = "";
change = true;
}
}
}
}
if (change)
File::write (rules.file (), lines);
if (change && found)
return 0;
else if (found)
return 1;
return 2;
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// timew config name value Set name=value // timew config name value Set name=value
// timew config name '' Set name='' // timew config name '' Set name=''
@ -302,7 +84,7 @@ int CmdConfig (
value += words[i]; value += words[i];
} }
change = setConfigVariable (database, rules, name, value, confirmation); change = Rules::setConfigVariable (database, rules, name, value, confirmation);
if (!change) if (!change)
{ {
@ -313,7 +95,7 @@ int CmdConfig (
else else
{ {
bool found = false; bool found = false;
rc = unsetConfigVariable (database, rules, name, confirmation); rc = Rules::unsetConfigVariable (database, rules, name, confirmation);
if (rc == 0) if (rc == 0)
{ {
change = true; change = true;