xref: /dragonfly/lib/libc/string/wcscoll.c (revision d705af0f)
116db8bacSJohn Marino /*
216db8bacSJohn Marino  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
3716024cdSPeter Avalos  * Copyright (c) 2002 Tim J. Robbins
4716024cdSPeter Avalos  * All rights reserved.
5716024cdSPeter Avalos  *
60d5acd74SJohn Marino  * Copyright (c) 2011 The FreeBSD Foundation
70d5acd74SJohn Marino  * All rights reserved.
80d5acd74SJohn Marino  * Portions of this software were developed by David Chisnall
90d5acd74SJohn Marino  * under sponsorship from the FreeBSD Foundation.
100d5acd74SJohn Marino  *
11716024cdSPeter Avalos  * Redistribution and use in source and binary forms, with or without
12716024cdSPeter Avalos  * modification, are permitted provided that the following conditions
13716024cdSPeter Avalos  * are met:
14716024cdSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
15716024cdSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
16716024cdSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
17716024cdSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
18716024cdSPeter Avalos  *    documentation and/or other materials provided with the distribution.
19716024cdSPeter Avalos  *
20716024cdSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21716024cdSPeter Avalos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22716024cdSPeter Avalos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23716024cdSPeter Avalos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24716024cdSPeter Avalos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25716024cdSPeter Avalos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26716024cdSPeter Avalos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27716024cdSPeter Avalos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28716024cdSPeter Avalos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29716024cdSPeter Avalos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30716024cdSPeter Avalos  * SUCH DAMAGE.
31716024cdSPeter Avalos  */
32716024cdSPeter Avalos 
33716024cdSPeter Avalos #include <errno.h>
34716024cdSPeter Avalos #include <stdlib.h>
35716024cdSPeter Avalos #include <string.h>
36716024cdSPeter Avalos #include <wchar.h>
37716024cdSPeter Avalos #include "collate.h"
38716024cdSPeter Avalos 
39716024cdSPeter Avalos int
wcscoll_l(const wchar_t * ws1,const wchar_t * ws2,locale_t locale)400d5acd74SJohn Marino wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale)
41716024cdSPeter Avalos {
4216db8bacSJohn Marino 	int len1, len2, pri1, pri2, ret;
4316db8bacSJohn Marino 	wchar_t *tr1 = NULL, *tr2 = NULL;
4416db8bacSJohn Marino 	int direc, pass;
4516db8bacSJohn Marino 
460d5acd74SJohn Marino 	FIX_LOCALE(locale);
470d5acd74SJohn Marino 	struct xlocale_collate *table =
480d5acd74SJohn Marino 		(struct xlocale_collate*)locale->components[XLC_COLLATE];
49716024cdSPeter Avalos 
5016db8bacSJohn Marino 	if (table->__collate_load_error)
51716024cdSPeter Avalos 		/*
5216db8bacSJohn Marino 		 * Locale has no special collating order or could not be
5316db8bacSJohn Marino 		 * loaded, do a fast binary comparison.
54716024cdSPeter Avalos 		 */
55716024cdSPeter Avalos 		return (wcscmp(ws1, ws2));
56716024cdSPeter Avalos 
5716db8bacSJohn Marino 	ret = 0;
5816db8bacSJohn Marino 
59716024cdSPeter Avalos 	/*
6016db8bacSJohn Marino 	 * Once upon a time we had code to try to optimize this, but
6116db8bacSJohn Marino 	 * it turns out that you really can't make many assumptions
6216db8bacSJohn Marino 	 * safely.  You absolutely have to run this pass by pass,
6316db8bacSJohn Marino 	 * because some passes will be ignored for a given character,
6416db8bacSJohn Marino 	 * while others will not.  Simpler locales will benefit from
6516db8bacSJohn Marino 	 * having fewer passes, and most comparisions should resolve
6616db8bacSJohn Marino 	 * during the primary pass anyway.
6716db8bacSJohn Marino 	 *
6816db8bacSJohn Marino 	 * Note that we do one final extra pass at the end to pick
6916db8bacSJohn Marino 	 * up UNDEFINED elements.  There is special handling for them.
70716024cdSPeter Avalos 	 */
7116db8bacSJohn Marino 	for (pass = 0; pass <= table->info->directive_count; pass++) {
7216db8bacSJohn Marino 
7316db8bacSJohn Marino 		const int32_t *st1 = NULL;
7416db8bacSJohn Marino 		const int32_t *st2 = NULL;
7516db8bacSJohn Marino 		const wchar_t	*w1 = ws1;
7616db8bacSJohn Marino 		const wchar_t	*w2 = ws2;
77*d705af0fSJohn Marino 		int check1, check2;
7816db8bacSJohn Marino 
7916db8bacSJohn Marino 		/* special pass for UNDEFINED */
8016db8bacSJohn Marino 		if (pass == table->info->directive_count) {
8116db8bacSJohn Marino 			direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
8216db8bacSJohn Marino 		} else {
8316db8bacSJohn Marino 			direc = table->info->directive[pass];
84716024cdSPeter Avalos 		}
85716024cdSPeter Avalos 
8616db8bacSJohn Marino 		if (direc & DIRECTIVE_BACKWARD) {
8716db8bacSJohn Marino 			wchar_t *bp, *fp, c;
8816db8bacSJohn Marino 			if ((tr1 = wcsdup(w1)) == NULL)
8916db8bacSJohn Marino 				goto fail;
9016db8bacSJohn Marino 			bp = tr1;
9116db8bacSJohn Marino 			fp = tr1 + wcslen(tr1) - 1;
9216db8bacSJohn Marino 			while (bp < fp) {
9316db8bacSJohn Marino 				c = *bp;
9416db8bacSJohn Marino 				*bp++ = *fp;
9516db8bacSJohn Marino 				*fp-- = c;
9616db8bacSJohn Marino 			}
9716db8bacSJohn Marino 			if ((tr2 = wcsdup(w2)) == NULL)
9816db8bacSJohn Marino 				goto fail;
9916db8bacSJohn Marino 			bp = tr2;
10016db8bacSJohn Marino 			fp = tr2 + wcslen(tr2) - 1;
10116db8bacSJohn Marino 			while (bp < fp) {
10216db8bacSJohn Marino 				c = *bp;
10316db8bacSJohn Marino 				*bp++ = *fp;
10416db8bacSJohn Marino 				*fp-- = c;
10516db8bacSJohn Marino 			}
10616db8bacSJohn Marino 			w1 = tr1;
10716db8bacSJohn Marino 			w2 = tr2;
10816db8bacSJohn Marino 		}
109716024cdSPeter Avalos 
11016db8bacSJohn Marino 		if (direc & DIRECTIVE_POSITION) {
111*d705af0fSJohn Marino 			while (*w1 && *w2) {
11216db8bacSJohn Marino 				pri1 = pri2 = 0;
113*d705af0fSJohn Marino 				check1 = check2 = 1;
114*d705af0fSJohn Marino 				while ((pri1 == pri2) && (check1 || check2)) {
115*d705af0fSJohn Marino 					if (check1) {
116*d705af0fSJohn Marino 						_collate_lookup(table, w1, &len1,
117*d705af0fSJohn Marino 						    &pri1, pass, &st1);
11816db8bacSJohn Marino 						if (pri1 < 0) {
11916db8bacSJohn Marino 							errno = EINVAL;
12016db8bacSJohn Marino 							goto fail;
12116db8bacSJohn Marino 						}
122*d705af0fSJohn Marino 						if (!pri1) {
12316db8bacSJohn Marino 							pri1 = COLLATE_MAX_PRIORITY;
124*d705af0fSJohn Marino 							st1 = NULL;
12516db8bacSJohn Marino 						}
126*d705af0fSJohn Marino 						check1 = (st1 != NULL);
127*d705af0fSJohn Marino 					}
128*d705af0fSJohn Marino 					if (check2) {
129*d705af0fSJohn Marino 						_collate_lookup(table, w2, &len2,
130*d705af0fSJohn Marino 						    &pri2, pass, &st2);
13116db8bacSJohn Marino 						if (pri2 < 0) {
13216db8bacSJohn Marino 							errno = EINVAL;
13316db8bacSJohn Marino 							goto fail;
13416db8bacSJohn Marino 						}
135*d705af0fSJohn Marino 						if (!pri2) {
13616db8bacSJohn Marino 							pri2 = COLLATE_MAX_PRIORITY;
137*d705af0fSJohn Marino 							st2 = NULL;
138*d705af0fSJohn Marino 						}
139*d705af0fSJohn Marino 						check2 = (st2 != NULL);
140*d705af0fSJohn Marino 					}
14116db8bacSJohn Marino 				}
14216db8bacSJohn Marino 				if (pri1 != pri2) {
14316db8bacSJohn Marino 					ret = pri1 - pri2;
14416db8bacSJohn Marino 					goto end;
14516db8bacSJohn Marino 				}
14616db8bacSJohn Marino 				w1 += len1;
14716db8bacSJohn Marino 				w2 += len2;
14816db8bacSJohn Marino 			}
14916db8bacSJohn Marino 		} else {
150*d705af0fSJohn Marino 			while (*w1 && *w2) {
15116db8bacSJohn Marino 				pri1 = pri2 = 0;
152*d705af0fSJohn Marino 				check1 = check2 = 1;
153*d705af0fSJohn Marino 				while ((pri1 == pri2) && (check1 || check2)) {
154*d705af0fSJohn Marino 					while (check1 && *w1) {
155*d705af0fSJohn Marino 						_collate_lookup(table, w1,
156*d705af0fSJohn Marino 						    &len1, &pri1, pass, &st1);
15716db8bacSJohn Marino 						if (pri1 > 0)
15816db8bacSJohn Marino 							break;
15916db8bacSJohn Marino 						if (pri1 < 0) {
16016db8bacSJohn Marino 							errno = EINVAL;
16116db8bacSJohn Marino 							goto fail;
16216db8bacSJohn Marino 						}
163*d705af0fSJohn Marino 						st1 = NULL;
164*d705af0fSJohn Marino 						w1 += 1;
16516db8bacSJohn Marino 					}
166*d705af0fSJohn Marino 					check1 = (st1 != NULL);
167*d705af0fSJohn Marino 					while (check2 && *w2) {
168*d705af0fSJohn Marino 						_collate_lookup(table, w2,
169*d705af0fSJohn Marino 						    &len2, &pri2, pass, &st2);
17016db8bacSJohn Marino 						if (pri2 > 0)
17116db8bacSJohn Marino 							break;
17216db8bacSJohn Marino 						if (pri2 < 0) {
17316db8bacSJohn Marino 							errno = EINVAL;
17416db8bacSJohn Marino 							goto fail;
17516db8bacSJohn Marino 						}
176*d705af0fSJohn Marino 						st2 = NULL;
177*d705af0fSJohn Marino 						w2 += 1;
178*d705af0fSJohn Marino 					}
179*d705af0fSJohn Marino 					check2 = (st2 != NULL);
180*d705af0fSJohn Marino 					if (!pri1 || !pri2)
181*d705af0fSJohn Marino 						break;
18216db8bacSJohn Marino 				}
18316db8bacSJohn Marino 				if (!pri1 || !pri2)
18416db8bacSJohn Marino 					break;
18516db8bacSJohn Marino 				if (pri1 != pri2) {
18616db8bacSJohn Marino 					ret = pri1 - pri2;
18716db8bacSJohn Marino 					goto end;
18816db8bacSJohn Marino 				}
18916db8bacSJohn Marino 				w1 += len1;
19016db8bacSJohn Marino 				w2 += len2;
19116db8bacSJohn Marino 			}
19216db8bacSJohn Marino 		}
19316db8bacSJohn Marino 		if (!*w1) {
19416db8bacSJohn Marino 			if (*w2) {
19516db8bacSJohn Marino 				ret = -(int)*w2;
19616db8bacSJohn Marino 				goto end;
19716db8bacSJohn Marino 			}
19816db8bacSJohn Marino 		} else {
19916db8bacSJohn Marino 			ret = *w1;
20016db8bacSJohn Marino 			goto end;
20116db8bacSJohn Marino 		}
20216db8bacSJohn Marino 	}
20316db8bacSJohn Marino 	ret = 0;
20416db8bacSJohn Marino 
20516db8bacSJohn Marino end:
20616db8bacSJohn Marino 	free(tr1);
20716db8bacSJohn Marino 	free(tr2);
20816db8bacSJohn Marino 
20916db8bacSJohn Marino 	return (ret);
21016db8bacSJohn Marino 
21116db8bacSJohn Marino fail:
21216db8bacSJohn Marino 	ret = wcscmp(ws1, ws2);
21316db8bacSJohn Marino 	goto end;
214716024cdSPeter Avalos }
215716024cdSPeter Avalos 
2160d5acd74SJohn Marino int
wcscoll(const wchar_t * ws1,const wchar_t * ws2)2170d5acd74SJohn Marino wcscoll(const wchar_t *ws1, const wchar_t *ws2)
2180d5acd74SJohn Marino {
2190d5acd74SJohn Marino 	return wcscoll_l(ws1, ws2, __get_locale());
2200d5acd74SJohn Marino }
221