Merge pull request #2212 from TwlyY29/bibtex-parser
[geany-mirror.git] / scintilla / lexlib / PropSetSimple.cxx
blob5ce353c71743ba30b6f6b9d9d16b1c73d5eaa41a
1 // Scintilla source code edit control
2 /** @file PropSetSimple.cxx
3 ** A basic string to string map.
4 **/
5 // Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
8 // Maintain a dictionary of properties
10 #include <cstdlib>
11 #include <cstring>
13 #include <string>
14 #include <map>
16 #include "PropSetSimple.h"
18 using namespace Scintilla;
20 namespace {
22 typedef std::map<std::string, std::string> mapss;
24 mapss *PropsFromPointer(void *impl) {
25 return static_cast<mapss *>(impl);
30 PropSetSimple::PropSetSimple() {
31 mapss *props = new mapss;
32 impl = static_cast<void *>(props);
35 PropSetSimple::~PropSetSimple() {
36 mapss *props = PropsFromPointer(impl);
37 delete props;
38 impl = 0;
41 void PropSetSimple::Set(const char *key, const char *val, size_t lenKey, size_t lenVal) {
42 mapss *props = PropsFromPointer(impl);
43 if (!*key) // Empty keys are not supported
44 return;
45 (*props)[std::string(key, lenKey)] = std::string(val, lenVal);
48 static bool IsASpaceCharacter(unsigned int ch) {
49 return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
52 void PropSetSimple::Set(const char *keyVal) {
53 while (IsASpaceCharacter(*keyVal))
54 keyVal++;
55 const char *endVal = keyVal;
56 while (*endVal && (*endVal != '\n'))
57 endVal++;
58 const char *eqAt = strchr(keyVal, '=');
59 if (eqAt) {
60 Set(keyVal, eqAt + 1, eqAt-keyVal,
61 endVal - eqAt - 1);
62 } else if (*keyVal) { // No '=' so assume '=1'
63 Set(keyVal, "1", endVal-keyVal, 1);
67 void PropSetSimple::SetMultiple(const char *s) {
68 const char *eol = strchr(s, '\n');
69 while (eol) {
70 Set(s);
71 s = eol + 1;
72 eol = strchr(s, '\n');
74 Set(s);
77 const char *PropSetSimple::Get(const char *key) const {
78 mapss *props = PropsFromPointer(impl);
79 mapss::const_iterator keyPos = props->find(std::string(key));
80 if (keyPos != props->end()) {
81 return keyPos->second.c_str();
82 } else {
83 return "";
87 // There is some inconsistency between GetExpanded("foo") and Expand("$(foo)").
88 // A solution is to keep a stack of variables that have been expanded, so that
89 // recursive expansions can be skipped. For now I'll just use the C++ stack
90 // for that, through a recursive function and a simple chain of pointers.
92 struct VarChain {
93 VarChain(const char *var_=nullptr, const VarChain *link_= nullptr): var(var_), link(link_) {}
95 bool contains(const char *testVar) const {
96 return (var && (0 == strcmp(var, testVar)))
97 || (link && link->contains(testVar));
100 const char *var;
101 const VarChain *link;
104 static int ExpandAllInPlace(const PropSetSimple &props, std::string &withVars, int maxExpands, const VarChain &blankVars) {
105 size_t varStart = withVars.find("$(");
106 while ((varStart != std::string::npos) && (maxExpands > 0)) {
107 const size_t varEnd = withVars.find(')', varStart+2);
108 if (varEnd == std::string::npos) {
109 break;
112 // For consistency, when we see '$(ab$(cde))', expand the inner variable first,
113 // regardless whether there is actually a degenerate variable named 'ab$(cde'.
114 size_t innerVarStart = withVars.find("$(", varStart+2);
115 while ((innerVarStart != std::string::npos) && (innerVarStart > varStart) && (innerVarStart < varEnd)) {
116 varStart = innerVarStart;
117 innerVarStart = withVars.find("$(", varStart+2);
120 std::string var(withVars, varStart + 2, varEnd - varStart - 2);
121 std::string val = props.Get(var.c_str());
123 if (blankVars.contains(var.c_str())) {
124 val = ""; // treat blankVar as an empty string (e.g. to block self-reference)
127 if (--maxExpands >= 0) {
128 maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars));
131 withVars.erase(varStart, varEnd-varStart+1);
132 withVars.insert(varStart, val.c_str(), val.length());
134 varStart = withVars.find("$(");
137 return maxExpands;
140 int PropSetSimple::GetExpanded(const char *key, char *result) const {
141 std::string val = Get(key);
142 ExpandAllInPlace(*this, val, 100, VarChain(key));
143 const int n = static_cast<int>(val.size());
144 if (result) {
145 memcpy(result, val.c_str(), n+1);
147 return n; // Not including NUL
150 int PropSetSimple::GetInt(const char *key, int defaultValue) const {
151 std::string val = Get(key);
152 ExpandAllInPlace(*this, val, 100, VarChain(key));
153 if (!val.empty()) {
154 return atoi(val.c_str());
156 return defaultValue;