diff --git a/sc2/ChangeLog b/sc2/ChangeLog index 035f5a270..44948ae44 100644 --- a/sc2/ChangeLog +++ b/sc2/ChangeLog @@ -1,6 +1,6 @@ Changes towards version 0.5: - Added star search in Starmap (define Menu-Search and Menu-Next keys - in your keys.cfg) from kworces, Alex + in your keys.cfg) from kworces, Alex, SvdB - Fixed Orz greeting at Taalo homeworld inconsistency (bug #819) - Alex - Fixed Venus' atmo density to 90 times that of Earth (bug #821) - Alex - Internationalization fixes: better or, in some cases, fixed support of diff --git a/sc2/src/sc2code/libs/strings/unicode.c b/sc2/src/sc2code/libs/strings/unicode.c index fbbe49d7b..0020e0866 100644 --- a/sc2/src/sc2code/libs/strings/unicode.c +++ b/sc2/src/sc2code/libs/strings/unicode.c @@ -269,6 +269,58 @@ utf8StringCopy (unsigned char *dst, size_t size, const unsigned char *src) return dst; } +// TODO: Better matching. It's now just based on the char number. +static inline int +utf8CompareChar (wchar_t ch1, wchar_t ch2) +{ + if (ch1 < ch2) + return -1; + + if (ch1 > ch2) + return 1; + + return 0; +} + +int +utf8StringCompare (const unsigned char *str1, const unsigned char *str2) +{ + wchar_t ch1; + wchar_t ch2; + + for (;;) + { + int cmp; + + ch1 = getCharFromString(&str1); + ch2 = getCharFromString(&str2); + if (ch1 == '\0' || ch2 == '\0') + break; + + cmp = utf8CompareChar (ch1, ch2); + if (cmp != 0) + return cmp; + } + + if (ch1 != '\0') + { + // ch2 == '\0' + // str2 ends, str1 continues + return 1; + } + + if (ch2 != '\0') + { + // ch1 == '\0' + // str1 ends, str2 continues + return -1; + } + + // ch1 == '\0' && ch2 == '\0'. + // Strings match completely. + return 0; +} + unsigned char * skipUTF8Chars(const unsigned char *ptr, size_t num) { wchar_t ch; diff --git a/sc2/src/sc2code/planets/pstarmap.c b/sc2/src/sc2code/planets/pstarmap.c index 44aef6d99..167ece44f 100644 --- a/sc2/src/sc2code/planets/pstarmap.c +++ b/sc2/src/sc2code/planets/pstarmap.c @@ -802,10 +802,43 @@ typedef struct starsearch_state UNICODE Buffer[STAR_SEARCH_BUFSIZE]; UNICODE *Prefix; UNICODE *Cluster; + int SortedStars[NUM_SOLAR_SYSTEMS]; int PrefixLen; int ClusterLen; } STAR_SEARCH_STATE; +static int +compStarName (const void *ptr1, const void *ptr2) { + int index1; + int index2; + + index1 = *(const int *) ptr1; + index2 = *(const int *) ptr2; + if (star_array[index1].Postfix != star_array[index2].Postfix) { + return utf8StringCompare (GAME_STRING (star_array[index1].Postfix), + GAME_STRING (star_array[index2].Postfix)); + } + + if (star_array[index1].Prefix < star_array[index2].Prefix) + return -1; + + if (star_array[index1].Prefix > star_array[index2].Prefix) + return 1; + + return 0; +} + +static void +SortStarsOnName (STAR_SEARCH_STATE *pSS) { + int i; + int *sorted = pSS->SortedStars; + + for (i = 0; i < NUM_SOLAR_SYSTEMS; i++) + sorted[i] = i; + + qsort (sorted, NUM_SOLAR_SYSTEMS, sizeof (int), compStarName); +} + static BOOLEAN OnStarNameChange (PTEXTENTRY_STATE pTES) { @@ -878,31 +911,22 @@ SplitStarName (STAR_SEARCH_STATE *pSS) pSS->PrefixLen = utf8StringCount (pSS->Prefix); } +// Returns the index in the sorted array with the specified Postfix. static int -GetFirstClusterStar (BYTE Postfix) +GetFirstClusterStarIndex (int *sortedStars, BYTE Postfix) { + // Linear search. A binary search would work, but why bother. int i; - int min = -1; - int min_pref = 1000; - STAR_DESCPTR SDPtr; - - for (i = 0, SDPtr = star_array; i < NUM_SOLAR_SYSTEMS; ++i, ++SDPtr) - { - if (SDPtr->Postfix != Postfix) - continue; - if (SDPtr->Prefix < min_pref) - { - min_pref = SDPtr->Prefix; - min = i; - } + for (i = 0; i < NUM_SOLAR_SYSTEMS; i++) { + if (star_array[sortedStars[i]].Postfix == Postfix) + return i; } - - return min; + return -1; } static int -FindNextStar (STAR_SEARCH_STATE *pSS, int from, BOOLEAN WithinClust) +FindNextStarIndex (STAR_SEARCH_STATE *pSS, int from, BOOLEAN WithinClust) { int i; @@ -911,7 +935,7 @@ FindNextStar (STAR_SEARCH_STATE *pSS, int from, BOOLEAN WithinClust) for (i = from; i < NUM_SOLAR_SYSTEMS; ++i) { - STAR_DESCPTR SDPtr = star_array + i; + STAR_DESCPTR SDPtr = &star_array[pSS->SortedStars[i]]; UNICODE FullName[STAR_SEARCH_BUFSIZE]; UNICODE *ClusterName = GAME_STRING (SDPtr->Postfix); UNICODE *sptr; @@ -944,7 +968,8 @@ FindNextStar (STAR_SEARCH_STATE *pSS, int from, BOOLEAN WithinClust) if (!pSS->Prefix) { // searching for cluster name only // return only the first stars in a cluster - if (i == GetFirstClusterStar (SDPtr->Postfix)) + if (i == GetFirstClusterStarIndex ( + pSS->SortedStars, SDPtr->Postfix)) break; else continue; @@ -980,7 +1005,7 @@ DrawMatchedStarName (PTEXTENTRY_STATE pTES) PMENU_STATE pMS = pSS->pMS; UNICODE buf[STAR_SEARCH_BUFSIZE] = ""; SIZE ExPos = 0; - STAR_DESCPTR SDPtr = star_array + pSS->CurIndex; + STAR_DESCPTR SDPtr = &star_array[pSS->SortedStars[pSS->CurIndex]]; if (pSS->SingleClust || pSS->SingleMatch) { // draw full star name @@ -1033,7 +1058,7 @@ OnStarNameFrame (PTEXTENTRY_STATE pTES) SplitStarName (pSS); } - pSS->CurIndex = FindNextStar (pSS, pSS->CurIndex + 1, + pSS->CurIndex = FindNextStarIndex (pSS, pSS->CurIndex + 1, pSS->SingleClust); if (pSS->FirstIndex < 0) // first search pSS->FirstIndex = pSS->CurIndex; @@ -1052,7 +1077,7 @@ OnStarNameFrame (PTEXTENTRY_STATE pTES) { // only one cluster matching pSS->SingleClust = TRUE; // reset the first - pSS->FirstIndex = FindNextStar (pSS, 0, TRUE); + pSS->FirstIndex = FindNextStarIndex (pSS, 0, TRUE); } else { //exact match @@ -1070,7 +1095,7 @@ OnStarNameFrame (PTEXTENTRY_STATE pTES) } // move the cursor to the found star - SDPtr = star_array + pSS->CurIndex; + SDPtr = &star_array[pSS->SortedStars[pSS->CurIndex]]; UpdateCursorLocation (pMS, 0, 0, &SDPtr->star_pt); DrawMatchedStarName (pTES); @@ -1101,6 +1126,7 @@ DoStarSearch (PMENU_STATE pMS) pss->LastChangeTime = 0; pss->LastText[0] = '\0'; pss->FirstIndex = -1; + SortStarsOnName (pss); // text entry setup tes.Initialized = FALSE;