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