Import locale tools and ressource files

This commit requires special steps, please checkout docs/UPDATING.

Tools:
 - gencat
 - locale
 - mkcsmapper
 - mkesdb
 - mklocale

Libs:
 - i18n_module
 - libintl

Ressources:
 - i18n
 - locale

Change-Id: I559d0399d8e98bcee15225cab786e43f31506207
This commit is contained in:
2016-06-20 18:30:51 +02:00
parent 733a844ac6
commit 36dcc4a4a9
1369 changed files with 623024 additions and 9 deletions

View File

@@ -11,13 +11,13 @@ SUBDIR= asa \
deroff dirname du \
env expand \
false find finger flock fold fpr from \
fsplit ftp genassym \
fsplit ftp genassym gencat \
getopt \
head hexdump id indent infocmp ipcrm ipcs join jot \
lam last ldd leave \
lock login logname lorder m4 \
locale lock login logname lorder m4 \
machine make man menuc mesg \
mkdep mkfifo mkstr mktemp \
mkcsmapper mkdep mkesdb mkfifo mklocale mkstr mktemp \
msgc \
nbperf newgrp nice nl nohup \
pagesize passwd paste patch pathchk pr \

6
usr.bin/gencat/Makefile Normal file
View File

@@ -0,0 +1,6 @@
# $NetBSD: Makefile,v 1.9 2009/04/14 22:15:20 lukem Exp $
PROG= gencat
MAN= gencat.1
.include <bsd.prog.mk>

233
usr.bin/gencat/gencat.1 Normal file
View File

@@ -0,0 +1,233 @@
.\" $NetBSD: gencat.1,v 1.13 2011/12/29 16:41:38 christos Exp $
.\"
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Kee Hinckley and Brian Ginsbach.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.\" Written by Kee Hinckley <nazgul@somewhere.com>
.\"
.Dd December 29, 2011
.Dt GENCAT 1
.Os
.Sh NAME
.Nm gencat
.Nd generates a Native Language Support (NLS) message catalog file
.Sh SYNOPSIS
.Nm
.Ar catfile
.Op Ar msgfile|- ...
.Sh DESCRIPTION
The
.Nm
utility generates a formatted message catalog
.Ar catfile
from stdin or one or more message source text files
.Ar msgfile .
The file
.Ar catfile
is created if it does not already exist.
If
.Ar catfile
does exist, its messages are included in the new
.Ar catfile .
The new message text defined in
.Ar msgfile
replaces the old message text currently in
.Ar catfile
when the set and message numbers match.
.Pp
The generated message catalog contains message
strings that will be retrieved using the
.Xr catgets 3
library call.
These messages are dynamically loaded by the
Native Language Support (NLS) library at run time.
Error messages are grouped into sets, and a program can load a
particular set depending on which type, or language, of messages
is desired.
.Ss Message Text Source File Format
The message text source files are text files in the format described below.
Note that the fields of a message text source line are separated by
space or tab characters.
.\" XXX Required by POSIX; the code must be fixed first. Above line should be
.\" a single space or tab character;
.\" any other space or tab characters are considered to be part of the
.\" field contents.
.Bl -tag -width 3n
.It Li $set Ar n comment
Determines the set identifier to be used for all subsequent messages
until the next
.Li $set
or end-of-file.
The
.Ar n
is the set identifier which is defined as a number in the range
.Bo 1 ,
.Dv NL_SETMAX Bc .
Set identifiers within a single source file need not be contiguous.
Any string following the set identifier is treated as a comment.
If no
.Li $set
directive is specified in a message text source file,
all messages will be located in the default message set
.Dv NL_SETD .
.It Li $delset Ar n comment
Removes message set
.Ar n
from the catalog.
The
.Ar n
is a set identifier in the range
.Bo 1 ,
.Dv NL_SETMAX Bc .
If a message set was created earlier in the
current file, or in a file previously read by the
.Nm
command, this directive will remove it.
Any string following the set identifier is treated as a comment.
.It Li $ Ar comment
A line beginning with
.Li $
followed by a space or tab character is treated as a comment.
.It Ar m message-text
A message line consists of a message identifier
.Ar m
in the range
.Bo 1 ,
.Dv NL_MSGMAX Bc
and the
.Ar message-text .
The
.Ar message-text
is read until the end of the line or a quote character
(if one is specified).
The
.Ar message-text
is stored in the message catalog with
the set identifier specified by the last
.Li $set
directive, and the message identifier
.Ar m .
If the
.Ar message-text
is empty and there is a space or tab character
following the message identifier,
an empty string is stored in the message catalog.
If no
.Ar message-text
is provided,
and if there is no space or tab character following the message
identifier,
the message with the message identifier
.Ar m
in the current set is removed from the catalog.
Message identifiers need not be contiguous within a single set.
The length of
.Ar message-text
must be in the range
.Bo 0 ,
.Dv NL_TEXTMAX Bc .
.It Li $quote Ar c
Sets an optional quote character to be used around the
.Ar message-text .
The quote character
.Ar c
may be any character other than white space.
If this is specified, then messages must begin and end with the
quote character.
.\" XXX Remove next sentence when code is fixed for POSIX conformance.
This is useful when messages must contain leading white space.
.\" XXX Replacement when above is removed.
.\" This is useful to make leading and trailing spaces or empty
.\" messages visible.
By default no quote character is used.
If an empty
.Li $quote
directive is specified, then the current quote character is unset.
.El
.Pp
Empty lines
.\" XXX Remove next line when the code is fixed for POSIX conformance.
and leading blanks
in a message text source file are ignored.
Any line beginning with any character other than those
described above is ignored as a syntax error.
.Pp
Text message strings may contain any characters and
the following special characters and escape sequences.
.Pp
.Bl -column -offset indent ".Sy carriage return" ".Sy Symbol" ".Sy Sequence"
.It Sy Description Ta Sy Symbol Ta Sy Sequence
.It newline Ta NL(LF) Ta Li \en
.It horizontal tab Ta HT Ta Li \et
.It vertical tab Ta VT Ta Li \ev
.It backspace Ta BS Ta Li \eb
.It carriage return Ta CR Ta Li \er
.It form feed Ta FF Ta Li \ef
.It backslash Ta \e Ta Li \e\e
.It bit pattern Ta ddd Ta Li \eddd
.El
.Pp
A bit pattern,
.Li \eddd ,
consists of a backslash followed by
one, two, or three octal digits representing the value of the character.
The current quote character, if defined, may be escaped with a backslash
to generate the quote character.
Any character following the backslash ('\e') other than those specified
is ignored.
.Pp
A backslash at the end of the line continues the message onto the next line.
The following two lines are an example of such a message:
.Pp
.Dl 1 This message continues \e
.D1 on the next line
.Pp
Producing the following message:
.Pp
.Dl 1 This message continues on the next line
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
.Xr catclose 3 ,
.Xr catgets 3 ,
.Xr catopen 3 ,
.Xr nls 7
.\" XXX Close but not quite; add when code is fixed.
.\".Sh STANDARDS
.\"The
.\".Nm
.\"utility is compliant with the
.\".St -p1003.1-2004
.\"standard.
.Sh AUTHORS
The Native Language Support (NLS) message catalog facility was
contributed by
.An J.T. Conklin
.Aq jtc@NetBSD.org .
This page was originally written by
.An Kee Hinckley
.Aq nazgul@somewhere.com .

879
usr.bin/gencat/gencat.c Normal file
View File

@@ -0,0 +1,879 @@
/* $NetBSD: gencat.c,v 1.36 2013/11/27 17:38:11 apb Exp $ */
/*
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by J.T. Conklin.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
__RCSID("$NetBSD: gencat.c,v 1.36 2013/11/27 17:38:11 apb Exp $");
#endif
/***********************************************************
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that Alfalfa's name not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
ALPHALPHA BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.
If you make any modifications, bugfixes or other changes to this software
we'd appreciate it if you could send a copy to us so we can keep things
up-to-date. Many thanks.
Kee Hinckley
Alfalfa Software, Inc.
267 Allston St., #3
Cambridge, MA 02139 USA
nazgul@alfalfa.com
******************************************************************/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#define _NLS_PRIVATE
#include <sys/types.h>
#include <sys/queue.h>
#include <netinet/in.h> /* Needed by arpa/inet.h on NetBSD */
#include <arpa/inet.h> /* Needed for htonl() on POSIX systems */
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <nl_types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifndef NL_SETMAX
#define NL_SETMAX 255
#endif
#ifndef NL_MSGMAX
#define NL_MSGMAX 2048
#endif
struct _msgT {
long msgId;
char *str;
LIST_ENTRY(_msgT) entries;
};
struct _setT {
long setId;
LIST_HEAD(msghead, _msgT) msghead;
LIST_ENTRY(_setT) entries;
};
static LIST_HEAD(sethead, _setT) sethead = LIST_HEAD_INITIALIZER(sethead);
static struct _setT *curSet;
static const char *curfile;
static char *curline = NULL;
static long lineno = 0;
static char *cskip(char *);
__dead static void error(const char *);
static char *get_line(int);
static char *getmsg(int, char *, char);
static void warning(const char *, const char *);
static char *wskip(char *);
static char *xstrdup(const char *);
static void *xmalloc(size_t);
static void *xrealloc(void *, size_t);
static void MCParse(int fd);
static void MCReadCat(int fd);
static void MCWriteCat(int fd);
static void MCDelMsg(int msgId);
static void MCAddMsg(int msgId, const char *msg);
static void MCAddSet(int setId);
static void MCDelSet(int setId);
__dead static void usage(void);
#define CORRUPT "corrupt message catalog"
#define NOMEMORY "out of memory"
static void
usage(void)
{
fprintf(stderr, "usage: %s catfile [msgfile|- ...]\n", getprogname());
exit(1);
}
int
main(int argc, char *argv[])
{
int ofd, ifd;
char *catfile = NULL;
int c;
int updatecat = 0;
while ((c = getopt(argc, argv, "")) != -1) {
switch (c) {
case '?':
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
usage();
/* NOTREACHED */
}
catfile = *argv++;
if ((catfile[0] == '-') && (catfile[1] == '\0')) {
ofd = STDOUT_FILENO;
} else {
ofd = open(catfile, O_WRONLY | O_CREAT | O_EXCL, 0666);
if (ofd < 0) {
if (errno == EEXIST) {
if ((ofd = open(catfile, O_RDWR)) < 0) {
err(1, "Unable to open %s", catfile);
/* NOTREACHED */
}
} else {
err(1, "Unable to create new %s", catfile);
/* NOTREACHED */
}
curfile = catfile;
updatecat = 1;
MCReadCat(ofd);
if (lseek(ofd, (off_t)0, SEEK_SET) == (off_t)-1) {
err(1, "Unable to seek on %s", catfile);
/* NOTREACHED */
}
}
}
if (argc < 2 || (((*argv)[0] == '-') && ((*argv)[1] == '\0'))) {
if (argc > 2)
usage();
/* NOTREACHED */
MCParse(STDIN_FILENO);
} else {
for (; *argv; argv++) {
if ((ifd = open(*argv, O_RDONLY)) < 0)
err(1, "Unable to read %s", *argv);
curfile = *argv;
lineno = 0;
MCParse(ifd);
close(ifd);
}
}
if (updatecat) {
if (ftruncate(ofd, 0) != 0) {
err(1, "Unable to truncate %s", catfile);
/* NOTREACHED */
}
}
MCWriteCat(ofd);
exit(0);
}
static void
warning(const char *cptr, const char *msg)
{
if (lineno) {
fprintf(stderr, "%s: %s on line %ld, %s\n",
getprogname(), msg, lineno, curfile);
fprintf(stderr, "%s\n", curline);
if (cptr) {
char *tptr;
for (tptr = curline; tptr < cptr; ++tptr)
putc(' ', stderr);
fprintf(stderr, "^\n");
}
} else {
fprintf(stderr, "%s: %s, %s\n", getprogname(), msg, curfile);
}
}
static void
error(const char *msg)
{
warning(NULL, msg);
exit(1);
}
static void *
xmalloc(size_t len)
{
void *p;
if ((p = malloc(len)) == NULL)
errx(1, NOMEMORY);
return (p);
}
static void *
xrealloc(void *ptr, size_t size)
{
if ((ptr = realloc(ptr, size)) == NULL)
errx(1, NOMEMORY);
return (ptr);
}
static char *
xstrdup(const char *str)
{
char *nstr;
if ((nstr = strdup(str)) == NULL)
errx(1, NOMEMORY);
return (nstr);
}
static char *
get_line(int fd)
{
static long curlen = BUFSIZ;
static char buf[BUFSIZ], *bptr = buf, *bend = buf;
char *cptr, *cend;
long buflen;
if (!curline) {
curline = xmalloc(curlen);
}
++lineno;
cptr = curline;
cend = curline + curlen;
for (;;) {
for (; bptr < bend && cptr < cend; ++cptr, ++bptr) {
if (*bptr == '\n') {
*cptr = '\0';
++bptr;
return (curline);
} else
*cptr = *bptr;
}
if (cptr == cend) {
cptr = curline = xrealloc(curline, curlen *= 2);
cend = curline + curlen;
}
if (bptr == bend) {
buflen = read(fd, buf, BUFSIZ);
if (buflen <= 0) {
if (cptr > curline) {
*cptr = '\0';
return (curline);
}
return (NULL);
}
bend = buf + buflen;
bptr = buf;
}
}
}
static char *
wskip(char *cptr)
{
if (!*cptr || !isspace((unsigned char) *cptr)) {
warning(cptr, "expected a space");
return (cptr);
}
while (*cptr && isspace((unsigned char) *cptr))
++cptr;
return (cptr);
}
static char *
cskip(char *cptr)
{
if (!*cptr || isspace((unsigned char) *cptr)) {
warning(cptr, "wasn't expecting a space");
return (cptr);
}
while (*cptr && !isspace((unsigned char) *cptr))
++cptr;
return (cptr);
}
static char *
getmsg(int fd, char *cptr, char quote)
{
static char *msg = NULL;
static size_t msglen = 0;
size_t clen, i;
int in_quote = 0;
char *tptr;
if (quote && *cptr == quote) {
++cptr;
in_quote = 1;
}
clen = strlen(cptr) + 1;
if (clen > msglen) {
if (msglen)
msg = xrealloc(msg, clen);
else
msg = xmalloc(clen);
msglen = clen;
}
tptr = msg;
while (*cptr) {
if (quote && *cptr == quote) {
char *tmp;
tmp = cptr + 1;
if (!in_quote) {
/* XXX hard error? */
warning(cptr, "unexpected quote character, ignoring");
*tptr++ = *cptr++;
} else {
cptr++;
/* don't use wskip() */
while (*cptr && isspace((unsigned char) *cptr))
#ifndef _BACKWARDS_COMPAT
cptr++;
#else
*tptr++ = *cptr++;
#endif
/* XXX hard error? */
if (*cptr)
warning(tmp, "unexpected extra characters, ignoring");
in_quote = 0;
#ifndef _BACKWARDS_COMPAT
break;
#endif
}
} else {
if (*cptr == '\\') {
++cptr;
switch (*cptr) {
case '\0':
cptr = get_line(fd);
if (!cptr)
error("premature end of file");
msglen += strlen(cptr);
i = tptr - msg;
msg = xrealloc(msg, msglen);
tptr = msg + i;
break;
case 'n':
*tptr++ = '\n';
++cptr;
break;
case 't':
*tptr++ = '\t';
++cptr;
break;
case 'v':
*tptr++ = '\v';
++cptr;
break;
case 'b':
*tptr++ = '\b';
++cptr;
break;
case 'r':
*tptr++ = '\r';
++cptr;
break;
case 'f':
*tptr++ = '\f';
++cptr;
break;
case '\\':
*tptr++ = '\\';
++cptr;
break;
default:
if (quote && *cptr == quote) {
*tptr++ = *cptr++;
} else if (isdigit((unsigned char) *cptr)) {
*tptr = 0;
for (i = 0; i < 3; ++i) {
if (!isdigit((unsigned char) *cptr))
break;
if (*cptr > '7')
warning(cptr, "octal number greater than 7?!");
*tptr *= 8;
*tptr += (*cptr - '0');
++cptr;
}
} else {
warning(cptr, "unrecognized escape sequence");
}
break;
}
} else {
*tptr++ = *cptr++;
}
}
}
if (in_quote)
warning(cptr, "unterminated quoted message, ignoring");
*tptr = '\0';
return (msg);
}
static void
MCParse(int fd)
{
char *cptr, *str;
int msgid = 0;
int setid = 0;
char quote = 0;
while ((cptr = get_line(fd))) {
if (*cptr == '$') {
++cptr;
if (strncmp(cptr, "set", 3) == 0) {
cptr += 3;
cptr = wskip(cptr);
setid = atoi(cptr);
MCAddSet(setid);
msgid = 0;
} else if (strncmp(cptr, "delset", 6) == 0) {
cptr += 6;
cptr = wskip(cptr);
setid = atoi(cptr);
MCDelSet(setid);
} else if (strncmp(cptr, "quote", 5) == 0) {
cptr += 5;
if (!*cptr)
quote = 0;
else {
cptr = wskip(cptr);
if (!*cptr)
quote = 0;
else
quote = *cptr;
}
} else if (isspace((unsigned char) *cptr)) {
;
} else {
if (*cptr) {
cptr = wskip(cptr);
if (*cptr)
warning(cptr, "unrecognized line");
}
}
} else {
/*
* First check for (and eat) empty lines....
*/
if (!*cptr)
continue;
/*
* We have a digit? Start of a message. Else,
* syntax error.
*/
if (isdigit((unsigned char) *cptr)) {
msgid = atoi(cptr);
cptr = cskip(cptr);
if (*cptr) {
cptr = wskip(cptr);
if (!*cptr) {
MCAddMsg(msgid, "");
continue;
}
}
} else {
warning(cptr, "neither blank line nor start of a message id");
continue;
}
/*
* If no set directive specified, all messages
* shall be in default message set NL_SETD.
*/
if (setid == 0) {
setid = NL_SETD;
MCAddSet(setid);
}
/*
* If we have a message ID, but no message,
* then this means "delete this message id
* from the catalog".
*/
if (!*cptr) {
MCDelMsg(msgid);
} else {
str = getmsg(fd, cptr, quote);
MCAddMsg(msgid, str);
}
}
}
}
static void
MCReadCat(int fd)
{
void *msgcat; /* message catalog data */
struct _nls_cat_hdr cat_hdr;
struct _nls_set_hdr *set_hdr;
struct _nls_msg_hdr *msg_hdr;
char *strings;
ssize_t n;
int m, s;
int msgno, setno;
n = read(fd, &cat_hdr, sizeof(cat_hdr));
if (n < (ssize_t)sizeof(cat_hdr)) {
if (n == 0)
return; /* empty file */
else if (n == -1)
err(1, "header read");
else
errx(1, CORRUPT);
}
if (ntohl((uint32_t)cat_hdr.__magic) != _NLS_MAGIC)
errx(1, "%s: bad magic number (%#x)", CORRUPT, cat_hdr.__magic);
cat_hdr.__mem = ntohl(cat_hdr.__mem);
cat_hdr.__nsets = ntohl(cat_hdr.__nsets);
cat_hdr.__msg_hdr_offset = ntohl(cat_hdr.__msg_hdr_offset);
cat_hdr.__msg_txt_offset = ntohl(cat_hdr.__msg_txt_offset);
if ((cat_hdr.__mem < 0) ||
(cat_hdr.__msg_hdr_offset < 0) ||
(cat_hdr.__msg_txt_offset < 0) ||
(cat_hdr.__mem < (int32_t)(cat_hdr.__nsets * sizeof(struct _nls_set_hdr))) ||
(cat_hdr.__mem < cat_hdr.__msg_hdr_offset) ||
(cat_hdr.__mem < cat_hdr.__msg_txt_offset))
errx(1, "%s: catalog header", CORRUPT);
msgcat = xmalloc(cat_hdr.__mem);
n = read(fd, msgcat, cat_hdr.__mem);
if (n < cat_hdr.__mem) {
if (n == -1)
err(1, "data read");
else
errx(1, CORRUPT);
}
set_hdr = (struct _nls_set_hdr *)msgcat;
msg_hdr = (struct _nls_msg_hdr *)((char *)msgcat +
cat_hdr.__msg_hdr_offset);
strings = (char *)msgcat + cat_hdr.__msg_txt_offset;
setno = 0;
for (s = 0; s < cat_hdr.__nsets; s++, set_hdr++) {
set_hdr->__setno = ntohl(set_hdr->__setno);
if (set_hdr->__setno < setno)
errx(1, "%s: bad set number (%d)",
CORRUPT, set_hdr->__setno);
setno = set_hdr->__setno;
MCAddSet(setno);
set_hdr->__nmsgs = ntohl(set_hdr->__nmsgs);
set_hdr->__index = ntohl(set_hdr->__index);
if (set_hdr->__nmsgs < 0 || set_hdr->__index < 0)
errx(1, "%s: set header", CORRUPT);
/* Get the data */
msgno = 0;
for (m = 0; m < set_hdr->__nmsgs; m++, msg_hdr++) {
msg_hdr->__msgno = ntohl(msg_hdr->__msgno);
msg_hdr->__offset = ntohl(msg_hdr->__offset);
if (msg_hdr->__msgno < msgno)
errx(1, "%s: bad message number (%d)",
CORRUPT, msg_hdr->__msgno);
if ((msg_hdr->__offset < 0) ||
((strings + msg_hdr->__offset) >
((char *)msgcat + cat_hdr.__mem)))
errx(1, "%s: message header", CORRUPT);
msgno = msg_hdr->__msgno;
MCAddMsg(msgno, strings + msg_hdr->__offset);
}
}
free(msgcat);
}
/*
* Write message catalog.
*
* The message catalog is first converted from its internal to its
* external representation in a chunk of memory allocated for this
* purpose. Then the completed catalog is written. This approach
* avoids additional housekeeping variables and/or a lot of seeks
* that would otherwise be required.
*/
static void
MCWriteCat(int fd)
{
int nsets; /* number of sets */
int nmsgs; /* number of msgs */
int string_size; /* total size of string pool */
int msgcat_size; /* total size of message catalog */
void *msgcat; /* message catalog data */
struct _nls_cat_hdr *cat_hdr;
struct _nls_set_hdr *set_hdr;
struct _nls_msg_hdr *msg_hdr;
char *strings;
struct _setT *set;
struct _msgT *msg;
int msg_index;
int msg_offset;
/* determine number of sets, number of messages, and size of the
* string pool */
nsets = 0;
nmsgs = 0;
string_size = 0;
LIST_FOREACH(set, &sethead, entries) {
nsets++;
LIST_FOREACH(msg, &set->msghead, entries) {
nmsgs++;
string_size += strlen(msg->str) + 1;
}
}
#ifdef DEBUG
printf("number of sets: %d\n", nsets);
printf("number of msgs: %d\n", nmsgs);
printf("string pool size: %d\n", string_size);
#endif
/* determine size and then allocate buffer for constructing external
* message catalog representation */
msgcat_size = sizeof(struct _nls_cat_hdr)
+ (nsets * sizeof(struct _nls_set_hdr))
+ (nmsgs * sizeof(struct _nls_msg_hdr))
+ string_size;
msgcat = xmalloc(msgcat_size);
memset(msgcat, '\0', msgcat_size);
/* fill in msg catalog header */
cat_hdr = (struct _nls_cat_hdr *) msgcat;
cat_hdr->__magic = htonl(_NLS_MAGIC);
cat_hdr->__nsets = htonl(nsets);
cat_hdr->__mem = htonl(msgcat_size - sizeof(struct _nls_cat_hdr));
cat_hdr->__msg_hdr_offset =
htonl(nsets * sizeof(struct _nls_set_hdr));
cat_hdr->__msg_txt_offset =
htonl(nsets * sizeof(struct _nls_set_hdr) +
nmsgs * sizeof(struct _nls_msg_hdr));
/* compute offsets for set & msg header tables and string pool */
set_hdr = (struct _nls_set_hdr *) ((char *) msgcat +
sizeof(struct _nls_cat_hdr));
msg_hdr = (struct _nls_msg_hdr *) ((char *) msgcat +
sizeof(struct _nls_cat_hdr) +
nsets * sizeof(struct _nls_set_hdr));
strings = (char *) msgcat +
sizeof(struct _nls_cat_hdr) +
nsets * sizeof(struct _nls_set_hdr) +
nmsgs * sizeof(struct _nls_msg_hdr);
msg_index = 0;
msg_offset = 0;
LIST_FOREACH(set, &sethead, entries) {
nmsgs = 0;
LIST_FOREACH(msg, &set->msghead, entries) {
int32_t msg_len = strlen(msg->str) + 1;
msg_hdr->__msgno = htonl(msg->msgId);
msg_hdr->__msglen = htonl(msg_len);
msg_hdr->__offset = htonl(msg_offset);
memcpy(strings, msg->str, msg_len);
strings += msg_len;
msg_offset += msg_len;
nmsgs++;
msg_hdr++;
}
set_hdr->__setno = htonl(set->setId);
set_hdr->__nmsgs = htonl(nmsgs);
set_hdr->__index = htonl(msg_index);
msg_index += nmsgs;
set_hdr++;
}
/* write out catalog. XXX: should this be done in small chunks? */
write(fd, msgcat, msgcat_size);
}
static void
MCAddSet(int setId)
{
struct _setT *p, *q;
if (setId <= 0) {
error("setId's must be greater than zero");
/* NOTREACHED */
}
if (setId > NL_SETMAX) {
error("setId exceeds limit");
/* NOTREACHED */
}
p = LIST_FIRST(&sethead);
q = NULL;
for (; p != NULL && p->setId < setId; q = p, p = LIST_NEXT(p, entries))
continue;
if (p && p->setId == setId) {
;
} else {
p = xmalloc(sizeof(struct _setT));
memset(p, '\0', sizeof(struct _setT));
LIST_INIT(&p->msghead);
p->setId = setId;
if (q == NULL) {
LIST_INSERT_HEAD(&sethead, p, entries);
} else {
LIST_INSERT_AFTER(q, p, entries);
}
}
curSet = p;
}
static void
MCAddMsg(int msgId, const char *str)
{
struct _msgT *p, *q;
if (!curSet)
error("can't specify a message when no set exists");
if (msgId <= 0) {
error("msgId's must be greater than zero");
/* NOTREACHED */
}
if (msgId > NL_MSGMAX) {
error("msgID exceeds limit");
/* NOTREACHED */
}
p = LIST_FIRST(&curSet->msghead);
q = NULL;
for (; p != NULL && p->msgId < msgId; q = p, p = LIST_NEXT(p, entries))
continue;
if (p && p->msgId == msgId) {
free(p->str);
} else {
p = xmalloc(sizeof(struct _msgT));
memset(p, '\0', sizeof(struct _msgT));
if (q == NULL) {
LIST_INSERT_HEAD(&curSet->msghead, p, entries);
} else {
LIST_INSERT_AFTER(q, p, entries);
}
}
p->msgId = msgId;
p->str = xstrdup(str);
}
static void
MCDelSet(int setId)
{
struct _setT *set;
struct _msgT *msg;
if (setId <= 0) {
error("setId's must be greater than zero");
/* NOTREACHED */
}
if (setId > NL_SETMAX) {
error("setId exceeds limit");
/* NOTREACHED */
}
set = LIST_FIRST(&sethead);
for (; set != NULL && set->setId < setId; set = LIST_NEXT(set, entries))
continue;
if (set && set->setId == setId) {
LIST_REMOVE(set, entries);
while ((msg = LIST_FIRST(&set->msghead)) != NULL) {
LIST_REMOVE(msg, entries);
free(msg->str);
free(msg);
}
free(set);
return;
}
warning(NULL, "specified set doesn't exist");
}
static void
MCDelMsg(int msgId)
{
struct _msgT *msg;
if (!curSet)
error("you can't delete a message before defining the set");
msg = LIST_FIRST(&curSet->msghead);
for (; msg != NULL && msg->msgId < msgId; msg = LIST_NEXT(msg, entries))
continue;
if (msg && msg->msgId == msgId) {
LIST_REMOVE(msg, entries);
free(msg->str);
free(msg);
return;
}
warning(NULL, "specified msg doesn't exist");
}

11
usr.bin/locale/Makefile Normal file
View File

@@ -0,0 +1,11 @@
# $NetBSD: Makefile,v 1.4 2012/01/20 16:31:30 joerg Exp $
# FreeBSD: src/usr.bin/locale/Makefile,v 1.4 2003/06/25 23:05:11 phantom Exp
WARNS?= 2 # XXX -Wcast-qual issues
PROG = locale
CPPFLAGS+= -I${NETBSDSRCDIR}/lib/libc/locale
CPPFLAGS+= -I${NETBSDSRCDIR}/lib/libc/citrus
.include <bsd.prog.mk>

113
usr.bin/locale/locale.1 Normal file
View File

@@ -0,0 +1,113 @@
.\" $NetBSD: locale.1,v 1.2 2003/07/04 07:28:14 wiz Exp $
.\"
.\" Copyright (c) 2003 Alexey Zelkin <phantom@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" FreeBSD: src/usr.bin/locale/locale.1,v 1.3 2003/06/26 11:01:03 phantom Exp
.\"
.Dd July 4, 2003
.Dt LOCALE 1
.Os
.Sh NAME
.Nm locale
.Nd get locale-specific information
.Sh SYNOPSIS
.Nm
.Op Fl a | Fl m
.Nm
.Op Fl ck
.Op Ar keyword ...
.Sh DESCRIPTION
The
.Nm
utility is supposed to provide most locale specific information to
the standard output.
.Pp
When
.Nm
is invoked without arguments it will print out a summary of the
current locale environment depending on environment variable settings
and internal status.
.Pp
When
.Nm
is invoked with arguments and no options specified it will print out
.Em keyword Ns No 's
value determined using current locale settings.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl a
Write names of all available locales.
While looking for locales
.Nm
will respect the
.Ev PATH_LOCALE
environment variable, and use it instead of the system default
locale directory.
.It Fl c
Write the category name for the selected keywords.
.It Fl k
Write the name and value of the selected keywords.
.It Fl m
Write names of all available charmaps.
.El
.Sh IMPLEMENTATION DETAILS
Special
.Pf ( Fx Ns -
/
.Nx Ns -specific )
keyword
.Ar list
can be used to retrieve a human readable list of available keywords.
.Sh DIAGNOSTICS
.Ex -std locale
.Sh STANDARDS
.Nm
conforms to
.St -p1003.1-2001 .
.Sh HISTORY
.Nm
first appeared in
.Nx 2.0 .
.Sh AUTHORS
This implementation of
.Nm
was originally written by
.An Alexey Zelkin
.Aq phantom@FreeBSD.org
for
.Fx .
.Sh BUGS
Since
.Nx
does not support
.Em charmap Ns No s
in their
.Em POSIX
meaning
.Nm
emulates the
.Fl m
option via CODESETs listing of all available locales.

707
usr.bin/locale/locale.c Normal file
View File

@@ -0,0 +1,707 @@
/* $NetBSD: locale.c,v 1.8 2012/01/20 16:31:30 joerg Exp $ */
/*-
* Copyright (c) 2002, 2003 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* FreeBSD: src/usr.bin/locale/locale.c,v 1.10 2003/06/26 11:05:56 phantom Exp
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: locale.c,v 1.8 2012/01/20 16:31:30 joerg Exp $");
#endif /* LIBC_SCCS and not lint */
/*
* XXX: implement missing era_* (LC_TIME) keywords (require libc &
* nl_langinfo(3) extensions)
*
* XXX: correctly handle reserved 'charmap' keyword and '-m' option (require
* localedef(1) implementation). Currently it's handled via
* nl_langinfo(CODESET).
*/
#include <sys/types.h>
#include <assert.h>
#include <dirent.h>
#include <err.h>
#include <locale.h>
#include <langinfo.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include "citrus_namespace.h"
#include "citrus_region.h"
#include "citrus_lookup.h"
#include "setlocale_local.h"
/* Local prototypes */
void init_locales_list(void);
void init_locales_list_alias(void);
void list_charmaps(void);
void list_locales(void);
const char *lookup_localecat(int);
char *kwval_lconv(int);
int kwval_lookup(char *, char **, int *, int *);
void showdetails(char *);
void showkeywordslist(void);
void showlocale(void);
void usage(void);
/* Global variables */
static StringList *locales = NULL;
int all_locales = 0;
int all_charmaps = 0;
int prt_categories = 0;
int prt_keywords = 0;
int more_params = 0;
struct _lcinfo {
const char *name;
int id;
} lcinfo [] = {
{ "LC_CTYPE", LC_CTYPE },
{ "LC_COLLATE", LC_COLLATE },
{ "LC_TIME", LC_TIME },
{ "LC_NUMERIC", LC_NUMERIC },
{ "LC_MONETARY", LC_MONETARY },
{ "LC_MESSAGES", LC_MESSAGES }
};
#define NLCINFO (sizeof(lcinfo)/sizeof(lcinfo[0]))
/* ids for values not referenced by nl_langinfo() */
#define KW_ZERO 10000
#define KW_GROUPING (KW_ZERO+1)
#define KW_INT_CURR_SYMBOL (KW_ZERO+2)
#define KW_CURRENCY_SYMBOL (KW_ZERO+3)
#define KW_MON_DECIMAL_POINT (KW_ZERO+4)
#define KW_MON_THOUSANDS_SEP (KW_ZERO+5)
#define KW_MON_GROUPING (KW_ZERO+6)
#define KW_POSITIVE_SIGN (KW_ZERO+7)
#define KW_NEGATIVE_SIGN (KW_ZERO+8)
#define KW_INT_FRAC_DIGITS (KW_ZERO+9)
#define KW_FRAC_DIGITS (KW_ZERO+10)
#define KW_P_CS_PRECEDES (KW_ZERO+11)
#define KW_P_SEP_BY_SPACE (KW_ZERO+12)
#define KW_N_CS_PRECEDES (KW_ZERO+13)
#define KW_N_SEP_BY_SPACE (KW_ZERO+14)
#define KW_P_SIGN_POSN (KW_ZERO+15)
#define KW_N_SIGN_POSN (KW_ZERO+16)
#define KW_INT_P_CS_PRECEDES (KW_ZERO+17)
#define KW_INT_P_SEP_BY_SPACE (KW_ZERO+18)
#define KW_INT_N_CS_PRECEDES (KW_ZERO+19)
#define KW_INT_N_SEP_BY_SPACE (KW_ZERO+20)
#define KW_INT_P_SIGN_POSN (KW_ZERO+21)
#define KW_INT_N_SIGN_POSN (KW_ZERO+22)
struct _kwinfo {
const char *name;
int isstr; /* true - string, false - number */
int catid; /* LC_* */
int value_ref;
const char *comment;
} kwinfo [] = {
{ "charmap", 1, LC_CTYPE, CODESET, "" }, /* hack */
{ "decimal_point", 1, LC_NUMERIC, RADIXCHAR, "" },
{ "thousands_sep", 1, LC_NUMERIC, THOUSEP, "" },
{ "grouping", 1, LC_NUMERIC, KW_GROUPING, "" },
{ "radixchar", 1, LC_NUMERIC, RADIXCHAR,
"Same as decimal_point (BSD only)" }, /* compat */
{ "thousep", 1, LC_NUMERIC, THOUSEP,
"Same as thousands_sep (BSD only)" }, /* compat */
{ "int_curr_symbol", 1, LC_MONETARY, KW_INT_CURR_SYMBOL, "" },
{ "currency_symbol", 1, LC_MONETARY, KW_CURRENCY_SYMBOL, "" },
{ "mon_decimal_point", 1, LC_MONETARY, KW_MON_DECIMAL_POINT, "" },
{ "mon_thousands_sep", 1, LC_MONETARY, KW_MON_THOUSANDS_SEP, "" },
{ "mon_grouping", 1, LC_MONETARY, KW_MON_GROUPING, "" },
{ "positive_sign", 1, LC_MONETARY, KW_POSITIVE_SIGN, "" },
{ "negative_sign", 1, LC_MONETARY, KW_NEGATIVE_SIGN, "" },
{ "int_frac_digits", 0, LC_MONETARY, KW_INT_FRAC_DIGITS, "" },
{ "frac_digits", 0, LC_MONETARY, KW_FRAC_DIGITS, "" },
{ "p_cs_precedes", 0, LC_MONETARY, KW_P_CS_PRECEDES, "" },
{ "p_sep_by_space", 0, LC_MONETARY, KW_P_SEP_BY_SPACE, "" },
{ "n_cs_precedes", 0, LC_MONETARY, KW_N_CS_PRECEDES, "" },
{ "n_sep_by_space", 0, LC_MONETARY, KW_N_SEP_BY_SPACE, "" },
{ "p_sign_posn", 0, LC_MONETARY, KW_P_SIGN_POSN, "" },
{ "n_sign_posn", 0, LC_MONETARY, KW_N_SIGN_POSN, "" },
{ "int_p_cs_precedes", 0, LC_MONETARY, KW_INT_P_CS_PRECEDES, "" },
{ "int_p_sep_by_space", 0, LC_MONETARY, KW_INT_P_SEP_BY_SPACE, "" },
{ "int_n_cs_precedes", 0, LC_MONETARY, KW_INT_N_CS_PRECEDES, "" },
{ "int_n_sep_by_space", 0, LC_MONETARY, KW_INT_N_SEP_BY_SPACE, "" },
{ "int_p_sign_posn", 0, LC_MONETARY, KW_INT_P_SIGN_POSN, "" },
{ "int_n_sign_posn", 0, LC_MONETARY, KW_INT_N_SIGN_POSN, "" },
{ "d_t_fmt", 1, LC_TIME, D_T_FMT, "" },
{ "d_fmt", 1, LC_TIME, D_FMT, "" },
{ "t_fmt", 1, LC_TIME, T_FMT, "" },
{ "am_str", 1, LC_TIME, AM_STR, "" },
{ "pm_str", 1, LC_TIME, PM_STR, "" },
{ "t_fmt_ampm", 1, LC_TIME, T_FMT_AMPM, "" },
{ "day_1", 1, LC_TIME, DAY_1, "" },
{ "day_2", 1, LC_TIME, DAY_2, "" },
{ "day_3", 1, LC_TIME, DAY_3, "" },
{ "day_4", 1, LC_TIME, DAY_4, "" },
{ "day_5", 1, LC_TIME, DAY_5, "" },
{ "day_6", 1, LC_TIME, DAY_6, "" },
{ "day_7", 1, LC_TIME, DAY_7, "" },
{ "abday_1", 1, LC_TIME, ABDAY_1, "" },
{ "abday_2", 1, LC_TIME, ABDAY_2, "" },
{ "abday_3", 1, LC_TIME, ABDAY_3, "" },
{ "abday_4", 1, LC_TIME, ABDAY_4, "" },
{ "abday_5", 1, LC_TIME, ABDAY_5, "" },
{ "abday_6", 1, LC_TIME, ABDAY_6, "" },
{ "abday_7", 1, LC_TIME, ABDAY_7, "" },
{ "mon_1", 1, LC_TIME, MON_1, "" },
{ "mon_2", 1, LC_TIME, MON_2, "" },
{ "mon_3", 1, LC_TIME, MON_3, "" },
{ "mon_4", 1, LC_TIME, MON_4, "" },
{ "mon_5", 1, LC_TIME, MON_5, "" },
{ "mon_6", 1, LC_TIME, MON_6, "" },
{ "mon_7", 1, LC_TIME, MON_7, "" },
{ "mon_8", 1, LC_TIME, MON_8, "" },
{ "mon_9", 1, LC_TIME, MON_9, "" },
{ "mon_10", 1, LC_TIME, MON_10, "" },
{ "mon_11", 1, LC_TIME, MON_11, "" },
{ "mon_12", 1, LC_TIME, MON_12, "" },
{ "abmon_1", 1, LC_TIME, ABMON_1, "" },
{ "abmon_2", 1, LC_TIME, ABMON_2, "" },
{ "abmon_3", 1, LC_TIME, ABMON_3, "" },
{ "abmon_4", 1, LC_TIME, ABMON_4, "" },
{ "abmon_5", 1, LC_TIME, ABMON_5, "" },
{ "abmon_6", 1, LC_TIME, ABMON_6, "" },
{ "abmon_7", 1, LC_TIME, ABMON_7, "" },
{ "abmon_8", 1, LC_TIME, ABMON_8, "" },
{ "abmon_9", 1, LC_TIME, ABMON_9, "" },
{ "abmon_10", 1, LC_TIME, ABMON_10, "" },
{ "abmon_11", 1, LC_TIME, ABMON_11, "" },
{ "abmon_12", 1, LC_TIME, ABMON_12, "" },
{ "era", 1, LC_TIME, ERA, "(unavailable)" },
{ "era_d_fmt", 1, LC_TIME, ERA_D_FMT, "(unavailable)" },
{ "era_d_t_fmt", 1, LC_TIME, ERA_D_T_FMT, "(unavailable)" },
{ "era_t_fmt", 1, LC_TIME, ERA_T_FMT, "(unavailable)" },
{ "alt_digits", 1, LC_TIME, ALT_DIGITS, "" },
{ "yesexpr", 1, LC_MESSAGES, YESEXPR, "" },
{ "noexpr", 1, LC_MESSAGES, NOEXPR, "" },
{ "yesstr", 1, LC_MESSAGES, YESSTR,
"(POSIX legacy)" }, /* compat */
{ "nostr", 1, LC_MESSAGES, NOSTR,
"(POSIX legacy)" } /* compat */
};
#define NKWINFO (sizeof(kwinfo)/sizeof(kwinfo[0]))
int
main(int argc, char *argv[])
{
int ch;
int tmp;
while ((ch = getopt(argc, argv, "ackm")) != -1) {
switch (ch) {
case 'a':
all_locales = 1;
break;
case 'c':
prt_categories = 1;
break;
case 'k':
prt_keywords = 1;
break;
case 'm':
all_charmaps = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
/* validate arguments */
if (all_locales && all_charmaps)
usage();
if ((all_locales || all_charmaps) && argc > 0)
usage();
if ((all_locales || all_charmaps) && (prt_categories || prt_keywords))
usage();
if ((prt_categories || prt_keywords) && argc <= 0)
usage();
/* process '-a' */
if (all_locales) {
list_locales();
exit(0);
}
/* process '-m' */
if (all_charmaps) {
list_charmaps();
exit(0);
}
/* check for special case '-k list' */
tmp = 0;
if (prt_keywords && argc > 0)
while (tmp < argc)
if (strcasecmp(argv[tmp++], "list") == 0) {
showkeywordslist();
exit(0);
}
/* process '-c' and/or '-k' */
if (prt_categories || prt_keywords || argc > 0) {
setlocale(LC_ALL, "");
while (argc > 0) {
showdetails(*argv);
argv++;
argc--;
}
exit(0);
}
/* no arguments, show current locale state */
showlocale();
return (0);
}
void
usage(void)
{
printf("usage: locale [ -a | -m ]\n"
" locale [ -ck ] name ...\n");
exit(1);
}
/*
* Output information about all available locales
*
* XXX actually output of this function does not guarantee that locale
* is really available to application, since it can be broken or
* inconsistent thus setlocale() will fail. Maybe add '-V' function to
* also validate these locales?
*/
void
list_locales(void)
{
size_t i;
init_locales_list();
for (i = 0; i < locales->sl_cur; i++) {
printf("%s\n", locales->sl_str[i]);
}
}
/*
* qsort() helper function
*/
static int
scmp(const void *s1, const void *s2)
{
return strcmp(*(const char **)s1, *(const char **)s2);
}
/*
* Output information about all available charmaps
*
* XXX this function is doing a task in hackish way, i.e. by scaning
* list of locales, spliting their codeset part and building list of
* them.
*/
void
list_charmaps(void)
{
size_t i;
char *s, *cs;
StringList *charmaps;
/* initialize StringList */
charmaps = sl_init();
if (charmaps == NULL)
err(1, "could not allocate memory");
/* fetch locales list */
init_locales_list();
/* split codesets and build their list */
for (i = 0; i < locales->sl_cur; i++) {
s = locales->sl_str[i];
if ((cs = strchr(s, '.')) != NULL) {
cs++;
if (sl_find(charmaps, cs) == NULL)
sl_add(charmaps, cs);
}
}
/* add US-ASCII, if not yet added */
if (sl_find(charmaps, "US-ASCII") == NULL)
sl_add(charmaps, "US-ASCII");
/* sort the list */
qsort(charmaps->sl_str, charmaps->sl_cur, sizeof(char *), scmp);
/* print results */
for (i = 0; i < charmaps->sl_cur; i++) {
printf("%s\n", charmaps->sl_str[i]);
}
}
/*
* Retrieve sorted list of system locales (or user locales, if PATH_LOCALE
* environment variable is set)
*/
void
init_locales_list(void)
{
DIR *dirp;
struct dirent *dp;
char *s;
/* why call this function twice ? */
if (locales != NULL)
return;
/* initialize StringList */
locales = sl_init();
if (locales == NULL)
err(1, "could not allocate memory");
/* get actual locales directory name */
setlocale(LC_CTYPE, "C");
if (_PathLocale == NULL)
errx(1, "unable to find locales storage");
/* open locales directory */
dirp = opendir(_PathLocale);
if (dirp == NULL)
err(1, "could not open directory '%s'", _PathLocale);
/* scan directory and store its contents except "." and ".." */
while ((dp = readdir(dirp)) != NULL) {
/* exclude "." and "..", _LOCALE_ALIAS_NAME */
if ((dp->d_name[0] != '.' || (dp->d_name[1] != '\0' &&
(dp->d_name[1] != '.' || dp->d_name[2] != '\0'))) &&
strcmp(_LOCALE_ALIAS_NAME, dp->d_name) != 0) {
s = strdup(dp->d_name);
if (s == NULL)
err(1, "could not allocate memory");
sl_add(locales, s);
}
}
closedir(dirp);
/* make sure that 'POSIX' and 'C' locales are present in the list.
* POSIX 1003.1-2001 requires presence of 'POSIX' name only here, but
* we also list 'C' for constistency
*/
if (sl_find(locales, "POSIX") == NULL)
sl_add(locales, "POSIX");
if (sl_find(locales, "C") == NULL)
sl_add(locales, "C");
init_locales_list_alias();
/* make output nicer, sort the list */
qsort(locales->sl_str, locales->sl_cur, sizeof(char *), scmp);
}
void
init_locales_list_alias(void)
{
char aliaspath[PATH_MAX];
struct _lookup *hlookup;
struct _region key, dat;
size_t n;
char *s, *t;
_DIAGASSERT(locales != NULL);
_DIAGASSERT(_PathLocale != NULL);
(void)snprintf(aliaspath, sizeof(aliaspath),
"%s/" _LOCALE_ALIAS_NAME, _PathLocale);
if (_lookup_seq_open(&hlookup, aliaspath,
_LOOKUP_CASE_SENSITIVE) == 0) {
while (_lookup_seq_next(hlookup, &key, &dat) == 0) {
n = _region_size((const struct _region *)&key);
s = _region_head((const struct _region *)&key);
for (t = s; n > 0 && *s!= '/'; --n, ++s);
n = (size_t)(s - t);
s = malloc(n + 1);
if (s == NULL)
err(1, "could not allocate memory");
memcpy(s, t, n);
s[n] = '\0';
if (sl_find(locales, s) == NULL)
sl_add(locales, s);
else
free(s);
}
_lookup_seq_close(hlookup);
}
}
/*
* Show current locale status, depending on environment variables
*/
void
showlocale(void)
{
size_t i;
const char *lang, *vval, *eval;
setlocale(LC_ALL, "");
lang = getenv("LANG");
if (lang == NULL) {
lang = "";
}
printf("LANG=\"%s\"\n", lang);
/* XXX: if LANG is null, then set it to "C" to get implied values? */
for (i = 0; i < NLCINFO; i++) {
vval = setlocale(lcinfo[i].id, NULL);
eval = getenv(lcinfo[i].name);
if (eval != NULL && !strcmp(eval, vval)
&& strcmp(lang, vval)) {
/*
* Appropriate environment variable set, its value
* is valid and not overriden by LC_ALL
*
* XXX: possible side effect: if both LANG and
* overriden environment variable are set into same
* value, then it'll be assumed as 'implied'
*/
printf("%s=\"%s\"\n", lcinfo[i].name, vval);
} else {
printf("%s=\"%s\"\n", lcinfo[i].name, vval);
}
}
vval = getenv("LC_ALL");
if (vval == NULL) {
vval = "";
}
printf("LC_ALL=\"%s\"\n", vval);
}
/*
* keyword value lookup helper (via localeconv())
*/
char *
kwval_lconv(int id)
{
struct lconv *lc;
char *rval;
rval = NULL;
lc = localeconv();
switch (id) {
case KW_GROUPING:
rval = lc->grouping;
break;
case KW_INT_CURR_SYMBOL:
rval = lc->int_curr_symbol;
break;
case KW_CURRENCY_SYMBOL:
rval = lc->currency_symbol;
break;
case KW_MON_DECIMAL_POINT:
rval = lc->mon_decimal_point;
break;
case KW_MON_THOUSANDS_SEP:
rval = lc->mon_thousands_sep;
break;
case KW_MON_GROUPING:
rval = lc->mon_grouping;
break;
case KW_POSITIVE_SIGN:
rval = lc->positive_sign;
break;
case KW_NEGATIVE_SIGN:
rval = lc->negative_sign;
break;
case KW_INT_FRAC_DIGITS:
rval = &(lc->int_frac_digits);
break;
case KW_FRAC_DIGITS:
rval = &(lc->frac_digits);
break;
case KW_P_CS_PRECEDES:
rval = &(lc->p_cs_precedes);
break;
case KW_P_SEP_BY_SPACE:
rval = &(lc->p_sep_by_space);
break;
case KW_N_CS_PRECEDES:
rval = &(lc->n_cs_precedes);
break;
case KW_N_SEP_BY_SPACE:
rval = &(lc->n_sep_by_space);
break;
case KW_P_SIGN_POSN:
rval = &(lc->p_sign_posn);
break;
case KW_N_SIGN_POSN:
rval = &(lc->n_sign_posn);
break;
case KW_INT_P_CS_PRECEDES:
rval = &(lc->int_p_cs_precedes);
break;
case KW_INT_P_SEP_BY_SPACE:
rval = &(lc->int_p_sep_by_space);
break;
case KW_INT_N_CS_PRECEDES:
rval = &(lc->int_n_cs_precedes);
break;
case KW_INT_N_SEP_BY_SPACE:
rval = &(lc->int_n_sep_by_space);
break;
case KW_INT_P_SIGN_POSN:
rval = &(lc->int_p_sign_posn);
break;
case KW_INT_N_SIGN_POSN:
rval = &(lc->int_n_sign_posn);
break;
default:
break;
}
return (rval);
}
/*
* keyword value and properties lookup
*/
int
kwval_lookup(char *kwname, char **kwval, int *cat, int *isstr)
{
int rval;
size_t i;
rval = 0;
for (i = 0; i < NKWINFO; i++) {
if (strcasecmp(kwname, kwinfo[i].name) == 0) {
rval = 1;
*cat = kwinfo[i].catid;
*isstr = kwinfo[i].isstr;
if (kwinfo[i].value_ref < KW_ZERO) {
*kwval = nl_langinfo(kwinfo[i].value_ref);
} else {
*kwval = kwval_lconv(kwinfo[i].value_ref);
}
break;
}
}
return (rval);
}
/*
* Show details about requested keyword according to '-k' and/or '-c'
* command line options specified.
*/
void
showdetails(char *kw)
{
int isstr, cat, tmpval;
char *kwval;
if (kwval_lookup(kw, &kwval, &cat, &isstr) == 0) {
/*
* invalid keyword specified.
* XXX: any actions?
*/
return;
}
if (prt_categories) {
printf("%s\n", lookup_localecat(cat));
}
if (prt_keywords) {
if (isstr) {
printf("%s=\"%s\"\n", kw, kwval);
} else {
tmpval = (char) *kwval;
printf("%s=%d\n", kw, tmpval);
}
}
if (!prt_categories && !prt_keywords) {
if (isstr) {
printf("%s\n", kwval);
} else {
tmpval = (char) *kwval;
printf("%d\n", tmpval);
}
}
}
/*
* Convert locale category id into string
*/
const char *
lookup_localecat(int cat)
{
size_t i;
for (i = 0; i < NLCINFO; i++)
if (lcinfo[i].id == cat) {
return (lcinfo[i].name);
}
return ("UNKNOWN");
}
/*
* Show list of keywords
*/
void
showkeywordslist(void)
{
size_t i;
#define FMT "%-20s %-12s %-7s %-20s\n"
printf("List of available keywords\n\n");
printf(FMT, "Keyword", "Category", "Type", "Comment");
printf("-------------------- ------------ ------- --------------------\n");
for (i = 0; i < NKWINFO; i++) {
printf(FMT,
kwinfo[i].name,
lookup_localecat(kwinfo[i].catid),
(kwinfo[i].isstr == 0) ? "number" : "string",
kwinfo[i].comment);
}
}

View File

@@ -0,0 +1,23 @@
# $NetBSD: Makefile,v 1.7 2009/10/29 14:37:16 christos Exp $
NOMAN=# defined (must come before bsd.own.mk)
.ifndef HOSTPROG
.include <bsd.own.mk>
.endif
.PATH: ${NETBSDSRCDIR}/lib/libc/citrus
PROG= mkcsmapper
SRCS= yacc.y lex.l \
citrus_db_factory.c citrus_bcs.c citrus_db_hash.c \
citrus_lookup_factory.c citrus_pivot_factory.c
CPPFLAGS+= -I. -I${.CURDIR} -I${NETBSDSRCDIR}/lib/libc \
-I${NETBSDSRCDIR}/lib/libc/citrus \
-I${NETBSDSRCDIR}/lib/libc/citrus/modules \
-DHOSTPROG -DLIBC_SCCS
YHEADER= 1
.ifndef HOSTPROG
.include <bsd.prog.mk>
.endif

40
usr.bin/mkcsmapper/ldef.h Normal file
View File

@@ -0,0 +1,40 @@
/* $NetBSD: ldef.h,v 1.2 2006/09/09 14:35:17 tnozaki Exp $ */
/*-
* Copyright (c)2003, 2006 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
typedef struct {
u_int32_t begin;
u_int32_t end;
u_int32_t width;
} linear_zone_t;
extern int line_number;
extern int debug;
extern FILE *yyin;
extern int yyparse(void);
extern int yylex(void);
extern int yyerror(const char *);

113
usr.bin/mkcsmapper/lex.l Normal file
View File

@@ -0,0 +1,113 @@
/* $NetBSD: lex.l,v 1.6 2009/10/29 14:37:16 christos Exp $ */
%{
/*-
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: lex.l,v 1.6 2009/10/29 14:37:16 christos Exp $");
#endif /* not lint */
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <machine/endian.h>
#include "ldef.h"
#include "yacc.h"
int line_number = 1;
%}
%option noinput nounput
%x COMMENT
%%
[ \t]+ { }
#.*[\n]|"//".*[\n]|[\n] { line_number++; return (R_LN); }
"/*" { BEGIN COMMENT; }
<COMMENT>"*/" { BEGIN 0; }
<COMMENT>[\n] { line_number++; }
<COMMENT>. { }
<COMMENT><<EOF>> {
yyerror("unexpected file end (unterminate comment)\n");
exit(1);
}
"="|"/"|"-" { return (int)yytext[0]; }
([1-9][0-9]*)|(0[0-9]*)|(0[xX][0-9A-Fa-f]+) {
yylval.i_value = strtoul(yytext, NULL, 0);
return L_IMM;
}
"TYPE" { return (R_TYPE); }
"NAME" { return (R_NAME); }
"SRC_ZONE" { return (R_SRC_ZONE); }
"DST_INVALID" { return (R_DST_INVALID); }
"DST_ILSEQ" { return (R_DST_ILSEQ); }
"DST_UNIT_BITS" { return (R_DST_UNIT_BITS); }
"BEGIN_MAP" { return (R_BEGIN_MAP); }
"END_MAP" { return (R_END_MAP); }
"INVALID" { return (R_INVALID); }
"ILSEQ" { return (R_ILSEQ); }
"OOB_MODE" { return (R_OOB_MODE); }
"ROWCOL" { return (R_ROWCOL); }
\"([^\"\n]*(\\\")?)*\"|\'([^\'\n]*(\\\')?)*\' {
size_t len;
len = strlen(yytext);
yylval.s_value = malloc(len-1);
strlcpy(yylval.s_value, yytext+1, len-1);
return L_STRING;
}
[^ =/\-0-9\t\n][^ \t\n]* {
yylval.s_value = strdup(yytext);
return L_STRING;
}
%%
#ifndef yywrap
int
yywrap(void)
{
return (1);
}
#endif

734
usr.bin/mkcsmapper/yacc.y Normal file
View File

@@ -0,0 +1,734 @@
/* $NetBSD: yacc.y,v 1.10 2015/06/16 22:54:10 christos Exp $ */
%{
/*-
* Copyright (c)2003, 2006 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: yacc.y,v 1.10 2015/06/16 22:54:10 christos Exp $");
#endif /* not lint */
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include "ldef.h"
#ifndef __packed
#define __packed
#endif
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_mapper_std_file.h"
#include "citrus_region.h"
#include "citrus_db_factory.h"
#include "citrus_db_hash.h"
#include "citrus_lookup_factory.h"
#include "citrus_pivot_factory.h"
int debug = 0;
static char *output = NULL;
static void *table = NULL;
static size_t table_size;
static char *map_name;
static int map_type;
static u_int32_t dst_invalid, dst_ilseq, oob_mode, dst_unit_bits;
static void (*putfunc)(void *, size_t, u_int32_t) = 0;
static u_int32_t src_next;
static u_int32_t done_flag = 0;
#define DF_TYPE 0x00000001
#define DF_NAME 0x00000002
#define DF_SRC_ZONE 0x00000004
#define DF_DST_INVALID 0x00000008
#define DF_DST_ILSEQ 0x00000010
#define DF_DST_UNIT_BITS 0x00000020
#define DF_OOB_MODE 0x00000040
static linear_zone_t rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX];
static size_t rowcol_len = 0;
static u_int32_t rowcol_bits = 0, rowcol_mask = 0;
static void dump_file(void);
static void setup_map(void);
static void set_type(int);
static void set_name(char *);
static void set_src_zone(u_int32_t);
static void set_dst_invalid(u_int32_t);
static void set_dst_ilseq(u_int32_t);
static void set_dst_unit_bits(u_int32_t);
static void set_oob_mode(u_int32_t);
static int check_src(u_int32_t, u_int32_t);
static void store(const linear_zone_t *, u_int32_t, int);
static void put8(void *, size_t, u_int32_t);
static void put16(void *, size_t, u_int32_t);
static void put32(void *, size_t, u_int32_t);
static void set_range(u_int32_t, u_int32_t);
static void set_src(linear_zone_t *, u_int32_t, u_int32_t);
%}
%union {
u_int32_t i_value;
char *s_value;
linear_zone_t lz_value;
}
%token R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS
%token R_DST_INVALID R_DST_ILSEQ
%token R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL
%token R_ILSEQ R_OOB_MODE
%token R_LN
%token <i_value> L_IMM
%token <s_value> L_STRING
%type <lz_value> src
%type <i_value> dst types oob_mode_sel zone
%%
file : property mapping lns
{ dump_file(); }
property : /* empty */
| property R_LN
| property name
| property type
| property src_zone
| property dst_invalid
| property dst_ilseq
| property dst_unit_bits
| property oob_mode
name : R_NAME L_STRING { set_name($2); $2 = NULL; }
type : R_TYPE types { set_type($2); }
types : R_ROWCOL { $$ = R_ROWCOL; }
range : L_IMM '-' L_IMM { set_range($1, $3); }
ranges : /* empty */
| ranges range '/'
src_zone : R_SRC_ZONE zone { set_src_zone($2); }
zone : range {
$$ = 32;
}
| range '/' range '/' ranges L_IMM {
$$ = $6;
}
dst_invalid : R_DST_INVALID L_IMM { set_dst_invalid($2); }
dst_ilseq : R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
dst_unit_bits : R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
oob_mode : R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
oob_mode_sel : R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
| R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
mapping : begin_map map_elems R_END_MAP
begin_map : R_BEGIN_MAP lns { setup_map(); }
map_elems : /* empty */
| map_elems map_elem lns
map_elem : src '=' dst
{ store(&$1, $3, 0); }
| src '=' L_IMM '-'
{ store(&$1, $3, 1); }
dst : L_IMM
{
$$ = $1;
}
| R_INVALID
{
$$ = dst_invalid;
}
| R_ILSEQ
{
$$ = dst_ilseq;
}
src : /* empty */
{
set_src(&$$, src_next, src_next);
}
| L_IMM
{
set_src(&$$, $1, $1);
}
| L_IMM '-' L_IMM
{
set_src(&$$, $1, $3);
}
| '-' L_IMM
{
set_src(&$$, src_next, $2);
}
lns : R_LN
| lns R_LN
%%
static void
warning(const char *s)
{
fprintf(stderr, "%s in %d\n", s, line_number);
}
int
yyerror(const char *s)
{
warning(s);
exit(1);
}
void
put8(void *ptr, size_t ofs, u_int32_t val)
{
*((u_int8_t *)ptr + ofs) = val;
}
void
put16(void *ptr, size_t ofs, u_int32_t val)
{
u_int16_t oval = htons(val);
memcpy((u_int16_t *)ptr + ofs, &oval, 2);
}
void
put32(void *ptr, size_t ofs, u_int32_t val)
{
u_int32_t oval = htonl(val);
memcpy((u_int32_t *)ptr + ofs, &oval, 4);
}
static void
alloc_table(void)
{
size_t i;
u_int32_t val = 0;
linear_zone_t *p;
i = rowcol_len;
p = &rowcol[--i];
table_size = p->width;
while (i > 0) {
p = &rowcol[--i];
table_size *= p->width;
}
table = (void *)malloc(table_size * dst_unit_bits / 8);
if (table == NULL) {
perror("malloc");
exit(1);
}
switch (oob_mode) {
case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
val = dst_invalid;
break;
case _CITRUS_MAPPER_STD_OOB_ILSEQ:
val = dst_ilseq;
break;
default:
_DIAGASSERT(0);
}
for (i = 0; i < table_size; i++)
(*putfunc)(table, i, val);
}
static void
setup_map(void)
{
if ((done_flag & DF_SRC_ZONE)==0) {
fprintf(stderr, "SRC_ZONE is mandatory.\n");
exit(1);
}
if ((done_flag & DF_DST_UNIT_BITS)==0) {
fprintf(stderr, "DST_UNIT_BITS is mandatory.\n");
exit(1);
}
if ((done_flag & DF_DST_INVALID) == 0)
dst_invalid = 0xFFFFFFFF;
if ((done_flag & DF_DST_ILSEQ) == 0)
dst_ilseq = 0xFFFFFFFE;
if ((done_flag & DF_OOB_MODE) == 0)
oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
alloc_table();
}
static void
create_rowcol_info(struct _region *r)
{
void *ptr;
size_t ofs, i, len;
ofs = 0;
ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
if (ptr == NULL)
err(EXIT_FAILURE, "malloc");
put32(ptr, ofs, rowcol_bits); ofs++;
put32(ptr, ofs, dst_invalid); ofs++;
/* XXX: keep backward compatibility */
switch (rowcol_len) {
case 1:
put32(ptr, ofs, 0); ofs++;
put32(ptr, ofs, 0); ofs++;
/*FALLTHROUGH*/
case 2:
len = 0;
break;
default:
len = rowcol_len;
}
for (i = 0; i < rowcol_len; ++i) {
put32(ptr, ofs, rowcol[i].begin); ofs++;
put32(ptr, ofs, rowcol[i].end); ofs++;
}
put32(ptr, ofs, dst_unit_bits); ofs++;
put32(ptr, ofs, len); ofs++;
_region_init(r, ptr, ofs * 4);
}
static void
create_rowcol_ext_ilseq_info(struct _region *r)
{
void *ptr;
size_t ofs;
ofs = 0;
ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
if (ptr==NULL)
err(EXIT_FAILURE, "malloc");
put32(ptr, ofs, oob_mode); ofs++;
put32(ptr, ofs, dst_ilseq); ofs++;
_region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
}
#define CHKERR(ret, func, a) \
do { \
ret = func a; \
if (ret) \
errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret)); \
} while (/*CONSTCOND*/0)
static void
dump_file(void)
{
FILE *fp;
int ret;
struct _db_factory *df;
struct _region data;
void *serialized;
size_t size;
/*
* build database
*/
CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
/* store type */
CHKERR(ret, _db_factory_addstr_by_s,
(df, _CITRUS_MAPPER_STD_SYM_TYPE,
_CITRUS_MAPPER_STD_TYPE_ROWCOL));
/* store info */
create_rowcol_info(&data);
CHKERR(ret, _db_factory_add_by_s,
(df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1));
/* ilseq extension */
create_rowcol_ext_ilseq_info(&data);
CHKERR(ret, _db_factory_add_by_s,
(df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1));
/* store table */
_region_init(&data, table, table_size*dst_unit_bits/8);
CHKERR(ret, _db_factory_add_by_s,
(df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1));
/*
* dump database to file
*/
if (output)
fp = fopen(output, "wb");
else
fp = stdout;
if (fp == NULL) {
perror("fopen");
exit(1);
}
/* dump database body */
size = _db_factory_calc_size(df);
serialized = malloc(size);
_region_init(&data, serialized, size);
CHKERR(ret, _db_factory_serialize,
(df, _CITRUS_MAPPER_STD_MAGIC, &data));
if (fwrite(serialized, size, 1, fp) != 1)
err(EXIT_FAILURE, "fwrite");
fclose(fp);
}
static void
/*ARGSUSED*/
set_type(int type)
{
if (done_flag & DF_TYPE) {
warning("TYPE is duplicated. ignored this one");
return;
}
map_type = type;
done_flag |= DF_TYPE;
}
static void
/*ARGSUSED*/
set_name(char *str)
{
if (done_flag & DF_NAME) {
warning("NAME is duplicated. ignored this one");
return;
}
map_name = str;
done_flag |= DF_NAME;
}
static void
set_src_zone(u_int32_t val)
{
size_t i;
linear_zone_t *p;
if (done_flag & DF_SRC_ZONE) {
warning("SRC_ZONE is duplicated. ignored this one");
return;
}
rowcol_bits = val;
/* sanity check */
switch (rowcol_bits) {
case 8: case 16: case 32:
if (rowcol_len <= 32 / rowcol_bits)
break;
/*FALLTHROUGH*/
default:
goto bad;
}
rowcol_mask = 1 << (rowcol_bits - 1);
rowcol_mask |= rowcol_mask - 1;
for (i = 0; i < rowcol_len; ++i) {
p = &rowcol[i];
_DIAGASSERT(p->begin <= p->end);
if (p->end > rowcol_mask)
goto bad;
}
done_flag |= DF_SRC_ZONE;
return;
bad:
yyerror("Illegal argument for SRC_ZONE");
}
static void
set_dst_invalid(u_int32_t val)
{
if (done_flag & DF_DST_INVALID) {
warning("DST_INVALID is duplicated. ignored this one");
return;
}
dst_invalid = val;
done_flag |= DF_DST_INVALID;
}
static void
set_dst_ilseq(u_int32_t val)
{
if (done_flag & DF_DST_ILSEQ) {
warning("DST_ILSEQ is duplicated. ignored this one");
return;
}
dst_ilseq = val;
done_flag |= DF_DST_ILSEQ;
}
static void
set_oob_mode(u_int32_t val)
{
if (done_flag & DF_OOB_MODE) {
warning("OOB_MODE is duplicated. ignored this one");
return;
}
oob_mode = val;
done_flag |= DF_OOB_MODE;
}
static void
set_dst_unit_bits(u_int32_t val)
{
if (done_flag & DF_DST_UNIT_BITS) {
warning("DST_UNIT_BITS is duplicated. ignored this one");
return;
}
switch (val) {
case 8:
putfunc = &put8;
dst_unit_bits = val;
break;
case 16:
putfunc = &put16;
dst_unit_bits = val;
break;
case 32:
putfunc = &put32;
dst_unit_bits = val;
break;
default:
yyerror("Illegal argument for DST_UNIT_BITS");
}
done_flag |= DF_DST_UNIT_BITS;
}
static int
check_src(u_int32_t begin, u_int32_t end)
{
size_t i;
linear_zone_t *p;
u_int32_t m, n;
if (begin > end)
return 1;
if (begin < end) {
m = begin & ~rowcol_mask;
n = end & ~rowcol_mask;
if (m != n)
return 1;
}
for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
i -= rowcol_bits;
m = (begin >> i) & rowcol_mask;
if (m < p->begin || m > p->end)
return 1;
}
if (begin < end) {
n = end & rowcol_mask;
_DIAGASSERT(p > rowcol);
--p;
if (n < p->begin || n > p->end)
return 1;
}
return 0;
}
static void
store(const linear_zone_t *lz, u_int32_t dst, int inc)
{
size_t i, ofs;
linear_zone_t *p;
u_int32_t n;
ofs = 0;
for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
i -= rowcol_bits;
n = ((lz->begin >> i) & rowcol_mask) - p->begin;
ofs = (ofs * p->width) + n;
}
n = lz->width;
while (n-- > 0) {
(*putfunc)(table, ofs++, dst);
if (inc)
dst++;
}
}
static void
set_range(u_int32_t begin, u_int32_t end)
{
linear_zone_t *p;
if (rowcol_len >= _CITRUS_MAPPER_STD_ROWCOL_MAX)
goto bad;
p = &rowcol[rowcol_len++];
if (begin > end)
goto bad;
p->begin = begin, p->end = end;
p->width = end - begin + 1;
return;
bad:
yyerror("Illegal argument for SRC_ZONE");
}
static void
set_src(linear_zone_t *lz, u_int32_t begin, u_int32_t end)
{
_DIAGASSERT(lz != NULL);
if (check_src(begin, end) != 0)
yyerror("illegal zone");
lz->begin = begin, lz->end = end;
lz->width = end - begin + 1;
src_next = end + 1;
}
static void
do_mkdb(FILE *in)
{
int ret;
FILE *out;
/* dump DB to file */
if (output)
out = fopen(output, "wb");
else
out = stdout;
if (out==NULL)
err(EXIT_FAILURE, "fopen");
ret = _lookup_factory_convert(out, in);
fclose(out);
if (ret && output)
unlink(output); /* dump failure */
}
static void
do_mkpv(FILE *in)
{
int ret;
FILE *out;
/* dump pivot to file */
if (output)
out = fopen(output, "wb");
else
out = stdout;
if (out == NULL)
err(EXIT_FAILURE, "fopen");
ret = _pivot_factory_convert(out, in);
fclose(out);
if (ret && output)
unlink(output); /* dump failure */
if (ret)
errc(EXIT_FAILURE, ret, "");
}
__dead static void
usage(void)
{
fprintf(stderr, "Usage: %s [-m|-p] [-d] [-o outfile] [infile]\n",
getprogname());
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
int ch;
extern char *optarg;
extern int optind;
FILE *in = NULL;
int mkdb = 0, mkpv = 0;
while ((ch=getopt(argc, argv, "do:mp")) != EOF) {
switch (ch) {
case 'd':
debug=1;
break;
case 'o':
output = strdup(optarg);
break;
case 'm':
mkdb = 1;
break;
case 'p':
mkpv = 1;
break;
default:
usage();
}
}
argc-=optind;
argv+=optind;
switch (argc) {
case 0:
in = stdin;
break;
case 1:
in = fopen(argv[0], "r");
if (!in)
err(EXIT_FAILURE, "%s", argv[0]);
break;
default:
usage();
}
if (mkdb)
do_mkdb(in);
else if (mkpv)
do_mkpv(in);
else {
yyin = in;
yyparse();
}
return (0);
}

22
usr.bin/mkesdb/Makefile Normal file
View File

@@ -0,0 +1,22 @@
# $NetBSD: Makefile,v 1.7 2009/10/28 22:22:44 christos Exp $
NOMAN=# defined (must come before bsd.own.mk)
.ifndef HOSTPROG
.include <bsd.own.mk>
.endif
.PATH: ${NETBSDSRCDIR}/lib/libc/citrus
PROG= mkesdb
SRCS= yacc.y lex.l \
citrus_bcs.c citrus_db_factory.c citrus_db_hash.c \
citrus_lookup_factory.c
CPPFLAGS+= -I. -I${.CURDIR} -I${NETBSDSRCDIR}/lib/libc \
-I${NETBSDSRCDIR}/lib/libc/citrus \
-DHOSTPROG -DLIBC_SCCS
YHEADER= 1
.ifndef HOSTPROG
.include <bsd.prog.mk>
.endif

40
usr.bin/mkesdb/ldef.h Normal file
View File

@@ -0,0 +1,40 @@
/* $NetBSD: ldef.h,v 1.2 2005/06/27 01:23:59 fvdl Exp $ */
/*-
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
extern int line_number;
extern FILE *yyin;
extern int yyparse(void);
extern int yylex(void);
extern int yyerror(const char *);
struct named_csid {
SIMPLEQ_ENTRY(named_csid) ci_entry;
u_int32_t ci_csid;
char *ci_symbol;
};
SIMPLEQ_HEAD(named_csid_list, named_csid);

103
usr.bin/mkesdb/lex.l Normal file
View File

@@ -0,0 +1,103 @@
/* $NetBSD: lex.l,v 1.5 2009/10/29 14:49:03 christos Exp $ */
%{
/*-
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: lex.l,v 1.5 2009/10/29 14:49:03 christos Exp $");
#endif /* not lint */
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <machine/endian.h>
#include <sys/queue.h>
#include "ldef.h"
#include "yacc.h"
int line_number = 1;
%}
%option noinput nounput
%x COMMENT
%%
[ \t]+ { }
#.*[\n]|"//".*[\n]|[\n] { line_number++; return (R_LN); }
"/*" { BEGIN COMMENT; }
<COMMENT>"*/" { BEGIN 0; }
<COMMENT>[\n] { line_number++; }
<COMMENT>. { }
<COMMENT><<EOF>> {
yyerror("unexpected file end (unterminate comment)\n");
exit(1);
}
([1-9][0-9]*)|(0[0-9]*)|(0[xX][0-9A-Fa-f]+) {
yylval.i_value = strtoul(yytext, NULL, 0);
return L_IMM;
}
"NAME" { return R_NAME; }
"ENCODING" { return R_ENCODING; }
"VARIABLE" { return R_VARIABLE; }
"DEFCSID" { return R_DEFCSID; }
"INVALID" { return R_INVALID; }
\"([^\"\n]*(\\\")?)*\"|\'([^\'\n]*(\\\')?)*\' {
size_t len;
len = strlen(yytext);
yylval.s_value = malloc(len-1);
strlcpy(yylval.s_value, yytext+1, len-1);
return L_STRING;
}
[^ =/\-0-9\t\n][^ \t\n]* {
yylval.s_value = strdup(yytext);
return L_STRING;
}
%%
#ifndef yywrap
int
yywrap(void)
{
return (1);
}
#endif

347
usr.bin/mkesdb/yacc.y Normal file
View File

@@ -0,0 +1,347 @@
/* $NetBSD: yacc.y,v 1.9 2015/06/16 23:44:44 christos Exp $ */
%{
/*-
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: yacc.y,v 1.9 2015/06/16 23:44:44 christos Exp $");
#endif /* not lint */
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/queue.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_region.h"
#include "citrus_esdb_file.h"
#include "citrus_db_hash.h"
#include "citrus_db_factory.h"
#include "citrus_lookup_factory.h"
#include "ldef.h"
static int debug = 0, num_csids = 0;
static char *output = NULL;
static char *name, *encoding, *variable;
static u_int32_t invalid;
static int use_invalid = 0;
static struct named_csid_list named_csids;
static void dump_file(void);
static void register_named_csid(char *, u_int32_t);
static void set_prop_string(const char *, char **, char **);
static void set_invalid(u_int32_t);
%}
%union {
u_int32_t i_value;
char *s_value;
}
%token R_NAME R_ENCODING R_VARIABLE R_DEFCSID R_INVALID
%token R_LN
%token <i_value> L_IMM
%token <s_value> L_STRING
%%
file : property
{ dump_file(); }
property : /* empty */
| property R_LN
| property name R_LN
| property encoding R_LN
| property variable R_LN
| property defcsid R_LN
| property invalid R_LN
name : R_NAME L_STRING
{
set_prop_string("NAME", &name, &$2);
}
encoding : R_ENCODING L_STRING
{
set_prop_string("ENCODING", &encoding, &$2);
}
variable : R_VARIABLE L_STRING
{
set_prop_string("VARIABLE", &variable, &$2);
}
defcsid : R_DEFCSID L_STRING L_IMM
{
register_named_csid($2, $3);
$2 = NULL;
}
invalid : R_INVALID L_IMM
{
set_invalid($2);
}
%%
int
yyerror(const char *s)
{
fprintf(stderr, "%s in %d\n", s, line_number);
return (0);
}
#define CHKERR(ret, func, a) \
do { \
ret = func a; \
if (ret) \
errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret)); \
} while (/*CONSTCOND*/0)
static void
dump_file(void)
{
int ret;
FILE *fp;
struct _db_factory *df;
struct _region data;
struct named_csid *csid;
char buf[100];
int i;
void *serialized;
size_t size;
ret = 0;
if (!name) {
fprintf(stderr, "NAME is mandatory.\n");
ret = 1;
}
if (!encoding) {
fprintf(stderr, "ENCODING is mandatory.\n");
ret = 1;
}
if (ret)
exit(1);
/*
* build database
*/
CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
/* store version */
CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_VERSION,
_CITRUS_ESDB_VERSION));
/* store encoding */
CHKERR(ret, _db_factory_addstr_by_s, (df, _CITRUS_ESDB_SYM_ENCODING,
encoding));
/* store variable */
if (variable)
CHKERR(ret, _db_factory_addstr_by_s,
(df, _CITRUS_ESDB_SYM_VARIABLE, variable));
/* store invalid */
if (use_invalid)
CHKERR(ret, _db_factory_add32_by_s, (df,
_CITRUS_ESDB_SYM_INVALID,
invalid));
/* store num of charsets */
CHKERR(ret, _db_factory_add32_by_s, (df, _CITRUS_ESDB_SYM_NUM_CHARSETS,
num_csids));
i=0;
SIMPLEQ_FOREACH(csid, &named_csids, ci_entry) {
snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d",
i);
CHKERR(ret, _db_factory_addstr_by_s,
(df, buf, csid->ci_symbol));
snprintf(buf, sizeof(buf), _CITRUS_ESDB_SYM_CSID_PREFIX "%d",
i);
CHKERR(ret, _db_factory_add32_by_s, (df, buf, csid->ci_csid));
i++;
}
/*
* dump database to file
*/
if (output)
fp = fopen(output, "wb");
else
fp = stdout;
if (fp == NULL) {
perror("fopen");
exit(1);
}
/* dump database body */
size = _db_factory_calc_size(df);
serialized = malloc(size);
_region_init(&data, serialized, size);
CHKERR(ret, _db_factory_serialize, (df, _CITRUS_ESDB_MAGIC, &data));
if (fwrite(serialized, size, 1, fp) != 1)
err(EXIT_FAILURE, "fwrite");
fclose(fp);
}
static void
set_prop_string(const char *res, char **store, char **data)
{
char buf[256];
if (*store) {
snprintf(buf, sizeof(buf),
"%s is duplicated. ignored the one", res);
yyerror(buf);
return;
}
*store = *data;
*data = NULL;
}
static void
set_invalid(u_int32_t inv)
{
invalid = inv;
use_invalid = 1;
}
static void
register_named_csid(char *sym, u_int32_t val)
{
struct named_csid *csid;
SIMPLEQ_FOREACH(csid, &named_csids, ci_entry) {
if (strcmp(csid->ci_symbol, sym) == 0) {
yyerror("multiply defined CSID");
exit(1);
}
}
csid = malloc(sizeof(*csid));
if (csid == NULL) {
perror("malloc");
exit(1);
}
csid->ci_symbol = sym;
csid->ci_csid = val;
SIMPLEQ_INSERT_TAIL(&named_csids, csid, ci_entry);
num_csids++;
}
static void
do_mkdb(FILE *in)
{
int ret;
FILE *out;
/* dump DB to file */
if (output)
out = fopen(output, "wb");
else
out = stdout;
if (out == NULL)
err(EXIT_FAILURE, "fopen");
ret = _lookup_factory_convert(out, in);
fclose(out);
if (ret && output)
unlink(output); /* dump failure */
if (ret)
errc(EXIT_FAILURE, ret, NULL);
}
__dead static void
usage(void)
{
fprintf(stderr, "Usage: %s [-m] [-o outfile] [infile]\n",
getprogname());
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
int ch;
extern char *optarg;
extern int optind;
FILE *in = NULL;
int mkdb = 0;
while ((ch=getopt(argc, argv, "do:m")) != EOF) {
switch (ch) {
case 'd':
debug = 1;
break;
case 'o':
output = strdup(optarg);
break;
case 'm':
mkdb = 1;
break;
default:
usage();
}
}
argc-=optind;
argv+=optind;
switch (argc) {
case 0:
in = stdin;
break;
case 1:
in = fopen(argv[0], "r");
if (!in)
err(EXIT_FAILURE, "%s", argv[0]);
break;
default:
usage();
}
if (mkdb)
do_mkdb(in);
else {
SIMPLEQ_INIT(&named_csids);
yyin=in;
yyparse();
}
return (0);
}

25
usr.bin/mklocale/Makefile Normal file
View File

@@ -0,0 +1,25 @@
# $NetBSD: Makefile,v 1.16 2009/04/14 22:15:24 lukem Exp $
WARNS?= 2 # XXX -Wextra -Wsign-compare issues
.ifndef HOSTPROG
.include <bsd.own.mk>
.endif
.PATH: ${NETBSDSRCDIR}/lib/libc/locale ${NETBSDSRCDIR}/lib/libc/citrus ${NETBSDSRCDIR}/lib/libc/stdio
PROG= mklocale
SRCS= yacc.y lex.l mklocaledb.c fix_grouping.c \
citrus_bcs_strtoul.c citrus_db_factory.c citrus_db_hash.c
CPPFLAGS+= -I. -I${.CURDIR} \
-I${NETBSDSRCDIR}/lib/libc/include \
-I${NETBSDSRCDIR}/lib/libc/locale \
-I${NETBSDSRCDIR}/lib/libc/citrus \
-DNBCHAR_MAX=127 -DHOSTPROG
CPPFLAGS.citrus_bcs_strtoul.c+= \
-I${NETBSDSRCDIR}/common/lib/libc/stdlib
YHEADER= 1
.ifndef HOSTPROG
.include <bsd.prog.mk>
.endif

51
usr.bin/mklocale/ldef.h Normal file
View File

@@ -0,0 +1,51 @@
/* $NetBSD: ldef.h,v 1.8 2010/05/22 18:15:21 tnozaki Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ldef.h 8.1 (Berkeley) 6/6/93
*/
/*
* This should look a LOT like a _RuneEntry
*/
typedef struct rune_list {
__nbrune_t min;
__nbrune_t max;
__nbrune_t map;
u_int32_t *types;
struct rune_list *next;
} rune_list;
typedef struct rune_map {
u_int32_t map[_CTYPE_CACHE_SIZE];
rune_list *root;
} rune_map;

186
usr.bin/mklocale/lex.l Normal file
View File

@@ -0,0 +1,186 @@
/* $NetBSD: lex.l,v 1.18 2010/06/13 04:14:57 tnozaki Exp $ */
%{
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)lex.l 8.1 (Berkeley) 6/6/93";
#else
__RCSID("$NetBSD: lex.l,v 1.18 2010/06/13 04:14:57 tnozaki Exp $");
#endif
#endif /* not lint */
#include <stdio.h>
#include <stdlib.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "runetype_file.h"
#include "ldef.h"
#include "yacc.h"
int yylex __P((void));
%}
ODIGIT [0-7]
DIGIT [0-9]
XDIGIT [0-9a-fA-F]
W [\t\n\r ]
%%
\'.\' { yylval.rune = (unsigned char)yytext[1];
return(RUNE); }
'\\a' { yylval.rune = '\a';
return(RUNE); }
'\\b' { yylval.rune = '\b';
return(RUNE); }
'\\f' { yylval.rune = '\f';
return(RUNE); }
'\\n' { yylval.rune = '\n';
return(RUNE); }
'\\r' { yylval.rune = '\r';
return(RUNE); }
'\\t' { yylval.rune = '\t';
return(RUNE); }
'\\v' { yylval.rune = '\v';
return(RUNE); }
0x{XDIGIT}+ { yylval.rune = _bcs_strtoul(yytext, 0, 16);
return(RUNE); }
0{ODIGIT}+ { yylval.rune = _bcs_strtoul(yytext, 0, 8);
return(RUNE); }
{DIGIT}+ { yylval.rune = _bcs_strtoul(yytext, 0, 10);
return(RUNE); }
MAPLOWER { return(MAPLOWER); }
MAPUPPER { return(MAPUPPER); }
TODIGIT { return(DIGITMAP); }
INVALID { return(INVALID); }
ALPHA { yylval.i = _RUNETYPE_A|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
CONTROL { yylval.i = _RUNETYPE_C;
return(LIST); }
DIGIT { yylval.i = _RUNETYPE_D|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
GRAPH { yylval.i = _RUNETYPE_G|_RUNETYPE_R;
return(LIST); }
LOWER { yylval.i = _RUNETYPE_L|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
PUNCT { yylval.i = _RUNETYPE_P|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
SPACE { yylval.i = _RUNETYPE_S;
return(LIST); }
UPPER { yylval.i = _RUNETYPE_U|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
XDIGIT { yylval.i = _RUNETYPE_X|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
BLANK { yylval.i = _RUNETYPE_B;
return(LIST); }
PRINT { yylval.i = _RUNETYPE_R;
return(LIST); }
IDEOGRAM { yylval.i = _RUNETYPE_I|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
SPECIAL { yylval.i = _RUNETYPE_T|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
PHONOGRAM { yylval.i = _RUNETYPE_Q|_RUNETYPE_R|_RUNETYPE_G;
return(LIST); }
SWIDTH0 { yylval.i = _RUNETYPE_SW0; return(LIST); }
SWIDTH1 { yylval.i = _RUNETYPE_SW1; return(LIST); }
SWIDTH2 { yylval.i = _RUNETYPE_SW2; return(LIST); }
SWIDTH3 { yylval.i = _RUNETYPE_SW3; return(LIST); }
VARIABLE[\t ] { static char vbuf[1024];
char *v = vbuf;
while ((*v = input()) && *v != '\n')
++v;
if (*v) {
unput(*v);
*v = 0;
}
yylval.str = vbuf;
return(VARIABLE);
}
CHARSET { return(CHARSET); }
ENCODING { return(ENCODING); }
\".*\" { char *e = yytext + 1;
yylval.str = e;
while (*e && *e != '"')
++e;
*e = 0;
return(STRING); }
\<|\(|\[ { return(LBRK); }
\>|\)|\] { return(RBRK); }
\- { return(THRU); }
\.\.\. { return(THRU); }
\: { return(':'); }
{W}+ ;
^\#.*\n ;
\/\* { char lc = 0;
do {
while ((lc) != '*')
if ((lc = input()) == 0)
break;
} while((lc = input()) != '/');
}
\\$ ;
. { printf("Lex is skipping '%s'\n", yytext); }
%%
#if !defined(yywrap)
int
yywrap()
{
return(1);
}
#endif

285
usr.bin/mklocale/mklocale.1 Normal file
View File

@@ -0,0 +1,285 @@
.\" $NetBSD: mklocale.1,v 1.16 2013/07/15 18:46:47 joerg Exp $
.\" FreeBSD: src/usr.bin/mklocale/mklocale.1,v 1.6 1999/09/20 09:15:21 phantom Exp
.\"
.\" Copyright (c) 1993, 1994
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" Paul Borman at Krystal Technologies.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. Neither the name of the University nor the names of its contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)mklocale.1 8.2 (Berkeley) 4/18/94
.\"
.Dd July 15, 2013
.Dt MKLOCALE 1
.Os
.Sh NAME
.Nm mklocale
.Nd make LC_CTYPE locale files
.Sh SYNOPSIS
.Nm mklocale
.Op Fl d
.Op Fl t Ar type
\*[Lt]
.Ar source
\*[Gt]
.Ar language/LC_CTYPE
.Nm mklocale
.Op Fl d
.Op Fl t Ar type
.Fl o
.Ar language/LC_CTYPE
.Ar source
.Sh DESCRIPTION
The
.Nm mklocale
utility reads an
.Dv LC_CTYPE
source file from standard input and produces an
.Dv LC_CTYPE
binary file on standard output suitable for placement in
.Pa /usr/share/locale/\*[Lt]language\*[Gt]/LC_CTYPE .
.Pp
The format of
.Ar source
is quite simple.
It consists of a series of lines which start with a keyword and have
associated data following.
C style comments are used
to place comments in the file.
.Pp
Following options are available:
.Bl -tag -width XXX
.It Fl d
Turns on debugging messages.
.It Fl o
Specify output file.
.It Fl t
Generate output in new-style LC_{MONETARY,NUMERIC,TIME,MESSAGES}
locale-db format.
.El
.Pp
Besides the keywords which will be listed below,
the following are valid tokens in
.Ar source :
.Bl -tag -width literal
.It Dv RUNE
A
.Dv RUNE
may be any of the following:
.Bl -tag -width 0x[0-9a-f]+
.It Ar 'x'
The ASCII character
.Ar x .
.It Ar '\ex'
The ANSI C character
.Ar \ex
where
.Ar \ex
is one of
.Dv \ea ,
.Dv \eb ,
.Dv \ef ,
.Dv \en ,
.Dv \er ,
.Dv \et ,
or
.Dv \ev .
.It Ar 0x[0-9a-f]+
A hexadecimal number representing a rune code.
.It Ar 0[0-7]*
An octal number representing a rune code.
.It Ar [1-9][0-9]*
A decimal number representing a rune code.
.El
.It Dv STRING
A string enclosed in double quotes (").
.It Dv THRU
Either
.Dv ...
or
.Dv - .
Used to indicate ranges.
.It Ar literal
The follow characters are taken literally:
.Bl -tag -width "\*[Lt]\|\|(\|\|["
.It Dv "\*[Lt]\|(\|["
Used to start a mapping.
All are equivalent.
.It Dv "\*[Gt]\|\^)\|]"
Used to end a mapping.
All are equivalent.
.It Dv \&:
Used as a delimiter in mappings.
.El
.El
.Pp
Key words which should only appear once are:
.Bl -tag -width PHONOGRAM
.It Dv ENCODING
Followed by a
.Dv STRING
which indicates the encoding mechanism to be used for this locale.
The current encodings are:
.Bl -tag -width NONE
.It Dv NONE
No translation and the default.
.It Dv UTF2
.Dv "Universal character set Transformation Format"
adopted from
.Nm "Plan 9 from Bell Labs" .
.It Dv EUC
.Dv EUC
encoding as used by several
vendors of
.Ux
systems.
.El
.It Dv VARIABLE
This keyword must be followed by a single tab or space character,
after which encoding specific data is placed.
Currently only the
.Dv "EUC"
encoding requires variable data.
.\" See
.\" .Xr euc 4
.\" for further details.
.It Dv INVALID
A single
.Dv RUNE
follows and is used as the invalid rune for this locale.
.El
.Pp
The following keywords may appear multiple times and have the following
format for data:
.Bl -tag -width "XXRUNE1 THRU RUNEn : RUNE2XX" -offset indent
.It Aq Dv RUNE1 RUNE2
.Dv RUNE1
is mapped to
.Dv RUNE2 .
.It Aq Dv RUNE1 THRU RUNEn : RUNE2
Runes
.Dv RUNE1
through
.Dv RUNEn
are mapped to
.Dv RUNE2
through
.Dv RUNE2
+ n-1.
.El
.Bl -tag -width PHONOGRAM
.It Dv MAPLOWER
Defines the tolower mappings.
.Dv RUNE2
is the lower case representation of
.Dv RUNE1 .
.It Dv MAPUPPER
Defines the toupper mappings.
.Dv RUNE2
is the upper case representation of
.Dv RUNE1 .
.It Dv TODIGIT
Defines a map from runes to their digit value.
.Dv RUNE2
is the integer value represented by
.Dv RUNE1 .
For example, the ASCII character
.Sq 0
would map to the decimal value 0.
Only values up to 255 are allowed.
.El
.Pp
The following keywords may appear multiple times and have the following
format for data:
.Bl -tag -width "RUNE1 THRU RUNEn"
.It Dv RUNE
This rune has the property defined by the keyword.
.It Dv "RUNE1 THRU RUNEn"
All the runes between and including
.Dv RUNE1
and
.Dv RUNEn
have the property defined by the keyword.
.El
.Bl -tag -width PHONOGRAM
.It Dv ALPHA
Defines runes which are alphabetic, printable, and graphic.
.It Dv CONTROL
Defines runes which are control characters.
.It Dv DIGIT
Defines runes which are decimal digits, printable, and graphic.
.It Dv GRAPH
Defines runes which are graphic and printable.
.It Dv LOWER
Defines runes which are lower case, printable, and graphic.
.It Dv PUNCT
Defines runes which are punctuation, printable, and graphic.
.It Dv SPACE
Defines runes which are spaces.
.It Dv UPPER
Defines runes which are upper case, printable, and graphic.
.It Dv XDIGIT
Defines runes which are hexadecimal digits, printable, and graphic.
.It Dv BLANK
Defines runes which are blank.
.It Dv PRINT
Defines runes which are printable.
.It Dv IDEOGRAM
Defines runes which are ideograms, printable, and graphic.
.It Dv SPECIAL
Defines runes which are special characters, printable, and graphic.
.It Dv PHONOGRAM
Defines runes which are phonograms, printable, and graphic.
.It Dv SWIDTHn
Defines runes with specific glyph width.
.Ar n
takes 0 to 3.
.It Dv CHARSET
Controls character set for subsequent runes.
.\" To support
.\" .Xr iso2022 4
.\" locale definitions.
.El
.Sh SEE ALSO
.\"Xr colldef 1 ,
.Xr setlocale 3 ,
.\" .Xr euc 4 ,
.\" .Xr utf8 4
.Xr nls 7
.Sh HISTORY
The
.Nm mklocale
utility first appeared in
.Bx 4.4 .
.Sh BUGS
The
.Nm mklocale
utility is overly simplistic.
.Pp
We should switch to
.Nm localedef
and its file format, which is more standard.

View File

@@ -0,0 +1,280 @@
/* $NetBSD: mklocaledb.c,v 1.4 2015/06/16 22:54:10 christos Exp $ */
/*-
* Copyright (c)2008 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* XXX TEMPORARY IMPLEMENTATION.
* don't waste your time, all we need is localedef(1).
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if !defined(lint)
__RCSID("$NetBSD: mklocaledb.c,v 1.4 2015/06/16 22:54:10 christos Exp $");
#endif /* not lint */
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fix_grouping.h"
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "citrus_types.h"
#include "citrus_region.h"
#include "citrus_db_factory.h"
#include "citrus_db_hash.h"
#include "citrus_db.h"
#include "citrus_lc_monetary.h"
#include "citrus_lc_numeric.h"
#include "citrus_lc_time.h"
#include "citrus_lc_messages.h"
void mklocaledb(const char *, FILE *, FILE *);
/*
* TODO: -d debug options's output.
*/
extern int debug;
extern void usage(void);
static int
save_as_string(struct _db_factory *df,
const char *key, const char *value)
{
return _db_factory_addstr_by_s(df, key, value);
}
static int
save_as_grouping(struct _db_factory *df,
const char *key, const char *value)
{
value = __fix_locale_grouping_str(value);
return _db_factory_addstr_by_s(df, key, value);
}
static int
save_as_uint8(struct _db_factory *df,
const char *key, const char *head)
{
char *tail;
unsigned long int value;
uint8_t u8;
value = _bcs_strtoul(head, &tail, 0);
if (head == tail || value > 0xFF)
return 1;
u8 = (uint8_t)(value & 0xFF);
return _db_factory_add8_by_s(df, key, u8);
}
typedef struct {
const char *key;
int (*save)(struct _db_factory *,
const char *, const char *);
} token_t;
typedef struct {
const char *magic, * vers_sym;
uint32_t version;
const token_t tokens[];
} category_t;
static const category_t lc_monetary = {
_CITRUS_LC_MONETARY_MAGIC_1,
_CITRUS_LC_MONETARY_SYM_VERSION,
_CITRUS_LC_MONETARY_VERSION,
{
{ _CITRUS_LC_MONETARY_SYM_INT_CURR_SYMBOL, &save_as_string },
{ _CITRUS_LC_MONETARY_SYM_CURRENCY_SYMBOL, &save_as_string },
{ _CITRUS_LC_MONETARY_SYM_MON_DECIMAL_POINT, &save_as_string },
{ _CITRUS_LC_MONETARY_SYM_MON_THOUSANDS_SEP, &save_as_string },
{ _CITRUS_LC_MONETARY_SYM_MON_GROUPING, &save_as_grouping },
{ _CITRUS_LC_MONETARY_SYM_POSITIVE_SIGN, &save_as_string },
{ _CITRUS_LC_MONETARY_SYM_NEGATIVE_SIGN, &save_as_string },
{ _CITRUS_LC_MONETARY_SYM_INT_FRAC_DIGITS, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_FRAC_DIGITS, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_P_CS_PRECEDES, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_P_SEP_BY_SPACE, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_N_CS_PRECEDES, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_N_SEP_BY_SPACE, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_P_SIGN_POSN, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_N_SIGN_POSN, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_INT_P_CS_PRECEDES, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_INT_P_SEP_BY_SPACE, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_INT_N_CS_PRECEDES, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_INT_N_SEP_BY_SPACE, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_INT_P_SIGN_POSN, &save_as_uint8 },
{ _CITRUS_LC_MONETARY_SYM_INT_N_SIGN_POSN, &save_as_uint8 },
{ NULL },
},
};
static const category_t lc_numeric = {
_CITRUS_LC_NUMERIC_MAGIC_1,
_CITRUS_LC_NUMERIC_SYM_VERSION,
_CITRUS_LC_NUMERIC_VERSION,
{
{ _CITRUS_LC_NUMERIC_SYM_DECIMAL_POINT, &save_as_string },
{ _CITRUS_LC_NUMERIC_SYM_THOUSANDS_SEP, &save_as_string },
{ _CITRUS_LC_NUMERIC_SYM_GROUPING, &save_as_grouping },
{ NULL },
},
};
static const category_t lc_time = {
_CITRUS_LC_TIME_MAGIC_1,
_CITRUS_LC_TIME_SYM_VERSION,
_CITRUS_LC_TIME_VERSION,
{
{ _CITRUS_LC_TIME_SYM_ABDAY_1, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABDAY_2, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABDAY_3, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABDAY_4, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABDAY_5, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABDAY_6, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABDAY_7, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_1, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_2, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_3, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_4, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_5, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_6, &save_as_string },
{ _CITRUS_LC_TIME_SYM_DAY_7, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_1, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_2, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_3, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_4, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_5, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_6, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_7, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_8, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_9, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_10, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_11, &save_as_string },
{ _CITRUS_LC_TIME_SYM_ABMON_12, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_1, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_2, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_3, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_4, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_5, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_6, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_7, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_8, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_9, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_10, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_11, &save_as_string },
{ _CITRUS_LC_TIME_SYM_MON_12, &save_as_string },
{ _CITRUS_LC_TIME_SYM_AM_STR, &save_as_string },
{ _CITRUS_LC_TIME_SYM_PM_STR, &save_as_string },
{ _CITRUS_LC_TIME_SYM_D_T_FMT, &save_as_string },
{ _CITRUS_LC_TIME_SYM_D_FMT, &save_as_string },
{ _CITRUS_LC_TIME_SYM_T_FMT, &save_as_string },
{ _CITRUS_LC_TIME_SYM_T_FMT_AMPM, &save_as_string },
{ NULL },
},
};
static const category_t lc_messages = {
_CITRUS_LC_MESSAGES_MAGIC_1,
_CITRUS_LC_MESSAGES_SYM_VERSION,
_CITRUS_LC_MESSAGES_VERSION,
{
{ _CITRUS_LC_MESSAGES_SYM_YESEXPR, &save_as_string },
{ _CITRUS_LC_MESSAGES_SYM_NOEXPR, &save_as_string },
{ _CITRUS_LC_MESSAGES_SYM_YESSTR, &save_as_string },
{ _CITRUS_LC_MESSAGES_SYM_NOSTR, &save_as_string },
{ NULL },
},
};
void
mklocaledb(const char *type, FILE *reader, FILE *writer)
{
static const char delim[3] = { '\0', '\0', '#' };
const category_t *category = NULL;
struct _db_factory *df;
const token_t *token;
char *line;
size_t size;
void *serialized;
struct _region r;
_DIAGASSERT(type != NULL);
_DIAGASSERT(reader != NULL);
_DIAGASSERT(writer != NULL);
if (!strcasecmp(type, "MONETARY"))
category = &lc_monetary;
else if (!strcasecmp(type, "NUMERIC"))
category = &lc_numeric;
else if (!strcasecmp(type, "TIME"))
category = &lc_time;
else if (!strcasecmp(type, "MESSAGES"))
category = &lc_messages;
else {
usage();
/*NOTREACHED*/
}
if (_db_factory_create(&df, &_db_hash_std, NULL))
errx(EXIT_FAILURE, "can't create db factory");
if (_db_factory_add32_by_s(df, category->vers_sym, category->version))
errx(EXIT_FAILURE, "can't store db");
token = &category->tokens[0];
while (token->key != NULL) {
line = fparseln(reader, NULL,
NULL, delim, FPARSELN_UNESCALL);
if (line == NULL)
errx(EXIT_FAILURE, "can't read line");
if ((*token->save)(df, token->key, (const char *)line))
errx(EXIT_FAILURE, "can't store db");
free(line);
++token;
}
size = _db_factory_calc_size(df);
_DIAGASSERT(size > 0);
serialized = malloc(size);
if (serialized == NULL)
errx(EXIT_FAILURE, "can't malloc");
_DIAGASSERT(serialized != NULL);
_region_init(&r, serialized, size);
if (_db_factory_serialize(df, category->magic, &r))
errx(EXIT_FAILURE, "can't serialize db");
fwrite(serialized, size, 1, writer);
_db_factory_free(df);
}

910
usr.bin/mklocale/yacc.y Normal file
View File

@@ -0,0 +1,910 @@
/* $NetBSD: yacc.y,v 1.31 2010/06/13 04:14:57 tnozaki Exp $ */
%{
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifndef lint
#if 0
static char sccsid[] = "@(#)yacc.y 8.1 (Berkeley) 6/6/93";
static char rcsid[] = "$FreeBSD$";
#else
__RCSID("$NetBSD: yacc.y,v 1.31 2010/06/13 04:14:57 tnozaki Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <netinet/in.h> /* Needed by <arpa/inet.h> on NetBSD 1.5. */
#include <arpa/inet.h> /* Needed for htonl on POSIX systems. */
#include <err.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "runetype_file.h"
#include "ldef.h"
const char *locale_file = "<stdout>";
rune_map maplower = { { 0, }, };
rune_map mapupper = { { 0, }, };
rune_map types = { { 0, }, };
_FileRuneLocale new_locale = { { 0, }, };
size_t rl_variable_len = (size_t)0;
void *rl_variable = NULL;
__nbrune_t charsetbits = (__nbrune_t)0x00000000;
#if 0
__nbrune_t charsetmask = (__nbrune_t)0x0000007f;
#endif
__nbrune_t charsetmask = (__nbrune_t)0xffffffff;
void set_map __P((rune_map *, rune_list *, u_int32_t));
void set_digitmap __P((rune_map *, rune_list *));
void add_map __P((rune_map *, rune_list *, u_int32_t));
int main __P((int, char *[]));
void usage __P((void));
int yyerror __P((const char *s));
void *xmalloc __P((unsigned int sz));
u_int32_t *xlalloc __P((unsigned int sz));
u_int32_t *xrelalloc __P((u_int32_t *old, unsigned int sz));
void dump_tables __P((void));
int yyparse __P((void));
extern int yylex __P((void));
/* mklocaledb.c */
extern void mklocaledb __P((const char *, FILE *, FILE *));
%}
%union {
__nbrune_t rune;
int i;
char *str;
rune_list *list;
}
%token <rune> RUNE
%token LBRK
%token RBRK
%token THRU
%token MAPLOWER
%token MAPUPPER
%token DIGITMAP
%token <i> LIST
%token <str> VARIABLE
%token CHARSET
%token ENCODING
%token INVALID
%token <str> STRING
%type <list> list
%type <list> map
%%
locale : /* empty */
| table
{ dump_tables(); }
;
table : entry
| table entry
;
entry : ENCODING STRING
{ strncpy(new_locale.frl_encoding, $2, sizeof(new_locale.frl_encoding)); }
| VARIABLE
{ rl_variable_len = strlen($1) + 1;
rl_variable = strdup($1);
new_locale.frl_variable_len = htonl((u_int32_t)rl_variable_len);
}
| CHARSET RUNE
{ charsetbits = $2; charsetmask = 0x0000007f; }
| CHARSET RUNE RUNE
{ charsetbits = $2; charsetmask = $3; }
| CHARSET STRING
{ int final = $2[strlen($2) - 1] & 0x7f;
charsetbits = final << 24;
if ($2[0] == '$') {
charsetmask = 0x00007f7f;
if (strchr(",-./", $2[1]))
charsetbits |= 0x80;
if (0xd0 <= final && final <= 0xdf)
charsetmask |= 0x007f0000;
} else {
charsetmask = 0x0000007f;
if (strchr(",-./", $2[0]))
charsetbits |= 0x80;
if (strlen($2) == 2 && $2[0] == '!')
charsetbits |= ((0x80 | $2[0]) << 16);
}
/*
* special rules
*/
if (charsetbits == ('B' << 24)
&& charsetmask == 0x0000007f) {
/*ASCII: 94B*/
charsetbits = 0;
charsetmask = 0x0000007f;
} else if (charsetbits == (('A' << 24) | 0x80)
&& charsetmask == 0x0000007f) {
/*Latin1: 96A*/
charsetbits = 0x80;
charsetmask = 0x0000007f;
}
}
| INVALID RUNE
{ new_locale.frl_invalid_rune = htonl((u_int32_t)$2); }
| LIST list
{ set_map(&types, $2, $1); }
| MAPLOWER map
{ set_map(&maplower, $2, 0); }
| MAPUPPER map
{ set_map(&mapupper, $2, 0); }
| DIGITMAP map
{ set_digitmap(&types, $2); }
;
list : RUNE
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($1 & charsetmask) | charsetbits;
$$->max = ($1 & charsetmask) | charsetbits;
$$->next = 0;
}
| RUNE THRU RUNE
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($1 & charsetmask) | charsetbits;
$$->max = ($3 & charsetmask) | charsetbits;
$$->next = 0;
}
| list RUNE
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($2 & charsetmask) | charsetbits;
$$->max = ($2 & charsetmask) | charsetbits;
$$->next = $1;
}
| list RUNE THRU RUNE
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($2 & charsetmask) | charsetbits;
$$->max = ($4 & charsetmask) | charsetbits;
$$->next = $1;
}
;
map : LBRK RUNE RUNE RBRK
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($2 & charsetmask) | charsetbits;
$$->max = ($2 & charsetmask) | charsetbits;
$$->map = $3;
$$->next = 0;
}
| map LBRK RUNE RUNE RBRK
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($3 & charsetmask) | charsetbits;
$$->max = ($3 & charsetmask) | charsetbits;
$$->map = $4;
$$->next = $1;
}
| LBRK RUNE THRU RUNE ':' RUNE RBRK
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($2 & charsetmask) | charsetbits;
$$->max = ($4 & charsetmask) | charsetbits;
$$->map = $6;
$$->next = 0;
}
| map LBRK RUNE THRU RUNE ':' RUNE RBRK
{
$$ = (rune_list *)malloc(sizeof(rune_list));
$$->min = ($3 & charsetmask) | charsetbits;
$$->max = ($5 & charsetmask) | charsetbits;
$$->map = $7;
$$->next = $1;
}
;
%%
int debug = 0;
FILE *ofile;
int
main(ac, av)
int ac;
char *av[];
{
int x;
const char *locale_type;
extern char *optarg;
extern int optind;
locale_type = NULL;
while ((x = getopt(ac, av, "do:t:")) != EOF) {
switch(x) {
case 'd':
debug = 1;
break;
case 'o':
locale_file = optarg;
if ((ofile = fopen(locale_file, "w")) == 0)
err(1, "unable to open output file %s", locale_file);
break;
case 't':
locale_type = optarg;
break;
default:
usage();
}
}
switch (ac - optind) {
case 0:
break;
case 1:
if (freopen(av[optind], "r", stdin) == 0)
err(1, "unable to open input file %s", av[optind]);
break;
default:
usage();
}
if (ofile == NULL)
ofile = stdout;
if (locale_type != NULL && strcasecmp(locale_type, "CTYPE")) {
mklocaledb(locale_type, stdin, ofile);
return 0;
}
for (x = 0; x < _CTYPE_CACHE_SIZE; ++x) {
mapupper.map[x] = x;
maplower.map[x] = x;
}
new_locale.frl_invalid_rune = htonl((u_int32_t)_DEFAULT_INVALID_RUNE);
memcpy(new_locale.frl_magic, _RUNECT10_MAGIC, sizeof(new_locale.frl_magic));
yyparse();
return 0;
}
void
usage()
{
fprintf(stderr,
"usage: mklocale [-d] [-o output] [-t type] [source]\n");
exit(1);
}
int
yyerror(s)
const char *s;
{
fprintf(stderr, "%s\n", s);
return 0;
}
void *
xmalloc(sz)
unsigned int sz;
{
void *r = malloc(sz);
if (!r) {
perror("xmalloc");
abort();
}
return(r);
}
u_int32_t *
xlalloc(sz)
unsigned int sz;
{
u_int32_t *r = (u_int32_t *)malloc(sz * sizeof(u_int32_t));
if (!r) {
perror("xlalloc");
abort();
}
return(r);
}
u_int32_t *
xrelalloc(old, sz)
u_int32_t *old;
unsigned int sz;
{
u_int32_t *r = (u_int32_t *)realloc((char *)old,
sz * sizeof(u_int32_t));
if (!r) {
perror("xrelalloc");
abort();
}
return(r);
}
void
set_map(map, list, flag)
rune_map *map;
rune_list *list;
u_int32_t flag;
{
list->map &= charsetmask;
list->map |= charsetbits;
while (list) {
rune_list *nlist = list->next;
add_map(map, list, flag);
list = nlist;
}
}
void
set_digitmap(map, list)
rune_map *map;
rune_list *list;
{
__nbrune_t i;
while (list) {
rune_list *nlist = list->next;
for (i = list->min; i <= list->max; ++i) {
if (list->map + (i - list->min)) {
rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list));
tmp->min = i;
tmp->max = i;
add_map(map, tmp, list->map + (i - list->min));
}
}
free(list);
list = nlist;
}
}
void
add_map(map, list, flag)
rune_map *map;
rune_list *list;
u_int32_t flag;
{
__nbrune_t i;
rune_list *lr = 0;
rune_list *r;
__nbrune_t run;
while (list->min < _CTYPE_CACHE_SIZE && list->min <= list->max) {
if (flag)
map->map[list->min++] |= flag;
else
map->map[list->min++] = list->map++;
}
if (list->min > list->max) {
free(list);
return;
}
run = list->max - list->min + 1;
if (!(r = map->root) || (list->max < r->min - 1)
|| (!flag && list->max == r->min - 1)) {
if (flag) {
list->types = xlalloc(run);
for (i = 0; i < run; ++i)
list->types[i] = flag;
}
list->next = map->root;
map->root = list;
return;
}
for (r = map->root; r && r->max + 1 < list->min; r = r->next)
lr = r;
if (!r) {
/*
* We are off the end.
*/
if (flag) {
list->types = xlalloc(run);
for (i = 0; i < run; ++i)
list->types[i] = flag;
}
list->next = 0;
lr->next = list;
return;
}
if (list->max < r->min - 1) {
/*
* We come before this range and we do not intersect it.
* We are not before the root node, it was checked before the loop
*/
if (flag) {
list->types = xlalloc(run);
for (i = 0; i < run; ++i)
list->types[i] = flag;
}
list->next = lr->next;
lr->next = list;
return;
}
/*
* At this point we have found that we at least intersect with
* the range pointed to by `r', we might intersect with one or
* more ranges beyond `r' as well.
*/
if (!flag && list->map - list->min != r->map - r->min) {
/*
* There are only two cases when we are doing case maps and
* our maps needn't have the same offset. When we are adjoining
* but not intersecting.
*/
if (list->max + 1 == r->min) {
lr->next = list;
list->next = r;
return;
}
if (list->min - 1 == r->max) {
list->next = r->next;
r->next = list;
return;
}
fprintf(stderr, "Error: conflicting map entries\n");
exit(1);
}
if (list->min >= r->min && list->max <= r->max) {
/*
* Subset case.
*/
if (flag) {
for (i = list->min; i <= list->max; ++i)
r->types[i - r->min] |= flag;
}
free(list);
return;
}
if (list->min <= r->min && list->max >= r->max) {
/*
* Superset case. Make him big enough to hold us.
* We might need to merge with the guy after him.
*/
if (flag) {
list->types = xlalloc(list->max - list->min + 1);
for (i = list->min; i <= list->max; ++i)
list->types[i - list->min] = flag;
for (i = r->min; i <= r->max; ++i)
list->types[i - list->min] |= r->types[i - r->min];
free(r->types);
r->types = list->types;
} else {
r->map = list->map;
}
r->min = list->min;
r->max = list->max;
free(list);
} else if (list->min < r->min) {
/*
* Our tail intersects his head.
*/
if (flag) {
list->types = xlalloc(r->max - list->min + 1);
for (i = r->min; i <= r->max; ++i)
list->types[i - list->min] = r->types[i - r->min];
for (i = list->min; i < r->min; ++i)
list->types[i - list->min] = flag;
for (i = r->min; i <= list->max; ++i)
list->types[i - list->min] |= flag;
free(r->types);
r->types = list->types;
} else {
r->map = list->map;
}
r->min = list->min;
free(list);
return;
} else {
/*
* Our head intersects his tail.
* We might need to merge with the guy after him.
*/
if (flag) {
r->types = xrelalloc(r->types, list->max - r->min + 1);
for (i = list->min; i <= r->max; ++i)
r->types[i - r->min] |= flag;
for (i = r->max+1; i <= list->max; ++i)
r->types[i - r->min] = flag;
}
r->max = list->max;
free(list);
}
/*
* Okay, check to see if we grew into the next guy(s)
*/
while ((lr = r->next) && r->max >= lr->min) {
if (flag) {
if (r->max >= lr->max) {
/*
* Good, we consumed all of him.
*/
for (i = lr->min; i <= lr->max; ++i)
r->types[i - r->min] |= lr->types[i - lr->min];
} else {
/*
* "append" him on to the end of us.
*/
r->types = xrelalloc(r->types, lr->max - r->min + 1);
for (i = lr->min; i <= r->max; ++i)
r->types[i - r->min] |= lr->types[i - lr->min];
for (i = r->max+1; i <= lr->max; ++i)
r->types[i - r->min] = lr->types[i - lr->min];
r->max = lr->max;
}
} else {
if (lr->max > r->max)
r->max = lr->max;
}
r->next = lr->next;
if (flag)
free(lr->types);
free(lr);
}
}
void
dump_tables()
{
int x, n;
rune_list *list;
FILE *fp = ofile;
u_int32_t nranges;
/*
* See if we can compress some of the istype arrays
*/
for(list = types.root; list; list = list->next) {
list->map = list->types[0];
for (x = 1; x < list->max - list->min + 1; ++x) {
if (list->types[x] != list->map) {
list->map = 0;
break;
}
}
}
/*
* Fill in our tables. Do this in network order so that
* diverse machines have a chance of sharing data.
* (Machines like Crays cannot share with little machines due to
* word size. Sigh. We tried.)
*/
for (x = 0; x < _CTYPE_CACHE_SIZE; ++x) {
new_locale.frl_runetype[x] = htonl(types.map[x]);
new_locale.frl_maplower[x] = htonl(maplower.map[x]);
new_locale.frl_mapupper[x] = htonl(mapupper.map[x]);
}
/*
* Count up how many ranges we will need for each of the extents.
*/
list = types.root;
nranges = (u_int32_t)0;
while (list) {
++nranges;
list = list->next;
}
new_locale.frl_runetype_ext.frr_nranges =
htonl(nranges);
list = maplower.root;
nranges = (u_int32_t)0;
while (list) {
++nranges;
list = list->next;
}
new_locale.frl_maplower_ext.frr_nranges =
htonl(nranges);
list = mapupper.root;
nranges = (u_int32_t)0;
while (list) {
++nranges;
list = list->next;
}
new_locale.frl_mapupper_ext.frr_nranges =
htonl(nranges);
/*
* Okay, we are now ready to write the new locale file.
*/
/*
* PART 1: The _RuneLocale structure
*/
if (fwrite((char *)&new_locale, sizeof(new_locale), 1, fp) != 1)
err(1, "writing _FileRuneLocale to %s", locale_file);
/*
* PART 2: The runetype_ext structures (not the actual tables)
*/
for (list = types.root, n = 0; list != NULL; list = list->next, n++) {
_FileRuneEntry re;
memset(&re, 0, sizeof(re));
re.fre_min = htonl(list->min);
re.fre_max = htonl(list->max);
re.fre_map = htonl(list->map);
if (fwrite((char *)&re, sizeof(re), 1, fp) != 1)
err(1, "writing runetype_ext #%d to %s", n, locale_file);
}
/*
* PART 3: The maplower_ext structures
*/
for (list = maplower.root, n = 0; list != NULL; list = list->next, n++) {
_FileRuneEntry re;
memset(&re, 0, sizeof(re));
re.fre_min = htonl(list->min);
re.fre_max = htonl(list->max);
re.fre_map = htonl(list->map);
if (fwrite((char *)&re, sizeof(re), 1, fp) != 1)
err(1, "writing maplower_ext #%d to %s", n, locale_file);
}
/*
* PART 4: The mapupper_ext structures
*/
for (list = mapupper.root, n = 0; list != NULL; list = list->next, n++) {
_FileRuneEntry re;
memset(&re, 0, sizeof(re));
re.fre_min = htonl(list->min);
re.fre_max = htonl(list->max);
re.fre_map = htonl(list->map);
if (fwrite((char *)&re, sizeof(re), 1, fp) != 1)
err(1, "writing mapupper_ext #%d to %s", n, locale_file);
}
/*
* PART 5: The runetype_ext tables
*/
for (list = types.root, n = 0; list != NULL; list = list->next, n++) {
for (x = 0; x < list->max - list->min + 1; ++x)
list->types[x] = htonl(list->types[x]);
if (!list->map) {
if (fwrite((char *)list->types,
(list->max - list->min + 1) * sizeof(u_int32_t),
1, fp) != 1)
err(1, "writing runetype_ext table #%d to %s", n, locale_file);
}
}
/*
* PART 5: And finally the variable data
*/
if (rl_variable_len != 0 &&
fwrite((char *)rl_variable, rl_variable_len, 1, fp) != 1)
err(1, "writing variable data to %s", locale_file);
fclose(fp);
if (!debug)
return;
if (new_locale.frl_encoding[0])
fprintf(stderr, "ENCODING %.*s\n",
(int)sizeof(new_locale.frl_encoding), new_locale.frl_encoding);
if (rl_variable)
fprintf(stderr, "VARIABLE %.*s\n",
(int)rl_variable_len, (char *)rl_variable);
fprintf(stderr, "\nMAPLOWER:\n\n");
for (x = 0; x < _CTYPE_CACHE_SIZE; ++x) {
if (isprint(maplower.map[x]))
fprintf(stderr, " '%c'", (int)maplower.map[x]);
else if (maplower.map[x])
fprintf(stderr, "%04x", maplower.map[x]);
else
fprintf(stderr, "%4x", 0);
if ((x & 0xf) == 0xf)
fprintf(stderr, "\n");
else
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
for (list = maplower.root; list; list = list->next)
fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
fprintf(stderr, "\nMAPUPPER:\n\n");
for (x = 0; x < _CTYPE_CACHE_SIZE; ++x) {
if (isprint(mapupper.map[x]))
fprintf(stderr, " '%c'", (int)mapupper.map[x]);
else if (mapupper.map[x])
fprintf(stderr, "%04x", mapupper.map[x]);
else
fprintf(stderr, "%4x", 0);
if ((x & 0xf) == 0xf)
fprintf(stderr, "\n");
else
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
for (list = mapupper.root; list; list = list->next)
fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
fprintf(stderr, "\nTYPES:\n\n");
for (x = 0; x < _CTYPE_CACHE_SIZE; ++x) {
u_int32_t r = types.map[x];
if (r) {
if (isprint(x))
fprintf(stderr, " '%c':%2d", x, (int)(r & 0xff));
else
fprintf(stderr, "%04x:%2d", x, (int)(r & 0xff));
fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
fprintf(stderr, "\n");
}
}
for (list = types.root; list; list = list->next) {
if (list->map && list->min + 3 < list->max) {
u_int32_t r = list->map;
fprintf(stderr, "%04x:%2d", list->min, r & 0xff);
fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
fprintf(stderr, "\n...\n");
fprintf(stderr, "%04x:%2d", list->max, r & 0xff);
fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
fprintf(stderr, " %1u", (unsigned)((r & _RUNETYPE_SWM)>>_RUNETYPE_SWS));
fprintf(stderr, "\n");
} else
for (x = list->min; x <= list->max; ++x) {
u_int32_t r = ntohl(list->types[x - list->min]);
if (r) {
fprintf(stderr, "%04x:%2d", x, (int)(r & 0xff));
fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
fprintf(stderr, " %1u", (unsigned)((r & _RUNETYPE_SWM)>>_RUNETYPE_SWS));
fprintf(stderr, "\n");
}
}
}
}