// Similar to BE_Cross_strcasecmp, but compares up to count chars int BE_Cross_strncasecmp(const char *s1, const char *s2, size_t count) { unsigned char uc1, uc2; for (; count && (*s1) && (BE_Cross_toupper(*s1) == BE_Cross_toupper(*s2)); s1++, s2++, count--); // If done, return 0 if (!count) return 0; // Otherwise behave as in BE_Cross_strcasecmp uc1 = (unsigned char)((char)(BE_Cross_toupper(*s1))); uc2 = (unsigned char)((char)(BE_Cross_toupper(*s2))); return ((int)uc1 - (int)uc2); }
int BE_Cross_strcasecmp(const char *s1, const char *s2) { unsigned char uc1, uc2; /* This one is easy. We don't care if a value is signed or not. */ /* All that matters here is consistency (everything is signed). */ for (; (*s1) && (BE_Cross_toupper(*s1) == BE_Cross_toupper(*s2)); s1++, s2++); /* But now, first we cast from int to char, and only *then* to */ /* unsigned char, so the correct difference can be calculated. */ uc1 = (unsigned char)((char)(BE_Cross_toupper(*s1))); uc2 = (unsigned char)((char)(BE_Cross_toupper(*s2))); /* We should still cast back to int, for a signed difference. */ /* Assumption: An int can store any unsigned char value. */ return ((int)uc1 - (int)uc2); }
int BE_Cross_GetSortedRewritableFilenames_AsUpperCase(char *outFilenames, int maxNum, int strLenBound, const char *suffix) { struct dirent *direntry; size_t sufLen = strlen(suffix); char *nextFilename = outFilenames, *outFilenamesEnd = outFilenames + maxNum*strLenBound, *outFilenamesLast = outFilenamesEnd - strLenBound; char *checkFilename, *checkCh; DIR *dir; // For the sake of consistency we go over same paths as in file open for reading function const char *searchpaths[] = {g_be_selectedGameInstallation->writableVanillaFilesPath, g_be_selectedGameInstallation->path}; for (int loopvar = 0; loopvar < (int)(sizeof(searchpaths)/sizeof(*searchpaths)); ++loopvar) { dir = opendir(searchpaths[loopvar]); if (!dir) { continue; } for (direntry = readdir(dir); direntry; direntry = readdir(dir)) { size_t len = strlen(direntry->d_name); if ((len < sufLen) || BE_Cross_strcasecmp(direntry->d_name+len-sufLen, suffix)) { continue; } len -= sufLen; /*** Possibly a HACK - Modify d_name itself ***/ len = (len >= (size_t)strLenBound) ? (strLenBound-1) : len; direntry->d_name[len] = '\0'; // Convert to upper case for (checkCh = direntry->d_name; *checkCh; ++checkCh) { *checkCh = BE_Cross_toupper(*checkCh); } // This is basically insertion-sort, but we store // the *last* entries if there isn't enough room. for (checkFilename = outFilenames; checkFilename < nextFilename; checkFilename += strLenBound) { if (strcmp(checkFilename, direntry->d_name) > 0) { break; } } // Gone over all inserted entries if (checkFilename == nextFilename) { if (nextFilename < outFilenamesEnd) { memcpy(nextFilename, direntry->d_name, 1+len); nextFilename += strLenBound; } else { memmove(outFilenames, outFilenames+strLenBound, strLenBound*(maxNum-1)); memcpy(outFilenamesLast, direntry->d_name, 1+len); } } // Shift existing entries and insert new one else { // If there's room for another entry, shift "forward" if (nextFilename < outFilenamesEnd) { memmove(checkFilename + strLenBound, checkFilename, outFilenamesEnd-checkFilename-strLenBound); memcpy(checkFilename, direntry->d_name, 1+len); nextFilename += strLenBound; } // Otherwise shift "backwards", but only if there's already an entry "smaller" than current one else if (checkFilename != outFilenames) { memmove(outFilenames, outFilenames+strLenBound, (checkFilename-strLenBound)-outFilenames); memcpy(checkFilename-strLenBound, direntry->d_name, 1+len); } }; } closedir(dir); } return (nextFilename-outFilenames)/strLenBound; }