📄 propset.cxx
字号:
SString PropSet::GetWild(const char *keybase, const char *filename) {
for (int root = 0; root < hashRoots; root++) {
for (Property *p = props[root]; p; p = p->next) {
if (isprefix(p->key, keybase)) {
char * orgkeyfile = p->key + strlen(keybase);
char *keyfile = NULL;
if (strstr(orgkeyfile, "$(") == orgkeyfile) {
char *cpendvar = strchr(orgkeyfile, ')');
if (cpendvar) {
*cpendvar = '\0';
SString s = GetExpanded(orgkeyfile + 2);
*cpendvar = ')';
keyfile = StringDup(s.c_str());
}
}
char *keyptr = keyfile;
if (keyfile == NULL)
keyfile = orgkeyfile;
for (;;) {
char *del = strchr(keyfile, ';');
if (del == NULL)
del = keyfile + strlen(keyfile);
char delchr = *del;
*del = '\0';
if (*keyfile == '*') {
if (IsSuffixCaseInsensitive(filename, keyfile + 1)) {
*del = delchr;
delete []keyptr;
return p->val;
}
} else if (0 == strcmp(keyfile, filename)) {
*del = delchr;
delete []keyptr;
return p->val;
}
if (delchr == '\0')
break;
*del = delchr;
keyfile = del + 1;
}
delete []keyptr;
if (0 == strcmp(p->key, keybase)) {
return p->val;
}
}
}
}
if (superPS) {
// Failed here, so try in base property set
return superPS->GetWild(keybase, filename);
} else {
return "";
}
}
// GetNewExpand does not use Expand as it has to use GetWild with the filename for each
// variable reference found.
SString PropSet::GetNewExpand(const char *keybase, const char *filename) {
char *base = StringDup(GetWild(keybase, filename).c_str());
char *cpvar = strstr(base, "$(");
int maxExpands = 1000; // Avoid infinite expansion of recursive definitions
while (cpvar && (maxExpands > 0)) {
char *cpendvar = strchr(cpvar, ')');
if (cpendvar) {
int lenvar = cpendvar - cpvar - 2; // Subtract the $()
char *var = StringDup(cpvar + 2, lenvar);
SString val = GetWild(var, filename);
if (0 == strcmp(var, keybase))
val.clear(); // Self-references evaluate to empty string
size_t newlenbase = strlen(base) + val.length() - lenvar;
char *newbase = new char[newlenbase];
strncpy(newbase, base, cpvar - base);
strcpy(newbase + (cpvar - base), val.c_str());
strcpy(newbase + (cpvar - base) + val.length(), cpendvar + 1);
delete []var;
delete []base;
base = newbase;
}
cpvar = strstr(base, "$(");
maxExpands--;
}
SString sret = base;
delete []base;
return sret;
}
void PropSet::Clear() {
for (int root = 0; root < hashRoots; root++) {
Property *p = props[root];
while (p) {
Property *pNext = p->next;
p->hash = 0;
delete []p->key;
p->key = 0;
delete []p->val;
p->val = 0;
delete p;
p = pNext;
}
props[root] = 0;
}
}
char *PropSet::ToString() {
size_t len=0;
for (int r = 0; r < hashRoots; r++) {
for (Property *p = props[r]; p; p = p->next) {
len += strlen(p->key) + 1;
len += strlen(p->val) + 1;
}
}
if (len == 0)
len = 1; // Return as empty string
char *ret = new char [len];
if (ret) {
char *w = ret;
for (int root = 0; root < hashRoots; root++) {
for (Property *p = props[root]; p; p = p->next) {
strcpy(w, p->key);
w += strlen(p->key);
*w++ = '=';
strcpy(w, p->val);
w += strlen(p->val);
*w++ = '\n';
}
}
ret[len-1] = '\0';
}
return ret;
}
/**
* Initiate enumeration.
*/
bool PropSet::GetFirst(char **key, char **val) {
for (int i = 0; i < hashRoots; i++) {
for (Property *p = props[i]; p; p = p->next) {
if (p) {
*key = p->key;
*val = p->val;
enumnext = p->next; // GetNext will begin here ...
enumhash = i; // ... in this block
return true;
}
}
}
return false;
}
/**
* Continue enumeration.
*/
bool PropSet::GetNext(char ** key, char ** val) {
bool firstloop = true;
// search begins where we left it : in enumhash block
for (int i = enumhash; i < hashRoots; i++) {
if (!firstloop)
enumnext = props[i]; // Begin with first property in block
// else : begin where we left
firstloop = false;
for (Property *p = enumnext; p; p = p->next) {
if (p) {
*key = p->key;
*val = p->val;
enumnext = p->next; // for GetNext
enumhash = i;
return true;
}
}
}
return false;
}
/**
* Creates an array that points into each word in the string and puts \0 terminators
* after each word.
*/
static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = false) {
int prev = '\n';
int words = 0;
// For rapid determination of whether a character is a separator, build
// a look up table.
bool wordSeparator[256];
for (int i=0;i<256; i++) {
wordSeparator[i] = false;
}
wordSeparator['\r'] = true;
wordSeparator['\n'] = true;
if (!onlyLineEnds) {
wordSeparator[' '] = true;
wordSeparator['\t'] = true;
}
for (int j = 0; wordlist[j]; j++) {
int curr = static_cast<unsigned char>(wordlist[j]);
if (!wordSeparator[curr] && wordSeparator[prev])
words++;
prev = curr;
}
char **keywords = new char *[words + 1];
if (keywords) {
words = 0;
prev = '\0';
size_t slen = strlen(wordlist);
for (size_t k = 0; k < slen; k++) {
if (!wordSeparator[static_cast<unsigned char>(wordlist[k])]) {
if (!prev) {
keywords[words] = &wordlist[k];
words++;
}
} else {
wordlist[k] = '\0';
}
prev = wordlist[k];
}
keywords[words] = &wordlist[slen];
*len = words;
} else {
*len = 0;
}
return keywords;
}
void WordList::Clear() {
if (words) {
delete []list;
delete []words;
delete []wordsNoCase;
}
words = 0;
wordsNoCase = 0;
list = 0;
len = 0;
sorted = false;
sortedNoCase = false;
}
void WordList::Set(const char *s) {
list = StringDup(s);
sorted = false;
sortedNoCase = false;
words = ArrayFromWordList(list, &len, onlyLineEnds);
wordsNoCase = new char * [len + 1];
memcpy(wordsNoCase, words, (len + 1) * sizeof (*words));
}
char *WordList::Allocate(int size) {
list = new char[size + 1];
list[size] = '\0';
return list;
}
void WordList::SetFromAllocated() {
sorted = false;
sortedNoCase = false;
words = ArrayFromWordList(list, &len, onlyLineEnds);
wordsNoCase = new char * [len + 1];
memcpy(wordsNoCase, words, (len + 1) * sizeof (*words));
}
int cmpString(const void *a1, const void *a2) {
// Can't work out the correct incantation to use modern casts here
return strcmp(*(char**)(a1), *(char**)(a2));
}
int cmpStringNoCase(const void *a1, const void *a2) {
// Can't work out the correct incantation to use modern casts here
return CompareCaseInsensitive(*(char**)(a1), *(char**)(a2));
}
static void SortWordList(char **words, unsigned int len) {
qsort(reinterpret_cast<void*>(words), len, sizeof(*words),
cmpString);
}
static void SortWordListNoCase(char **wordsNoCase, unsigned int len) {
qsort(reinterpret_cast<void*>(wordsNoCase), len, sizeof(*wordsNoCase),
cmpStringNoCase);
}
bool WordList::InList(const char *s) {
if (0 == words)
return false;
if (!sorted) {
sorted = true;
SortWordList(words, len);
for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)
starts[k] = -1;
for (int l = len - 1; l >= 0; l--) {
unsigned char indexChar = words[l][0];
starts[indexChar] = l;
}
}
unsigned char firstChar = s[0];
int j = starts[firstChar];
if (j >= 0) {
while (words[j][0] == firstChar) {
if (s[1] == words[j][1]) {
const char *a = words[j] + 1;
const char *b = s + 1;
while (*a && *a == *b) {
a++;
b++;
}
if (!*a && !*b)
return true;
}
j++;
}
}
j = starts['^'];
if (j >= 0) {
while (words[j][0] == '^') {
const char *a = words[j] + 1;
const char *b = s;
while (*a && *a == *b) {
a++;
b++;
}
if (!*a)
return true;
j++;
}
}
return false;
}
/**
* Returns an element (complete) of the wordlist array which has
* the same beginning as the passed string.
* The length of the word to compare is passed too.
* Letter case can be ignored or preserved (default).
*/
const char *WordList::GetNearestWord(const char *wordStart, int searchLen, bool ignoreCase /*= false*/, SString wordCharacters /*='/0' */, int wordIndex /*= -1 */) {
int start = 0; // lower bound of the api array block to search
int end = len - 1; // upper bound of the api array block to search
int pivot; // index of api array element just being compared
int cond; // comparison result (in the sense of strcmp() result)
const char *word; // api array element just being compared
if (0 == words)
return NULL;
if (ignoreCase) {
if (!sortedNoCase) {
sortedNoCase = true;
SortWordListNoCase(wordsNoCase, len);
}
while (start <= end) { // binary searching loop
pivot = (start + end) >> 1;
word = wordsNoCase[pivot];
cond = CompareNCaseInsensitive(wordStart, word, searchLen);
if (!cond) {
// find first word
start = pivot;
while (start > 0 && !CompareNCaseInsensitive(wordStart, wordsNoCase[start-1], searchLen)) {
start--;
}
// find last word
end = pivot;
while (end < len-1 && !CompareNCaseInsensitive(wordStart, wordsNoCase[end+1], searchLen)) {
end++;
}
// Finds first word in a series of equal words
for (pivot = start; pivot <= end; pivot++) {
word = wordsNoCase[pivot];
if (!wordCharacters.contains(word[searchLen])) {
if (wordIndex <= 0) // Checks if a specific index was requested
return word; // result must not be freed with free()
wordIndex--;
}
}
return NULL;
}
else if (cond > 0)
start = pivot + 1;
else if (cond < 0)
end = pivot - 1;
}
} else { // preserve the letter case
if (!sorted) {
sorted = true;
SortWordList(words, len);
}
while (start <= end) { // binary searching loop
pivot = (start + end) >> 1;
word = words[pivot];
cond = strncmp(wordStart, word, searchLen);
if (!cond) {
// find first word
start = pivot;
while (start > 0 && !strncmp(wordStart, words[start-1], searchLen)) {
start--;
}
// find last word
end = pivot;
while (end < len-1 && !strncmp(wordStart, words[end+1], searchLen)) {
end++;
}
// Finds first word in a series of equal words
pivot = start;
while (pivot <= end) {
word = words[pivot];
if (!wordCharacters.contains(word[searchLen])) {
if (wordIndex <= 0) // Checks if a specific index was requested
return word; // result must not be freed with free()
wordIndex--;
}
pivot++;
}
return NULL;
}
else if (cond > 0)
start = pivot + 1;
else if (cond < 0)
end = pivot - 1;
}
}
return NULL;
}
/**
* Find the length of a 'word' which is actually an identifier in a string
* which looks like "identifier(..." or "identifier" and where
* there may be extra spaces after the identifier that should not be
* counted in the length.
*/
static unsigned int LengthWord(const char *word, char otherSeparator) {
// Find a '('. If that fails go to the end of the string.
const char *endWord = strchr(word, '(');
if (!endWord && otherSeparator)
endWord = strchr(word, otherSeparator);
if (!endWord)
endWord = word + strlen(word);
// Last case always succeeds so endWord != 0
// Drop any space characters.
if (endWord > word) {
endWord--; // Back from the '(', otherSeparator, or '\0'
// Move backwards over any spaces
while ((endWord > word) && (IsASpace(*endWord))) {
endWord--;
}
}
return endWord - word;
}
/**
* Returns elements (first words of them) of the wordlist array which have
* the same beginning as the passed string.
* The length of the word to compare is passed too.
* Letter case can be ignored or preserved (default).
* If there are more words meeting the condition they are returned all of
* them in the ascending order separated with spaces.
*
* NOTE: returned buffer has to be freed with delete[].
*/
char *WordList::GetNearestWords(
const char *wordStart,
int searchLen,
bool ignoreCase /*= false*/,
char otherSeparator /*= '\0'*/,
bool exactLen /*=false*/) {
unsigned int wordlen; // length of the word part (before the '(' brace) of the api array element
SString wordsNear;
wordsNear.setsizegrowth(1000);
int start = 0; // lower bound of the api array block to search
int end = len - 1; // upper bound of the api array block to search
int pivot; // index of api array element just being compared
int cond; // comparison result (in the sense of strcmp() result)
if (0 == words)
return NULL;
if (ignoreCase) {
if (!sortedNoCase) {
sortedNoCase = true;
SortWordListNoCase(wordsNoCase, len);
}
while (start <= end) { // Binary searching loop
pivot = (start + end) / 2;
cond = CompareNCaseInsensitive(wordStart, wordsNoCase[pivot], searchLen);
if (!cond) {
// Find first match
while ((pivot > start) &&
(0 == CompareNCaseInsensitive(wordStart,
wordsNoCase[pivot-1], searchLen))) {
--pivot;
}
// Grab each match
while ((pivot <= end) &&
(0 == CompareNCaseInsensitive(wordStart,
wordsNoCase[pivot], searchLen))) {
wordlen = LengthWord(wordsNoCase[pivot], otherSeparator) + 1;
++pivot;
if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1)
continue;
wordsNear.append(wordsNoCase[pivot-1], wordlen, ' ');
}
return wordsNear.detach();
} else if (cond < 0) {
end = pivot - 1;
} else if (cond > 0) {
start = pivot + 1;
}
}
} else { // Preserve the letter case
if (!sorted) {
sorted = true;
SortWordList(words, len);
}
while (start <= end) { // Binary searching loop
pivot = (start + end) / 2;
cond = strncmp(wordStart, words[pivot], searchLen);
if (!cond) {
// Find first match
while ((pivot > start) &&
(0 == strncmp(wordStart,
words[pivot-1], searchLen))) {
--pivot;
}
// Grab each match
while ((pivot <= end) &&
(0 == strncmp(wordStart,
words[pivot], searchLen))) {
wordlen = LengthWord(words[pivot], otherSeparator) + 1;
++pivot;
if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1)
continue;
wordsNear.append(words[pivot-1], wordlen, ' ');
}
return wordsNear.detach();
} else if (cond < 0) {
end = pivot - 1;
} else if (cond > 0) {
start = pivot + 1;
}
}
}
return NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -