+
+/**
+ * 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 /*= -1*/, 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 (!sorted) {
+ sorted = true;
+ SortWordList(words, wordsNoCase, len);
+ }
+ if (ignoreCase) {
+ while (start <= end) { // binary searching loop
+ pivot = (start + end) >> 1;
+ word = wordsNoCase[pivot];
+ cond = CompareNCaseInsensitive(wordStart, word, searchLen);
+ if (!cond && (!wordCharacters.contains(word[searchLen]))) {
+ // Found a word in a binary fashion. Now checks if a specific index was requested
+ if (wordIndex < 0)
+ return word; // result must not be freed with free()
+
+ // Finds first word in a series of equal words
+ int first = pivot;
+ end = pivot - 1;
+ while (start <= end) {
+ pivot = (start + end) >> 1;
+ word = wordsNoCase[pivot];
+ cond = CompareNCaseInsensitive(wordStart, word, searchLen);
+ if (!cond && (!wordCharacters.contains(word[searchLen]))) {
+ // Found another word
+ first = pivot;
+ end = pivot - 1;
+ }
+ else if (cond > 0)
+ start = pivot + 1;
+ else if (cond <= 0)
+ break;
+ }
+
+ // Gets the word at the requested index
+ word = wordsNoCase[first + wordIndex];
+ return word;
+ }
+ else if (cond > 0)
+ start = pivot + 1;
+ else if (cond <= 0)
+ end = 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 && (!wordCharacters.contains(word[searchLen]))) {
+ // Found a word in a binary fashion. Now checks if a specific index was requested
+ if (wordIndex < 0)
+ return word; // result must not be freed with free()
+
+ // Finds first word in a series of equal words
+ int first = pivot;
+ end = pivot - 1;
+ while (start <= end) {
+ pivot = (start + end) >> 1;
+ word = words[pivot];
+ cond = strncmp(wordStart, word, searchLen);
+ if (!cond && (!wordCharacters.contains(word[searchLen]))) {
+ // Found another word
+ first = pivot;
+ end = pivot - 1;
+ }
+ else if (cond > 0)
+ start = pivot + 1;
+ else if (cond <= 0)
+ break;
+ }
+
+ // Gets the word at the requested index
+ word = words[first + wordIndex];
+ return word;
+ }
+ 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:" 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 '(', or ':'. If that fails go to the end of the string.
+ const char *endWord = strchr(word, '(');
+ if (!endWord)
+ 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 '(', ':', 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 /*= -1*/,
+ 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 (!sorted) {
+ sorted = true;
+ SortWordList(words, wordsNoCase, len);
+ }
+ if (ignoreCase) {
+ 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;
+ if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1)
+ break;
+ wordsNear.append(wordsNoCase[pivot], wordlen, ' ');
+ ++pivot;
+ }
+ return wordsNear.detach();
+ } 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) / 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;
+ if (exactLen && wordlen != LengthWord(wordStart, otherSeparator) + 1)
+ break;
+ wordsNear.append(words[pivot], wordlen, ' ');
+ ++pivot;
+ }
+ return wordsNear.detach();
+ } else if (cond < 0) {
+ end = pivot - 1;
+ } else if (cond > 0) {
+ start = pivot + 1;
+ }
+ }
+ }
+ return NULL;
+}