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:
@@ -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
6
usr.bin/gencat/Makefile
Normal 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
233
usr.bin/gencat/gencat.1
Normal 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
879
usr.bin/gencat/gencat.c
Normal 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
11
usr.bin/locale/Makefile
Normal 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
113
usr.bin/locale/locale.1
Normal 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
707
usr.bin/locale/locale.c
Normal 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);
|
||||
}
|
||||
}
|
||||
23
usr.bin/mkcsmapper/Makefile
Normal file
23
usr.bin/mkcsmapper/Makefile
Normal 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
40
usr.bin/mkcsmapper/ldef.h
Normal 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
113
usr.bin/mkcsmapper/lex.l
Normal 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
734
usr.bin/mkcsmapper/yacc.y
Normal 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
22
usr.bin/mkesdb/Makefile
Normal 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
40
usr.bin/mkesdb/ldef.h
Normal 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
103
usr.bin/mkesdb/lex.l
Normal 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
347
usr.bin/mkesdb/yacc.y
Normal 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
25
usr.bin/mklocale/Makefile
Normal 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
51
usr.bin/mklocale/ldef.h
Normal 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
186
usr.bin/mklocale/lex.l
Normal 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
285
usr.bin/mklocale/mklocale.1
Normal 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.
|
||||
280
usr.bin/mklocale/mklocaledb.c
Normal file
280
usr.bin/mklocale/mklocaledb.c
Normal 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
910
usr.bin/mklocale/yacc.y
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user