bwstring.c revision 235435
1235267Sgabor/*-
2235267Sgabor * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
3235267Sgabor * Copyright (C) 2012 Oleg Moskalenko <oleg.moskalenko@citrix.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: head/usr.bin/sort/bwstring.c 235435 2012-05-14 10:06:49Z gabor $");
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);
72235267Sgabor				len = strlen(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);
98235267Sgabor				len = strlen(tmp);
99235267Sgabor				if (len < 1)
100235267Sgabor					continue;
101235267Sgabor				while (isblank(*tmp))
102235267Sgabor					++tmp;
103235267Sgabor				m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1));
104235267Sgabor				if (mbstowcs(m, 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 */
424235267Sgaborint
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;
445235267Sgabor		int printed = 0;
446235267Sgabor
447235267Sgabor		eols = zero_ended ? btowc('\0') : btowc('\n');
448235267Sgabor
449235267Sgabor		while (printed < (int) 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{
482235267Sgabor	wchar_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) {
497235267Sgabor			if (ret[*len - 1] == eols)
498235267Sgabor				--(*len);
499235267Sgabor		}
500235267Sgabor		return (bwssbdup(ret, *len));
501235267Sgabor
502235267Sgabor	} else {
503235267Sgabor		wchar_t c = 0;
504235267Sgabor
505235267Sgabor		*len = 0;
506235267Sgabor
507235267Sgabor		if (feof(f))
508235267Sgabor			return (NULL);
509235267Sgabor
510235267Sgabor		if (2 >= rb->fgetwln_z_buffer_size) {
511235267Sgabor			rb->fgetwln_z_buffer_size += 256;
512235267Sgabor			rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
513235267Sgabor			    sizeof(wchar_t) * rb->fgetwln_z_buffer_size);
514235267Sgabor		}
515235267Sgabor		rb->fgetwln_z_buffer[*len] = 0;
516235267Sgabor
517235267Sgabor		if (MB_CUR_MAX == 1)
518235267Sgabor			while (!feof(f)) {
519235267Sgabor				c = fgetc(f);
520235267Sgabor
521235267Sgabor				if (c == EOF) {
522235267Sgabor					if (*len == 0)
523235267Sgabor						return (NULL);
524235267Sgabor					goto line_read_done;
525235267Sgabor				}
526235267Sgabor				if (c == eols)
527235267Sgabor					goto line_read_done;
528235267Sgabor
529235267Sgabor				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
530235267Sgabor					rb->fgetwln_z_buffer_size += 256;
531235267Sgabor					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
532235267Sgabor					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
533235267Sgabor				}
534235267Sgabor
535235267Sgabor				rb->fgetwln_z_buffer[*len] = c;
536235267Sgabor				rb->fgetwln_z_buffer[++(*len)] = 0;
537235267Sgabor			}
538235267Sgabor		else
539235267Sgabor			while (!feof(f)) {
540235267Sgabor				c = fgetwc(f);
541235267Sgabor
542235267Sgabor				if (c == WEOF) {
543235267Sgabor					if (*len == 0)
544235267Sgabor						return (NULL);
545235267Sgabor					goto line_read_done;
546235267Sgabor				}
547235267Sgabor				if (c == eols)
548235267Sgabor					goto line_read_done;
549235267Sgabor
550235267Sgabor				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
551235267Sgabor					rb->fgetwln_z_buffer_size += 256;
552235267Sgabor					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
553235267Sgabor					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
554235267Sgabor				}
555235267Sgabor
556235267Sgabor				rb->fgetwln_z_buffer[*len] = c;
557235267Sgabor				rb->fgetwln_z_buffer[++(*len)] = 0;
558235267Sgabor			}
559235267Sgabor
560235267Sgaborline_read_done:
561235267Sgabor		/* we do not count the last 0 */
562235267Sgabor		return (bwssbdup(rb->fgetwln_z_buffer, *len));
563235267Sgabor	}
564235267Sgabor}
565235267Sgabor
566235267Sgaborint
567235267Sgaborbwsncmp(const struct bwstring *bws1, const struct bwstring *bws2,
568235267Sgabor    size_t offset, size_t len)
569235267Sgabor{
570235267Sgabor	size_t cmp_len, len1, len2;
571235267Sgabor	int res = 0;
572235267Sgabor
573235267Sgabor	cmp_len = 0;
574235267Sgabor	len1 = bws1->len;
575235267Sgabor	len2 = bws2->len;
576235267Sgabor
577235267Sgabor	if (len1 <= offset) {
578235267Sgabor		return ((len2 <= offset) ? 0 : -1);
579235267Sgabor	} else {
580235267Sgabor		if (len2 <= offset)
581235267Sgabor			return (+1);
582235267Sgabor		else {
583235267Sgabor			len1 -= offset;
584235267Sgabor			len2 -= offset;
585235267Sgabor
586235267Sgabor			cmp_len = len1;
587235267Sgabor
588235267Sgabor			if (len2 < cmp_len)
589235267Sgabor				cmp_len = len2;
590235267Sgabor
591235267Sgabor			if (len < cmp_len)
592235267Sgabor				cmp_len = len;
593235267Sgabor
594235267Sgabor			if (MB_CUR_MAX == 1) {
595235267Sgabor				const unsigned char *s1, *s2;
596235267Sgabor
597235267Sgabor				s1 = bws1->data.cstr + offset;
598235267Sgabor				s2 = bws2->data.cstr + offset;
599235267Sgabor
600235267Sgabor				res = memcmp(s1, s2, cmp_len);
601235267Sgabor
602235267Sgabor			} else {
603235267Sgabor				const wchar_t *s1, *s2;
604235267Sgabor
605235267Sgabor				s1 = bws1->data.wstr + offset;
606235267Sgabor				s2 = bws2->data.wstr + offset;
607235267Sgabor
608235267Sgabor				res = memcmp(s1, s2, SIZEOF_WCHAR_STRING(cmp_len));
609235267Sgabor			}
610235267Sgabor		}
611235267Sgabor	}
612235267Sgabor
613235267Sgabor	if (res == 0) {
614235267Sgabor		if (len1 < cmp_len && len1 < len2)
615235267Sgabor			res = -1;
616235267Sgabor		else if (len2 < cmp_len && len2 < len1)
617235267Sgabor			res = +1;
618235267Sgabor	}
619235267Sgabor
620235267Sgabor	return (res);
621235267Sgabor}
622235267Sgabor
623235267Sgaborint
624235267Sgaborbwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
625235267Sgabor{
626235267Sgabor	size_t len1, len2, cmp_len;
627235267Sgabor	int res;
628235267Sgabor
629235267Sgabor	len1 = bws1->len;
630235267Sgabor	len2 = bws2->len;
631235267Sgabor
632235267Sgabor	len1 -= offset;
633235267Sgabor	len2 -= offset;
634235267Sgabor
635235267Sgabor	cmp_len = len1;
636235267Sgabor
637235267Sgabor	if (len2 < cmp_len)
638235267Sgabor		cmp_len = len2;
639235267Sgabor
640235267Sgabor	res = bwsncmp(bws1, bws2, offset, cmp_len);
641235267Sgabor
642235267Sgabor	if (res == 0) {
643235267Sgabor		if( len1 < len2)
644235267Sgabor			res = -1;
645235267Sgabor		else if (len2 < len1)
646235267Sgabor			res = +1;
647235267Sgabor	}
648235267Sgabor
649235267Sgabor	return (res);
650235267Sgabor}
651235267Sgabor
652235267Sgaborint
653235267Sgaborbws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len)
654235267Sgabor{
655235267Sgabor	wchar_t c1, c2;
656235267Sgabor	size_t i = 0;
657235267Sgabor
658235267Sgabor	for (i = 0; i < len; ++i) {
659235267Sgabor		c1 = bws_get_iter_value(iter1);
660235267Sgabor		c2 = bws_get_iter_value(iter2);
661235267Sgabor		if (c1 != c2)
662235267Sgabor			return (c1 - c2);
663235267Sgabor		iter1 = bws_iterator_inc(iter1, 1);
664235267Sgabor		iter2 = bws_iterator_inc(iter2, 1);
665235267Sgabor	}
666235267Sgabor
667235267Sgabor	return (0);
668235267Sgabor}
669235267Sgabor
670235267Sgaborint
671235267Sgaborbwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
672235267Sgabor{
673235267Sgabor	size_t len1, len2;
674235267Sgabor
675235267Sgabor	len1 = bws1->len;
676235267Sgabor	len2 = bws2->len;
677235267Sgabor
678235267Sgabor	if (len1 <= offset)
679235267Sgabor		return ((len2 <= offset) ? 0 : -1);
680235267Sgabor	else {
681235267Sgabor		if (len2 <= offset)
682235267Sgabor			return (+1);
683235267Sgabor		else {
684235267Sgabor			len1 -= offset;
685235267Sgabor			len2 -= offset;
686235267Sgabor
687235267Sgabor			if (MB_CUR_MAX == 1) {
688235267Sgabor				const unsigned char *s1, *s2;
689235267Sgabor
690235267Sgabor				s1 = bws1->data.cstr + offset;
691235267Sgabor				s2 = bws2->data.cstr + offset;
692235267Sgabor
693235267Sgabor				if (byte_sort) {
694235267Sgabor					int res = 0;
695235267Sgabor
696235267Sgabor					if (len1 > len2) {
697235267Sgabor						res = memcmp(s1, s2, len2);
698235267Sgabor						if (!res)
699235267Sgabor							res = +1;
700235267Sgabor					} else if (len1 < len2) {
701235267Sgabor						res = memcmp(s1, s2, len1);
702235267Sgabor						if (!res)
703235267Sgabor							res = -1;
704235267Sgabor					} else
705235267Sgabor						res = memcmp(s1, s2, len1);
706235267Sgabor
707235267Sgabor					return (res);
708235267Sgabor
709235267Sgabor				} else {
710235267Sgabor					int res = 0;
711235267Sgabor					size_t i, maxlen;
712235267Sgabor
713235267Sgabor					i = 0;
714235267Sgabor					maxlen = len1;
715235267Sgabor
716235267Sgabor					if (maxlen > len2)
717235267Sgabor						maxlen = len2;
718235267Sgabor
719235267Sgabor					while (i < maxlen) {
720235267Sgabor						/* goto next non-zero part: */
721235267Sgabor						while ((i < maxlen) &&
722235267Sgabor						    !s1[i] && !s2[i])
723235267Sgabor							++i;
724235267Sgabor
725235267Sgabor						if (i >= maxlen)
726235267Sgabor							break;
727235267Sgabor
728235267Sgabor						if (s1[i] == 0) {
729235267Sgabor							if (s2[i] == 0)
730235267Sgabor								/* NOTREACHED */
731235267Sgabor								err(2, "bwscoll error 01");
732235267Sgabor							else
733235267Sgabor								return (-1);
734235267Sgabor						} else if (s2[i] == 0)
735235267Sgabor							return (+1);
736235267Sgabor
737235267Sgabor						res = strcoll(s1 + i, s2 + i);
738235267Sgabor						if (res)
739235267Sgabor							return (res);
740235267Sgabor
741235267Sgabor						while ((i < maxlen) &&
742235267Sgabor						    s1[i] && s2[i])
743235267Sgabor							++i;
744235267Sgabor
745235267Sgabor						if (i >= maxlen)
746235267Sgabor							break;
747235267Sgabor
748235267Sgabor						if (s1[i] == 0) {
749235267Sgabor							if (s2[i] == 0) {
750235267Sgabor								++i;
751235267Sgabor								continue;
752235267Sgabor							} else
753235267Sgabor								return (-1);
754235267Sgabor						} else if (s2[i] == 0)
755235267Sgabor							return (+1);
756235267Sgabor						else
757235267Sgabor							/* NOTREACHED */
758235267Sgabor							err(2, "bwscoll error 02");
759235267Sgabor					}
760235267Sgabor
761235267Sgabor					if (len1 < len2)
762235267Sgabor						return (-1);
763235267Sgabor					else if (len1 > len2)
764235267Sgabor						return (+1);
765235267Sgabor
766235267Sgabor					return (0);
767235267Sgabor				}
768235267Sgabor			} else {
769235267Sgabor				const wchar_t *s1, *s2;
770235267Sgabor				size_t i, maxlen;
771235267Sgabor				int res = 0;
772235267Sgabor
773235267Sgabor				s1 = bws1->data.wstr + offset;
774235267Sgabor				s2 = bws2->data.wstr + offset;
775235267Sgabor
776235267Sgabor				i = 0;
777235267Sgabor				maxlen = len1;
778235267Sgabor
779235267Sgabor				if (maxlen > len2)
780235267Sgabor					maxlen = len2;
781235267Sgabor
782235267Sgabor				while (i < maxlen) {
783235267Sgabor
784235267Sgabor					/* goto next non-zero part: */
785235267Sgabor					while ((i < maxlen) &&
786235267Sgabor					    !s1[i] && !s2[i])
787235267Sgabor						++i;
788235267Sgabor
789235267Sgabor					if (i >= maxlen)
790235267Sgabor						break;
791235267Sgabor
792235267Sgabor					if (s1[i] == 0) {
793235267Sgabor						if (s2[i] == 0)
794235267Sgabor							/* NOTREACHED */
795235267Sgabor							err(2, "bwscoll error 1");
796235267Sgabor						else
797235267Sgabor							return (-1);
798235267Sgabor					} else if (s2[i] == 0)
799235267Sgabor						return (+1);
800235267Sgabor
801235267Sgabor					res = wide_str_coll(s1 + i, s2 + i);
802235267Sgabor					if (res)
803235267Sgabor						return (res);
804235267Sgabor
805235267Sgabor					while ((i < maxlen) && s1[i] && s2[i])
806235267Sgabor						++i;
807235267Sgabor
808235267Sgabor					if (i >= maxlen)
809235267Sgabor						break;
810235267Sgabor
811235267Sgabor					if (s1[i] == 0) {
812235267Sgabor						if (s2[i] == 0) {
813235267Sgabor							++i;
814235267Sgabor							continue;
815235267Sgabor						} else
816235267Sgabor							return (-1);
817235267Sgabor					} else if (s2[i] == 0)
818235267Sgabor						return (+1);
819235267Sgabor					else
820235267Sgabor						/* NOTREACHED */
821235267Sgabor						err(2, "bwscoll error 2");
822235267Sgabor				}
823235267Sgabor
824235267Sgabor				if (len1 < len2)
825235267Sgabor					return (-1);
826235267Sgabor				else if (len1 > len2)
827235267Sgabor					return (+1);
828235267Sgabor
829235267Sgabor				return (0);
830235267Sgabor			}
831235267Sgabor		}
832235267Sgabor	}
833235267Sgabor}
834235267Sgabor
835235267Sgabor/*
836235267Sgabor * Correction of the system API
837235267Sgabor */
838235267Sgabordouble
839235267Sgaborbwstod(struct bwstring *s0, bool *empty)
840235267Sgabor{
841235267Sgabor	double ret = 0;
842235267Sgabor
843235267Sgabor	if (MB_CUR_MAX == 1) {
844235267Sgabor		unsigned char *end, *s;
845235267Sgabor		char *ep;
846235267Sgabor
847235267Sgabor		s = s0->data.cstr;
848235267Sgabor		end = s + s0->len;
849235267Sgabor		ep = NULL;
850235267Sgabor
851235267Sgabor		while (isblank(*s) && s < end)
852235267Sgabor			++s;
853235267Sgabor
854235267Sgabor		if (!isprint(*s)) {
855235267Sgabor			*empty = true;
856235267Sgabor			return (0);
857235267Sgabor		}
858235267Sgabor
859235267Sgabor		ret = strtod(s, &ep);
860235267Sgabor		if ((unsigned char*) ep == s) {
861235267Sgabor			*empty = true;
862235267Sgabor			return (0);
863235267Sgabor		}
864235267Sgabor	} else {
865235267Sgabor		wchar_t *end, *ep, *s;
866235267Sgabor
867235267Sgabor		s = s0->data.wstr;
868235267Sgabor		end = s + s0->len;
869235267Sgabor		ep = NULL;
870235267Sgabor
871235267Sgabor		while (iswblank(*s) && s < end)
872235267Sgabor			++s;
873235267Sgabor
874235267Sgabor		if (!iswprint(*s)) {
875235267Sgabor			*empty = true;
876235267Sgabor			return (0);
877235267Sgabor		}
878235267Sgabor
879235267Sgabor		ret = wcstod(s, &ep);
880235267Sgabor		if (ep == s) {
881235267Sgabor			*empty = true;
882235267Sgabor			return (0);
883235267Sgabor		}
884235267Sgabor	}
885235267Sgabor
886235267Sgabor	*empty = false;
887235267Sgabor	return (ret);
888235267Sgabor}
889235267Sgabor
890235267Sgabor/*
891235267Sgabor * A helper function for monthcoll.  If a line matches
892235267Sgabor * a month name, it returns (number of the month - 1),
893235267Sgabor * while if there is no match, it just return -1.
894235267Sgabor */
895235267Sgabor
896235267Sgaborint
897235267Sgaborbws_month_score(const struct bwstring *s0)
898235267Sgabor{
899235267Sgabor
900235267Sgabor	if (MB_CUR_MAX == 1) {
901235267Sgabor		const unsigned char *end, *s;
902235267Sgabor		size_t len;
903235267Sgabor
904235267Sgabor		s = s0->data.cstr;
905235267Sgabor		end = s + s0->len;
906235267Sgabor
907235267Sgabor		while (isblank(*s) && s < end)
908235267Sgabor			++s;
909235267Sgabor
910235267Sgabor		len = strlen(s);
911235267Sgabor
912235267Sgabor		for (int i = 11; i >= 0; --i) {
913235267Sgabor			if (cmonths[i] &&
914235267Sgabor			    (s == (unsigned char*)strstr(s, cmonths[i])))
915235267Sgabor				return (i);
916235267Sgabor		}
917235267Sgabor
918235267Sgabor	} else {
919235267Sgabor		const wchar_t *end, *s;
920235267Sgabor		size_t len;
921235267Sgabor
922235267Sgabor		s = s0->data.wstr;
923235267Sgabor		end = s + s0->len;
924235267Sgabor
925235267Sgabor		while (iswblank(*s) && s < end)
926235267Sgabor			++s;
927235267Sgabor
928235267Sgabor		len = wcslen(s);
929235267Sgabor
930235267Sgabor		for (int i = 11; i >= 0; --i) {
931235267Sgabor			if (wmonths[i] && (s == wcsstr(s, wmonths[i])))
932235267Sgabor				return (i);
933235267Sgabor		}
934235267Sgabor	}
935235267Sgabor
936235267Sgabor	return (-1);
937235267Sgabor}
938235267Sgabor
939235267Sgabor/*
940235267Sgabor * Rips out leading blanks (-b).
941235267Sgabor */
942235267Sgaborstruct bwstring *
943235267Sgaborignore_leading_blanks(struct bwstring *str)
944235267Sgabor{
945235267Sgabor
946235267Sgabor	if (MB_CUR_MAX == 1) {
947235267Sgabor		unsigned char *dst, *end, *src;
948235267Sgabor
949235267Sgabor		src = str->data.cstr;
950235267Sgabor		dst = src;
951235267Sgabor		end = src + str->len;
952235267Sgabor
953235267Sgabor		while (src < end && isblank(*src))
954235267Sgabor			++src;
955235267Sgabor
956235267Sgabor		if (src != dst) {
957235267Sgabor			size_t newlen;
958235267Sgabor
959235267Sgabor			newlen = BWSLEN(str) - (src - dst);
960235267Sgabor
961235267Sgabor			while (src < end) {
962235267Sgabor				*dst = *src;
963235267Sgabor				++dst;
964235267Sgabor				++src;
965235267Sgabor			}
966235267Sgabor			bws_setlen(str, newlen);
967235267Sgabor		}
968235267Sgabor	} else {
969235267Sgabor		wchar_t *dst, *end, *src;
970235267Sgabor
971235267Sgabor		src = str->data.wstr;
972235267Sgabor		dst = src;
973235267Sgabor		end = src + str->len;
974235267Sgabor
975235267Sgabor		while (src < end && iswblank(*src))
976235267Sgabor			++src;
977235267Sgabor
978235267Sgabor		if (src != dst) {
979235267Sgabor
980235267Sgabor			size_t newlen = BWSLEN(str) - (src - dst);
981235267Sgabor
982235267Sgabor			while (src < end) {
983235267Sgabor				*dst = *src;
984235267Sgabor				++dst;
985235267Sgabor				++src;
986235267Sgabor			}
987235267Sgabor			bws_setlen(str, newlen);
988235267Sgabor
989235267Sgabor		}
990235267Sgabor	}
991235267Sgabor	return (str);
992235267Sgabor}
993235267Sgabor
994235267Sgabor/*
995235267Sgabor * Rips out nonprinting characters (-i).
996235267Sgabor */
997235267Sgaborstruct bwstring *
998235267Sgaborignore_nonprinting(struct bwstring *str)
999235267Sgabor{
1000235267Sgabor	size_t newlen = str->len;
1001235267Sgabor
1002235267Sgabor	if (MB_CUR_MAX == 1) {
1003235267Sgabor		unsigned char *dst, *end, *src;
1004235267Sgabor		unsigned char c;
1005235267Sgabor
1006235267Sgabor		src = str->data.cstr;
1007235267Sgabor		dst = src;
1008235267Sgabor		end = src + str->len;
1009235267Sgabor
1010235267Sgabor		while (src < end) {
1011235267Sgabor			c = *src;
1012235267Sgabor			if (isprint(c)) {
1013235267Sgabor				*dst = c;
1014235267Sgabor				++dst;
1015235267Sgabor				++src;
1016235267Sgabor			} else {
1017235267Sgabor				++src;
1018235267Sgabor				--newlen;
1019235267Sgabor			}
1020235267Sgabor		}
1021235267Sgabor	} else {
1022235267Sgabor		wchar_t *dst, *end, *src;
1023235267Sgabor		wchar_t c;
1024235267Sgabor
1025235267Sgabor		src = str->data.wstr;
1026235267Sgabor		dst = src;
1027235267Sgabor		end = src + str->len;
1028235267Sgabor
1029235267Sgabor		while (src < end) {
1030235267Sgabor			c = *src;
1031235267Sgabor			if (iswprint(c)) {
1032235267Sgabor				*dst = c;
1033235267Sgabor				++dst;
1034235267Sgabor				++src;
1035235267Sgabor			} else {
1036235267Sgabor				++src;
1037235267Sgabor				--newlen;
1038235267Sgabor			}
1039235267Sgabor		}
1040235267Sgabor	}
1041235267Sgabor	bws_setlen(str, newlen);
1042235267Sgabor
1043235267Sgabor	return (str);
1044235267Sgabor}
1045235267Sgabor
1046235267Sgabor/*
1047235267Sgabor * Rips out any characters that are not alphanumeric characters
1048235267Sgabor * nor blanks (-d).
1049235267Sgabor */
1050235267Sgaborstruct bwstring *
1051235267Sgabordictionary_order(struct bwstring *str)
1052235267Sgabor{
1053235267Sgabor	size_t newlen = str->len;
1054235267Sgabor
1055235267Sgabor	if (MB_CUR_MAX == 1) {
1056235267Sgabor		unsigned char *dst, *end, *src;
1057235267Sgabor		unsigned char c;
1058235267Sgabor
1059235267Sgabor		src = str->data.cstr;
1060235267Sgabor		dst = src;
1061235267Sgabor		end = src + str->len;
1062235267Sgabor
1063235267Sgabor		while (src < end) {
1064235267Sgabor			c = *src;
1065235267Sgabor			if (isalnum(c) || isblank(c)) {
1066235267Sgabor				*dst = c;
1067235267Sgabor				++dst;
1068235267Sgabor				++src;
1069235267Sgabor			} else {
1070235267Sgabor				++src;
1071235267Sgabor				--newlen;
1072235267Sgabor			}
1073235267Sgabor		}
1074235267Sgabor	} else {
1075235267Sgabor		wchar_t *dst, *end, *src;
1076235267Sgabor		wchar_t c;
1077235267Sgabor
1078235267Sgabor		src = str->data.wstr;
1079235267Sgabor		dst = src;
1080235267Sgabor		end = src + str->len;
1081235267Sgabor
1082235267Sgabor		while (src < end) {
1083235267Sgabor			c = *src;
1084235267Sgabor			if (iswalnum(c) || iswblank(c)) {
1085235267Sgabor				*dst = c;
1086235267Sgabor				++dst;
1087235267Sgabor				++src;
1088235267Sgabor			} else {
1089235267Sgabor				++src;
1090235267Sgabor				--newlen;
1091235267Sgabor			}
1092235267Sgabor		}
1093235267Sgabor	}
1094235267Sgabor	bws_setlen(str, newlen);
1095235267Sgabor
1096235267Sgabor	return (str);
1097235267Sgabor}
1098235267Sgabor
1099235267Sgabor/*
1100235267Sgabor * Converts string to lower case(-f).
1101235267Sgabor */
1102235267Sgaborstruct bwstring *
1103235267Sgaborignore_case(struct bwstring *str)
1104235267Sgabor{
1105235267Sgabor
1106235267Sgabor	if (MB_CUR_MAX == 1) {
1107235267Sgabor		unsigned char *end, *s;
1108235267Sgabor
1109235267Sgabor		s = str->data.cstr;
1110235267Sgabor		end = s + str->len;
1111235267Sgabor
1112235267Sgabor		while (s < end) {
1113235267Sgabor			*s = toupper(*s);
1114235267Sgabor			++s;
1115235267Sgabor		}
1116235267Sgabor	} else {
1117235267Sgabor		wchar_t *end, *s;
1118235267Sgabor
1119235267Sgabor		s = str->data.wstr;
1120235267Sgabor		end = s + str->len;
1121235267Sgabor
1122235267Sgabor		while (s < end) {
1123235267Sgabor			*s = towupper(*s);
1124235267Sgabor			++s;
1125235267Sgabor		}
1126235267Sgabor	}
1127235267Sgabor	return (str);
1128235267Sgabor}
1129235267Sgabor
1130235267Sgaborvoid
1131235267Sgaborbws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos)
1132235267Sgabor{
1133235267Sgabor
1134235267Sgabor	if (MB_CUR_MAX == 1)
1135235267Sgabor		warnx("%s:%zu: disorder: %s", fn, pos + 1, s->data.cstr);
1136235267Sgabor	else
1137235267Sgabor		warnx("%s:%zu: disorder: %ls", fn, pos + 1, s->data.wstr);
1138235267Sgabor}
1139