]> git.saurik.com Git - wxWidgets.git/blame - src/stc/scintilla/lexlib/PropSetSimple.cxx
Avoid calling gtk_window_get_position() from "configure-event" handler, if possible.
[wxWidgets.git] / src / stc / scintilla / lexlib / PropSetSimple.cxx
CommitLineData
9ce192d4 1// SciTE - Scintilla based Text Editor
1dcf666d 2/** @file PropSetSimple.cxx
65ec6247
RD
3 ** A Java style properties file module.
4 **/
1dcf666d 5// Copyright 1998-2010 by Neil Hodgson <neilh@scintilla.org>
9ce192d4
RD
6// The License.txt file describes the conditions under which this software may be distributed.
7
8// Maintain a dictionary of properties
9
10#include <stdlib.h>
11#include <string.h>
9ce192d4
RD
12#include <stdio.h>
13
9e96e16f 14#ifdef _MSC_VER
1dcf666d
RD
15// Visual C++ doesn't like unreachable code in its own headers.
16#pragma warning(disable: 4018 4100 4245 4511 4512 4663 4702)
9e96e16f
RD
17#endif
18
19#include <string>
20#include <map>
21
9e96e16f 22#include "PropSetSimple.h"
9ce192d4 23
7e0c58e9
RD
24#ifdef SCI_NAMESPACE
25using namespace Scintilla;
26#endif
27
9e96e16f 28typedef std::map<std::string, std::string> mapss;
591d01be 29
9e96e16f
RD
30PropSetSimple::PropSetSimple() {
31 mapss *props = new mapss;
32 impl = static_cast<void *>(props);
591d01be
RD
33}
34
9e96e16f
RD
35PropSetSimple::~PropSetSimple() {
36 mapss *props = static_cast<mapss *>(impl);
37 delete props;
38 impl = 0;
591d01be
RD
39}
40
9e96e16f
RD
41void PropSetSimple::Set(const char *key, const char *val, int lenKey, int lenVal) {
42 mapss *props = static_cast<mapss *>(impl);
65ec6247
RD
43 if (!*key) // Empty keys are not supported
44 return;
45 if (lenKey == -1)
a834585d 46 lenKey = static_cast<int>(strlen(key));
65ec6247 47 if (lenVal == -1)
a834585d 48 lenVal = static_cast<int>(strlen(val));
9e96e16f 49 (*props)[std::string(key, lenKey)] = std::string(val, lenVal);
9ce192d4
RD
50}
51
9e96e16f
RD
52static bool IsASpaceCharacter(unsigned int ch) {
53 return (ch == ' ') || ((ch >= 0x09) && (ch <= 0x0d));
54}
55
56void PropSetSimple::Set(const char *keyVal) {
57 while (IsASpaceCharacter(*keyVal))
65ec6247
RD
58 keyVal++;
59 const char *endVal = keyVal;
60 while (*endVal && (*endVal != '\n'))
61 endVal++;
62 const char *eqAt = strchr(keyVal, '=');
63 if (eqAt) {
1dcf666d
RD
64 Set(keyVal, eqAt + 1, static_cast<int>(eqAt-keyVal),
65 static_cast<int>(endVal - eqAt - 1));
65ec6247 66 } else if (*keyVal) { // No '=' so assume '=1'
1dcf666d 67 Set(keyVal, "1", static_cast<int>(endVal-keyVal), 1);
9ce192d4
RD
68 }
69}
70
9e96e16f 71void PropSetSimple::SetMultiple(const char *s) {
65ec6247
RD
72 const char *eol = strchr(s, '\n');
73 while (eol) {
74 Set(s);
75 s = eol + 1;
76 eol = strchr(s, '\n');
77 }
78 Set(s);
79}
80
9e96e16f
RD
81const char *PropSetSimple::Get(const char *key) const {
82 mapss *props = static_cast<mapss *>(impl);
83 mapss::const_iterator keyPos = props->find(std::string(key));
84 if (keyPos != props->end()) {
85 return keyPos->second.c_str();
9ce192d4
RD
86 } else {
87 return "";
88 }
89}
90
a33203cb
RD
91// There is some inconsistency between GetExpanded("foo") and Expand("$(foo)").
92// A solution is to keep a stack of variables that have been expanded, so that
93// recursive expansions can be skipped. For now I'll just use the C++ stack
94// for that, through a recursive function and a simple chain of pointers.
95
96struct VarChain {
1dcf666d 97 VarChain(const char *var_=NULL, const VarChain *link_=NULL): var(var_), link(link_) {}
a33203cb
RD
98
99 bool contains(const char *testVar) const {
1e9bafca 100 return (var && (0 == strcmp(var, testVar)))
a33203cb
RD
101 || (link && link->contains(testVar));
102 }
103
104 const char *var;
105 const VarChain *link;
106};
107
9e96e16f
RD
108static int ExpandAllInPlace(const PropSetSimple &props, std::string &withVars, int maxExpands, const VarChain &blankVars) {
109 size_t varStart = withVars.find("$(");
110 while ((varStart != std::string::npos) && (maxExpands > 0)) {
111 size_t varEnd = withVars.find(")", varStart+2);
112 if (varEnd == std::string::npos) {
a33203cb
RD
113 break;
114 }
115
116 // For consistency, when we see '$(ab$(cde))', expand the inner variable first,
117 // regardless whether there is actually a degenerate variable named 'ab$(cde'.
9e96e16f
RD
118 size_t innerVarStart = withVars.find("$(", varStart+2);
119 while ((innerVarStart != std::string::npos) && (innerVarStart > varStart) && (innerVarStart < varEnd)) {
a33203cb 120 varStart = innerVarStart;
9e96e16f 121 innerVarStart = withVars.find("$(", varStart+2);
a33203cb
RD
122 }
123
9e96e16f
RD
124 std::string var(withVars.c_str(), varStart + 2, varEnd - varStart - 2);
125 std::string val = props.Get(var.c_str());
a33203cb
RD
126
127 if (blankVars.contains(var.c_str())) {
9e96e16f 128 val = ""; // treat blankVar as an empty string (e.g. to block self-reference)
a33203cb
RD
129 }
130
131 if (--maxExpands >= 0) {
132 maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars));
133 }
134
9e96e16f 135 withVars.erase(varStart, varEnd-varStart+1);
a33203cb
RD
136 withVars.insert(varStart, val.c_str(), val.length());
137
9e96e16f 138 varStart = withVars.find("$(");
a33203cb
RD
139 }
140
141 return maxExpands;
142}
143
9e96e16f
RD
144char *PropSetSimple::Expanded(const char *key) const {
145 std::string val = Get(key);
a33203cb 146 ExpandAllInPlace(*this, val, 100, VarChain(key));
9e96e16f
RD
147 char *ret = new char [val.size() + 1];
148 strcpy(ret, val.c_str());
65ec6247
RD
149 return ret;
150}
151
1dcf666d
RD
152int PropSetSimple::GetExpanded(const char *key, char *result) const {
153 char *val = Expanded(key);
154 const int n = static_cast<int>(strlen(val));
155 if (result) {
156 strcpy(result, val);
65ec6247 157 }
1dcf666d
RD
158 delete []val;
159 return n; // Not including NUL
9ce192d4 160}
d134f170 161
9e96e16f
RD
162int PropSetSimple::GetInt(const char *key, int defaultValue) const {
163 char *val = Expanded(key);
164 if (val) {
165 int retVal = val[0] ? atoi(val) : defaultValue;
166 delete []val;
167 return retVal;
1e9bafca 168 }
9e96e16f 169 return defaultValue;
1e9bafca 170}