static PyObject* PyLocale_strxfrm(PyObject* self, PyObject* args) { char *s, *buf; size_t n1, n2; PyObject *result; if (!PyArg_ParseTuple(args, "s:strxfrm", &s)) return NULL; /* assume no change in size, first */ n1 = strlen(s) + 1; buf = PyMem_Malloc(n1); if (!buf) return PyErr_NoMemory(); n2 = strxfrm(buf, s, n1); if (n2 > n1) { /* more space needed */ buf = PyMem_Realloc(buf, n2); if (!buf) return PyErr_NoMemory(); strxfrm(buf, s, n2); } result = PyString_FromString(buf); PyMem_Free(buf); return result; }
void dbBtree::remove(dbDatabase* db, oid_t treeId, oid_t recordId, int offs) { dbGetTie treeTie; dbBtree* tree = (dbBtree*)db->getRow(treeTie, treeId); dbBtreePage::item rem; oid_t rootId = tree->root; int height = tree->height; dbGetTie tie; byte* p = (byte*)db->getRow(tie, recordId); if (tree->type == dbField::tpString) { rem.keyLen = ((dbVarying*)(p + offs))->size; assert(rem.keyLen <= dbMaxKeyLen); #ifdef USE_LOCALE_SETTINGS char cnvBuf[dbMaxKeyLen]; if (tree->caseInsensitive) { rem.keyLen = strxfrm(cnvBuf, (char*)(p + ((dbVarying*)(p + offs))->offs), dbMaxKeyLen) + 1; strlower(rem.keyChar, cnvBuf); } else { rem.keyLen = strxfrm(rem.keyChar, (char*)(p + ((dbVarying*)(p + offs))->offs), dbMaxKeyLen) + 1; } #else if (tree->caseInsensitive) { strlower(rem.keyChar, (char*)(p + ((dbVarying*)(p + offs))->offs)); } else { strcpy(rem.keyChar, (char*)(p + ((dbVarying*)(p + offs))->offs)); } #endif } else { memcpy(rem.keyChar, p + offs, keySize[tree->type]); } rem.oid = recordId; int result = dbBtreePage::remove(db, rootId, tree->type, rem, height); assert(result != not_found); if (result == underflow && height != 1) { dbBtreePage* page = (dbBtreePage*)db->get(rootId); if (page->nItems == 0) { dbPutTie tie; dbBtree* t = (dbBtree*)db->putRow(tie, treeId); if (tree->type == dbField::tpString) { t->root = page->keyStr[0].oid; } else { t->root = page->record[dbBtreePage::maxItems-1]; } t->height -= 1; db->freePage(rootId); } db->pool.unfix(page); } else if (result == dbBtree::overflow) { dbPutTie tie; dbBtree* t = (dbBtree*)db->putRow(tie, treeId); t->root = dbBtreePage::allocate(db, rootId, tree->type, rem); t->height += 1; } }
int strcoll(const char *s1, const char *s2) { char t1[1 + strxfrm(0, s1, 0)]; strxfrm(t1, s1, sizeof(t1)); char t2[1 + strxfrm(0, s2, 0)]; strxfrm(t2, s2, sizeof(t2)); return strcmp(t1, t2); }
CAMLprim value ml_text_strxfrm(value string) { CAMLparam1(string); size_t length = strxfrm(NULL, String_val(string), 0); char buffer[length + 1]; strxfrm(buffer, String_val(string), length + 1); CAMLreturn(caml_copy_string(buffer)); }
void dbBtree::insert(dbDatabase* db, oid_t treeId, oid_t recordId, int offs) { dbGetTie treeTie; dbBtree* tree = (dbBtree*)db->getRow(treeTie, treeId); oid_t rootId = tree->root; int height = tree->height; dbBtreePage::item ins; dbGetTie tie; byte* p = (byte*)db->getRow(tie, recordId); if (tree->type == dbField::tpString) { ins.keyLen = ((dbVarying*)(p + offs))->size; assert(ins.keyLen <= dbMaxKeyLen); #ifdef USE_LOCALE_SETTINGS char cnvBuf[dbMaxKeyLen]; if (tree->caseInsensitive) { ins.keyLen = strxfrm(cnvBuf, (char*)(p + ((dbVarying*)(p + offs))->offs), dbMaxKeyLen) + 1; strlower(ins.keyChar, cnvBuf); } else { ins.keyLen = strxfrm(ins.keyChar, (char*)(p + ((dbVarying*)(p + offs))->offs), dbMaxKeyLen) + 1; } #else if (tree->caseInsensitive) { strlower(ins.keyChar, (char*)(p + ((dbVarying*)(p + offs))->offs)); } else { strcpy(ins.keyChar, (char*)(p + ((dbVarying*)(p + offs))->offs)); } #endif } else { memcpy(ins.keyChar, p + offs, keySize[tree->type]); } ins.oid = recordId; if (rootId == 0) { dbPutTie tie; dbBtree* t = (dbBtree*)db->putRow(tie, treeId); t->root = dbBtreePage::allocate(db, 0, tree->type, ins); t->height = 1; } else { int result; result = dbBtreePage::insert(db, rootId, tree->type, ins, height); assert(result != not_found); if (result == overflow) { dbPutTie tie; dbBtree* t = (dbBtree*)db->putRow(tie, treeId); t->root = dbBtreePage::allocate(db, rootId, tree->type, ins); t->height += 1; } } }
static void genequiv(STR *s) { int i, p, pri; char src[2], dst[3]; size_t clen; wchar_t wc; if (*s->str == '\\') { s->equiv[0] = backslash(s, NULL); if (*s->str != '=') errx(1, "misplaced equivalence equals sign"); s->str += 2; } else { clen = mbrtowc(&wc, s->str, MB_LEN_MAX, NULL); if (clen == (size_t)-1 || clen == (size_t)-2 || clen == 0) errc(1, EILSEQ, NULL); s->equiv[0] = wc; if (s->str[clen] != '=') errx(1, "misplaced equivalence equals sign"); s->str += clen + 2; } /* * Calculate the set of all characters in the same equivalence class * as the specified character (they will have the same primary * collation weights). * XXX Knows too much about how strxfrm() is implemented. Assumes * it fills the string with primary collation weight bytes. Only one- * to-one mappings are supported. * XXX Equivalence classes not supported in multibyte locales. */ src[0] = (char)s->equiv[0]; src[1] = '\0'; if (MB_CUR_MAX == 1 && strxfrm(dst, src, sizeof(dst)) == 1) { pri = (unsigned char)*dst; for (p = 1, i = 1; i < NCHARS_SB; i++) { *src = i; if (strxfrm(dst, src, sizeof(dst)) == 1 && pri && pri == (unsigned char)*dst) s->equiv[p++] = i; } s->equiv[p] = OOBCH; } s->cnt = 0; s->state = SET; s->set = s->equiv; }
int main( int argc, char *argv[] ) { char x[300]; char y[300]; int ret; CYG_TEST_INIT(); CYG_TEST_INFO("Starting tests from testcase " __FILE__ " for C library " "strxfrm() function"); CYG_TEST_INFO("This testcase provides simple basic tests"); // Check 1 my_strcpy(x, "Nine rings for men doomed to die"); ret = strxfrm(y, x, my_strlen(x)+1); if (my_strcmp(x, y) == 0) CYG_TEST_PASS("Simple strxfrm()"); else CYG_TEST_FAIL("Simple strxfrm()"); // Check return value CYG_TEST_PASS_FAIL( (my_strlen(x) == ret), "Simple strxfrm() return value"); // Check 2 x[0] = '\0'; my_strcpy(y, "Seven rings for the dwarves in their halls of stone"); ret = strxfrm(y, x, my_strlen(x)+1); if (my_strcmp(y, "") == 0) CYG_TEST_PASS("strxfrm() of empty string"); else CYG_TEST_FAIL("strxfrm() of empty string"); // Check return value CYG_TEST_PASS_FAIL( (my_strlen(x) == ret), "strxfrm() of empty string return value"); // Check 3 my_strcpy(y, "Seven rings for the dwarves in their halls of stone"); ret = strxfrm(NULL, y, 0); // Check return value CYG_TEST_PASS_FAIL( (my_strlen(y) == ret), "strxfrm() of NULL string for 0 bytes return value"); // CYG_TEST_NA("Testing is not applicable to this configuration"); CYG_TEST_FINISH("Finished tests from testcase " __FILE__ " for C library " "strxfrm() function"); } // main()
static int test (const char *locale) { size_t bufsize; size_t r; size_t l; char *buf; locale_t loc; int result = 0; if (setlocale (LC_COLLATE, locale) == NULL) { printf ("cannot set locale \"%s\"\n", locale); return 1; } bufsize = strxfrm (NULL, string, 0) + 1; buf = malloc (bufsize); if (buf == NULL) { printf ("cannot allocate %zd bytes\n", bufsize); return 1; } r = strxfrm (buf, string, bufsize); l = strlen (buf); if (r != l) { printf ("locale \"%s\": strxfrm returned %zu, strlen returned %zu\n", locale, r, l); result = 1; } loc = newlocale (1 << LC_ALL, locale, NULL); r = strxfrm_l (buf, string, bufsize, loc); l = strlen (buf); if (r != l) { printf ("locale \"%s\": strxfrm_l returned %zu, strlen returned %zu\n", locale, r, l); result = 1; } freelocale (loc); free (buf); return result; }
void cyg_user_start(void) #endif { char x[300]; char y[300]; int ret; int ctr; int fail; CYG_TEST_INIT(); CYG_TEST_INFO("Starting tests from testcase " __FILE__ " for C library " "strxfrm() function"); CYG_TEST_INFO("This testcase tests robustness, and may take some time"); fail = 0; for (ctr = 0; ctr < NUM_ROBUSTNESS_RUNS; ctr++) { my_strcpy(x, "Green plastic watering can, "); my_strcpy(y, "for her fake Chineese rubber plant"); ret = strxfrm(x, y, my_strlen(y)+1); if ( (my_strcmp(x, "for her fake Chineese rubber plant") != 0) || (my_strlen(y) != ret) ) { fail = 1; break; } } CYG_TEST_PASS_FAIL( (fail == 0), "Robustness test" ); // CYG_TEST_NA("Testing is not applicable to this configuration"); CYG_TEST_FINISH("Finished tests from testcase " __FILE__ " for C library " "strxfrm() function"); } // main()
int main() { size_t s = 0; void* vp = 0; const void* vpc = 0; char* cp = 0; const char* cpc = 0; static_assert((std::is_same<decltype(memcpy(vp, vpc, s)), void*>::value), ""); static_assert((std::is_same<decltype(memmove(vp, vpc, s)), void*>::value), ""); static_assert((std::is_same<decltype(strcpy(cp, cpc)), char*>::value), ""); static_assert((std::is_same<decltype(strncpy(cp, cpc, s)), char*>::value), ""); static_assert((std::is_same<decltype(strcat(cp, cpc)), char*>::value), ""); static_assert((std::is_same<decltype(strncat(cp, cpc, s)), char*>::value), ""); static_assert((std::is_same<decltype(memcmp(vpc, vpc, s)), int>::value), ""); static_assert((std::is_same<decltype(strcmp(cpc, cpc)), int>::value), ""); static_assert((std::is_same<decltype(strncmp(cpc, cpc, s)), int>::value), ""); static_assert((std::is_same<decltype(strcoll(cpc, cpc)), int>::value), ""); static_assert((std::is_same<decltype(strxfrm(cp, cpc, s)), size_t>::value), ""); static_assert((std::is_same<decltype(memchr(vp, 0, s)), void*>::value), ""); static_assert((std::is_same<decltype(strchr(cp, 0)), char*>::value), ""); static_assert((std::is_same<decltype(strcspn(cpc, cpc)), size_t>::value), ""); static_assert((std::is_same<decltype(strpbrk(cp, cpc)), char*>::value), ""); static_assert((std::is_same<decltype(strrchr(cp, 0)), char*>::value), ""); static_assert((std::is_same<decltype(strspn(cpc, cpc)), size_t>::value), ""); static_assert((std::is_same<decltype(strstr(cp, cpc)), char*>::value), ""); #ifndef _LIBCPP_HAS_NO_THREAD_UNSAFE_C_FUNCTIONS static_assert((std::is_same<decltype(strtok(cp, cpc)), char*>::value), ""); #endif static_assert((std::is_same<decltype(memset(vp, 0, s)), void*>::value), ""); static_assert((std::is_same<decltype(strerror(0)), char*>::value), ""); static_assert((std::is_same<decltype(strlen(cpc)), size_t>::value), ""); }
val_t eic_strxfrm(void) { val_t v; v.szval = strxfrm(arg(0,getargs(),ptr_t).p, arg(1,getargs(),ptr_t).p, arg(2,getargs(),size_t)); return v; }
int main() { char dst[9]; char *source = "This is a string"; setlocale(LC_ALL, "C"); size_t sz; sz = strxfrm(dst, source, 10); return 0; }
/* * Detect aging strxfrm() implementations that, in a subset of locales, write * past the specified buffer length. Affected users must update OS packages * before using PostgreSQL 9.5 or later. * * Assume that the bug can come and go from one postmaster startup to another * due to physical replication among diverse machines. Assume that the bug's * presence will not change during the life of a particular postmaster. Given * those assumptions, call this no less than once per postmaster startup per * LC_COLLATE setting used. No known-affected system offers strxfrm_l(), so * there is no need to consider pg_collation locales. */ void check_strxfrm_bug(void) { char buf[32]; const int canary = 0x7F; bool ok = true; /* * Given a two-byte ASCII string and length limit 7, 8 or 9, Solaris 10 * 05/08 returns 18 and modifies 10 bytes. It respects limits above or * below that range. * * The bug is present in Solaris 8 as well; it is absent in Solaris 10 * 01/13 and Solaris 11.2. Affected locales include is_IS.ISO8859-1, * en_US.UTF-8, en_US.ISO8859-1, and ru_RU.KOI8-R. Unaffected locales * include de_DE.UTF-8, de_DE.ISO8859-1, zh_TW.UTF-8, and C. */ buf[7] = canary; (void) strxfrm(buf, "ab", 7); if (buf[7] != canary) ok = false; /* * illumos bug #1594 was present in the source tree from 2010-10-11 to * 2012-02-01. Given an ASCII string of any length and length limit 1, * affected systems ignore the length limit and modify a number of bytes * one less than the return value. The problem inputs for this bug do not * overlap those for the Solaris bug, hence a distinct test. * * Affected systems include smartos-20110926T021612Z. Affected locales * include en_US.ISO8859-1 and en_US.UTF-8. Unaffected locales include C. */ buf[1] = canary; (void) strxfrm(buf, "a", 1); if (buf[1] != canary) ok = false; if (!ok) ereport(ERROR, (errcode(ERRCODE_SYSTEM_ERROR), errmsg_internal("strxfrm(), in locale \"%s\", writes past the specified array length", setlocale(LC_COLLATE, NULL)), errhint("Apply system library package updates."))); }
void test_pointer (const char *s, const char *t) { q[0] = strcmp (s, t); q[1] = strncmp (s, t, 7); q[2] = strlen (s); q[3] = strnlen (s, 7); q[4] = strcspn (s, t); q[5] = strspn (s, t); q[6] = strxfrm (s, s, 7); }
static void genequiv(STR *s) { int i, p, pri; char src[2], dst[3]; if (*s->str == '\\') { s->equiv[0] = backslash(s); if (*s->str != '=') errx(1, "misplaced equivalence equals sign"); s->str += 2; } else { s->equiv[0] = s->str[0]; if (s->str[1] != '=') errx(1, "misplaced equivalence equals sign"); s->str += 3; } /* * Calculate the set of all characters in the same equivalence class * as the specified character (they will have the same primary * collation weights). * XXX Knows too much about how strxfrm() is implemented. Assumes * it fills the string with primary collation weight bytes. Only one- * to-one mappings are supported. */ src[0] = s->equiv[0]; src[1] = '\0'; if (strxfrm(dst, src, sizeof(dst)) == 1) { pri = (unsigned char)*dst; for (p = 1, i = 1; i < NCHARS; i++) { *src = i; if (strxfrm(dst, src, sizeof(dst)) == 1 && pri && pri == (unsigned char)*dst) s->equiv[p++] = i; } s->equiv[p] = OOBCH; } s->cnt = 0; s->state = SET; s->set = s->equiv; }
/* * Set up for a new collation locale. */ void Perl_new_collate(pTHX_ const char *newcoll) { #ifdef USE_LOCALE_COLLATE dVAR; if (! newcoll) { if (PL_collation_name) { ++PL_collation_ix; Safefree(PL_collation_name); PL_collation_name = NULL; } PL_collation_standard = TRUE; PL_collxfrm_base = 0; PL_collxfrm_mult = 2; return; } if (! PL_collation_name || strNE(PL_collation_name, newcoll)) { ++PL_collation_ix; Safefree(PL_collation_name); PL_collation_name = stdize_locale(savepv(newcoll)); PL_collation_standard = ((*newcoll == 'C' && newcoll[1] == '\0') || strEQ(newcoll, "POSIX")); { /* 2: at most so many chars ('a', 'b'). */ /* 50: surely no system expands a char more. */ #define XFRMBUFSIZE (2 * 50) char xbuf[XFRMBUFSIZE]; const Size_t fa = strxfrm(xbuf, "a", XFRMBUFSIZE); const Size_t fb = strxfrm(xbuf, "ab", XFRMBUFSIZE); const SSize_t mult = fb - fa; if (mult < 1 && !(fa == 0 && fb == 0)) Perl_croak(aTHX_ "panic: strxfrm() gets absurd - a => %"UVuf", ab => %"UVuf, (UV) fa, (UV) fb); PL_collxfrm_base = (fa > (Size_t)mult) ? (fa - mult) : 0; PL_collxfrm_mult = mult; } } #endif /* USE_LOCALE_COLLATE */ }
size_t _Locale_strxfrm(struct _Locale_collate* lcollate, char* dest, size_t destN, const char* src, size_t srcN) { size_t n; n = strxfrm(dest, src, destN); if (n > destN) return (size_t)-1; dest[n] = 0; return n; }
void dbBtree::find(dbDatabase* db, oid_t treeId, dbSearchContext& sc) { dbGetTie tie; dbBtree* tree = (dbBtree*)db->getRow(tie, treeId); oid_t rootId = tree->root; int height = tree->height; char firstKeyBuf[dbMaxKeyLen]; char lastKeyBuf[dbMaxKeyLen]; #ifdef USE_LOCALE_SETTINGS char cnvBuf[dbMaxKeyLen]; #endif if (tree->type == dbField::tpString) { if (sc.firstKey != NULL) { if (tree->caseInsensitive) { strlower(firstKeyBuf, sc.firstKey); sc.firstKey = firstKeyBuf; } #ifdef USE_LOCALE_SETTINGS strxfrm(cnvBuf, sc.firstKey, dbMaxKeyLen); sc.firstKey = cnvBuf; #endif } if (sc.lastKey != NULL) { if (tree->caseInsensitive) { strlower(lastKeyBuf, sc.lastKey); sc.lastKey = lastKeyBuf; } #ifdef USE_LOCALE_SETTINGS // Hack!!! firstKeyBuf is free at rthis moment and cnvBuf is used. // So use firstKeyBuf for convertsion of last key. strxfrm(firstKeyBuf, sc.lastKey, dbMaxKeyLen); sc.lastKey = firstKeyBuf; #endif } } if (rootId != 0) { dbBtreePage* page = (dbBtreePage*)db->get(rootId); page->find(db, sc, tree->type, height); db->pool.unfix(page); } }
void main(void) { char buffer[64] = "Jamsa\'s C/C++ Programmer\'s Bible"; char target[64]; int length; length = strxfrm(target, buffer, sizeof(buffer)); printf("Length %d Target %s Buffer %s\n", length, target, buffer); }
void test_array (const char *s) { extern char a[8]; q[0] = strcmp (a, s); q[1] = strncmp (a, s, 7); q[2] = strlen (a); q[3] = strnlen (a, 7); q[4] = strcspn (a, s); q[5] = strspn (a, s); q[6] = strxfrm (a, s, 7); }
int main(int argc, char **argv) { char q[10]; size_t n = strxfrm(q, "abcdef", sizeof(q)); assert(n < sizeof(q)); char q2[10]; locale_t loc = newlocale(LC_ALL_MASK, "", (locale_t)0); n = strxfrm_l(q2, L"qwerty", sizeof(q), loc); assert(n < sizeof(q2)); freelocale(loc); return 0; }
nsresult nsCollationUnix::AllocateRawSortKey(int32_t strength, const nsAString& stringIn, uint8_t** key, uint32_t* outLen) { nsresult res = NS_OK; nsAutoString stringNormalized; if (strength != kCollationCaseSensitive) { res = mCollation->NormalizeString(stringIn, stringNormalized); if (NS_FAILED(res)) return res; } else { stringNormalized = stringIn; } // convert unicode to charset char *str; res = mCollation->UnicodeToChar(stringNormalized, &str); if (NS_SUCCEEDED(res) && str) { DoSetLocale(); // call strxfrm to generate a key size_t len = strxfrm(nullptr, str, 0) + 1; void *buffer = PR_Malloc(len); if (!buffer) { res = NS_ERROR_OUT_OF_MEMORY; } else if (strxfrm((char *)buffer, str, len) >= len) { PR_Free(buffer); res = NS_ERROR_FAILURE; } else { *key = (uint8_t *)buffer; *outLen = len; } DoRestoreLocale(); PR_Free(str); } return res; }
char * Perl_mem_collxfrm(pTHX_ const char *s, STRLEN len, STRLEN *xlen) { dVAR; char *xbuf; STRLEN xAlloc, xin, xout; /* xalloc is a reserved word in VC */ PERL_ARGS_ASSERT_MEM_COLLXFRM; /* the first sizeof(collationix) bytes are used by sv_collxfrm(). */ /* the +1 is for the terminating NUL. */ xAlloc = sizeof(PL_collation_ix) + PL_collxfrm_base + (PL_collxfrm_mult * len) + 1; Newx(xbuf, xAlloc, char); if (! xbuf) goto bad; *(U32*)xbuf = PL_collation_ix; xout = sizeof(PL_collation_ix); for (xin = 0; xin < len; ) { Size_t xused; for (;;) { xused = strxfrm(xbuf + xout, s + xin, xAlloc - xout); if (xused >= PERL_INT_MAX) goto bad; if ((STRLEN)xused < xAlloc - xout) break; xAlloc = (2 * xAlloc) + 1; Renew(xbuf, xAlloc, char); if (! xbuf) goto bad; } xin += strlen(s + xin) + 1; xout += xused; /* Embedded NULs are understood but silently skipped * because they make no sense in locale collation. */ } xbuf[xout] = '\0'; *xlen = xout - sizeof(PL_collation_ix); return xbuf; bad: Safefree(xbuf); *xlen = 0; return NULL; }
inline int8 packStrKey(byte* p) { #ifdef USE_LOCALE_SETTINGS char buf[8]; strxfrm(buf, (char*)p, sizeof buf); p = (byte*)buf; #endif int8 pkey = 0; for (int i = 0; i < 8 && p[i] != 0; i++) { pkey |= int8(p[i]) << ((7-i)*8); } // As far as signed comparison is used for packed key, // and strcmp compares characters as unsign, we should make this // correction return pkey - (int8(-1) << 63); }
void TestLocale( void ) { char bufA[80] = "FoO baR gOoBeR bLaH"; char bufB[80]; int status; setlocale( LC_ALL, "C" ); /* set locale to "C" */ status = strxfrm( bufB, bufA, 20 ); /* transform the string */ VERIFY( status == 19 ); status = strcoll( bufB, bufA ); /* compare with "C" locale */ VERIFY( status == 0 ); status = strcoll( bufB, "Bar" ); /* compare with "C" locale */ VERIFY( status != 0 ); }
size_t _Locale_strxfrm(struct _Locale_collate *lcollate, char *dest, size_t dest_n, const char *src, size_t src_n ) { if (src_n == 0) { if (dest != NULL) dest[0] = 0; return 0; } const char *real_src; char *buf = NULL; if (src[src_n] != 0) { buf = malloc(src_n + 1); strncpy(buf, src, src_n); buf[src_n] = 0; real_src = buf; } else real_src = src; size_t result = strxfrm(dest, real_src, dest_n); if (buf != NULL) free(buf); return result; }
/* * stress_strxfrm() * stress on strxfrm */ static void stress_strxfrm( const char *name, char *str1, const size_t len1, char *str2, const size_t len2) { register size_t i; char buf[len1 + len2]; for (i = 0; i < len1 - 1; i++) { *buf = '\0'; STRCHK(name, 0 != strxfrm(buf, str1, sizeof(buf))); *buf = '\0'; STRCHK(name, 0 != strxfrm(buf, str2, sizeof(buf))); *buf = '\0'; STRCHK(name, 0 != strxfrm(buf, str1, sizeof(buf))); STRCHK(name, 0 != strxfrm(buf, str2, sizeof(buf))); *buf = '\0'; STRCHK(name, 0 != strxfrm(buf, str2, sizeof(buf))); STRCHK(name, 0 != strxfrm(buf, str1, sizeof(buf))); } }
char * astrxfrm (const char *s, char *resultbuf, size_t *lengthp) { char tmpbuf[4000]; char *result; /* either == resultbuf or == tmpbuf or freshly allocated or NULL. */ size_t allocated; /* number of bytes allocated at result */ size_t length; if (resultbuf != NULL) { result = resultbuf; allocated = *lengthp; } else { result = NULL; allocated = 0; } { size_t l = strlen (s); size_t k; /* A call to strxfrm costs about 20 times more than a call to strdup of the result. Therefore it is worth to try to avoid calling strxfrm more than once on a given string, by making enough room before calling strxfrm. The size of the strxfrm result, k, is likely to be between l and 3 * l. */ if (3 * l + 1 > allocated) { /* Grow the result buffer. */ if (3 * l + 1 <= sizeof (tmpbuf)) { result = tmpbuf; allocated = sizeof (tmpbuf); } else { size_t new_allocated; char *new_result; new_allocated = 3 * l + 1; if (new_allocated < 2 * allocated) new_allocated = 2 * allocated; new_result = (char *) malloc (new_allocated); if (new_result != NULL) { allocated = new_allocated; result = new_result; } } } errno = 0; k = strxfrm (result, s, allocated); if (errno != 0) goto fail; if (k >= allocated) { /* Grow the result buffer. */ if (result != resultbuf && result != tmpbuf) free (result); if (k + 1 <= sizeof (tmpbuf)) { result = tmpbuf; allocated = sizeof (tmpbuf); } else { size_t new_allocated; char *new_result; new_allocated = k + 1; new_result = (char *) malloc (new_allocated); if (new_result == NULL) goto out_of_memory; allocated = new_allocated; result = new_result; } /* Here k < allocated. */ /* Try again. */ errno = 0; if (strxfrm (result, s, allocated) != k) /* strxfrm() is not producing reproducible results. */ abort (); if (errno != 0) goto fail; } /* Verify that strxfrm() has NUL-terminated the result. */ if (result[k] != '\0') abort (); length = k + 1; } /* Here length > 0. */ if (result == tmpbuf) { if (resultbuf != NULL && length <= *lengthp) { memcpy (resultbuf, result, length); result = resultbuf; } else { char *memory = (char *) malloc (length); if (memory == NULL) goto out_of_memory; memcpy (memory, result, length); result = memory; } } else { /* Shrink the allocated memory if possible. */ if (result != resultbuf && length < allocated) { if (length <= *lengthp) { memcpy (resultbuf, result, length); free (result); result = resultbuf; } else { char *memory = (char *) realloc (result, length); if (memory != NULL) { memcpy (memory, result, length); result = memory; } } } } *lengthp = length; return result; fail: { int saved_errno = errno; if (result != resultbuf && result != tmpbuf) free (result); errno = saved_errno; return NULL; } out_of_memory: errno = ENOMEM; return NULL; }
int main (int argc, char *argv[]) { int result = 0; bool nocache = false; size_t nstrings, nstrings_max; struct lines *strings; char *line = NULL; size_t len = 0; size_t n; if (argc < 2) error (1, 0, "usage: %s <random seed> [-nocache]", argv[0]); if (argc == 3) { if (strcmp (argv[2], "-nocache") == 0) nocache = true; else { printf ("Unknown option %s!\n", argv[2]); exit (1); } } setlocale (LC_ALL, ""); nstrings_max = 100; nstrings = 0; strings = (struct lines *) malloc (nstrings_max * sizeof (struct lines)); if (strings == NULL) { perror (argv[0]); exit (1); } while (1) { char saved, *word, *newp; size_t l, line_len, needed; if (getline (&line, &len, stdin) < 0) break; if (nstrings == nstrings_max) { strings = (struct lines *) realloc (strings, (nstrings_max *= 2) * sizeof (*strings)); if (strings == NULL) { perror (argv[0]); exit (1); } } strings[nstrings].line = strdup (line); l = strcspn (line, ":(;"); while (l > 0 && isspace (line[l - 1])) --l; saved = line[l]; line[l] = '\0'; if (nocache) { line_len = strlen (line); word = malloc (line_len + SMALL_STR_SIZE + 1); if (word == NULL) { printf ("malloc failed: %m\n"); exit (1); } memset (word, ' ', SMALL_STR_SIZE); memcpy (word + SMALL_STR_SIZE, line, line_len); word[line_len + SMALL_STR_SIZE] = '\0'; } else word = line; needed = strxfrm (NULL, word, 0); newp = malloc (needed + 1); if (newp == NULL) { printf ("malloc failed: %m\n"); exit (1); } strxfrm (newp, word, needed + 1); strings[nstrings].xfrm = newp; if (nocache) free (word); line[l] = saved; ++nstrings; } free (line); /* First shuffle. */ srandom (atoi (argv[1])); for (n = 0; n < 10 * nstrings; ++n) { int r1, r2, r; size_t idx1 = random () % nstrings; size_t idx2 = random () % nstrings; struct lines tmp = strings[idx1]; strings[idx1] = strings[idx2]; strings[idx2] = tmp; /* While we are at it a first little test. */ r1 = strcmp (strings[idx1].xfrm, strings[idx2].xfrm); r2 = strcmp (strings[idx2].xfrm, strings[idx1].xfrm); r = -(r1 ^ r2); if (r) r /= abs (r1 ^ r2); if (r < 0 || (r == 0 && (r1 != 0 || r2 != 0)) || (r > 0 && (r1 ^ r2) >= 0)) printf ("collate wrong: %d vs. %d\n", r1, r2); } /* Now sort. */ qsort (strings, nstrings, sizeof (struct lines), xstrcmp); /* Print the result. */ for (n = 0; n < nstrings; ++n) { fputs (strings[n].line, stdout); free (strings[n].line); free (strings[n].xfrm); } free (strings); return result; }
KServiceGroup::List KServiceGroup::entries(bool sort, bool excludeNoDisplay, bool allowSeparators, bool sortByGenericName) { KServiceGroup *group = this; // If the entries haven't been loaded yet, we have to reload ourselves // together with the entries. We can't only load the entries afterwards // since the offsets could have been changed if the database has changed. if (!m_bDeep) { group = KServiceGroupFactory::self()->findGroupByDesktopPath(relPath(), true); if (0 == group) // No guarantee that we still exist! return List(); } if (!sort) return group->m_serviceList; // Sort the list alphabetically, according to locale. // Groups come first, then services. KSortableValueList<SPtr,QCString> slist; KSortableValueList<SPtr,QCString> glist; for (List::ConstIterator it(group->m_serviceList.begin()); it != group->m_serviceList.end(); ++it) { KSycocaEntry *p = (*it); bool noDisplay = p->isType(KST_KServiceGroup) ? static_cast<KServiceGroup *>(p)->noDisplay() : static_cast<KService *>(p)->noDisplay(); if (excludeNoDisplay && noDisplay) continue; // Choose the right list KSortableValueList<SPtr,QCString> & list = p->isType(KST_KServiceGroup) ? glist : slist; QString name; if (p->isType(KST_KServiceGroup)) name = static_cast<KServiceGroup *>(p)->caption(); else if (sortByGenericName) name = static_cast<KService *>(p)->genericName() + " " + p->name(); else name = p->name() + " " + static_cast<KService *>(p)->genericName(); QCString key( name.length() * 4 + 1 ); // strxfrm() crashes on Solaris #ifndef USE_SOLARIS // maybe it'd be better to use wcsxfrm() where available size_t ln = strxfrm( key.data(), name.local8Bit().data(), key.size()); if( ln != size_t( -1 )) { if( ln >= key.size()) { // didn't fit? key.resize( ln + 1 ); if( strxfrm( key.data(), name.local8Bit().data(), key.size()) == size_t( -1 )) key = name.local8Bit(); } } else #endif { key = name.local8Bit(); } list.insert(key,SPtr(*it)); } // Now sort slist.sort(); glist.sort(); if (d->sortOrder.isEmpty()) { d->sortOrder << ":M"; d->sortOrder << ":F"; d->sortOrder << ":OIH IL[4]"; //just inline header } QString rp = relPath(); if(rp == "/") rp = QString::null; // Iterate through the sort spec list. // If an entry gets mentioned explicitly, we remove it from the sorted list for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it) { const QString &item = *it; if (item.isEmpty()) continue; if (item[0] == '/') { QString groupPath = rp + item.mid(1) + "/"; // Remove entry from sorted list of services. for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) { KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)((*it2).value())); if (group->relPath() == groupPath) { glist.remove(it2); break; } } } else if (item[0] != ':') { // Remove entry from sorted list of services. // TODO: Remove item from sortOrder-list if not found // TODO: This prevents duplicates for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2) { KService *service = (KService *)((KSycocaEntry *)((*it2).value())); if (service->menuId() == item) { slist.remove(it2); break; } } } } List sorted; bool needSeparator = false; // Iterate through the sort spec list. // Add the entries to the list according to the sort spec. for (QStringList::ConstIterator it(d->sortOrder.begin()); it != d->sortOrder.end(); ++it) { const QString &item = *it; if (item.isEmpty()) continue; if (item[0] == ':') { // Special condition... if (item == ":S") { if (allowSeparators) needSeparator = true; } else if ( item.contains( ":O" ) ) { //todo parse attribute: QString tmp( item ); tmp = tmp.remove(":O"); QStringList optionAttribute = QStringList::split(" ",tmp); if( optionAttribute.count()==0) optionAttribute.append(tmp); bool showEmptyMenu = false; bool showInline = false; bool showInlineHeader = false; bool showInlineAlias = false; int inlineValue = -1; for ( QStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3 ) { parseAttribute( *it3, showEmptyMenu, showInline, showInlineHeader, showInlineAlias, inlineValue ); } for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) { KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2).value()); group->setShowEmptyMenu( showEmptyMenu ); group->setAllowInline( showInline ); group->setShowInlineHeader( showInlineHeader ); group->setInlineAlias( showInlineAlias ); group->setInlineValue( inlineValue ); } } else if (item == ":M") { // Add sorted list of sub-menus for(KSortableValueList<SPtr,QCString>::Iterator it2 = glist.begin(); it2 != glist.end(); ++it2) { addItem(sorted, (*it2).value(), needSeparator); } } else if (item == ":F") { // Add sorted list of services for(KSortableValueList<SPtr,QCString>::Iterator it2 = slist.begin(); it2 != slist.end(); ++it2) { addItem(sorted, (*it2).value(), needSeparator); } } else if (item == ":A") { // Add sorted lists of services and submenus KSortableValueList<SPtr,QCString>::Iterator it_s = slist.begin(); KSortableValueList<SPtr,QCString>::Iterator it_g = glist.begin(); while(true) { if (it_s == slist.end()) { if (it_g == glist.end()) break; // Done // Insert remaining sub-menu addItem(sorted, (*it_g).value(), needSeparator); it_g++; } else if (it_g == glist.end()) { // Insert remaining service addItem(sorted, (*it_s).value(), needSeparator); it_s++; } else if ((*it_g).index() < (*it_s).index()) { // Insert sub-menu first addItem(sorted, (*it_g).value(), needSeparator); it_g++; } else { // Insert service first addItem(sorted, (*it_s).value(), needSeparator); it_s++; } } } } else if (item[0] == '/') { QString groupPath = rp + item.mid(1) + "/"; for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2) { if (!(*it2)->isType(KST_KServiceGroup)) continue; KServiceGroup *group = (KServiceGroup *)((KSycocaEntry *)(*it2)); if (group->relPath() == groupPath) { if (!excludeNoDisplay || !group->noDisplay()) { const QString &nextItem = *( ++it ); if ( nextItem.startsWith( ":O" ) ) { QString tmp( nextItem ); tmp = tmp.remove(":O"); QStringList optionAttribute = QStringList::split(" ",tmp); if( optionAttribute.count()==0) optionAttribute.append(tmp); bool bShowEmptyMenu = false; bool bShowInline = false; bool bShowInlineHeader = false; bool bShowInlineAlias = false; int inlineValue = -1; for ( QStringList::Iterator it3 = optionAttribute.begin(); it3 != optionAttribute.end(); ++it3 ) { parseAttribute( *it3 , bShowEmptyMenu, bShowInline, bShowInlineHeader, bShowInlineAlias , inlineValue ); group->setShowEmptyMenu( bShowEmptyMenu ); group->setAllowInline( bShowInline ); group->setShowInlineHeader( bShowInlineHeader ); group->setInlineAlias( bShowInlineAlias ); group->setInlineValue( inlineValue ); } } else it--; addItem(sorted, (group), needSeparator); } break; } } } else { for (List::ConstIterator it2(group->m_serviceList.begin()); it2 != group->m_serviceList.end(); ++it2) { if (!(*it2)->isType(KST_KService)) continue; KService *service = (KService *)((KSycocaEntry *)(*it2)); if (service->menuId() == item) { if (!excludeNoDisplay || !service->noDisplay()) addItem(sorted, (*it2), needSeparator); break; } } } } return sorted; }