xref: /netbsd-src/lib/libc/locale/fix_grouping.c (revision 75f9c6b12541b45ff9db9b3cc2adc92cf7e130d8)
1*75f9c6b1Sriastradh /* $NetBSD: fix_grouping.c,v 1.7 2024/06/07 13:53:12 riastradh Exp $ */
252ed7b03Stnozaki 
352ed7b03Stnozaki /*
452ed7b03Stnozaki  * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
552ed7b03Stnozaki  * All rights reserved.
652ed7b03Stnozaki  *
752ed7b03Stnozaki  * Redistribution and use in source and binary forms, with or without
852ed7b03Stnozaki  * modification, are permitted provided that the following conditions
952ed7b03Stnozaki  * are met:
1052ed7b03Stnozaki  * 1. Redistributions of source code must retain the above copyright
1152ed7b03Stnozaki  *    notice, this list of conditions and the following disclaimer.
1252ed7b03Stnozaki  * 2. Redistributions in binary form must reproduce the above copyright
1352ed7b03Stnozaki  *    notice, this list of conditions and the following disclaimer in the
1452ed7b03Stnozaki  *    documentation and/or other materials provided with the distribution.
1552ed7b03Stnozaki  *
1652ed7b03Stnozaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1752ed7b03Stnozaki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1852ed7b03Stnozaki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1952ed7b03Stnozaki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2052ed7b03Stnozaki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2152ed7b03Stnozaki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2252ed7b03Stnozaki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2352ed7b03Stnozaki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2452ed7b03Stnozaki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2552ed7b03Stnozaki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2652ed7b03Stnozaki  * SUCH DAMAGE.
2752ed7b03Stnozaki  *
2852ed7b03Stnozaki  * Original version ID:
2952ed7b03Stnozaki  *     FreeBSD: fix_grouping.c,v 1.8 2003/06/26 10:46:16 phantom Exp
3052ed7b03Stnozaki  */
3152ed7b03Stnozaki 
322af58f1cStnozaki #if HAVE_NBTOOL_CONFIG_H
332af58f1cStnozaki #include "nbtool_config.h"
342af58f1cStnozaki #endif
352af58f1cStnozaki 
3652ed7b03Stnozaki #include <sys/cdefs.h>
3752ed7b03Stnozaki #if defined(LIBC_SCCS) && !defined(lint)
38*75f9c6b1Sriastradh __RCSID("$NetBSD: fix_grouping.c,v 1.7 2024/06/07 13:53:12 riastradh Exp $");
3952ed7b03Stnozaki #endif /* LIBC_SCCS and not lint */
4052ed7b03Stnozaki 
4152ed7b03Stnozaki #include <limits.h>
4252ed7b03Stnozaki #include <stddef.h>
4352ed7b03Stnozaki 
4452ed7b03Stnozaki #include "fix_grouping.h"
4552ed7b03Stnozaki 
4652ed7b03Stnozaki #ifndef NBCHAR_MAX
47*75f9c6b1Sriastradh #define NBCHAR_MAX	CHAR_MAX
4852ed7b03Stnozaki #endif
4952ed7b03Stnozaki 
50c67ae0d6Sdogcow #ifndef __UNCONST
51c67ae0d6Sdogcow #define __UNCONST(a)    ((void *)(unsigned long)(const void *)(a))
52c67ae0d6Sdogcow #endif
53c67ae0d6Sdogcow 
5452ed7b03Stnozaki static const char nogrouping[] = { NBCHAR_MAX, '\0' };
5552ed7b03Stnozaki 
5652ed7b03Stnozaki /* don't use libc's isdigit, it owes locale. */
5752ed7b03Stnozaki #define isdigit(c)	(c >= '0' && c <= '9')
5852ed7b03Stnozaki 
5952ed7b03Stnozaki /*
6052ed7b03Stnozaki  * Internal helper used to convert grouping sequences from string
6152ed7b03Stnozaki  * representation into POSIX specified form, i.e.
6252ed7b03Stnozaki  *
6352ed7b03Stnozaki  * "3;3;-1" -> "\003\003\177\000"
6452ed7b03Stnozaki  */
6552ed7b03Stnozaki 
6652ed7b03Stnozaki const char *
__fix_locale_grouping_str(const char * str)6752ed7b03Stnozaki __fix_locale_grouping_str(const char *str)
6852ed7b03Stnozaki {
6952ed7b03Stnozaki 	char *src, *dst;
7052ed7b03Stnozaki 	char n;
7152ed7b03Stnozaki 
7252ed7b03Stnozaki 	if (str == NULL || *str == '\0') {
7352ed7b03Stnozaki 		return nogrouping;
7452ed7b03Stnozaki 	}
7552ed7b03Stnozaki 
7652ed7b03Stnozaki 	for (src = __UNCONST(str), dst = __UNCONST(str); *src != '\0'; src++) {
7752ed7b03Stnozaki 
7852ed7b03Stnozaki 		/* input string examples: "3;3", "3;2;-1" */
7952ed7b03Stnozaki 		if (*src == ';')
8052ed7b03Stnozaki 			continue;
8152ed7b03Stnozaki 
8252ed7b03Stnozaki 		if (*src == '-' && *(src+1) == '1') {
8352ed7b03Stnozaki 			*dst++ = NBCHAR_MAX;
8452ed7b03Stnozaki 			src++;
8552ed7b03Stnozaki 			continue;
8652ed7b03Stnozaki 		}
8752ed7b03Stnozaki 
8852ed7b03Stnozaki 		if (!isdigit((unsigned char)*src)) {
8952ed7b03Stnozaki 			/* broken grouping string */
9052ed7b03Stnozaki 			return nogrouping;
9152ed7b03Stnozaki 		}
9252ed7b03Stnozaki 
9352ed7b03Stnozaki 		/* assume all numbers <= 99 */
9452ed7b03Stnozaki 		n = *src - '0';
9552ed7b03Stnozaki 		if (isdigit((unsigned char)*(src+1))) {
9652ed7b03Stnozaki 			src++;
9752ed7b03Stnozaki 			n *= 10;
9852ed7b03Stnozaki 			n += *src - '0';
9952ed7b03Stnozaki 		}
10052ed7b03Stnozaki 
10152ed7b03Stnozaki 		*dst = n;
10252ed7b03Stnozaki 		/* NOTE: assume all input started with "0" as 'no grouping' */
10352ed7b03Stnozaki 		if (*dst == '\0')
10452ed7b03Stnozaki 			return (dst == __UNCONST(str)) ? nogrouping : str;
10552ed7b03Stnozaki 		dst++;
10652ed7b03Stnozaki 	}
10752ed7b03Stnozaki 	*dst = '\0';
10852ed7b03Stnozaki 	return str;
10952ed7b03Stnozaki }
110