diff options
Diffstat (limited to 'src/PropSet.cxx')
-rw-r--r-- | src/PropSet.cxx | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/src/PropSet.cxx b/src/PropSet.cxx new file mode 100644 index 000000000..7e2a906a4 --- /dev/null +++ b/src/PropSet.cxx @@ -0,0 +1,399 @@ +// SciTE - Scintilla based Text Editor +// PropSet.cxx - a java style properties file module +// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org> +// The License.txt file describes the conditions under which this software may be distributed. + +// Maintain a dictionary of properties + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> + +#include "Platform.h" + +#include "PropSet.h" + +bool EqualCaseInsensitive(const char *a, const char *b) { +#if PLAT_GTK + return 0 == strcasecmp(a, b); +#elif PLAT_WIN + return 0 == stricmp(a, b); +#elif PLAT_WX + return 0 == wxStricmp(a, b); +#endif +} + +// Get a line of input. If end of line escaped with '\\' then continue reading. +static bool GetFullLine(const char *&fpc, int &lenData, char *s, int len) { + bool continuation = true; + while ((len > 1) && lenData > 0) { + char ch = *fpc; + fpc++; + lenData--; + if ((ch == '\r') || (ch == '\n')) { + if (!continuation) { + if ((lenData > 0) && (ch == '\r') && ((*fpc) == '\n')) { + // munch the second half of a crlf + fpc++; + lenData--; + } + *s++ = '\0'; + return true; + } + } else if ((ch == '\\') && (lenData > 0) && ((*fpc == '\r') || (*fpc == '\n'))) { + continuation = true; + } else { + continuation = false; + *s++ = ch; + len--; + } + } + return false; +} + +PropSet::PropSet() { + superPS = 0; + size = 10; + used = 0; + vals = new char * [size]; +} + +PropSet::~PropSet() { + superPS = 0; + Clear(); + delete []vals; +} + +void PropSet::EnsureCanAddEntry() { + if (used >= size - 2) { + int newsize = size + 10; + char **newvals = new char * [newsize]; + + for (int i = 0; i < used; i++) { + newvals[i] = vals[i]; + } + delete []vals; + vals = newvals; + size = newsize; + } +} + +void PropSet::Set(const char *key, const char *val) { + EnsureCanAddEntry(); + for (int i = 0; i < used; i += 2) { + if (EqualCaseInsensitive(vals[i], key)) { + // Replace current value + delete [](vals[i + 1]); + vals[i + 1] = StringDup(val); + return; + } + } + // Not found + vals[used++] = StringDup(key); + vals[used++] = StringDup(val); +} + +void PropSet::Set(char *keyval) { + char *eqat = strchr(keyval, '='); + if (eqat) { + *eqat = '\0'; + Set(keyval, eqat + 1); + *eqat = '='; + } +} + +SString PropSet::Get(const char *key) { + for (int i = 0; i < used; i += 2) { + if (EqualCaseInsensitive(vals[i], key)) { + return vals[i + 1]; + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->Get(key); + } else { + return ""; + } +} + +int PropSet::GetInt(const char *key, int defaultValue) { + SString val = Get(key); + if (val.length()) + return Get(key).value(); + else + return defaultValue; +} + +bool isprefix(const char *target, const char *prefix) { + while (*target && *prefix) { + if (toupper(*target) != toupper(*prefix)) + return false; + target++; + prefix++; + } + if (*prefix) + return false; + else + return true; +} + +bool issuffix(const char *target, const char *suffix) { + int lentarget = strlen(target); + int lensuffix = strlen(suffix); + if (lensuffix > lentarget) + return false; + for (int i = lensuffix - 1; i >= 0; i--) { + if (toupper(target[i + lentarget - lensuffix]) != toupper(suffix[i])) + return false; + } + return true; +} + +SString PropSet::GetWild(const char *keybase, const char *filename) { + for (int i = 0; i < used; i += 2) { + if (isprefix(vals[i], keybase)) { + char *orgkeyfile = vals[i] + strlen(keybase); + char *keyfile = NULL; + + if (strstr(orgkeyfile, "$(") == orgkeyfile) { + char *cpendvar = strchr(orgkeyfile, ')'); + if (cpendvar) { + int lenvar = cpendvar - orgkeyfile - 2; // Subtract the $() + char *var = static_cast<char *>(malloc(lenvar + 1)); + strncpy(var, orgkeyfile + 2, lenvar); + var[lenvar] = '\0'; + SString s = Get(var); + free(var); + keyfile = strdup(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)) { + *del = delchr; + free(keyptr); + return vals[i + 1]; + } + } else if (EqualCaseInsensitive(keyfile, filename)) { + *del = delchr; + free(keyptr); + return vals[i + 1]; + } + if (delchr == '\0') + break; + *del = delchr; + keyfile = del + 1; + } + free(keyptr); + + if (EqualCaseInsensitive(vals[i], keybase)) { + return vals[i + 1]; + } + } + } + if (superPS) { + // Failed here, so try in base property set + return superPS->GetWild(keybase, filename); + } else { + return ""; + } +} + +SString PropSet::GetNewExpand(const char *keybase, const char *filename) { + char *base = StringDup(GetWild(keybase, filename).c_str()); + char *cpvar = strstr(base, "$("); + while (cpvar) { + char *cpendvar = strchr(cpvar, ')'); + if (cpendvar) { + int lenvar = cpendvar - cpvar - 2; // Subtract the $() + char *var = new char[lenvar + 1]; + strncpy(var, cpvar + 2, lenvar); + var[lenvar] = '\0'; + SString val = GetWild(var, filename); + int 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, "$("); + } + SString sret = base; + delete []base; + return sret; +} + +void PropSet::Clear() { + for (int i = 0; i < used; i++) { + delete [](vals[i]); + vals[i] = 0; + } + used = 0; +} + +void PropSet::ReadFromMemory(const char *data, int len) { + if (len > 0) { + const char *pd = data; + char linebuf[60000]; + while (GetFullLine(pd, len, linebuf, sizeof(linebuf))) { + if (isalpha(linebuf[0])) + Set(linebuf); + } + } +} + +void PropSet::Read(const char *filename) { + //printf("Opening properties <%s>\n", filename); + Clear(); + char propsData[60000]; + FILE *rcfile = fopen(filename, "rb"); + if (rcfile) { + int lenFile = fread(propsData, 1, sizeof(propsData), rcfile); + fclose(rcfile); + ReadFromMemory(propsData, lenFile); + } else { + //printf("Could not open <%s>\n", filename); + } +} + +static bool iswordsep(char ch, bool onlyLineEnds) { + if (!isspace(ch)) + return false; + if (!onlyLineEnds) + return true; + return ch == '\r' || ch == '\n'; +} + +// Creates an array that points into each word in the string and puts \0 terminators +// after each word. +static char **ArrayFromWordList(char *wordlist, bool onlyLineEnds = false) { + char prev = '\n'; + int words = 0; + for (int j = 0; wordlist[j]; j++) { + if (!iswordsep(wordlist[j], onlyLineEnds) && iswordsep(prev, onlyLineEnds)) + words++; + prev = wordlist[j]; + } + char **keywords = new char * [words + 1]; + if (keywords) { + words = 0; + prev = '\0'; + int len = strlen(wordlist); + for (int k = 0; k < len; k++) { + if (!iswordsep(wordlist[k], onlyLineEnds)) { + if (!prev) { + keywords[words] = &wordlist[k]; + words++; + } + } else { + wordlist[k] = '\0'; + } + prev = wordlist[k]; + } + keywords[words] = &wordlist[len]; + } + return keywords; +} + +void WordList::Clear() { + if (words) { + delete []words; + delete []list; + } + words = 0; + list = 0; + len = 0; +} + +void WordList::Set(const char *s) { + len = 0; + list = StringDup(s); + words = ArrayFromWordList(list, onlyLineEnds); +} + +char *WordList::Allocate(int size) { + list = new char[size + 1]; + list[size] = '\0'; + return list; +} + +void WordList::SetFromAllocated() { + len = 0; + words = ArrayFromWordList(list, onlyLineEnds); +} + +// Shell sort based upon public domain C implementation by Raymond Gardner 1991 +// Used here because of problems with mingw qsort. +static void SortWordList(char **words, unsigned int len) { + unsigned int gap = len / 2; + + while (gap > 0) { + unsigned int i = gap; + while (i < len) { + unsigned int j = i; + char **a = words + j; + do { + j -= gap; + char **b = a; + a -= gap; + if (strcmp(*a, *b) > 0) { + char *tmp = *a; + *a = *b; + *b = tmp; + } else { + break; + } + } while (j >= gap); + i++; + } + gap = gap / 2; + } +} + +bool WordList::InList(const char *s) { + if (0 == words) + return false; + if (len == 0) { + for (int i = 0; words[i][0]; i++) + len++; + SortWordList(words, len); + for (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++; + } + } + return false; +} |