diff options
Diffstat (limited to 'src/PropSet.cxx')
| -rw-r--r-- | src/PropSet.cxx | 271 | 
1 files changed, 267 insertions, 4 deletions
| diff --git a/src/PropSet.cxx b/src/PropSet.cxx index 42c5869c9..66018544a 100644 --- a/src/PropSet.cxx +++ b/src/PropSet.cxx @@ -336,6 +336,7 @@ static bool iswordsep(char ch, bool onlyLineEnds) {  // 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) { +#if 0  	char prev = '\n';  	int words = 0;  	for (int j = 0; wordlist[j]; j++) { @@ -364,15 +365,49 @@ static char **ArrayFromWordList(char *wordlist, int *len, bool onlyLineEnds = fa  	} else {  		*len = 0;  	} +#else +	int words = 0; // length of the returned buffer of pointers +	#undef APICHUNK // how many pointers will be pre-allocated (to avoid buffer reallocation on each new pointer) +	#define APICHUNK 256 +	int size = APICHUNK; // real size of the returned buffer of pointers +	char **keywords; // buffer for the pointers returned +	int slen = strlen(wordlist); //length of the buffer with api file +	keywords = (char**) malloc((size + 1) * sizeof (*keywords)); +	words = 0; +	for (int k = 0;;) { +		while (iswordsep(wordlist[k], onlyLineEnds)) +			wordlist[k++] = '\0'; +		if (k >= slen) +			break; +		if (words >= size) { +			do +				size += APICHUNK; +			while (size <= words); +			keywords = (char**) realloc(keywords, (size + 1) * sizeof (*keywords)); +		} +		keywords[words++] = wordlist + k; +		do +			if (k < slen) +				k++; +			else +				goto out; +		while (!iswordsep(wordlist[k], onlyLineEnds)); +	} +out: +	keywords[words] = wordlist + slen; +	*len = words; +#endif  	return keywords;  }  void WordList::Clear() {  	if (words) { -		delete []words;  		delete []list; +		free(words); +		free(wordsNoCase);  	}  	words = 0; +	wordsNoCase = 0;  	list = 0;  	len = 0;  	sorted = false; @@ -382,6 +417,8 @@ void WordList::Set(const char *s) {  	list = StringDup(s);  	sorted = false;  	words = ArrayFromWordList(list, &len, onlyLineEnds); +	wordsNoCase = (char**) malloc ((len + 1) * sizeof (*wordsNoCase)); +	memcpy(wordsNoCase, words, (len + 1) * sizeof (*words));  }  char *WordList::Allocate(int size) { @@ -393,6 +430,8 @@ char *WordList::Allocate(int size) {  void WordList::SetFromAllocated() {  	sorted = false;  	words = ArrayFromWordList(list, &len, onlyLineEnds); +	wordsNoCase = (char**) malloc ((len + 1) * sizeof (*wordsNoCase)); +	memcpy(wordsNoCase, words, (len + 1) * sizeof (*words));  }  int cmpString(const void *a1, const void *a2) { @@ -400,17 +439,24 @@ int cmpString(const void *a1, const void *a2) {      return strcmp(*(char**)(a1), *(char**)(a2));  } -static void SortWordList(char **words, unsigned int len) { +int cmpStringNoCase(const void *a1, const void *a2) { +    // Can't work out the correct incantation to use modern casts here +    return strcasecmp(*(char**)(a1), *(char**)(a2)); +} + +static void SortWordList(char **words, char **wordsNoCase, unsigned int len) {  	qsort(reinterpret_cast<void*>(words), len, sizeof(*words),  		cmpString); +	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); +		SortWordList(words, wordsNoCase, len);  		for (unsigned int k = 0; k < (sizeof(starts) / sizeof(starts[0])); k++)  			starts[k] = -1;  		for (int l = len - 1; l >= 0; l--) { @@ -437,3 +483,220 @@ bool WordList::InList(const char *s) {  	}  	return false;  } + +/** + * Returns an element (complete) of the wordlist array which has the beginning + * the same 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 /*= -1*/, bool ignoreCase /*= false*/) { +	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 (!sorted) { +		sorted = true; +		SortWordList(words, wordsNoCase, len); +	} +	if (ignoreCase) +		while (start <= end) { // binary searching loop +			pivot = (start + end) >> 1; +			word = wordsNoCase[pivot]; +			cond = strncasecmp(wordStart, word, searchLen); +			if (!cond && nonFuncChar(word[searchLen])) // maybe there should be a "non-word character" test here? +				return word; // result must not be freed with free() +			else if (cond < 0) +				end = pivot - 1; +			else if (cond > 0) +				start = pivot + 1; +		} +	else // preserve the letter case +		while (start <= end) { // binary searching loop +			pivot = (start + end) >> 1; +			word = words[pivot]; +			cond = strncmp(wordStart, word, searchLen); +			if (!cond && nonFuncChar(word[searchLen])) // maybe there should be a "non-word character" test here? +				return word; // result must not be freed with free() +			else if (cond >= 0) +				start = pivot + 1; +			else if (cond < 0) +				end = pivot - 1; +		} +	return NULL; +} +	 +/** + * Returns elements (first words of them) of the wordlist array which have + * the beginning the same 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 a free() call. + */ +char *WordList::GetNearestWords(const char *wordStart, int searchLen /*= -1*/, bool ignoreCase /*= false*/) { +	int wordlen; // length of the word part (before the '(' brace) of the api array element +	int length = 0; // length of the returned buffer of words (string) +	int newlength; // length of the new buffer before the reallocating itself +	#undef WORDCHUNK // how many characters will be pre-allocated (to avoid buffer reallocation on each new word) +	#define WORDCHUNK 100 +	int size = WORDCHUNK; // real size of the returned buffer of words +	char *buffer; // buffer for the words returned +	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) +	int oldpivot; // pivot storage to be able to browse the api array upwards and then downwards +	const char *word; // api array element just being compared +	const char *brace; // position of the opening brace in the api array element just being compared + +	if (0 == words) +		return NULL; +	if (!sorted) { +		sorted = true; +		SortWordList(words, wordsNoCase, len); +	} +	buffer = (char*) malloc(size); +	*buffer = '\0'; +	if (ignoreCase) +		while (start <= end) { // binary searching loop +			pivot = (start + end) >> 1; +			word = wordsNoCase[pivot]; +			cond = strncasecmp(wordStart, word, searchLen); +			if (!cond) { +				oldpivot = pivot; +				do { // browse sequentially the rest after the hit +					brace = strchr(word, '('); +					if (brace) +						wordlen = brace - word; +					else +						wordlen = strlen(word); +					newlength = length + wordlen; // stretch the buffer +					if (length) +						newlength++; +					if (newlength >= size) { +						do +							size += WORDCHUNK; +						while (size <= newlength); +						buffer = (char*) realloc(buffer, size); +					} +					if (length) // append a new entry +						buffer[length++] = ' '; +					memcpy(buffer + length, word, wordlen); +					length = newlength; +					buffer[length] = '\0'; +					if (++pivot >= end) +						break; +					word = wordsNoCase[pivot]; +				} while (!strncasecmp(wordStart, word, searchLen)); + +				pivot = oldpivot; +				for (;;) { // browse sequentially the rest before the hit +					if (--pivot < start) +						break; +					word = wordsNoCase[pivot]; +					if (strncasecmp(wordStart, word, searchLen)) +						break;                  +					brace = strchr(word, '('); +					if (brace) +						wordlen = brace - word; +					else +						wordlen = strlen(word); +					newlength = length + wordlen; // stretch the buffer +					if (length) +						newlength++; +					if (newlength >= size) +					{ +						do +							size += WORDCHUNK; +						while (size <= newlength); +						buffer = (char*) realloc(buffer, size); +					} +					if (length) // append a new entry +						buffer[length++] = ' '; +					memcpy(buffer + length, word, wordlen); +					length = newlength; +					buffer[length] = '\0'; +				} +				return buffer; // result has to be freed with free() +			} +			else if (cond < 0) +				end = pivot - 1; +			else if (cond > 0) +				start = pivot + 1; +		} +	else // preserve the letter case +		while (start <= end) { // binary searching loop +			pivot = (start + end) >> 1; +			word = words[pivot]; +			cond = strncmp(wordStart, word, searchLen); +			if (!cond) { +				oldpivot = pivot; +				do { // browse sequentially the rest after the hit +					brace = strchr(word, '('); +					if (brace) +						wordlen = brace - word; +					else +						wordlen = strlen(word); +					newlength = length + wordlen; // stretch the buffer +					if (length) +						newlength++; +					if (newlength >= size) +					{ +						do +							size += WORDCHUNK; +						while (size <= newlength); +						buffer = (char*) realloc(buffer, size); +					} +					if (length) // append a new entry +						buffer[length++] = ' '; +					memcpy(buffer + length, word, wordlen); +					length = newlength; +					buffer[length] = '\0'; +					if (++pivot >= end) +						break; +					word = words[pivot]; +				} while (!strncmp(wordStart, word, searchLen)); + +				pivot = oldpivot; +				for (;;) { // browse sequentially the rest before the hit +					if (--pivot < start) +						break; +					word = words[pivot]; +					if (strncmp(wordStart, word, searchLen)) +						break; +					brace = strchr(word, '('); +					if (brace) +						wordlen = brace - word; +					else +						wordlen = strlen(word); +					newlength = length + wordlen; // stretch the buffer +					if (length) +						newlength++; +					if (newlength >= size) +					{ +						do +							size += WORDCHUNK; +						while (size <= newlength); +						buffer = (char*) realloc(buffer, size); +					} +					if (length) // append a new entry +						buffer[length++] = ' '; +					memcpy(buffer + length, word, wordlen); +					length = newlength; +					buffer[length] = '\0'; +				} +				return buffer; // result has to be freed with free() +			} +			else if (cond < 0) +				end = pivot - 1; +			else if (cond > 0) +				start = pivot + 1; +		} +	free(buffer); +	return NULL; +} | 
