📄 propset.cxx
字号:
lenKey = static_cast<int>(strlen(key)); unsigned int hash = HashString(key, lenKey); ScProperty *pPrev = NULL; for (ScProperty *p = props[hash % hashRoots]; p; p = p->next) { if ((hash == p->hash) && ((strlen(p->key) == static_cast<unsigned int>(lenKey)) && (0 == strncmp(p->key, key, lenKey)))) { if (pPrev) pPrev->next = p->next; else props[hash % hashRoots] = p->next; if (p == enumnext) enumnext = p->next; // Not that anyone should mix enum and Set / Unset. delete [](p->key); delete [](p->val); delete p; return; } else { pPrev = p; } }}void PropSet::SetMultiple(const char *s) { const char *eol = strchr(s, '\n'); while (eol) { Set(s); s = eol + 1; eol = strchr(s, '\n'); } Set(s);}SString PropSet::Get(const char *key) { unsigned int hash = HashString(key, strlen(key)); for (ScProperty *p = props[hash % hashRoots]; p; p = p->next) { if ((hash == p->hash) && (0 == strcmp(p->key, key))) { return p->val; } } if (superPS) { // Failed here, so try in base property set return superPS->Get(key); } else { return ""; }}bool PropSet::IncludesVar(const char *value, const char *key) { const char *var = strstr(value, "$("); while (var) { if (isprefix(var + 2, key) && (var[2 + strlen(key)] == ')')) { // Found $(key) which would lead to an infinite loop so exit return true; } var = strstr(var + 2, ")"); if (var) var = strstr(var + 1, "$("); } return false;}// There is some inconsistency between GetExpanded("foo") and Expand("$(foo)").// A solution is to keep a stack of variables that have been expanded, so that// recursive expansions can be skipped. For now I'll just use the C++ stack// for that, through a recursive function and a simple chain of pointers.struct VarChain { VarChain(const char*var_=NULL, const VarChain *link_=NULL): var(var_), link(link_) {} bool contains(const char *testVar) const { return (var && (0 == strcmp(var, testVar))) || (link && link->contains(testVar)); } const char *var; const VarChain *link;};static int ExpandAllInPlace(PropSet &props, SString &withVars, int maxExpands, const VarChain &blankVars = VarChain()) { int varStart = withVars.search("$("); while ((varStart >= 0) && (maxExpands > 0)) { int varEnd = withVars.search(")", varStart+2); if (varEnd < 0) { break; } // For consistency, when we see '$(ab$(cde))', expand the inner variable first, // regardless whether there is actually a degenerate variable named 'ab$(cde'. int innerVarStart = withVars.search("$(", varStart+2); while ((innerVarStart > varStart) && (innerVarStart < varEnd)) { varStart = innerVarStart; innerVarStart = withVars.search("$(", varStart+2); } SString var(withVars.c_str(), varStart + 2, varEnd); SString val = props.Get(var.c_str()); if (blankVars.contains(var.c_str())) { val.clear(); // treat blankVar as an empty string (e.g. to block self-reference) } if (--maxExpands >= 0) { maxExpands = ExpandAllInPlace(props, val, maxExpands, VarChain(var.c_str(), &blankVars)); } withVars.remove(varStart, varEnd-varStart+1); withVars.insert(varStart, val.c_str(), val.length()); varStart = withVars.search("$("); } return maxExpands;}SString PropSet::GetExpanded(const char *key) { SString val = Get(key); ExpandAllInPlace(*this, val, 100, VarChain(key)); return val;}SString PropSet::Expand(const char *withVars, int maxExpands) { SString val = withVars; ExpandAllInPlace(*this, val, maxExpands); return val;}int PropSet::GetInt(const char *key, int defaultValue) { SString val = GetExpanded(key); if (val.length()) return val.value(); return defaultValue;}bool isprefix(const char *target, const char *prefix) { while (*target && *prefix) { if (*target != *prefix) return false; target++; prefix++; } if (*prefix) return false; else return true;}static bool IsSuffix(const char *target, const char *suffix, bool caseSensitive) { size_t lentarget = strlen(target); size_t lensuffix = strlen(suffix); if (lensuffix > lentarget) return false; if (caseSensitive) { for (int i = static_cast<int>(lensuffix) - 1; i >= 0; i--) { if (target[i + lentarget - lensuffix] != suffix[i]) return false; } } else { for (int i = static_cast<int>(lensuffix) - 1; i >= 0; i--) { if (MakeUpperCase(target[i + lentarget - lensuffix]) != MakeUpperCase(suffix[i])) return false; } } return true;}SString PropSet::GetWild(const char *keybase, const char *filename) { for (int root = 0; root < hashRoots; root++) { for (ScProperty *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 (IsSuffix(filename, keyfile + 1, caseSensitiveFilenames)) { *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++) { ScProperty *p = props[root]; while (p) { ScProperty *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 (ScProperty *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 (ScProperty *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 (ScProperty *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 (ScProperty *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]; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -