int simple_caseless_compare(const uint8_t *s1,const uint8_t *s2) { ucs4_t c1,c2; int d=0; if((s1[0]!='\0')||(s2[0]!='\0')) { do { s1=u8_next(&c1,s1); s2=u8_next(&c2,s2); if((s1==NULL)&&(s2==NULL)) break; if(s1!=NULL) d=uc_tolower(c1); if(s2!=NULL) d-=uc_tolower(c2); } while(d==0); } return d; }
ustring32_t ustring32_assign8(ustring32_t u32,const uint8_t *u8) { ustring32_clear(u32); ucs4_t c; const uint8_t *s=u8; while((s=u8_next(&c,s))) { if(!ustring32_push(u32,c)) return NULL; } return u32; }
static void sort_tag_create(char **sort_tag, char *src_tag) { const uint8_t *i_ptr; const uint8_t *n_ptr; const uint8_t *number; uint8_t out[1024]; uint8_t *o_ptr; int append_number; ucs4_t puc; int numlen; size_t len; int charlen; /* Note: include terminating NUL in string length for u8_normalize */ if (*sort_tag) { DPRINTF(E_DBG, L_LIB, "Existing sort tag will be normalized: %s\n", *sort_tag); o_ptr = u8_normalize(UNINORM_NFD, (uint8_t *)*sort_tag, strlen(*sort_tag) + 1, NULL, &len); free(*sort_tag); *sort_tag = (char *)o_ptr; return; } if (!src_tag || ((len = strlen(src_tag)) == 0)) { *sort_tag = NULL; return; } // Set input pointer past article if present if ((strncasecmp(src_tag, "a ", 2) == 0) && (len > 2)) i_ptr = (uint8_t *)(src_tag + 2); else if ((strncasecmp(src_tag, "an ", 3) == 0) && (len > 3)) i_ptr = (uint8_t *)(src_tag + 3); else if ((strncasecmp(src_tag, "the ", 4) == 0) && (len > 4)) i_ptr = (uint8_t *)(src_tag + 4); else i_ptr = (uint8_t *)src_tag; // Poor man's natural sort. Makes sure we sort like this: a1, a2, a10, a11, a21, a111 // We do this by padding zeroes to (short) numbers. As an alternative we could have // made a proper natural sort algorithm in sqlext.c, but we don't, since we don't // want any risk of hurting response times memset(&out, 0, sizeof(out)); o_ptr = (uint8_t *)&out; number = NULL; append_number = 0; do { n_ptr = u8_next(&puc, i_ptr); if (uc_is_digit(puc)) { if (!number) // We have encountered the beginning of a number number = i_ptr; append_number = (n_ptr == NULL); // If last char in string append number now } else { if (number) append_number = 1; // A number has ended so time to append it else { charlen = u8_strmblen(i_ptr); if (charlen >= 0) o_ptr = u8_stpncpy(o_ptr, i_ptr, charlen); // No numbers in sight, just append char } } // Break if less than 100 bytes remain (prevent buffer overflow) if (sizeof(out) - u8_strlen(out) < 100) break; // Break if number is very large (prevent buffer overflow) if (number && (i_ptr - number > 50)) break; if (append_number) { numlen = i_ptr - number; if (numlen < 5) // Max pad width { u8_strcpy(o_ptr, (uint8_t *)"00000"); o_ptr += (5 - numlen); } o_ptr = u8_stpncpy(o_ptr, number, numlen + u8_strmblen(i_ptr)); number = NULL; append_number = 0; } i_ptr = n_ptr; } while (n_ptr); *sort_tag = (char *)u8_normalize(UNINORM_NFD, (uint8_t *)&out, u8_strlen(out) + 1, NULL, &len); }
int main () { ucs4_t uc; const uint8_t *ret; /* Test NUL unit input. */ { static const uint8_t input[] = ""; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0); } /* Test ISO 646 unit input. */ { ucs4_t c; uint8_t buf[2]; for (c = 1; c < 0x80; c++) { buf[0] = c; buf[1] = 0; uc = 0xBADFACE; ret = u8_next (&uc, buf); ASSERT (ret == buf + 1); ASSERT (uc == c); } } /* Test 2-byte character input. */ { static const uint8_t input[] = { 0xC3, 0x97, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == input + 2); ASSERT (uc == 0x00D7); } /* Test 3-byte character input. */ { static const uint8_t input[] = { 0xE2, 0x82, 0xAC, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == input + 3); ASSERT (uc == 0x20AC); } /* Test 4-byte character input. */ { static const uint8_t input[] = { 0xF4, 0x8F, 0xBF, 0xBD, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == input + 4); ASSERT (uc == 0x10FFFD); } /* Test incomplete/invalid 1-byte input. */ { static const uint8_t input[] = { 0xC1, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xC3, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xE2, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xF4, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xFE, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } /* Test incomplete/invalid 2-byte input. */ { static const uint8_t input[] = { 0xE0, 0x9F, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xE2, 0x82, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xE2, 0xD0, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xF0, 0x8F, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xF3, 0x8F, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xF3, 0xD0, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } /* Test incomplete/invalid 3-byte input. */ { static const uint8_t input[] = { 0xF3, 0x8F, 0xBF, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xF3, 0xD0, 0xBF, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } { static const uint8_t input[] = { 0xF3, 0x8F, 0xD0, 0 }; uc = 0xBADFACE; ret = u8_next (&uc, input); ASSERT (ret == NULL); ASSERT (uc == 0xFFFD); } return 0; }