| /* Test collation function via transformation using real data. |
| Copyright (C) 1997-2014 Free Software Foundation, Inc. |
| This file is part of the GNU C Library. |
| Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. |
| |
| The GNU C Library is free software; you can redistribute it and/or |
| modify it under the terms of the GNU Lesser General Public |
| License as published by the Free Software Foundation; either |
| version 2.1 of the License, or (at your option) any later version. |
| |
| The GNU C Library is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| Lesser General Public License for more details. |
| |
| You should have received a copy of the GNU Lesser General Public |
| License along with the GNU C Library; if not, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| /* Branched from glibc's localedata/xfrm-test.c. */ |
| |
| #include <ctype.h> |
| #include <error.h> |
| #include <locale.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| /* Keep in sync with string/strxfrm_l.c. */ |
| #define SMALL_STR_SIZE 4095 |
| |
| #include "third_party/glibc_locales/glibc_locales.h" |
| |
| struct lines { |
| char *xfrm; |
| char *line; |
| }; |
| |
| static int xstrcmp(const void *, const void *); |
| |
| 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 < 3) |
| error(1, 0, "usage: %s <random seed> <locale> [-nocache]", argv[0]); |
| |
| if (argc == 4) { |
| if (strcmp(argv[3], "-nocache") == 0) |
| nocache = true; |
| else { |
| printf("Unknown option %s!\n", argv[3]); |
| exit(1); |
| } |
| } |
| |
| google_locale_t locale = google_newlocale(LC_ALL_MASK, argv[2], NULL, 0); |
| if (locale == NULL) { |
| error(1, 0, "failed to load locale '%s'", argv[2]); |
| exit(1); |
| } |
| |
| 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 = google_strxfrm_l(NULL, word, 0, locale); |
| newp = malloc(needed + 1); |
| if (newp == NULL) { |
| printf("malloc failed: %m\n"); |
| exit(1); |
| } |
| google_strxfrm_l(newp, word, needed + 1, locale); |
| 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; |
| } |
| |
| static int xstrcmp(ptr1, ptr2) const void *ptr1; |
| const void *ptr2; |
| { |
| const struct lines *l1 = (const struct lines *)ptr1; |
| const struct lines *l2 = (const struct lines *)ptr2; |
| |
| return strcmp(l1->xfrm, l2->xfrm); |
| } |