/* * Convert a wide character string argument for the %ls format to a multibyte * string representation. If not -1, prec specifies the maximum number of * bytes to output, and also means that we can't assume that the wide char. * string ends is null-terminated. */ static char * __wcsconv(wchar_t *wcsarg, int prec, locale_t loc) { static const mbstate_t initial; mbstate_t mbs; char buf[MB_LEN_MAX]; wchar_t *p; char *convbuf; size_t clen, nbytes; /* Allocate space for the maximum number of bytes we could output. */ if (prec < 0) { p = wcsarg; mbs = initial; nbytes = wcsrtombs_l(NULL, (const wchar_t **)&p, 0, &mbs, loc); if (nbytes == (size_t)-1) return (NULL); } else { /* * Optimisation: if the output precision is small enough, * just allocate enough memory for the maximum instead of * scanning the string. */ if (prec < 128) nbytes = prec; else { nbytes = 0; p = wcsarg; mbs = initial; for (;;) { clen = wcrtomb_l(buf, *p++, &mbs, loc); if (clen == 0 || clen == (size_t)-1 || nbytes + clen > prec) break; nbytes += clen; } } } if ((convbuf = malloc(nbytes + 1)) == NULL) return (NULL); /* Fill the output buffer. */ p = wcsarg; mbs = initial; if ((nbytes = wcsrtombs_l(convbuf, (const wchar_t **)&p, nbytes, &mbs, loc)) == (size_t)-1) { free(convbuf); return (NULL); } convbuf[nbytes] = '\0'; return (convbuf); }
void test_wcsrtombs_thr_iter(test_t t, const char *locale, struct wcsrtombs_test *test) { locale_t loc; mbstate_t ms; loc = newlocale(LC_ALL_MASK, locale, NULL); if (loc == NULL) { test_failed(t, "newlocale failed: %s", strerror(errno)); } for (int i = 0; test[i].mbs[0] != 0; i++) { char mbs[32]; const wchar_t *wcs = test[i].wcs; size_t cnt; (void) memset(&ms, 0, sizeof (ms)); (void) memset(mbs, 0, sizeof (mbs)); cnt = wcsrtombs_l(mbs, &wcs, sizeof (mbs), &ms, loc); if (cnt != strlen(test[i].mbs)) { test_failed(t, "incorrect return value: %d != %d", cnt, strlen(test[i].mbs)); } if (strcmp(mbs, test[i].mbs) != 0) { test_failed(t, "wrong result: %s != %s", mbs, test[i].mbs); } if (extra_debug) { test_debugf(t, "mbs is %s", mbs); } } freelocale(loc); }
void test_wcsrtombs_l(const char *locale, struct wcsrtombs_test *test) { test_t t; locale_t loc; char *v; mbstate_t ms; t = test_start("wcsrtombs_l (locale %s)", locale); v = setlocale(LC_ALL, "C"); if (v == NULL) { test_failed(t, "setlocale failed: %s", strerror(errno)); } if (strcmp(v, "C") != 0) { test_failed(t, "setlocale got %s instead of %s", v, "C"); } loc = newlocale(LC_ALL_MASK, locale, NULL); if (loc == NULL) { test_failed(t, "newlocale failed: %s", strerror(errno)); } for (int i = 0; test[i].mbs[0] != 0; i++) { char mbs[32]; const wchar_t *wcs = test[i].wcs; size_t cnt; (void) memset(&ms, 0, sizeof (ms)); (void) memset(mbs, 0, sizeof (mbs)); cnt = wcsrtombs_l(mbs, &wcs, sizeof (mbs), &ms, loc); if (cnt != strlen(test[i].mbs)) { test_failed(t, "incorrect return value: %d != %d", cnt, strlen(test[i].mbs)); } if (strcmp(mbs, test[i].mbs) != 0) { test_failed(t, "wrong result: %s != %s", mbs, test[i].mbs); } if (extra_debug) { test_debugf(t, "mbs is %s", mbs); } } test_passed(t); }
void shorten_name(const char *name, char short_name[512], char shortest_name[512]) { wchar_t w_name[512]; wchar_t w_short_name[512]; wchar_t w_shortest_name[512]; const wchar_t *cur_word, *wchar_ptr; wchar_t *cur_short_word, *cur_shortest_word; int unabbrev = 0; int i, len, new_len, capital; if (!name) return; mbsrtowcs_l(w_name, &name, ARRAY_SIZE(w_name), NULL, l); /* TODO: also skip anything in parenthesis from the short names */ /* TODO: instead of calling wcscasecmp_l all the time it'd be more * effective to lower case w_name once and use plain wcscmp or mem * compare since the phrases we search for are all lower case already. * Might also want to take "collation" into account (wcsxfrm_l the * string once and use memcmp instead of wcscoll_l). */ cur_word = w_name; cur_short_word = w_short_name; cur_shortest_word = w_shortest_name; while (1) { while (*cur_word && !iswalnum_l(*cur_word, l)) *cur_short_word ++ = *cur_shortest_word ++ = *cur_word ++; if (!*cur_word) break; /* TODO: use a hash of some kind instead of iterating over arrays */ /* Go through possible abbreviations from top to bottom */ for (i = 0; i < ARRAY_SIZE(abbrevs); i += 2) if (!wcsncasecmp_l(abbrevs[i], cur_word, wcslen(abbrevs[i]), l)) { len = wcslen(abbrevs[i]); /* Check that we matched a full word */ if (iswalnum_l(cur_word[len], l)) continue; capital = iswupper_l(*cur_word, l); cur_word += len; new_len = wcslen(abbrevs[i + 1]); memcpy(cur_short_word, abbrevs[i + 1], new_len * sizeof(wchar_t)); /* * If original was capitalised then capitalise the abbreviation * as well, if it was lower case. */ if (capital) *cur_short_word = towupper_l(*cur_short_word, l); /* Make sure shortest_word doesn't end up being empty */ if (!*cur_word && !unabbrev) { memcpy(cur_shortest_word, cur_short_word, new_len * sizeof(wchar_t)); cur_shortest_word += new_len; } cur_short_word += new_len; /* * Avoid excess whitespace in short and shortest * when a word is replaced with "". * TODO: this may require more complicated logic to get * the corner cases right. */ if (new_len == 0) { if (cur_short_word > w_short_name && iswspace_l(cur_short_word[-1], l)) cur_short_word --; if (cur_shortest_word > w_shortest_name && iswspace_l(cur_shortest_word[-1], l)) cur_shortest_word --; } /*if (new_len != len)*/ break; } if (i < ARRAY_SIZE(abbrevs)) continue; /* Go through possible given names from top to bottom */ for (i = 0; i < ARRAY_SIZE(given_names); i ++) if (!wcsncasecmp_l(given_names[i], cur_word, wcslen(given_names[i]), l)) { len = wcslen(given_names[i]); /* Check that we matched a full word */ if (iswalnum_l(cur_word[len], l)) continue; /* * If this is the final part of the name, and it matches a * given name then that's most likely somebody's surname which * happens to also be a possibble given name. In that case * do not abbreviate or omit it. */ if (!cur_word[len]) continue; cur_word += len; *cur_short_word++ = given_names[i][0]; *cur_short_word++ = L'.'; /* * Avoid excess whitespace in shortest when a word is * replaced with "". * TODO: this may require more complicated logic to get * the corner cases right. */ if (cur_shortest_word > w_shortest_name && iswspace_l(cur_shortest_word[-1], l)) cur_shortest_word --; break; } if (i < ARRAY_SIZE(given_names)) continue; /* Nothing matched, copy the current word as-is */ while (iswalnum_l(*cur_word, l)) *cur_short_word ++ = *cur_shortest_word ++ = *cur_word ++; unabbrev += 1; } *cur_short_word = 0; *cur_shortest_word = 0; wchar_ptr = w_short_name; wcsrtombs_l(short_name, &wchar_ptr, 512, NULL, l); wchar_ptr = w_shortest_name; wcsrtombs_l(shortest_name, &wchar_ptr, 512, NULL, l); }
/********************************************************************* * wcstombs (MSVCRT.@) */ size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count) { return wcsrtombs_l(mbstr, &wcstr, count, NULL); }
/********************************************************************* * _wcstombs_l (MSVCRT.@) */ size_t CDECL _wcstombs_l(char *mbstr, const wchar_t *wcstr, size_t count, _locale_t locale) { return wcsrtombs_l(mbstr, &wcstr, count, locale); }
char *dst, *sformat; const char *dstp; const wchar_t *formatp; size_t n, sflen; int sverrno; FIX_LOCALE(locale); sformat = dst = NULL; /* * Convert the supplied format string to a multibyte representation * for strftime(), which only handles single-byte characters. */ mbs = initial; formatp = format; sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale); if (sflen == (size_t)-1) goto error; if ((sformat = malloc(sflen + 1)) == NULL) goto error; mbs = initial; wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale); /* * Allocate memory for longest multibyte sequence that will fit * into the caller's buffer and call strftime() to fill it. * Then, copy and convert the result back into wide characters in * the caller's buffer. */ if (SIZE_T_MAX / MB_CUR_MAX <= maxsize) { /* maxsize is prepostorously large - avoid int. overflow. */