Wed May 17 16:50:21 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
Merged 1003.2 locale and localedef programs by Ulrich Drepper. * locale/charmap.c: New file. * locale/collate.c: New file. * locale/config.h: New file. * locale/ctype.c: New file. * locale/ctypedump.c: New file. * locale/hash.c: New file. * locale/hash.h: New file. * locale/iso-4217.def: New file. * locale/keyword.gperf: New file. * locale/keyword.h: New file. * locale/libintl.h: New file. * locale/locale.c: New file. * locale/localedef.c: New file. * locale/localedef.h: New file. * locale/locfile-lex.c: New file. * locale/locfile-parse.c: New file. * locale/messages.c: New file. * locale/monetary.c: New file. * locale/numeric.c: New file. * locale/token.h: New file. * posix/regex.c, posix/regex.h: New files, incorporated from GNU regex. * posix/Makefile (headers): Add regex.h. (routines): Add regex. (gpl2lgpl): Add regex.c and regex.h. Tue May 16 17:35:07 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu> * locale/loadlocale.c: Expect macro LOCALE_PATH to be defined, instead of hard-coding "/share/locale".
This commit is contained in:
parent
4f6dc78a92
commit
2b83a2a4d9
34
ChangeLog
34
ChangeLog
|
@ -1,3 +1,37 @@
|
|||
Wed May 17 16:50:21 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
Merged 1003.2 locale and localedef programs by Ulrich Drepper.
|
||||
* locale/charmap.c: New file.
|
||||
* locale/collate.c: New file.
|
||||
* locale/config.h: New file.
|
||||
* locale/ctype.c: New file.
|
||||
* locale/ctypedump.c: New file.
|
||||
* locale/hash.c: New file.
|
||||
* locale/hash.h: New file.
|
||||
* locale/iso-4217.def: New file.
|
||||
* locale/keyword.gperf: New file.
|
||||
* locale/keyword.h: New file.
|
||||
* locale/libintl.h: New file.
|
||||
* locale/locale.c: New file.
|
||||
* locale/localedef.c: New file.
|
||||
* locale/localedef.h: New file.
|
||||
* locale/locfile-lex.c: New file.
|
||||
* locale/locfile-parse.c: New file.
|
||||
* locale/messages.c: New file.
|
||||
* locale/monetary.c: New file.
|
||||
* locale/numeric.c: New file.
|
||||
* locale/token.h: New file.
|
||||
|
||||
* posix/regex.c, posix/regex.h: New files, incorporated from GNU regex.
|
||||
* posix/Makefile (headers): Add regex.h.
|
||||
(routines): Add regex.
|
||||
(gpl2lgpl): Add regex.c and regex.h.
|
||||
|
||||
Tue May 16 17:35:07 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
* locale/loadlocale.c: Expect macro LOCALE_PATH to be defined,
|
||||
instead of hard-coding "/share/locale".
|
||||
|
||||
Sat May 13 02:16:42 1995 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
|
||||
|
||||
* configure.in (os=gnu*): Always set elf=yes, not just for os=gnu*elf*.
|
||||
|
|
26
configure
vendored
26
configure
vendored
|
@ -571,6 +571,19 @@ echo "$ac_t""$host" 1>&4
|
|||
# $machine, $vendor, and $os, and changes them whenever convenient.
|
||||
config_machine=$host_cpu config_vendor=$host_vendor config_os=$host_os
|
||||
|
||||
# Some configurations imply other options.
|
||||
case "$host_os" in
|
||||
gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
|
||||
# These systems always use GNU tools.
|
||||
gnu_ld=yes gnu_as=yes
|
||||
esac
|
||||
case "$host_os" in
|
||||
gnu* | linux* | sysv4* | solaris2*)
|
||||
# These systems always use the ELF format.
|
||||
elf=yes
|
||||
esac
|
||||
|
||||
# Compute the list of sysdep directories for this configuration.
|
||||
sysdep_dir=$srcdir/sysdeps
|
||||
echo $ac_n "checking sysdep dirs""... $ac_c" 1>&4
|
||||
if eval "test \"`echo '$''{'libc_cv_sysdirs'+set}'`\" = set"; then
|
||||
|
@ -621,19 +634,6 @@ none)
|
|||
base_os='' ;;
|
||||
esac
|
||||
|
||||
# Some configurations imply other options.
|
||||
case "$os" in
|
||||
gnu* | linux* | bsd4.4* | netbsd* | freebsd*)
|
||||
# These systems always use GNU tools.
|
||||
gnu_ld=yes gnu_as=yes
|
||||
esac
|
||||
case "$os" in
|
||||
gnu* | linux* | sysv4* | solaris2*)
|
||||
# These systems always use the ELF format.
|
||||
elf=yes
|
||||
esac
|
||||
|
||||
|
||||
# For sunos4.1.1, try sunos4.1.1, then sunos4.1, then sunos4, then sunos.
|
||||
tail=$os
|
||||
ostry=$os
|
||||
|
|
|
@ -21,10 +21,36 @@
|
|||
#
|
||||
subdir := locale
|
||||
|
||||
headers := locale.h
|
||||
distribute := localeinfo.h categories.def
|
||||
routines := setlocale loadlocale localeconv
|
||||
categories := ctype messages monetary numeric time collate
|
||||
headers = locale.h
|
||||
distribute = localeinfo.h categories.def \
|
||||
$(localedef-modules:=.c) $(locale-modules:=.c) \
|
||||
$(lib-modules:=.c) config.h hash.h iso-4217.def \
|
||||
keyword.gperf keyword.h localedef.h token.h
|
||||
routines = setlocale loadlocale localeconv nl_langinfo
|
||||
categories = ctype messages monetary numeric time collate
|
||||
aux = $(categories:%=lc-%) $(categories:%=C-%)
|
||||
others = localedef locale
|
||||
install-bin = localedef locale
|
||||
extra-objs = $(localedef-modules:=.o) $(locale-modules:=.o) \
|
||||
$(lib-modules:=.o)
|
||||
|
||||
localedef-modules := charmap locfile-lex locfile-parse ctype \
|
||||
monetary messages collate numeric
|
||||
locale-modules := ctypedump
|
||||
lib-modules := error hash xmalloc
|
||||
|
||||
|
||||
GPERF = gperf
|
||||
GPERFFLAGS = -acCgopt -k1,2,5,$$
|
||||
|
||||
include ../Rules
|
||||
|
||||
keyword.h: keyword.gperf
|
||||
$(GPERF) $(GPERFFLAGS) $< > $@.new
|
||||
mv -f $@.new $@
|
||||
|
||||
$(objpfx)localedef: $(localedef-modules:%=$(objpfx)%.o)
|
||||
$(objpfx)locale: $(locale-modules:%=$(objpfx)%.o)
|
||||
$(objpfx)localedef $(objpfx)locale: $(lib-modules:%=$(objpfx)%.o)
|
||||
|
||||
CPPFLAGS += -DLOCALE_PATH='"$(localedir)"' -DCHARMAP_PATH='"$(nlsdir)/charmap"'
|
||||
|
|
|
@ -101,6 +101,10 @@ DEFINE_CATEGORY (LC_TIME, "LC_TIME",
|
|||
{ D_FMT, "d_fmt", std, string },
|
||||
{ T_FMT, "t_fmt", std, string },
|
||||
{ T_FMT_AMPM, "t_fmt_ampm", std, string },
|
||||
{ ERA, "era", opt, string },
|
||||
{ ERA_YEAR, "era_year", opt, string },
|
||||
{ ERA_D_FMT, "era_d_fmt", opt, string },
|
||||
{ ALT_DIGITS, "alt_digits", opt, stringarray, 0, 100 },
|
||||
{ 0 }
|
||||
), NO_POSTLOAD, NULL, NULL, NULL )
|
||||
|
||||
|
|
524
locale/charmap.c
Normal file
524
locale/charmap.c
Normal file
|
@ -0,0 +1,524 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "localedef.h"
|
||||
#include "hash.h"
|
||||
|
||||
/* Data structure for representing charmap database. */
|
||||
struct charmap charmap_data;
|
||||
|
||||
/* Line number in charmap file. */
|
||||
static unsigned int line_no;
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static void read_prolog (FILE *infile);
|
||||
static unsigned long read_body (FILE *infile);
|
||||
|
||||
|
||||
/* Read complete table of symbolic names for character set from file. If
|
||||
this file does not exist or is not readable a default file is tried.
|
||||
If this also is not readable no character map is defined. */
|
||||
void
|
||||
charmap_read (const char *filename)
|
||||
{
|
||||
unsigned long max_char;
|
||||
long path_max = pathconf (".", _PC_PATH_MAX);
|
||||
char buf[path_max];
|
||||
FILE *infile = NULL;
|
||||
|
||||
/* Initialize charmap data. */
|
||||
charmap_data.codeset_name = NULL;
|
||||
charmap_data.mb_cur_max = -1;
|
||||
charmap_data.mb_cur_min = -1;
|
||||
charmap_data.escape_char = '\\';
|
||||
charmap_data.comment_char = '#';
|
||||
|
||||
if (filename != NULL)
|
||||
{
|
||||
strcpy (buf, filename);
|
||||
infile = fopen (filename, "r");
|
||||
if (infile == NULL && filename[0] != '/')
|
||||
{
|
||||
snprintf (buf, path_max, "%s/%s", CHARMAP_PATH, filename);
|
||||
infile = fopen (buf, "r");
|
||||
}
|
||||
}
|
||||
if (infile == NULL)
|
||||
{
|
||||
if (filename != NULL)
|
||||
error (0, errno, gettext ("input file `%s' not found"), filename);
|
||||
|
||||
snprintf (buf, path_max, "%s/%s", CHARMAP_PATH, DEFAULT_CHARMAP);
|
||||
infile = fopen (buf, "r");
|
||||
|
||||
if (infile == NULL)
|
||||
error (4, errno, gettext ("input file `%s' not found"), filename);
|
||||
}
|
||||
|
||||
charmap_data.filename = buf;
|
||||
init_hash (&charmap_data.table, 500);
|
||||
line_no = 0;
|
||||
|
||||
/* Read the prolog of the charmap file. */
|
||||
read_prolog (infile);
|
||||
|
||||
/* Last works on the charmap tables global data. */
|
||||
if (charmap_data.mb_cur_max == -1)
|
||||
charmap_data.mb_cur_max = 1;
|
||||
if (charmap_data.mb_cur_min == -1)
|
||||
charmap_data.mb_cur_min = charmap_data.mb_cur_max;
|
||||
|
||||
if ((size_t) charmap_data.mb_cur_max > sizeof (long))
|
||||
{
|
||||
error (2, 0, gettext ("program limitation: for now only upto %Zu "
|
||||
"bytes per character are allowed"), sizeof (long));
|
||||
}
|
||||
|
||||
/* Now process all entries. */
|
||||
max_char = read_body (infile);
|
||||
|
||||
/* We don't need the file anymore. */
|
||||
fclose (infile);
|
||||
|
||||
|
||||
/* Determine the optimal table size when using the simple modulo hashing
|
||||
function. */
|
||||
if (max_char >= 256)
|
||||
{
|
||||
int size;
|
||||
/* Current best values, initialized to some never reached high value. */
|
||||
int best_count = 10000;
|
||||
int best_size = 10000;
|
||||
int best_product = best_count * best_size;
|
||||
|
||||
/* Give warning. */
|
||||
error (-1, 0, gettext ("computing character table size: this may take "
|
||||
"a while"));
|
||||
|
||||
for (size = 256; size <= best_product; ++size)
|
||||
{
|
||||
/* Array with slot counters. */
|
||||
int cnt[size];
|
||||
/* Current character. */
|
||||
int ch;
|
||||
/* Maximal number of characters in any slot. */
|
||||
int maxcnt = 0;
|
||||
/* Product of current size and maximal count. */
|
||||
int product = 0;
|
||||
/* Iteration pointer through hashing table. */
|
||||
char *ptr = NULL;
|
||||
|
||||
/* Initializes counters to zero. */
|
||||
memset(cnt, 0, size * sizeof (int));
|
||||
|
||||
/* Iterate through whole hashing table. */
|
||||
while (product < best_product
|
||||
&& iterate_table (&charmap_data.table, (void **) &ptr,
|
||||
(void **) &ch))
|
||||
{
|
||||
/* Increment slot counter. */
|
||||
++cnt[ch % size];
|
||||
/* Test for current maximum. */
|
||||
if (cnt[ch % size] > maxcnt)
|
||||
{
|
||||
maxcnt = cnt[ch % size];
|
||||
product = maxcnt * size;
|
||||
}
|
||||
}
|
||||
|
||||
if (product < best_product)
|
||||
{
|
||||
best_count = maxcnt;
|
||||
best_size = size;
|
||||
best_product = best_count * best_size;
|
||||
}
|
||||
}
|
||||
|
||||
charmap_data.hash_size = best_size;
|
||||
charmap_data.hash_layers = best_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
charmap_data.hash_size = 256;
|
||||
charmap_data.hash_layers = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define SYNTAX_ERROR \
|
||||
do { error (0, 0, gettext ("%s:%u: syntax error in charmap file"), \
|
||||
charmap_data.filename, line_no); \
|
||||
goto end_of_loop; } while (0)
|
||||
|
||||
/* Read the prolog of the charmap file until the line containing `CHARMAP'.
|
||||
All possible entries are processed. */
|
||||
static void
|
||||
read_prolog (FILE *infile)
|
||||
{
|
||||
size_t bufsize = sysconf (_SC_LINE_MAX);
|
||||
char buf[bufsize];
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *cp = buf;
|
||||
char len;
|
||||
|
||||
/* Read the next line. */
|
||||
fgets (buf, bufsize, infile);
|
||||
len = strlen (buf);
|
||||
|
||||
/* On EOF simply return. */
|
||||
if (len == 0 || buf[len - 1] != '\n')
|
||||
error (4, 0, gettext ("%s: unexpected end of file in charmap"),
|
||||
charmap_data.filename);
|
||||
|
||||
/* This is the next line. */
|
||||
++line_no;
|
||||
|
||||
/* Comments and empty lines are ignored. */
|
||||
if (len == 1 || buf[0] == charmap_data.comment_char)
|
||||
continue;
|
||||
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
/* Throw away leading white spaces. This is not defined in POSIX.2
|
||||
so don't do it if conformance is requested. */
|
||||
if (!posix_conformance)
|
||||
while (isspace (*cp))
|
||||
++cp;
|
||||
|
||||
/* If `CHARMAP' is read the prolog is over. */
|
||||
if (strncmp (cp, "CHARMAP", 7) == 0
|
||||
&& (!posix_conformance || cp[7] == '\0'))
|
||||
return;
|
||||
|
||||
/* Now it can be only one of special symbols defining the charmap
|
||||
parameters. All are beginning with '<'. */
|
||||
if (*cp != '<')
|
||||
SYNTAX_ERROR;
|
||||
|
||||
++cp;
|
||||
if (strncmp (cp, "code_set_name>", 14) == 0)
|
||||
{
|
||||
char *startp;
|
||||
|
||||
#define cp_to_arg(no,pred) \
|
||||
cp += no; \
|
||||
while (isspace (*cp)) \
|
||||
++cp; \
|
||||
if (*cp == '\0' || !pred (*cp)) \
|
||||
SYNTAX_ERROR;
|
||||
|
||||
cp_to_arg (14,isgraph)
|
||||
|
||||
if (charmap_data.codeset_name != NULL)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%u: duplicate code set name "
|
||||
"specification"),
|
||||
charmap_data.filename, line_no);
|
||||
free (charmap_data.codeset_name);
|
||||
}
|
||||
|
||||
startp = cp;
|
||||
while (*cp != '\0' && isgraph (*cp) && !isspace (*cp))
|
||||
++cp;
|
||||
|
||||
charmap_data.codeset_name = (char *) xmalloc (cp - startp + 1);
|
||||
strncpy (startp, startp, cp - startp);
|
||||
}
|
||||
else if (strncmp (cp, "mb_cur_max>", 11) == 0)
|
||||
{
|
||||
int new_val;
|
||||
cp_to_arg (11,isdigit)
|
||||
|
||||
if (charmap_data.mb_cur_max != -1)
|
||||
error (0, 0,
|
||||
gettext ("%s:%u: duplicate definition of mb_cur_max"),
|
||||
charmap_data.filename, line_no);
|
||||
|
||||
new_val = (int) strtol (cp, &cp, posix_conformance ? 10 : 0);
|
||||
if (new_val < 1)
|
||||
error (0, 0, gettext ("%s:%u: illegal value for mb_cur_max: %d"),
|
||||
charmap_data.filename, line_no, new_val);
|
||||
else
|
||||
charmap_data.mb_cur_max = new_val;
|
||||
}
|
||||
else if (strncmp (cp, "mb_cur_min>", 11) == 0)
|
||||
{
|
||||
int new_val;
|
||||
cp_to_arg (11,isdigit)
|
||||
|
||||
if (charmap_data.mb_cur_max != -1)
|
||||
error (0, 0,
|
||||
gettext ("%s:%u: duplicate definition of mb_cur_min"),
|
||||
charmap_data.filename, line_no);
|
||||
|
||||
new_val = (int) strtol (cp, &cp, posix_conformance ? 10 : 0);
|
||||
if (new_val < 1)
|
||||
error (0, 0, gettext ("%s:%u: illegal value for mb_cur_min: %d"),
|
||||
charmap_data.filename, line_no, new_val);
|
||||
else
|
||||
charmap_data.mb_cur_min = new_val;
|
||||
}
|
||||
else if (strncmp (cp, "escape_char>", 12) == 0)
|
||||
{
|
||||
cp_to_arg (12, isgraph)
|
||||
charmap_data.escape_char = *cp;
|
||||
}
|
||||
else if (strncmp (cp, "comment_char>", 13) == 0)
|
||||
{
|
||||
cp_to_arg (13, isgraph)
|
||||
charmap_data.comment_char = *cp;
|
||||
}
|
||||
else
|
||||
SYNTAX_ERROR;
|
||||
end_of_loop:
|
||||
}
|
||||
}
|
||||
#undef cp_to_arg
|
||||
|
||||
|
||||
static unsigned long
|
||||
read_body (FILE *infile)
|
||||
{
|
||||
unsigned long max_char = 0;
|
||||
size_t bufsize = sysconf (_SC_LINE_MAX);
|
||||
char buf[bufsize];
|
||||
char name_str[bufsize / 2];
|
||||
char code_str[bufsize / 2];
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *cp = buf;
|
||||
size_t len;
|
||||
|
||||
/* Read the next line. */
|
||||
fgets (buf, bufsize, infile);
|
||||
len = strlen (buf);
|
||||
|
||||
/* On EOF simply return. */
|
||||
if (len == 0)
|
||||
error (0, 0, gettext ("%s: `END CHARMAP' is missing"),
|
||||
charmap_data.filename);
|
||||
|
||||
/* This is the next line. */
|
||||
++line_no;
|
||||
|
||||
if (len == bufsize - 1)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%u: line too long; use `getconf "
|
||||
"LINE_MAX' to get the current maximum line"
|
||||
"length"), charmap_data.filename, line_no);
|
||||
do
|
||||
{
|
||||
fgets (buf, bufsize, infile);
|
||||
len = strlen (buf);
|
||||
}
|
||||
while (len == bufsize - 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Comments and empty lines are ignored. */
|
||||
if (len == 1 || buf[0] == charmap_data.comment_char)
|
||||
continue;
|
||||
|
||||
buf[len - 1] = '\0';
|
||||
|
||||
/* Throw away leading white spaces. This is not defined in POSIX.2
|
||||
so don't do it if conformance is requested. */
|
||||
if (!posix_conformance)
|
||||
while (isspace (*cp))
|
||||
++cp;
|
||||
|
||||
if (*cp == '<')
|
||||
{
|
||||
char *end1p, *end2p, *start2p;
|
||||
size_t cnt = 0;
|
||||
unsigned long char_value = 0;
|
||||
|
||||
if (sscanf (cp + 1, "%s %s", name_str, code_str) != 2)
|
||||
SYNTAX_ERROR;
|
||||
|
||||
end1p = cp = name_str;
|
||||
while (*cp != '\0' && *cp != '>')
|
||||
{
|
||||
if (*cp == charmap_data.escape_char)
|
||||
if (*++cp == '\0')
|
||||
SYNTAX_ERROR;
|
||||
*end1p++ = *cp++;
|
||||
}
|
||||
if (*cp == '\0')
|
||||
/* No final '>'. Make error condition. */
|
||||
end1p = name_str;
|
||||
else
|
||||
++cp;
|
||||
|
||||
*end1p = '\0';
|
||||
|
||||
if (*cp == '.' && *++cp == '.' && *++cp == '.' && *++cp == '<')
|
||||
{
|
||||
/* This might be the alternate form. */
|
||||
start2p = end2p = ++cp;
|
||||
while (*cp != '\0' && *cp != '>')
|
||||
{
|
||||
if (*cp == charmap_data.escape_char)
|
||||
if (*++cp == '\0')
|
||||
SYNTAX_ERROR;
|
||||
*end2p = *cp++;
|
||||
}
|
||||
if (*cp == '\0')
|
||||
/* NO final '>'. Make error condition. */
|
||||
end2p = start2p;
|
||||
else
|
||||
++cp;
|
||||
}
|
||||
else
|
||||
start2p = end2p = NULL;
|
||||
|
||||
|
||||
if (end1p == name_str || (start2p != NULL && start2p != end2p)
|
||||
|| *cp != '\0'
|
||||
|| *code_str != charmap_data.escape_char)
|
||||
SYNTAX_ERROR;
|
||||
|
||||
cp = code_str;
|
||||
do
|
||||
{
|
||||
char *begin;
|
||||
long val;
|
||||
|
||||
switch (*++cp)
|
||||
{
|
||||
case 'd':
|
||||
val = strtol ((begin = cp + 1), &cp, 10);
|
||||
break;
|
||||
case 'x':
|
||||
val = strtol ((begin = cp + 1), &cp, 16);
|
||||
break;
|
||||
default:
|
||||
val = strtol ((begin = cp), &cp, 8);
|
||||
break;
|
||||
}
|
||||
if (begin == cp)
|
||||
SYNTAX_ERROR;
|
||||
|
||||
if (posix_conformance && cp - begin < 2)
|
||||
error (0, 0, gettext ("%s:%u: byte constant has less than "
|
||||
"two digits"),
|
||||
charmap_data.filename, line_no);
|
||||
|
||||
if (val < 0 || val > 255)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%u: character encoding must be "
|
||||
"given in 8-bit bytes"),
|
||||
charmap_data.filename, line_no);
|
||||
goto end_of_loop;
|
||||
}
|
||||
|
||||
if (cnt < (size_t) charmap_data.mb_cur_max)
|
||||
{
|
||||
if (cnt < sizeof (long)) /* FIXME */
|
||||
char_value = (char_value << 8) | val;
|
||||
}
|
||||
else
|
||||
{
|
||||
error (0, 0, gettext ("%s:%u: number of bytes in character "
|
||||
"definition exceeds `mb_cur_max'"),
|
||||
charmap_data.filename, line_no);
|
||||
break;
|
||||
}
|
||||
++cnt;
|
||||
}
|
||||
while (*cp == charmap_data.escape_char);
|
||||
|
||||
/* Ignore the rest of the line (comment). */
|
||||
if (end2p == NULL)
|
||||
{
|
||||
if (insert_entry (&charmap_data.table, name_str,
|
||||
end1p - name_str, (void *) char_value))
|
||||
error (0, 0, gettext ("%s:%u: duplicate entry"),
|
||||
charmap_data.filename, line_no);
|
||||
|
||||
max_char = MAX (max_char, char_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *en1, *en2, *start1p;
|
||||
long n1, n2, n;
|
||||
|
||||
start1p = name_str;
|
||||
|
||||
while (*start1p == *start2p && !isdigit (*start1p)
|
||||
&& start1p < end1p)
|
||||
++start1p, ++start2p;
|
||||
|
||||
n1 = strtol (start1p, &en1, 10);
|
||||
n2 = strtol (start2p, &en2, 10);
|
||||
|
||||
if (en1 - start1p != en2 - start2p || en1 != end1p
|
||||
|| en2 != end2p)
|
||||
SYNTAX_ERROR;
|
||||
|
||||
if (n1 > n2)
|
||||
error (0, 0, gettext ("%s:%u: starting character is bigger "
|
||||
"than last"),
|
||||
charmap_data.filename, line_no);
|
||||
|
||||
n = n1;
|
||||
while (n <= n2)
|
||||
{
|
||||
snprintf(start1p, en1 - start1p, "%0*d", en1 - start1p, n);
|
||||
|
||||
if (insert_entry (&charmap_data.table, name_str,
|
||||
en1 - name_str,
|
||||
(void *) (char_value + n - n1)))
|
||||
error (0, 0, gettext ("%s:%u: duplicate entry"),
|
||||
charmap_data.filename, line_no);
|
||||
|
||||
max_char = MAX (max_char, char_value + n - n1);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp (cp, "END CHARMAP", 11) == 0)
|
||||
return max_char;
|
||||
|
||||
SYNTAX_ERROR;
|
||||
}
|
||||
end_of_loop:
|
||||
}
|
||||
|
||||
return max_char;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
212
locale/collate.c
Normal file
212
locale/collate.c
Normal file
|
@ -0,0 +1,212 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
|
||||
#include "localedef.h"
|
||||
#include "token.h"
|
||||
|
||||
|
||||
/* defined in locfile-lex.c: flag to indicate that unknown element names
|
||||
are allowed. */
|
||||
extern int reject_new_char;
|
||||
|
||||
|
||||
#define SYNTAX_ERROR \
|
||||
error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
|
||||
void
|
||||
collate_input (int token)
|
||||
{
|
||||
int read_order_start = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *ptr;
|
||||
int len;
|
||||
|
||||
if (token == TOK_END)
|
||||
/* This is the end of the category. */
|
||||
{
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token != _NL_NUM_LC_COLLATE)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
|
||||
"with `END %s'"), locfile_data.filename,
|
||||
locfile_data.line_no, "LC_COLLATE", "LC_COLLATE");
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
else
|
||||
ignore_to_eol (0, 1);
|
||||
|
||||
/* Start next category. */
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Process line. */
|
||||
if (read_order_start == 0)
|
||||
/* We're still in the preambel. */
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case TOK_COLLATING_ELEMENT:
|
||||
reject_new_char = 0;
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
reject_new_char = 1;
|
||||
if (token == TOK_CHAR)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: symbolic name must not be "
|
||||
"duplicate name in charmap"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
else if (token != TOK_ILL_CHAR)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
char elem_name[len + 1];
|
||||
memcpy (elem_name, ptr, len);
|
||||
elem_name[len] = '\0';
|
||||
|
||||
/* Test whether defined in symbol table. */
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_FROM)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_STRING)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Insert collating element into table. */
|
||||
|
||||
/* Rest of the line should be empty. */
|
||||
ignore_to_eol (0, 1);
|
||||
}
|
||||
break;
|
||||
case TOK_COLLATING_SYMBOL:
|
||||
reject_new_char = 0;
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
reject_new_char = 1;
|
||||
if (token == TOK_CHAR)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: symbolic name must not "
|
||||
"duplicate name in charmap"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
else if (token != TOK_ILL_CHAR)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Test whether defined in element table. */
|
||||
|
||||
/* Insert collating symbol into table. */
|
||||
|
||||
ignore_to_eol (0, 1);
|
||||
}
|
||||
case TOK_ORDER_START:
|
||||
nsort_rules = 0;
|
||||
|
||||
do
|
||||
{
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (nsort_rules == 0 && token == ENDOFLINE)
|
||||
break;
|
||||
|
||||
if (token != TOK_BACKWARD && token != TOK_FORWARD
|
||||
&& token != TOK_POSITION)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (token)
|
||||
{
|
||||
case TOK_BACKWARD:
|
||||
if ((sort_rule[nsort_rules] & FORWARD_BIT) != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: directives `forward' "
|
||||
"and `backward' are mutually "
|
||||
"exclusive"),
|
||||
locfile_data.filename, locfile_data.lineno);
|
||||
else
|
||||
sort_rule[nsort_rules] |= BACKWARD_BIT;
|
||||
break;
|
||||
case TOK_FORWARD:
|
||||
if ((sort_rule[nsort_rules] & BACKWARD_BIT) != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: directives `forward' "
|
||||
"and `backward' are mutually "
|
||||
"exclusive"),
|
||||
locfile_data.filename, locfile_data.lineno);
|
||||
else
|
||||
sort_rule[nsort_rules] |= FORWARD_BIT;
|
||||
break;
|
||||
case TOK_POSITION:
|
||||
sort_rule[nsort_rules] |= POSITION_BIT;
|
||||
break;
|
||||
}
|
||||
|
||||
++nsort_rules;
|
||||
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (token, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
ignore_to_eol(token,0);
|
||||
/* Get next token. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
45
locale/config.h
Normal file
45
locale/config.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/* config.h used by locale and localedef programs in GNU libc.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _CONFIG_H
|
||||
#define _CONFIG_H
|
||||
|
||||
#define PACKAGE "libc"
|
||||
#define VERSION __libc_version
|
||||
extern const char __libc_version[];
|
||||
|
||||
#define DEFAULT_CHARMAP "POSIX"
|
||||
|
||||
|
||||
/* These are tested by xmalloc.c and error.c. */
|
||||
#define HAVE_VPRINTF 1
|
||||
#define STDC_HEADERS 1
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
#define program_name program_invocation_name
|
||||
|
||||
typedef unsigned short u16;
|
||||
typedef int i32;
|
||||
typedef int u32;
|
||||
|
||||
|
||||
/* Get the global libc configuration info. */
|
||||
#include_next <config.h>
|
||||
|
||||
#endif /* config.h */
|
817
locale/ctype.c
Normal file
817
locale/ctype.c
Normal file
|
@ -0,0 +1,817 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <alloca.h>
|
||||
#include <fcntl.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <localeinfo.h>
|
||||
#include <langinfo.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "localedef.h"
|
||||
#include "token.h"
|
||||
|
||||
/* Arrays representing ctype tables. They must be initialized for the
|
||||
right size to hold the full charmap. */
|
||||
static u16 *ctype_b;
|
||||
static i32 *names_b, *toupper_b, *tolower_b;
|
||||
|
||||
/* For accessing the element of the (possibly sparse) array we use this
|
||||
macro. */
|
||||
#define ELEM(arr, idx) \
|
||||
(arr)[({ int h = idx % charmap_data.hash_size; \
|
||||
int n = 0; \
|
||||
while (n < charmap_data.hash_layers \
|
||||
&& names_b[n * charmap_data.hash_size + h] != idx) \
|
||||
++n; \
|
||||
if (n >= charmap_data.hash_layers) \
|
||||
error (6, 0, gettext ("internal error in %s, line %u"), \
|
||||
__FUNCTION__, __LINE__); \
|
||||
n * charmap_data.hash_size + h; })]
|
||||
|
||||
/* The bit used for representing a special class. */
|
||||
#define BITPOS(class) ((class) - TOK_UPPER)
|
||||
#define BIT(class) (1 << BITPOS (class))
|
||||
|
||||
/* Remember which class or conversion is already done. */
|
||||
static unsigned short class_done = 0;
|
||||
static unsigned short toupper_done = 0;
|
||||
static unsigned short tolower_done = 0;
|
||||
|
||||
#define SYNTAX_ERROR \
|
||||
error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static void allocate_arrays (void);
|
||||
static void set_class_defaults (void);
|
||||
static int valid_char (int ch);
|
||||
|
||||
|
||||
/* Read CTYPE category. The initial token is given as a parameter. */
|
||||
void
|
||||
ctype_input (int token)
|
||||
{
|
||||
char *ptr;
|
||||
int len;
|
||||
|
||||
/* If necessary allocate arrays. */
|
||||
allocate_arrays ();
|
||||
|
||||
while (token != TOK_END)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
case TOK_UPPER: case TOK_LOWER: case TOK_ALPHA: case TOK_DIGIT:
|
||||
case TOK_XDIGIT: case TOK_SPACE: case TOK_PRINT: case TOK_GRAPH:
|
||||
case TOK_BLANK: case TOK_CNTRL: case TOK_PUNCT:
|
||||
{
|
||||
/* TAKE CARE: the order of the tokens in "token.h" determines
|
||||
the bit used to indicate the membership in the class. This
|
||||
also has to correspond to the values used in <ctype.h>. */
|
||||
int bit = BIT (token);
|
||||
int was_ell = 0;
|
||||
int last = -1;
|
||||
|
||||
if ((class_done & bit) != 0)
|
||||
{
|
||||
char tmp[len + 1];
|
||||
memcpy (tmp, ptr, len);
|
||||
tmp[len] = '\0';
|
||||
|
||||
error (0, 0, gettext ("%s:%Zd: duplicate definiton of item "
|
||||
"`%s' in category `LC_CTYPE'"),
|
||||
locfile_data.filename, locfile_data.line_no, tmp);
|
||||
}
|
||||
class_done |= bit;
|
||||
|
||||
do
|
||||
{
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token == TOK_ENDOFLINE)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (token == TOK_ELLIPSIS)
|
||||
{
|
||||
if (was_ell != 0 || last < 0)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: illegal use of `...'"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
break;
|
||||
}
|
||||
was_ell = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (token != TOK_CHAR)
|
||||
{
|
||||
if (token != TOK_ILL_CHAR)
|
||||
SYNTAX_ERROR;
|
||||
was_ell = 0;
|
||||
last = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (len < 0 || !valid_char (len))
|
||||
{
|
||||
was_ell = 0;
|
||||
last = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We have found a valid character. Include it to
|
||||
the class' bit set. */
|
||||
if (was_ell == 0)
|
||||
{
|
||||
ELEM (ctype_b, len) |= bit;
|
||||
last = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
if (last > len)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: lower bound of "
|
||||
"ellipsis not smaller"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
was_ell = 0;
|
||||
last = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = last + 1; i <= len; ++i)
|
||||
ELEM (ctype_b, i) |= bit;
|
||||
|
||||
last = -1;
|
||||
}
|
||||
was_ell = 0;
|
||||
}
|
||||
while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
|
||||
&& len == ';');
|
||||
|
||||
/* Rest of the line should be empty. */
|
||||
ignore_to_eol (token, 0);
|
||||
}
|
||||
break;
|
||||
case TOK_TOUPPER: case TOK_TOLOWER:
|
||||
{
|
||||
int from;
|
||||
int to = -1;
|
||||
int is_upper = token == TOK_TOUPPER;
|
||||
|
||||
if (((is_upper ? toupper_done : tolower_done) & BIT (token)) != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: duplicate definition of item "
|
||||
"`%s' in category `LC_CTYPE'"),
|
||||
locfile_data.filename, locfile_data.line_no,
|
||||
is_upper ? "toupper" : "tolower");
|
||||
(is_upper ? toupper_done : tolower_done) |= BIT (token);
|
||||
|
||||
do
|
||||
{
|
||||
int ignore;
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_CHAR || len != '(')
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_CHAR && token != TOK_ILL_CHAR)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
from = len;
|
||||
ignore = token == TOK_ILL_CHAR;
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_CHAR || len != ',')
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_CHAR && token != TOK_ILL_CHAR)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
to = len;
|
||||
ignore |= token == TOK_ILL_CHAR;
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_CHAR || len != ')')
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ignore && valid_char (from) && valid_char (to))
|
||||
/* Have a valid pair. */
|
||||
ELEM (is_upper ? toupper_b : tolower_b, from) = to;
|
||||
}
|
||||
while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
|
||||
&& len == ';');
|
||||
|
||||
/* Rest of the line should be empty. */
|
||||
ignore_to_eol (token, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (0, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read next token. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
}
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token != _NL_NUM_LC_CTYPE)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: category `%s' does not end with "
|
||||
"`END %s'"), locfile_data.filename,
|
||||
locfile_data.line_no, "LC_CTYPE", "LC_CTYPE");
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
else
|
||||
ignore_to_eol (0, posix_conformance);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ctype_check(void)
|
||||
{
|
||||
/* Here are a lot of things to check. See POSIX.2, table 2-6. */
|
||||
#define NCLASS 11
|
||||
static const struct
|
||||
{
|
||||
const char *name;
|
||||
const char allow[NCLASS];
|
||||
}
|
||||
valid_table[NCLASS] =
|
||||
{
|
||||
/* The order is important. See token.h for more information.
|
||||
M = Always, D = Default, - = Permitted, X = Mutually exclusive */
|
||||
[BITPOS (TOK_UPPER)] = { "upper", "--MX-XDDXXX" },
|
||||
[BITPOS (TOK_LOWER)] = { "lower", "--MX-XDDXXX" },
|
||||
[BITPOS (TOK_ALPHA)] = { "alpha", "---X-XDDXXX" },
|
||||
[BITPOS (TOK_DIGIT)] = { "digit", "XXX--XDDXXX" },
|
||||
[BITPOS (TOK_XDIGIT)] = { "xdigit", "-----XDDXXX" },
|
||||
[BITPOS (TOK_SPACE)] = { "space", "XXXXX------" },
|
||||
[BITPOS (TOK_PRINT)] = { "print", "---------X-" },
|
||||
[BITPOS (TOK_GRAPH)] = { "graph", "---------X-" },
|
||||
[BITPOS (TOK_BLANK)] = { "blank", "XXXXXM-----" },
|
||||
[BITPOS (TOK_CNTRL)] = { "cntrl", "XXXXX-XX--X" },
|
||||
[BITPOS (TOK_PUNCT)] = { "punct", "XXXXX-DD-X-" }
|
||||
};
|
||||
int ch, cls1, cls2, eq, space_char;
|
||||
u16 tmp;
|
||||
|
||||
/* Set default value for classes not specified. */
|
||||
set_class_defaults ();
|
||||
|
||||
/* Check according to table. */
|
||||
for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers; ++ch)
|
||||
{
|
||||
if (ch != 0 && names_b[ch] == 0)
|
||||
continue;
|
||||
tmp = ELEM (ctype_b, names_b[ch]);
|
||||
for (cls1 = 0; cls1 < NCLASS; ++cls1)
|
||||
if ((tmp & (1 << cls1)) != 0)
|
||||
for (cls2 = 0; cls2 < NCLASS; ++cls2)
|
||||
if (cls2 != cls1 && valid_table[cls1].allow[cls2] != '-')
|
||||
{
|
||||
eq = (tmp & (1 << cls2)) != 0;
|
||||
switch (valid_table[cls1].allow[cls2])
|
||||
{
|
||||
case 'M':
|
||||
if (!eq)
|
||||
error (0, 0, gettext ("character '\\%o' in class `%s' "
|
||||
"must be in class `%s'"), ch,
|
||||
valid_table[cls1].name, valid_table[cls2].name);
|
||||
break;
|
||||
case 'X':
|
||||
if (eq)
|
||||
error (0, 0, gettext ("character '\\%o' inc class `%s' "
|
||||
"must not be in class `%s'"), ch,
|
||||
valid_table[cls1].name, valid_table[cls2].name);
|
||||
break;
|
||||
case 'D':
|
||||
ELEM (ctype_b, names_b[ch]) |= 1 << cls2;
|
||||
break;
|
||||
default:
|
||||
error (5, 0, gettext ("internal error in %s, line %u"),
|
||||
__FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ... and now test <SP> as a special case. */
|
||||
if (find_entry (&charmap_data.table, "SP", 2, (void **) &space_char) == 0)
|
||||
error (0, 0, gettext ("character <SP> not defined in character map"));
|
||||
else if ((tmp = BITPOS (TOK_SPACE),
|
||||
(ELEM (ctype_b, space_char) & BIT (TOK_SPACE)) == 0)
|
||||
|| (tmp = BITPOS (TOK_BLANK),
|
||||
(ELEM (ctype_b, space_char) & BIT (TOK_BLANK)) == 0))
|
||||
error (0, 0, gettext ("<SP> character not in class `%s'"),
|
||||
valid_table[tmp].name);
|
||||
else if ((tmp = BITPOS (TOK_PUNCT),
|
||||
(ELEM (ctype_b, space_char) & BIT (TOK_PUNCT)) != 0)
|
||||
|| (tmp = BITPOS (TOK_GRAPH),
|
||||
(ELEM (ctype_b, space_char) & BIT (TOK_GRAPH)) != 0))
|
||||
error (0, 0, gettext ("<SP> character must not be in class `%s'"),
|
||||
valid_table[tmp].name);
|
||||
else
|
||||
ELEM (ctype_b, space_char) |= BIT (TOK_PRINT);
|
||||
}
|
||||
|
||||
|
||||
/* These macros can change little to big endian and vice versa. */
|
||||
#define SWAP16(v) \
|
||||
((u16) (((((unsigned short) (v)) & 0x00ff) << 8) \
|
||||
| ((((unsigned short) (v)) & 0xff00) >> 8)))
|
||||
#define SWAP32(v) \
|
||||
((u32) (((((u32) (v)) & 0x000000ff) << 24) \
|
||||
| ((((u32) (v)) & 0x0000ff00) << 8) \
|
||||
| ((((u32) (v)) & 0x00ff0000) >> 8) \
|
||||
| ((((u32) (v)) & 0xff000000) >> 24)))
|
||||
|
||||
|
||||
int
|
||||
ctype_output (void)
|
||||
{
|
||||
char *path, *t;
|
||||
int ch;
|
||||
/* File descriptor for output file. */
|
||||
int fd;
|
||||
/* Magic number. */
|
||||
i32 magic = LIMAGIC (LC_CTYPE);
|
||||
/* Number of table. */
|
||||
int tables = 6;
|
||||
/* Number ints in leading information table. */
|
||||
#if 0
|
||||
i32 n = 2 + 2 * tables;
|
||||
#else
|
||||
i32 n = 5;
|
||||
#endif
|
||||
/* Values describing the character set. */
|
||||
char mb_cur_min = (char) charmap_data.mb_cur_min;
|
||||
char mb_cur_max = (char) charmap_data.mb_cur_max;
|
||||
/* Optimal size of hashing table. */
|
||||
i32 hash_size = charmap_data.hash_size;
|
||||
i32 hash_layers = charmap_data.hash_layers;
|
||||
/* Number of elements in the tables. */
|
||||
int size = hash_size * charmap_data.hash_layers;
|
||||
/* Positions of the tables. */
|
||||
i32 pos[14] =
|
||||
{
|
||||
/* No, no. We don't play towers of Hanoi. This is a more or less
|
||||
readable table of the offsets of the different strings in the
|
||||
produced file. It is seperated in three columns which represent
|
||||
the number of values with 1, 2, and 4 bytes. */
|
||||
|
||||
#if 0
|
||||
4 * (2 + n),
|
||||
1 + 4 * (2 + n),
|
||||
2 + 4 * (2 + n),
|
||||
2 + 4 * (3 + n),
|
||||
2 + 4 * (4 + n),
|
||||
2 + 2 * (128 + size) + 4 * (4 + n),
|
||||
2 + 2 * (128 + size) + 4 * ((4 + n) + (size + 128)),
|
||||
2 + 2 * (128 + size) + 4 * ((4 + n) + 2 * (size + 128)),
|
||||
2 + 2 * (128 + size) + 4 * ((4 + n) + 2 * (size + 128) + 1 * size),
|
||||
2 + 2 * (128 + size) + 4 * ((5 + n) + 2 * (size + 128) + 1 * size),
|
||||
2 + 2 * (128 + size) + 4 * ((6 + n) + 2 * (size + 128) + 1 * size),
|
||||
2 + 2 * (2 * (128 + size)) + 4 * ((6 + n) + 2 * (size + 128) + 1 * size),
|
||||
2 + 2 * (2 * (128 + size)) + 4 * ((6 + n) + 3 * (size + 128) + 1 * size),
|
||||
2 + 2 * (2 * (128 + size)) + 4 * ((6 + n) + 4 * (size + 128) + 1 * size),
|
||||
#else
|
||||
4 * (2 + n),
|
||||
2 * (128 + size) + 4 * (2 + n),
|
||||
2 * (128 + size) + 4 * ((2 + n) + (size + 128)),
|
||||
2 * (128 + size) + 4 * ((2 + n) + 2 * (size + 128)),
|
||||
2 * (128 + size) + 4 * ((2 + n) + 3 * (size + 128)),
|
||||
#endif
|
||||
};
|
||||
/* Parameter to writev. */
|
||||
struct iovec iov[11] =
|
||||
{
|
||||
{ &magic, sizeof (i32) },
|
||||
{ &n, sizeof (i32) },
|
||||
#if 0
|
||||
{ pos, sizeof (pos) },
|
||||
{ &mb_cur_min, 1 },
|
||||
{ &mb_cur_max, 1 },
|
||||
{ &hash_size, sizeof (i32) },
|
||||
{ &hash_layers, sizeof (i32) },
|
||||
#else
|
||||
{ pos, 5 * 4 },
|
||||
#endif
|
||||
{ ctype_b - 128, (size + 128) * sizeof (u16) },
|
||||
{ toupper_b - 128, (size + 128) * sizeof (i32) },
|
||||
{ tolower_b - 128, (size + 128) * sizeof (i32) },
|
||||
{ names_b, size * sizeof (i32) }
|
||||
};
|
||||
int result = 0;
|
||||
|
||||
/* Now we can bring the representations into the right form. */
|
||||
for (ch = -128; ch < -1; ++ch)
|
||||
{
|
||||
ctype_b[ch] = ctype_b[256 + ch];
|
||||
toupper_b[ch] = toupper_b[256 + ch];
|
||||
tolower_b[ch] = tolower_b[256 + ch];
|
||||
}
|
||||
/* Set value for EOF. */
|
||||
ctype_b[-1] = 0;
|
||||
toupper_b[-1] = -1;
|
||||
tolower_b[-1] = -1;
|
||||
|
||||
for (ch = -128; ch < size; ++ch)
|
||||
ctype_b[ch] = htons (ctype_b[ch]);
|
||||
|
||||
/* Construct the output filename from the argument given to
|
||||
localedef on the command line. */
|
||||
path = (char *) alloca (strlen (output_path) +
|
||||
strlen (category[LC_CTYPE].name) + 1);
|
||||
t = stpcpy (path, output_path);
|
||||
strcpy (t, category[LC_CTYPE].name);
|
||||
|
||||
fd = creat (path, 0666);
|
||||
if (fd == -1)
|
||||
{
|
||||
error (0, 0, gettext ("cannot open output file `%s': %m"), path);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx;
|
||||
|
||||
#if 0
|
||||
if (writev (fd, iov, 10) == -1)
|
||||
#else
|
||||
if (writev (fd, iov, 6) == -1)
|
||||
#endif
|
||||
{
|
||||
error (0, 0, gettext ("cannot write output file `%s': %m"), path);
|
||||
result = 1;
|
||||
goto close_and_return;
|
||||
}
|
||||
|
||||
/* Now we have to write the three tables with different endianess. */
|
||||
hash_size = SWAP32 (hash_size);
|
||||
for (idx = -128; idx < size; ++idx)
|
||||
{
|
||||
ctype_b[idx] = SWAP16 (ctype_b[idx]);
|
||||
toupper_b[idx] = SWAP32 (toupper_b[idx]);
|
||||
tolower_b[idx] = SWAP32 (tolower_b[idx]);
|
||||
if (idx >= 0)
|
||||
names_b[idx] = SWAP32 (names_b[idx]);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (writev (fd, iov + 5, 6) == -1)
|
||||
#else
|
||||
if (writev (fd, iov + 3, 2) == -1)
|
||||
#endif
|
||||
{
|
||||
error (0, 0, gettext ("cannot write output file `%s': %m"), path);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
close_and_return:
|
||||
close (fd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* If necessary allocate the memory for the arrays according to the
|
||||
current character map. */
|
||||
static void
|
||||
allocate_arrays (void)
|
||||
{
|
||||
/* Init ctype data structures. */
|
||||
if (ctype_b == NULL)
|
||||
/* All data structures are not initialized yet. */
|
||||
{
|
||||
/* You wonder about this amount of memory? This is only because
|
||||
some users do not manage to address the array with unsigned
|
||||
values or data types with range >= 256. '\200' would result
|
||||
in the array index -128. To help these poor people we
|
||||
duplicate the entries for 128 upto 255 below the entry for \0. */
|
||||
int ch, h, n;
|
||||
char *ptr;
|
||||
int size = charmap_data.hash_size * charmap_data.hash_layers;
|
||||
|
||||
ctype_b = (u16 *) xcalloc (size - (-128), sizeof (u16));
|
||||
ctype_b += 128;
|
||||
|
||||
|
||||
names_b = (i32 *) xcalloc (size, sizeof (i32));
|
||||
|
||||
toupper_b = (i32 *) xcalloc ((size - (-128)), sizeof (i32));
|
||||
toupper_b += 128;
|
||||
|
||||
tolower_b = (i32 *) xcalloc ((size - (-128)), sizeof (i32));
|
||||
tolower_b += 128;
|
||||
|
||||
ptr = NULL;
|
||||
/* Mark the place of the NUL character as occupied. */
|
||||
names_b[0] = 1;
|
||||
|
||||
while (iterate_table (&charmap_data.table, (void **) &ptr,
|
||||
(void **) &ch))
|
||||
{
|
||||
/* We already handled the NUL character. */
|
||||
if (ch == 0)
|
||||
continue;
|
||||
|
||||
h = ch % charmap_data.hash_size;
|
||||
n = 0;
|
||||
while (names_b[h + n * charmap_data.hash_size] != 0)
|
||||
++n;
|
||||
|
||||
names_b[h + n * charmap_data.hash_size] = ch;
|
||||
toupper_b[h + n * charmap_data.hash_size] = ch;
|
||||
tolower_b[h + n * charmap_data.hash_size] = ch;
|
||||
}
|
||||
/* Correct the value for NUL character. */
|
||||
names_b[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_class_defaults (void)
|
||||
{
|
||||
/* These function defines the default values for the classes and conversions
|
||||
according to POSIX.2 2.5.2.1.
|
||||
It may seem that the order of these if-blocks is arbitrary but it is NOT.
|
||||
Don't move them unless you know what you do! */
|
||||
|
||||
void set_default (int bit, int from, int to)
|
||||
{
|
||||
char tmp[4];
|
||||
int ch;
|
||||
/* Define string. */
|
||||
strcpy (tmp, "<?>");
|
||||
|
||||
for (ch = from; ch <= to; ++ch)
|
||||
{
|
||||
int code;
|
||||
tmp[1] = ch;
|
||||
|
||||
code = find_char (tmp + 1, 1);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed "
|
||||
"as default value"), tmp);
|
||||
ELEM (ctype_b, code) |= bit;
|
||||
}
|
||||
}
|
||||
|
||||
/* If necessary allocate arrays. */
|
||||
allocate_arrays ();
|
||||
|
||||
/* Set default values if keyword was not present. */
|
||||
if ((class_done & BIT (TOK_UPPER)) == 0)
|
||||
/* "If this keyword [lower] is not specified, the lowercase letters
|
||||
`A' through `Z', ..., shall automatically belong to this class,
|
||||
with implementation defined character values." */
|
||||
set_default (BIT (TOK_UPPER), 'A', 'Z');
|
||||
|
||||
if ((class_done & BIT (TOK_LOWER)) == 0)
|
||||
/* "If this keyword [lower] is not specified, the lowercase letters
|
||||
`a' through `z', ..., shall automatically belong to this class,
|
||||
with implementation defined character values." */
|
||||
set_default (BIT (TOK_LOWER), 'a', 'z');
|
||||
|
||||
if ((class_done & BIT (TOK_DIGIT)) == 0)
|
||||
/* "If this keyword [digit] is not specified, the digits `0' through
|
||||
`9', ..., shall automatically belong to this class, with
|
||||
implementation-defined character values." */
|
||||
set_default (BIT (TOK_DIGIT), '0', '9');
|
||||
|
||||
if ((class_done & BIT (TOK_SPACE)) == 0)
|
||||
/* "If this keyword [space] is not specified, the characters <space>,
|
||||
<form-feed>, <newline>, <carriage-return>, <tab>, and
|
||||
<vertical-tab>, ..., shall automatically belong to this class,
|
||||
with implementtation-defined character values." */
|
||||
{
|
||||
int code;
|
||||
|
||||
code = find_char ("space", 5);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<space>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_SPACE);
|
||||
|
||||
code = find_char ("form-feed", 9);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<form-feed>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_SPACE);
|
||||
|
||||
code = find_char ("newline", 7);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<newline>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_SPACE);
|
||||
|
||||
code = find_char ("carriage-return", 15);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<carriage-return>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_SPACE);
|
||||
|
||||
code = find_char ("tab", 3);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<tab>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_SPACE);
|
||||
|
||||
code = find_char ("vertical-tab", 11);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<vertical-tab>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_SPACE);
|
||||
}
|
||||
|
||||
if ((class_done & BIT (TOK_XDIGIT)) == 0)
|
||||
/* "If this keyword is not specified, the digits `0' to `9', the
|
||||
uppercase letters `A' through `F', and the lowercase letters `a'
|
||||
through `f', ..., shell automatically belong to this class, with
|
||||
implementation defined character values." */
|
||||
{
|
||||
if ((class_done & BIT (TOK_XDIGIT)) == 0)
|
||||
set_default (BIT (TOK_XDIGIT), '0', '9');
|
||||
|
||||
if ((class_done & BIT (TOK_XDIGIT)) == 0)
|
||||
set_default (BIT (TOK_XDIGIT), 'A', 'F');
|
||||
|
||||
if ((class_done & BIT (TOK_XDIGIT)) == 0)
|
||||
set_default (BIT (TOK_XDIGIT), 'a', 'f');
|
||||
}
|
||||
|
||||
if ((class_done & BIT (TOK_BLANK)) == 0)
|
||||
/* "If this keyword [blank] is unspecified, the characters <space> and
|
||||
<tab> shall belong to this character class." */
|
||||
{
|
||||
int code;
|
||||
|
||||
code = find_char ("space", 5);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<space>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_BLANK);
|
||||
|
||||
code = find_char ("tab", 3);
|
||||
if (code == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<tab>");
|
||||
ELEM (ctype_b, code) |= BIT (TOK_BLANK);
|
||||
}
|
||||
|
||||
if ((class_done & BIT (TOK_GRAPH)) == 0)
|
||||
/* "If this keyword [graph] is not specified, characters specified for
|
||||
the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
|
||||
shall belong to this character class." */
|
||||
{
|
||||
int ch;
|
||||
unsigned short int mask = BIT (TOK_UPPER) | BIT (TOK_LOWER) |
|
||||
BIT (TOK_ALPHA) | BIT (TOK_DIGIT) | BIT (TOK_XDIGIT) | BIT (TOK_PUNCT);
|
||||
|
||||
for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
|
||||
++ch)
|
||||
{
|
||||
if (ch != 0 && names_b[ch] == 0)
|
||||
continue;
|
||||
if ((ELEM (ctype_b, names_b[ch]) & mask) != 0)
|
||||
ELEM (ctype_b, names_b[ch]) |= BIT (TOK_GRAPH);
|
||||
}
|
||||
}
|
||||
|
||||
if ((class_done & BIT (TOK_PRINT)) == 0)
|
||||
/* "If this keyword [print] is not provided, characters specified for
|
||||
the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
|
||||
and the <space> character shall belong to this character class." */
|
||||
{
|
||||
int ch;
|
||||
int space = find_char ("space", 5);
|
||||
unsigned short int mask = BIT (TOK_UPPER) | BIT (TOK_LOWER) |
|
||||
BIT (TOK_ALPHA) | BIT (TOK_DIGIT) | BIT (TOK_XDIGIT) | BIT (TOK_PUNCT);
|
||||
|
||||
if (space == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed as "
|
||||
"default value"), "<space>");
|
||||
|
||||
for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
|
||||
++ch)
|
||||
{
|
||||
if (ch != 0 && names_b[ch] == 0)
|
||||
continue;
|
||||
if ((ELEM (ctype_b, names_b[ch]) & mask) != 0)
|
||||
ELEM (ctype_b, names_b[ch]) |= BIT (TOK_PRINT);
|
||||
}
|
||||
ELEM (ctype_b, space) |= BIT (TOK_PRINT);
|
||||
}
|
||||
|
||||
if (toupper_done == 0)
|
||||
/* "If this keyword [toupper] is not spcified, the lowercase letters
|
||||
`a' through `z', and their corresponding uppercase letters `A' to
|
||||
`Z', ..., shall automatically be included, with implementation-
|
||||
defined character values." */
|
||||
{
|
||||
char tmp[4];
|
||||
int ch;
|
||||
|
||||
strcpy (tmp, "<?>");
|
||||
|
||||
for (ch = 'a'; ch <= 'z'; ++ch)
|
||||
{
|
||||
int code_to, code_from;
|
||||
|
||||
tmp[1] = ch;
|
||||
code_from = find_char (tmp + 1, 1);
|
||||
if (code_from == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed "
|
||||
"as default value"), tmp);
|
||||
|
||||
/* This conversion is implementation defined. */
|
||||
tmp[1] = ch + ('A' - 'a');
|
||||
code_to = find_char (tmp + 1, 1);
|
||||
if (code_to == -1)
|
||||
error (5, 0, gettext ("character `%s' not defined while needed "
|
||||
"as default value"), tmp);
|
||||
|
||||
ELEM (toupper_b, code_from) = code_to;
|
||||
}
|
||||
}
|
||||
|
||||
if (tolower_done == 0)
|
||||
/* "If this keyword [tolower] is not specified, the mapping shall be
|
||||
the reverse mapping of the one specified to `toupper'." */
|
||||
{
|
||||
int ch;
|
||||
|
||||
for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
|
||||
++ch)
|
||||
{
|
||||
if (ch != 0 && names_b[ch] == 0)
|
||||
continue;
|
||||
|
||||
if (toupper_b[ch] != names_b[ch])
|
||||
ELEM (tolower_b, toupper_b[ch]) = names_b[ch];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Test whether the given character is valid for the current charmap. */
|
||||
static int
|
||||
valid_char (int ch)
|
||||
{
|
||||
/* FIXME: this assumes 32-bit integers. */
|
||||
int ok = ch >= 0
|
||||
&& (charmap_data.mb_cur_max < 4
|
||||
? ch < 1 << (8 * charmap_data.mb_cur_max) : 1);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
163
locale/ctypedump.c
Normal file
163
locale/ctypedump.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <endian.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <netinet/in.h> /* Just for htons() */
|
||||
|
||||
#include "localedef.h"
|
||||
#include "localeinfo.h"
|
||||
|
||||
|
||||
/* FIXME: these values should be part of the LC_CTYPE information. */
|
||||
#define mb_cur_max 1
|
||||
#define mb_cur_min 1
|
||||
|
||||
|
||||
#define SWAP32(v) \
|
||||
((u32) (((((u32) (v)) & 0x000000ff) << 24) \
|
||||
| ((((u32) (v)) & 0x0000ff00) << 8) \
|
||||
| ((((u32) (v)) & 0x00ff0000) >> 8) \
|
||||
| ((((u32) (v)) & 0xff000000) >> 24)))
|
||||
|
||||
|
||||
|
||||
static inline void
|
||||
print_short_in_char (unsigned short val)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) &val;
|
||||
printf ("\"\\%03o\\%03o\"", p[0], p[1]);
|
||||
}
|
||||
|
||||
|
||||
static inline void
|
||||
print_int_in_char (unsigned int val)
|
||||
{
|
||||
const unsigned char *p = (const unsigned char *) &val;
|
||||
printf ("\"\\%03o\\%03o\\%03o\\%03o\"", p[0], p[1], p[2], p[3]);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ctype_output (void)
|
||||
{
|
||||
int ch;
|
||||
int result = 0;
|
||||
const char *locname = (getenv ("LC_ALL") ?: getenv ("LC_CTYPE") ?:
|
||||
getenv ("LANG") ?: "POSIX");
|
||||
|
||||
puts ("#include <endian.h>\n");
|
||||
|
||||
if (mb_cur_max == 1)
|
||||
{
|
||||
printf ("const char _nl_%s_LC_CTYPE_class[] = \n", locname);
|
||||
for (ch = -128; ch < (1 << (8 * MB_CUR_MAX)); ++ch)
|
||||
{
|
||||
if (((ch + 128) % 6) == 0)
|
||||
printf (" /* 0x%02x */ ", ch < 0 ? 256 + ch : ch);
|
||||
print_short_in_char (htons (__ctype_b [ch < 0 ? 256 + ch : ch]));
|
||||
fputc (((ch + 128) % 6) == 5 ? '\n' : ' ', stdout);
|
||||
}
|
||||
puts (";");
|
||||
}
|
||||
|
||||
printf ("#if BYTE_ORDER == %s\n",
|
||||
BYTE_ORDER == LITTLE_ENDIAN ? "LITTLE_ENDIAN" : "BIG_ENDIAN");
|
||||
|
||||
if (mb_cur_max == 1)
|
||||
{
|
||||
printf ("const char _nl_%s_LC_CTYPE_toupper[] = \n", locname);
|
||||
for (ch = -128; ch < (1 << (8 * MB_CUR_MAX)); ++ch)
|
||||
{
|
||||
if (((ch + 128) % 3) == 0)
|
||||
printf (" /* 0x%02x */ ", ch < 0 ? 256 + ch : ch);
|
||||
print_int_in_char (__ctype_toupper[ch < 0 ? 256 + ch : ch]);
|
||||
fputc (((ch + 128) % 3) == 2 ? '\n' : ' ', stdout);
|
||||
}
|
||||
puts (";");
|
||||
|
||||
printf ("const char _nl_%s_LC_CTYPE_tolower[] = \n", locname);
|
||||
for (ch = -128; ch < (1 << (8 * MB_CUR_MAX)); ++ch)
|
||||
{
|
||||
if (((ch + 128) % 3) == 0)
|
||||
printf (" /* 0x%02x */ ", ch < 0 ? 256 + ch : ch);
|
||||
print_int_in_char (__ctype_tolower[ch < 0 ? 256 + ch : ch]);
|
||||
fputc (((ch + 128) % 3) == 2 ? '\n' : ' ', stdout);
|
||||
}
|
||||
puts (";");
|
||||
}
|
||||
else
|
||||
/* not implemented */;
|
||||
|
||||
printf ("#elif BYTE_ORDER == %s\n",
|
||||
BYTE_ORDER == LITTLE_ENDIAN ? "BIG_ENDIAN" : "LITTLE_ENDIAN");
|
||||
|
||||
if (mb_cur_max == 1)
|
||||
{
|
||||
printf ("const char _nl_%s_LC_CTYPE_toupper[] = \n", locname);
|
||||
for (ch = -128; ch < (1 << (8 * MB_CUR_MAX)); ++ch)
|
||||
{
|
||||
if (((ch + 128) % 3) == 0)
|
||||
printf (" /* 0x%02x */ ", ch < 0 ? 256 + ch : ch);
|
||||
print_int_in_char (SWAP32 (__ctype_toupper[ch < 0 ? 256 + ch : ch]));
|
||||
fputc (((ch + 128) % 3) == 2 ? '\n' : ' ', stdout);
|
||||
}
|
||||
puts (";");
|
||||
|
||||
printf ("const char _nl_%s_LC_CTYPE_tolower[] = \n", locname);
|
||||
for (ch = -128; ch < (1 << (8 * MB_CUR_MAX)); ++ch)
|
||||
{
|
||||
if (((ch + 128) % 3) == 0)
|
||||
printf (" /* 0x%02x */ ", ch < 0 ? 256 + ch : ch);
|
||||
print_int_in_char (SWAP32 (__ctype_tolower[ch < 0 ? 256 + ch : ch]));
|
||||
fputc (((ch + 128) % 3) == 2 ? '\n' : ' ', stdout);
|
||||
}
|
||||
puts (";");
|
||||
}
|
||||
else
|
||||
/* not implemented */;
|
||||
|
||||
puts ("#else\n#error \"BYTE_ORDER\" BYTE_ORDER \" not handled.\"\n#endif\n");
|
||||
|
||||
printf("const struct locale_data _nl_%s_LC_CTYPE = \n\
|
||||
{\n\
|
||||
NULL, 0, /* no file mapped */\n\
|
||||
5,\n\
|
||||
{\n\
|
||||
_nl_C_LC_CTYPE_class,\n\
|
||||
#ifdef BYTE_ORDER == LITTLE_ENDIAN\n\
|
||||
NULL, NULL,\n\
|
||||
#endif\n\
|
||||
_nl_C_LC_CTYPE_toupper,\n\
|
||||
_nl_C_LC_CTYPE_tolower,\n\
|
||||
#ifdef BYTE_ORDER == BIG_ENDIAN\n\
|
||||
NULL, NULL,\n\
|
||||
#endif\n\
|
||||
}\n\
|
||||
};\n", locname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
254
locale/hash.c
Normal file
254
locale/hash.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <obstack.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <values.h>
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free free
|
||||
|
||||
void *xmalloc (size_t n);
|
||||
|
||||
typedef struct hash_entry
|
||||
{
|
||||
int used;
|
||||
char *key;
|
||||
void *data;
|
||||
struct hash_entry *next;
|
||||
}
|
||||
hash_entry;
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static size_t lookup (hash_table *htab, const char *key, size_t keylen,
|
||||
unsigned long hval);
|
||||
static unsigned long compute_hashval(const char *key, size_t keylen);
|
||||
static unsigned long next_prime(unsigned long seed);
|
||||
static int is_prime(unsigned long candidate);
|
||||
|
||||
|
||||
int
|
||||
init_hash(hash_table *htab, unsigned long init_size)
|
||||
{
|
||||
/* We need the size to be a prime. */
|
||||
init_size = next_prime (init_size);
|
||||
|
||||
/* Initialize the data structure. */
|
||||
htab->size = init_size;
|
||||
htab->filled = 0;
|
||||
htab->first = NULL;
|
||||
htab->table = calloc (init_size + 1, sizeof (hash_entry));
|
||||
obstack_init (&htab->mem_pool);
|
||||
|
||||
return htab->table == NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
delete_hash(hash_table *htab)
|
||||
{
|
||||
free (htab->table);
|
||||
obstack_free (&htab->mem_pool, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
insert_entry (hash_table *htab, const char *key, size_t keylen, void *data)
|
||||
{
|
||||
unsigned long hval = compute_hashval (key, keylen);
|
||||
hash_entry *table = (hash_entry *) htab->table;
|
||||
size_t idx = lookup (htab, key, keylen, hval);
|
||||
|
||||
if (table[idx].used)
|
||||
/* We don't want to overwrite the old value. */
|
||||
return 1;
|
||||
else
|
||||
{
|
||||
hash_entry **p;
|
||||
|
||||
/* An empty bucket has been found. */
|
||||
table[idx].used = hval;
|
||||
table[idx].key = obstack_copy0 (&htab->mem_pool, key, keylen);
|
||||
table[idx].data = data;
|
||||
|
||||
/* List the new value in the ordered list. */
|
||||
for (p = (hash_entry **) &htab->first; *p != NULL && (*p)->data < data;
|
||||
p = &(*p)->next);
|
||||
if (*p == NULL || (*p)->data > data)
|
||||
/* Insert new value in the list. */
|
||||
{
|
||||
table[idx].next = *p;
|
||||
*p = &table[idx];
|
||||
}
|
||||
|
||||
++htab->filled;
|
||||
if (100 * htab->filled > 90 * htab->size)
|
||||
{
|
||||
/* Resize the table. */
|
||||
unsigned long old_size = htab->size;
|
||||
|
||||
htab->size = next_prime (htab->size * 2);
|
||||
htab->filled = 0;
|
||||
htab->first = NULL;
|
||||
htab->table = calloc (htab->size, sizeof (hash_entry));
|
||||
|
||||
for (idx = 1; idx <= old_size; ++idx)
|
||||
if (table[idx].used)
|
||||
insert_entry (htab, table[idx].key, strlen(table[idx].key),
|
||||
table[idx].data);
|
||||
|
||||
free (table);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
find_entry (hash_table *htab, const char *key, size_t keylen, void **result)
|
||||
{
|
||||
hash_entry *table = (hash_entry *) htab->table;
|
||||
size_t idx = lookup (htab, key, keylen, compute_hashval (key, keylen));
|
||||
int retval;
|
||||
|
||||
retval = table[idx].used;
|
||||
*result = retval ? table[idx].data : NULL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
iterate_table (hash_table *htab, void **ptr, void **result)
|
||||
{
|
||||
if (*ptr == NULL)
|
||||
*ptr = (void *) htab->first;
|
||||
else
|
||||
{
|
||||
*ptr = (void *) (((hash_entry *) *ptr)->next);
|
||||
if (*ptr == NULL)
|
||||
return 0;
|
||||
}
|
||||
|
||||
*result = ((hash_entry *) *ptr)->data;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
lookup (hash_table *htab, const char *key, size_t keylen, unsigned long hval)
|
||||
{
|
||||
unsigned long hash;
|
||||
size_t idx;
|
||||
hash_entry *table = (hash_entry *) htab->table;
|
||||
|
||||
/* First hash function: simply take the modul but prevent zero. */
|
||||
hash = 1 + hval % htab->size;
|
||||
|
||||
idx = hash;
|
||||
|
||||
if (table[idx].used)
|
||||
{
|
||||
if (table[idx].used == hval && table[idx].key[keylen] == '\0'
|
||||
&& strncmp (key, table[idx].key, keylen) == 0)
|
||||
return idx;
|
||||
|
||||
/* Second hash function as suggested in [Knuth]. */
|
||||
hash = 1 + hash % (htab->size - 2);
|
||||
|
||||
do
|
||||
{
|
||||
if (idx <= hash)
|
||||
idx = htab->size + idx - hash;
|
||||
else
|
||||
idx -= hash;
|
||||
|
||||
/* If entry is found use it. */
|
||||
if (table[idx].used == hval && table[idx].key[keylen] == '\0'
|
||||
&& strncmp (key, table[idx].key, keylen) == 0)
|
||||
return idx;
|
||||
}
|
||||
while (table[idx].used);
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long
|
||||
compute_hashval(const char *key, size_t keylen)
|
||||
{
|
||||
size_t cnt;
|
||||
unsigned long hval, g;
|
||||
/* Compute the hash value for the given string. */
|
||||
cnt = 0;
|
||||
hval = keylen;
|
||||
while (cnt < keylen)
|
||||
{
|
||||
hval <<= 4;
|
||||
hval += key[cnt++];
|
||||
g = hval & (0xf << (LONGBITS - 4));
|
||||
if (g != 0)
|
||||
{
|
||||
hval ^= g >> (LONGBITS - 8);
|
||||
hval ^= g;
|
||||
}
|
||||
}
|
||||
return hval;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long
|
||||
next_prime(unsigned long seed)
|
||||
{
|
||||
/* Make it definitely odd. */
|
||||
seed |= 1;
|
||||
|
||||
while (!is_prime (seed))
|
||||
seed += 2;
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
is_prime(unsigned long candidate)
|
||||
{
|
||||
/* No even number and none less than 10 will be passwd here. */
|
||||
unsigned long div = 3;
|
||||
unsigned long sq = div * div;
|
||||
|
||||
while (sq < candidate && candidate % div != 0)
|
||||
{
|
||||
++div;
|
||||
sq += 4 * div;
|
||||
++div;
|
||||
}
|
||||
|
||||
return candidate % div != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
50
locale/hash.h
Normal file
50
locale/hash.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _HASH_H
|
||||
#define _HASH_H
|
||||
|
||||
#include <obstack.h>
|
||||
|
||||
typedef struct hash_table
|
||||
{
|
||||
unsigned long size;
|
||||
unsigned long filled;
|
||||
void *first;
|
||||
void *table;
|
||||
struct obstack mem_pool;
|
||||
}
|
||||
hash_table;
|
||||
|
||||
|
||||
int init_hash (hash_table *htab, unsigned long init_size);
|
||||
int delete_hash(hash_table *htab);
|
||||
int insert_entry (hash_table *htab, const char *key, size_t keylen,
|
||||
void *data);
|
||||
int find_entry (hash_table *htab, const char *key, size_t keylen,
|
||||
void **result);
|
||||
|
||||
int iterate_table (hash_table *htab, void **ptr, void **result);
|
||||
|
||||
#endif /* hash.h */
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
||||
|
36
locale/iso-4217.def
Normal file
36
locale/iso-4217.def
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Defines the valid international currency symbols according to ISO-4217.
|
||||
* This is used in monetary.c(monetary_check).
|
||||
*
|
||||
* !!! The list has to be sorted !!!
|
||||
*/
|
||||
DEFINE_INT_CURR("ATS ") /* Austria */
|
||||
DEFINE_INT_CURR("BEF ") /* Belgium */
|
||||
DEFINE_INT_CURR("CAD ") /* Canada */
|
||||
DEFINE_INT_CURR("CHF ") /* Switzerland */
|
||||
DEFINE_INT_CURR("DEM ") /* Germany */
|
||||
DEFINE_INT_CURR("DKK ") /* Denmark */
|
||||
DEFINE_INT_CURR("EEK ") /* Estonia */
|
||||
DEFINE_INT_CURR("ESP ") /* Spain */
|
||||
DEFINE_INT_CURR("FIM ") /* Finland */
|
||||
DEFINE_INT_CURR("FRF ") /* France */
|
||||
DEFINE_INT_CURR("GBP ") /* Great Britain */
|
||||
DEFINE_INT_CURR("GRD ") /* Greece */
|
||||
DEFINE_INT_CURR("HRD ") /* Croatia */
|
||||
DEFINE_INT_CURR("HUF ") /* Hungary */
|
||||
DEFINE_INT_CURR("IEP ") /* Ireland */
|
||||
DEFINE_INT_CURR("ILS ") /* Israel */
|
||||
DEFINE_INT_CURR("ISK ") /* Iceland */
|
||||
DEFINE_INT_CURR("ITL ") /* Italy */
|
||||
DEFINE_INT_CURR("LTL ") /* Lithuania */
|
||||
DEFINE_INT_CURR("LUF ") /* Luxemburg */
|
||||
DEFINE_INT_CURR("LVL ") /* Latvia */
|
||||
DEFINE_INT_CURR("NLG ") /* Netherlands */
|
||||
DEFINE_INT_CURR("NOK ") /* Norway */
|
||||
DEFINE_INT_CURR("PLZ ") /* Poland */
|
||||
DEFINE_INT_CURR("PTE ") /* Portugal */
|
||||
DEFINE_INT_CURR("ROL ") /* Romania */
|
||||
DEFINE_INT_CURR("RUR ") /* Russia */
|
||||
DEFINE_INT_CURR("SEK ") /* Sweden */
|
||||
DEFINE_INT_CURR("SIT ") /* Slovenia */
|
||||
DEFINE_INT_CURR("USD ") /* United States */
|
77
locale/keyword.gperf
Normal file
77
locale/keyword.gperf
Normal file
|
@ -0,0 +1,77 @@
|
|||
%{
|
||||
/* `strncmp' is used for comparison. */
|
||||
#include <string.h>
|
||||
|
||||
/* This file defines `enum token'. */
|
||||
#include "token.h"
|
||||
%}
|
||||
struct locale_keyword { char *name; enum token token_id; };
|
||||
%%
|
||||
END, TOK_END
|
||||
IGNORE, TOK_IGNORE
|
||||
LC_COLLATE, _NL_NUM_LC_COLLATE
|
||||
LC_CTYPE, _NL_NUM_LC_CTYPE
|
||||
LC_MESSAGES, _NL_NUM_LC_MESSAGES
|
||||
LC_MONETARY, _NL_NUM_LC_MONETARY
|
||||
LC_NUMERIC, _NL_NUM_LC_NUMERIC
|
||||
LC_TIME, _NL_NUM_LC_TIME
|
||||
UNDEFINED, TOK_UNDEFINED
|
||||
abday, ABDAY_1
|
||||
abmon, ABMON_1
|
||||
alpha, TOK_ALPHA
|
||||
alt_digits, ALT_DIGITS
|
||||
am_pm, AM_STR
|
||||
backward, TOK_BACKWARD
|
||||
blank, TOK_BLANK
|
||||
cntrl, TOK_CNTRL
|
||||
collating_element, TOK_COLLATING_ELEMENT
|
||||
collating_symbol, TOK_COLLATING_SYMBOL
|
||||
comment_char, TOK_COMMENT_CHAR
|
||||
copy, TOK_COPY
|
||||
currency_symbol, CURRENCY_SYMBOL
|
||||
d_fmt, D_FMT
|
||||
d_t_fmt, D_T_FMT
|
||||
day, DAY_1
|
||||
decimal_point, DECIMAL_POINT
|
||||
digit, TOK_DIGIT
|
||||
era, ERA
|
||||
era_d_fmt, ERA_D_FMT
|
||||
era_year, ERA_YEAR
|
||||
escape_char, TOK_ESCAPE_CHAR
|
||||
forward, TOK_FORWARD
|
||||
frac_digits, FRAC_DIGITS
|
||||
from, TOK_FROM
|
||||
graph, TOK_GRAPH
|
||||
grouping, GROUPING
|
||||
int_curr_symbol, INT_CURR_SYMBOL
|
||||
int_frac_digits, INT_FRAC_DIGITS
|
||||
lower, TOK_LOWER
|
||||
mon, MON_1
|
||||
mon_decimal_point, MON_DECIMAL_POINT
|
||||
mon_grouping, MON_GROUPING
|
||||
mon_thousands_sep, MON_THOUSANDS_SEP
|
||||
n_cs_precedes, N_CS_PRECEDES
|
||||
n_sep_by_space, N_SEP_BY_SPACE
|
||||
n_sign_posn, N_SIGN_POSN
|
||||
negative_sign, NEGATIVE_SIGN
|
||||
noexpr, NOEXPR
|
||||
nostr, NOSTR
|
||||
order_end, TOK_ORDER_END
|
||||
order_start, TOK_ORDER_START
|
||||
p_cs_precedes, P_CS_PRECEDES
|
||||
p_sep_by_space, P_SEP_BY_SPACE
|
||||
p_sign_posn, P_SIGN_POSN
|
||||
position, TOK_POSITION
|
||||
positive_sign, POSITIVE_SIGN
|
||||
print, TOK_PRINT
|
||||
punct, TOK_PUNCT
|
||||
space, TOK_SPACE
|
||||
t_fmt, T_FMT
|
||||
t_fmt_ampm, T_FMT_AMPM
|
||||
thousands_sep, THOUSANDS_SEP
|
||||
tolower, TOK_TOLOWER
|
||||
toupper, TOK_TOUPPER
|
||||
upper, TOK_UPPER
|
||||
xdigit, TOK_XDIGIT
|
||||
yesexpr, YESEXPR
|
||||
yesstr, YESSTR
|
180
locale/keyword.h
Normal file
180
locale/keyword.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
/* C code produced by gperf version 2.5 (GNU C++ version) */
|
||||
/* Command-line: gperf -acCgopt -k1,2,5, keyword.gperf */
|
||||
/* `strncmp' is used for comparison. */
|
||||
#include <string.h>
|
||||
|
||||
/* This file defines `enum token'. */
|
||||
#include "token.h"
|
||||
struct locale_keyword { char *name; enum token token_id; };
|
||||
|
||||
#define TOTAL_KEYWORDS 68
|
||||
#define MIN_WORD_LENGTH 3
|
||||
#define MAX_WORD_LENGTH 17
|
||||
#define MIN_HASH_VALUE 4
|
||||
#define MAX_HASH_VALUE 140
|
||||
/* maximum key range = 137, duplicates = 0 */
|
||||
|
||||
#ifdef __GNUC__
|
||||
inline
|
||||
#endif
|
||||
static unsigned int
|
||||
hash (register const char *str, register int len)
|
||||
{
|
||||
static const unsigned char asso_values[] =
|
||||
{
|
||||
141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 141, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 141, 141, 0, 141, 65,
|
||||
5, 0, 141, 30, 141, 141, 0, 141, 0, 95,
|
||||
141, 141, 0, 141, 45, 10, 141, 141, 141, 141,
|
||||
141, 141, 141, 141, 141, 5, 141, 10, 85, 0,
|
||||
20, 0, 40, 35, 30, 10, 141, 0, 30, 15,
|
||||
15, 0, 0, 141, 55, 0, 0, 80, 141, 15,
|
||||
10, 0, 141, 141, 141, 141, 141, 141,
|
||||
};
|
||||
register int hval = len;
|
||||
|
||||
switch (hval)
|
||||
{
|
||||
default:
|
||||
case 5:
|
||||
hval += asso_values[str[4]];
|
||||
case 4:
|
||||
case 3:
|
||||
case 2:
|
||||
hval += asso_values[str[1]];
|
||||
case 1:
|
||||
hval += asso_values[str[0]];
|
||||
}
|
||||
return hval;
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
inline
|
||||
#endif
|
||||
const struct locale_keyword *
|
||||
in_word_set (register const char *str, register int len)
|
||||
{
|
||||
static const struct locale_keyword wordlist[] =
|
||||
{
|
||||
{"",}, {"",}, {"",}, {"",},
|
||||
{"copy", TOK_COPY},
|
||||
{"space", TOK_SPACE},
|
||||
{"yesstr", YESSTR},
|
||||
{"toupper", TOK_TOUPPER},
|
||||
{"position", TOK_POSITION},
|
||||
{"",},
|
||||
{"t_fmt", T_FMT},
|
||||
{"escape_char", TOK_ESCAPE_CHAR},
|
||||
{"comment_char", TOK_COMMENT_CHAR},
|
||||
{"positive_sign", POSITIVE_SIGN},
|
||||
{"",},
|
||||
{"t_fmt_ampm", T_FMT_AMPM},
|
||||
{"",},
|
||||
{"yesexpr", YESEXPR},
|
||||
{"mon", MON_1},
|
||||
{"p_sep_by_space", P_SEP_BY_SPACE},
|
||||
{"LC_NUMERIC", _NL_NUM_LC_NUMERIC},
|
||||
{"noexpr", NOEXPR},
|
||||
{"tolower", TOK_TOLOWER},
|
||||
{"p_cs_precedes", P_CS_PRECEDES},
|
||||
{"UNDEFINED", TOK_UNDEFINED},
|
||||
{"",},
|
||||
{"collating_symbol", TOK_COLLATING_SYMBOL},
|
||||
{"collating_element", TOK_COLLATING_ELEMENT},
|
||||
{"negative_sign", NEGATIVE_SIGN},
|
||||
{"",},
|
||||
{"d_fmt", D_FMT},
|
||||
{"",},
|
||||
{"mon_thousands_sep", MON_THOUSANDS_SEP},
|
||||
{"day", DAY_1},
|
||||
{"n_sep_by_space", N_SEP_BY_SPACE},
|
||||
{"digit", TOK_DIGIT},
|
||||
{"IGNORE", TOK_IGNORE},
|
||||
{"LC_TIME", _NL_NUM_LC_TIME},
|
||||
{"n_cs_precedes", N_CS_PRECEDES},
|
||||
{"",},
|
||||
{"int_curr_symbol", INT_CURR_SYMBOL},
|
||||
{"",}, {"",},
|
||||
{"thousands_sep", THOUSANDS_SEP},
|
||||
{"",},
|
||||
{"am_pm", AM_STR},
|
||||
{"xdigit", TOK_XDIGIT},
|
||||
{"",},
|
||||
{"decimal_point", DECIMAL_POINT},
|
||||
{"",},
|
||||
{"cntrl", TOK_CNTRL},
|
||||
{"p_sign_posn", P_SIGN_POSN},
|
||||
{"mon_decimal_point", MON_DECIMAL_POINT},
|
||||
{"LC_CTYPE", _NL_NUM_LC_CTYPE},
|
||||
{"",},
|
||||
{"alpha", TOK_ALPHA},
|
||||
{"",},
|
||||
{"forward", TOK_FORWARD},
|
||||
{"era", ERA},
|
||||
{"",},
|
||||
{"print", TOK_PRINT},
|
||||
{"",},
|
||||
{"mon_grouping", MON_GROUPING},
|
||||
{"era_year", ERA_YEAR},
|
||||
{"",}, {"",},
|
||||
{"n_sign_posn", N_SIGN_POSN},
|
||||
{"",},
|
||||
{"END", TOK_END},
|
||||
{"",},
|
||||
{"alt_digits", ALT_DIGITS},
|
||||
{"",},
|
||||
{"d_t_fmt", D_T_FMT},
|
||||
{"",}, {"",},
|
||||
{"nostr", NOSTR},
|
||||
{"LC_MESSAGES", _NL_NUM_LC_MESSAGES},
|
||||
{"",}, {"",}, {"",},
|
||||
{"int_frac_digits", INT_FRAC_DIGITS},
|
||||
{"",}, {"",}, {"",},
|
||||
{"era_d_fmt", ERA_D_FMT},
|
||||
{"punct", TOK_PUNCT},
|
||||
{"",}, {"",}, {"",}, {"",},
|
||||
{"lower", TOK_LOWER},
|
||||
{"",}, {"",}, {"",}, {"",},
|
||||
{"currency_symbol", CURRENCY_SYMBOL},
|
||||
{"",}, {"",},
|
||||
{"grouping", GROUPING},
|
||||
{"from", TOK_FROM},
|
||||
{"abday", ABDAY_1},
|
||||
{"",}, {"",}, {"",}, {"",},
|
||||
{"LC_COLLATE", _NL_NUM_LC_COLLATE},
|
||||
{"LC_MONETARY", _NL_NUM_LC_MONETARY},
|
||||
{"",}, {"",}, {"",}, {"",},
|
||||
{"frac_digits", FRAC_DIGITS},
|
||||
{"",}, {"",}, {"",},
|
||||
{"abmon", ABMON_1},
|
||||
{"",}, {"",},
|
||||
{"backward", TOK_BACKWARD},
|
||||
{"order_end", TOK_ORDER_END},
|
||||
{"blank", TOK_BLANK},
|
||||
{"order_start", TOK_ORDER_START},
|
||||
{"",}, {"",}, {"",},
|
||||
{"graph", TOK_GRAPH},
|
||||
{"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",},
|
||||
{"",}, {"",}, {"",}, {"",}, {"",},
|
||||
{"upper", TOK_UPPER},
|
||||
};
|
||||
|
||||
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
||||
{
|
||||
register int key = hash (str, len);
|
||||
|
||||
if (key <= MAX_HASH_VALUE && key >= 0)
|
||||
{
|
||||
register const char *s = wordlist[key].name;
|
||||
|
||||
if (*s == *str && !strncmp (str + 1, s + 1, len - 1))
|
||||
return &wordlist[key];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -145,8 +145,10 @@ typedef enum
|
|||
_NL_NUM_LC_MESSAGES,
|
||||
|
||||
/* Stubs for unfinished categories. */
|
||||
_NL_NUM_LC_COLLATE = 0,
|
||||
_NL_NUM_LC_COLLATE = _NL_ITEM (LC_COLLATE, 0),
|
||||
|
||||
/* This marks the highest value used. */
|
||||
_NL_NUM
|
||||
} nl_item;
|
||||
|
||||
|
||||
|
|
77
locale/libintl.h
Normal file
77
locale/libintl.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* libintl.h -- Message catalogs for internationalization.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _LIBINTL_H
|
||||
#define _LIBINTL_H 1
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
|
||||
/* Look up MSGID in the current default message catalog for the current
|
||||
LC_MESSAGES locale. If not found, returns MSGID itself (the default
|
||||
text). */
|
||||
extern char *gettext __P ((const char *__msgid));
|
||||
|
||||
/* Look up MSGID in the DOMAINNAME message catalog for the current
|
||||
LC_MESSAGES locale. */
|
||||
extern char *dgettext __P ((const char *__domainname, const char *__msgid));
|
||||
|
||||
/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
|
||||
locale. */
|
||||
extern char *__dcgettext __P ((const char *__domainname, const char *__msgid,
|
||||
int __category));
|
||||
extern char *dcgettext __P ((const char *__domainname, const char *__msgid,
|
||||
int __category));
|
||||
|
||||
|
||||
/* Set the current default message catalog to DOMAINNAME.
|
||||
If DOMAINNAME is null, return the current default.
|
||||
If DOMAINNAME is "", reset to the default of "messages". */
|
||||
extern char *textdomain __P ((const char *__domainname));
|
||||
|
||||
/* Specify that the DOMAINNAME message catalog will be found
|
||||
in DIRNAME rather than in the system locale data base. */
|
||||
extern char *bindtextdomain __P ((const char *__domainname,
|
||||
const char *__dirname));
|
||||
|
||||
|
||||
#if 1 /* XXX stub for the moment */
|
||||
#define gettext(msgid) (msgid)
|
||||
#define textdomain(domain) (void)(domain)
|
||||
#else
|
||||
#define gettext(msgid) __gettext (msgid)
|
||||
#define __gettext(msgid) __dgettext (NULL, (msgid))
|
||||
|
||||
#define dgettext(domainname, msgid) __dgettext (domainname, msgid)
|
||||
#define __dgettext(domainname, msgid) \
|
||||
__dcgettext (NULL, (msgid), LC_MESSAGES)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define __dcgettext(domainname, msgid, category) \
|
||||
(__extension__ \
|
||||
({ \
|
||||
static char *__translation__; \
|
||||
if (! __translation__) \
|
||||
__translation__ = (__dcgettext) ((domainname), (msgid), (category)); \
|
||||
__translation__; \
|
||||
}))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* libintl.h */
|
|
@ -69,13 +69,14 @@ _nl_load_locale (int category, char **name)
|
|||
}
|
||||
|
||||
{
|
||||
const char localedir[] = "/share/locale/"; /* XXX */
|
||||
const char *catname = _nl_category_names[category];
|
||||
size_t namelen = strlen (*name);
|
||||
size_t catlen = strlen (catname);
|
||||
char file[sizeof localedir + namelen + catlen * 2 + 4];
|
||||
sprintf (file, "%s%s/%s",
|
||||
strchr (*name, '/') != NULL ? "" : localedir, *name, catname);
|
||||
char file[sizeof LOCALE_PATH + 1 + namelen + catlen * 2 + 4];
|
||||
if (strchr (*name, '/') != NULL)
|
||||
sprintf (file, "%s/%s", *name, catname);
|
||||
else
|
||||
sprintf (file, "%s/%s/%s", LOCALE_PATH, *name, catname);
|
||||
fd = __open (file, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
|
538
locale/locale.c
Normal file
538
locale/locale.c
Normal file
|
@ -0,0 +1,538 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <dirent.h>
|
||||
#include <getopt.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "localedef.h"
|
||||
|
||||
|
||||
/* If set dump C code describing the current locale. */
|
||||
static int do_dump;
|
||||
|
||||
/* If set print the name of the category. */
|
||||
static int show_category_name;
|
||||
|
||||
/* If set print the name of the item. */
|
||||
static int show_keyword_name;
|
||||
|
||||
/* Long options. */
|
||||
static const struct option long_options[] =
|
||||
{
|
||||
{ "all-locales", no_argument, NULL, 'a' },
|
||||
{ "category-name", no_argument, &show_category_name, 1 },
|
||||
{ "charmaps", no_argument, NULL, 'm' },
|
||||
{ "dump", no_argument, &do_dump, 1 },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "keyword-name", no_argument, &show_keyword_name, 1 },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
/* We don't have these constants defined because we don't use them. Give
|
||||
default values. */
|
||||
#define CTYPE_MB_CUR_MIN 0
|
||||
#define CTYPE_MB_CUR_MAX 0
|
||||
#define CTYPE_HASH_SIZE 0
|
||||
#define CTYPE_HASH_LAYERS 0
|
||||
#define CTYPE_CLASS 0
|
||||
#define CTYPE_TOUPPER_EB 0
|
||||
#define CTYPE_TOLOWER_EB 0
|
||||
#define CTYPE_TOUPPER_EL 0
|
||||
#define CTYPE_TOLOWER_EL 0
|
||||
|
||||
|
||||
/* We have all categories defined in `categories.def'. Now construct
|
||||
the description and data structure used for all categories. */
|
||||
#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
|
||||
static struct cat_item category##_desc[] = \
|
||||
{ \
|
||||
NO_PAREN items \
|
||||
};
|
||||
|
||||
#include "categories.def"
|
||||
#undef DEFINE_CATEGORY
|
||||
|
||||
static struct category category[] =
|
||||
{
|
||||
#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
|
||||
{ _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \
|
||||
category##_desc, NULL, NULL, NULL, out },
|
||||
#include "categories.def"
|
||||
#undef DEFINE_CATEGORY
|
||||
};
|
||||
#define NCATEGORIES NELEMS (category)
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static void usage (int status) __attribute__ ((noreturn));
|
||||
static void write_locales (void);
|
||||
static void write_charmaps (void);
|
||||
static void show_locale_vars (void);
|
||||
static void show_info (const char *name);
|
||||
static void dump_category (const char *name);
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int optchar;
|
||||
int do_all = 0;
|
||||
int do_help = 0;
|
||||
int do_version = 0;
|
||||
int do_charmaps = 0;
|
||||
|
||||
/* Set initial values for global varaibles. */
|
||||
do_dump = 0;
|
||||
show_category_name = 0;
|
||||
show_keyword_name = 0;
|
||||
|
||||
/* Set locale. Do not set LC_ALL because the other categories must
|
||||
not be affected (acccording to POSIX.2). */
|
||||
setlocale (LC_CTYPE, "");
|
||||
setlocale (LC_MESSAGES, "");
|
||||
|
||||
/* Initialize the message catalog. */
|
||||
textdomain (PACKAGE);
|
||||
|
||||
while ((optchar = getopt_long (argc, argv, "achkmv", long_options, NULL))
|
||||
!= EOF)
|
||||
switch (optchar)
|
||||
{
|
||||
case '\0':
|
||||
break;
|
||||
case 'a':
|
||||
do_all = 1;
|
||||
break;
|
||||
case 'c':
|
||||
show_category_name = 1;
|
||||
break;
|
||||
case 'h':
|
||||
do_help = 1;
|
||||
break;
|
||||
case 'k':
|
||||
show_keyword_name = 1;
|
||||
break;
|
||||
case 'm':
|
||||
do_charmaps = 1;
|
||||
break;
|
||||
case 'v':
|
||||
do_version = 1;
|
||||
break;
|
||||
default:
|
||||
error (1, 0, gettext ("illegal option \"%s\""), optarg);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Version information is requested. */
|
||||
if (do_version)
|
||||
{
|
||||
fprintf (stderr, "GNU %s %s\n", PACKAGE, VERSION);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Help is requested. */
|
||||
if (do_help)
|
||||
usage (EXIT_SUCCESS);
|
||||
|
||||
/* Dump C code. */
|
||||
if (do_dump)
|
||||
{
|
||||
printf ("\
|
||||
/* Generated by GNU %s %s. */\n\
|
||||
\n\
|
||||
#include \"localeinfo.h\"\n", program_invocation_name, VERSION);
|
||||
|
||||
while (optind < argc)
|
||||
dump_category (argv[optind++]);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* `-a' requests the names of all available locales. */
|
||||
if (do_all != 0)
|
||||
{
|
||||
write_locales ();
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* `m' requests the names of all available charmaps. The names can be
|
||||
used for the -f argument to localedef(3). */
|
||||
if (do_charmaps != 0)
|
||||
{
|
||||
write_charmaps ();
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* If no real argument is given we have to print the contents of the
|
||||
current locale definition variables. These are LANG and the LC_*. */
|
||||
if (optind == argc && show_keyword_name == 0 && show_category_name == 0)
|
||||
{
|
||||
show_locale_vars ();
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Process all given names. */
|
||||
while (optind < argc)
|
||||
show_info (argv[optind++]);
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* Display usage information and exit. */
|
||||
static void
|
||||
usage(int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
|
||||
program_invocation_name);
|
||||
else
|
||||
printf(gettext ("\
|
||||
Usage: %s [OPTION]... name\n\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-h, --help display this help and exit\n\
|
||||
-v, --version output version information and exit\n\
|
||||
\n\
|
||||
-a, --all-locales write names of available locales\n\
|
||||
-m, --charmaps write names of available charmaps\n\
|
||||
\n\
|
||||
-c, --category-name write names of selected categories\n\
|
||||
-k, --keyword-name write names of selected keywords\n\
|
||||
\n\
|
||||
--dump dump C code describing the current locale\n\
|
||||
(this code can be used in the C library)\n\
|
||||
"), program_invocation_name);
|
||||
|
||||
exit (status);
|
||||
}
|
||||
|
||||
|
||||
/* Write the names of all available locales to stdout. */
|
||||
static void
|
||||
write_locales (void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
|
||||
/* `POSIX' locale is always available (POSIX.2 4.34.3). */
|
||||
puts ("POSIX");
|
||||
|
||||
dir = opendir (LOCALE_PATH);
|
||||
if (dir == NULL)
|
||||
{
|
||||
error (1, errno, gettext ("cannot read locale directory `%s'"),
|
||||
LOCALE_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we can look for all files in the directory. */
|
||||
while ((dirent = readdir (dir)) != NULL)
|
||||
if (strcmp (dirent->d_name, ".") != 0
|
||||
&& strcmp (dirent->d_name, "..") != 0)
|
||||
puts (dirent->d_name);
|
||||
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
|
||||
/* Write the names of all available character maps to stdout. */
|
||||
static void
|
||||
write_charmaps (void)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
|
||||
dir = opendir (CHARMAP_PATH);
|
||||
if (dir == NULL)
|
||||
{
|
||||
error (1, errno, gettext ("cannot read character map directory `%s'"),
|
||||
CHARMAP_PATH);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now we can look for all files in the directory. */
|
||||
while ((dirent = readdir (dir)) != NULL)
|
||||
if (strcmp (dirent->d_name, ".") != 0
|
||||
&& strcmp (dirent->d_name, "..") != 0)
|
||||
puts (dirent->d_name);
|
||||
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
|
||||
/* We have to show the contents of the environments determining the
|
||||
locale. */
|
||||
static void
|
||||
show_locale_vars (void)
|
||||
{
|
||||
size_t cat_no;
|
||||
const char *lcall = getenv ("LC_ALL");
|
||||
const char *lang = getenv ("LANG") ? : "POSIX";
|
||||
|
||||
void get_source (const char *name)
|
||||
{
|
||||
char *val = getenv (name);
|
||||
|
||||
if (lcall != NULL || val == NULL)
|
||||
printf ("%s=\"%s\"\n", name, lcall ? : lang);
|
||||
else
|
||||
printf ("%s=%s\n", name, val);
|
||||
}
|
||||
|
||||
/* LANG has to be the first value. */
|
||||
printf ("LANG=%s\n", lang);
|
||||
|
||||
/* Now all categories in an unspecified order. */
|
||||
for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
|
||||
get_source (category[cat_no].name);
|
||||
|
||||
/* The last is the LC_ALL value. */
|
||||
printf ("LC_ALL=%s\n", lcall ? : "");
|
||||
}
|
||||
|
||||
|
||||
/* Show the information request for NAME. */
|
||||
static void
|
||||
show_info (const char *name)
|
||||
{
|
||||
size_t cat_no;
|
||||
|
||||
void print_item (struct cat_item *item)
|
||||
{
|
||||
if (show_keyword_name != 0)
|
||||
printf ("%s=", item->name);
|
||||
|
||||
switch (item->value_type)
|
||||
{
|
||||
case string:
|
||||
printf ("%s%s%s", show_keyword_name ? "\"" : "",
|
||||
nl_langinfo (item->item_id) ? : "",
|
||||
show_keyword_name ? "\"" : "");
|
||||
break;
|
||||
case stringarray:
|
||||
{
|
||||
int cnt;
|
||||
const char *val;
|
||||
|
||||
if (show_keyword_name)
|
||||
putchar ('"');
|
||||
|
||||
for (cnt = 0; cnt < item->max - 1; ++cnt)
|
||||
{
|
||||
val = nl_langinfo (item->item_id + cnt);
|
||||
printf ("%s;", val ? : "");
|
||||
}
|
||||
|
||||
val = nl_langinfo (item->item_id + cnt);
|
||||
printf ("%s", val ? : "");
|
||||
|
||||
if (show_keyword_name)
|
||||
putchar ('"');
|
||||
}
|
||||
break;
|
||||
case byte:
|
||||
{
|
||||
const char *val = nl_langinfo (item->item_id);
|
||||
|
||||
if (val != NULL)
|
||||
printf ("%d", *val == CHAR_MAX ? -1 : *val);
|
||||
}
|
||||
break;
|
||||
case bytearray:
|
||||
{
|
||||
const char *val = nl_langinfo (item->item_id);
|
||||
int cnt = val ? strlen (val) : 0;
|
||||
|
||||
while (cnt > 1)
|
||||
{
|
||||
printf ("%d;", *val == CHAR_MAX ? -1 : *val);
|
||||
--cnt;
|
||||
++val;
|
||||
}
|
||||
|
||||
printf ("%d", cnt == 0 || *val == CHAR_MAX ? -1 : *val);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
|
||||
{
|
||||
size_t item_no;
|
||||
|
||||
if (category[cat_no].outfct != NULL)
|
||||
/* Categories which need special handling of the output are
|
||||
not written. This is especially for LC_CTYPE and LC_COLLATE.
|
||||
It does not make sense to have this large number of cryptic
|
||||
characters displayed. */
|
||||
continue;
|
||||
|
||||
if (strcmp (name, category[cat_no].name) == 0)
|
||||
/* Print the whole category. */
|
||||
{
|
||||
if (show_category_name != 0)
|
||||
puts (category[cat_no].name);
|
||||
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
print_item (&category[cat_no].item_desc[item_no]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
if (strcmp (name, category[cat_no].item_desc[item_no].name) == 0)
|
||||
{
|
||||
if (show_category_name != 0)
|
||||
puts (category[cat_no].name);
|
||||
|
||||
print_item (&category[cat_no].item_desc[item_no]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dump_category (const char *name)
|
||||
{
|
||||
char *locname;
|
||||
size_t cat_no, item_no, nstrings;
|
||||
|
||||
for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
|
||||
if (strcmp (name, category[cat_no].name) == 0)
|
||||
break;
|
||||
|
||||
if (cat_no >= NCATEGORIES)
|
||||
return;
|
||||
|
||||
/* The NAME specifies a correct locale category. */
|
||||
if (category[cat_no].outfct != NULL)
|
||||
{
|
||||
category[cat_no].outfct ();
|
||||
return;
|
||||
}
|
||||
|
||||
locname = (getenv ("LC_ALL") ?: getenv (name) ?:
|
||||
getenv ("LANG") ?: (char *) "POSIX");
|
||||
|
||||
/* Determine the number of strings in advance. */
|
||||
nstrings = 0;
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
switch (category[cat_no].item_desc[item_no].value_type)
|
||||
{
|
||||
case string:
|
||||
case byte:
|
||||
case bytearray:
|
||||
++nstrings;
|
||||
break;
|
||||
case stringarray:
|
||||
nstrings += category[cat_no].item_desc[item_no].max;
|
||||
default:
|
||||
}
|
||||
|
||||
printf ("\nconst struct locale_data _nl_%s_%s =\n{\n"
|
||||
" NULL, 0, /* no file mapped */\n %Zu,\n {\n",
|
||||
locname, name, nstrings);
|
||||
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
switch (category[cat_no].item_desc[item_no].value_type)
|
||||
{
|
||||
case string:
|
||||
{
|
||||
const char *val = nl_langinfo (
|
||||
category[cat_no].item_desc[item_no].item_id);
|
||||
|
||||
if (val != NULL)
|
||||
printf (" \"%s\",\n", val);
|
||||
else
|
||||
puts (" NULL,");
|
||||
}
|
||||
break;
|
||||
case stringarray:
|
||||
{
|
||||
const char *val;
|
||||
int cnt;
|
||||
|
||||
for (cnt = 0; cnt < category[cat_no].item_desc[item_no].max; ++cnt)
|
||||
{
|
||||
val = nl_langinfo (
|
||||
category[cat_no].item_desc[item_no].item_id + cnt);
|
||||
|
||||
if (val != NULL)
|
||||
printf (" \"%s\",\n", val);
|
||||
else
|
||||
puts (" NULL,");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case byte:
|
||||
{
|
||||
const char *val = nl_langinfo (
|
||||
category[cat_no].item_desc[item_no].item_id);
|
||||
|
||||
if (val != NULL)
|
||||
printf (" \"\\%o\",\n",
|
||||
*(unsigned char *) val ? : UCHAR_MAX);
|
||||
else
|
||||
puts (" NULL,");
|
||||
}
|
||||
break;
|
||||
case bytearray:
|
||||
{
|
||||
const char *bytes = nl_langinfo (
|
||||
category[cat_no].item_desc[item_no].item_id);
|
||||
|
||||
if (bytes != NULL)
|
||||
{
|
||||
fputs (" \"", stdout);
|
||||
if (*bytes != '\0')
|
||||
do
|
||||
printf ("\\%o", *(unsigned char *) bytes++);
|
||||
while (*bytes != '\0');
|
||||
else
|
||||
printf ("\\%o", UCHAR_MAX);
|
||||
|
||||
puts ("\",");
|
||||
}
|
||||
else
|
||||
puts (" NULL,");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
puts (" }\n};");
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
261
locale/localedef.c
Normal file
261
locale/localedef.c
Normal file
|
@ -0,0 +1,261 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "localedef.h"
|
||||
|
||||
/* The charmap file used. If none given DEFAULT_CHARMAP is used. */
|
||||
static char *charmap_file;
|
||||
|
||||
/* If set output is always written, even when warning are given. */
|
||||
static int force_output;
|
||||
|
||||
/* The input file name. */
|
||||
static char *input_file;
|
||||
|
||||
/* Path leading to the destination directory for the produced files. */
|
||||
char *output_path;
|
||||
|
||||
/* If this is defined be POSIX conform. */
|
||||
int posix_conformance;
|
||||
|
||||
/* If not zero give a lot more messages. */
|
||||
int verbose;
|
||||
|
||||
/* Long options. */
|
||||
static const struct option long_options[] =
|
||||
{
|
||||
{ "charmap", required_argument, NULL, 'f' },
|
||||
{ "debug", no_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "force", no_argument, NULL, 'c' },
|
||||
{ "inputfile", required_argument, NULL, 'i' },
|
||||
{ "posix", no_argument, &posix_conformance, 1 },
|
||||
{ "verbose", no_argument, &verbose, 1},
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
/* This is defined in error-msg.h. */
|
||||
extern int warning_cntr;
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static void usage (int status) __attribute__ ((noreturn));
|
||||
static int construct_output_path (const char *path);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int optchar;
|
||||
int cannot_write;
|
||||
int do_help = 0;
|
||||
int do_version = 0;
|
||||
|
||||
/* Set initial values for global varaibles. */
|
||||
charmap_file = NULL;
|
||||
force_output = 0;
|
||||
input_file = 0;
|
||||
posix_conformance = getenv ("POSIXLY_CORRECT") != NULL;
|
||||
verbose = 0;
|
||||
|
||||
/* Set locale. Do not set LC_ALL because the other categories must
|
||||
not be affected (acccording to POSIX.2). */
|
||||
setlocale (LC_MESSAGES, "");
|
||||
setlocale (LC_CTYPE, "");
|
||||
|
||||
/* Initialize the message catalog. */
|
||||
textdomain (PACKAGE);
|
||||
|
||||
while ((optchar = getopt_long (argc, argv, "cdf:hi:vV", long_options, NULL))
|
||||
!= EOF)
|
||||
switch (optchar)
|
||||
{
|
||||
case '\0':
|
||||
break;
|
||||
case 'c':
|
||||
force_output = 1;
|
||||
break;
|
||||
case 'f':
|
||||
if (charmap_file != NULL)
|
||||
error (0, 0, gettext ("\"%s %s\" overwrites old option \"%s\""),
|
||||
"-f", optarg, charmap_file);
|
||||
charmap_file = optarg;
|
||||
break;
|
||||
case 'h':
|
||||
do_help = 1;
|
||||
break;
|
||||
case 'i':
|
||||
if (input_file != NULL)
|
||||
error (0, 0, gettext ("\"%s %s\" overwrites old option \"%s\""),
|
||||
"-i", optarg, input_file);
|
||||
input_file = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'V':
|
||||
do_version = 1;
|
||||
break;
|
||||
default:
|
||||
usage (4);
|
||||
break;
|
||||
}
|
||||
|
||||
/* POSIX.2 requires to be verbose about missing characters in the
|
||||
character map. */
|
||||
verbose |= posix_conformance;
|
||||
|
||||
/* Version information is requested. */
|
||||
if (do_version)
|
||||
{
|
||||
fprintf (stderr, "GNU %s %s\n", PACKAGE, VERSION);
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Help is requested. */
|
||||
if (do_help)
|
||||
usage (0);
|
||||
|
||||
if (argc - optind != 1)
|
||||
/* We need exactly one non-option parameter. */
|
||||
usage (4);
|
||||
|
||||
/* The parameter describes the output path of the constructed files.
|
||||
If the files cannot be written return a non-zero value. */
|
||||
cannot_write = construct_output_path (argv[optind]);
|
||||
|
||||
/* Now that the parameters are processed we have to reset the local
|
||||
ctype locale. (POSIX.2 4.35.5.2) */
|
||||
setlocale (LC_CTYPE, "POSIX");
|
||||
|
||||
/* Look whether the system really allows locale definitions. */
|
||||
if (sysconf (_SC_2_LOCALEDEF) < 0)
|
||||
error (3, 0,
|
||||
gettext ("warning: system does not define `_POSIX2_LOCALEDEF'"));
|
||||
|
||||
/* Process charmap file. */
|
||||
charmap_read (charmap_file);
|
||||
|
||||
/* Now read the locale file. */
|
||||
locfile_read (input_file);
|
||||
|
||||
/* Check all categories for consistency. */
|
||||
categories_check ();
|
||||
|
||||
/* We are now able to write the data files. If warning were given we
|
||||
do it only if it is explicitly requested (--force). */
|
||||
if (warning_cntr == 0 || force_output != 0)
|
||||
if (cannot_write != 0)
|
||||
error (0, 0, gettext ("cannot write output file `%s': %s"),
|
||||
output_path, strerror (cannot_write));
|
||||
else
|
||||
categories_write ();
|
||||
else
|
||||
error (0, 0,
|
||||
gettext ("no output file produced because warning were issued"));
|
||||
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
|
||||
/* Display usage information and exit. */
|
||||
static void
|
||||
usage(int status)
|
||||
{
|
||||
if (status != EXIT_SUCCESS)
|
||||
fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
|
||||
program_invocation_name);
|
||||
else
|
||||
printf(gettext ("\
|
||||
Usage: %s [OPTION]... name\n\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-c, --force create output even if warning messages have been issued\n\
|
||||
-h, --help display this help and exit\n\
|
||||
-V, --version output version information and exit\n\
|
||||
\n\
|
||||
-i, --inputfile=FILE source definitions are found in FILE\n\
|
||||
-f, --charmap=FILE symbolic character names defined in FILE\n\
|
||||
\n\
|
||||
-v, --verbose print more messages\n\
|
||||
--posix be strictly POSIX conform\n\
|
||||
\n\
|
||||
System's directory for character maps: %s\n\
|
||||
locale files : %s\n\
|
||||
"), program_invocation_name, CHARMAP_PATH, LOCALE_PATH);
|
||||
|
||||
exit (status);
|
||||
}
|
||||
|
||||
|
||||
/* The parameter to localedef describes the output path. If it does
|
||||
contain a '/' character it is a relativ path. Otherwise it names the
|
||||
locale this definition is for. */
|
||||
static int
|
||||
construct_output_path (const char *path)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (strchr (path, '/') == NULL)
|
||||
{
|
||||
/* This is a system path. */
|
||||
int path_max_len = pathconf (LOCALE_PATH, _PC_PATH_MAX) + 1;
|
||||
output_path = (char *) xmalloc (path_max_len);
|
||||
|
||||
snprintf (output_path, path_max_len, "%s/%s", LOCALE_PATH, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *t;
|
||||
/* This is a user path. */
|
||||
output_path = malloc (strlen (path) + 2);
|
||||
t = stpcpy (output_path, path);
|
||||
*t = '\0';
|
||||
}
|
||||
|
||||
if (euidaccess (output_path, W_OK) == -1)
|
||||
/* Perhaps the directory does not exist now. Try to create it. */
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
if (mkdir (output_path, 0777) == -1)
|
||||
result = errno;
|
||||
}
|
||||
else
|
||||
result = errno;
|
||||
|
||||
if (result == 0)
|
||||
strcat (output_path, "/");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
196
locale/localedef.h
Normal file
196
locale/localedef.h
Normal file
|
@ -0,0 +1,196 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _LOCALEDEF_H
|
||||
#define _LOCALEDEF_H 1
|
||||
|
||||
#define __need_wchar_t
|
||||
#include <stddef.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
|
||||
/* Needed always. */
|
||||
#define MAX(a, b) ({typeof (a) _a = (a); typeof (b) _b = (b); \
|
||||
_a > _b ? _a : _b; })
|
||||
#define MIN(a, b) ({typeof (a) _a = (a); typeof (b) _b = (b); \
|
||||
_a < _b ? _a : _b; })
|
||||
|
||||
/* Determine number of elements in ARR. */
|
||||
#define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0])))
|
||||
|
||||
/* I simply love these GCC features ... :) */
|
||||
#define NO_PAREN(arg, rest...) arg, ##rest
|
||||
|
||||
|
||||
/* The character set used in the locale is defined in a character map file.
|
||||
The information of the file is stored in the following struct. */
|
||||
struct charmap
|
||||
{
|
||||
char *filename;
|
||||
char *codeset_name;
|
||||
int mb_cur_min;
|
||||
int mb_cur_max;
|
||||
char escape_char;
|
||||
char comment_char;
|
||||
hash_table table;
|
||||
int hash_size;
|
||||
int hash_layers;
|
||||
};
|
||||
|
||||
/* Data structure for representing charmap database. */
|
||||
extern struct charmap charmap_data;
|
||||
|
||||
|
||||
/* We can map the types of the entries into four categories. */
|
||||
enum value_type { none, string, stringarray, byte, bytearray, integer };
|
||||
|
||||
/* Definition of the data structure which represents a category and its
|
||||
items. */
|
||||
struct category
|
||||
{
|
||||
int cat_id;
|
||||
const char *name;
|
||||
size_t number;
|
||||
struct cat_item
|
||||
{
|
||||
int item_id;
|
||||
const char *name;
|
||||
enum { std, opt } status;
|
||||
enum value_type value_type;
|
||||
int min;
|
||||
int max;
|
||||
} *item_desc;
|
||||
char **item_value;
|
||||
void (*infct)(int);
|
||||
void (*checkfct)(void);
|
||||
int (*outfct)(void);
|
||||
int filled;
|
||||
char *copy_locale;
|
||||
};
|
||||
|
||||
/* This a the structure which contains all information about all
|
||||
categories. */
|
||||
extern struct category category[];
|
||||
|
||||
|
||||
/* The function used to load the contents of a charmap file into the
|
||||
the global variable `charmap_data'. */
|
||||
void charmap_read (const char *filename);
|
||||
|
||||
/* Find a character constant given by its name in the hash table. */
|
||||
static inline wchar_t find_char (const char *name, size_t len)
|
||||
{
|
||||
wchar_t retval;
|
||||
if (find_entry (&charmap_data.table, name, len, (void **) &retval) != 0)
|
||||
return retval;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Path to the directory the output files are written in. */
|
||||
extern char *output_path;
|
||||
|
||||
/* If this is defined be POSIX conform. */
|
||||
extern int posix_conformance;
|
||||
|
||||
/* If not zero give a lot more messages. */
|
||||
extern int verbose;
|
||||
|
||||
/* This structure contains all informations about the status of of
|
||||
reading the locale definition file. */
|
||||
struct locfile_data
|
||||
{
|
||||
const char *filename;
|
||||
char escape_char;
|
||||
char comment_char;
|
||||
size_t bufsize;
|
||||
char *buf;
|
||||
char *strbuf;
|
||||
size_t buf_ptr;
|
||||
int continue_line;
|
||||
size_t returned_tokens;
|
||||
size_t line_no;
|
||||
};
|
||||
|
||||
/* The status variable. */
|
||||
extern struct locfile_data locfile_data;
|
||||
|
||||
/* Open the locale definition file. */
|
||||
void locfile_open (const char *fname);
|
||||
|
||||
/* Return the next token from the locale definition file. */
|
||||
int locfile_lex (char **token, int *token_len);
|
||||
/* Dito, but check for EOF. */
|
||||
int xlocfile_lex (char **token, int *token_len);
|
||||
|
||||
/* Ignore the rest of the line. First TOKEN given if != 0. Warn about
|
||||
anything other than end of line if WARN_FLAG nonzero. */
|
||||
void ignore_to_eol (int token, int warn_flag);
|
||||
|
||||
/* Code a character with UTF-8 if the character map has multi-byte
|
||||
characters. */
|
||||
int char_to_utf (char *buf, int char_val);
|
||||
|
||||
|
||||
/* Read the locale defintion file FNAME and fill the appropriate
|
||||
data structures. */
|
||||
void locfile_read (const char *fname);
|
||||
|
||||
/* Check categories for consistency. */
|
||||
void categories_check (void);
|
||||
|
||||
/* Write out the binary representation of the category data. */
|
||||
void categories_write (void);
|
||||
|
||||
|
||||
/* Treat reading the LC_COLLATE definition. */
|
||||
void collate_input (int token);
|
||||
|
||||
/* Treat reading the LC_CTYPE definition. */
|
||||
void ctype_input (int token);
|
||||
void ctype_check (void);
|
||||
int ctype_output (void);
|
||||
|
||||
/* Treat reading the LC_MONETARY definition. */
|
||||
void monetary_check (void);
|
||||
|
||||
/* Treat reading the LC_MESSAGES definition. */
|
||||
void messages_check (void);
|
||||
|
||||
/* Treat reading the LC_NUMERIC definition. */
|
||||
void numeric_check (void);
|
||||
|
||||
|
||||
/* Print an error message, possibly with NLS. */
|
||||
void error (int status, int errnum, const char *format, ...)
|
||||
__attribute__ ((format (printf, 3, 4)));
|
||||
|
||||
/* Library functions. */
|
||||
void *xmalloc (size_t n);
|
||||
void *xcalloc (size_t n, size_t s);
|
||||
void *xrealloc (void *p, size_t n);
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
||||
#endif /* _LOCALEDEF_H */
|
533
locale/locfile-lex.c
Normal file
533
locale/locfile-lex.c
Normal file
|
@ -0,0 +1,533 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "localedef.h"
|
||||
#include "token.h"
|
||||
|
||||
|
||||
/* Include the hashing table for the keywords. */
|
||||
const struct locale_keyword* in_word_set (register const char *str,
|
||||
register int len);
|
||||
#include "keyword.h"
|
||||
|
||||
|
||||
/* Contains the status of reading the locale definition file. */
|
||||
struct locfile_data locfile_data;
|
||||
|
||||
/* This is a flag used while collation input. This is the only place
|
||||
where element names beside the ones defined in the character map are
|
||||
allowed. There we must not give error messages. */
|
||||
int reject_new_char = 1;
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static int get_char (void);
|
||||
|
||||
|
||||
#define LD locfile_data
|
||||
|
||||
/* Opens the locale definition file and initializes the status data structure
|
||||
for following calls of `locfile_lex'. */
|
||||
void
|
||||
locfile_open (const char *fname)
|
||||
{
|
||||
if (fname == NULL)
|
||||
/* We read from stdin. */
|
||||
LD.filename = "<stdin>";
|
||||
else
|
||||
{
|
||||
if (freopen (fname, "r", stdin) == NULL)
|
||||
error (4, 0, gettext ("input file `%s' not found"), fname);
|
||||
LD.filename = fname;
|
||||
}
|
||||
|
||||
/* Set default values. */
|
||||
LD.escape_char = '\\';
|
||||
LD.comment_char = '#';
|
||||
|
||||
LD.bufsize = sysconf (_SC_LINE_MAX);
|
||||
LD.buf = (char *) xmalloc (LD.bufsize);
|
||||
LD.strbuf = (char *) xmalloc (LD.bufsize);
|
||||
|
||||
LD.buf_ptr = LD.returned_tokens = LD.line_no = 0;
|
||||
|
||||
/* Now sign that we want immediately read a line. */
|
||||
LD.continue_line = 1;
|
||||
LD.buf[LD.buf_ptr] = '\0';
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
xlocfile_lex (char **token, int *token_len)
|
||||
{
|
||||
int retval = locfile_lex (token, token_len);
|
||||
|
||||
if (retval == 0)
|
||||
/* I.e. end of file. */
|
||||
error (4, 0, gettext ("%s: unexpected end of file in locale defintion "
|
||||
"file"), locfile_data.filename);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
locfile_lex (char **token, int *token_len)
|
||||
{
|
||||
int start_again;
|
||||
int retval = 0;
|
||||
|
||||
do
|
||||
{
|
||||
int start_ptr;
|
||||
|
||||
start_again = 0;
|
||||
|
||||
/* Read the next line. Skip over empty lines and comments. */
|
||||
if ((LD.buf[LD.buf_ptr] == '\0' && LD.continue_line != 0)
|
||||
|| LD.buf_ptr >= LD.bufsize
|
||||
|| (posix_conformance == 0 && LD.buf[LD.buf_ptr] == LD.comment_char))
|
||||
do
|
||||
{
|
||||
size_t linelen;
|
||||
|
||||
LD.buf_ptr = 0;
|
||||
|
||||
if (fgets (LD.buf, LD.bufsize, stdin) == NULL)
|
||||
{
|
||||
/* This makes subsequent calls also return EOF. */
|
||||
LD.buf[0] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Increment line number counter. */
|
||||
++LD.line_no;
|
||||
|
||||
/* We now have to look whether this line is continued and
|
||||
whether it at all fits into our buffer. */
|
||||
linelen = strlen (LD.buf);
|
||||
|
||||
if (linelen == LD.bufsize - 1)
|
||||
/* The did not fit into the buffer. */
|
||||
error (2, 0, gettext ("%s:%Zd: line too long; use "
|
||||
"`getconf LINE_MAX' to get the maximum "
|
||||
"line length"), LD.filename, LD.line_no);
|
||||
|
||||
/* Remove '\n' at end of line. */
|
||||
if (LD.buf[linelen - 1] == '\n')
|
||||
LD.buf[--linelen] = '\0';
|
||||
|
||||
if (linelen > 0 && LD.buf[linelen - 1] == LD.escape_char)
|
||||
{
|
||||
LD.buf[--linelen] = '\0';
|
||||
LD.continue_line = 1;
|
||||
}
|
||||
else
|
||||
LD.continue_line = 0;
|
||||
|
||||
while (isspace (LD.buf[LD.buf_ptr]))
|
||||
++LD.buf_ptr;
|
||||
|
||||
/* We are not so restrictive and allow white spaces before
|
||||
a comment. */
|
||||
if (posix_conformance == 0
|
||||
&& LD.buf[LD.buf_ptr] == LD.comment_char
|
||||
&& LD.buf_ptr != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: comment does not start in "
|
||||
"column 1"), LD.filename, LD.line_no);
|
||||
}
|
||||
while (LD.buf[LD.buf_ptr] == '\0'
|
||||
|| LD.buf[LD.buf_ptr] == LD.comment_char);
|
||||
|
||||
|
||||
/* Get information for return values. */
|
||||
*token = LD.buf + LD.buf_ptr;
|
||||
start_ptr = LD.buf_ptr;
|
||||
|
||||
/* If no further character is in the line this is the end of a logical
|
||||
line. This information is needed in the parser. */
|
||||
if (LD.buf[LD.buf_ptr] == '\0')
|
||||
{
|
||||
LD.buf_ptr = LD.bufsize;
|
||||
retval = TOK_ENDOFLINE;
|
||||
}
|
||||
else if (isalpha (LD.buf[LD.buf_ptr]))
|
||||
/* The token is an identifier. The POSIX standard does not say
|
||||
what characters might be contained but offical POSIX locale
|
||||
definition files contain beside alnum characters '_', '-' and
|
||||
'+'. */
|
||||
{
|
||||
const struct locale_keyword *kw;
|
||||
|
||||
do
|
||||
++LD.buf_ptr;
|
||||
while (isalnum (LD.buf[LD.buf_ptr]) || LD.buf[LD.buf_ptr] == '_'
|
||||
|| LD.buf[LD.buf_ptr] == '-' || LD.buf[LD.buf_ptr] == '+');
|
||||
|
||||
/* Look in table of keywords. */
|
||||
kw = in_word_set (*token, LD.buf_ptr - start_ptr);
|
||||
if (kw == NULL)
|
||||
retval = TOK_IDENT;
|
||||
else
|
||||
{
|
||||
if (kw->token_id == TOK_ESCAPE_CHAR
|
||||
|| kw->token_id == TOK_COMMENT_CHAR)
|
||||
/* `escape_char' and `comment_char' are keywords for the
|
||||
lexer. Do not give them to the parser. */
|
||||
{
|
||||
start_again = 1;
|
||||
|
||||
if (!isspace (LD.buf[LD.buf_ptr])
|
||||
|| (posix_conformance && LD.returned_tokens > 0))
|
||||
error (0, 0, gettext ("%s:%Zd: syntax error in locale "
|
||||
"definition file"),
|
||||
LD.filename, LD.line_no);
|
||||
|
||||
do
|
||||
++LD.buf_ptr;
|
||||
while (isspace (LD.buf[LD.buf_ptr]));
|
||||
|
||||
kw->token_id == TOK_ESCAPE_CHAR
|
||||
? LD.escape_char
|
||||
: LD.comment_char = LD.buf[LD.buf_ptr++];
|
||||
|
||||
ignore_to_eol (0, posix_conformance);
|
||||
}
|
||||
else
|
||||
/* It is one of the normal keywords. */
|
||||
retval = kw->token_id;
|
||||
}
|
||||
|
||||
*token_len = LD.buf_ptr - start_ptr;
|
||||
}
|
||||
else if (LD.buf[LD.buf_ptr] == '"')
|
||||
/* Read a string. All symbolic character descriptions are expanded.
|
||||
This has to be done in a local buffer because a simple symbolic
|
||||
character like <A> may expand to upto 6 bytes. */
|
||||
{
|
||||
char *last = LD.strbuf;
|
||||
|
||||
++LD.buf_ptr;
|
||||
while (LD.buf[LD.buf_ptr] != '"')
|
||||
{
|
||||
int pre = LD.buf_ptr;
|
||||
int char_val = get_char (); /* token, token_len); */
|
||||
|
||||
if (char_val == 0)
|
||||
{
|
||||
error (4, 0, gettext ("%s:%Zd: unterminated string at end "
|
||||
"of line"), LD.filename, LD.line_no);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (char_val > 0)
|
||||
/* Unknown characters are simply not stored. */
|
||||
last += char_to_utf (last, char_val);
|
||||
else
|
||||
{
|
||||
char tmp[LD.buf_ptr - pre + 1];
|
||||
memcpy (tmp, &LD.buf[pre], LD.buf_ptr - pre);
|
||||
tmp[LD.buf_ptr - pre] = '\0';
|
||||
error (0, 0, gettext ("%s:%Zd: character `%s' not defined"),
|
||||
LD.filename, LD.line_no, tmp);
|
||||
}
|
||||
}
|
||||
if (LD.buf[LD.buf_ptr] != '\0')
|
||||
++LD.buf_ptr;
|
||||
|
||||
*last = '\0';
|
||||
*token = LD.strbuf;
|
||||
*token_len = last - LD.strbuf;
|
||||
retval = TOK_STRING;
|
||||
}
|
||||
else if (LD.buf[LD.buf_ptr] == '.' && LD.buf[LD.buf_ptr + 1] == '.'
|
||||
&& LD.buf[LD.buf_ptr + 2] == '.')
|
||||
{
|
||||
LD.buf_ptr += 3;
|
||||
retval = TOK_ELLIPSIS;
|
||||
}
|
||||
else if (LD.buf[LD.buf_ptr] == LD.escape_char)
|
||||
{
|
||||
char *endp;
|
||||
|
||||
++LD.buf_ptr;
|
||||
switch (LD.buf[LD.buf_ptr])
|
||||
{
|
||||
case 'x':
|
||||
if (isdigit (LD.buf[++LD.buf_ptr]))
|
||||
{
|
||||
retval = strtol (&LD.buf[LD.buf_ptr], &endp, 16);
|
||||
if (endp - (LD.buf + LD.buf_ptr) < 2 || retval > 255)
|
||||
retval = 'x';
|
||||
else
|
||||
LD.buf_ptr = endp - LD.buf;
|
||||
}
|
||||
else
|
||||
retval = 'x';
|
||||
break;
|
||||
case 'd':
|
||||
if (isdigit (LD.buf[++LD.buf_ptr]))
|
||||
{
|
||||
retval = strtol (&LD.buf[LD.buf_ptr], &endp, 10);
|
||||
if (endp - (LD.buf + LD.buf_ptr) < 2 || retval > 255)
|
||||
retval = 'd';
|
||||
else
|
||||
LD.buf_ptr = endp - LD.buf;
|
||||
}
|
||||
else
|
||||
retval = 'd';
|
||||
break;
|
||||
case '0'...'9':
|
||||
retval = strtol (&LD.buf[LD.buf_ptr], &endp, 8);
|
||||
if (endp - (LD.buf + LD.buf_ptr) < 2 || retval > 255)
|
||||
retval = LD.buf[LD.buf_ptr++];
|
||||
else
|
||||
LD.buf_ptr = endp - LD.buf;
|
||||
break;
|
||||
case 'a':
|
||||
retval = '\a';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
case 'b':
|
||||
retval = '\b';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
case 'f':
|
||||
retval = '\f';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
case 'n':
|
||||
retval = '\n';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
case 'r':
|
||||
retval = '\r';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
case 't':
|
||||
retval = '\t';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
case 'v':
|
||||
retval = '\v';
|
||||
++LD.buf_ptr;
|
||||
break;
|
||||
default:
|
||||
retval = LD.buf[LD.buf_ptr++];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (isdigit (LD.buf[LD.buf_ptr]))
|
||||
{
|
||||
char *endp;
|
||||
|
||||
*token_len = strtol (&LD.buf[LD.buf_ptr], &endp, 10);
|
||||
LD.buf_ptr = endp - LD.buf;
|
||||
retval = TOK_NUMBER;
|
||||
}
|
||||
else if (LD.buf[LD.buf_ptr] == '-' && LD.buf[LD.buf_ptr + 1] == '1')
|
||||
{
|
||||
LD.buf_ptr += 2;
|
||||
retval = TOK_MINUS1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int ch = get_char (); /* token, token_len); */
|
||||
if (ch != -1)
|
||||
{
|
||||
*token_len = ch;
|
||||
retval = TOK_CHAR;
|
||||
}
|
||||
else
|
||||
retval = TOK_ILL_CHAR;
|
||||
}
|
||||
|
||||
/* Ignore white space. */
|
||||
while (isspace (LD.buf[LD.buf_ptr]))
|
||||
++LD.buf_ptr;
|
||||
}
|
||||
while (start_again != 0);
|
||||
|
||||
++LD.returned_tokens;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/* Code a character with UTF-8 if the character map has multi-byte
|
||||
characters. */
|
||||
int
|
||||
char_to_utf (char *buf, int char_val)
|
||||
{
|
||||
if (charmap_data.mb_cur_max == 1)
|
||||
{
|
||||
*buf++ = char_val;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The number of bits coded in each character. */
|
||||
#define CBPC 6
|
||||
static struct coding_tab
|
||||
{
|
||||
int mask;
|
||||
int val;
|
||||
}
|
||||
tab[] =
|
||||
{
|
||||
{ 0x7f, 0x00 },
|
||||
{ 0x7ff, 0xc0 },
|
||||
{ 0xffff, 0xe0 },
|
||||
{ 0x1fffff, 0xf0 },
|
||||
{ 0x3ffffff, 0xf8 },
|
||||
{ 0x7fffffff, 0xfc },
|
||||
{ 0, }
|
||||
};
|
||||
struct coding_tab *t;
|
||||
int c;
|
||||
int cnt = 1;
|
||||
|
||||
for (t = tab; char_val > t->mask; ++t, ++cnt)
|
||||
;
|
||||
|
||||
c = cnt;
|
||||
|
||||
buf += cnt;
|
||||
while (c > 1)
|
||||
{
|
||||
*--buf = 0x80 | (char_val & ((1 << CBPC) - 1));
|
||||
char_val >>= CBPC;
|
||||
--c;
|
||||
}
|
||||
|
||||
*--buf = t->val | char_val;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Ignore rest of line upto ENDOFLINE token, starting with given token.
|
||||
If WARN_FLAG is set warn about any token but ENDOFLINE. */
|
||||
void
|
||||
ignore_to_eol (int token, int warn_flag)
|
||||
{
|
||||
if (token == TOK_ENDOFLINE)
|
||||
return;
|
||||
|
||||
if (LD.buf[LD.buf_ptr] != '\0' && warn_flag)
|
||||
error (0, 0, gettext ("%s:%Zd: trailing garbage at end of line"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
|
||||
while (LD.continue_line)
|
||||
{
|
||||
LD.continue_line = 0;
|
||||
|
||||
/* Increment line number counter. */
|
||||
++LD.line_no;
|
||||
|
||||
if (fgets (LD.buf, LD.bufsize, stdin) != NULL)
|
||||
{
|
||||
/* We now have to look whether this line is continued and
|
||||
whether it at all fits into our buffer. */
|
||||
int linelen = strlen (LD.buf);
|
||||
|
||||
if (linelen == LD.bufsize - 1)
|
||||
/* The did not fit into the buffer. */
|
||||
error (2, 0, gettext ("%s:%Zd: line too long; use `getconf "
|
||||
"LINE_MAX' to get the current maximum "
|
||||
"line length"), LD.filename, LD.line_no);
|
||||
|
||||
/* Remove '\n' at end of line. */
|
||||
if (LD.buf[linelen - 1] == '\n')
|
||||
--linelen;
|
||||
|
||||
if (LD.buf[linelen - 1] == LD.escape_char)
|
||||
LD.continue_line = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* This causes to begin the next line. */
|
||||
LD.buf_ptr = LD.bufsize;
|
||||
}
|
||||
|
||||
|
||||
/* Return the value of the character at the beginning of the input buffer.
|
||||
Symbolic character constants are expanded. */
|
||||
static int
|
||||
get_char (void)
|
||||
{
|
||||
if (LD.buf[LD.buf_ptr] == '<')
|
||||
/* This is a symbolic character name. */
|
||||
{
|
||||
int char_val;
|
||||
char *startp = LD.buf + (++LD.buf_ptr);
|
||||
char *endp = startp;
|
||||
|
||||
while (LD.buf[LD.buf_ptr] != '>' && isprint (LD.buf[LD.buf_ptr]))
|
||||
{
|
||||
if (LD.buf[LD.buf_ptr] == '\0'
|
||||
|| (LD.buf[LD.buf_ptr] == LD.escape_char
|
||||
&& LD.buf[++LD.buf_ptr] == '\0'))
|
||||
break;
|
||||
|
||||
*endp++ = LD.buf[LD.buf_ptr++];
|
||||
}
|
||||
|
||||
if (LD.buf[LD.buf_ptr] != '>' && LD.buf[LD.buf_ptr] == '\0')
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: end of line in character symbol"),
|
||||
LD.filename, LD.line_no);
|
||||
|
||||
if (startp == endp)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
++LD.buf_ptr;
|
||||
|
||||
char_val = find_char (startp, endp - startp);
|
||||
if (char_val == -1 && verbose != 0 && reject_new_char != 0)
|
||||
{
|
||||
/* Locale defintions are often given very general. Missing
|
||||
characters are only reported when explicitely requested. */
|
||||
char tmp[endp - startp + 3];
|
||||
|
||||
tmp[0] = '<';
|
||||
memcpy (tmp + 1, startp, endp - startp);
|
||||
tmp[endp - startp + 1] = '>';
|
||||
tmp[endp - startp + 2] = '\0';
|
||||
|
||||
error (0, 0, gettext ("%s:%Zd: character `%s' not defined"),
|
||||
LD.filename, LD.line_no, tmp);
|
||||
}
|
||||
|
||||
return char_val;
|
||||
}
|
||||
else
|
||||
return (int) LD.buf[LD.buf_ptr++];
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
820
locale/locfile-parse.c
Normal file
820
locale/locfile-parse.c
Normal file
|
@ -0,0 +1,820 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <limits.h>
|
||||
#include <obstack.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "localedef.h"
|
||||
#include "localeinfo.h"
|
||||
#include "token.h"
|
||||
|
||||
/* We don't have these constants defined because we don't use them. Give
|
||||
default values. */
|
||||
#define CTYPE_MB_CUR_MIN 0
|
||||
#define CTYPE_MB_CUR_MAX 0
|
||||
#define CTYPE_HASH_SIZE 0
|
||||
#define CTYPE_HASH_LAYERS 0
|
||||
#define CTYPE_CLASS 0
|
||||
#define CTYPE_TOUPPER_EB 0
|
||||
#define CTYPE_TOLOWER_EB 0
|
||||
#define CTYPE_TOUPPER_EL 0
|
||||
#define CTYPE_TOLOWER_EL 0
|
||||
|
||||
|
||||
/* We have all categories defined in `categories.def'. Now construct
|
||||
the description and data structure used for all categories. */
|
||||
#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
|
||||
struct cat_item category##_desc[] = \
|
||||
{ \
|
||||
NO_PAREN items \
|
||||
}; \
|
||||
\
|
||||
char *category##_values[NELEMS (category##_desc) - 1] = { NULL, };
|
||||
#include "categories.def"
|
||||
#undef DEFINE_CATEGORY
|
||||
|
||||
struct category category[] =
|
||||
{
|
||||
#define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \
|
||||
[category] = { _NL_NUM_##category, name, NELEMS (category##_desc) - 1, \
|
||||
category##_desc, category##_values, in, check, out },
|
||||
#include "categories.def"
|
||||
#undef DEFINE_CATEGORY
|
||||
};
|
||||
#define NCATEGORIES NELEMS (category)
|
||||
|
||||
|
||||
#define SYNTAX_ERROR \
|
||||
error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
|
||||
locfile_data.filename, locfile_data.line_no)
|
||||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static int get_byte (char *byte_ptr);
|
||||
static char *is_locale_name (int cat_no, const char *str, int len);
|
||||
|
||||
|
||||
/* Read a locale definition file FILE. The format is defined in
|
||||
POSIX.2 2.5.3. */
|
||||
void
|
||||
locfile_read (const char *fname)
|
||||
{
|
||||
/* Pointer to text of last token. */
|
||||
char *ptr;
|
||||
/* Length of last token (or if NUMBER the value itself). */
|
||||
int len;
|
||||
/* The last returned token. */
|
||||
int token;
|
||||
/* For error correction we remember whether the last token was correct. */
|
||||
int correct_token = 1;
|
||||
|
||||
/* Open the desired input file on stdin. */
|
||||
locfile_open (fname);
|
||||
|
||||
while ((token = locfile_lex (&ptr, &len)) != 0)
|
||||
{
|
||||
int cat_no;
|
||||
|
||||
for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
|
||||
if (token == category[cat_no].cat_id)
|
||||
break;
|
||||
|
||||
if (cat_no >= NCATEGORIES)
|
||||
/* A syntax error occured. No valid category defintion starts. */
|
||||
{
|
||||
if (correct_token != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: locale category start expected"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
|
||||
/* To prevent following errors mark as error case. */
|
||||
correct_token = 0;
|
||||
|
||||
/* Synchronization point is the beginning of a new category.
|
||||
Overread all line upto this silently. */
|
||||
ignore_to_eol (0, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Rest of the line should be empty. */
|
||||
ignore_to_eol (0, 1);
|
||||
|
||||
/* Perhaps these category is already specified. We simply give a
|
||||
warning and overwrite the values. */
|
||||
if (category[cat_no].filled != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: multiple definition of locale "
|
||||
"category %s"), locfile_data.filename,
|
||||
locfile_data.line_no, category[cat_no].name);
|
||||
|
||||
/* We read the first token because this could be the copy statement. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token == TOK_COPY)
|
||||
/* Copying the definitions from an existing locale is requested. */
|
||||
{
|
||||
char *str;
|
||||
|
||||
/* Get the name of the locale to copy from. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_IDENT && token != TOK_STRING)
|
||||
/* No name, then mark error and ignore everything upto next
|
||||
start of an category section. */
|
||||
{
|
||||
/* To prevent following errors mark as error case. */
|
||||
correct_token = 0;
|
||||
|
||||
/* Synchronization point is the beginning of a new category.
|
||||
Overread all line upto this silently. */
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
else if ((str = is_locale_name (cat_no, ptr, len)) != NULL)
|
||||
/* Yes the name really names an existing locale file. We are
|
||||
returned the complete file name. Store it so that we can
|
||||
copy it in the output phase. */
|
||||
{
|
||||
category[cat_no].copy_locale = str;
|
||||
category[cat_no].filled = 1;
|
||||
|
||||
ignore_to_eol (0, 1);
|
||||
}
|
||||
else
|
||||
/* No, the name does not address a valid locale file. Mark
|
||||
error case and ignore rest of category. */
|
||||
{
|
||||
char tmp[len + 1];
|
||||
memcpy (tmp, ptr, len);
|
||||
tmp[len] = '\0';
|
||||
error (0, 0, gettext ("%s:%Zd: invalid locale `%s' in copy "
|
||||
"statement"), locfile_data.filename,
|
||||
locfile_data.line_no, tmp);
|
||||
correct_token = 0;
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
|
||||
/* This should END as the next token. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token == TOK_END)
|
||||
/* This is the end of the category. */
|
||||
{
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token != category[cat_no].cat_id)
|
||||
/* Wrong category name after END. */
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: category `%s' does not "
|
||||
"end with `END %s'"),
|
||||
locfile_data.filename, locfile_data.line_no,
|
||||
category[cat_no].name, category[cat_no].name);
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
else
|
||||
ignore_to_eol (0, 1);
|
||||
|
||||
correct_token = 1;
|
||||
}
|
||||
else
|
||||
/* No END following copy. Give error while not in error case. */
|
||||
{
|
||||
if (correct_token != 0)
|
||||
error (0, 0, gettext ("%s:%Zd: `copy' must be sole rule"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
correct_token = 0;
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now it's time to mark as mentioned in the locale file. */
|
||||
category[cat_no].filled = 1;
|
||||
|
||||
if (category[cat_no].infct != NULL)
|
||||
/* The category needs a special input handling. */
|
||||
{
|
||||
category[cat_no].infct(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Now process the given items. */
|
||||
while (1)
|
||||
{
|
||||
int item_no;
|
||||
|
||||
if (token == TOK_END)
|
||||
/* This is the end of the category. */
|
||||
{
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token != category[cat_no].cat_id)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: category `%s' does not end "
|
||||
"with `END %s'"),
|
||||
locfile_data.filename, locfile_data.line_no,
|
||||
category[cat_no].name, category[cat_no].name);
|
||||
ignore_to_eol (0, 0);
|
||||
}
|
||||
else
|
||||
ignore_to_eol (0, 1);
|
||||
|
||||
/* Start next category. */
|
||||
break;
|
||||
}
|
||||
|
||||
/* All other lines should describe valid items of the category. */
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
if (category[cat_no].item_desc[item_no].item_id == token)
|
||||
break;
|
||||
|
||||
if (item_no >= category[cat_no].number)
|
||||
/* This is not a valid item of the category. */
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
ignore_to_eol (0, 0);
|
||||
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
/* And process next item. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Test whether already a value is defined. */
|
||||
if (category[cat_no].item_value[item_no] != NULL)
|
||||
error (0, 0, gettext ("%s:%Zd: category item `%s' already "
|
||||
"defined"),
|
||||
locfile_data.filename, locfile_data.line_no,
|
||||
category[cat_no].item_desc[item_no].name);
|
||||
|
||||
switch (category[cat_no].item_desc[item_no].value_type)
|
||||
{
|
||||
case string:
|
||||
/* Get next token. This is the argument to the item. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
|
||||
if (token != TOK_STRING)
|
||||
SYNTAX_ERROR;
|
||||
else
|
||||
category[cat_no].item_value[item_no] = strdup (ptr);
|
||||
ignore_to_eol (0, ptr != NULL);
|
||||
break;
|
||||
case stringarray:
|
||||
/* This is a difficult case. The number of strings in
|
||||
the array may vary. But for now its only necessary
|
||||
with ALT_DIGITS from LC_TIME. This item is the last
|
||||
so be can solve it by storing the number of string in
|
||||
the first place and the string indeces following
|
||||
that. */
|
||||
{
|
||||
int cnt;
|
||||
char **buffer;
|
||||
if (category[cat_no].item_value[item_no] != NULL)
|
||||
buffer = (char **) category[cat_no].item_value[item_no];
|
||||
else
|
||||
buffer = (char **) xmalloc (
|
||||
sizeof (char *) * category[cat_no].item_desc[item_no].max);
|
||||
|
||||
category[cat_no].item_value[item_no] = (char *) buffer;
|
||||
|
||||
/* As explained we may need a place to store the real number
|
||||
of strings. */
|
||||
if (category[cat_no].item_desc[item_no].min
|
||||
!= category[cat_no].item_desc[item_no].max)
|
||||
++buffer;
|
||||
|
||||
cnt = 0;
|
||||
do
|
||||
{
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
if (token != TOK_STRING)
|
||||
{
|
||||
SYNTAX_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cnt >= category[cat_no].item_desc[item_no].max)
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: too many elements "
|
||||
"for item `%s`"),
|
||||
locfile_data.filename, locfile_data.line_no,
|
||||
category[cat_no].item_desc[item_no].name);
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[cnt++] = strdup (ptr);
|
||||
|
||||
token = locfile_lex (&ptr, &len);
|
||||
}
|
||||
while (token == TOK_CHAR && len == ';');
|
||||
|
||||
ignore_to_eol (token, ptr != NULL);
|
||||
|
||||
if (cnt < category[cat_no].item_desc[item_no].min)
|
||||
error (0, 0, gettext ("%s:%Zd: too few elements for item "
|
||||
"`%s'"),
|
||||
locfile_data.filename, locfile_data.line_no,
|
||||
category[cat_no].item_desc[item_no].name);
|
||||
|
||||
if (category[cat_no].item_desc[item_no].min
|
||||
!= category[cat_no].item_desc[item_no].max)
|
||||
*(int *) category[cat_no].item_value[item_no] = cnt;
|
||||
}
|
||||
break;
|
||||
case byte:
|
||||
{
|
||||
int ok;
|
||||
category[cat_no].item_value[item_no] = (char *) xmalloc (
|
||||
__alignof__ (char));
|
||||
ok = get_byte (category[cat_no].item_value[item_no]);
|
||||
ignore_to_eol (0, ok);
|
||||
}
|
||||
break;
|
||||
case bytearray:
|
||||
{
|
||||
char *buffer;
|
||||
int maxsize;
|
||||
int cnt;
|
||||
char byte;
|
||||
int ok;
|
||||
|
||||
buffer = (char *) xmalloc ((maxsize = 30));
|
||||
cnt = 0;
|
||||
|
||||
while ((ok = get_byte (&byte)))
|
||||
{
|
||||
if (cnt >= maxsize)
|
||||
buffer = (char *) xmalloc ((maxsize *= 2));
|
||||
|
||||
buffer[cnt++] = byte;
|
||||
|
||||
token = locfile_lex (&ptr, &len);
|
||||
if (token != TOK_CHAR || len != ';')
|
||||
break;
|
||||
}
|
||||
|
||||
buffer[cnt] = '\0';
|
||||
category[cat_no].item_value[item_no] = buffer;
|
||||
ignore_to_eol (token, ok);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error (5, 0, gettext ("internal error in %s, line %u"),
|
||||
__FUNCTION__, __LINE__);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Get next token. */
|
||||
token = xlocfile_lex (&ptr, &len);
|
||||
} /* while (1) */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check given values for categories for consistency. */
|
||||
void
|
||||
categories_check (void)
|
||||
{
|
||||
int cat_no;
|
||||
|
||||
for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
|
||||
if (category[cat_no].copy_locale == NULL)
|
||||
if (category[cat_no].filled != 0)
|
||||
if (category[cat_no].checkfct)
|
||||
category[cat_no].checkfct();
|
||||
else
|
||||
{
|
||||
int item_no;
|
||||
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
if (category[cat_no].item_value[item_no] == NULL)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
/* If the item is defined in the standard is it an error to
|
||||
have it not defined. */
|
||||
errcode = category[cat_no].item_desc[item_no].status == std
|
||||
? 5 : 0;
|
||||
|
||||
error (errcode, 0, gettext ("item `%s' of category `%s' "
|
||||
"undefined"),
|
||||
category[cat_no].item_desc[item_no].name,
|
||||
category[cat_no].name);
|
||||
}
|
||||
}
|
||||
else
|
||||
error (0, 0, gettext ("category `%s' not defined"),
|
||||
category[cat_no].name);
|
||||
}
|
||||
|
||||
|
||||
/* Write out the binary representation of the category data which can be
|
||||
loaded by setlocale(1). */
|
||||
void
|
||||
categories_write (void)
|
||||
{
|
||||
struct locale_file
|
||||
{
|
||||
int magic;
|
||||
int n;
|
||||
int idx[0];
|
||||
} *data;
|
||||
struct obstack obstk;
|
||||
int cat_no;
|
||||
|
||||
#define obstack_chunk_alloc xmalloc
|
||||
#define obstack_chunk_free free
|
||||
obstack_init (&obstk);
|
||||
|
||||
for (cat_no = 0; cat_no < NCATEGORIES; ++cat_no)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (category[cat_no].copy_locale != NULL)
|
||||
/* Simply copy the addressed locale file of the specified
|
||||
category. Please note that this is tried before the distinction
|
||||
between categories which need special handling is made. */
|
||||
{
|
||||
int source;
|
||||
|
||||
/* Open source file. */
|
||||
source = open (category[cat_no].copy_locale, O_RDONLY);
|
||||
if (source < 0)
|
||||
error (0, 0, gettext ("cannot copy locale definition file `%s'"),
|
||||
category[cat_no].copy_locale);
|
||||
else
|
||||
{
|
||||
/* Construct file name of output file and open for writing. */
|
||||
char path[strlen (output_path)
|
||||
+ strlen(category[cat_no].name) + 1];
|
||||
int dest;
|
||||
char *t;
|
||||
|
||||
t = stpcpy (path, output_path);
|
||||
strcpy (t, category[cat_no].name);
|
||||
|
||||
dest = creat (path, 0666);
|
||||
if (dest == -1)
|
||||
error (0, 0, gettext ("cannot open output file `%s': %m"),
|
||||
path);
|
||||
else
|
||||
{
|
||||
char buffer[BUFSIZ];
|
||||
int size;
|
||||
|
||||
/* Copy the files. */
|
||||
do
|
||||
{
|
||||
size = read (source, buffer, BUFSIZ);
|
||||
write (dest, buffer, size);
|
||||
}
|
||||
while (size > 0);
|
||||
|
||||
close (dest);
|
||||
|
||||
/* Show success. */
|
||||
puts (category[cat_no].name);
|
||||
}
|
||||
close (source);
|
||||
}
|
||||
|
||||
/* Next category. */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (category[cat_no].outfct)
|
||||
result = category[cat_no].outfct();
|
||||
else
|
||||
{
|
||||
char *path, *t;
|
||||
int fd;
|
||||
struct iovec *iov;
|
||||
int item_no, len, slen, cnt;
|
||||
int elems = 0;
|
||||
|
||||
/* Count number of elements. */
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
{
|
||||
switch (category[cat_no].item_desc[item_no].value_type)
|
||||
{
|
||||
case string:
|
||||
case byte:
|
||||
case bytearray:
|
||||
++elems;
|
||||
break;
|
||||
case stringarray:
|
||||
elems += category[cat_no].item_desc[item_no].max;
|
||||
break;
|
||||
default:
|
||||
error (5, 0, gettext ("internal error in %s, line %u"),
|
||||
__FUNCTION__, __LINE__);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
/* We now have the number of elements. We build the structure
|
||||
and a helper structure for writing all out. */
|
||||
len = sizeof (struct locale_file) + elems * sizeof (int);
|
||||
data = obstack_alloc (&obstk, len);
|
||||
iov = obstack_alloc (&obstk, (elems + 1) * sizeof (struct iovec));
|
||||
|
||||
data->magic = LIMAGIC (cat_no);
|
||||
data->n = elems;
|
||||
iov[0].iov_base = data;
|
||||
iov[0].iov_len = len;
|
||||
|
||||
cnt = 0;
|
||||
for (item_no = 0; item_no < category[cat_no].number; ++item_no)
|
||||
if (category[cat_no].item_value[item_no] == NULL)
|
||||
{
|
||||
switch (category[cat_no].item_desc[item_no].value_type)
|
||||
{
|
||||
case string:
|
||||
case byte:
|
||||
case bytearray:
|
||||
data->idx[cnt] = len;
|
||||
++len; /* We reserve one single byte for this entry. */
|
||||
iov[1 + cnt].iov_base = (char *) "";
|
||||
iov[1 + cnt].iov_len = 1;
|
||||
++cnt;
|
||||
break;
|
||||
case stringarray:
|
||||
{
|
||||
int max;
|
||||
int nstr;
|
||||
|
||||
max = category[cat_no].item_desc[item_no].max;
|
||||
|
||||
for (nstr = 0; nstr < max; ++nstr)
|
||||
{
|
||||
data->idx[cnt] = len;
|
||||
++len;
|
||||
iov[1 + cnt].iov_base = (char *) "";
|
||||
iov[1 + cnt].iov_len = 1;
|
||||
++cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
switch (category[cat_no].item_desc[item_no].value_type)
|
||||
{
|
||||
case string:
|
||||
case bytearray:
|
||||
data->idx[cnt] = len;
|
||||
slen = strlen (category[cat_no].item_value[item_no]) + 1;
|
||||
len += slen;
|
||||
iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
|
||||
iov[1 + cnt].iov_len = slen;
|
||||
++cnt;
|
||||
break;
|
||||
case byte:
|
||||
data->idx[cnt] = len;
|
||||
slen = 1;
|
||||
len += slen;
|
||||
iov[1 + cnt].iov_base = category[cat_no].item_value[item_no];
|
||||
iov[1 + cnt].iov_len = slen;
|
||||
++cnt;
|
||||
break;
|
||||
case stringarray:
|
||||
{
|
||||
int nstr, nact;
|
||||
char **first;
|
||||
|
||||
if (category[cat_no].item_desc[item_no].min
|
||||
== category[cat_no].item_desc[item_no].max)
|
||||
{
|
||||
nstr = category[cat_no].item_desc[item_no].min;
|
||||
first = (char **) category[cat_no].item_value[item_no];
|
||||
}
|
||||
else
|
||||
{
|
||||
nstr = *(int *) category[cat_no].item_value[item_no];
|
||||
first =
|
||||
((char **) category[cat_no].item_value[item_no]) + 1;
|
||||
}
|
||||
nact = nstr;
|
||||
while (nstr > 0)
|
||||
{
|
||||
data->idx[cnt] = len;
|
||||
if (*first != NULL)
|
||||
{
|
||||
slen = strlen (*first) + 1;
|
||||
iov[1 + cnt].iov_base = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
slen = 1;
|
||||
iov[1 + cnt].iov_base = (char *) "";
|
||||
}
|
||||
len += slen;
|
||||
iov[1 + cnt].iov_len = slen;
|
||||
++cnt;
|
||||
++first;
|
||||
--nstr;
|
||||
}
|
||||
while (nact < category[cat_no].item_desc[item_no].max)
|
||||
{
|
||||
data->idx[cnt] = len;
|
||||
len += 1;
|
||||
iov[1 + cnt].iov_base = (char *) "";
|
||||
iov[1 + cnt].iov_len = 1;
|
||||
++cnt;
|
||||
++nact;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Cannot happen. */
|
||||
break;
|
||||
}
|
||||
assert (cnt <= elems);
|
||||
|
||||
/* Construct the output filename from the argument given to
|
||||
localedef on the command line. */
|
||||
path = (char *) obstack_alloc (&obstk, strlen (output_path) +
|
||||
strlen (category[cat_no].name) + 1);
|
||||
t = stpcpy (path, output_path);
|
||||
strcpy (t, category[cat_no].name);
|
||||
|
||||
fd = creat (path, 0666);
|
||||
if (fd == -1)
|
||||
{
|
||||
error (0, 0, gettext ("cannot open output file `%s': %m"), path);
|
||||
result = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (writev (fd, iov, cnt + 1) == -1)
|
||||
{
|
||||
error (0, 0, gettext ("cannot write output file `%s': %m"),
|
||||
path);
|
||||
result = 1;
|
||||
}
|
||||
|
||||
if (elems==0) write(fd, &elems, 1);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
/* The old data is not needed anymore, but keep the obstack
|
||||
intact. */
|
||||
obstack_free (&obstk, data);
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
puts (category[cat_no].name);
|
||||
}
|
||||
/* Now the whole obstack can be removed. */
|
||||
obstack_free (&obstk, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Get the representation of a number. This is a positive integer or
|
||||
the number -1 which is handled as a special symbol by the scanner. */
|
||||
static int
|
||||
get_byte (char *byte_ptr)
|
||||
{
|
||||
int token;
|
||||
char *ptr;
|
||||
int len;
|
||||
|
||||
token = locfile_lex (&ptr, &len);
|
||||
if (token != TOK_NUMBER && token != TOK_MINUS1)
|
||||
/* None of the valid number format. */
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: number expected"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
*byte_ptr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (token == TOK_MINUS1)
|
||||
{
|
||||
*byte_ptr = CHAR_MAX;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (len > CHAR_MAX)
|
||||
/* The value of the numbers has to be less than CHAR_MAX. This is
|
||||
ok for the information they have to express. */
|
||||
{
|
||||
error (0, 0, gettext ("%s:%Zd: invalid number"),
|
||||
locfile_data.filename, locfile_data.line_no);
|
||||
*byte_ptr = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*byte_ptr = len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Test whether the string STR with length LEN is the name of an existing
|
||||
locale and whether a file for category CAT_NO is found in this directory.
|
||||
This categories are looked for in the system locale definition file
|
||||
directory.
|
||||
Return the complete file name for the category file. */
|
||||
static char *
|
||||
is_locale_name (int cat_no, const char *str, int len)
|
||||
{
|
||||
static char **locale_names = NULL;
|
||||
static int max_count = 0;
|
||||
static int locale_count = 0;
|
||||
int cnt, exist, fd;
|
||||
char *fname;
|
||||
struct stat st;
|
||||
|
||||
if (locale_names == NULL)
|
||||
/* Read in the list of all available locales. */
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dirent;
|
||||
|
||||
/* LOCALE_NAMES is not NULL anymore, but LOCALE_COUNT == 0. */
|
||||
++locale_names;
|
||||
|
||||
dir = opendir (LOCALE_PATH);
|
||||
if (dir == NULL)
|
||||
{
|
||||
error (1, errno, gettext ("cannot read locale directory `%s'"),
|
||||
LOCALE_PATH);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now we can look for all files in the directory. */
|
||||
while ((dirent = readdir (dir)) != NULL)
|
||||
if (strcmp (dirent->d_name, ".") != 0
|
||||
&& strcmp (dirent->d_name, "..") != 0)
|
||||
{
|
||||
if (max_count == 0)
|
||||
locale_names = (char **) xmalloc ((max_count = 10)
|
||||
* sizeof (char *));
|
||||
else
|
||||
locale_names = (char **) xrealloc (locale_names,
|
||||
(max_count *= 2)
|
||||
* sizeof (char *));
|
||||
locale_names[locale_count++] = strdup (dirent->d_name);
|
||||
}
|
||||
closedir (dir);
|
||||
}
|
||||
|
||||
for (cnt = 0; cnt < locale_count; ++cnt)
|
||||
if (strncmp (str, locale_names[cnt], len) == 0
|
||||
&& locale_names[cnt][len] == '\0')
|
||||
break;
|
||||
|
||||
if (cnt >= locale_count)
|
||||
return NULL;
|
||||
|
||||
/* Now search for this specific locale file. */
|
||||
asprintf (&fname, "%s/%s/%s", LOCALE_PATH, locale_names[cnt],
|
||||
category[cat_no].name);
|
||||
|
||||
fd = open (fname, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
free (fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
exist = fstat (fd, &st);
|
||||
close (fd);
|
||||
|
||||
if (exist < 0)
|
||||
{
|
||||
free (fname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
76
locale/messages.c
Normal file
76
locale/messages.c
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include "localedef.h"
|
||||
|
||||
/* These are defined in locfile-parse.c. */
|
||||
extern struct cat_item LC_MESSAGES_desc[];
|
||||
extern char *LC_MESSAGES_values[];
|
||||
|
||||
void
|
||||
messages_check(void)
|
||||
{
|
||||
int item_no;
|
||||
|
||||
/* First general check for existence. */
|
||||
for (item_no = 0; item_no < category[LC_MESSAGES].number; ++item_no)
|
||||
if (LC_MESSAGES_values[item_no] == NULL)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = LC_MESSAGES_desc[item_no].status == std ? 5 : 0;
|
||||
|
||||
error (errcode, 0, gettext ("item `%s' of category `%s' undefined"),
|
||||
LC_MESSAGES_desc[item_no].name, "LC_MESSAGES");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Some fields need special tests. */
|
||||
if (LC_MESSAGES_desc[item_no].item_id == YESEXPR
|
||||
|| LC_MESSAGES_desc[item_no].item_id == NOEXPR)
|
||||
/* The expression has to be a POSIX extended regular expression. */
|
||||
{
|
||||
regex_t re;
|
||||
int result;
|
||||
|
||||
result = regcomp (&re, LC_MESSAGES_values[item_no], REG_EXTENDED);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
char errbuf[BUFSIZ];
|
||||
|
||||
(void) regerror (result, &re, errbuf, BUFSIZ);
|
||||
error (0, 0, gettext ("no correct regular expression for "
|
||||
"item `%s' in category `%s': %s"),
|
||||
LC_MESSAGES_desc[item_no].name, "LC_MESSAGES", errbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
132
locale/monetary.c
Normal file
132
locale/monetary.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "localedef.h"
|
||||
#include "token.h"
|
||||
|
||||
|
||||
/* The content iof the field int_curr_symbol has to be taken from
|
||||
ISO-4217. We test for correct values. */
|
||||
#define DEFINE_INT_CURR(str) str,
|
||||
static const char *const valid_int_curr[] =
|
||||
{
|
||||
# include "iso-4217.def"
|
||||
};
|
||||
#define NVALID_INT_CURR ((sizeof (valid_int_curr) \
|
||||
/ sizeof (valid_int_curr[0])))
|
||||
#undef DEFINE_INT_CURR
|
||||
|
||||
|
||||
/* These are defined in locfile-parse.c. */
|
||||
extern struct cat_item LC_MONETARY_desc[];
|
||||
extern char *LC_MONETARY_values[];
|
||||
|
||||
static int _curr_strcmp(const char *s1, const char **s2);
|
||||
|
||||
|
||||
|
||||
void
|
||||
monetary_check(void)
|
||||
{
|
||||
int item_no, val;
|
||||
|
||||
for (item_no = 0; LC_MONETARY_desc[item_no].item_id != 0; ++item_no)
|
||||
/* Test whether the entry has been defined. Byte values are simply
|
||||
stored. */
|
||||
if (LC_MONETARY_values[item_no] == NULL)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = LC_MONETARY_desc[item_no].status = std ? 5 : 0;
|
||||
|
||||
error (errcode, 0, gettext ("item `%s' of category `%s' undefined"),
|
||||
LC_MONETARY_desc[item_no].name, "LC_MONETARY");
|
||||
}
|
||||
else
|
||||
switch (LC_MONETARY_desc[item_no].item_id)
|
||||
{
|
||||
case INT_CURR_SYMBOL:
|
||||
if (strlen (LC_MONETARY_values[item_no]) != 4)
|
||||
error (0, 0,
|
||||
gettext ("item `%s' of category `%s' has wrong length"),
|
||||
LC_MONETARY_desc[item_no].name, "LC_MONETARY");
|
||||
else if (bsearch (LC_MONETARY_values[item_no], valid_int_curr,
|
||||
NVALID_INT_CURR, sizeof (char *),
|
||||
(comparison_fn_t) _curr_strcmp) == NULL)
|
||||
error (0, 0, gettext ("item `%s' does not correspond to any "
|
||||
"valid name in ISO-4217"),
|
||||
LC_MONETARY_desc[item_no].name);
|
||||
break;
|
||||
case P_CS_PRECEDES:
|
||||
case P_SEP_BY_SPACE:
|
||||
case N_CS_PRECEDES:
|
||||
case N_SEP_BY_SPACE:
|
||||
case P_SIGN_POSN:
|
||||
case N_SIGN_POSN:
|
||||
val = (int) *(char *) LC_MONETARY_values[item_no];
|
||||
if (val < LC_MONETARY_desc[item_no].min
|
||||
|| val > LC_MONETARY_desc[item_no].max)
|
||||
error (0, 0, gettext ("value for item `%s' in category `%s' "
|
||||
"must be in range %d...%d"),
|
||||
LC_MONETARY_desc[item_no].name, "LC_MONETARY",
|
||||
LC_MONETARY_desc[item_no].min,
|
||||
LC_MONETARY_desc[item_no].max);
|
||||
break;
|
||||
case MON_DECIMAL_POINT:
|
||||
/* The decimal point must not be empty. This is not said
|
||||
explicitly in POSIX but ANSI C (ISO/IEC 9899) says in
|
||||
4.4.2.1 it has to be != "". */
|
||||
if (LC_MONETARY_values[item_no][0] == '\0')
|
||||
error (0, 0,
|
||||
gettext ("item `%s' in category `%s' must not be empty"),
|
||||
LC_MONETARY_desc[item_no].name, "LC_MONETARY");
|
||||
break;
|
||||
case CURRENCY_SYMBOL:
|
||||
case MON_THOUSANDS_SEP:
|
||||
case MON_GROUPING:
|
||||
case POSITIVE_SIGN:
|
||||
case NEGATIVE_SIGN:
|
||||
case INT_FRAC_DIGITS:
|
||||
case FRAC_DIGITS:
|
||||
/* Everything is ok for these values. */
|
||||
break;
|
||||
default:
|
||||
error (5, 0, gettext ("Internal error in %s, line %u"),
|
||||
__FUNCTION__, __LINE__);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_curr_strcmp(const char *s1, const char **s2)
|
||||
{
|
||||
return strcmp (s1, *s2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
62
locale/numeric.c
Normal file
62
locale/numeric.c
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <langinfo.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
|
||||
#include "localedef.h"
|
||||
|
||||
/* These are defined in locfile-parse.c. */
|
||||
extern struct cat_item LC_NUMERIC_desc[];
|
||||
extern char *LC_NUMERIC_values[];
|
||||
|
||||
void
|
||||
numeric_check(void)
|
||||
{
|
||||
int item_no;
|
||||
|
||||
/* First general check for existence. */
|
||||
for (item_no = 0; item_no < category[LC_NUMERIC].number; ++item_no)
|
||||
if (LC_NUMERIC_values[item_no] == NULL)
|
||||
{
|
||||
int errcode;
|
||||
|
||||
errcode = LC_NUMERIC_desc[item_no].status = std ? 5 : 0;
|
||||
|
||||
error (errcode, 0, gettext ("item `%s' of category `%s' undefined"),
|
||||
LC_NUMERIC_desc[item_no].name, "LC_NUMERIC");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LC_NUMERIC_desc[item_no].item_id == DECIMAL_POINT
|
||||
&& LC_NUMERIC_values[item_no][0] == '\0')
|
||||
/* The decimal point must not be empty. This is not said
|
||||
explicitly in POSIX but ANSI C (ISO/IEC 9899) says in
|
||||
4.4.2.1 it has to be != "". */
|
||||
error (0, 0,
|
||||
gettext ("item `%s' in category `%s' must not be empty"),
|
||||
LC_NUMERIC_desc[item_no].name, "LC_NUMERIC");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
54
locale/token.h
Normal file
54
locale/token.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
/* Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef _TOKEN_H
|
||||
#define _TOKEN_H 1
|
||||
|
||||
/* Define those keywords which does not correspond directly to any
|
||||
item in a category. Those already have values. */
|
||||
|
||||
enum token
|
||||
{
|
||||
/* We must make sure that these values do not overlap with the
|
||||
other possible return values of the lexer. */
|
||||
TOK_LAST_USED = _NL_NUM,
|
||||
|
||||
/* General tokens. */
|
||||
TOK_END, TOK_COMMENT_CHAR, TOK_COPY, TOK_ESCAPE_CHAR, TOK_FROM,
|
||||
TOK_ENDOFLINE, TOK_IDENT, TOK_STRING, TOK_ELLIPSIS, TOK_CHAR,
|
||||
TOK_ILL_CHAR, TOK_NUMBER, TOK_MINUS1,
|
||||
|
||||
/* Tokens from the collate category. */
|
||||
TOK_IGNORE, TOK_UNDEFINED, TOK_BACKWARD, TOK_FORWARD, TOK_POSITION,
|
||||
TOK_COLLATING_ELEMENT, TOK_COLLATING_SYMBOL, TOK_ORDER_END,
|
||||
TOK_ORDER_START,
|
||||
|
||||
/* Tokens from the ctype category. */
|
||||
TOK_TOLOWER, TOK_TOUPPER,
|
||||
/* The order here is important. It must correspond to the bits
|
||||
used for indicating the class membership (ctype.h). */
|
||||
TOK_UPPER, TOK_LOWER, TOK_ALPHA, TOK_DIGIT, TOK_XDIGIT, TOK_SPACE,
|
||||
TOK_PRINT, TOK_GRAPH, TOK_BLANK, TOK_CNTRL, TOK_PUNCT,
|
||||
};
|
||||
|
||||
/*
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
* c-basic-offset:2
|
||||
* End:
|
||||
*/
|
||||
#endif /* token.h */
|
|
@ -22,7 +22,7 @@
|
|||
subdir := posix
|
||||
|
||||
headers := sys/utsname.h sys/times.h sys/wait.h sys/types.h unistd.h \
|
||||
glob.h wordexp.h fnmatch.h gnu/types.h getopt.h \
|
||||
glob.h regex.h wordexp.h fnmatch.h gnu/types.h getopt.h \
|
||||
posix1_lim.h posix2_lim.h posix_opt.h local_lim.h tar.h \
|
||||
utsnamelen.h confname.h waitflags.h waitstatus.h sys/unistd.h
|
||||
|
||||
|
@ -40,7 +40,7 @@ routines := \
|
|||
getpgid setpgid getpgrp setsid \
|
||||
getlogin setlogin \
|
||||
pathconf sysconf fpathconf \
|
||||
glob fnmatch \
|
||||
glob fnmatch regex \
|
||||
confstr \
|
||||
getopt getopt1
|
||||
aux := init-posix environ
|
||||
|
@ -48,7 +48,7 @@ tests := tstgetopt testfnm
|
|||
others := getconf
|
||||
install-bin := getconf
|
||||
install-lib := libposix.a
|
||||
gpl2lgpl := getopt.c getopt1.c getopt.h # Frob these guys' copying notices.
|
||||
gpl2lgpl := getopt.c getopt1.c getopt.h regex.c regex.h
|
||||
|
||||
include ../Rules
|
||||
|
||||
|
|
5400
posix/regex.c
Normal file
5400
posix/regex.c
Normal file
File diff suppressed because it is too large
Load diff
495
posix/regex.h
Normal file
495
posix/regex.h
Normal file
|
@ -0,0 +1,495 @@
|
|||
/* Definitions for data structures and routines for the regular
|
||||
expression library, version 0.12.
|
||||
|
||||
Copyright (C) 1985, 89, 90, 91, 92, 93, 95 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library. Its master source is NOT part of
|
||||
the C library, however. The master source lives in /gd/gnu/lib.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If
|
||||
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
|
||||
Cambridge, MA 02139, USA. */
|
||||
|
||||
#ifndef __REGEXP_LIBRARY_H__
|
||||
#define __REGEXP_LIBRARY_H__
|
||||
|
||||
/* POSIX says that <sys/types.h> must be included (by the caller) before
|
||||
<regex.h>. */
|
||||
|
||||
#if !defined (_POSIX_C_SOURCE) && !defined (_POSIX_SOURCE) && defined (VMS)
|
||||
/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
|
||||
should be there. */
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* The following bits are used to determine the regexp syntax we
|
||||
recognize. The set/not-set meanings are chosen so that Emacs syntax
|
||||
remains the value 0. The bits are given in alphabetical order, and
|
||||
the definitions shifted by one from the previous bit; thus, when we
|
||||
add or remove a bit, only one other definition need change. */
|
||||
typedef unsigned reg_syntax_t;
|
||||
|
||||
/* If this bit is not set, then \ inside a bracket expression is literal.
|
||||
If set, then such a \ quotes the following character. */
|
||||
#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
|
||||
|
||||
/* If this bit is not set, then + and ? are operators, and \+ and \? are
|
||||
literals.
|
||||
If set, then \+ and \? are operators and + and ? are literals. */
|
||||
#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
|
||||
|
||||
/* If this bit is set, then character classes are supported. They are:
|
||||
[:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
|
||||
[:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
|
||||
If not set, then character classes are not supported. */
|
||||
#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
|
||||
|
||||
/* If this bit is set, then ^ and $ are always anchors (outside bracket
|
||||
expressions, of course).
|
||||
If this bit is not set, then it depends:
|
||||
^ is an anchor if it is at the beginning of a regular
|
||||
expression or after an open-group or an alternation operator;
|
||||
$ is an anchor if it is at the end of a regular expression, or
|
||||
before a close-group or an alternation operator.
|
||||
|
||||
This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
|
||||
POSIX draft 11.2 says that * etc. in leading positions is undefined.
|
||||
We already implemented a previous draft which made those constructs
|
||||
invalid, though, so we haven't changed the code back. */
|
||||
#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
|
||||
|
||||
/* If this bit is set, then special characters are always special
|
||||
regardless of where they are in the pattern.
|
||||
If this bit is not set, then special characters are special only in
|
||||
some contexts; otherwise they are ordinary. Specifically,
|
||||
* + ? and intervals are only special when not after the beginning,
|
||||
open-group, or alternation operator. */
|
||||
#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
|
||||
|
||||
/* If this bit is set, then *, +, ?, and { cannot be first in an re or
|
||||
immediately after an alternation or begin-group operator. */
|
||||
#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
|
||||
|
||||
/* If this bit is set, then . matches newline.
|
||||
If not set, then it doesn't. */
|
||||
#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
|
||||
|
||||
/* If this bit is set, then . doesn't match NUL.
|
||||
If not set, then it does. */
|
||||
#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
|
||||
|
||||
/* If this bit is set, nonmatching lists [^...] do not match newline.
|
||||
If not set, they do. */
|
||||
#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
|
||||
|
||||
/* If this bit is set, either \{...\} or {...} defines an
|
||||
interval, depending on RE_NO_BK_BRACES.
|
||||
If not set, \{, \}, {, and } are literals. */
|
||||
#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
|
||||
|
||||
/* If this bit is set, +, ? and | aren't recognized as operators.
|
||||
If not set, they are. */
|
||||
#define RE_LIMITED_OPS (RE_INTERVALS << 1)
|
||||
|
||||
/* If this bit is set, newline is an alternation operator.
|
||||
If not set, newline is literal. */
|
||||
#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
|
||||
|
||||
/* If this bit is set, then `{...}' defines an interval, and \{ and \}
|
||||
are literals.
|
||||
If not set, then `\{...\}' defines an interval. */
|
||||
#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
|
||||
|
||||
/* If this bit is set, (...) defines a group, and \( and \) are literals.
|
||||
If not set, \(...\) defines a group, and ( and ) are literals. */
|
||||
#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
|
||||
|
||||
/* If this bit is set, then \<digit> matches <digit>.
|
||||
If not set, then \<digit> is a back-reference. */
|
||||
#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
|
||||
|
||||
/* If this bit is set, then | is an alternation operator, and \| is literal.
|
||||
If not set, then \| is an alternation operator, and | is literal. */
|
||||
#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
|
||||
|
||||
/* If this bit is set, then an ending range point collating higher
|
||||
than the starting range point, as in [z-a], is invalid.
|
||||
If not set, then when ending range point collates higher than the
|
||||
starting range point, the range is ignored. */
|
||||
#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
|
||||
|
||||
/* If this bit is set, then an unmatched ) is ordinary.
|
||||
If not set, then an unmatched ) is invalid. */
|
||||
#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
|
||||
|
||||
/* If this bit is set, succeed as soon as we match the whole pattern,
|
||||
without further backtracking. */
|
||||
#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
|
||||
|
||||
/* This global variable defines the particular regexp syntax to use (for
|
||||
some interfaces). When a regexp is compiled, the syntax used is
|
||||
stored in the pattern buffer, so changing this does not affect
|
||||
already-compiled regexps. */
|
||||
extern reg_syntax_t re_syntax_options;
|
||||
|
||||
/* Define combinations of the above bits for the standard possibilities.
|
||||
(The [[[ comments delimit what gets put into the Texinfo file, so
|
||||
don't delete them!) */
|
||||
/* [[[begin syntaxes]]] */
|
||||
#define RE_SYNTAX_EMACS 0
|
||||
|
||||
#define RE_SYNTAX_AWK \
|
||||
(RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
|
||||
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
|
||||
| RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
|
||||
| RE_UNMATCHED_RIGHT_PAREN_ORD)
|
||||
|
||||
#define RE_SYNTAX_POSIX_AWK \
|
||||
(RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
|
||||
|
||||
#define RE_SYNTAX_GREP \
|
||||
(RE_BK_PLUS_QM | RE_CHAR_CLASSES \
|
||||
| RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
|
||||
| RE_NEWLINE_ALT)
|
||||
|
||||
#define RE_SYNTAX_EGREP \
|
||||
(RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
|
||||
| RE_NEWLINE_ALT | RE_NO_BK_PARENS \
|
||||
| RE_NO_BK_VBAR)
|
||||
|
||||
#define RE_SYNTAX_POSIX_EGREP \
|
||||
(RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
|
||||
|
||||
/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
|
||||
#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
|
||||
|
||||
#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
|
||||
|
||||
/* Syntax bits common to both basic and extended POSIX regex syntax. */
|
||||
#define _RE_SYNTAX_POSIX_COMMON \
|
||||
(RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
|
||||
| RE_INTERVALS | RE_NO_EMPTY_RANGES)
|
||||
|
||||
#define RE_SYNTAX_POSIX_BASIC \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
|
||||
|
||||
/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
|
||||
RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
|
||||
isn't minimal, since other operators, such as \`, aren't disabled. */
|
||||
#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
|
||||
|
||||
#define RE_SYNTAX_POSIX_EXTENDED \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
|
||||
| RE_NO_BK_PARENS | RE_NO_BK_VBAR \
|
||||
| RE_UNMATCHED_RIGHT_PAREN_ORD)
|
||||
|
||||
/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
|
||||
replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
|
||||
#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
|
||||
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
|
||||
| RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
|
||||
/* [[[end syntaxes]]] */
|
||||
|
||||
/* Maximum number of duplicates an interval can allow. Some systems
|
||||
(erroneously) define this in other header files, but we want our
|
||||
value, so remove any previous define. */
|
||||
#ifdef RE_DUP_MAX
|
||||
#undef RE_DUP_MAX
|
||||
#endif
|
||||
#define RE_DUP_MAX ((1 << 15) - 1)
|
||||
|
||||
|
||||
/* POSIX `cflags' bits (i.e., information for `regcomp'). */
|
||||
|
||||
/* If this bit is set, then use extended regular expression syntax.
|
||||
If not set, then use basic regular expression syntax. */
|
||||
#define REG_EXTENDED 1
|
||||
|
||||
/* If this bit is set, then ignore case when matching.
|
||||
If not set, then case is significant. */
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
|
||||
/* If this bit is set, then anchors do not match at newline
|
||||
characters in the string.
|
||||
If not set, then anchors do match at newlines. */
|
||||
#define REG_NEWLINE (REG_ICASE << 1)
|
||||
|
||||
/* If this bit is set, then report only success or fail in regexec.
|
||||
If not set, then returns differ between not matching and errors. */
|
||||
#define REG_NOSUB (REG_NEWLINE << 1)
|
||||
|
||||
|
||||
/* POSIX `eflags' bits (i.e., information for regexec). */
|
||||
|
||||
/* If this bit is set, then the beginning-of-line operator doesn't match
|
||||
the beginning of the string (presumably because it's not the
|
||||
beginning of a line).
|
||||
If not set, then the beginning-of-line operator does match the
|
||||
beginning of the string. */
|
||||
#define REG_NOTBOL 1
|
||||
|
||||
/* Like REG_NOTBOL, except for the end-of-line. */
|
||||
#define REG_NOTEOL (1 << 1)
|
||||
|
||||
|
||||
/* If any error codes are removed, changed, or added, update the
|
||||
`re_error_msg' table in regex.c. */
|
||||
typedef enum
|
||||
{
|
||||
REG_NOERROR = 0, /* Success. */
|
||||
REG_NOMATCH, /* Didn't find a match (for regexec). */
|
||||
|
||||
/* POSIX regcomp return error codes. (In the order listed in the
|
||||
standard.) */
|
||||
REG_BADPAT, /* Invalid pattern. */
|
||||
REG_ECOLLATE, /* Not implemented. */
|
||||
REG_ECTYPE, /* Invalid character class name. */
|
||||
REG_EESCAPE, /* Trailing backslash. */
|
||||
REG_ESUBREG, /* Invalid back reference. */
|
||||
REG_EBRACK, /* Unmatched left bracket. */
|
||||
REG_EPAREN, /* Parenthesis imbalance. */
|
||||
REG_EBRACE, /* Unmatched \{. */
|
||||
REG_BADBR, /* Invalid contents of \{\}. */
|
||||
REG_ERANGE, /* Invalid range end. */
|
||||
REG_ESPACE, /* Ran out of memory. */
|
||||
REG_BADRPT, /* No preceding re for repetition op. */
|
||||
|
||||
/* Error codes we've added. */
|
||||
REG_EEND, /* Premature end. */
|
||||
REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
|
||||
REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
|
||||
} reg_errcode_t;
|
||||
|
||||
/* This data structure represents a compiled pattern. Before calling
|
||||
the pattern compiler, the fields `buffer', `allocated', `fastmap',
|
||||
`translate', and `no_sub' can be set. After the pattern has been
|
||||
compiled, the `re_nsub' field is available. All other fields are
|
||||
private to the regex routines. */
|
||||
|
||||
struct re_pattern_buffer
|
||||
{
|
||||
/* [[[begin pattern_buffer]]] */
|
||||
/* Space that holds the compiled pattern. It is declared as
|
||||
`unsigned char *' because its elements are
|
||||
sometimes used as array indexes. */
|
||||
unsigned char *buffer;
|
||||
|
||||
/* Number of bytes to which `buffer' points. */
|
||||
unsigned long allocated;
|
||||
|
||||
/* Number of bytes actually used in `buffer'. */
|
||||
unsigned long used;
|
||||
|
||||
/* Syntax setting with which the pattern was compiled. */
|
||||
reg_syntax_t syntax;
|
||||
|
||||
/* Pointer to a fastmap, if any, otherwise zero. re_search uses
|
||||
the fastmap, if there is one, to skip over impossible
|
||||
starting points for matches. */
|
||||
char *fastmap;
|
||||
|
||||
/* Either a translate table to apply to all characters before
|
||||
comparing them, or zero for no translation. The translation
|
||||
is applied to a pattern when it is compiled and to a string
|
||||
when it is matched. */
|
||||
char *translate;
|
||||
|
||||
/* Number of subexpressions found by the compiler. */
|
||||
size_t re_nsub;
|
||||
|
||||
/* Zero if this pattern cannot match the empty string, one else.
|
||||
Well, in truth it's used only in `re_search_2', to see
|
||||
whether or not we should use the fastmap, so we don't set
|
||||
this absolutely perfectly; see `re_compile_fastmap' (the
|
||||
`duplicate' case). */
|
||||
unsigned can_be_null : 1;
|
||||
|
||||
/* If REGS_UNALLOCATED, allocate space in the `regs' structure
|
||||
for `max (RE_NREGS, re_nsub + 1)' groups.
|
||||
If REGS_REALLOCATE, reallocate space if necessary.
|
||||
If REGS_FIXED, use what's there. */
|
||||
#define REGS_UNALLOCATED 0
|
||||
#define REGS_REALLOCATE 1
|
||||
#define REGS_FIXED 2
|
||||
unsigned regs_allocated : 2;
|
||||
|
||||
/* Set to zero when `regex_compile' compiles a pattern; set to one
|
||||
by `re_compile_fastmap' if it updates the fastmap. */
|
||||
unsigned fastmap_accurate : 1;
|
||||
|
||||
/* If set, `re_match_2' does not return information about
|
||||
subexpressions. */
|
||||
unsigned no_sub : 1;
|
||||
|
||||
/* If set, a beginning-of-line anchor doesn't match at the
|
||||
beginning of the string. */
|
||||
unsigned not_bol : 1;
|
||||
|
||||
/* Similarly for an end-of-line anchor. */
|
||||
unsigned not_eol : 1;
|
||||
|
||||
/* If true, an anchor at a newline matches. */
|
||||
unsigned newline_anchor : 1;
|
||||
|
||||
/* [[[end pattern_buffer]]] */
|
||||
};
|
||||
|
||||
typedef struct re_pattern_buffer regex_t;
|
||||
|
||||
/* Type for byte offsets within the string. POSIX mandates this. */
|
||||
typedef int regoff_t;
|
||||
|
||||
|
||||
/* This is the structure we store register match data in. See
|
||||
regex.texinfo for a full description of what registers match. */
|
||||
struct re_registers
|
||||
{
|
||||
unsigned num_regs;
|
||||
regoff_t *start;
|
||||
regoff_t *end;
|
||||
};
|
||||
|
||||
|
||||
/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
|
||||
`re_match_2' returns information about at least this many registers
|
||||
the first time a `regs' structure is passed. */
|
||||
#ifndef RE_NREGS
|
||||
#define RE_NREGS 30
|
||||
#endif
|
||||
|
||||
|
||||
/* POSIX specification for registers. Aside from the different names than
|
||||
`re_registers', POSIX uses an array of structures, instead of a
|
||||
structure of arrays. */
|
||||
typedef struct
|
||||
{
|
||||
regoff_t rm_so; /* Byte offset from string's start to substring's start. */
|
||||
regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
|
||||
} regmatch_t;
|
||||
|
||||
/* Declarations for routines. */
|
||||
|
||||
/* To avoid duplicating every routine declaration -- once with a
|
||||
prototype (if we are ANSI), and once without (if we aren't) -- we
|
||||
use the following macro to declare argument types. This
|
||||
unfortunately clutters up the declarations a bit, but I think it's
|
||||
worth it. */
|
||||
|
||||
#if __STDC__
|
||||
|
||||
#define _RE_ARGS(args) args
|
||||
|
||||
#else /* not __STDC__ */
|
||||
|
||||
#define _RE_ARGS(args) ()
|
||||
|
||||
#endif /* not __STDC__ */
|
||||
|
||||
/* Sets the current default syntax to SYNTAX, and return the old syntax.
|
||||
You can also simply assign to the `re_syntax_options' variable. */
|
||||
extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
|
||||
|
||||
/* Compile the regular expression PATTERN, with length LENGTH
|
||||
and syntax given by the global `re_syntax_options', into the buffer
|
||||
BUFFER. Return NULL if successful, and an error string if not. */
|
||||
extern const char *re_compile_pattern
|
||||
_RE_ARGS ((const char *pattern, int length,
|
||||
struct re_pattern_buffer *buffer));
|
||||
|
||||
|
||||
/* Compile a fastmap for the compiled pattern in BUFFER; used to
|
||||
accelerate searches. Return 0 if successful and -2 if was an
|
||||
internal error. */
|
||||
extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
|
||||
|
||||
|
||||
/* Search in the string STRING (with length LENGTH) for the pattern
|
||||
compiled into BUFFER. Start searching at position START, for RANGE
|
||||
characters. Return the starting position of the match, -1 for no
|
||||
match, or -2 for an internal error. Also return register
|
||||
information in REGS (if REGS and BUFFER->no_sub are nonzero). */
|
||||
extern int re_search
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
|
||||
int length, int start, int range, struct re_registers *regs));
|
||||
|
||||
|
||||
/* Like `re_search', but search in the concatenation of STRING1 and
|
||||
STRING2. Also, stop searching at index START + STOP. */
|
||||
extern int re_search_2
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
|
||||
int length1, const char *string2, int length2,
|
||||
int start, int range, struct re_registers *regs, int stop));
|
||||
|
||||
|
||||
/* Like `re_search', but return how many characters in STRING the regexp
|
||||
in BUFFER matched, starting at position START. */
|
||||
extern int re_match
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
|
||||
int length, int start, struct re_registers *regs));
|
||||
|
||||
|
||||
/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
|
||||
extern int re_match_2
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
|
||||
int length1, const char *string2, int length2,
|
||||
int start, struct re_registers *regs, int stop));
|
||||
|
||||
|
||||
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
|
||||
ENDS. Subsequent matches using BUFFER and REGS will use this memory
|
||||
for recording register information. STARTS and ENDS must be
|
||||
allocated with malloc, and must each be at least `NUM_REGS * sizeof
|
||||
(regoff_t)' bytes long.
|
||||
|
||||
If NUM_REGS == 0, then subsequent matches should allocate their own
|
||||
register data.
|
||||
|
||||
Unless this function is called, the first search or match using
|
||||
PATTERN_BUFFER will allocate its own register data, without
|
||||
freeing the old data. */
|
||||
extern void re_set_registers
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
|
||||
unsigned num_regs, regoff_t *starts, regoff_t *ends));
|
||||
|
||||
#ifdef _REGEX_RE_COMP
|
||||
/* 4.2 bsd compatibility. */
|
||||
extern char *re_comp _RE_ARGS ((const char *));
|
||||
extern int re_exec _RE_ARGS ((const char *));
|
||||
#endif
|
||||
|
||||
/* POSIX compatibility. */
|
||||
extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
|
||||
extern int regexec
|
||||
_RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
|
||||
regmatch_t pmatch[], int eflags));
|
||||
extern size_t regerror
|
||||
_RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
|
||||
size_t errbuf_size));
|
||||
extern void regfree _RE_ARGS ((regex_t *preg));
|
||||
|
||||
#endif /* not __REGEXP_LIBRARY_H__ */
|
||||
|
||||
/*
|
||||
Local variables:
|
||||
make-backup-files: t
|
||||
version-control: t
|
||||
trim-versions-without-asking: nil
|
||||
End:
|
||||
*/
|
Loading…
Reference in a new issue