mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-21 01:12:26 +08:00
487253ea1f
* Makerules (lib%.so: lib%_pic.a): Pass -soname switch giving the library's name including $(libprefix) and major version number. * locale/locale-ctype.c (allocate_arrays): Use xmalloc and bzero in place of xcalloc. * Makeconfig (prefix, exec_prefix, libprefix): Instead of `ifndef', use the $(origin) function to only set these if they are undefined, and not if they are defined to empty. * gnu-versions.h: New file. * features.h (__GNU_LIBRARY__): Increase value to 5.
822 lines
24 KiB
C
822 lines
24 KiB
C
/* 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 = xmalloc ((size - (-128)) * sizeof (u16));
|
|
bzero (ctype_b, (size - (-128)) * sizeof (u16));
|
|
ctype_b += 128;
|
|
|
|
|
|
names_b = xmalloc (size * sizeof (i32));
|
|
bzero (names_b, size * sizeof (i32));
|
|
|
|
toupper_b = xmalloc ((size - (-128)) * sizeof (i32));
|
|
bzero (toupper_b, (size - (-128)) * sizeof (i32));
|
|
toupper_b += 128;
|
|
|
|
tolower_b = xmalloc ((size - (-128)) * sizeof (i32));
|
|
bzero (tolower_b, (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:
|
|
*/
|