1235267Sgabor/*-
2235267Sgabor * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
3251245Sgabor * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
4235267Sgabor * All rights reserved.
5235267Sgabor *
6235267Sgabor * Redistribution and use in source and binary forms, with or without
7235267Sgabor * modification, are permitted provided that the following conditions
8235267Sgabor * are met:
9235267Sgabor * 1. Redistributions of source code must retain the above copyright
10235267Sgabor *    notice, this list of conditions and the following disclaimer.
11235267Sgabor * 2. Redistributions in binary form must reproduce the above copyright
12235267Sgabor *    notice, this list of conditions and the following disclaimer in the
13235267Sgabor *    documentation and/or other materials provided with the distribution.
14235267Sgabor *
15235267Sgabor * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16235267Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17235267Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18235267Sgabor * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19235267Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20235267Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21235267Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22235267Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23235267Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24235267Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25235267Sgabor * SUCH DAMAGE.
26235267Sgabor */
27235267Sgabor
28235267Sgabor#include <sys/cdefs.h>
29235267Sgabor__FBSDID("$FreeBSD$");
30235267Sgabor
31235267Sgabor#include <ctype.h>
32235267Sgabor#include <errno.h>
33235267Sgabor#include <err.h>
34235267Sgabor#include <langinfo.h>
35235267Sgabor#include <math.h>
36235267Sgabor#include <stdlib.h>
37235267Sgabor#include <string.h>
38235267Sgabor#include <wchar.h>
39235267Sgabor#include <wctype.h>
40235267Sgabor
41235267Sgabor#include "bwstring.h"
42235267Sgabor#include "sort.h"
43235267Sgabor
44235435Sgaborbool byte_sort;
45235267Sgabor
46235435Sgaborstatic wchar_t **wmonths;
47235435Sgaborstatic unsigned char **cmonths;
48235267Sgabor
49235267Sgabor/* initialise months */
50235267Sgabor
51235267Sgaborvoid
52235267Sgaborinitialise_months(void)
53235267Sgabor{
54235267Sgabor	const nl_item item[12] = { ABMON_1, ABMON_2, ABMON_3, ABMON_4,
55235267Sgabor	    ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10,
56235267Sgabor	    ABMON_11, ABMON_12 };
57235267Sgabor	unsigned char *tmp;
58235267Sgabor	size_t len;
59235267Sgabor
60235267Sgabor	if (MB_CUR_MAX == 1) {
61235267Sgabor		if (cmonths == NULL) {
62235267Sgabor			unsigned char *m;
63235267Sgabor
64235267Sgabor			cmonths = sort_malloc(sizeof(unsigned char*) * 12);
65235267Sgabor			for (int i = 0; i < 12; i++) {
66235267Sgabor				cmonths[i] = NULL;
67235267Sgabor				tmp = (unsigned char *) nl_langinfo(item[i]);
68235267Sgabor				if (tmp == NULL)
69235267Sgabor					continue;
70235267Sgabor				if (debug_sort)
71235267Sgabor					printf("month[%d]=%s\n", i, tmp);
72242430Sgabor				len = strlen((char*)tmp);
73235267Sgabor				if (len < 1)
74235267Sgabor					continue;
75235267Sgabor				while (isblank(*tmp))
76235267Sgabor					++tmp;
77235267Sgabor				m = sort_malloc(len + 1);
78235267Sgabor				memcpy(m, tmp, len + 1);
79235267Sgabor				m[len] = '\0';
80235267Sgabor				for (unsigned int j = 0; j < len; j++)
81235267Sgabor					m[j] = toupper(m[j]);
82235267Sgabor				cmonths[i] = m;
83235267Sgabor			}
84235267Sgabor		}
85235267Sgabor
86235267Sgabor	} else {
87235267Sgabor		if (wmonths == NULL) {
88235267Sgabor			wchar_t *m;
89235267Sgabor
90235267Sgabor			wmonths = sort_malloc(sizeof(wchar_t *) * 12);
91235267Sgabor			for (int i = 0; i < 12; i++) {
92235267Sgabor				wmonths[i] = NULL;
93235267Sgabor				tmp = (unsigned char *) nl_langinfo(item[i]);
94235267Sgabor				if (tmp == NULL)
95235267Sgabor					continue;
96235267Sgabor				if (debug_sort)
97235267Sgabor					printf("month[%d]=%s\n", i, tmp);
98242430Sgabor				len = strlen((char*)tmp);
99235267Sgabor				if (len < 1)
100235267Sgabor					continue;
101235267Sgabor				while (isblank(*tmp))
102235267Sgabor					++tmp;
103235267Sgabor				m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1));
104242430Sgabor				if (mbstowcs(m, (char*)tmp, len) == ((size_t) -1))
105235267Sgabor					continue;
106235267Sgabor				m[len] = L'\0';
107235267Sgabor				for (unsigned int j = 0; j < len; j++)
108235267Sgabor					m[j] = towupper(m[j]);
109235267Sgabor				wmonths[i] = m;
110235267Sgabor			}
111235267Sgabor		}
112235267Sgabor	}
113235267Sgabor}
114235267Sgabor
115235267Sgabor/*
116235267Sgabor * Compare two wide-character strings
117235267Sgabor */
118235267Sgaborstatic int
119235267Sgaborwide_str_coll(const wchar_t *s1, const wchar_t *s2)
120235267Sgabor{
121235267Sgabor	int ret = 0;
122235267Sgabor
123235267Sgabor	errno = 0;
124235267Sgabor	ret = wcscoll(s1, s2);
125235267Sgabor	if (errno == EILSEQ) {
126235267Sgabor		errno = 0;
127235267Sgabor		ret = wcscmp(s1, s2);
128235267Sgabor		if (errno != 0) {
129235267Sgabor			for (size_t i = 0; ; ++i) {
130235267Sgabor				wchar_t c1 = s1[i];
131235267Sgabor				wchar_t c2 = s2[i];
132235267Sgabor				if (c1 == L'\0')
133235267Sgabor					return ((c2 == L'\0') ? 0 : -1);
134235267Sgabor				if (c2 == L'\0')
135235267Sgabor					return (+1);
136235267Sgabor				if (c1 == c2)
137235267Sgabor					continue;
138235267Sgabor				return ((int)(c1 - c2));
139235267Sgabor			}
140235267Sgabor		}
141235267Sgabor	}
142235267Sgabor	return (ret);
143235267Sgabor}
144235267Sgabor
145235267Sgabor/* counterparts of wcs functions */
146235267Sgabor
147235267Sgaborvoid
148235267Sgaborbwsprintf(FILE *f, struct bwstring *bws, const char *prefix, const char *suffix)
149235267Sgabor{
150235267Sgabor
151235267Sgabor	if (MB_CUR_MAX == 1)
152235267Sgabor		fprintf(f, "%s%s%s", prefix, bws->data.cstr, suffix);
153235267Sgabor	else
154235267Sgabor		fprintf(f, "%s%S%s", prefix, bws->data.wstr, suffix);
155235267Sgabor}
156235267Sgabor
157235267Sgaborconst void* bwsrawdata(const struct bwstring *bws)
158235267Sgabor{
159235267Sgabor
160235267Sgabor	return (&(bws->data));
161235267Sgabor}
162235267Sgabor
163235267Sgaborsize_t bwsrawlen(const struct bwstring *bws)
164235267Sgabor{
165235267Sgabor
166235267Sgabor	return ((MB_CUR_MAX == 1) ? bws->len : SIZEOF_WCHAR_STRING(bws->len));
167235267Sgabor}
168235267Sgabor
169235267Sgaborsize_t
170235267Sgaborbws_memsize(const struct bwstring *bws)
171235267Sgabor{
172235267Sgabor
173235267Sgabor	return ((MB_CUR_MAX == 1) ? (bws->len + 2 + sizeof(struct bwstring)) :
174235267Sgabor	    (SIZEOF_WCHAR_STRING(bws->len + 1) + sizeof(struct bwstring)));
175235267Sgabor}
176235267Sgabor
177235267Sgaborvoid
178235267Sgaborbws_setlen(struct bwstring *bws, size_t newlen)
179235267Sgabor{
180235267Sgabor
181235267Sgabor	if (bws && newlen != bws->len && newlen <= bws->len) {
182235267Sgabor		bws->len = newlen;
183235267Sgabor		if (MB_CUR_MAX == 1)
184235267Sgabor			bws->data.cstr[newlen] = '\0';
185235267Sgabor		else
186235267Sgabor			bws->data.wstr[newlen] = L'\0';
187235267Sgabor	}
188235267Sgabor}
189235267Sgabor
190235267Sgabor/*
191235267Sgabor * Allocate a new binary string of specified size
192235267Sgabor */
193235267Sgaborstruct bwstring *
194235267Sgaborbwsalloc(size_t sz)
195235267Sgabor{
196235267Sgabor	struct bwstring *ret;
197235267Sgabor
198235267Sgabor	if (MB_CUR_MAX == 1)
199235267Sgabor		ret = sort_malloc(sizeof(struct bwstring) + 1 + sz);
200235267Sgabor	else
201235267Sgabor		ret = sort_malloc(sizeof(struct bwstring) +
202235267Sgabor		    SIZEOF_WCHAR_STRING(sz + 1));
203235267Sgabor	ret->len = sz;
204235267Sgabor
205235267Sgabor	if (MB_CUR_MAX == 1)
206235267Sgabor		ret->data.cstr[ret->len] = '\0';
207235267Sgabor	else
208235267Sgabor		ret->data.wstr[ret->len] = L'\0';
209235267Sgabor
210235267Sgabor	return (ret);
211235267Sgabor}
212235267Sgabor
213235267Sgabor/*
214235267Sgabor * Create a copy of binary string.
215235267Sgabor * New string size equals the length of the old string.
216235267Sgabor */
217235267Sgaborstruct bwstring *
218235267Sgaborbwsdup(const struct bwstring *s)
219235267Sgabor{
220235267Sgabor
221235267Sgabor	if (s == NULL)
222235267Sgabor		return (NULL);
223235267Sgabor	else {
224235267Sgabor		struct bwstring *ret = bwsalloc(s->len);
225235267Sgabor
226235267Sgabor		if (MB_CUR_MAX == 1)
227235267Sgabor			memcpy(ret->data.cstr, s->data.cstr, (s->len));
228235267Sgabor		else
229235267Sgabor			memcpy(ret->data.wstr, s->data.wstr,
230235267Sgabor			    SIZEOF_WCHAR_STRING(s->len));
231235267Sgabor
232235267Sgabor		return (ret);
233235267Sgabor	}
234235267Sgabor}
235235267Sgabor
236235267Sgabor/*
237235267Sgabor * Create a new binary string from a raw binary buffer.
238235267Sgabor */
239235267Sgaborstruct bwstring *
240235267Sgaborbwssbdup(const wchar_t *str, size_t len)
241235267Sgabor{
242235267Sgabor
243235267Sgabor	if (str == NULL)
244235267Sgabor		return ((len == 0) ? bwsalloc(0) : NULL);
245235267Sgabor	else {
246235267Sgabor		struct bwstring *ret;
247235267Sgabor
248235267Sgabor		ret = bwsalloc(len);
249235267Sgabor
250235267Sgabor		if (MB_CUR_MAX == 1)
251235267Sgabor			for (size_t i = 0; i < len; ++i)
252235267Sgabor				ret->data.cstr[i] = (unsigned char) str[i];
253235267Sgabor		else
254235267Sgabor			memcpy(ret->data.wstr, str, SIZEOF_WCHAR_STRING(len));
255235267Sgabor
256235267Sgabor		return (ret);
257235267Sgabor	}
258235267Sgabor}
259235267Sgabor
260235267Sgabor/*
261235267Sgabor * Create a new binary string from a raw binary buffer.
262235267Sgabor */
263235267Sgaborstruct bwstring *
264235267Sgaborbwscsbdup(const unsigned char *str, size_t len)
265235267Sgabor{
266235267Sgabor	struct bwstring *ret;
267235267Sgabor
268235267Sgabor	ret = bwsalloc(len);
269235267Sgabor
270235267Sgabor	if (str) {
271235267Sgabor		if (MB_CUR_MAX == 1)
272235267Sgabor			memcpy(ret->data.cstr, str, len);
273235267Sgabor		else {
274235267Sgabor			mbstate_t mbs;
275235267Sgabor			const char *s;
276235267Sgabor			size_t charlen, chars, cptr;
277235267Sgabor
278235267Sgabor			charlen = chars = 0;
279235267Sgabor			cptr = 0;
280235267Sgabor			s = (const char *) str;
281235267Sgabor
282235267Sgabor			memset(&mbs, 0, sizeof(mbs));
283235267Sgabor
284235267Sgabor			while (cptr < len) {
285235267Sgabor				size_t n = MB_CUR_MAX;
286235267Sgabor
287235267Sgabor				if (n > len - cptr)
288235267Sgabor					n = len - cptr;
289235267Sgabor				charlen = mbrlen(s + cptr, n, &mbs);
290235267Sgabor				switch (charlen) {
291235267Sgabor				case 0:
292235267Sgabor					/* FALLTHROUGH */
293235267Sgabor				case (size_t) -1:
294235267Sgabor					/* FALLTHROUGH */
295235267Sgabor				case (size_t) -2:
296235267Sgabor					ret->data.wstr[chars++] =
297235267Sgabor					    (unsigned char) s[cptr];
298235267Sgabor					++cptr;
299235267Sgabor					break;
300235267Sgabor				default:
301235267Sgabor					n = mbrtowc(ret->data.wstr + (chars++),
302235267Sgabor					    s + cptr, charlen, &mbs);
303235267Sgabor					if ((n == (size_t)-1) || (n == (size_t)-2))
304235267Sgabor						/* NOTREACHED */
305235267Sgabor						err(2, "mbrtowc error");
306235267Sgabor					cptr += charlen;
307235267Sgabor				};
308235267Sgabor			}
309235267Sgabor
310235267Sgabor			ret->len = chars;
311235267Sgabor			ret->data.wstr[ret->len] = L'\0';
312235267Sgabor		}
313235267Sgabor	}
314235267Sgabor	return (ret);
315235267Sgabor}
316235267Sgabor
317235267Sgabor/*
318235267Sgabor * De-allocate object memory
319235267Sgabor */
320235267Sgaborvoid
321235267Sgaborbwsfree(const struct bwstring *s)
322235267Sgabor{
323235267Sgabor
324235267Sgabor	if (s)
325235267Sgabor		sort_free(s);
326235267Sgabor}
327235267Sgabor
328235267Sgabor/*
329235267Sgabor * Copy content of src binary string to dst.
330235267Sgabor * If the capacity of the dst string is not sufficient,
331235267Sgabor * then the data is truncated.
332235267Sgabor */
333235267Sgaborsize_t
334235267Sgaborbwscpy(struct bwstring *dst, const struct bwstring *src)
335235267Sgabor{
336235267Sgabor	size_t nums = src->len;
337235267Sgabor
338235267Sgabor	if (nums > dst->len)
339235267Sgabor		nums = dst->len;
340235267Sgabor	dst->len = nums;
341235267Sgabor
342235267Sgabor	if (MB_CUR_MAX == 1) {
343235267Sgabor		memcpy(dst->data.cstr, src->data.cstr, nums);
344235267Sgabor		dst->data.cstr[dst->len] = '\0';
345235267Sgabor	} else {
346235267Sgabor		memcpy(dst->data.wstr, src->data.wstr,
347235267Sgabor		    SIZEOF_WCHAR_STRING(nums + 1));
348235267Sgabor		dst->data.wstr[dst->len] = L'\0';
349235267Sgabor	}
350235267Sgabor
351235267Sgabor	return (nums);
352235267Sgabor}
353235267Sgabor
354235267Sgabor/*
355235267Sgabor * Copy content of src binary string to dst,
356235267Sgabor * with specified number of symbols to be copied.
357235267Sgabor * If the capacity of the dst string is not sufficient,
358235267Sgabor * then the data is truncated.
359235267Sgabor */
360235267Sgaborstruct bwstring *
361235267Sgaborbwsncpy(struct bwstring *dst, const struct bwstring *src, size_t size)
362235267Sgabor{
363235267Sgabor	size_t nums = src->len;
364235267Sgabor
365235267Sgabor	if (nums > dst->len)
366235267Sgabor		nums = dst->len;
367235267Sgabor	if (nums > size)
368235267Sgabor		nums = size;
369235267Sgabor	dst->len = nums;
370235267Sgabor
371235267Sgabor	if (MB_CUR_MAX == 1) {
372235267Sgabor		memcpy(dst->data.cstr, src->data.cstr, nums);
373235267Sgabor		dst->data.cstr[dst->len] = '\0';
374235267Sgabor	} else {
375235267Sgabor		memcpy(dst->data.wstr, src->data.wstr,
376235267Sgabor		    SIZEOF_WCHAR_STRING(nums + 1));
377235267Sgabor		dst->data.wstr[dst->len] = L'\0';
378235267Sgabor	}
379235267Sgabor
380235267Sgabor	return (dst);
381235267Sgabor}
382235267Sgabor
383235267Sgabor/*
384235267Sgabor * Copy content of src binary string to dst,
385235267Sgabor * with specified number of symbols to be copied.
386235267Sgabor * An offset value can be specified, from the start of src string.
387235267Sgabor * If the capacity of the dst string is not sufficient,
388235267Sgabor * then the data is truncated.
389235267Sgabor */
390235267Sgaborstruct bwstring *
391235267Sgaborbwsnocpy(struct bwstring *dst, const struct bwstring *src, size_t offset,
392235267Sgabor    size_t size)
393235267Sgabor{
394235267Sgabor
395235267Sgabor	if (offset >= src->len) {
396235267Sgabor		dst->data.wstr[0] = 0;
397235267Sgabor		dst->len = 0;
398235267Sgabor	} else {
399235267Sgabor		size_t nums = src->len - offset;
400235267Sgabor
401235267Sgabor		if (nums > dst->len)
402235267Sgabor			nums = dst->len;
403235267Sgabor		if (nums > size)
404235267Sgabor			nums = size;
405235267Sgabor		dst->len = nums;
406235267Sgabor		if (MB_CUR_MAX == 1) {
407235267Sgabor			memcpy(dst->data.cstr, src->data.cstr + offset,
408235267Sgabor			    (nums));
409235267Sgabor			dst->data.cstr[dst->len] = '\0';
410235267Sgabor		} else {
411235267Sgabor			memcpy(dst->data.wstr, src->data.wstr + offset,
412235267Sgabor			    SIZEOF_WCHAR_STRING(nums));
413235267Sgabor			dst->data.wstr[dst->len] = L'\0';
414235267Sgabor		}
415235267Sgabor	}
416235267Sgabor	return (dst);
417235267Sgabor}
418235267Sgabor
419235267Sgabor/*
420235267Sgabor * Write binary string to the file.
421235267Sgabor * The output is ended either with '\n' (nl == true)
422235267Sgabor * or '\0' (nl == false).
423235267Sgabor */
424242430Sgaborsize_t
425235267Sgaborbwsfwrite(struct bwstring *bws, FILE *f, bool zero_ended)
426235267Sgabor{
427235267Sgabor
428235267Sgabor	if (MB_CUR_MAX == 1) {
429235267Sgabor		size_t len = bws->len;
430235267Sgabor
431235267Sgabor		if (!zero_ended) {
432235267Sgabor			bws->data.cstr[len] = '\n';
433235267Sgabor
434235267Sgabor			if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
435235267Sgabor				err(2, NULL);
436235267Sgabor
437235267Sgabor			bws->data.cstr[len] = '\0';
438235267Sgabor		} else if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
439235267Sgabor			err(2, NULL);
440235267Sgabor
441235267Sgabor		return (len + 1);
442235267Sgabor
443235267Sgabor	} else {
444235267Sgabor		wchar_t eols;
445242430Sgabor		size_t printed = 0;
446235267Sgabor
447235267Sgabor		eols = zero_ended ? btowc('\0') : btowc('\n');
448235267Sgabor
449242430Sgabor		while (printed < BWSLEN(bws)) {
450235267Sgabor			const wchar_t *s = bws->data.wstr + printed;
451235267Sgabor
452235267Sgabor			if (*s == L'\0') {
453235267Sgabor				int nums;
454235267Sgabor
455235267Sgabor				nums = fwprintf(f, L"%lc", *s);
456235267Sgabor
457235267Sgabor				if (nums != 1)
458235267Sgabor					err(2, NULL);
459235267Sgabor				++printed;
460235267Sgabor			} else {
461235267Sgabor				int nums;
462235267Sgabor
463235267Sgabor				nums = fwprintf(f, L"%ls", s);
464235267Sgabor
465235267Sgabor				if (nums < 1)
466235267Sgabor					err(2, NULL);
467235267Sgabor				printed += nums;
468235267Sgabor			}
469235267Sgabor		}
470235267Sgabor		fwprintf(f, L"%lc", eols);
471235267Sgabor		return (printed + 1);
472235267Sgabor	}
473235267Sgabor}
474235267Sgabor
475235267Sgabor/*
476235267Sgabor * Allocate and read a binary string from file.
477235267Sgabor * The strings are nl-ended or zero-ended, depending on the sort setting.
478235267Sgabor */
479235267Sgaborstruct bwstring *
480235267Sgaborbwsfgetln(FILE *f, size_t *len, bool zero_ended, struct reader_buffer *rb)
481235267Sgabor{
482242430Sgabor	wint_t eols;
483235267Sgabor
484235267Sgabor	eols = zero_ended ? btowc('\0') : btowc('\n');
485235267Sgabor
486235267Sgabor	if (!zero_ended && (MB_CUR_MAX > 1)) {
487235267Sgabor		wchar_t *ret;
488235267Sgabor
489235267Sgabor		ret = fgetwln(f, len);
490235267Sgabor
491235267Sgabor		if (ret == NULL) {
492235267Sgabor			if (!feof(f))
493235267Sgabor				err(2, NULL);
494235267Sgabor			return (NULL);
495235267Sgabor		}
496235267Sgabor		if (*len > 0) {
497242430Sgabor			if (ret[*len - 1] == (wchar_t)eols)
498235267Sgabor				--(*len);
499235267Sgabor		}
500235267Sgabor		return (bwssbdup(ret, *len));
501235267Sgabor
502235987Sgabor	} else if (!zero_ended && (MB_CUR_MAX == 1)) {
503235987Sgabor		char *ret;
504235987Sgabor
505235987Sgabor		ret = fgetln(f, len);
506235987Sgabor
507235987Sgabor		if (ret == NULL) {
508235987Sgabor			if (!feof(f))
509235987Sgabor				err(2, NULL);
510235987Sgabor			return (NULL);
511235987Sgabor		}
512235987Sgabor		if (*len > 0) {
513235987Sgabor			if (ret[*len - 1] == '\n')
514235987Sgabor				--(*len);
515235987Sgabor		}
516242430Sgabor		return (bwscsbdup((unsigned char*)ret, *len));
517235987Sgabor
518235267Sgabor	} else {
519235267Sgabor		*len = 0;
520235267Sgabor
521235267Sgabor		if (feof(f))
522235267Sgabor			return (NULL);
523235267Sgabor
524235267Sgabor		if (2 >= rb->fgetwln_z_buffer_size) {
525235267Sgabor			rb->fgetwln_z_buffer_size += 256;
526235267Sgabor			rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
527235267Sgabor			    sizeof(wchar_t) * rb->fgetwln_z_buffer_size);
528235267Sgabor		}
529235267Sgabor		rb->fgetwln_z_buffer[*len] = 0;
530235267Sgabor
531235267Sgabor		if (MB_CUR_MAX == 1)
532235267Sgabor			while (!feof(f)) {
533242430Sgabor				int c;
534242430Sgabor
535235267Sgabor				c = fgetc(f);
536235267Sgabor
537235267Sgabor				if (c == EOF) {
538235267Sgabor					if (*len == 0)
539235267Sgabor						return (NULL);
540235267Sgabor					goto line_read_done;
541235267Sgabor				}
542235267Sgabor				if (c == eols)
543235267Sgabor					goto line_read_done;
544235267Sgabor
545235267Sgabor				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
546235267Sgabor					rb->fgetwln_z_buffer_size += 256;
547235267Sgabor					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
548235267Sgabor					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
549235267Sgabor				}
550235267Sgabor
551235267Sgabor				rb->fgetwln_z_buffer[*len] = c;
552235267Sgabor				rb->fgetwln_z_buffer[++(*len)] = 0;
553235267Sgabor			}
554235267Sgabor		else
555235267Sgabor			while (!feof(f)) {
556242430Sgabor				wint_t c = 0;
557242430Sgabor
558235267Sgabor				c = fgetwc(f);
559235267Sgabor
560235267Sgabor				if (c == WEOF) {
561235267Sgabor					if (*len == 0)
562235267Sgabor						return (NULL);
563235267Sgabor					goto line_read_done;
564235267Sgabor				}
565235267Sgabor				if (c == eols)
566235267Sgabor					goto line_read_done;
567235267Sgabor
568235267Sgabor				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
569235267Sgabor					rb->fgetwln_z_buffer_size += 256;
570235267Sgabor					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
571235267Sgabor					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
572235267Sgabor				}
573235267Sgabor
574235267Sgabor				rb->fgetwln_z_buffer[*len] = c;
575235267Sgabor				rb->fgetwln_z_buffer[++(*len)] = 0;
576235267Sgabor			}
577235267Sgabor
578235267Sgaborline_read_done:
579235267Sgabor		/* we do not count the last 0 */
580235267Sgabor		return (bwssbdup(rb->fgetwln_z_buffer, *len));
581235267Sgabor	}
582235267Sgabor}
583235267Sgabor
584235267Sgaborint
585235267Sgaborbwsncmp(const struct bwstring *bws1, const struct bwstring *bws2,
586235267Sgabor    size_t offset, size_t len)
587235267Sgabor{
588235267Sgabor	size_t cmp_len, len1, len2;
589235267Sgabor	int res = 0;
590235267Sgabor
591235267Sgabor	cmp_len = 0;
592235267Sgabor	len1 = bws1->len;
593235267Sgabor	len2 = bws2->len;
594235267Sgabor
595235267Sgabor	if (len1 <= offset) {
596235267Sgabor		return ((len2 <= offset) ? 0 : -1);
597235267Sgabor	} else {
598235267Sgabor		if (len2 <= offset)
599235267Sgabor			return (+1);
600235267Sgabor		else {
601235267Sgabor			len1 -= offset;
602235267Sgabor			len2 -= offset;
603235267Sgabor
604235267Sgabor			cmp_len = len1;
605235267Sgabor
606235267Sgabor			if (len2 < cmp_len)
607235267Sgabor				cmp_len = len2;
608235267Sgabor
609235267Sgabor			if (len < cmp_len)
610235267Sgabor				cmp_len = len;
611235267Sgabor
612235267Sgabor			if (MB_CUR_MAX == 1) {
613235267Sgabor				const unsigned char *s1, *s2;
614235267Sgabor
615235267Sgabor				s1 = bws1->data.cstr + offset;
616235267Sgabor				s2 = bws2->data.cstr + offset;
617235267Sgabor
618235267Sgabor				res = memcmp(s1, s2, cmp_len);
619235267Sgabor
620235267Sgabor			} else {
621235267Sgabor				const wchar_t *s1, *s2;
622235267Sgabor
623235267Sgabor				s1 = bws1->data.wstr + offset;
624235267Sgabor				s2 = bws2->data.wstr + offset;
625235267Sgabor
626235267Sgabor				res = memcmp(s1, s2, SIZEOF_WCHAR_STRING(cmp_len));
627235267Sgabor			}
628235267Sgabor		}
629235267Sgabor	}
630235267Sgabor
631235267Sgabor	if (res == 0) {
632235267Sgabor		if (len1 < cmp_len && len1 < len2)
633235267Sgabor			res = -1;
634235267Sgabor		else if (len2 < cmp_len && len2 < len1)
635235267Sgabor			res = +1;
636235267Sgabor	}
637235267Sgabor
638235267Sgabor	return (res);
639235267Sgabor}
640235267Sgabor
641235267Sgaborint
642235267Sgaborbwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
643235267Sgabor{
644235267Sgabor	size_t len1, len2, cmp_len;
645235267Sgabor	int res;
646235267Sgabor
647235267Sgabor	len1 = bws1->len;
648235267Sgabor	len2 = bws2->len;
649235267Sgabor
650235267Sgabor	len1 -= offset;
651235267Sgabor	len2 -= offset;
652235267Sgabor
653235267Sgabor	cmp_len = len1;
654235267Sgabor
655235267Sgabor	if (len2 < cmp_len)
656235267Sgabor		cmp_len = len2;
657235267Sgabor
658235267Sgabor	res = bwsncmp(bws1, bws2, offset, cmp_len);
659235267Sgabor
660235267Sgabor	if (res == 0) {
661235267Sgabor		if( len1 < len2)
662235267Sgabor			res = -1;
663235267Sgabor		else if (len2 < len1)
664235267Sgabor			res = +1;
665235267Sgabor	}
666235267Sgabor
667235267Sgabor	return (res);
668235267Sgabor}
669235267Sgabor
670235267Sgaborint
671235267Sgaborbws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len)
672235267Sgabor{
673235267Sgabor	wchar_t c1, c2;
674235267Sgabor	size_t i = 0;
675235267Sgabor
676235267Sgabor	for (i = 0; i < len; ++i) {
677235267Sgabor		c1 = bws_get_iter_value(iter1);
678235267Sgabor		c2 = bws_get_iter_value(iter2);
679235267Sgabor		if (c1 != c2)
680235267Sgabor			return (c1 - c2);
681235267Sgabor		iter1 = bws_iterator_inc(iter1, 1);
682235267Sgabor		iter2 = bws_iterator_inc(iter2, 1);
683235267Sgabor	}
684235267Sgabor
685235267Sgabor	return (0);
686235267Sgabor}
687235267Sgabor
688235267Sgaborint
689235267Sgaborbwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
690235267Sgabor{
691235267Sgabor	size_t len1, len2;
692235267Sgabor
693235267Sgabor	len1 = bws1->len;
694235267Sgabor	len2 = bws2->len;
695235267Sgabor
696235267Sgabor	if (len1 <= offset)
697235267Sgabor		return ((len2 <= offset) ? 0 : -1);
698235267Sgabor	else {
699235267Sgabor		if (len2 <= offset)
700235267Sgabor			return (+1);
701235267Sgabor		else {
702235267Sgabor			len1 -= offset;
703235267Sgabor			len2 -= offset;
704235267Sgabor
705235267Sgabor			if (MB_CUR_MAX == 1) {
706235267Sgabor				const unsigned char *s1, *s2;
707235267Sgabor
708235267Sgabor				s1 = bws1->data.cstr + offset;
709235267Sgabor				s2 = bws2->data.cstr + offset;
710235267Sgabor
711235267Sgabor				if (byte_sort) {
712235267Sgabor					int res = 0;
713235267Sgabor
714235267Sgabor					if (len1 > len2) {
715235267Sgabor						res = memcmp(s1, s2, len2);
716235267Sgabor						if (!res)
717235267Sgabor							res = +1;
718235267Sgabor					} else if (len1 < len2) {
719235267Sgabor						res = memcmp(s1, s2, len1);
720235267Sgabor						if (!res)
721235267Sgabor							res = -1;
722235267Sgabor					} else
723235267Sgabor						res = memcmp(s1, s2, len1);
724235267Sgabor
725235267Sgabor					return (res);
726235267Sgabor
727235267Sgabor				} else {
728235267Sgabor					int res = 0;
729235267Sgabor					size_t i, maxlen;
730235267Sgabor
731235267Sgabor					i = 0;
732235267Sgabor					maxlen = len1;
733235267Sgabor
734235267Sgabor					if (maxlen > len2)
735235267Sgabor						maxlen = len2;
736235267Sgabor
737235267Sgabor					while (i < maxlen) {
738235267Sgabor						/* goto next non-zero part: */
739235267Sgabor						while ((i < maxlen) &&
740235267Sgabor						    !s1[i] && !s2[i])
741235267Sgabor							++i;
742235267Sgabor
743235267Sgabor						if (i >= maxlen)
744235267Sgabor							break;
745235267Sgabor
746235267Sgabor						if (s1[i] == 0) {
747235267Sgabor							if (s2[i] == 0)
748235267Sgabor								/* NOTREACHED */
749235267Sgabor								err(2, "bwscoll error 01");
750235267Sgabor							else
751235267Sgabor								return (-1);
752235267Sgabor						} else if (s2[i] == 0)
753235267Sgabor							return (+1);
754235267Sgabor
755242430Sgabor						res = strcoll((const char*)(s1 + i), (const char*)(s2 + i));
756235267Sgabor						if (res)
757235267Sgabor							return (res);
758235267Sgabor
759235267Sgabor						while ((i < maxlen) &&
760235267Sgabor						    s1[i] && s2[i])
761235267Sgabor							++i;
762235267Sgabor
763235267Sgabor						if (i >= maxlen)
764235267Sgabor							break;
765235267Sgabor
766235267Sgabor						if (s1[i] == 0) {
767235267Sgabor							if (s2[i] == 0) {
768235267Sgabor								++i;
769235267Sgabor								continue;
770235267Sgabor							} else
771235267Sgabor								return (-1);
772235267Sgabor						} else if (s2[i] == 0)
773235267Sgabor							return (+1);
774235267Sgabor						else
775235267Sgabor							/* NOTREACHED */
776235267Sgabor							err(2, "bwscoll error 02");
777235267Sgabor					}
778235267Sgabor
779235267Sgabor					if (len1 < len2)
780235267Sgabor						return (-1);
781235267Sgabor					else if (len1 > len2)
782235267Sgabor						return (+1);
783235267Sgabor
784235267Sgabor					return (0);
785235267Sgabor				}
786235267Sgabor			} else {
787235267Sgabor				const wchar_t *s1, *s2;
788235267Sgabor				size_t i, maxlen;
789235267Sgabor				int res = 0;
790235267Sgabor
791235267Sgabor				s1 = bws1->data.wstr + offset;
792235267Sgabor				s2 = bws2->data.wstr + offset;
793235267Sgabor
794235267Sgabor				i = 0;
795235267Sgabor				maxlen = len1;
796235267Sgabor
797235267Sgabor				if (maxlen > len2)
798235267Sgabor					maxlen = len2;
799235267Sgabor
800235267Sgabor				while (i < maxlen) {
801235267Sgabor
802235267Sgabor					/* goto next non-zero part: */
803235267Sgabor					while ((i < maxlen) &&
804235267Sgabor					    !s1[i] && !s2[i])
805235267Sgabor						++i;
806235267Sgabor
807235267Sgabor					if (i >= maxlen)
808235267Sgabor						break;
809235267Sgabor
810235267Sgabor					if (s1[i] == 0) {
811235267Sgabor						if (s2[i] == 0)
812235267Sgabor							/* NOTREACHED */
813235267Sgabor							err(2, "bwscoll error 1");
814235267Sgabor						else
815235267Sgabor							return (-1);
816235267Sgabor					} else if (s2[i] == 0)
817235267Sgabor						return (+1);
818235267Sgabor
819235267Sgabor					res = wide_str_coll(s1 + i, s2 + i);
820235267Sgabor					if (res)
821235267Sgabor						return (res);
822235267Sgabor
823235267Sgabor					while ((i < maxlen) && s1[i] && s2[i])
824235267Sgabor						++i;
825235267Sgabor
826235267Sgabor					if (i >= maxlen)
827235267Sgabor						break;
828235267Sgabor
829235267Sgabor					if (s1[i] == 0) {
830235267Sgabor						if (s2[i] == 0) {
831235267Sgabor							++i;
832235267Sgabor							continue;
833235267Sgabor						} else
834235267Sgabor							return (-1);
835235267Sgabor					} else if (s2[i] == 0)
836235267Sgabor						return (+1);
837235267Sgabor					else
838235267Sgabor						/* NOTREACHED */
839235267Sgabor						err(2, "bwscoll error 2");
840235267Sgabor				}
841235267Sgabor
842235267Sgabor				if (len1 < len2)
843235267Sgabor					return (-1);
844235267Sgabor				else if (len1 > len2)
845235267Sgabor					return (+1);
846235267Sgabor
847235267Sgabor				return (0);
848235267Sgabor			}
849235267Sgabor		}
850235267Sgabor	}
851235267Sgabor}
852235267Sgabor
853235267Sgabor/*
854235267Sgabor * Correction of the system API
855235267Sgabor */
856235267Sgabordouble
857235267Sgaborbwstod(struct bwstring *s0, bool *empty)
858235267Sgabor{
859235267Sgabor	double ret = 0;
860235267Sgabor
861235267Sgabor	if (MB_CUR_MAX == 1) {
862235267Sgabor		unsigned char *end, *s;
863235267Sgabor		char *ep;
864235267Sgabor
865235267Sgabor		s = s0->data.cstr;
866235267Sgabor		end = s + s0->len;
867235267Sgabor		ep = NULL;
868235267Sgabor
869235267Sgabor		while (isblank(*s) && s < end)
870235267Sgabor			++s;
871235267Sgabor
872235267Sgabor		if (!isprint(*s)) {
873235267Sgabor			*empty = true;
874235267Sgabor			return (0);
875235267Sgabor		}
876235267Sgabor
877242430Sgabor		ret = strtod((char*)s, &ep);
878235267Sgabor		if ((unsigned char*) ep == s) {
879235267Sgabor			*empty = true;
880235267Sgabor			return (0);
881235267Sgabor		}
882235267Sgabor	} else {
883235267Sgabor		wchar_t *end, *ep, *s;
884235267Sgabor
885235267Sgabor		s = s0->data.wstr;
886235267Sgabor		end = s + s0->len;
887235267Sgabor		ep = NULL;
888235267Sgabor
889235267Sgabor		while (iswblank(*s) && s < end)
890235267Sgabor			++s;
891235267Sgabor
892235267Sgabor		if (!iswprint(*s)) {
893235267Sgabor			*empty = true;
894235267Sgabor			return (0);
895235267Sgabor		}
896235267Sgabor
897235267Sgabor		ret = wcstod(s, &ep);
898235267Sgabor		if (ep == s) {
899235267Sgabor			*empty = true;
900235267Sgabor			return (0);
901235267Sgabor		}
902235267Sgabor	}
903235267Sgabor
904235267Sgabor	*empty = false;
905235267Sgabor	return (ret);
906235267Sgabor}
907235267Sgabor
908235267Sgabor/*
909235267Sgabor * A helper function for monthcoll.  If a line matches
910235267Sgabor * a month name, it returns (number of the month - 1),
911235267Sgabor * while if there is no match, it just return -1.
912235267Sgabor */
913235267Sgabor
914235267Sgaborint
915235267Sgaborbws_month_score(const struct bwstring *s0)
916235267Sgabor{
917235267Sgabor
918235267Sgabor	if (MB_CUR_MAX == 1) {
919235267Sgabor		const unsigned char *end, *s;
920235267Sgabor		size_t len;
921235267Sgabor
922235267Sgabor		s = s0->data.cstr;
923235267Sgabor		end = s + s0->len;
924235267Sgabor
925235267Sgabor		while (isblank(*s) && s < end)
926235267Sgabor			++s;
927235267Sgabor
928242430Sgabor		len = strlen((const char*)s);
929235267Sgabor
930235267Sgabor		for (int i = 11; i >= 0; --i) {
931235267Sgabor			if (cmonths[i] &&
932242430Sgabor			    (s == (unsigned char*)strstr((const char*)s, (char*)(cmonths[i]))))
933235267Sgabor				return (i);
934235267Sgabor		}
935235267Sgabor
936235267Sgabor	} else {
937235267Sgabor		const wchar_t *end, *s;
938235267Sgabor		size_t len;
939235267Sgabor
940235267Sgabor		s = s0->data.wstr;
941235267Sgabor		end = s + s0->len;
942235267Sgabor
943235267Sgabor		while (iswblank(*s) && s < end)
944235267Sgabor			++s;
945235267Sgabor
946235267Sgabor		len = wcslen(s);
947235267Sgabor
948235267Sgabor		for (int i = 11; i >= 0; --i) {
949235267Sgabor			if (wmonths[i] && (s == wcsstr(s, wmonths[i])))
950235267Sgabor				return (i);
951235267Sgabor		}
952235267Sgabor	}
953235267Sgabor
954235267Sgabor	return (-1);
955235267Sgabor}
956235267Sgabor
957235267Sgabor/*
958235267Sgabor * Rips out leading blanks (-b).
959235267Sgabor */
960235267Sgaborstruct bwstring *
961235267Sgaborignore_leading_blanks(struct bwstring *str)
962235267Sgabor{
963235267Sgabor
964235267Sgabor	if (MB_CUR_MAX == 1) {
965235267Sgabor		unsigned char *dst, *end, *src;
966235267Sgabor
967235267Sgabor		src = str->data.cstr;
968235267Sgabor		dst = src;
969235267Sgabor		end = src + str->len;
970235267Sgabor
971235267Sgabor		while (src < end && isblank(*src))
972235267Sgabor			++src;
973235267Sgabor
974235267Sgabor		if (src != dst) {
975235267Sgabor			size_t newlen;
976235267Sgabor
977235267Sgabor			newlen = BWSLEN(str) - (src - dst);
978235267Sgabor
979235267Sgabor			while (src < end) {
980235267Sgabor				*dst = *src;
981235267Sgabor				++dst;
982235267Sgabor				++src;
983235267Sgabor			}
984235267Sgabor			bws_setlen(str, newlen);
985235267Sgabor		}
986235267Sgabor	} else {
987235267Sgabor		wchar_t *dst, *end, *src;
988235267Sgabor
989235267Sgabor		src = str->data.wstr;
990235267Sgabor		dst = src;
991235267Sgabor		end = src + str->len;
992235267Sgabor
993235267Sgabor		while (src < end && iswblank(*src))
994235267Sgabor			++src;
995235267Sgabor
996235267Sgabor		if (src != dst) {
997235267Sgabor
998235267Sgabor			size_t newlen = BWSLEN(str) - (src - dst);
999235267Sgabor
1000235267Sgabor			while (src < end) {
1001235267Sgabor				*dst = *src;
1002235267Sgabor				++dst;
1003235267Sgabor				++src;
1004235267Sgabor			}
1005235267Sgabor			bws_setlen(str, newlen);
1006235267Sgabor
1007235267Sgabor		}
1008235267Sgabor	}
1009235267Sgabor	return (str);
1010235267Sgabor}
1011235267Sgabor
1012235267Sgabor/*
1013235267Sgabor * Rips out nonprinting characters (-i).
1014235267Sgabor */
1015235267Sgaborstruct bwstring *
1016235267Sgaborignore_nonprinting(struct bwstring *str)
1017235267Sgabor{
1018235267Sgabor	size_t newlen = str->len;
1019235267Sgabor
1020235267Sgabor	if (MB_CUR_MAX == 1) {
1021235267Sgabor		unsigned char *dst, *end, *src;
1022235267Sgabor		unsigned char c;
1023235267Sgabor
1024235267Sgabor		src = str->data.cstr;
1025235267Sgabor		dst = src;
1026235267Sgabor		end = src + str->len;
1027235267Sgabor
1028235267Sgabor		while (src < end) {
1029235267Sgabor			c = *src;
1030235267Sgabor			if (isprint(c)) {
1031235267Sgabor				*dst = c;
1032235267Sgabor				++dst;
1033235267Sgabor				++src;
1034235267Sgabor			} else {
1035235267Sgabor				++src;
1036235267Sgabor				--newlen;
1037235267Sgabor			}
1038235267Sgabor		}
1039235267Sgabor	} else {
1040235267Sgabor		wchar_t *dst, *end, *src;
1041235267Sgabor		wchar_t c;
1042235267Sgabor
1043235267Sgabor		src = str->data.wstr;
1044235267Sgabor		dst = src;
1045235267Sgabor		end = src + str->len;
1046235267Sgabor
1047235267Sgabor		while (src < end) {
1048235267Sgabor			c = *src;
1049235267Sgabor			if (iswprint(c)) {
1050235267Sgabor				*dst = c;
1051235267Sgabor				++dst;
1052235267Sgabor				++src;
1053235267Sgabor			} else {
1054235267Sgabor				++src;
1055235267Sgabor				--newlen;
1056235267Sgabor			}
1057235267Sgabor		}
1058235267Sgabor	}
1059235267Sgabor	bws_setlen(str, newlen);
1060235267Sgabor
1061235267Sgabor	return (str);
1062235267Sgabor}
1063235267Sgabor
1064235267Sgabor/*
1065235267Sgabor * Rips out any characters that are not alphanumeric characters
1066235267Sgabor * nor blanks (-d).
1067235267Sgabor */
1068235267Sgaborstruct bwstring *
1069235267Sgabordictionary_order(struct bwstring *str)
1070235267Sgabor{
1071235267Sgabor	size_t newlen = str->len;
1072235267Sgabor
1073235267Sgabor	if (MB_CUR_MAX == 1) {
1074235267Sgabor		unsigned char *dst, *end, *src;
1075235267Sgabor		unsigned char c;
1076235267Sgabor
1077235267Sgabor		src = str->data.cstr;
1078235267Sgabor		dst = src;
1079235267Sgabor		end = src + str->len;
1080235267Sgabor
1081235267Sgabor		while (src < end) {
1082235267Sgabor			c = *src;
1083235267Sgabor			if (isalnum(c) || isblank(c)) {
1084235267Sgabor				*dst = c;
1085235267Sgabor				++dst;
1086235267Sgabor				++src;
1087235267Sgabor			} else {
1088235267Sgabor				++src;
1089235267Sgabor				--newlen;
1090235267Sgabor			}
1091235267Sgabor		}
1092235267Sgabor	} else {
1093235267Sgabor		wchar_t *dst, *end, *src;
1094235267Sgabor		wchar_t c;
1095235267Sgabor
1096235267Sgabor		src = str->data.wstr;
1097235267Sgabor		dst = src;
1098235267Sgabor		end = src + str->len;
1099235267Sgabor
1100235267Sgabor		while (src < end) {
1101235267Sgabor			c = *src;
1102235267Sgabor			if (iswalnum(c) || iswblank(c)) {
1103235267Sgabor				*dst = c;
1104235267Sgabor				++dst;
1105235267Sgabor				++src;
1106235267Sgabor			} else {
1107235267Sgabor				++src;
1108235267Sgabor				--newlen;
1109235267Sgabor			}
1110235267Sgabor		}
1111235267Sgabor	}
1112235267Sgabor	bws_setlen(str, newlen);
1113235267Sgabor
1114235267Sgabor	return (str);
1115235267Sgabor}
1116235267Sgabor
1117235267Sgabor/*
1118235267Sgabor * Converts string to lower case(-f).
1119235267Sgabor */
1120235267Sgaborstruct bwstring *
1121235267Sgaborignore_case(struct bwstring *str)
1122235267Sgabor{
1123235267Sgabor
1124235267Sgabor	if (MB_CUR_MAX == 1) {
1125235267Sgabor		unsigned char *end, *s;
1126235267Sgabor
1127235267Sgabor		s = str->data.cstr;
1128235267Sgabor		end = s + str->len;
1129235267Sgabor
1130235267Sgabor		while (s < end) {
1131235267Sgabor			*s = toupper(*s);
1132235267Sgabor			++s;
1133235267Sgabor		}
1134235267Sgabor	} else {
1135235267Sgabor		wchar_t *end, *s;
1136235267Sgabor
1137235267Sgabor		s = str->data.wstr;
1138235267Sgabor		end = s + str->len;
1139235267Sgabor
1140235267Sgabor		while (s < end) {
1141235267Sgabor			*s = towupper(*s);
1142235267Sgabor			++s;
1143235267Sgabor		}
1144235267Sgabor	}
1145235267Sgabor	return (str);
1146235267Sgabor}
1147235267Sgabor
1148235267Sgaborvoid
1149235267Sgaborbws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos)
1150235267Sgabor{
1151235267Sgabor
1152235267Sgabor	if (MB_CUR_MAX == 1)
1153235267Sgabor		warnx("%s:%zu: disorder: %s", fn, pos + 1, s->data.cstr);
1154235267Sgabor	else
1155235267Sgabor		warnx("%s:%zu: disorder: %ls", fn, pos + 1, s->data.wstr);
1156235267Sgabor}
1157