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: stable/10/usr.bin/sort/bwstring.c 309862 2016-12-12 00:47:12Z delphij $");
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 (debug_sort)
69235267Sgabor					printf("month[%d]=%s\n", i, tmp);
70281535Spfg				if (*tmp == '\0')
71235267Sgabor					continue;
72281535Spfg				m = sort_strdup(tmp);
73281535Spfg				len = strlen(tmp);
74235267Sgabor				for (unsigned int j = 0; j < len; j++)
75235267Sgabor					m[j] = toupper(m[j]);
76235267Sgabor				cmonths[i] = m;
77235267Sgabor			}
78235267Sgabor		}
79235267Sgabor
80235267Sgabor	} else {
81235267Sgabor		if (wmonths == NULL) {
82235267Sgabor			wchar_t *m;
83235267Sgabor
84235267Sgabor			wmonths = sort_malloc(sizeof(wchar_t *) * 12);
85235267Sgabor			for (int i = 0; i < 12; i++) {
86235267Sgabor				wmonths[i] = NULL;
87235267Sgabor				tmp = (unsigned char *) nl_langinfo(item[i]);
88235267Sgabor				if (debug_sort)
89235267Sgabor					printf("month[%d]=%s\n", i, tmp);
90281535Spfg				if (*tmp == '\0')
91235267Sgabor					continue;
92281535Spfg				len = strlen(tmp);
93235267Sgabor				m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1));
94281535Spfg				if (mbstowcs(m, (char*)tmp, len) ==
95281535Spfg				    ((size_t) - 1)) {
96281535Spfg					sort_free(m);
97235267Sgabor					continue;
98281535Spfg				}
99235267Sgabor				m[len] = L'\0';
100235267Sgabor				for (unsigned int j = 0; j < len; j++)
101235267Sgabor					m[j] = towupper(m[j]);
102235267Sgabor				wmonths[i] = m;
103235267Sgabor			}
104235267Sgabor		}
105235267Sgabor	}
106235267Sgabor}
107235267Sgabor
108235267Sgabor/*
109235267Sgabor * Compare two wide-character strings
110235267Sgabor */
111235267Sgaborstatic int
112235267Sgaborwide_str_coll(const wchar_t *s1, const wchar_t *s2)
113235267Sgabor{
114235267Sgabor	int ret = 0;
115235267Sgabor
116235267Sgabor	errno = 0;
117235267Sgabor	ret = wcscoll(s1, s2);
118235267Sgabor	if (errno == EILSEQ) {
119235267Sgabor		errno = 0;
120235267Sgabor		ret = wcscmp(s1, s2);
121235267Sgabor		if (errno != 0) {
122235267Sgabor			for (size_t i = 0; ; ++i) {
123235267Sgabor				wchar_t c1 = s1[i];
124235267Sgabor				wchar_t c2 = s2[i];
125235267Sgabor				if (c1 == L'\0')
126235267Sgabor					return ((c2 == L'\0') ? 0 : -1);
127235267Sgabor				if (c2 == L'\0')
128235267Sgabor					return (+1);
129235267Sgabor				if (c1 == c2)
130235267Sgabor					continue;
131235267Sgabor				return ((int)(c1 - c2));
132235267Sgabor			}
133235267Sgabor		}
134235267Sgabor	}
135235267Sgabor	return (ret);
136235267Sgabor}
137235267Sgabor
138235267Sgabor/* counterparts of wcs functions */
139235267Sgabor
140235267Sgaborvoid
141235267Sgaborbwsprintf(FILE *f, struct bwstring *bws, const char *prefix, const char *suffix)
142235267Sgabor{
143235267Sgabor
144235267Sgabor	if (MB_CUR_MAX == 1)
145235267Sgabor		fprintf(f, "%s%s%s", prefix, bws->data.cstr, suffix);
146235267Sgabor	else
147235267Sgabor		fprintf(f, "%s%S%s", prefix, bws->data.wstr, suffix);
148235267Sgabor}
149235267Sgabor
150235267Sgaborconst void* bwsrawdata(const struct bwstring *bws)
151235267Sgabor{
152235267Sgabor
153235267Sgabor	return (&(bws->data));
154235267Sgabor}
155235267Sgabor
156235267Sgaborsize_t bwsrawlen(const struct bwstring *bws)
157235267Sgabor{
158235267Sgabor
159235267Sgabor	return ((MB_CUR_MAX == 1) ? bws->len : SIZEOF_WCHAR_STRING(bws->len));
160235267Sgabor}
161235267Sgabor
162235267Sgaborsize_t
163235267Sgaborbws_memsize(const struct bwstring *bws)
164235267Sgabor{
165235267Sgabor
166235267Sgabor	return ((MB_CUR_MAX == 1) ? (bws->len + 2 + sizeof(struct bwstring)) :
167235267Sgabor	    (SIZEOF_WCHAR_STRING(bws->len + 1) + sizeof(struct bwstring)));
168235267Sgabor}
169235267Sgabor
170235267Sgaborvoid
171235267Sgaborbws_setlen(struct bwstring *bws, size_t newlen)
172235267Sgabor{
173235267Sgabor
174235267Sgabor	if (bws && newlen != bws->len && newlen <= bws->len) {
175235267Sgabor		bws->len = newlen;
176235267Sgabor		if (MB_CUR_MAX == 1)
177235267Sgabor			bws->data.cstr[newlen] = '\0';
178235267Sgabor		else
179235267Sgabor			bws->data.wstr[newlen] = L'\0';
180235267Sgabor	}
181235267Sgabor}
182235267Sgabor
183235267Sgabor/*
184235267Sgabor * Allocate a new binary string of specified size
185235267Sgabor */
186235267Sgaborstruct bwstring *
187235267Sgaborbwsalloc(size_t sz)
188235267Sgabor{
189235267Sgabor	struct bwstring *ret;
190235267Sgabor
191235267Sgabor	if (MB_CUR_MAX == 1)
192235267Sgabor		ret = sort_malloc(sizeof(struct bwstring) + 1 + sz);
193235267Sgabor	else
194235267Sgabor		ret = sort_malloc(sizeof(struct bwstring) +
195235267Sgabor		    SIZEOF_WCHAR_STRING(sz + 1));
196235267Sgabor	ret->len = sz;
197235267Sgabor
198235267Sgabor	if (MB_CUR_MAX == 1)
199235267Sgabor		ret->data.cstr[ret->len] = '\0';
200235267Sgabor	else
201235267Sgabor		ret->data.wstr[ret->len] = L'\0';
202235267Sgabor
203235267Sgabor	return (ret);
204235267Sgabor}
205235267Sgabor
206235267Sgabor/*
207235267Sgabor * Create a copy of binary string.
208235267Sgabor * New string size equals the length of the old string.
209235267Sgabor */
210235267Sgaborstruct bwstring *
211235267Sgaborbwsdup(const struct bwstring *s)
212235267Sgabor{
213235267Sgabor
214235267Sgabor	if (s == NULL)
215235267Sgabor		return (NULL);
216235267Sgabor	else {
217235267Sgabor		struct bwstring *ret = bwsalloc(s->len);
218235267Sgabor
219235267Sgabor		if (MB_CUR_MAX == 1)
220235267Sgabor			memcpy(ret->data.cstr, s->data.cstr, (s->len));
221235267Sgabor		else
222235267Sgabor			memcpy(ret->data.wstr, s->data.wstr,
223235267Sgabor			    SIZEOF_WCHAR_STRING(s->len));
224235267Sgabor
225235267Sgabor		return (ret);
226235267Sgabor	}
227235267Sgabor}
228235267Sgabor
229235267Sgabor/*
230235267Sgabor * Create a new binary string from a raw binary buffer.
231235267Sgabor */
232235267Sgaborstruct bwstring *
233235267Sgaborbwssbdup(const wchar_t *str, size_t len)
234235267Sgabor{
235235267Sgabor
236235267Sgabor	if (str == NULL)
237235267Sgabor		return ((len == 0) ? bwsalloc(0) : NULL);
238235267Sgabor	else {
239235267Sgabor		struct bwstring *ret;
240235267Sgabor
241235267Sgabor		ret = bwsalloc(len);
242235267Sgabor
243235267Sgabor		if (MB_CUR_MAX == 1)
244235267Sgabor			for (size_t i = 0; i < len; ++i)
245235267Sgabor				ret->data.cstr[i] = (unsigned char) str[i];
246235267Sgabor		else
247235267Sgabor			memcpy(ret->data.wstr, str, SIZEOF_WCHAR_STRING(len));
248235267Sgabor
249235267Sgabor		return (ret);
250235267Sgabor	}
251235267Sgabor}
252235267Sgabor
253235267Sgabor/*
254235267Sgabor * Create a new binary string from a raw binary buffer.
255235267Sgabor */
256235267Sgaborstruct bwstring *
257235267Sgaborbwscsbdup(const unsigned char *str, size_t len)
258235267Sgabor{
259235267Sgabor	struct bwstring *ret;
260235267Sgabor
261235267Sgabor	ret = bwsalloc(len);
262235267Sgabor
263235267Sgabor	if (str) {
264235267Sgabor		if (MB_CUR_MAX == 1)
265235267Sgabor			memcpy(ret->data.cstr, str, len);
266235267Sgabor		else {
267235267Sgabor			mbstate_t mbs;
268235267Sgabor			const char *s;
269235267Sgabor			size_t charlen, chars, cptr;
270235267Sgabor
271235267Sgabor			charlen = chars = 0;
272235267Sgabor			cptr = 0;
273235267Sgabor			s = (const char *) str;
274235267Sgabor
275235267Sgabor			memset(&mbs, 0, sizeof(mbs));
276235267Sgabor
277235267Sgabor			while (cptr < len) {
278235267Sgabor				size_t n = MB_CUR_MAX;
279235267Sgabor
280235267Sgabor				if (n > len - cptr)
281235267Sgabor					n = len - cptr;
282235267Sgabor				charlen = mbrlen(s + cptr, n, &mbs);
283235267Sgabor				switch (charlen) {
284235267Sgabor				case 0:
285235267Sgabor					/* FALLTHROUGH */
286235267Sgabor				case (size_t) -1:
287235267Sgabor					/* FALLTHROUGH */
288235267Sgabor				case (size_t) -2:
289235267Sgabor					ret->data.wstr[chars++] =
290235267Sgabor					    (unsigned char) s[cptr];
291235267Sgabor					++cptr;
292235267Sgabor					break;
293235267Sgabor				default:
294235267Sgabor					n = mbrtowc(ret->data.wstr + (chars++),
295235267Sgabor					    s + cptr, charlen, &mbs);
296235267Sgabor					if ((n == (size_t)-1) || (n == (size_t)-2))
297235267Sgabor						/* NOTREACHED */
298235267Sgabor						err(2, "mbrtowc error");
299235267Sgabor					cptr += charlen;
300235267Sgabor				};
301235267Sgabor			}
302235267Sgabor
303235267Sgabor			ret->len = chars;
304235267Sgabor			ret->data.wstr[ret->len] = L'\0';
305235267Sgabor		}
306235267Sgabor	}
307235267Sgabor	return (ret);
308235267Sgabor}
309235267Sgabor
310235267Sgabor/*
311235267Sgabor * De-allocate object memory
312235267Sgabor */
313235267Sgaborvoid
314235267Sgaborbwsfree(const struct bwstring *s)
315235267Sgabor{
316235267Sgabor
317235267Sgabor	if (s)
318235267Sgabor		sort_free(s);
319235267Sgabor}
320235267Sgabor
321235267Sgabor/*
322235267Sgabor * Copy content of src binary string to dst.
323235267Sgabor * If the capacity of the dst string is not sufficient,
324235267Sgabor * then the data is truncated.
325235267Sgabor */
326235267Sgaborsize_t
327235267Sgaborbwscpy(struct bwstring *dst, const struct bwstring *src)
328235267Sgabor{
329235267Sgabor	size_t nums = src->len;
330235267Sgabor
331235267Sgabor	if (nums > dst->len)
332235267Sgabor		nums = dst->len;
333235267Sgabor	dst->len = nums;
334235267Sgabor
335235267Sgabor	if (MB_CUR_MAX == 1) {
336235267Sgabor		memcpy(dst->data.cstr, src->data.cstr, nums);
337235267Sgabor		dst->data.cstr[dst->len] = '\0';
338235267Sgabor	} else {
339235267Sgabor		memcpy(dst->data.wstr, src->data.wstr,
340235267Sgabor		    SIZEOF_WCHAR_STRING(nums + 1));
341235267Sgabor		dst->data.wstr[dst->len] = L'\0';
342235267Sgabor	}
343235267Sgabor
344235267Sgabor	return (nums);
345235267Sgabor}
346235267Sgabor
347235267Sgabor/*
348235267Sgabor * Copy content of src binary string to dst,
349235267Sgabor * with specified number of symbols to be copied.
350235267Sgabor * If the capacity of the dst string is not sufficient,
351235267Sgabor * then the data is truncated.
352235267Sgabor */
353235267Sgaborstruct bwstring *
354235267Sgaborbwsncpy(struct bwstring *dst, const struct bwstring *src, size_t size)
355235267Sgabor{
356235267Sgabor	size_t nums = src->len;
357235267Sgabor
358235267Sgabor	if (nums > dst->len)
359235267Sgabor		nums = dst->len;
360235267Sgabor	if (nums > size)
361235267Sgabor		nums = size;
362235267Sgabor	dst->len = nums;
363235267Sgabor
364235267Sgabor	if (MB_CUR_MAX == 1) {
365235267Sgabor		memcpy(dst->data.cstr, src->data.cstr, nums);
366235267Sgabor		dst->data.cstr[dst->len] = '\0';
367235267Sgabor	} else {
368235267Sgabor		memcpy(dst->data.wstr, src->data.wstr,
369235267Sgabor		    SIZEOF_WCHAR_STRING(nums + 1));
370235267Sgabor		dst->data.wstr[dst->len] = L'\0';
371235267Sgabor	}
372235267Sgabor
373235267Sgabor	return (dst);
374235267Sgabor}
375235267Sgabor
376235267Sgabor/*
377235267Sgabor * Copy content of src binary string to dst,
378235267Sgabor * with specified number of symbols to be copied.
379235267Sgabor * An offset value can be specified, from the start of src string.
380235267Sgabor * If the capacity of the dst string is not sufficient,
381235267Sgabor * then the data is truncated.
382235267Sgabor */
383235267Sgaborstruct bwstring *
384235267Sgaborbwsnocpy(struct bwstring *dst, const struct bwstring *src, size_t offset,
385235267Sgabor    size_t size)
386235267Sgabor{
387235267Sgabor
388235267Sgabor	if (offset >= src->len) {
389235267Sgabor		dst->data.wstr[0] = 0;
390235267Sgabor		dst->len = 0;
391235267Sgabor	} else {
392235267Sgabor		size_t nums = src->len - offset;
393235267Sgabor
394235267Sgabor		if (nums > dst->len)
395235267Sgabor			nums = dst->len;
396235267Sgabor		if (nums > size)
397235267Sgabor			nums = size;
398235267Sgabor		dst->len = nums;
399235267Sgabor		if (MB_CUR_MAX == 1) {
400235267Sgabor			memcpy(dst->data.cstr, src->data.cstr + offset,
401235267Sgabor			    (nums));
402235267Sgabor			dst->data.cstr[dst->len] = '\0';
403235267Sgabor		} else {
404235267Sgabor			memcpy(dst->data.wstr, src->data.wstr + offset,
405235267Sgabor			    SIZEOF_WCHAR_STRING(nums));
406235267Sgabor			dst->data.wstr[dst->len] = L'\0';
407235267Sgabor		}
408235267Sgabor	}
409235267Sgabor	return (dst);
410235267Sgabor}
411235267Sgabor
412235267Sgabor/*
413235267Sgabor * Write binary string to the file.
414235267Sgabor * The output is ended either with '\n' (nl == true)
415235267Sgabor * or '\0' (nl == false).
416235267Sgabor */
417242430Sgaborsize_t
418235267Sgaborbwsfwrite(struct bwstring *bws, FILE *f, bool zero_ended)
419235267Sgabor{
420235267Sgabor
421235267Sgabor	if (MB_CUR_MAX == 1) {
422235267Sgabor		size_t len = bws->len;
423235267Sgabor
424235267Sgabor		if (!zero_ended) {
425235267Sgabor			bws->data.cstr[len] = '\n';
426235267Sgabor
427235267Sgabor			if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
428235267Sgabor				err(2, NULL);
429235267Sgabor
430235267Sgabor			bws->data.cstr[len] = '\0';
431235267Sgabor		} else if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
432235267Sgabor			err(2, NULL);
433235267Sgabor
434235267Sgabor		return (len + 1);
435235267Sgabor
436235267Sgabor	} else {
437235267Sgabor		wchar_t eols;
438242430Sgabor		size_t printed = 0;
439235267Sgabor
440235267Sgabor		eols = zero_ended ? btowc('\0') : btowc('\n');
441235267Sgabor
442242430Sgabor		while (printed < BWSLEN(bws)) {
443235267Sgabor			const wchar_t *s = bws->data.wstr + printed;
444235267Sgabor
445235267Sgabor			if (*s == L'\0') {
446235267Sgabor				int nums;
447235267Sgabor
448235267Sgabor				nums = fwprintf(f, L"%lc", *s);
449235267Sgabor
450235267Sgabor				if (nums != 1)
451235267Sgabor					err(2, NULL);
452235267Sgabor				++printed;
453235267Sgabor			} else {
454235267Sgabor				int nums;
455235267Sgabor
456235267Sgabor				nums = fwprintf(f, L"%ls", s);
457235267Sgabor
458235267Sgabor				if (nums < 1)
459235267Sgabor					err(2, NULL);
460235267Sgabor				printed += nums;
461235267Sgabor			}
462235267Sgabor		}
463235267Sgabor		fwprintf(f, L"%lc", eols);
464235267Sgabor		return (printed + 1);
465235267Sgabor	}
466235267Sgabor}
467235267Sgabor
468235267Sgabor/*
469235267Sgabor * Allocate and read a binary string from file.
470235267Sgabor * The strings are nl-ended or zero-ended, depending on the sort setting.
471235267Sgabor */
472235267Sgaborstruct bwstring *
473235267Sgaborbwsfgetln(FILE *f, size_t *len, bool zero_ended, struct reader_buffer *rb)
474235267Sgabor{
475242430Sgabor	wint_t eols;
476235267Sgabor
477235267Sgabor	eols = zero_ended ? btowc('\0') : btowc('\n');
478235267Sgabor
479235267Sgabor	if (!zero_ended && (MB_CUR_MAX > 1)) {
480235267Sgabor		wchar_t *ret;
481235267Sgabor
482235267Sgabor		ret = fgetwln(f, len);
483235267Sgabor
484235267Sgabor		if (ret == NULL) {
485235267Sgabor			if (!feof(f))
486235267Sgabor				err(2, NULL);
487235267Sgabor			return (NULL);
488235267Sgabor		}
489235267Sgabor		if (*len > 0) {
490242430Sgabor			if (ret[*len - 1] == (wchar_t)eols)
491235267Sgabor				--(*len);
492235267Sgabor		}
493235267Sgabor		return (bwssbdup(ret, *len));
494235267Sgabor
495235987Sgabor	} else if (!zero_ended && (MB_CUR_MAX == 1)) {
496235987Sgabor		char *ret;
497235987Sgabor
498235987Sgabor		ret = fgetln(f, len);
499235987Sgabor
500235987Sgabor		if (ret == NULL) {
501235987Sgabor			if (!feof(f))
502235987Sgabor				err(2, NULL);
503235987Sgabor			return (NULL);
504235987Sgabor		}
505235987Sgabor		if (*len > 0) {
506235987Sgabor			if (ret[*len - 1] == '\n')
507235987Sgabor				--(*len);
508235987Sgabor		}
509242430Sgabor		return (bwscsbdup((unsigned char*)ret, *len));
510235987Sgabor
511235267Sgabor	} else {
512235267Sgabor		*len = 0;
513235267Sgabor
514235267Sgabor		if (feof(f))
515235267Sgabor			return (NULL);
516235267Sgabor
517235267Sgabor		if (2 >= rb->fgetwln_z_buffer_size) {
518235267Sgabor			rb->fgetwln_z_buffer_size += 256;
519235267Sgabor			rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
520235267Sgabor			    sizeof(wchar_t) * rb->fgetwln_z_buffer_size);
521235267Sgabor		}
522235267Sgabor		rb->fgetwln_z_buffer[*len] = 0;
523235267Sgabor
524235267Sgabor		if (MB_CUR_MAX == 1)
525235267Sgabor			while (!feof(f)) {
526242430Sgabor				int c;
527242430Sgabor
528235267Sgabor				c = fgetc(f);
529235267Sgabor
530235267Sgabor				if (c == EOF) {
531235267Sgabor					if (*len == 0)
532235267Sgabor						return (NULL);
533235267Sgabor					goto line_read_done;
534235267Sgabor				}
535235267Sgabor				if (c == eols)
536235267Sgabor					goto line_read_done;
537235267Sgabor
538235267Sgabor				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
539235267Sgabor					rb->fgetwln_z_buffer_size += 256;
540235267Sgabor					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
541235267Sgabor					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
542235267Sgabor				}
543235267Sgabor
544235267Sgabor				rb->fgetwln_z_buffer[*len] = c;
545235267Sgabor				rb->fgetwln_z_buffer[++(*len)] = 0;
546235267Sgabor			}
547235267Sgabor		else
548235267Sgabor			while (!feof(f)) {
549242430Sgabor				wint_t c = 0;
550242430Sgabor
551235267Sgabor				c = fgetwc(f);
552235267Sgabor
553235267Sgabor				if (c == WEOF) {
554235267Sgabor					if (*len == 0)
555235267Sgabor						return (NULL);
556235267Sgabor					goto line_read_done;
557235267Sgabor				}
558235267Sgabor				if (c == eols)
559235267Sgabor					goto line_read_done;
560235267Sgabor
561235267Sgabor				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
562235267Sgabor					rb->fgetwln_z_buffer_size += 256;
563235267Sgabor					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
564235267Sgabor					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
565235267Sgabor				}
566235267Sgabor
567235267Sgabor				rb->fgetwln_z_buffer[*len] = c;
568235267Sgabor				rb->fgetwln_z_buffer[++(*len)] = 0;
569235267Sgabor			}
570235267Sgabor
571235267Sgaborline_read_done:
572235267Sgabor		/* we do not count the last 0 */
573235267Sgabor		return (bwssbdup(rb->fgetwln_z_buffer, *len));
574235267Sgabor	}
575235267Sgabor}
576235267Sgabor
577235267Sgaborint
578235267Sgaborbwsncmp(const struct bwstring *bws1, const struct bwstring *bws2,
579235267Sgabor    size_t offset, size_t len)
580235267Sgabor{
581235267Sgabor	size_t cmp_len, len1, len2;
582235267Sgabor	int res = 0;
583235267Sgabor
584235267Sgabor	cmp_len = 0;
585235267Sgabor	len1 = bws1->len;
586235267Sgabor	len2 = bws2->len;
587235267Sgabor
588235267Sgabor	if (len1 <= offset) {
589235267Sgabor		return ((len2 <= offset) ? 0 : -1);
590235267Sgabor	} else {
591235267Sgabor		if (len2 <= offset)
592235267Sgabor			return (+1);
593235267Sgabor		else {
594235267Sgabor			len1 -= offset;
595235267Sgabor			len2 -= offset;
596235267Sgabor
597235267Sgabor			cmp_len = len1;
598235267Sgabor
599235267Sgabor			if (len2 < cmp_len)
600235267Sgabor				cmp_len = len2;
601235267Sgabor
602235267Sgabor			if (len < cmp_len)
603235267Sgabor				cmp_len = len;
604235267Sgabor
605235267Sgabor			if (MB_CUR_MAX == 1) {
606235267Sgabor				const unsigned char *s1, *s2;
607235267Sgabor
608235267Sgabor				s1 = bws1->data.cstr + offset;
609235267Sgabor				s2 = bws2->data.cstr + offset;
610235267Sgabor
611235267Sgabor				res = memcmp(s1, s2, cmp_len);
612235267Sgabor
613235267Sgabor			} else {
614235267Sgabor				const wchar_t *s1, *s2;
615235267Sgabor
616235267Sgabor				s1 = bws1->data.wstr + offset;
617235267Sgabor				s2 = bws2->data.wstr + offset;
618235267Sgabor
619235267Sgabor				res = memcmp(s1, s2, SIZEOF_WCHAR_STRING(cmp_len));
620235267Sgabor			}
621235267Sgabor		}
622235267Sgabor	}
623235267Sgabor
624235267Sgabor	if (res == 0) {
625235267Sgabor		if (len1 < cmp_len && len1 < len2)
626235267Sgabor			res = -1;
627235267Sgabor		else if (len2 < cmp_len && len2 < len1)
628235267Sgabor			res = +1;
629235267Sgabor	}
630235267Sgabor
631235267Sgabor	return (res);
632235267Sgabor}
633235267Sgabor
634235267Sgaborint
635235267Sgaborbwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
636235267Sgabor{
637235267Sgabor	size_t len1, len2, cmp_len;
638235267Sgabor	int res;
639235267Sgabor
640235267Sgabor	len1 = bws1->len;
641235267Sgabor	len2 = bws2->len;
642235267Sgabor
643235267Sgabor	len1 -= offset;
644235267Sgabor	len2 -= offset;
645235267Sgabor
646235267Sgabor	cmp_len = len1;
647235267Sgabor
648235267Sgabor	if (len2 < cmp_len)
649235267Sgabor		cmp_len = len2;
650235267Sgabor
651235267Sgabor	res = bwsncmp(bws1, bws2, offset, cmp_len);
652235267Sgabor
653235267Sgabor	if (res == 0) {
654235267Sgabor		if( len1 < len2)
655235267Sgabor			res = -1;
656235267Sgabor		else if (len2 < len1)
657235267Sgabor			res = +1;
658235267Sgabor	}
659235267Sgabor
660235267Sgabor	return (res);
661235267Sgabor}
662235267Sgabor
663235267Sgaborint
664235267Sgaborbws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len)
665235267Sgabor{
666235267Sgabor	wchar_t c1, c2;
667235267Sgabor	size_t i = 0;
668235267Sgabor
669235267Sgabor	for (i = 0; i < len; ++i) {
670235267Sgabor		c1 = bws_get_iter_value(iter1);
671235267Sgabor		c2 = bws_get_iter_value(iter2);
672235267Sgabor		if (c1 != c2)
673235267Sgabor			return (c1 - c2);
674235267Sgabor		iter1 = bws_iterator_inc(iter1, 1);
675235267Sgabor		iter2 = bws_iterator_inc(iter2, 1);
676235267Sgabor	}
677235267Sgabor
678235267Sgabor	return (0);
679235267Sgabor}
680235267Sgabor
681235267Sgaborint
682235267Sgaborbwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
683235267Sgabor{
684235267Sgabor	size_t len1, len2;
685235267Sgabor
686235267Sgabor	len1 = bws1->len;
687235267Sgabor	len2 = bws2->len;
688235267Sgabor
689235267Sgabor	if (len1 <= offset)
690235267Sgabor		return ((len2 <= offset) ? 0 : -1);
691235267Sgabor	else {
692235267Sgabor		if (len2 <= offset)
693235267Sgabor			return (+1);
694235267Sgabor		else {
695235267Sgabor			len1 -= offset;
696235267Sgabor			len2 -= offset;
697235267Sgabor
698235267Sgabor			if (MB_CUR_MAX == 1) {
699235267Sgabor				const unsigned char *s1, *s2;
700235267Sgabor
701235267Sgabor				s1 = bws1->data.cstr + offset;
702235267Sgabor				s2 = bws2->data.cstr + offset;
703235267Sgabor
704235267Sgabor				if (byte_sort) {
705235267Sgabor					int res = 0;
706235267Sgabor
707235267Sgabor					if (len1 > len2) {
708235267Sgabor						res = memcmp(s1, s2, len2);
709235267Sgabor						if (!res)
710235267Sgabor							res = +1;
711235267Sgabor					} else if (len1 < len2) {
712235267Sgabor						res = memcmp(s1, s2, len1);
713235267Sgabor						if (!res)
714235267Sgabor							res = -1;
715235267Sgabor					} else
716235267Sgabor						res = memcmp(s1, s2, len1);
717235267Sgabor
718235267Sgabor					return (res);
719235267Sgabor
720235267Sgabor				} else {
721235267Sgabor					int res = 0;
722235267Sgabor					size_t i, maxlen;
723235267Sgabor
724235267Sgabor					i = 0;
725235267Sgabor					maxlen = len1;
726235267Sgabor
727235267Sgabor					if (maxlen > len2)
728235267Sgabor						maxlen = len2;
729235267Sgabor
730235267Sgabor					while (i < maxlen) {
731235267Sgabor						/* goto next non-zero part: */
732235267Sgabor						while ((i < maxlen) &&
733235267Sgabor						    !s1[i] && !s2[i])
734235267Sgabor							++i;
735235267Sgabor
736235267Sgabor						if (i >= maxlen)
737235267Sgabor							break;
738235267Sgabor
739235267Sgabor						if (s1[i] == 0) {
740235267Sgabor							if (s2[i] == 0)
741235267Sgabor								/* NOTREACHED */
742235267Sgabor								err(2, "bwscoll error 01");
743235267Sgabor							else
744235267Sgabor								return (-1);
745235267Sgabor						} else if (s2[i] == 0)
746235267Sgabor							return (+1);
747235267Sgabor
748242430Sgabor						res = strcoll((const char*)(s1 + i), (const char*)(s2 + i));
749235267Sgabor						if (res)
750235267Sgabor							return (res);
751235267Sgabor
752235267Sgabor						while ((i < maxlen) &&
753235267Sgabor						    s1[i] && s2[i])
754235267Sgabor							++i;
755235267Sgabor
756235267Sgabor						if (i >= maxlen)
757235267Sgabor							break;
758235267Sgabor
759235267Sgabor						if (s1[i] == 0) {
760235267Sgabor							if (s2[i] == 0) {
761235267Sgabor								++i;
762235267Sgabor								continue;
763235267Sgabor							} else
764235267Sgabor								return (-1);
765235267Sgabor						} else if (s2[i] == 0)
766235267Sgabor							return (+1);
767235267Sgabor						else
768235267Sgabor							/* NOTREACHED */
769235267Sgabor							err(2, "bwscoll error 02");
770235267Sgabor					}
771235267Sgabor
772235267Sgabor					if (len1 < len2)
773235267Sgabor						return (-1);
774235267Sgabor					else if (len1 > len2)
775235267Sgabor						return (+1);
776235267Sgabor
777235267Sgabor					return (0);
778235267Sgabor				}
779235267Sgabor			} else {
780235267Sgabor				const wchar_t *s1, *s2;
781235267Sgabor				size_t i, maxlen;
782235267Sgabor				int res = 0;
783235267Sgabor
784235267Sgabor				s1 = bws1->data.wstr + offset;
785235267Sgabor				s2 = bws2->data.wstr + offset;
786235267Sgabor
787235267Sgabor				i = 0;
788235267Sgabor				maxlen = len1;
789235267Sgabor
790235267Sgabor				if (maxlen > len2)
791235267Sgabor					maxlen = len2;
792235267Sgabor
793235267Sgabor				while (i < maxlen) {
794235267Sgabor
795235267Sgabor					/* goto next non-zero part: */
796235267Sgabor					while ((i < maxlen) &&
797235267Sgabor					    !s1[i] && !s2[i])
798235267Sgabor						++i;
799235267Sgabor
800235267Sgabor					if (i >= maxlen)
801235267Sgabor						break;
802235267Sgabor
803235267Sgabor					if (s1[i] == 0) {
804235267Sgabor						if (s2[i] == 0)
805235267Sgabor							/* NOTREACHED */
806235267Sgabor							err(2, "bwscoll error 1");
807235267Sgabor						else
808235267Sgabor							return (-1);
809235267Sgabor					} else if (s2[i] == 0)
810235267Sgabor						return (+1);
811235267Sgabor
812235267Sgabor					res = wide_str_coll(s1 + i, s2 + i);
813235267Sgabor					if (res)
814235267Sgabor						return (res);
815235267Sgabor
816235267Sgabor					while ((i < maxlen) && s1[i] && s2[i])
817235267Sgabor						++i;
818235267Sgabor
819235267Sgabor					if (i >= maxlen)
820235267Sgabor						break;
821235267Sgabor
822235267Sgabor					if (s1[i] == 0) {
823235267Sgabor						if (s2[i] == 0) {
824235267Sgabor							++i;
825235267Sgabor							continue;
826235267Sgabor						} else
827235267Sgabor							return (-1);
828235267Sgabor					} else if (s2[i] == 0)
829235267Sgabor						return (+1);
830235267Sgabor					else
831235267Sgabor						/* NOTREACHED */
832235267Sgabor						err(2, "bwscoll error 2");
833235267Sgabor				}
834235267Sgabor
835235267Sgabor				if (len1 < len2)
836235267Sgabor					return (-1);
837235267Sgabor				else if (len1 > len2)
838235267Sgabor					return (+1);
839235267Sgabor
840235267Sgabor				return (0);
841235267Sgabor			}
842235267Sgabor		}
843235267Sgabor	}
844235267Sgabor}
845235267Sgabor
846235267Sgabor/*
847235267Sgabor * Correction of the system API
848235267Sgabor */
849235267Sgabordouble
850235267Sgaborbwstod(struct bwstring *s0, bool *empty)
851235267Sgabor{
852235267Sgabor	double ret = 0;
853235267Sgabor
854235267Sgabor	if (MB_CUR_MAX == 1) {
855235267Sgabor		unsigned char *end, *s;
856235267Sgabor		char *ep;
857235267Sgabor
858235267Sgabor		s = s0->data.cstr;
859235267Sgabor		end = s + s0->len;
860235267Sgabor		ep = NULL;
861235267Sgabor
862235267Sgabor		while (isblank(*s) && s < end)
863235267Sgabor			++s;
864235267Sgabor
865235267Sgabor		if (!isprint(*s)) {
866235267Sgabor			*empty = true;
867235267Sgabor			return (0);
868235267Sgabor		}
869235267Sgabor
870242430Sgabor		ret = strtod((char*)s, &ep);
871235267Sgabor		if ((unsigned char*) ep == s) {
872235267Sgabor			*empty = true;
873235267Sgabor			return (0);
874235267Sgabor		}
875235267Sgabor	} else {
876235267Sgabor		wchar_t *end, *ep, *s;
877235267Sgabor
878235267Sgabor		s = s0->data.wstr;
879235267Sgabor		end = s + s0->len;
880235267Sgabor		ep = NULL;
881235267Sgabor
882235267Sgabor		while (iswblank(*s) && s < end)
883235267Sgabor			++s;
884235267Sgabor
885235267Sgabor		if (!iswprint(*s)) {
886235267Sgabor			*empty = true;
887235267Sgabor			return (0);
888235267Sgabor		}
889235267Sgabor
890235267Sgabor		ret = wcstod(s, &ep);
891235267Sgabor		if (ep == s) {
892235267Sgabor			*empty = true;
893235267Sgabor			return (0);
894235267Sgabor		}
895235267Sgabor	}
896235267Sgabor
897235267Sgabor	*empty = false;
898235267Sgabor	return (ret);
899235267Sgabor}
900235267Sgabor
901235267Sgabor/*
902235267Sgabor * A helper function for monthcoll.  If a line matches
903235267Sgabor * a month name, it returns (number of the month - 1),
904235267Sgabor * while if there is no match, it just return -1.
905235267Sgabor */
906235267Sgabor
907235267Sgaborint
908235267Sgaborbws_month_score(const struct bwstring *s0)
909235267Sgabor{
910235267Sgabor
911235267Sgabor	if (MB_CUR_MAX == 1) {
912235267Sgabor		const unsigned char *end, *s;
913235267Sgabor
914235267Sgabor		s = s0->data.cstr;
915235267Sgabor		end = s + s0->len;
916235267Sgabor
917235267Sgabor		while (isblank(*s) && s < end)
918235267Sgabor			++s;
919235267Sgabor
920235267Sgabor		for (int i = 11; i >= 0; --i) {
921235267Sgabor			if (cmonths[i] &&
922242430Sgabor			    (s == (unsigned char*)strstr((const char*)s, (char*)(cmonths[i]))))
923235267Sgabor				return (i);
924235267Sgabor		}
925235267Sgabor
926235267Sgabor	} else {
927235267Sgabor		const wchar_t *end, *s;
928235267Sgabor
929235267Sgabor		s = s0->data.wstr;
930235267Sgabor		end = s + s0->len;
931235267Sgabor
932235267Sgabor		while (iswblank(*s) && s < end)
933235267Sgabor			++s;
934235267Sgabor
935235267Sgabor		for (int i = 11; i >= 0; --i) {
936235267Sgabor			if (wmonths[i] && (s == wcsstr(s, wmonths[i])))
937235267Sgabor				return (i);
938235267Sgabor		}
939235267Sgabor	}
940235267Sgabor
941235267Sgabor	return (-1);
942235267Sgabor}
943235267Sgabor
944235267Sgabor/*
945235267Sgabor * Rips out leading blanks (-b).
946235267Sgabor */
947235267Sgaborstruct bwstring *
948235267Sgaborignore_leading_blanks(struct bwstring *str)
949235267Sgabor{
950235267Sgabor
951235267Sgabor	if (MB_CUR_MAX == 1) {
952235267Sgabor		unsigned char *dst, *end, *src;
953235267Sgabor
954235267Sgabor		src = str->data.cstr;
955235267Sgabor		dst = src;
956235267Sgabor		end = src + str->len;
957235267Sgabor
958235267Sgabor		while (src < end && isblank(*src))
959235267Sgabor			++src;
960235267Sgabor
961235267Sgabor		if (src != dst) {
962235267Sgabor			size_t newlen;
963235267Sgabor
964235267Sgabor			newlen = BWSLEN(str) - (src - dst);
965235267Sgabor
966235267Sgabor			while (src < end) {
967235267Sgabor				*dst = *src;
968235267Sgabor				++dst;
969235267Sgabor				++src;
970235267Sgabor			}
971235267Sgabor			bws_setlen(str, newlen);
972235267Sgabor		}
973235267Sgabor	} else {
974235267Sgabor		wchar_t *dst, *end, *src;
975235267Sgabor
976235267Sgabor		src = str->data.wstr;
977235267Sgabor		dst = src;
978235267Sgabor		end = src + str->len;
979235267Sgabor
980235267Sgabor		while (src < end && iswblank(*src))
981235267Sgabor			++src;
982235267Sgabor
983235267Sgabor		if (src != dst) {
984235267Sgabor
985235267Sgabor			size_t newlen = BWSLEN(str) - (src - dst);
986235267Sgabor
987235267Sgabor			while (src < end) {
988235267Sgabor				*dst = *src;
989235267Sgabor				++dst;
990235267Sgabor				++src;
991235267Sgabor			}
992235267Sgabor			bws_setlen(str, newlen);
993235267Sgabor
994235267Sgabor		}
995235267Sgabor	}
996235267Sgabor	return (str);
997235267Sgabor}
998235267Sgabor
999235267Sgabor/*
1000235267Sgabor * Rips out nonprinting characters (-i).
1001235267Sgabor */
1002235267Sgaborstruct bwstring *
1003235267Sgaborignore_nonprinting(struct bwstring *str)
1004235267Sgabor{
1005235267Sgabor	size_t newlen = str->len;
1006235267Sgabor
1007235267Sgabor	if (MB_CUR_MAX == 1) {
1008235267Sgabor		unsigned char *dst, *end, *src;
1009235267Sgabor		unsigned char c;
1010235267Sgabor
1011235267Sgabor		src = str->data.cstr;
1012235267Sgabor		dst = src;
1013235267Sgabor		end = src + str->len;
1014235267Sgabor
1015235267Sgabor		while (src < end) {
1016235267Sgabor			c = *src;
1017235267Sgabor			if (isprint(c)) {
1018235267Sgabor				*dst = c;
1019235267Sgabor				++dst;
1020235267Sgabor				++src;
1021235267Sgabor			} else {
1022235267Sgabor				++src;
1023235267Sgabor				--newlen;
1024235267Sgabor			}
1025235267Sgabor		}
1026235267Sgabor	} else {
1027235267Sgabor		wchar_t *dst, *end, *src;
1028235267Sgabor		wchar_t c;
1029235267Sgabor
1030235267Sgabor		src = str->data.wstr;
1031235267Sgabor		dst = src;
1032235267Sgabor		end = src + str->len;
1033235267Sgabor
1034235267Sgabor		while (src < end) {
1035235267Sgabor			c = *src;
1036235267Sgabor			if (iswprint(c)) {
1037235267Sgabor				*dst = c;
1038235267Sgabor				++dst;
1039235267Sgabor				++src;
1040235267Sgabor			} else {
1041235267Sgabor				++src;
1042235267Sgabor				--newlen;
1043235267Sgabor			}
1044235267Sgabor		}
1045235267Sgabor	}
1046235267Sgabor	bws_setlen(str, newlen);
1047235267Sgabor
1048235267Sgabor	return (str);
1049235267Sgabor}
1050235267Sgabor
1051235267Sgabor/*
1052235267Sgabor * Rips out any characters that are not alphanumeric characters
1053235267Sgabor * nor blanks (-d).
1054235267Sgabor */
1055235267Sgaborstruct bwstring *
1056235267Sgabordictionary_order(struct bwstring *str)
1057235267Sgabor{
1058235267Sgabor	size_t newlen = str->len;
1059235267Sgabor
1060235267Sgabor	if (MB_CUR_MAX == 1) {
1061235267Sgabor		unsigned char *dst, *end, *src;
1062235267Sgabor		unsigned char c;
1063235267Sgabor
1064235267Sgabor		src = str->data.cstr;
1065235267Sgabor		dst = src;
1066235267Sgabor		end = src + str->len;
1067235267Sgabor
1068235267Sgabor		while (src < end) {
1069235267Sgabor			c = *src;
1070235267Sgabor			if (isalnum(c) || isblank(c)) {
1071235267Sgabor				*dst = c;
1072235267Sgabor				++dst;
1073235267Sgabor				++src;
1074235267Sgabor			} else {
1075235267Sgabor				++src;
1076235267Sgabor				--newlen;
1077235267Sgabor			}
1078235267Sgabor		}
1079235267Sgabor	} else {
1080235267Sgabor		wchar_t *dst, *end, *src;
1081235267Sgabor		wchar_t c;
1082235267Sgabor
1083235267Sgabor		src = str->data.wstr;
1084235267Sgabor		dst = src;
1085235267Sgabor		end = src + str->len;
1086235267Sgabor
1087235267Sgabor		while (src < end) {
1088235267Sgabor			c = *src;
1089235267Sgabor			if (iswalnum(c) || iswblank(c)) {
1090235267Sgabor				*dst = c;
1091235267Sgabor				++dst;
1092235267Sgabor				++src;
1093235267Sgabor			} else {
1094235267Sgabor				++src;
1095235267Sgabor				--newlen;
1096235267Sgabor			}
1097235267Sgabor		}
1098235267Sgabor	}
1099235267Sgabor	bws_setlen(str, newlen);
1100235267Sgabor
1101235267Sgabor	return (str);
1102235267Sgabor}
1103235267Sgabor
1104235267Sgabor/*
1105235267Sgabor * Converts string to lower case(-f).
1106235267Sgabor */
1107235267Sgaborstruct bwstring *
1108235267Sgaborignore_case(struct bwstring *str)
1109235267Sgabor{
1110235267Sgabor
1111235267Sgabor	if (MB_CUR_MAX == 1) {
1112235267Sgabor		unsigned char *end, *s;
1113235267Sgabor
1114235267Sgabor		s = str->data.cstr;
1115235267Sgabor		end = s + str->len;
1116235267Sgabor
1117235267Sgabor		while (s < end) {
1118235267Sgabor			*s = toupper(*s);
1119235267Sgabor			++s;
1120235267Sgabor		}
1121235267Sgabor	} else {
1122235267Sgabor		wchar_t *end, *s;
1123235267Sgabor
1124235267Sgabor		s = str->data.wstr;
1125235267Sgabor		end = s + str->len;
1126235267Sgabor
1127235267Sgabor		while (s < end) {
1128235267Sgabor			*s = towupper(*s);
1129235267Sgabor			++s;
1130235267Sgabor		}
1131235267Sgabor	}
1132235267Sgabor	return (str);
1133235267Sgabor}
1134235267Sgabor
1135235267Sgaborvoid
1136235267Sgaborbws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos)
1137235267Sgabor{
1138235267Sgabor
1139235267Sgabor	if (MB_CUR_MAX == 1)
1140235267Sgabor		warnx("%s:%zu: disorder: %s", fn, pos + 1, s->data.cstr);
1141235267Sgabor	else
1142235267Sgabor		warnx("%s:%zu: disorder: %ls", fn, pos + 1, s->data.wstr);
1143235267Sgabor}
1144