1128059Smarkm/*-
2255362Smarkm * Copyright (C) 2009 Gabor Kovesdan <gabor@FreeBSD.org>
3136338Srwatson * Copyright (C) 2012 Oleg Moskalenko <mom040267@gmail.com>
4128059Smarkm * All rights reserved.
5128059Smarkm *
6128059Smarkm * Redistribution and use in source and binary forms, with or without
7128059Smarkm * modification, are permitted provided that the following conditions
8128059Smarkm * are met:
9128059Smarkm * 1. Redistributions of source code must retain the above copyright
10128059Smarkm *    notice, this list of conditions and the following disclaimer.
11128059Smarkm * 2. Redistributions in binary form must reproduce the above copyright
12128059Smarkm *    notice, this list of conditions and the following disclaimer in the
13128059Smarkm *    documentation and/or other materials provided with the distribution.
14128059Smarkm *
15128059Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16128059Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17128059Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18128059Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19128059Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20128059Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21128059Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22128059Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23128059Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24128059Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25128059Smarkm * SUCH DAMAGE.
26128059Smarkm */
27128059Smarkm
28128059Smarkm#include <sys/cdefs.h>
29256381Smarkm__FBSDID("$FreeBSD$");
30256381Smarkm
31256381Smarkm#include <ctype.h>
32256381Smarkm#include <errno.h>
33256381Smarkm#include <err.h>
34256381Smarkm#include <langinfo.h>
35255362Smarkm#include <math.h>
36256381Smarkm#include <stdlib.h>
37256381Smarkm#include <string.h>
38256381Smarkm#include <wchar.h>
39255362Smarkm#include <wctype.h>
40128059Smarkm
41128059Smarkm#include "bwstring.h"
42128059Smarkm#include "sort.h"
43128059Smarkm
44128059Smarkmbool byte_sort;
45128059Smarkm
46128059Smarkmstatic wchar_t **wmonths;
47128059Smarkmstatic unsigned char **cmonths;
48128059Smarkm
49254147Sobrien/* initialise months */
50128059Smarkm
51128059Smarkmvoid
52128059Smarkminitialise_months(void)
53128059Smarkm{
54128059Smarkm	const nl_item item[12] = { ABMON_1, ABMON_2, ABMON_3, ABMON_4,
55128059Smarkm	    ABMON_5, ABMON_6, ABMON_7, ABMON_8, ABMON_9, ABMON_10,
56128059Smarkm	    ABMON_11, ABMON_12 };
57128059Smarkm	unsigned char *tmp;
58128059Smarkm	size_t len;
59128059Smarkm
60128059Smarkm	if (MB_CUR_MAX == 1) {
61128059Smarkm		if (cmonths == NULL) {
62128059Smarkm			unsigned char *m;
63256381Smarkm
64256381Smarkm			cmonths = sort_malloc(sizeof(unsigned char*) * 12);
65256381Smarkm			for (int i = 0; i < 12; i++) {
66255362Smarkm				cmonths[i] = NULL;
67255362Smarkm				tmp = (unsigned char *) nl_langinfo(item[i]);
68256381Smarkm				if (tmp == NULL)
69255362Smarkm					continue;
70255362Smarkm				if (debug_sort)
71128059Smarkm					printf("month[%d]=%s\n", i, tmp);
72128059Smarkm				len = strlen((char*)tmp);
73255362Smarkm				if (len < 1)
74255362Smarkm					continue;
75255362Smarkm				while (isblank(*tmp))
76128059Smarkm					++tmp;
77256381Smarkm				m = sort_malloc(len + 1);
78255362Smarkm				memcpy(m, tmp, len + 1);
79128059Smarkm				m[len] = '\0';
80255362Smarkm				for (unsigned int j = 0; j < len; j++)
81255362Smarkm					m[j] = toupper(m[j]);
82255362Smarkm				cmonths[i] = m;
83128059Smarkm			}
84255362Smarkm		}
85255362Smarkm
86256381Smarkm	} else {
87256414Smarkm		if (wmonths == NULL) {
88128059Smarkm			wchar_t *m;
89255362Smarkm
90255362Smarkm			wmonths = sort_malloc(sizeof(wchar_t *) * 12);
91255362Smarkm			for (int i = 0; i < 12; i++) {
92128059Smarkm				wmonths[i] = NULL;
93256381Smarkm				tmp = (unsigned char *) nl_langinfo(item[i]);
94255362Smarkm				if (tmp == NULL)
95255362Smarkm					continue;
96255362Smarkm				if (debug_sort)
97255362Smarkm					printf("month[%d]=%s\n", i, tmp);
98255362Smarkm				len = strlen((char*)tmp);
99255362Smarkm				if (len < 1)
100255362Smarkm					continue;
101255362Smarkm				while (isblank(*tmp))
102256381Smarkm					++tmp;
103256414Smarkm				m = sort_malloc(SIZEOF_WCHAR_STRING(len + 1));
104128059Smarkm				if (mbstowcs(m, (char*)tmp, len) == ((size_t) -1))
105255362Smarkm					continue;
106255362Smarkm				m[len] = L'\0';
107255362Smarkm				for (unsigned int j = 0; j < len; j++)
108128059Smarkm					m[j] = towupper(m[j]);
109256381Smarkm				wmonths[i] = m;
110256381Smarkm			}
111128059Smarkm		}
112254147Sobrien	}
113128059Smarkm}
114128059Smarkm
115128059Smarkm/*
116128059Smarkm * Compare two wide-character strings
117128059Smarkm */
118128059Smarkmstatic int
119128059Smarkmwide_str_coll(const wchar_t *s1, const wchar_t *s2)
120256381Smarkm{
121128059Smarkm	int ret = 0;
122128059Smarkm
123128059Smarkm	errno = 0;
124255362Smarkm	ret = wcscoll(s1, s2);
125128059Smarkm	if (errno == EILSEQ) {
126254147Sobrien		errno = 0;
127128059Smarkm		ret = wcscmp(s1, s2);
128256381Smarkm		if (errno != 0) {
129254147Sobrien			for (size_t i = 0; ; ++i) {
130255362Smarkm				wchar_t c1 = s1[i];
131256381Smarkm				wchar_t c2 = s2[i];
132255362Smarkm				if (c1 == L'\0')
133255362Smarkm					return ((c2 == L'\0') ? 0 : -1);
134128059Smarkm				if (c2 == L'\0')
135170067Srwatson					return (+1);
136254147Sobrien				if (c1 == c2)
137128059Smarkm					continue;
138128059Smarkm				return ((int)(c1 - c2));
139128059Smarkm			}
140170067Srwatson		}
141128059Smarkm	}
142128059Smarkm	return (ret);
143256381Smarkm}
144128059Smarkm
145128059Smarkm/* counterparts of wcs functions */
146170067Srwatson
147128059Smarkmvoid
148128059Smarkmbwsprintf(FILE *f, struct bwstring *bws, const char *prefix, const char *suffix)
149128059Smarkm{
150128059Smarkm
151170067Srwatson	if (MB_CUR_MAX == 1)
152128059Smarkm		fprintf(f, "%s%s%s", prefix, bws->data.cstr, suffix);
153128059Smarkm	else
154128320Smarkm		fprintf(f, "%s%S%s", prefix, bws->data.wstr, suffix);
155128059Smarkm}
156170067Srwatson
157128059Smarkmconst void* bwsrawdata(const struct bwstring *bws)
158128059Smarkm{
159128320Smarkm
160128059Smarkm	return (&(bws->data));
161170067Srwatson}
162128059Smarkm
163128059Smarkmsize_t bwsrawlen(const struct bwstring *bws)
164256381Smarkm{
165128059Smarkm
166170067Srwatson	return ((MB_CUR_MAX == 1) ? bws->len : SIZEOF_WCHAR_STRING(bws->len));
167128059Smarkm}
168128059Smarkm
169256381Smarkmsize_t
170128059Smarkmbws_memsize(const struct bwstring *bws)
171128059Smarkm{
172255362Smarkm
173128059Smarkm	return ((MB_CUR_MAX == 1) ? (bws->len + 2 + sizeof(struct bwstring)) :
174128059Smarkm	    (SIZEOF_WCHAR_STRING(bws->len + 1) + sizeof(struct bwstring)));
175255362Smarkm}
176255362Smarkm
177128059Smarkmvoid
178128059Smarkmbws_setlen(struct bwstring *bws, size_t newlen)
179128059Smarkm{
180255362Smarkm
181128059Smarkm	if (bws && newlen != bws->len && newlen <= bws->len) {
182128059Smarkm		bws->len = newlen;
183255362Smarkm		if (MB_CUR_MAX == 1)
184128059Smarkm			bws->data.cstr[newlen] = '\0';
185128059Smarkm		else
186128059Smarkm			bws->data.wstr[newlen] = L'\0';
187128059Smarkm	}
188128059Smarkm}
189157815Sjhb
190128059Smarkm/*
191256381Smarkm * Allocate a new binary string of specified size
192128059Smarkm */
193255362Smarkmstruct bwstring *
194256381Smarkmbwsalloc(size_t sz)
195255362Smarkm{
196255362Smarkm	struct bwstring *ret;
197128059Smarkm
198128059Smarkm	if (MB_CUR_MAX == 1)
199128059Smarkm		ret = sort_malloc(sizeof(struct bwstring) + 1 + sz);
200128059Smarkm	else
201128059Smarkm		ret = sort_malloc(sizeof(struct bwstring) +
202255362Smarkm		    SIZEOF_WCHAR_STRING(sz + 1));
203128059Smarkm	ret->len = sz;
204255362Smarkm
205255362Smarkm	if (MB_CUR_MAX == 1)
206255362Smarkm		ret->data.cstr[ret->len] = '\0';
207256381Smarkm	else
208256381Smarkm		ret->data.wstr[ret->len] = L'\0';
209128059Smarkm
210256381Smarkm	return (ret);
211249631Sache}
212249631Sache
213128059Smarkm/*
214153575Sps * Create a copy of binary string.
215153575Sps * New string size equals the length of the old string.
216255362Smarkm */
217153575Spsstruct bwstring *
218153575Spsbwsdup(const struct bwstring *s)
219256381Smarkm{
220153575Sps
221153575Sps	if (s == NULL)
222255362Smarkm		return (NULL);
223153575Sps	else {
224153575Sps		struct bwstring *ret = bwsalloc(s->len);
225255362Smarkm
226192774Smarkm		if (MB_CUR_MAX == 1)
227153575Sps			memcpy(ret->data.cstr, s->data.cstr, (s->len));
228256381Smarkm		else
229153575Sps			memcpy(ret->data.wstr, s->data.wstr,
230153575Sps			    SIZEOF_WCHAR_STRING(s->len));
231153575Sps
232255362Smarkm		return (ret);
233153575Sps	}
234153575Sps}
235153575Sps
236153575Sps/*
237153575Sps * Create a new binary string from a raw binary buffer.
238153575Sps */
239255362Smarkmstruct bwstring *
240153575Spsbwssbdup(const wchar_t *str, size_t len)
241153575Sps{
242153575Sps
243256381Smarkm	if (str == NULL)
244255362Smarkm		return ((len == 0) ? bwsalloc(0) : NULL);
245153575Sps	else {
246153575Sps		struct bwstring *ret;
247153575Sps
248153575Sps		ret = bwsalloc(len);
249153575Sps
250153575Sps		if (MB_CUR_MAX == 1)
251256381Smarkm			for (size_t i = 0; i < len; ++i)
252192774Smarkm				ret->data.cstr[i] = (unsigned char) str[i];
253185254Scperciva		else
254185254Scperciva			memcpy(ret->data.wstr, str, SIZEOF_WCHAR_STRING(len));
255185254Scperciva
256255362Smarkm		return (ret);
257185254Scperciva	}
258185254Scperciva}
259185254Scperciva
260185254Scperciva/*
261185254Scperciva * Create a new binary string from a raw binary buffer.
262185254Scperciva */
263256381Smarkmstruct bwstring *
264256381Smarkmbwscsbdup(const unsigned char *str, size_t len)
265185254Scperciva{
266255362Smarkm	struct bwstring *ret;
267256381Smarkm
268256381Smarkm	ret = bwsalloc(len);
269255362Smarkm
270255362Smarkm	if (str) {
271185254Scperciva		if (MB_CUR_MAX == 1)
272254147Sobrien			memcpy(ret->data.cstr, str, len);
273254147Sobrien		else {
274256381Smarkm			mbstate_t mbs;
275254147Sobrien			const char *s;
276254147Sobrien			size_t charlen, chars, cptr;
277254147Sobrien
278254147Sobrien			charlen = chars = 0;
279255362Smarkm			cptr = 0;
280254147Sobrien			s = (const char *) str;
281254147Sobrien
282254147Sobrien			memset(&mbs, 0, sizeof(mbs));
283254147Sobrien
284254147Sobrien			while (cptr < len) {
285254147Sobrien				size_t n = MB_CUR_MAX;
286254147Sobrien
287254147Sobrien				if (n > len - cptr)
288254147Sobrien					n = len - cptr;
289254147Sobrien				charlen = mbrlen(s + cptr, n, &mbs);
290254147Sobrien				switch (charlen) {
291254147Sobrien				case 0:
292255362Smarkm					/* FALLTHROUGH */
293254147Sobrien				case (size_t) -1:
294254147Sobrien					/* FALLTHROUGH */
295254147Sobrien				case (size_t) -2:
296254147Sobrien					ret->data.wstr[chars++] =
297254147Sobrien					    (unsigned char) s[cptr];
298254147Sobrien					++cptr;
299255362Smarkm					break;
300				default:
301					n = mbrtowc(ret->data.wstr + (chars++),
302					    s + cptr, charlen, &mbs);
303					if ((n == (size_t)-1) || (n == (size_t)-2))
304						/* NOTREACHED */
305						err(2, "mbrtowc error");
306					cptr += charlen;
307				};
308			}
309
310			ret->len = chars;
311			ret->data.wstr[ret->len] = L'\0';
312		}
313	}
314	return (ret);
315}
316
317/*
318 * De-allocate object memory
319 */
320void
321bwsfree(const struct bwstring *s)
322{
323
324	if (s)
325		sort_free(s);
326}
327
328/*
329 * Copy content of src binary string to dst.
330 * If the capacity of the dst string is not sufficient,
331 * then the data is truncated.
332 */
333size_t
334bwscpy(struct bwstring *dst, const struct bwstring *src)
335{
336	size_t nums = src->len;
337
338	if (nums > dst->len)
339		nums = dst->len;
340	dst->len = nums;
341
342	if (MB_CUR_MAX == 1) {
343		memcpy(dst->data.cstr, src->data.cstr, nums);
344		dst->data.cstr[dst->len] = '\0';
345	} else {
346		memcpy(dst->data.wstr, src->data.wstr,
347		    SIZEOF_WCHAR_STRING(nums + 1));
348		dst->data.wstr[dst->len] = L'\0';
349	}
350
351	return (nums);
352}
353
354/*
355 * Copy content of src binary string to dst,
356 * with specified number of symbols to be copied.
357 * If the capacity of the dst string is not sufficient,
358 * then the data is truncated.
359 */
360struct bwstring *
361bwsncpy(struct bwstring *dst, const struct bwstring *src, size_t size)
362{
363	size_t nums = src->len;
364
365	if (nums > dst->len)
366		nums = dst->len;
367	if (nums > size)
368		nums = size;
369	dst->len = nums;
370
371	if (MB_CUR_MAX == 1) {
372		memcpy(dst->data.cstr, src->data.cstr, nums);
373		dst->data.cstr[dst->len] = '\0';
374	} else {
375		memcpy(dst->data.wstr, src->data.wstr,
376		    SIZEOF_WCHAR_STRING(nums + 1));
377		dst->data.wstr[dst->len] = L'\0';
378	}
379
380	return (dst);
381}
382
383/*
384 * Copy content of src binary string to dst,
385 * with specified number of symbols to be copied.
386 * An offset value can be specified, from the start of src string.
387 * If the capacity of the dst string is not sufficient,
388 * then the data is truncated.
389 */
390struct bwstring *
391bwsnocpy(struct bwstring *dst, const struct bwstring *src, size_t offset,
392    size_t size)
393{
394
395	if (offset >= src->len) {
396		dst->data.wstr[0] = 0;
397		dst->len = 0;
398	} else {
399		size_t nums = src->len - offset;
400
401		if (nums > dst->len)
402			nums = dst->len;
403		if (nums > size)
404			nums = size;
405		dst->len = nums;
406		if (MB_CUR_MAX == 1) {
407			memcpy(dst->data.cstr, src->data.cstr + offset,
408			    (nums));
409			dst->data.cstr[dst->len] = '\0';
410		} else {
411			memcpy(dst->data.wstr, src->data.wstr + offset,
412			    SIZEOF_WCHAR_STRING(nums));
413			dst->data.wstr[dst->len] = L'\0';
414		}
415	}
416	return (dst);
417}
418
419/*
420 * Write binary string to the file.
421 * The output is ended either with '\n' (nl == true)
422 * or '\0' (nl == false).
423 */
424size_t
425bwsfwrite(struct bwstring *bws, FILE *f, bool zero_ended)
426{
427
428	if (MB_CUR_MAX == 1) {
429		size_t len = bws->len;
430
431		if (!zero_ended) {
432			bws->data.cstr[len] = '\n';
433
434			if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
435				err(2, NULL);
436
437			bws->data.cstr[len] = '\0';
438		} else if (fwrite(bws->data.cstr, len + 1, 1, f) < 1)
439			err(2, NULL);
440
441		return (len + 1);
442
443	} else {
444		wchar_t eols;
445		size_t printed = 0;
446
447		eols = zero_ended ? btowc('\0') : btowc('\n');
448
449		while (printed < BWSLEN(bws)) {
450			const wchar_t *s = bws->data.wstr + printed;
451
452			if (*s == L'\0') {
453				int nums;
454
455				nums = fwprintf(f, L"%lc", *s);
456
457				if (nums != 1)
458					err(2, NULL);
459				++printed;
460			} else {
461				int nums;
462
463				nums = fwprintf(f, L"%ls", s);
464
465				if (nums < 1)
466					err(2, NULL);
467				printed += nums;
468			}
469		}
470		fwprintf(f, L"%lc", eols);
471		return (printed + 1);
472	}
473}
474
475/*
476 * Allocate and read a binary string from file.
477 * The strings are nl-ended or zero-ended, depending on the sort setting.
478 */
479struct bwstring *
480bwsfgetln(FILE *f, size_t *len, bool zero_ended, struct reader_buffer *rb)
481{
482	wint_t eols;
483
484	eols = zero_ended ? btowc('\0') : btowc('\n');
485
486	if (!zero_ended && (MB_CUR_MAX > 1)) {
487		wchar_t *ret;
488
489		ret = fgetwln(f, len);
490
491		if (ret == NULL) {
492			if (!feof(f))
493				err(2, NULL);
494			return (NULL);
495		}
496		if (*len > 0) {
497			if (ret[*len - 1] == (wchar_t)eols)
498				--(*len);
499		}
500		return (bwssbdup(ret, *len));
501
502	} else if (!zero_ended && (MB_CUR_MAX == 1)) {
503		char *ret;
504
505		ret = fgetln(f, len);
506
507		if (ret == NULL) {
508			if (!feof(f))
509				err(2, NULL);
510			return (NULL);
511		}
512		if (*len > 0) {
513			if (ret[*len - 1] == '\n')
514				--(*len);
515		}
516		return (bwscsbdup((unsigned char*)ret, *len));
517
518	} else {
519		*len = 0;
520
521		if (feof(f))
522			return (NULL);
523
524		if (2 >= rb->fgetwln_z_buffer_size) {
525			rb->fgetwln_z_buffer_size += 256;
526			rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
527			    sizeof(wchar_t) * rb->fgetwln_z_buffer_size);
528		}
529		rb->fgetwln_z_buffer[*len] = 0;
530
531		if (MB_CUR_MAX == 1)
532			while (!feof(f)) {
533				int c;
534
535				c = fgetc(f);
536
537				if (c == EOF) {
538					if (*len == 0)
539						return (NULL);
540					goto line_read_done;
541				}
542				if (c == eols)
543					goto line_read_done;
544
545				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
546					rb->fgetwln_z_buffer_size += 256;
547					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
548					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
549				}
550
551				rb->fgetwln_z_buffer[*len] = c;
552				rb->fgetwln_z_buffer[++(*len)] = 0;
553			}
554		else
555			while (!feof(f)) {
556				wint_t c = 0;
557
558				c = fgetwc(f);
559
560				if (c == WEOF) {
561					if (*len == 0)
562						return (NULL);
563					goto line_read_done;
564				}
565				if (c == eols)
566					goto line_read_done;
567
568				if (*len + 1 >= rb->fgetwln_z_buffer_size) {
569					rb->fgetwln_z_buffer_size += 256;
570					rb->fgetwln_z_buffer = sort_realloc(rb->fgetwln_z_buffer,
571					    SIZEOF_WCHAR_STRING(rb->fgetwln_z_buffer_size));
572				}
573
574				rb->fgetwln_z_buffer[*len] = c;
575				rb->fgetwln_z_buffer[++(*len)] = 0;
576			}
577
578line_read_done:
579		/* we do not count the last 0 */
580		return (bwssbdup(rb->fgetwln_z_buffer, *len));
581	}
582}
583
584int
585bwsncmp(const struct bwstring *bws1, const struct bwstring *bws2,
586    size_t offset, size_t len)
587{
588	size_t cmp_len, len1, len2;
589	int res = 0;
590
591	cmp_len = 0;
592	len1 = bws1->len;
593	len2 = bws2->len;
594
595	if (len1 <= offset) {
596		return ((len2 <= offset) ? 0 : -1);
597	} else {
598		if (len2 <= offset)
599			return (+1);
600		else {
601			len1 -= offset;
602			len2 -= offset;
603
604			cmp_len = len1;
605
606			if (len2 < cmp_len)
607				cmp_len = len2;
608
609			if (len < cmp_len)
610				cmp_len = len;
611
612			if (MB_CUR_MAX == 1) {
613				const unsigned char *s1, *s2;
614
615				s1 = bws1->data.cstr + offset;
616				s2 = bws2->data.cstr + offset;
617
618				res = memcmp(s1, s2, cmp_len);
619
620			} else {
621				const wchar_t *s1, *s2;
622
623				s1 = bws1->data.wstr + offset;
624				s2 = bws2->data.wstr + offset;
625
626				res = memcmp(s1, s2, SIZEOF_WCHAR_STRING(cmp_len));
627			}
628		}
629	}
630
631	if (res == 0) {
632		if (len1 < cmp_len && len1 < len2)
633			res = -1;
634		else if (len2 < cmp_len && len2 < len1)
635			res = +1;
636	}
637
638	return (res);
639}
640
641int
642bwscmp(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
643{
644	size_t len1, len2, cmp_len;
645	int res;
646
647	len1 = bws1->len;
648	len2 = bws2->len;
649
650	len1 -= offset;
651	len2 -= offset;
652
653	cmp_len = len1;
654
655	if (len2 < cmp_len)
656		cmp_len = len2;
657
658	res = bwsncmp(bws1, bws2, offset, cmp_len);
659
660	if (res == 0) {
661		if( len1 < len2)
662			res = -1;
663		else if (len2 < len1)
664			res = +1;
665	}
666
667	return (res);
668}
669
670int
671bws_iterator_cmp(bwstring_iterator iter1, bwstring_iterator iter2, size_t len)
672{
673	wchar_t c1, c2;
674	size_t i = 0;
675
676	for (i = 0; i < len; ++i) {
677		c1 = bws_get_iter_value(iter1);
678		c2 = bws_get_iter_value(iter2);
679		if (c1 != c2)
680			return (c1 - c2);
681		iter1 = bws_iterator_inc(iter1, 1);
682		iter2 = bws_iterator_inc(iter2, 1);
683	}
684
685	return (0);
686}
687
688int
689bwscoll(const struct bwstring *bws1, const struct bwstring *bws2, size_t offset)
690{
691	size_t len1, len2;
692
693	len1 = bws1->len;
694	len2 = bws2->len;
695
696	if (len1 <= offset)
697		return ((len2 <= offset) ? 0 : -1);
698	else {
699		if (len2 <= offset)
700			return (+1);
701		else {
702			len1 -= offset;
703			len2 -= offset;
704
705			if (MB_CUR_MAX == 1) {
706				const unsigned char *s1, *s2;
707
708				s1 = bws1->data.cstr + offset;
709				s2 = bws2->data.cstr + offset;
710
711				if (byte_sort) {
712					int res = 0;
713
714					if (len1 > len2) {
715						res = memcmp(s1, s2, len2);
716						if (!res)
717							res = +1;
718					} else if (len1 < len2) {
719						res = memcmp(s1, s2, len1);
720						if (!res)
721							res = -1;
722					} else
723						res = memcmp(s1, s2, len1);
724
725					return (res);
726
727				} else {
728					int res = 0;
729					size_t i, maxlen;
730
731					i = 0;
732					maxlen = len1;
733
734					if (maxlen > len2)
735						maxlen = len2;
736
737					while (i < maxlen) {
738						/* goto next non-zero part: */
739						while ((i < maxlen) &&
740						    !s1[i] && !s2[i])
741							++i;
742
743						if (i >= maxlen)
744							break;
745
746						if (s1[i] == 0) {
747							if (s2[i] == 0)
748								/* NOTREACHED */
749								err(2, "bwscoll error 01");
750							else
751								return (-1);
752						} else if (s2[i] == 0)
753							return (+1);
754
755						res = strcoll((const char*)(s1 + i), (const char*)(s2 + i));
756						if (res)
757							return (res);
758
759						while ((i < maxlen) &&
760						    s1[i] && s2[i])
761							++i;
762
763						if (i >= maxlen)
764							break;
765
766						if (s1[i] == 0) {
767							if (s2[i] == 0) {
768								++i;
769								continue;
770							} else
771								return (-1);
772						} else if (s2[i] == 0)
773							return (+1);
774						else
775							/* NOTREACHED */
776							err(2, "bwscoll error 02");
777					}
778
779					if (len1 < len2)
780						return (-1);
781					else if (len1 > len2)
782						return (+1);
783
784					return (0);
785				}
786			} else {
787				const wchar_t *s1, *s2;
788				size_t i, maxlen;
789				int res = 0;
790
791				s1 = bws1->data.wstr + offset;
792				s2 = bws2->data.wstr + offset;
793
794				i = 0;
795				maxlen = len1;
796
797				if (maxlen > len2)
798					maxlen = len2;
799
800				while (i < maxlen) {
801
802					/* goto next non-zero part: */
803					while ((i < maxlen) &&
804					    !s1[i] && !s2[i])
805						++i;
806
807					if (i >= maxlen)
808						break;
809
810					if (s1[i] == 0) {
811						if (s2[i] == 0)
812							/* NOTREACHED */
813							err(2, "bwscoll error 1");
814						else
815							return (-1);
816					} else if (s2[i] == 0)
817						return (+1);
818
819					res = wide_str_coll(s1 + i, s2 + i);
820					if (res)
821						return (res);
822
823					while ((i < maxlen) && s1[i] && s2[i])
824						++i;
825
826					if (i >= maxlen)
827						break;
828
829					if (s1[i] == 0) {
830						if (s2[i] == 0) {
831							++i;
832							continue;
833						} else
834							return (-1);
835					} else if (s2[i] == 0)
836						return (+1);
837					else
838						/* NOTREACHED */
839						err(2, "bwscoll error 2");
840				}
841
842				if (len1 < len2)
843					return (-1);
844				else if (len1 > len2)
845					return (+1);
846
847				return (0);
848			}
849		}
850	}
851}
852
853/*
854 * Correction of the system API
855 */
856double
857bwstod(struct bwstring *s0, bool *empty)
858{
859	double ret = 0;
860
861	if (MB_CUR_MAX == 1) {
862		unsigned char *end, *s;
863		char *ep;
864
865		s = s0->data.cstr;
866		end = s + s0->len;
867		ep = NULL;
868
869		while (isblank(*s) && s < end)
870			++s;
871
872		if (!isprint(*s)) {
873			*empty = true;
874			return (0);
875		}
876
877		ret = strtod((char*)s, &ep);
878		if ((unsigned char*) ep == s) {
879			*empty = true;
880			return (0);
881		}
882	} else {
883		wchar_t *end, *ep, *s;
884
885		s = s0->data.wstr;
886		end = s + s0->len;
887		ep = NULL;
888
889		while (iswblank(*s) && s < end)
890			++s;
891
892		if (!iswprint(*s)) {
893			*empty = true;
894			return (0);
895		}
896
897		ret = wcstod(s, &ep);
898		if (ep == s) {
899			*empty = true;
900			return (0);
901		}
902	}
903
904	*empty = false;
905	return (ret);
906}
907
908/*
909 * A helper function for monthcoll.  If a line matches
910 * a month name, it returns (number of the month - 1),
911 * while if there is no match, it just return -1.
912 */
913
914int
915bws_month_score(const struct bwstring *s0)
916{
917
918	if (MB_CUR_MAX == 1) {
919		const unsigned char *end, *s;
920		size_t len;
921
922		s = s0->data.cstr;
923		end = s + s0->len;
924
925		while (isblank(*s) && s < end)
926			++s;
927
928		len = strlen((const char*)s);
929
930		for (int i = 11; i >= 0; --i) {
931			if (cmonths[i] &&
932			    (s == (unsigned char*)strstr((const char*)s, (char*)(cmonths[i]))))
933				return (i);
934		}
935
936	} else {
937		const wchar_t *end, *s;
938		size_t len;
939
940		s = s0->data.wstr;
941		end = s + s0->len;
942
943		while (iswblank(*s) && s < end)
944			++s;
945
946		len = wcslen(s);
947
948		for (int i = 11; i >= 0; --i) {
949			if (wmonths[i] && (s == wcsstr(s, wmonths[i])))
950				return (i);
951		}
952	}
953
954	return (-1);
955}
956
957/*
958 * Rips out leading blanks (-b).
959 */
960struct bwstring *
961ignore_leading_blanks(struct bwstring *str)
962{
963
964	if (MB_CUR_MAX == 1) {
965		unsigned char *dst, *end, *src;
966
967		src = str->data.cstr;
968		dst = src;
969		end = src + str->len;
970
971		while (src < end && isblank(*src))
972			++src;
973
974		if (src != dst) {
975			size_t newlen;
976
977			newlen = BWSLEN(str) - (src - dst);
978
979			while (src < end) {
980				*dst = *src;
981				++dst;
982				++src;
983			}
984			bws_setlen(str, newlen);
985		}
986	} else {
987		wchar_t *dst, *end, *src;
988
989		src = str->data.wstr;
990		dst = src;
991		end = src + str->len;
992
993		while (src < end && iswblank(*src))
994			++src;
995
996		if (src != dst) {
997
998			size_t newlen = BWSLEN(str) - (src - dst);
999
1000			while (src < end) {
1001				*dst = *src;
1002				++dst;
1003				++src;
1004			}
1005			bws_setlen(str, newlen);
1006
1007		}
1008	}
1009	return (str);
1010}
1011
1012/*
1013 * Rips out nonprinting characters (-i).
1014 */
1015struct bwstring *
1016ignore_nonprinting(struct bwstring *str)
1017{
1018	size_t newlen = str->len;
1019
1020	if (MB_CUR_MAX == 1) {
1021		unsigned char *dst, *end, *src;
1022		unsigned char c;
1023
1024		src = str->data.cstr;
1025		dst = src;
1026		end = src + str->len;
1027
1028		while (src < end) {
1029			c = *src;
1030			if (isprint(c)) {
1031				*dst = c;
1032				++dst;
1033				++src;
1034			} else {
1035				++src;
1036				--newlen;
1037			}
1038		}
1039	} else {
1040		wchar_t *dst, *end, *src;
1041		wchar_t c;
1042
1043		src = str->data.wstr;
1044		dst = src;
1045		end = src + str->len;
1046
1047		while (src < end) {
1048			c = *src;
1049			if (iswprint(c)) {
1050				*dst = c;
1051				++dst;
1052				++src;
1053			} else {
1054				++src;
1055				--newlen;
1056			}
1057		}
1058	}
1059	bws_setlen(str, newlen);
1060
1061	return (str);
1062}
1063
1064/*
1065 * Rips out any characters that are not alphanumeric characters
1066 * nor blanks (-d).
1067 */
1068struct bwstring *
1069dictionary_order(struct bwstring *str)
1070{
1071	size_t newlen = str->len;
1072
1073	if (MB_CUR_MAX == 1) {
1074		unsigned char *dst, *end, *src;
1075		unsigned char c;
1076
1077		src = str->data.cstr;
1078		dst = src;
1079		end = src + str->len;
1080
1081		while (src < end) {
1082			c = *src;
1083			if (isalnum(c) || isblank(c)) {
1084				*dst = c;
1085				++dst;
1086				++src;
1087			} else {
1088				++src;
1089				--newlen;
1090			}
1091		}
1092	} else {
1093		wchar_t *dst, *end, *src;
1094		wchar_t c;
1095
1096		src = str->data.wstr;
1097		dst = src;
1098		end = src + str->len;
1099
1100		while (src < end) {
1101			c = *src;
1102			if (iswalnum(c) || iswblank(c)) {
1103				*dst = c;
1104				++dst;
1105				++src;
1106			} else {
1107				++src;
1108				--newlen;
1109			}
1110		}
1111	}
1112	bws_setlen(str, newlen);
1113
1114	return (str);
1115}
1116
1117/*
1118 * Converts string to lower case(-f).
1119 */
1120struct bwstring *
1121ignore_case(struct bwstring *str)
1122{
1123
1124	if (MB_CUR_MAX == 1) {
1125		unsigned char *end, *s;
1126
1127		s = str->data.cstr;
1128		end = s + str->len;
1129
1130		while (s < end) {
1131			*s = toupper(*s);
1132			++s;
1133		}
1134	} else {
1135		wchar_t *end, *s;
1136
1137		s = str->data.wstr;
1138		end = s + str->len;
1139
1140		while (s < end) {
1141			*s = towupper(*s);
1142			++s;
1143		}
1144	}
1145	return (str);
1146}
1147
1148void
1149bws_disorder_warnx(struct bwstring *s, const char *fn, size_t pos)
1150{
1151
1152	if (MB_CUR_MAX == 1)
1153		warnx("%s:%zu: disorder: %s", fn, pos + 1, s->data.cstr);
1154	else
1155		warnx("%s:%zu: disorder: %ls", fn, pos + 1, s->data.wstr);
1156}
1157