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:
Roland McGrath 1995-05-18 09:00:09 +00:00
parent 4f6dc78a92
commit 2b83a2a4d9
31 changed files with 11096 additions and 25 deletions

View file

@ -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
View file

@ -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

1
libintl.h Normal file
View file

@ -0,0 +1 @@
#include <locale/libintl.h>

View file

@ -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"'

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}

View file

@ -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
View 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 */

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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 */

View file

@ -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

File diff suppressed because it is too large Load diff

495
posix/regex.h Normal file
View 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:
*/

1
regex.h Normal file
View file

@ -0,0 +1 @@
#include <posix/regex.h>