From 299a95b9f048679f1288512b0a6ab6ca16dd9d7c Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 3 Apr 1996 16:31:49 +0000 Subject: Tue Apr 2 21:27:01 1996 Andreas Schwab * posix/glob.c (glob_pattern_p): Avoid scanning past eos if the pattern ends with a backslash and quoting is enabled. * posix/fnmatch.c (fnmatch): Likewise; return FNM_NOMATCH for such patterns. --- ChangeLog | 7 + MakeTAGS | 4 +- Makerules | 4 + locale/Makefile | 5 +- locale/programs/config.h | 3 +- locale/programs/ctypedump.c | 163 ----- locale/programs/locale.c | 188 +---- po/header.pot | 14 + posix/fnmatch.c | 17 +- posix/glob.c | 2 +- setjmp/setjmp.h | 2 +- stdio-common/_itoa.c | 6 +- stdio-common/_itoa.h | 29 +- stdio-common/printf-parse.h | 135 ++-- stdio-common/printf-prs.c | 52 +- stdio-common/printf.h | 9 +- stdio-common/tst-printf.c | 17 +- stdio-common/vfprintf.c | 1710 +++++++++++++++++++++++++++++-------------- stdlib/strtod.c | 20 +- sysdeps/generic/setenv.c | 5 +- wcsmbs/Makefile | 11 +- wcsmbs/mbsadvance.c | 38 - wcsmbs/mbscat.c | 56 -- wcsmbs/mbschr.c | 60 -- wcsmbs/mbscpy.c | 47 -- wcsmbs/mbsdup.c | 51 -- wcsmbs/mbslen.c | 45 -- wcsmbs/mbsncat.c | 61 -- wcsmbs/mbsncmp.c | 68 -- wcsmbs/mbsncpy.c | 55 -- wcsmbs/mbsrchr.c | 61 -- wcsmbs/mbstomb.c | 42 -- wcsmbs/mbstr.h | 69 -- wcsmbs/wcscat.c | 9 +- wcsmbs/wcschr.c | 8 +- wcsmbs/wcscmp.c | 11 +- wcsmbs/wcscpy.c | 9 +- wcsmbs/wcscspn.c | 9 +- wcsmbs/wcsdup.c | 7 +- wcsmbs/wcslen.c | 7 +- wcsmbs/wcsncat.c | 11 +- wcsmbs/wcsncmp.c | 11 +- wcsmbs/wcsncpy.c | 13 +- wcsmbs/wcspbrk.c | 9 +- wcsmbs/wcsrchr.c | 9 +- wcsmbs/wcsspn.c | 9 +- wcsmbs/wcstok.c | 43 +- wcsmbs/wcstr.h | 84 --- wcsmbs/wcswcs.c | 97 --- 49 files changed, 1507 insertions(+), 1895 deletions(-) delete mode 100644 locale/programs/ctypedump.c create mode 100644 po/header.pot delete mode 100644 wcsmbs/mbsadvance.c delete mode 100644 wcsmbs/mbscat.c delete mode 100644 wcsmbs/mbschr.c delete mode 100644 wcsmbs/mbscpy.c delete mode 100644 wcsmbs/mbsdup.c delete mode 100644 wcsmbs/mbslen.c delete mode 100644 wcsmbs/mbsncat.c delete mode 100644 wcsmbs/mbsncmp.c delete mode 100644 wcsmbs/mbsncpy.c delete mode 100644 wcsmbs/mbsrchr.c delete mode 100644 wcsmbs/mbstomb.c delete mode 100644 wcsmbs/mbstr.h delete mode 100644 wcsmbs/wcstr.h delete mode 100644 wcsmbs/wcswcs.c diff --git a/ChangeLog b/ChangeLog index f8c952fa76..ac276db283 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Tue Apr 2 21:27:01 1996 Andreas Schwab + + * posix/glob.c (glob_pattern_p): Avoid scanning past eos if + the pattern ends with a backslash and quoting is enabled. + * posix/fnmatch.c (fnmatch): Likewise; return FNM_NOMATCH for such + patterns. + Mon Apr 1 13:34:55 1996 Roland McGrath * stdio-common/tst-printf.c (main): Add new test case. diff --git a/MakeTAGS b/MakeTAGS index a9baba65e8..7aaf0ac7da 100644 --- a/MakeTAGS +++ b/MakeTAGS @@ -165,7 +165,9 @@ $P/subdirs.pot: $(subdirs:%=$P/%.pot) # Combine all the messages into the final sorted template translation file. $P/SYS_libc.pot: $(all-pot) @rm -f $@.new - $(XGETTEXT) -d - -n -s --omit-header $^ > $@.new + sed -e 's/VERSION/$(version)/' -e "s/DATE/`date +'%Y-%m-%d %k:%M'`" \ + po/header.pot > $@.new + $(XGETTEXT) -d - -n -s --omit-header $^ >> $@.new mv -f $@.new $@ test ! -d CVS || cvs ci -m'Regenerated from source files' $@ diff --git a/Makerules b/Makerules index 296e811432..d7e82d9082 100644 --- a/Makerules +++ b/Makerules @@ -610,8 +610,12 @@ cd $(@D); $(BUILD_CC) $(BUILD_CFLAGS) $(<:$(common-objpfx)%=%) -o $(@F) endef # We always want to use configuration definitions. +ifdef objdir # This is always used in $(common-objdir), so we use no directory name. BUILD_CFLAGS = -include config.h +else +BUILD_CFLAGS = -include $(..)config.h +endif # Support the GNU standard name for this target. .PHONY: check diff --git a/locale/Makefile b/locale/Makefile index 675052aa03..0a30cd27d3 100644 --- a/locale/Makefile +++ b/locale/Makefile @@ -31,8 +31,8 @@ distribute = localeinfo.h categories.def \ routines = setlocale loadlocale localeconv nl_langinfo categories = ctype messages monetary numeric time collate aux = $(categories:%=lc-%) $(categories:%=C-%) SYS_libc -others = localedef# locale -install-bin = localedef# locale +others = localedef locale +install-bin = localedef locale extra-objs = $(localedef-modules:=.o) $(locale-modules:=.o) \ $(lib-modules:=.o) @@ -41,7 +41,6 @@ vpath %.h programs localedef-modules := $(categories:%=ld-%) charmap charset linereader \ locfile stringtrans -locale-modules := ctypedump lib-modules := simple-hash xmalloc xstrdup diff --git a/locale/programs/config.h b/locale/programs/config.h index 64054657cb..4aa406d755 100644 --- a/locale/programs/config.h +++ b/locale/programs/config.h @@ -27,7 +27,6 @@ typedef int wint_t; typedef unsigned short int u16_t; - -int euidaccess (__const char *__name, int __type); +#include_next #endif diff --git a/locale/programs/ctypedump.c b/locale/programs/ctypedump.c deleted file mode 100644 index 2a6753495e..0000000000 --- a/locale/programs/ctypedump.c +++ /dev/null @@ -1,163 +0,0 @@ -/* Copyright (C) 1995, 1996 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 -#include -#include -#include -#include /* 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_t) (((((u32_t) (v)) & 0x000000ff) << 24) \ - | ((((u32_t) (v)) & 0x0000ff00) << 8) \ - | ((((u32_t) (v)) & 0x00ff0000) >> 8) \ - | ((((u32_t) (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 \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: - */ diff --git a/locale/programs/locale.c b/locale/programs/locale.c index 4e4ff83a37..8254289598 100644 --- a/locale/programs/locale.c +++ b/locale/programs/locale.c @@ -15,7 +15,12 @@ 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. */ +#ifdef HAVE_CONFIG_H +# include +#endif + #include +#include #include #include #include @@ -26,13 +31,9 @@ Cambridge, MA 02139, USA. */ #include #include -/*#include "localedef.h"*/ #include "localeinfo.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; @@ -45,7 +46,6 @@ 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' }, @@ -65,35 +65,48 @@ static const struct option long_options[] = #define CTYPE_TOUPPER_EL 0 #define CTYPE_TOLOWER_EL 0 -/* XXX Hack */ -struct cat_item +/* Definition of the data structure which represents a category and its + items. */ +struct category { - int item_id; + int cat_id; const char *name; - enum { std, opt } status; - enum value_type value_type; - int min; - int max; + 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; }; +/* Simple helper macro. */ +#define NELEMS(arr) ((sizeof (arr)) / (sizeof (arr[0]))) + +/* For some tricky stuff. */ +#define NO_PAREN(Item, More...) Item, ## More /* We have all categories defined in `categories.def'. Now construct the description and data structure used for all categories. */ +#define DEFINE_ELEMENT(Item, More...) { Item, ## More }, #define DEFINE_CATEGORY(category, name, items, postload, in, check, out) \ static struct cat_item category##_desc[] = \ { \ NO_PAREN items \ }; -#include "locale/aux/categories.def" +#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 "locale/aux/categories.def" + category##_desc }, +#include "categories.def" #undef DEFINE_CATEGORY }; #define NCATEGORIES NELEMS (category) @@ -105,7 +118,6 @@ 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 @@ -118,7 +130,6 @@ main (int argc, char *argv[]) int do_charmaps = 0; /* Set initial values for global varaibles. */ - do_dump = 0; show_category_name = 0; show_keyword_name = 0; @@ -170,20 +181,6 @@ main (int argc, char *argv[]) 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) { @@ -235,8 +232,6 @@ Mandatory arguments to long options are mandatory for short options too.\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); @@ -389,6 +384,12 @@ show_info (const char *name) printf ("%d", cnt == 0 || *val == CHAR_MAX ? -1 : *val); } break; + case word: + { + unsigned int val = (unsigned int) nl_langinfo (item->item_id); + printf ("%d", val); + } + break; default: } putchar ('\n'); @@ -398,13 +399,6 @@ show_info (const char *name) { 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. */ { @@ -428,117 +422,3 @@ show_info (const char *name) } } } - - -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};"); -} diff --git a/po/header.pot b/po/header.pot new file mode 100644 index 0000000000..c8d0c8a9d2 --- /dev/null +++ b/po/header.pot @@ -0,0 +1,14 @@ +# GNU libc message catalog of translations +# Copyright (C) 1996 Free Software Foundation, Inc. +# Automatically generated; contact +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: libc VERSION\n" +"PO-Revision-Date: DATE\n" +"Last-Translator: GNU libc maintainers \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8-bit\n" diff --git a/posix/fnmatch.c b/posix/fnmatch.c index 1ddea80961..08c1c9448e 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -78,6 +78,9 @@ fnmatch (pattern, string, flags) if (!(flags & FNM_NOESCAPE)) { c = *p++; + if (c == '\0') + /* Trailing \ loses. */ + return FNM_NOMATCH; c = FOLD (c); } if (FOLD (*n) != c) @@ -129,7 +132,11 @@ fnmatch (pattern, string, flags) register char cstart = c, cend = c; if (!(flags & FNM_NOESCAPE) && c == '\\') - cstart = cend = *p++; + { + if (*p == '\0') + return FNM_NOMATCH; + cstart = cend = *p++; + } cstart = cend = FOLD (cstart); @@ -176,8 +183,12 @@ fnmatch (pattern, string, flags) c = *p++; if (!(flags & FNM_NOESCAPE) && c == '\\') - /* XXX 1003.2d11 is unclear if this is right. */ - ++p; + { + if (*p == '\0') + return FNM_NOMATCH; + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } } if (not) return FNM_NOMATCH; diff --git a/posix/glob.c b/posix/glob.c index eea126d800..1a00af6f3f 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -699,7 +699,7 @@ glob_pattern_p (pattern, quote) return 1; case '\\': - if (quote) + if (quote && p[1] != '\0') ++p; break; diff --git a/setjmp/setjmp.h b/setjmp/setjmp.h index 12b05f1033..1cd5bbd36d 100644 --- a/setjmp/setjmp.h +++ b/setjmp/setjmp.h @@ -32,7 +32,7 @@ __BEGIN_DECLS #include /* Get `__sigset_t'. */ /* Calling environment, plus possibly a saved signal mask. */ -typedef struct __jmp_buf /* C++ doesn't like tagless structs. */ +typedef struct __jmp_buf_tag /* C++ doesn't like tagless structs. */ { /* NOTE: The machine-dependent definitions of `__sigsetjmp' assume that a `jmp_buf' begins with a `__jmp_buf'. diff --git a/stdio-common/_itoa.c b/stdio-common/_itoa.c index caa8179624..38d5367ba2 100644 --- a/stdio-common/_itoa.c +++ b/stdio-common/_itoa.c @@ -1,5 +1,5 @@ /* Internal function for converting integers to ASCII. -Copyright (C) 1994, 1995 Free Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Torbjorn Granlund and Ulrich Drepper . @@ -159,10 +159,10 @@ static const struct base_table_t base_table[] = }; /* Lower-case digits. */ -static const char _itoa_lower_digits[] +const char _itoa_lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; /* Upper-case digits. */ -static const char _itoa_upper_digits[] +const char _itoa_upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; diff --git a/stdio-common/_itoa.h b/stdio-common/_itoa.h index ab3d1d1d3a..75f5f85892 100644 --- a/stdio-common/_itoa.h +++ b/stdio-common/_itoa.h @@ -1,5 +1,5 @@ /* Internal function for converting integers to ASCII. -Copyright (C) 1994, 1995 Free Software Foundation, Inc. +Copyright (C) 1994, 1995, 1996 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 @@ -29,4 +29,31 @@ Cambridge, MA 02139, USA. */ extern char *_itoa __P ((unsigned long long int value, char *buflim, unsigned int base, int upper_case)); +static inline char *_itoa_word (unsigned long value, char *buflim, + unsigned int base, int upper_case) +{ + extern const char _itoa_upper_digits[], _itoa_lower_digits[]; + const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits; + char *bp = buflim; + + switch (base) + { +#define SPECIAL(Base) \ + case Base: \ + do \ + *--bp = digits[value % Base]; \ + while ((value /= Base) != 0); \ + break + + SPECIAL (10); + SPECIAL (16); + SPECIAL (8); + default: + do + *--bp = digits[value % base]; + while ((value /= base) != 0); + } + return bp; +} + #endif /* itoa.h */ diff --git a/stdio-common/printf-parse.h b/stdio-common/printf-parse.h index 9abbdba187..a7960e6003 100644 --- a/stdio-common/printf-parse.h +++ b/stdio-common/printf-parse.h @@ -1,5 +1,5 @@ /* Internal header for parsing printf format strings. -Copyright (C) 1995 Free Software Foundation, Inc. +Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of th GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -73,14 +73,14 @@ union printf_arg /* Read a simple integer from a string and update the string pointer. It is assumed that the first character is a digit. */ static inline unsigned int -read_int (const char * *pstr) +read_int (const UCHAR_T * *pstr) { - unsigned int retval = **pstr - '0'; + unsigned int retval = **pstr - L_('0'); - while (isdigit (*++(*pstr))) + while (ISDIGIT (*++(*pstr))) { retval *= 10; - retval += **pstr - '0'; + retval += **pstr - L_('0'); } return retval; @@ -91,13 +91,13 @@ read_int (const char * *pstr) /* Find the next spec in FORMAT, or the end of the string. Returns a pointer into FORMAT, to a '%' or a '\0'. */ static inline const char * -find_spec (const char *format) +find_spec (const char *format, mbstate_t *ps) { while (*format != '\0' && *format != '%') { int len; - if (isascii (*format) || (len = mblen (format, MB_CUR_MAX)) <= 0) + if (isascii (*format) || (len = mbrlen (format, MB_CUR_MAX, ps)) <= 0) ++format; else format += len; @@ -116,8 +116,8 @@ extern printf_arginfo_function **__printf_arginfo_table; the number of args consumed by this spec; *MAX_REF_ARG is updated so it remains the highest argument index used. */ static inline size_t -parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, - size_t *max_ref_arg) +parse_one_spec (const UCHAR_T *format, size_t posn, struct printf_spec *spec, + size_t *max_ref_arg, mbstate_t *ps) { unsigned int n; size_t nargs = 0; @@ -135,13 +135,13 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, spec->info.pad = ' '; /* Test for positional argument. */ - if (isdigit (*format)) + if (ISDIGIT (*format)) { - const char *begin = format; + const UCHAR_T *begin = format; n = read_int (&format); - if (n > 0 && *format == '$') + if (n > 0 && *format == L_('$')) /* Is positional parameter. */ { ++format; /* Skip the '$'. */ @@ -155,32 +155,32 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, } /* Check for spec modifiers. */ - while (*format == ' ' || *format == '+' || *format == '-' || - *format == '#' || *format == '0' || *format == '\'') + while (*format == L_(' ') || *format == L_('+') || *format == L_('-') || + *format == L_('#') || *format == L_('0') || *format == L_('\'')) switch (*format++) { - case ' ': + case L_(' '): /* Output a space in place of a sign, when there is no sign. */ spec->info.space = 1; break; - case '+': + case L_('+'): /* Always output + or - for numbers. */ spec->info.showsign = 1; break; - case '-': + case L_('-'): /* Left-justify things. */ spec->info.left = 1; break; - case '#': + case L_('#'): /* Use the "alternate form": Hex has 0x or 0X, FP always has a decimal point. */ spec->info.alt = 1; break; - case '0': + case L_('0'): /* Pad with 0s. */ spec->info.pad = '0'; break; - case '\'': + case L_('\''): /* Show grouping in numbers if the locale information indicates any. */ spec->info.group = 1; @@ -192,18 +192,18 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, /* Get the field width. */ spec->width_arg = -1; spec->info.width = 0; - if (*format == '*') + if (*format == L_('*')) { /* The field width is given in an argument. A negative field width indicates left justification. */ - const char *begin = ++format; + const UCHAR_T *begin = ++format; - if (isdigit (*format)) + if (ISDIGIT (*format)) { /* The width argument might be found in a positional parameter. */ n = read_int (&format); - if (n > 0 && *format == '$') + if (n > 0 && *format == L_('$')) { spec->width_arg = n - 1; *max_ref_arg = MAX (*max_ref_arg, n); @@ -219,7 +219,7 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, format = begin; /* Step back and reread. */ } } - else if (isdigit (*format)) + else if (ISDIGIT (*format)) /* Constant width specification. */ spec->info.width = read_int (&format); @@ -227,19 +227,19 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, spec->prec_arg = -1; /* -1 means none given; 0 means explicit 0. */ spec->info.prec = -1; - if (*format == '.') + if (*format == L_('.')) { ++format; - if (*format == '*') + if (*format == L_('*')) { /* The precision is given in an argument. */ - const char *begin = ++format; + const UCHAR_T *begin = ++format; - if (isdigit (*format)) + if (ISDIGIT (*format)) { n = read_int (&format); - if (n > 0 && *format == '$') + if (n > 0 && *format == L_('$')) { spec->prec_arg = n - 1; *max_ref_arg = MAX (*max_ref_arg, n); @@ -255,7 +255,7 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, format = begin; } } - else if (isdigit (*format)) + else if (ISDIGIT (*format)) spec->info.prec = read_int (&format); else /* "%.?" is treated like "%.0?". */ @@ -268,40 +268,41 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, spec->info.is_short = 0; spec->info.is_long = 0; - while (*format == 'h' || *format == 'l' || *format == 'L' || - *format == 'Z' || *format == 'q') + if (*format == L_('h') || *format == L_('l') || *format == L_('L') || + *format == L_('Z') || *format == L_('q')) switch (*format++) { - case 'h': + case L_('h'): /* int's are short int's. */ spec->info.is_short = 1; break; - case 'l': - if (spec->info.is_long) - /* A double `l' is equivalent to an `L'. */ - spec->info.is_longlong = 1; - else - /* int's are long int's. */ - spec->info.is_long = 1; - break; - case 'L': + case L_('l'): + /* int's are long int's. */ + spec->info.is_long = 1; + if (*format != L_('l')) + break; + ++format; + /* FALLTHROUGH */ + case L_('L'): /* double's are long double's, and int's are long long int's. */ + case L_('q'): + /* 4.4 uses this for long long. */ spec->info.is_long_double = 1; break; - case 'Z': + case L_('Z'): /* int's are size_t's. */ assert (sizeof(size_t) <= sizeof(unsigned long long int)); spec->info.is_longlong = sizeof(size_t) > sizeof(unsigned long int); spec->info.is_long = sizeof(size_t) > sizeof(unsigned int); break; - case 'q': - /* 4.4 uses this for long long. */ - spec->info.is_longlong = 1; - break; } /* Get the format specification. */ - spec->info.spec = *format++; +#ifdef THIS_IS_INCOMPATIBLE_WITH_LINUX_LIBC + spec->info.spec = (wchar_t) *format++; +#else + spec->info.spec = (char) *format++; +#endif if (__printf_arginfo_table != NULL && __printf_arginfo_table[spec->info.spec] != NULL) /* We don't try to get the types for all arguments if the format @@ -315,12 +316,12 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, switch (spec->info.spec) { - case 'i': - case 'd': - case 'u': - case 'o': - case 'X': - case 'x': + case L'i': + case L'd': + case L'u': + case L'o': + case L'X': + case L'x': if (spec->info.is_longlong) spec->data_arg_type = PA_INT|PA_FLAG_LONG_LONG; else if (spec->info.is_long) @@ -330,30 +331,30 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, else spec->data_arg_type = PA_INT; break; - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': + case L'e': + case L'E': + case L'f': + case L'g': + case L'G': if (spec->info.is_long_double) spec->data_arg_type = PA_DOUBLE|PA_FLAG_LONG_DOUBLE; else spec->data_arg_type = PA_DOUBLE; break; - case 'c': + case L'c': spec->data_arg_type = PA_CHAR; break; - case 's': + case L's': spec->data_arg_type = PA_STRING; break; - case 'p': + case L'p': spec->data_arg_type = PA_POINTER; break; - case 'n': + case L'n': spec->data_arg_type = PA_INT|PA_FLAG_PTR; break; - case 'm': + case L'm': default: /* An unknown spec will consume no args. */ spec->ndata_args = 0; @@ -370,14 +371,14 @@ parse_one_spec (const char *format, size_t posn, struct printf_spec *spec, } } - if (spec->info.spec == '\0') + if (spec->info.spec == L'\0') /* Format ended before this spec was complete. */ spec->end_of_fmt = spec->next_fmt = format - 1; else { /* Find the next format spec. */ spec->end_of_fmt = format; - spec->next_fmt = find_spec (format); + spec->next_fmt = find_spec (format, ps); } return nargs; diff --git a/stdio-common/printf-prs.c b/stdio-common/printf-prs.c index 811a9cb7eb..d0756de7d4 100644 --- a/stdio-common/printf-prs.c +++ b/stdio-common/printf-prs.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1995, 1996 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 @@ -20,6 +20,50 @@ Cambridge, MA 02139, USA. */ #include #include #include +#include + +#ifndef COMPILE_WPRINTF +# define CHAR_T char +# define UCHAR_T unsigned char +# define INT_T int +# define L_(Str) Str +# define ISDIGIT(Ch) isdigit (Ch) + +# ifdef USE_IN_LIBIO +# define PUT(F, S, N) _IO_sputn (F, S, N) +# define PAD(Padchar) \ + if (width > 0) \ + done += _IO_padn (s, Padchar, width) +# else +# define PUTC(C, F) putc (C, F) +ssize_t __printf_pad __P ((FILE *, char pad, size_t n)); +# define PAD(Padchar) \ + if (width > 0) \ + { if (__printf_pad (s, Padchar, width) == -1) \ + return -1; else done += width; } +# endif +#else +# define vfprintf vfwprintf +# define CHAR_T wchar_t +# define UCHAR_T uwchar_t +# define INT_T wint_t +# define L_(Str) L##Str +# define ISDIGIT(Ch) iswdigit (Ch) + +# ifdef USE_IN_LIBIO +# define PUT(F, S, N) _IO_sputn (F, S, N) +# define PAD(Padchar) \ + if (width > 0) \ + done += _IO_wpadn (s, Padchar, width) +# else +# define PUTC(C, F) wputc (C, F) +ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n)); +# define PAD(Padchar) \ + if (width > 0) \ + { if (__wprintf_pad (s, Padchar, width) == -1) \ + return -1; else done += width; } +# endif +#endif #include "printf-parse.h" @@ -33,15 +77,17 @@ parse_printf_format (fmt, n, argtypes) size_t nargs; /* Number of arguments. */ size_t max_ref_arg; /* Highest index used in a positional arg. */ struct printf_spec spec; + mbstate_t mbstate; nargs = 0; max_ref_arg = 0; + mbstate = 0; /* Search for format specifications. */ - for (fmt = find_spec (fmt); *fmt != '\0'; fmt = spec.next_fmt) + for (fmt = find_spec (fmt, &mbstate); *fmt != '\0'; fmt = spec.next_fmt) { /* Parse this spec. */ - nargs += parse_one_spec (fmt, nargs, &spec, &max_ref_arg); + nargs += parse_one_spec (fmt, nargs, &spec, &max_ref_arg, &mbstate); /* If the width is determined by an argument this is an int. */ if (spec.width_arg != -1 && spec.width_arg < n) diff --git a/stdio-common/printf.h b/stdio-common/printf.h index df7747ec38..6e90154cde 100644 --- a/stdio-common/printf.h +++ b/stdio-common/printf.h @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +/* Copyright (C) 1991, 92, 93, 95, 96 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 @@ -26,6 +26,7 @@ __BEGIN_DECLS #define __need_FILE #include #define __need_size_t +#define __need_wchar_t #include @@ -33,7 +34,11 @@ struct printf_info { int prec; /* Precision. */ int width; /* Width. */ - unsigned char spec; /* Format letter. */ +#ifdef THIS_IS_INCOMPATIBLE_WITH_LINUX_LIBC + wchar_t spec; /* Format letter. */ +#else + char spec; /* Format letter. */ +#endif unsigned int is_long_double:1;/* L flag. */ unsigned int is_short:1; /* h flag. */ unsigned int is_long:1; /* l flag. */ diff --git a/stdio-common/tst-printf.c b/stdio-common/tst-printf.c index c177da18b2..12212b87b2 100644 --- a/stdio-common/tst-printf.c +++ b/stdio-common/tst-printf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +/* Copyright (C) 1991, 1992, 1993, 1995, 1996 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 @@ -188,7 +188,7 @@ I am ready for my first lesson today."; { double d = FLT_MIN; int niter = 17; - + while (niter-- != 0) printf ("%.17e\n", d / 2); fflush (stdout); @@ -233,7 +233,18 @@ I am ready for my first lesson today."; rfg1 (); rfg2 (); - exit(EXIT_SUCCESS); + { + char buf[200]; + int result; + + sprintf(buf,"%*s%*s%*s",-1,"one",-20,"two",-30,"three"); + + result = strcmp (buf, + "onetwo three "); + + puts (result != 0 ? "Test failed!" : "Test ok."); + return result != 0; + } } rfg1 () diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c index d6b9f9a092..26b31a6ed2 100644 --- a/stdio-common/vfprintf.c +++ b/stdio-common/vfprintf.c @@ -13,128 +13,162 @@ 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. */ +not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ #include -#include -#include #include -#include #include #include #include -#include -#include -#include +#include #include "_itoa.h" #include "../locale/localeinfo.h" +/* This code is shared between the standard stdio implementation found + in GNU C library and the libio implementation originally found in + GNU libg++. + + Beside this it is also shared between the normal and wide character + implementation as defined in ISO/IEC 9899:1990/Amendment 1:1995. */ + +#ifndef COMPILE_WPRINTF +# define CHAR_T char +# define UCHAR_T unsigned char +# define INT_T int +# define L_(Str) Str +# define ISDIGIT(Ch) isdigit (Ch) + +# ifdef USE_IN_LIBIO +# define PUT(F, S, N) _IO_sputn (F, S, N) +# define PAD(Padchar) \ + if (width > 0) \ + done += _IO_padn (s, Padchar, width) +# else +# define PUTC(C, F) putc (C, F) +ssize_t __printf_pad __P ((FILE *, char pad, size_t n)); +# define PAD(Padchar) \ + if (width > 0) \ + { if (__printf_pad (s, Padchar, width) == -1) \ + return -1; else done += width; } +# endif +#else +# define vfprintf vfwprintf +# define CHAR_T wchar_t +# define UCHAR_T uwchar_t +# define INT_T wint_t +# define L_(Str) L##Str +# define ISDIGIT(Ch) iswdigit (Ch) + +# ifdef USE_IN_LIBIO +# define PUT(F, S, N) _IO_sputn (F, S, N) +# define PAD(Padchar) \ + if (width > 0) \ + done += _IO_wpadn (s, Padchar, width) +# else +# define PUTC(C, F) wputc (C, F) +ssize_t __wprintf_pad __P ((FILE *, wchar_t pad, size_t n)); +# define PAD(Padchar) \ + if (width > 0) \ + { if (__wprintf_pad (s, Padchar, width) == -1) \ + return -1; else done += width; } +# endif +#endif + /* Include the shared code for parsing the format string. */ #include "printf-parse.h" -/* This function from the GNU C library is also used in libio. - To compile for use in libio, compile with -DUSE_IN_LIBIO. */ - #ifdef USE_IN_LIBIO /* This code is for use in libio. */ -#include -#define PUT(f, s, n) _IO_sputn (f, s, n) -#define PAD(padchar) \ - if (specs[cnt].info.width > 0) \ - done += _IO_padn (s, padchar, specs[cnt].info.width) -#define PUTC(c, f) _IO_putc (c, f) -#define vfprintf _IO_vfprintf -#define size_t _IO_size_t -#define FILE _IO_FILE -#define va_list _IO_va_list -#undef BUFSIZ -#define BUFSIZ _IO_BUFSIZ -#define ARGCHECK(s, format) \ +# include +# define PUTC(C, F) _IO_putc (C, F) +# define vfprintf _IO_vfprintf +# define size_t _IO_size_t +# define FILE _IO_FILE +# define va_list _IO_va_list +# undef BUFSIZ +# define BUFSIZ _IO_BUFSIZ +# define ARGCHECK(S, Format) \ do \ { \ /* Check file argument for consistence. */ \ - CHECK_FILE (s, -1); \ - if (s->_flags & _IO_NO_WRITES || format == NULL) \ + CHECK_FILE (S, -1); \ + if (S->_flags & _IO_NO_WRITES || Format == NULL) \ { \ MAYBE_SET_EINVAL; \ return -1; \ } \ } while (0) -#define UNBUFFERED_P(s) ((s)->_IO_file_flags & _IO_UNBUFFERED) +# define UNBUFFERED_P(S) ((S)->_IO_file_flags & _IO_UNBUFFERED) #else /* ! USE_IN_LIBIO */ /* This code is for use in the GNU C library. */ -#include -#define PUTC(c, f) putc (c, f) -#define PUT(f, s, n) fwrite (s, 1, n, f) -ssize_t __printf_pad __P ((FILE *, char pad, size_t n)); -#define PAD(padchar) \ - if (specs[cnt].info.width > 0) \ - { if (__printf_pad (s, padchar, specs[cnt].info.width) == -1) \ - return -1; else done += specs[cnt].info.width; } -#define ARGCHECK(s, format) \ +# include +# define PUT(F, S, N) fwrite (S, 1, N, F) +# define ARGCHECK(S, Format) \ do \ { \ /* Check file argument for consistence. */ \ - if (!__validfp(s) || !s->__mode.__write || format == NULL) \ + if (!__validfp(S) || !S->__mode.__write || Format == NULL) \ { \ errno = EINVAL; \ return -1; \ } \ - if (!s->__seen) \ + if (!S->__seen) \ { \ - if (__flshfp (s, EOF) == EOF) \ + if (__flshfp (S, EOF) == EOF) \ return -1; \ } \ - } while (0) -#define UNBUFFERED_P(s) ((s)->__buffer == NULL) + } \ + while (0) +# define UNBUFFERED_P(s) ((s)->__buffer == NULL) #endif /* USE_IN_LIBIO */ -#define outchar(x) \ +#define outchar(Ch) \ do \ { \ - register const int outc = (x); \ + register const int outc = (Ch); \ if (PUTC (outc, s) == EOF) \ return -1; \ else \ ++done; \ - } while (0) + } \ + while (0) -#define outstring(string, len) \ +#define outstring(String, Len) \ do \ { \ - if (len > 20) \ - { \ - if (PUT (s, string, len) != len) \ - return -1; \ - done += len; \ - } \ - else \ - { \ - register const char *cp = string; \ - register int l = len; \ - while (l-- > 0) \ - outchar (*cp++); \ - } \ - } while (0) + if (PUT (s, String, Len) != Len) \ + return -1; \ + done += Len; \ + } \ + while (0) -/* Helper function to provide temporary buffering for unbuffered streams. */ -static int buffered_vfprintf __P ((FILE *stream, const char *fmt, va_list)); +/* For handling long_double and longlong we use the same flag. */ +#ifndef is_longlong +# define is_longlong is_long_double +#endif + + +/* Global variables. */ +static const char null[] = "(null)"; -static printf_function printf_unknown; -extern printf_function **__printf_function_table; +/* Helper function to provide temporary buffering for unbuffered streams. */ +static int buffered_vfprintf __P ((FILE *stream, const CHAR_T *fmt, va_list)); + +/* Handle unknown format specifier. */ +static int printf_unknown __P ((FILE *, const struct printf_info *, + const void *const *)); -static char *group_number __P ((char *, char *, const char *, wchar_t)); +/* Group digits of number string. */ +static char *group_number __P ((CHAR_T *, CHAR_T *, const CHAR_T *, wchar_t)); +/* The function itself. */ int -vfprintf (s, format, ap) - register FILE *s; - const char *format; - va_list ap; +vfprintf (FILE *s, const CHAR_T *format, va_list ap) { /* The character used as thousands separator. */ wchar_t thousands_sep; @@ -142,35 +176,613 @@ vfprintf (s, format, ap) /* The string describing the size of groups of digits. */ const char *grouping; - /* Array with information about the needed arguments. This has to be - dynamically extendable. */ - size_t nspecs; - size_t nspecs_max; - struct printf_spec *specs; + /* Place to accumulate the result. */ + int done; - /* The number of arguments the format string requests. This will - determine the size of the array needed to store the argument - attributes. */ - size_t nargs; - int *args_type; - union printf_arg *args_value; - - /* Positional parameters refer to arguments directly. This could also - determine the maximum number of arguments. Track the maximum number. */ - size_t max_ref_arg; + /* Current character in format string. */ + const UCHAR_T *f; /* End of leading constant string. */ - const char *lead_str_end; + const UCHAR_T *lead_str_end; + + /* Points to next format specifier. */ + const UCHAR_T *end_of_spec; + + /* Buffer intermediate results. */ + char work_buffer[1000]; +#define workend (&work_buffer[sizeof (work_buffer) - 1]) + + /* State for restartable multibyte character handling functions. */ + mbstate_t mbstate; + + /* We have to save the original argument pointer. */ + va_list ap_save; - /* Number of characters written. */ - register size_t done = 0; + /* Count number of specifiers we already processed. */ + int nspecs_done; + + + /* This table maps a character into a number representing a + class. In each step there is a destination label for each + class. */ + static const int jump_table[] = + { + /* ' ' */ 1, 0, 0, /* '#' */ 4, + 0, /* '%' */ 14, 0, /* '\''*/ 6, + 0, 0, /* '*' */ 7, /* '+' */ 2, + 0, /* '-' */ 3, /* '.' */ 9, 0, + /* '0' */ 5, /* '1' */ 8, /* '2' */ 8, /* '3' */ 8, + /* '4' */ 8, /* '5' */ 8, /* '6' */ 8, /* '7' */ 8, + /* '8' */ 8, /* '9' */ 8, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, /* 'E' */ 19, 0, /* 'G' */ 19, + 0, 0, 0, 0, + /* 'L' */ 12, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + /* 'X' */ 18, 0, /* 'Z' */ 13, 0, + 0, 0, 0, 0, + 0, 0, 0, /* 'c' */ 20, + /* 'd' */ 15, /* 'e' */ 19, /* 'f' */ 19, /* 'g' */ 19, + /* 'h' */ 10, /* 'i' */ 15, 0, 0, + /* 'l' */ 11, /* 'm' */ 24, /* 'n' */ 23, /* 'o' */ 17, + /* 'p' */ 22, /* 'q' */ 12, 0, /* 's' */ 21, + 0, /* 'u' */ 16, 0, 0, + /* 'x' */ 18 + }; + +#define NOT_IN_JUMP_RANGE(Ch) ((Ch) < ' ' || (Ch) > 'x') +#define CHAR_CLASS(Ch) (jump_table[(int) (Ch) - ' ']) +#define JUMP(ChExpr, table) \ + do \ + { \ + const void *ptr; \ + spec = (ChExpr); \ + ptr = NOT_IN_JUMP_RANGE (spec) ? REF (form_unknown) \ + : table[CHAR_CLASS (spec)]; \ + goto *ptr; \ + } \ + while (0) + +#define STEP0_3_TABLE \ + /* Step 0: at the beginning. */ \ + static const void *step0_jumps[25] = \ + { \ + REF (form_unknown), \ + REF (flag_space), /* for ' ' */ \ + REF (flag_plus), /* for '+' */ \ + REF (flag_minus), /* for '-' */ \ + REF (flag_hash), /* for '' */ \ + REF (flag_zero), /* for '0' */ \ + REF (flag_quote), /* for '\'' */ \ + REF (width_asterics), /* for '*' */ \ + REF (width), /* for '1'...'9' */ \ + REF (precision), /* for '.' */ \ + REF (mod_half), /* for 'h' */ \ + REF (mod_long), /* for 'l' */ \ + REF (mod_longlong), /* for 'L', 'q' */ \ + REF (mod_size_t), /* for 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror) /* for 'm' */ \ + }; \ + /* Step 1: after processing width. */ \ + static const void *step1_jumps[25] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (precision), /* for '.' */ \ + REF (mod_half), /* for 'h' */ \ + REF (mod_long), /* for 'l' */ \ + REF (mod_longlong), /* for 'L', 'q' */ \ + REF (mod_size_t), /* for 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror) /* for 'm' */ \ + }; \ + /* Step 2: after processing precision. */ \ + static const void *step2_jumps[25] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (mod_half), /* for 'h' */ \ + REF (mod_long), /* for 'l' */ \ + REF (mod_longlong), /* for 'L', 'q' */ \ + REF (mod_size_t), /* for 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror) /* for 'm' */ \ + }; \ + /* Step 3: after processing first 'l' modifier. */ \ + static const void *step3_jumps[25] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (form_unknown), /* for 'h' */ \ + REF (mod_longlong), /* for 'l' */ \ + REF (form_unknown), /* for 'L', 'q' */ \ + REF (form_unknown), /* for 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror) /* for 'm' */ \ + } - /* Running pointer through format string. */ - const char *f; +#define STEP4_TABLE \ + /* Step 4: processing format specifier. */ \ + static const void *step4_jumps[25] = \ + { \ + REF (form_unknown), \ + REF (form_unknown), /* for ' ' */ \ + REF (form_unknown), /* for '+' */ \ + REF (form_unknown), /* for '-' */ \ + REF (form_unknown), /* for '' */ \ + REF (form_unknown), /* for '0' */ \ + REF (form_unknown), /* for '\'' */ \ + REF (form_unknown), /* for '*' */ \ + REF (form_unknown), /* for '1'...'9' */ \ + REF (form_unknown), /* for '.' */ \ + REF (form_unknown), /* for 'h' */ \ + REF (form_unknown), /* for 'l' */ \ + REF (form_unknown), /* for 'L', 'q' */ \ + REF (form_unknown), /* for 'Z' */ \ + REF (form_percent), /* for '%' */ \ + REF (form_integer), /* for 'd', 'i' */ \ + REF (form_unsigned), /* for 'u' */ \ + REF (form_octal), /* for 'o' */ \ + REF (form_hexa), /* for 'X', 'x' */ \ + REF (form_float), /* for 'E', 'e', 'f', 'G', 'g' */ \ + REF (form_character), /* for 'c' */ \ + REF (form_string), /* for 's' */ \ + REF (form_pointer), /* for 'p' */ \ + REF (form_number), /* for 'n' */ \ + REF (form_strerror) /* for 'm' */ \ + } - /* Just a counter. */ - int cnt; +#define process_arg(fspec) \ + /* Start real work. We know about all flag and modifiers and \ + now process the wanted format specifier. */ \ + LABEL (form_percent): \ + /* Write a literal "%". */ \ + outchar ('%'); \ + break; \ + \ + LABEL (form_integer): \ + /* Signed decimal integer. */ \ + base = 10; \ + \ + if (is_longlong) \ + { \ + long long int signed_number; \ + \ + signed_number = va_arg (ap, long long int); \ + \ + is_negative = signed_number < 0; \ + number.longlong = is_negative ? (- signed_number) : signed_number; \ + \ + goto LABEL (longlong_number); \ + } \ + else \ + { \ + long int signed_number; \ + \ + if (is_long) \ + signed_number = va_arg (ap, long int); \ + else /* `short int' will be promoted to `int'. */ \ + signed_number = va_arg (ap, int); \ + \ + is_negative = signed_number < 0; \ + number.word = is_negative ? (- signed_number) : signed_number; \ + \ + goto LABEL (number); \ + } \ + /* NOTREACHED */ \ + \ + LABEL (form_unsigned): \ + /* Unsigned decimal integer. */ \ + base = 10; \ + goto LABEL (unsigned_number); \ + /* NOTREACHED */ \ + \ + LABEL (form_octal): \ + /* Unsigned octal integer. */ \ + base = 8; \ + goto LABEL (unsigned_number); \ + /* NOTREACHED */ \ + \ + LABEL (form_hexa): \ + /* Unsigned hexadecimal integer. */ \ + base = 16; \ + \ + LABEL (unsigned_number): /* Unsigned number of base BASE. */ \ + \ + /* ANSI specifies the `+' and ` ' flags only for signed \ + conversions. */ \ + is_negative = 0; \ + showsign = 0; \ + space = 0; \ + \ + if (is_longlong) \ + { \ + number.longlong = va_arg (ap, unsigned long long int); \ + \ + LABEL (longlong_number): \ + if (prec < 0) \ + /* Supply a default precision if none was given. */ \ + prec = 1; \ + else \ + /* We have to take care for the '0' flag. If a precision \ + is given it must be ignored. */ \ + pad = ' '; \ + \ + /* If the precision is 0 and the number is 0 nothing has to \ + be written for the number. */ \ + if (prec == 0 && number.longlong == 0) \ + string = workend; \ + else \ + { \ + /* Put the number in WORK. */ \ + string = _itoa (number.longlong, workend + 1, base, \ + spec == 'X'); \ + string -= 1; \ + if (group && grouping) \ + string = group_number (string, workend, grouping, \ + thousands_sep); \ + } \ + /* Simply further test for num != 0. */ \ + number.word = number.longlong != 0; \ + } \ + else \ + { \ + if (is_long) \ + number.word = va_arg (ap, unsigned long int); \ + else \ + number.word = va_arg (ap, unsigned int); /* Promoted. */ \ + \ + LABEL (number): \ + if (prec < 0) \ + /* Supply a default precision if none was given. */ \ + prec = 1; \ + else \ + /* We have to take care for the '0' flag. If a precision \ + is given it must be ignored. */ \ + pad = ' '; \ + \ + /* If the precision is 0 and the number is 0 nothing has to \ + be written for the number. */ \ + if (prec == 0 && number.word == 0) \ + string = workend; \ + else \ + { \ + /* Put the number in WORK. */ \ + string = _itoa_word (number.word, workend + 1, base, \ + spec == 'X'); \ + string -= 1; \ + if (group && grouping) \ + string = group_number (string, workend, grouping, \ + thousands_sep); \ + } \ + } \ + \ + prec -= workend - string; \ + \ + if (prec > 0) \ + /* Add zeros to the precision. */ \ + while (prec-- > 0) \ + *string-- = '0'; \ + else if (number.word != 0 && alt && base == 8) \ + /* Add octal marker. */ \ + *string-- = '0'; \ + \ + if (!left) \ + { \ + width -= workend - string; \ + \ + if (number.word != 0 && alt && base == 16) \ + /* Account for 0X hex marker. */ \ + width -= 2; \ + \ + if (is_negative || showsign || space) \ + --width; \ + \ + if (pad == '0') \ + { \ + while (width-- > 0) \ + *string-- = '0'; \ + \ + if (number.word != 0 && alt && base == 16) \ + { \ + *string-- = spec; \ + *string-- = '0'; \ + } \ + \ + if (is_negative) \ + *string-- = '-'; \ + else if (showsign) \ + *string-- = '+'; \ + else if (space) \ + *string-- = ' '; \ + } \ + else \ + { \ + if (number.word != 0 && alt && base == 16) \ + { \ + *string-- = spec; \ + *string-- = '0'; \ + } \ + \ + if (is_negative) \ + *string-- = '-'; \ + else if (showsign) \ + *string-- = '+'; \ + else if (space) \ + *string-- = ' '; \ + \ + while (width-- > 0) \ + *string-- = ' '; \ + } \ + \ + outstring (string + 1, workend - string); \ + \ + break; \ + } \ + else \ + { \ + if (number.word != 0 && alt && base == 16) \ + { \ + *string-- = spec; \ + *string-- = '0'; \ + } \ + \ + if (is_negative) \ + *string-- = '-'; \ + else if (showsign) \ + *string-- = '+'; \ + else if (space) \ + *string-- = ' '; \ + \ + width -= workend - string; \ + outstring (string + 1, workend - string); \ + \ + PAD (' '); \ + break; \ + } \ + \ + LABEL (form_float): \ + { \ + /* Floating-point number. This is handled by printf_fp.c. */ \ + extern int __printf_fp __P ((FILE *, const struct printf_info *, \ + const void **const)); \ + const void *ptr; \ + int function_done; \ + \ + if (is_long_double) \ + the_arg.pa_long_double = va_arg (ap, long double); \ + else \ + the_arg.pa_double = va_arg (ap, double); \ + \ + ptr = (const void *) &the_arg; \ + \ + if (fspec == NULL) \ + { \ + struct printf_info info = { prec: prec, \ + width: width, \ + spec: spec, \ + is_long_double: is_long_double, \ + is_short: is_short, \ + is_long: is_long, \ + alt: alt, \ + space: space, \ + left: left, \ + showsign: showsign, \ + group: group, \ + pad: pad }; \ + \ + function_done = __printf_fp (s, &info, &ptr); \ + } \ + else \ + function_done = __printf_fp (s, &fspec->info, &ptr); \ + \ + if (function_done < 0) \ + /* Error in print handler. */ \ + return -1; \ + \ + done += function_done; \ + } \ + break; \ + \ + LABEL (form_character): \ + /* Character. */ \ + --width; /* Account for the character itself. */ \ + if (!left) \ + PAD (' '); \ + outchar ((unsigned char) va_arg (ap, int)); /* Promoted. */ \ + if (left) \ + PAD (' '); \ + break; \ + \ + LABEL (form_string): \ + { \ + size_t len; \ + \ + /* The string argument could in fact be `char *' or `wchar_t *'. \ + But this should not make a difference here. */ \ + string = (char *) va_arg (ap, const char *); \ + \ + /* Entry point for printing other strings. */ \ + LABEL (print_string): \ + \ + if (string == NULL) \ + { \ + /* Write "(null)" if there's space. */ \ + if (prec == -1 || prec >= (int) sizeof (null) - 1) \ + { \ + string = (char *) null; \ + len = sizeof (null) - 1; \ + } \ + else \ + { \ + string = (char *) ""; \ + len = 0; \ + } \ + } \ + else if (!is_long) \ + { \ + if (prec != -1) \ + { \ + /* Search for the end of the string, but don't search past \ + the length specified by the precision. */ \ + const char *end = memchr (string, '\0', prec); \ + if (end) \ + len = end - string; \ + else \ + len = prec; \ + } \ + else \ + len = strlen (string); \ + } \ + else \ + { \ + const wchar_t *s2 = (const wchar_t *) string; \ + mbstate_t mbstate = 0; \ + \ + len = wcsrtombs (NULL, &s2, prec != -1 ? prec : UINT_MAX, \ + &mbstate); \ + if (len == (size_t) -1) \ + /* Illegal wide-character string. */ \ + return -1; \ + \ + s2 = (const wchar_t *) string; \ + mbstate = 0; \ + string = alloca (len + 1); \ + (void) wcsrtombs (string, &s2, prec != -1 ? prec : UINT_MAX, \ + &mbstate); \ + } \ + \ + if ((width -= len) < 0) \ + { \ + outstring (string, len); \ + break; \ + } \ + \ + if (!left) \ + PAD (' '); \ + outstring (string, len); \ + if (left) \ + PAD (' '); \ + } \ + break; \ + \ + LABEL (form_pointer): \ + /* Generic pointer. */ \ + { \ + const void *ptr; \ + ptr = va_arg (ap, void *); \ + if (ptr != NULL) \ + { \ + /* If the pointer is not NULL, write it as a %#x spec. */ \ + base = 16; \ + number.word = (unsigned long int) ptr; \ + is_negative = 0; \ + alt = 1; \ + group = 0; \ + spec = 'x'; \ + goto LABEL (number); \ + } \ + else \ + { \ + /* Write "(nil)" for a nil pointer. */ \ + string = (char *) "(nil)"; \ + /* Make sure the full string "(nil)" is printed. */ \ + if (prec < 5) \ + prec = 5; \ + is_long = 0; /* This is no wide-char string. */ \ + goto LABEL (print_string); \ + } \ + } \ + /* NOTREACHED */ \ + \ + LABEL (form_number): \ + /* Answer the count of characters written. */ \ + if (is_longlong) \ + *(long long int *) va_arg (ap, void *) = done; \ + else if (is_long) \ + *(long int *) va_arg (ap, void *) = done; \ + else if (!is_short) \ + *(int *) va_arg (ap, void *) = done; \ + else \ + *(short int *) va_arg (ap, void *) = done; \ + break; \ + \ + LABEL (form_strerror): \ + /* Print description of error ERRNO. */ \ + { \ + extern char *_strerror_internal __P ((int, char *buf, size_t)); \ + \ + string = (char *) \ + _strerror_internal (errno, work_buffer, sizeof work_buffer); \ + } \ + is_long = 0; /* This is no wide-char string. */ \ + goto LABEL (print_string) + + + /* Sanity check of arguments. */ ARGCHECK (s, format); if (UNBUFFERED_P (s)) @@ -178,101 +790,326 @@ vfprintf (s, format, ap) for the stream and then call us again. */ return buffered_vfprintf (s, format, ap); - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); + /* Initialize local variables. */ + done = 0; + grouping = (const char *) -1; + mbstate = 0; + ap_save = ap; + nspecs_done = 0; - /* Figure out the thousands separator character. */ - if (mbtowc (&thousands_sep, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP), - strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0) - thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); - grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); - if (*grouping == '\0' || *grouping == CHAR_MAX || thousands_sep == L'\0') - grouping = NULL; + /* Find the first format specifier. */ + f = lead_str_end = find_spec (format, &mbstate); - nspecs_max = 32; /* A more or less arbitrary start value. */ - specs = alloca (nspecs_max * sizeof (struct printf_spec)); - nspecs = 0; - nargs = 0; - max_ref_arg = 0; + /* Write the literal text before the first format. */ + outstring ((const UCHAR_T *) format, + lead_str_end - (const UCHAR_T *) format); - /* Find the first format specifier. */ - lead_str_end = find_spec (format); + /* If we only have to print a simple string, return now. */ + if (*f == L_('\0')) + return done; - for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt) + /* Process whole format string. */ + do { - if (nspecs >= nspecs_max) +#define REF(Name) &&do_##Name +#define LABEL(Name) do_##Name + STEP0_3_TABLE; + STEP4_TABLE; + + int is_negative; /* Flag for negative number. */ + union + { + unsigned long long int longlong; + unsigned long int word; + } number; + int base; + union printf_arg the_arg; + char *string; /* Pointer to argument string. */ + int alt = 0; /* Alternate format. */ + int space = 0; /* Use space prefix if no sign is needed. */ + int left = 0; /* Left-justify output. */ + int showsign = 0; /* Always begin with plus or minus sign. */ + int group = 0; /* Print numbers according grouping rules. */ + int is_long_double = 0; /* Argument is long double/ long long int. */ + int is_short = 0; /* Argument is long int. */ + int is_long = 0; /* Argument is short int. */ + int width = 0; /* Width of output; 0 means none specified. */ + int prec = -1; /* Precision of output; -1 means none specified. */ + char pad = ' '; /* Padding character. */ + CHAR_T spec; + + /* Get current character in format string. */ + JUMP (*++f, step0_jumps); + + /* ' ' flag. */ + LABEL (flag_space): + space = 1; + JUMP (*++f, step0_jumps); + + /* '+' flag. */ + LABEL (flag_plus): + showsign = 1; + JUMP (*++f, step0_jumps); + + /* The '-' flag. */ + LABEL (flag_minus): + left = 1; + pad = L_(' '); + JUMP (*++f, step0_jumps); + + /* The '#' flag. */ + LABEL (flag_hash): + alt = 1; + JUMP (*++f, step0_jumps); + + /* The '0' flag. */ + LABEL (flag_zero): + if (!left) + pad = L_('0'); + JUMP (*++f, step0_jumps); + + /* The '\'' flag. */ + LABEL (flag_quote): + group = 1; + + /* XXX Completely wrong. Use wctob. */ + if (grouping == (const char *) -1) { - /* Extend the array of format specifiers. */ - struct printf_spec *old = specs; - - nspecs_max *= 2; - specs = alloca (nspecs_max * sizeof (struct printf_spec)); - if (specs == &old[nspecs]) - /* Stack grows up, OLD was the last thing allocated; extend it. */ - nspecs_max += nspecs_max / 2; - else - { - /* Copy the old array's elements to the new space. */ - memcpy (specs, old, nspecs * sizeof (struct printf_spec)); - if (old == &specs[nspecs]) - /* Stack grows down, OLD was just below the new SPECS. - We can use that space when the new space runs out. */ - nspecs_max += nspecs_max / 2; - } + /* Figure out the thousands separator character. */ + if (mbtowc (&thousands_sep, + _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP), + strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0) + thousands_sep = (wchar_t) + *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); + grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); + if (*grouping == '\0' || *grouping == CHAR_MAX + || thousands_sep == L'\0') + grouping = NULL; } + JUMP (*++f, step0_jumps); - /* Parse the format specifier. */ - nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg); - } + /* Get width from argument. */ + LABEL (width_asterics): + { + const UCHAR_T *tmp; /* Temporary value. */ - /* Determine the number of arguments the format string consumes. */ - nargs = MAX (nargs, max_ref_arg); + tmp = ++f; + if (ISDIGIT (*tmp) && read_int (&tmp) && *tmp == L_('$')) + /* The width comes from an positional parameter. */ + goto do_positional; - /* Allocate memory for the argument descriptions. */ - args_type = alloca (nargs * sizeof (int)); - memset (args_type, 0, nargs * sizeof (int)); - args_value = alloca (nargs * sizeof (union printf_arg)); + width = va_arg (ap, int); - /* XXX Could do sanity check here: If any element in ARGS_TYPE is - still zero after this loop, format is invalid. For now we simply - use 0 as the value. */ + /* Negative width means left justified. */ + if (width < 0) + { + width = -width; + pad = L_(' '); + left = 1; + } + } + JUMP (*f, step1_jumps); + + /* Given width in format string. */ + LABEL (width): + width = read_int (&f); + if (*f == L_('$')) + /* Oh, oh. The argument comes from an positional parameter. */ + goto do_positional; + JUMP (*f, step1_jumps); + + LABEL (precision): + ++f; + if (*f == L_('*')) + { + const UCHAR_T *tmp; /* Temporary value. */ - /* Fill in the types of all the arguments. */ - for (cnt = 0; cnt < nspecs; ++cnt) - { - /* If the width is determined by an argument this is an int. */ - if (specs[cnt].width_arg != -1) - args_type[specs[cnt].width_arg] = PA_INT; + tmp = ++f; + if (ISDIGIT (*tmp) && read_int (&tmp) > 0 && *tmp == L_('$')) + /* The precision comes from an positional parameter. */ + goto do_positional; - /* If the precision is determined by an argument this is an int. */ - if (specs[cnt].prec_arg != -1) - args_type[specs[cnt].prec_arg] = PA_INT; + prec = va_arg (ap, int); - switch (specs[cnt].ndata_args) + /* If the precision is negative the precision is omitted. */ + if (prec < 0) + prec = -1; + } + else if (ISDIGIT (*f)) + prec = read_int (&f); + else + prec = 0; + JUMP (*f, step2_jumps); + + /* Process 'h' modifier. No other modifier is allowed to + follow. */ + LABEL (mod_half): + is_short = 1; + JUMP (*++f, step4_jumps); + + /* Process 'l' modifier. There might another 'l' follow. */ + LABEL (mod_long): + is_long = 1; + JUMP (*++f, step3_jumps); + + /* Process 'L', 'q', or 'll' modifier. No other modifier is + allowed to follow. */ + LABEL (mod_longlong): + is_long_double = 1; + JUMP (*++f, step4_jumps); + + LABEL (mod_size_t): + is_longlong = sizeof (size_t) > sizeof (unsigned long int); + is_long = sizeof (size_t) > sizeof (unsigned int); + JUMP (*++f, step4_jumps); + + + /* Process current format. */ + while (1) { - case 0: /* No arguments. */ - break; - case 1: /* One argument; we already have the type. */ - args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type; - break; - default: - /* We have more than one argument for this format spec. We must - call the arginfo function again to determine all the types. */ - (void) (*__printf_arginfo_table[specs[cnt].info.spec]) - (&specs[cnt].info, - specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]); - break; + process_arg (((struct printf_spec *) NULL)); + + LABEL (form_unknown): + if (spec == L_('\0')) + /* The format string ended before the specifier is complete. */ + return -1; + + /* If we are in the fast loop force entering the complicated + one. */ + goto do_positional; } + + /* Look for next format specifier. */ + f = find_spec ((end_of_spec = ++f), &mbstate); + + /* Write the following constant string. */ + outstring (end_of_spec, f - end_of_spec); } + while (*f != L_('\0')); - /* Now we know all the types and the order. Fill in the argument values. */ - for (cnt = 0; cnt < nargs; ++cnt) - switch (args_type[cnt]) + /* We processed the whole format without any positional parameters. */ + return done; + + /* Here starts the more complex loop to handle positional parameters. */ +do_positional: + { + /* Array with information about the needed arguments. This has to + be dynamically extendable. */ + size_t nspecs = 0; + size_t nspecs_max = 32; /* A more or less arbitrary start value. */ + struct printf_spec *specs + = alloca (nspecs_max * sizeof (struct printf_spec)); + + /* The number of arguments the format string requests. This will + determine the size of the array needed to store the argument + attributes. */ + size_t nargs = 0; + int *args_type; + union printf_arg *args_value; + + /* Positional parameters refer to arguments directly. This could + also determine the maximum number of arguments. Track the + maximum number. */ + size_t max_ref_arg = 0; + + /* Just a counter. */ + int cnt; + + + if (grouping == (const char *) -1) { + /* XXX Use wctob. But this is incompatible for now. */ + /* Figure out the thousands separator character. */ + if (mbtowc (&thousands_sep, + _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP), + strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0) + thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP); + grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); + if (*grouping == '\0' || *grouping == CHAR_MAX + || thousands_sep == L'\0') + grouping = NULL; + } + + for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt) + { + if (nspecs >= nspecs_max) + { + /* Extend the array of format specifiers. */ + struct printf_spec *old = specs; + + nspecs_max *= 2; + specs = alloca (nspecs_max * sizeof (struct printf_spec)); + + if (specs == &old[nspecs]) + /* Stack grows up, OLD was the last thing allocated; + extend it. */ + nspecs_max += nspecs_max / 2; + else + { + /* Copy the old array's elements to the new space. */ + memcpy (specs, old, nspecs * sizeof (struct printf_spec)); + if (old == &specs[nspecs]) + /* Stack grows down, OLD was just below the new + SPECS. We can use that space when the new space + runs out. */ + nspecs_max += nspecs_max / 2; + } + } + + /* Parse the format specifier. */ + nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg, NULL); + } + + /* Determine the number of arguments the format string consumes. */ + nargs = MAX (nargs, max_ref_arg); + + /* Allocate memory for the argument descriptions. */ + args_type = alloca (nargs * sizeof (int)); + memset (args_type, 0, nargs * sizeof (int)); + args_value = alloca (nargs * sizeof (union printf_arg)); + + /* XXX Could do sanity check here: If any element in ARGS_TYPE is + still zero after this loop, format is invalid. For now we + simply use 0 as the value. */ + + /* Fill in the types of all the arguments. */ + for (cnt = 0; cnt < nspecs; ++cnt) + { + /* If the width is determined by an argument this is an int. */ + if (specs[cnt].width_arg != -1) + args_type[specs[cnt].width_arg] = PA_INT; + + /* If the precision is determined by an argument this is an int. */ + if (specs[cnt].prec_arg != -1) + args_type[specs[cnt].prec_arg] = PA_INT; + + switch (specs[cnt].ndata_args) + { + case 0: /* No arguments. */ + break; + case 1: /* One argument; we already have the type. */ + args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type; + break; + default: + /* We have more than one argument for this format spec. + We must call the arginfo function again to determine + all the types. */ + (void) (*__printf_arginfo_table[specs[cnt].info.spec]) + (&specs[cnt].info, + specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]); + break; + } + } + + /* Now we know all the types and the order. Fill in the argument + values. */ + for (cnt = 0, ap = ap_save; cnt < nargs; ++cnt) + switch (args_type[cnt]) + { #define T(tag, mem, type) \ - case tag: \ - args_value[cnt].mem = va_arg (ap, type); \ - break + case tag: \ + args_value[cnt].mem = va_arg (ap, type); \ + break T (PA_CHAR, pa_char, int); /* Promoted. */ T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted. */ @@ -285,349 +1122,126 @@ vfprintf (s, format, ap) T (PA_STRING, pa_string, const char *); T (PA_POINTER, pa_pointer, void *); #undef T - default: - if ((args_type[cnt] & PA_FLAG_PTR) != 0) - args_value[cnt].pa_pointer = va_arg (ap, void *); - else - args_value[cnt].pa_long_double = 0.0; - break; - } - - /* Write the literal text before the first format. */ - outstring (format, lead_str_end - format); + default: + if ((args_type[cnt] & PA_FLAG_PTR) != 0) + args_value[cnt].pa_pointer = va_arg (ap, void *); + else + args_value[cnt].pa_long_double = 0.0; + break; + } - /* Now walk through all format specifiers and process them. */ - for (cnt = 0; cnt < nspecs; ++cnt) - { - printf_function *function; /* Auxiliary function to do output. */ - int is_neg; /* Decimal integer is negative. */ - int base; /* Base of a number to be written. */ - unsigned long long int num; /* Integral number to be written. */ - const char *str; /* String to be written. */ - char errorbuf[1024]; /* Buffer sometimes used by %m. */ - - if (specs[cnt].width_arg != -1) + /* Now walk through all format specifiers and process them. */ + for (; nspecs_done < nspecs; ++nspecs_done) + { +#undef REF +#define REF(Name) &&do2_##Name +#undef LABEL +#define LABEL(Name) do2_##Name + STEP4_TABLE; + + int is_negative; + union { - /* Extract the field width from an argument. */ - specs[cnt].info.width = args_value[specs[cnt].width_arg].pa_int; + unsigned long long int longlong; + unsigned long int word; + } number; + int base; + union printf_arg the_arg; + char *string; /* Pointer to argument string. */ + + /* Fill variables from values in struct. */ + int alt = specs[nspecs_done].info.alt; + int space = specs[nspecs_done].info.space; + int left = specs[nspecs_done].info.left; + int showsign = specs[nspecs_done].info.showsign; + int group = specs[nspecs_done].info.group; + int is_long_double = specs[nspecs_done].info.is_long_double; + int is_short = specs[nspecs_done].info.is_short; + int is_long = specs[nspecs_done].info.is_long; + int width = specs[nspecs_done].info.width; + int prec = specs[nspecs_done].info.prec; + char pad = specs[nspecs_done].info.pad; + CHAR_T spec = specs[nspecs_done].info.spec; + + /* Fill in last information. */ + if (specs[nspecs_done].width_arg != -1) + { + /* Extract the field width from an argument. */ + specs[nspecs_done].info.width = + args_value[specs[nspecs_done].width_arg].pa_int; + + if (specs[nspecs_done].info.width < 0) + /* If the width value is negative left justification is + selected and the value is taken as being positive. */ + { + specs[nspecs_done].info.width *= -1; + left = specs[nspecs_done].info.left = 1; + } + width = specs[nspecs_done].info.width; + } - if (specs[cnt].info.width < 0) - /* If the width value is negative left justification is selected - and the value is taken as being positive. */ - { - specs[cnt].info.width = -specs[cnt].info.width; - specs[cnt].info.left = 1; - } - } + if (specs[nspecs_done].prec_arg != -1) + { + /* Extract the precision from an argument. */ + specs[nspecs_done].info.prec = + args_value[specs[nspecs_done].prec_arg].pa_int; - if (specs[cnt].prec_arg != -1) - { - /* Extract the precision from an argument. */ - specs[cnt].info.prec = args_value[specs[cnt].prec_arg].pa_int; + if (specs[nspecs_done].info.prec < 0) + /* If the precision is negative the precision is + omitted. */ + specs[nspecs_done].info.prec = -1; - if (specs[cnt].info.prec < 0) - /* If the precision is negative the precision is omitted. */ - specs[cnt].info.prec = -1; - } + prec = specs[nspecs_done].info.prec; + } - /* Check for a user-defined handler for this spec. */ - function = (__printf_function_table == NULL ? NULL : - __printf_function_table[specs[cnt].info.spec]); + /* Process format specifiers. */ + while (1) + { + JUMP (spec, step4_jumps); - if (function != NULL) - use_function: /* Built-in formats with helpers use this. */ - { - int function_done; - unsigned int i; - const void *ptr[specs[cnt].ndata_args]; + process_arg ((&specs[nspecs_done])); - /* Fill in an array of pointers to the argument values. */ - for (i = 0; i < specs[cnt].ndata_args; ++i) - ptr[i] = &args_value[specs[cnt].data_arg + i]; + LABEL (form_unknown): + { + extern printf_function **__printf_function_table; + int function_done; + printf_function *function; + unsigned int i; + const void **ptr; - /* Call the function. */ - function_done = (*function) (s, &specs[cnt].info, ptr); + function = + (__printf_function_table == NULL ? NULL : + __printf_function_table[specs[nspecs_done].info.spec]); - /* If an error occured don't do any further work. */ - if (function_done < 0) - return -1; + if (function == NULL) + function = &printf_unknown; - done += function_done; - } - else - switch (specs[cnt].info.spec) - { - case '%': - /* Write a literal "%". */ - outchar ('%'); - break; - case 'i': - case 'd': - { - long long int signed_num; - - /* Decimal integer. */ - base = 10; - if (specs[cnt].info.is_longlong) - signed_num = args_value[specs[cnt].data_arg].pa_long_long_int; - else if (specs[cnt].info.is_long) - signed_num = args_value[specs[cnt].data_arg].pa_long_int; - else if (!specs[cnt].info.is_short) - signed_num = args_value[specs[cnt].data_arg].pa_int; - else - signed_num = args_value[specs[cnt].data_arg].pa_short_int; - - is_neg = signed_num < 0; - num = is_neg ? (- signed_num) : signed_num; - goto number; - } + ptr = alloca (specs[nspecs_done].ndata_args + * sizeof (const void *)); + + /* Fill in an array of pointers to the argument values. */ + for (i = 0; i < specs[nspecs_done].ndata_args; ++i) + ptr[i] = &args_value[specs[nspecs_done].data_arg + i]; - case 'u': - /* Decimal unsigned integer. */ - base = 10; - goto unsigned_number; - - case 'o': - /* Octal unsigned integer. */ - base = 8; - goto unsigned_number; - - case 'X': - /* Hexadecimal unsigned integer. */ - case 'x': - /* Hex with lower-case digits. */ - base = 16; - - unsigned_number: - /* Unsigned number of base BASE. */ - - if (specs[cnt].info.is_longlong) - num = args_value[specs[cnt].data_arg].pa_u_long_long_int; - else if (specs[cnt].info.is_long) - num = args_value[specs[cnt].data_arg].pa_u_long_int; - else if (!specs[cnt].info.is_short) - num = args_value[specs[cnt].data_arg].pa_u_int; - else - num = args_value[specs[cnt].data_arg].pa_u_short_int; - - /* ANSI only specifies the `+' and - ` ' flags for signed conversions. */ - is_neg = 0; - specs[cnt].info.showsign = 0; - specs[cnt].info.space = 0; - - number: - /* Number of base BASE. */ - { - char work[BUFSIZ]; - char *const workend = &work[sizeof(work) - 1]; - register char *w; - - if (specs[cnt].info.prec == -1) - /* Supply a default precision if none was given. */ - specs[cnt].info.prec = 1; - else - /* We have to take care for the '0' flag. If a - precision is given it must be ignored. */ - specs[cnt].info.pad = ' '; - - /* If the precision is 0 and the number is 0 nothing has - to be written for the number. */ - if (specs[cnt].info.prec == 0 && num == 0) - w = workend; - else - { - /* Put the number in WORK. */ - w = _itoa (num, workend + 1, base, - specs[cnt].info.spec == 'X'); - w -= 1; - if (specs[cnt].info.group && grouping) - w = group_number (w, workend, grouping, thousands_sep); - } - specs[cnt].info.width -= workend - w; - specs[cnt].info.prec -= workend - w; - - if (num != 0 && specs[cnt].info.alt && base == 8 - && specs[cnt].info.prec <= 0) - { - /* Add octal marker. */ - *w-- = '0'; - --specs[cnt].info.width; - } - - if (specs[cnt].info.prec > 0) - { - /* Add zeros to the precision. */ - specs[cnt].info.width -= specs[cnt].info.prec; - while (specs[cnt].info.prec-- > 0) - *w-- = '0'; - } - - if (num != 0 && specs[cnt].info.alt && base == 16) - /* Account for 0X hex marker. */ - specs[cnt].info.width -= 2; - - if (is_neg || specs[cnt].info.showsign || specs[cnt].info.space) - --specs[cnt].info.width; - - if (!specs[cnt].info.left && specs[cnt].info.pad == ' ') - PAD (' '); - - if (is_neg) - outchar ('-'); - else if (specs[cnt].info.showsign) - outchar ('+'); - else if (specs[cnt].info.space) - outchar (' '); - - if (num != 0 && specs[cnt].info.alt && base == 16) - { - outchar ('0'); - outchar (specs[cnt].info.spec); - } - - if (!specs[cnt].info.left && specs[cnt].info.pad == '0') - PAD ('0'); - - /* Write the number. */ - while (++w <= workend) - outchar (*w); - - if (specs[cnt].info.left) - PAD (' '); - } - break; - - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - { - /* Floating-point number. This is handled by printf_fp.c. */ - extern printf_function __printf_fp; - function = __printf_fp; - goto use_function; - } - - case 'c': - /* Character. */ - --specs[cnt].info.width;/* Account for the character itself. */ - if (!specs[cnt].info.left) - PAD (' '); - outchar ((unsigned char) args_value[specs[cnt].data_arg].pa_char); - if (specs[cnt].info.left) - PAD (' '); - break; - - case 's': - { - static const char null[] = "(null)"; - size_t len; - - str = args_value[specs[cnt].data_arg].pa_string; - - string: - - if (str == NULL) - { - /* Write "(null)" if there's space. */ - if (specs[cnt].info.prec == -1 - || specs[cnt].info.prec >= (int) sizeof (null) - 1) - { - str = null; - len = sizeof (null) - 1; - } - else - { - str = ""; - len = 0; - } - } - else if (specs[cnt].info.prec != -1) - { - /* Search for the end of the string, but don't search - past the length specified by the precision. */ - const char *end = memchr (str, '\0', specs[cnt].info.prec); - if (end) - len = end - str; - else - len = specs[cnt].info.prec; - } - else - len = strlen (str); - - specs[cnt].info.width -= len; - - if (!specs[cnt].info.left) - PAD (' '); - outstring (str, len); - if (specs[cnt].info.left) - PAD (' '); - } - break; - - case 'p': - /* Generic pointer. */ - { - const void *ptr; - ptr = args_value[specs[cnt].data_arg].pa_pointer; - if (ptr != NULL) - { - /* If the pointer is not NULL, write it as a %#x spec. */ - base = 16; - num = (unsigned long long int) (unsigned long int) ptr; - is_neg = 0; - specs[cnt].info.alt = 1; - specs[cnt].info.spec = 'x'; - specs[cnt].info.group = 0; - goto number; - } - else - { - /* Write "(nil)" for a nil pointer. */ - str = "(nil)"; - /* Make sure the full string "(nil)" is printed. */ - if (specs[cnt].info.prec < 5) - specs[cnt].info.prec = 5; - goto string; - } - } - break; - - case 'n': - /* Answer the count of characters written. */ - if (specs[cnt].info.is_longlong) - *(long long int *) - args_value[specs[cnt].data_arg].pa_pointer = done; - else if (specs[cnt].info.is_long) - *(long int *) - args_value[specs[cnt].data_arg].pa_pointer = done; - else if (!specs[cnt].info.is_short) - *(int *) - args_value[specs[cnt].data_arg].pa_pointer = done; - else - *(short int *) - args_value[specs[cnt].data_arg].pa_pointer = done; - break; - - case 'm': - { - extern char *_strerror_internal __P ((int, char *buf, size_t)); - str = _strerror_internal (errno, errorbuf, sizeof errorbuf); - goto string; - } - - default: - /* Unrecognized format specifier. */ - function = printf_unknown; - goto use_function; + /* Call the function. */ + function_done = (*function) (s, &specs[nspecs_done].info, ptr); + + /* If an error occured we don't have information about # + of chars. */ + if (function_done < 0) + return -1; + + done += function_done; + } + break; } - /* Write the following constant string. */ - outstring (specs[cnt].end_of_fmt, - specs[cnt].next_fmt - specs[cnt].end_of_fmt); - } + /* Write the following constant string. */ + outstring (specs[nspecs_done].end_of_fmt, + specs[nspecs_done].next_fmt + - specs[nspecs_done].end_of_fmt); + } + } return done; } @@ -636,7 +1250,7 @@ vfprintf (s, format, ap) # undef vfprintf # ifdef strong_alias /* This is for glibc. */ -strong_alias (_IO_vfprintf, vfprintf) +strong_alias (_IO_vfprintf, vfprintf); # else # if defined __ELF__ || defined __GNU_LIBRARY__ # include @@ -646,20 +1260,16 @@ weak_alias (_IO_vfprintf, vfprintf); # endif # endif #endif - - + /* Handle an unknown format specifier. This prints out a canonicalized representation of the format spec itself. */ - static int -printf_unknown (s, info, args) - FILE *s; - const struct printf_info *info; - const void *const *args; +printf_unknown (FILE *s, const struct printf_info *info, + const void *const *args) + { int done = 0; - char work[BUFSIZ]; - char *const workend = &work[sizeof(work) - 1]; + char work_buffer[BUFSIZ]; register char *w; outchar ('%'); @@ -679,7 +1289,7 @@ printf_unknown (s, info, args) if (info->width != 0) { - w = _itoa (info->width, workend + 1, 10, 0); + w = _itoa_word (info->width, workend + 1, 10, 0); while (++w <= workend) outchar (*w); } @@ -687,7 +1297,7 @@ printf_unknown (s, info, args) if (info->prec != -1) { outchar ('.'); - w = _itoa (info->prec, workend + 1, 10, 0); + w = _itoa_word (info->prec, workend + 1, 10, 0); while (++w <= workend) outchar (*w); } @@ -700,9 +1310,8 @@ printf_unknown (s, info, args) /* Group the digits according to the grouping rules of the current locale. The interpretation of GROUPING is as in `struct lconv' from . */ - static char * -group_number (char *w, char *workend, const char *grouping, +group_number (CHAR_T *w, CHAR_T *rear_ptr, const CHAR_T *grouping, wchar_t thousands_sep) { int len; @@ -717,10 +1326,10 @@ group_number (char *w, char *workend, const char *grouping, len = *grouping; /* Copy existing string so that nothing gets overwritten. */ - src = (char *) alloca (workend - w); - memcpy (src, w + 1, workend - w); - s = &src[workend - w - 1]; - w = workend; + src = (char *) alloca (rear_ptr - w); + memcpy (src, w + 1, rear_ptr - w); + s = &src[rear_ptr - w - 1]; + w = rear_ptr; /* Process all characters in the string. */ while (s >= src) @@ -772,32 +1381,30 @@ _IO_helper_overflow (_IO_FILE *s, int c) } static const struct _IO_jump_t _IO_helper_jumps = - { - JUMP_INIT_DUMMY, - JUMP_INIT (finish, _IO_default_finish), - JUMP_INIT (overflow, _IO_helper_overflow), - JUMP_INIT (underflow, _IO_default_underflow), - JUMP_INIT (uflow, _IO_default_uflow), - JUMP_INIT (pbackfail, _IO_default_pbackfail), - JUMP_INIT (xsputn, _IO_default_xsputn), - JUMP_INIT (xsgetn, _IO_default_xsgetn), - JUMP_INIT (seekoff, _IO_default_seekoff), - JUMP_INIT (seekpos, _IO_default_seekpos), - JUMP_INIT (setbuf, _IO_default_setbuf), - JUMP_INIT (sync, _IO_default_sync), - JUMP_INIT (doallocate, _IO_default_doallocate), - JUMP_INIT (read, _IO_default_read), - JUMP_INIT (write, _IO_default_write), - JUMP_INIT (seek, _IO_default_seek), - JUMP_INIT (close, _IO_default_close), - JUMP_INIT (stat, _IO_default_stat) - }; +{ + JUMP_INIT_DUMMY, + JUMP_INIT (finish, _IO_default_finish), + JUMP_INIT (overflow, _IO_helper_overflow), + JUMP_INIT (underflow, _IO_default_underflow), + JUMP_INIT (uflow, _IO_default_uflow), + JUMP_INIT (pbackfail, _IO_default_pbackfail), + JUMP_INIT (xsputn, _IO_default_xsputn), + JUMP_INIT (xsgetn, _IO_default_xsgetn), + JUMP_INIT (seekoff, _IO_default_seekoff), + JUMP_INIT (seekpos, _IO_default_seekpos), + JUMP_INIT (setbuf, _IO_default_setbuf), + JUMP_INIT (sync, _IO_default_sync), + JUMP_INIT (doallocate, _IO_default_doallocate), + JUMP_INIT (read, _IO_default_read), + JUMP_INIT (write, _IO_default_write), + JUMP_INIT (seek, _IO_default_seek), + JUMP_INIT (close, _IO_default_close), + JUMP_INIT (stat, _IO_default_stat) +}; static int -buffered_vfprintf (s, format, args) - register _IO_FILE *s; - char const *format; - _IO_va_list args; +buffered_vfprintf (register _IO_FILE *s, const CHAR_T *format, + _IO_va_list args) { char buf[_IO_BUFSIZ]; struct helper_file helper; @@ -828,10 +1435,7 @@ buffered_vfprintf (s, format, args) #else /* !USE_IN_LIBIO */ static int -buffered_vfprintf (s, format, args) - register FILE *s; - char const *format; - va_list args; +buffered_vfprintf (register FILE *s, const CHAR_T *format, va_list args) { char buf[BUFSIZ]; int result; @@ -851,26 +1455,28 @@ buffered_vfprintf (s, format, args) return result; } - - + /* Pads string with given number of a specified character. This code is taken from iopadn.c of the GNU I/O library. */ #define PADSIZE 16 -static const char blanks[PADSIZE] = -{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; -static const char zeroes[PADSIZE] = -{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; +static const CHAR_T blanks[PADSIZE] = +{ L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), + L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' '), L_(' ') }; +static const CHAR_T zeroes[PADSIZE] = +{ L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), + L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0'), L_('0') }; ssize_t -__printf_pad (s, pad, count) - FILE *s; - char pad; - size_t count; +#ifndef COMPILE_WPRINTF +__printf_pad (FILE *s, char pad, size_t count) +#else +__wprintf_pad (FILE *s, wchar_t pad, size_t count) +#endif { - const char *padptr; + const CHAR_T *padptr; register size_t i; - padptr = pad == ' ' ? blanks : zeroes; + padptr = pad == L_(' ') ? blanks : zeroes; for (i = count; i >= PADSIZE; i -= PADSIZE) if (PUT (s, padptr, PADSIZE) != PADSIZE) diff --git a/stdlib/strtod.c b/stdlib/strtod.c index 3818c81ecb..51dc520c01 100644 --- a/stdlib/strtod.c +++ b/stdlib/strtod.c @@ -481,20 +481,12 @@ INTERNAL (STRTOF) (nptr, endptr, group) /* Read the fractional digits. A special case are the 'american style' numbers like `16.' i.e. with decimal but without trailing digits. */ if (c == decimal) - { - if (isdigit (cp[1])) - { - c = *++cp; - do - { - if (c != '0' && lead_zero == -1) - lead_zero = dig_no - int_no; - ++dig_no; - c = *++cp; - } - while (isdigit (c)); - } - } + while (isdigit (c = *++cp)) + { + if (c != '0' && lead_zero == -1) + lead_zero = dig_no - int_no; + ++dig_no; + } /* Remember start of exponent (if any). */ expp = cp; diff --git a/sysdeps/generic/setenv.c b/sysdeps/generic/setenv.c index dc2e8b43f3..7bbd0acbab 100644 --- a/sysdeps/generic/setenv.c +++ b/sysdeps/generic/setenv.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1992, 1995 Free Software Foundation, Inc. +/* Copyright (C) 1992, 1995, 1996 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 @@ -108,7 +108,8 @@ setenv (name, value, replace) } void -unsetenv (const char *name) +unsetenv (name) + const char *name; { const size_t len = strlen (name); char **ep; diff --git a/wcsmbs/Makefile b/wcsmbs/Makefile index 6d75c7b01f..99d9dd5010 100644 --- a/wcsmbs/Makefile +++ b/wcsmbs/Makefile @@ -21,11 +21,12 @@ # subdir := wcsmbs -headers := wcstr.h mbstr.h +headers := wchar.h -routines := mbsadvance mbscat mbschr mbscmp mbscpy mbsdup mbslen \ - mbsncat mbsncmp mbsncpy mbsrchr mbstomb wcscat wcschr wcscmp\ - wcscpy wcscspn wcsdup wcslen wcsncat wcsncmp wcsncpy wcspbrk\ - wcsrchr wcsspn wcstok wcswcs +routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \ + wcsncmp wcsncpy wcspbrk wcsrchr wcsspn wcstok wcsstr wmemchr \ + wmemcmp wmemcpy wmemmove wmemset \ + btowc wctob mbsinit \ + mbrlen mbrtowc wcrtomb mbsrtowcs wcsrtombs include ../Rules diff --git a/wcsmbs/mbsadvance.c b/wcsmbs/mbsadvance.c deleted file mode 100644 index b6649935d7..0000000000 --- a/wcsmbs/mbsadvance.c +++ /dev/null @@ -1,38 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Advance pointer to multibyte string by one character. */ -char * -mbsadvance (mbs) - const char *mbs; -{ - int clen; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - clen = mblen (mbs, MB_CUR_MAX); - - /* FIXME: when current character is illegal return same character. */ - return clen <= 0 ? (char *) mbs : (char *) (mbs + clen); -} - diff --git a/wcsmbs/mbscat.c b/wcsmbs/mbscat.c deleted file mode 100644 index 324cad9cc8..0000000000 --- a/wcsmbs/mbscat.c +++ /dev/null @@ -1,56 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Append SRC onto DEST. */ -char * -mbscat (dest, src) - char *dest; - const char *src; -{ - const char * const d = dest; - size_t len = 0; - int clen = 0; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - dest += clen; - clen = mblen (dest, MB_CUR_MAX); - } - while (clen > 0); - - clen = 0; - do - { - len += clen; - clen = mblen (&src[len], MB_CUR_MAX); - } - while (clen > 0); - - (void) memcpy ((void *) dest, (void *) src, len); - dest[len] = '\0'; /* '\0' is the multibyte representation of L'\0' */ - - return (char *) d; -} - diff --git a/wcsmbs/mbschr.c b/wcsmbs/mbschr.c deleted file mode 100644 index f8a7d21857..0000000000 --- a/wcsmbs/mbschr.c +++ /dev/null @@ -1,60 +0,0 @@ -/* 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. */ - -#include -#include - -#define __need_wchar_t -#include - - -/* Find the first occurence of MBC in MBS. */ -char * -mbschr (mbs, mbc) - const char *mbs; - mbchar_t mbc; -{ - int clen; - wchar_t wc; - wchar_t c; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - clen = mbtowc (&wc, (char *) &mbc, MB_CUR_MAX); - if (clen < 0) - /* FIXME: search character is illegal. */ - return NULL; - else if (clen == 0) - wc = L'\0'; - - clen = 0; - do - { - mbs += clen; - clen = mbtowc (&c, mbs, MB_CUR_MAX); - } - while (clen > 0 && c != wc); - - if (clen < 0 || (clen == 0 && wc != L'\0')) - /* FIXME: clen < 0 means illegal character in string. */ - return NULL; - - return (char *) mbs; -} - diff --git a/wcsmbs/mbscpy.c b/wcsmbs/mbscpy.c deleted file mode 100644 index 8f354ceede..0000000000 --- a/wcsmbs/mbscpy.c +++ /dev/null @@ -1,47 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Copy SRC to DEST. */ -char * -mbscpy (dest, src) - char *dest; - const char *src; -{ - size_t len = 0; - int clen = 0; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - len += clen; - clen = mblen (&src[len], MB_CUR_MAX); - } - while (clen > 0); - - (void) memcpy ((void *) dest, (void *) src, len); - dest[len] = '\0'; /* '\0' is the multibyte representation of L'\0' */ - - return dest; -} - diff --git a/wcsmbs/mbsdup.c b/wcsmbs/mbsdup.c deleted file mode 100644 index 2d196dd06d..0000000000 --- a/wcsmbs/mbsdup.c +++ /dev/null @@ -1,51 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Duplicate MBS, returning an identical malloc'd string. */ -char * -mbsdup (mbs) - const char *mbs; -{ - size_t len = 0; - int clen = 0; - char *retval; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - len += clen; - clen = mblen (&mbs[len], MB_CUR_MAX); - } - while (clen > 0); - - retval = (char *) malloc (len + 1); - if (retval != NULL) - { - (void) memcpy ((void *) retval, (void *) mbs, len); - retval[len] = '\0'; /* '\0' is the multibyte representation of L'\0' */ - } - - return retval; -} - diff --git a/wcsmbs/mbslen.c b/wcsmbs/mbslen.c deleted file mode 100644 index f8077d0fb9..0000000000 --- a/wcsmbs/mbslen.c +++ /dev/null @@ -1,45 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Return the length of MBS. */ -size_t -mbslen (mbs) - const char *mbs; -{ - size_t len = 0; - int clen = 0; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - len += clen; - clen = mblen (&mbs[len], MB_CUR_MAX); - } - while (clen > 0); - - /* FIXME: if string contains an illegal character the length upto this - character is returned. */ - return len; -} - diff --git a/wcsmbs/mbsncat.c b/wcsmbs/mbsncat.c deleted file mode 100644 index 3dd4df1c70..0000000000 --- a/wcsmbs/mbsncat.c +++ /dev/null @@ -1,61 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Append no more than N multi-byte characters from SRC onto DEST. */ -char * -mbsncat (dest, src, n) - char *dest; - const char *src; - size_t n; -{ - const char * const d = dest; - const char * const s = src; - size_t len = 0; - int clen = 0; - - if (n == 0) - return (char *) d; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - dest += clen; - clen = mblen (dest, MB_CUR_MAX); - } - while (clen > 0); - - clen = 0; - do - { - src += clen; - clen = mblen (src, MB_CUR_MAX); - } - while (clen > 0 && ++len < n); - - (void) memcpy ((void *) dest, (void *) s, src - s); - dest[src - s] = '\0'; /* '\0' is the multibyte representation of L'\0' */ - - return (char *) d; -} - diff --git a/wcsmbs/mbsncmp.c b/wcsmbs/mbsncmp.c deleted file mode 100644 index 43fb527afb..0000000000 --- a/wcsmbs/mbsncmp.c +++ /dev/null @@ -1,68 +0,0 @@ -/* 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. */ - -#include -#include - -#define __need_wchar_t -/* FIXME: should be defined in stddef.h. -!!! #define __need_uwchar_t */ -typedef unsigned int uwchar_t; -#include - - -/* Compare N characters of MBS1 and MBS2. */ -int -mbsncmp (mbs1, mbs2, n) - const char *mbs1; - const char *mbs2; - size_t n; -{ - size_t len = 0; - int clen1 = 0; - int clen2 = 0; - uwchar_t c1; - uwchar_t c2; - - if (n == 0) - return 0; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - clen1 = mbtowc ((wchar_t *) &c1, mbs1, MB_CUR_MAX); - clen2 = mbtowc ((wchar_t *) &c2, mbs2, MB_CUR_MAX); - - if (clen1 == 0) - return clen2 == 0 ? 0 : -1; - if (clen2 == 0) - return 1; - if (clen1 < 0 || clen2 < 0) - /* FIXME: an illegal character appears. What to do? */ - return c1 - c2; - - mbs1 += clen1; - mbs2 += clen2; - } - while (c1 == c2 && ++len < n); - - return len < n ? c1 - c2 : 0; -} - diff --git a/wcsmbs/mbsncpy.c b/wcsmbs/mbsncpy.c deleted file mode 100644 index 09aecefd03..0000000000 --- a/wcsmbs/mbsncpy.c +++ /dev/null @@ -1,55 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Copy no more than N characters of SRC to DEST. */ -char * -mbsncpy (dest, src, n) - char *dest; - const char *src; - size_t n; -{ - const char * const s = src; - size_t len = 0; - int clen = 0; - - if (n == 0) - { - dest[0] = '\0'; /* '\0' is the multibyte representation of L'\0' */ - return dest; - } - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - do - { - src += clen; - clen = mblen (src, MB_CUR_MAX); - } - while (clen > 0 && ++len < n); - - (void) memcpy ((void *) dest, (void *) s, src - s); - dest[src - s] = '\0'; /* '\0' is the multibyte representation of L'\0' */ - - return dest; -} - diff --git a/wcsmbs/mbsrchr.c b/wcsmbs/mbsrchr.c deleted file mode 100644 index 62fa219dd2..0000000000 --- a/wcsmbs/mbsrchr.c +++ /dev/null @@ -1,61 +0,0 @@ -/* 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. */ - -#include -#include - -#define __need_wchar_t -#include - - -/* Find the last occurence of MBC in MBS. */ -char * -mbsrchr (mbs, mbc) - const char *mbs; - mbchar_t mbc; -{ - const char * retval = NULL; - int clen; - wchar_t wc; - wchar_t c; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - clen = mbtowc (&wc, (char *) &mbc, MB_CUR_MAX); - if (clen < 0) - /* FIXME: search character MBC is illegal. */ - return NULL; - else if (clen == 0) - wc = L'\0'; - - clen = 0; - do - { - mbs += clen; - clen = mbtowc (&c, mbs, MB_CUR_MAX); - } - while (clen > 0 && c != wc); - - if (clen < 0) - /* FIXME: clen < 0 means illegal character in string. */ - return NULL; - - return (char *) (clen > 0 || (clen == 0 && wc == L'\0') ? mbs : retval); -} - diff --git a/wcsmbs/mbstomb.c b/wcsmbs/mbstomb.c deleted file mode 100644 index f593ced3cb..0000000000 --- a/wcsmbs/mbstomb.c +++ /dev/null @@ -1,42 +0,0 @@ -/* 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. */ - -#include -#include - - -/* Advance pointer to multibyte string by one character. */ -mbchar_t -mbstomb (mbs) - const char *mbs; -{ - mbchar_t retval = 0; - int clen; - - /* Reset multibyte characters to their initial state. */ - (void) mblen ((char *) NULL, 0); - - clen = mblen (mbs, MB_CUR_MAX); - - if (clen > 0) - (void) memcpy (&retval, mbs, clen); - - /* FIXME: when current character is illegal return '\0'. */ - return retval; -} - diff --git a/wcsmbs/mbstr.h b/wcsmbs/mbstr.h deleted file mode 100644 index 7cb94bf85b..0000000000 --- a/wcsmbs/mbstr.h +++ /dev/null @@ -1,69 +0,0 @@ -/* 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 _MBSTRING_H - -#define _MBSTRING_H 1 -#include -#include - -#define __need_size_t -#include - -__BEGIN_DECLS - -/* This data type should be large enough to contain MB_CUR_MAX bytes. */ -typedef unsigned int mbchar_t; - - -/* Copy SRC to DEST. */ -extern char *mbscpy __P ((char *__dest, __const char *__src)); -/* Copy no more than N multi-byte characters of SRC to DEST. */ -extern char *mbsncpy __P ((char *__dest, __const char *__src, size_t __n)); - -/* Append SRC onto DEST. */ -extern char *mbscat __P ((char *__dest, __const char *__src)); -/* Append no more than N characters from SRC onto DEST. */ -extern char *mbsncat __P ((char *__dest, __const char *__src, size_t __n)); - -/* Compare S1 and S2. */ -extern int mbscmp __P ((__const char *__s1, __const char *__s2)); -/* Compare N characters of S1 and S2. */ -extern int mbsncmp __P ((__const char *__s1, __const char *__s2, size_t __n)); - -/* Duplicate MBS, returning an identical malloc'd string. */ -extern char *mbsdup __P ((__const char *__s)); - -/* Find the first occurence of MBC in MBS. */ -extern char *mbschr __P ((__const char *__mbs, mbchar_t mbc)); -/* Find the last occurence of MBC in MBS. */ -extern char *mbsrchr __P ((__const char *__mbs, mbchar_t mbc)); - -/* Return the length of MBS. */ -extern size_t mbslen __P ((__const char *__mbs)); - - -/* Advance pointer to multibyte string by one character. */ -extern char *mbsadvance __P ((__const char *__mbs)); - -/* Return first character in MBS. */ -extern mbchar_t mbstomb __P ((__const char *__mbs)); - -__END_DECLS - -#endif /* mbstring.h */ diff --git a/wcsmbs/wcscat.c b/wcsmbs/wcscat.c index 4ff5c861e4..e142806fae 100644 --- a/wcsmbs/wcscat.c +++ b/wcsmbs/wcscat.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,14 +17,14 @@ 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 +#include /* Append SRC on the end of DEST. */ wchar_t * wcscat (dest, src) - wchar_t *dest; - const wchar_t *src; + wchar_t *dest; + const wchar_t *src; { register wchar_t *s1 = dest; register const wchar_t *s2 = src; diff --git a/wcsmbs/wcschr.c b/wcsmbs/wcschr.c index 85a1801839..64af0bf456 100644 --- a/wcsmbs/wcschr.c +++ b/wcsmbs/wcschr.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 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 @@ -16,14 +16,14 @@ 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 +#include /* Find the first ocurrence of WC in WCS. */ wchar_t * wcschr (wcs, wc) - register const wchar_t *wcs; - register const wchar_t wc; + register const wchar_t *wcs; + register const wchar_t wc; { while (*wcs != L'\0') if (*wcs == wc) diff --git a/wcsmbs/wcscmp.c b/wcsmbs/wcscmp.c index 84ecae8553..08da116787 100644 --- a/wcsmbs/wcscmp.c +++ b/wcsmbs/wcscmp.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,16 +17,16 @@ 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 +#include /* Compare S1 and S2, returning less than, equal to or - greater than zero if S1 is lexiographically less than, + greater than zero if S1 is lexicographically less than, equal to or greater than S2. */ int wcscmp (s1, s2) - const wchar_t *s1; - const wchar_t *s2; + const wchar_t *s1; + const wchar_t *s2; { uwchar_t c1, c2; diff --git a/wcsmbs/wcscpy.c b/wcsmbs/wcscpy.c index a45747edf1..3aa897ec7f 100644 --- a/wcsmbs/wcscpy.c +++ b/wcsmbs/wcscpy.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,7 +17,7 @@ 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 +#include #define __need_ptrdiff_t #include @@ -25,8 +26,8 @@ Cambridge, MA 02139, USA. */ /* Copy SRC to DEST. */ wchar_t * wcscpy (dest, src) - wchar_t *dest; - const wchar_t *src; + wchar_t *dest; + const wchar_t *src; { wchar_t *wcp = (wchar_t *) src; wchar_t c; diff --git a/wcsmbs/wcscspn.c b/wcsmbs/wcscspn.c index 0dc4d9bc9e..7ab8f278fd 100644 --- a/wcsmbs/wcscspn.c +++ b/wcsmbs/wcscspn.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,15 +17,15 @@ 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 +#include /* Return the length of the maximum initial segment of WCS which contains only wide-characters not in REJECT. */ size_t wcscspn (wcs, reject) - const wchar_t *wcs; - const wchar_t *reject; + const wchar_t *wcs; + const wchar_t *reject; { register size_t count = 0; diff --git a/wcsmbs/wcsdup.c b/wcsmbs/wcsdup.c index 62c64621de..c24ba96f88 100644 --- a/wcsmbs/wcsdup.c +++ b/wcsmbs/wcsdup.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,7 +17,7 @@ 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 +#include #include #include @@ -24,7 +25,7 @@ Cambridge, MA 02139, USA. */ /* Duplicate S, returning an identical malloc'd string. */ wchar_t * wcsdup (s) - const wchar_t *s; + const wchar_t *s; { size_t len = (wcslen (s) + 1) * sizeof (wchar_t); void *new = malloc (len); diff --git a/wcsmbs/wcslen.c b/wcsmbs/wcslen.c index 2907cb3cc4..1ce365f8c4 100644 --- a/wcsmbs/wcslen.c +++ b/wcsmbs/wcslen.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,13 +17,13 @@ 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 +#include /* Copy SRC to DEST. */ size_t wcslen (s) - const wchar_t *s; + const wchar_t *s; { size_t len = 0; diff --git a/wcsmbs/wcsncat.c b/wcsmbs/wcsncat.c index 7851d7048d..48d54603d6 100644 --- a/wcsmbs/wcsncat.c +++ b/wcsmbs/wcsncat.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,15 +17,15 @@ 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 +#include /* Append no more than N wide-character of SRC onto DEST. */ wchar_t * wcsncat (dest, src, n) - wchar_t *dest; - const wchar_t *src; - size_t n; + wchar_t *dest; + const wchar_t *src; + size_t n; { wchar_t c; wchar_t * const s = dest; diff --git a/wcsmbs/wcsncmp.c b/wcsmbs/wcsncmp.c index 9f1829bc5d..3df6bfc151 100644 --- a/wcsmbs/wcsncmp.c +++ b/wcsmbs/wcsncmp.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,7 +17,7 @@ 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 +#include /* Compare no more than N characters of S1 and S2, @@ -25,9 +26,9 @@ Cambridge, MA 02139, USA. */ greater than S2. */ int wcsncmp (s1, s2, n) - const wchar_t *s1; - const wchar_t *s2; - size_t n; + const wchar_t *s1; + const wchar_t *s2; + size_t n; { uwchar_t c1 = L'\0'; uwchar_t c2 = L'\0'; diff --git a/wcsmbs/wcsncpy.c b/wcsmbs/wcsncpy.c index 740c71ecf8..180da794d7 100644 --- a/wcsmbs/wcsncpy.c +++ b/wcsmbs/wcsncpy.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,18 +17,18 @@ 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 +#include /* Copy no more than N wide-characters of SRC to DEST. */ wchar_t * wcsncpy (dest, src, n) - wchar_t *dest; - const wchar_t *src; - size_t n; + wchar_t *dest; + const wchar_t *src; + size_t n; { wchar_t c; - wchar_t * const s = dest; + wchar_t *const s = dest; --dest; diff --git a/wcsmbs/wcspbrk.c b/wcsmbs/wcspbrk.c index 83892bacb0..91c5573722 100644 --- a/wcsmbs/wcspbrk.c +++ b/wcsmbs/wcspbrk.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,14 +17,14 @@ 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 +#include /* Find the first ocurrence in WCS of any wide-character in ACCEPT. */ wchar_t * wcspbrk (wcs, accept) - register const wchar_t *wcs; - register const wchar_t *accept; + register const wchar_t *wcs; + register const wchar_t *accept; { while (*wcs != L'\0') if (wcschr (accept, *wcs) == NULL) diff --git a/wcsmbs/wcsrchr.c b/wcsmbs/wcsrchr.c index 87823b3709..ae31dc4104 100644 --- a/wcsmbs/wcsrchr.c +++ b/wcsmbs/wcsrchr.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,14 +17,14 @@ 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 +#include /* Find the last ocurrence of WC in WCS. */ wchar_t * wcsrchr (wcs, wc) - register const wchar_t *wcs; - register const wchar_t wc; + register const wchar_t *wcs; + register const wchar_t wc; { const wchar_t *retval = NULL; diff --git a/wcsmbs/wcsspn.c b/wcsmbs/wcsspn.c index 81a557c7b7..158e35ee97 100644 --- a/wcsmbs/wcsspn.c +++ b/wcsmbs/wcsspn.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,15 +17,15 @@ 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 +#include /* Return the length of the maximum initial segment of WCS which contains only wide-characters in ACCEPT. */ size_t wcsspn (wcs, accept) - const wchar_t *wcs; - const wchar_t *accept; + const wchar_t *wcs; + const wchar_t *accept; { register const wchar_t *p; register const wchar_t *a; diff --git a/wcsmbs/wcstok.c b/wcsmbs/wcstok.c index 191bbd5960..376fe7bfcb 100644 --- a/wcsmbs/wcstok.c +++ b/wcsmbs/wcstok.c @@ -1,5 +1,6 @@ -/* Copyright (C) 1995 Free Software Foundation, Inc. +/* Copyright (C) 1995, 1996 Free Software Foundation, Inc. This file is part of the GNU C Library. +Contributed by Ulrich Drepper, 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 @@ -16,52 +17,42 @@ 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 +#include #include -static wchar_t *olds = NULL; - -/* Parse WCS into tokens separated by characters in DELIM. - If WCS is NULL, the last string wcstok() was called with is - used. */ +/* Parse WCS into tokens separated by characters in DELIM. If WCS is + NULL, the last string wcstok() was called with is used. */ wchar_t * -wcstok (wcs, delim) - register wchar_t *wcs; - register const wchar_t *delim; +wcstok (wcs, delim, ptr) + register wchar_t *wcs; + register const wchar_t *delim; + register wchar_t **ptr; { - wchar_t *token; + wchar_t *result; if (wcs == NULL) - { - if (olds == NULL) - { - errno = EINVAL; - return NULL; - } - else - wcs = olds; - } + wcs = *ptr; /* Scan leading delimiters. */ wcs += wcsspn (wcs, delim); if (*wcs == L'\0') { - olds = NULL; + *ptr = NULL; return NULL; } /* Find the end of the token. */ - token = wcs; - wcs = wcspbrk (token, delim); + result = wcs; + wcs = wcspbrk (result, delim); if (wcs == NULL) /* This token finishes the string. */ - olds = NULL; + *ptr = NULL; else { /* Terminate the token and make OLDS point past it. */ *wcs = L'\0'; - olds = wcs + 1; + *ptr = wcs + 1; } - return token; + return result; } diff --git a/wcsmbs/wcstr.h b/wcsmbs/wcstr.h deleted file mode 100644 index e9cc64ddc1..0000000000 --- a/wcsmbs/wcstr.h +++ /dev/null @@ -1,84 +0,0 @@ -/* 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, 1992 Free Software Foundation, Inc., 675 Mass Ave, -Cambridge, MA 02139, USA. */ - -#ifndef _WCSTRING_H - -#define _WCSTRING_H 1 -#include - -__BEGIN_DECLS - -/* Get size_t, wchar_t, uwchar_t and NULL from . */ -#define __need_size_t -#define __need_wchar_t -/* #define __need_uwchar_t */ -#define __need_NULL -#include - -/* FIXME: Should go with this or another name in stddef.h. */ -typedef unsigned int uwchar_t; - - -/* Copy SRC to DEST. */ -extern wchar_t *wcscpy __P ((wchar_t *__dest, __const wchar_t *__src)); -/* Copy no more than N wide-characters of SRC to DEST. */ -extern wchar_t *wcsncpy __P ((wchar_t *__dest, __const wchar_t *__src, - size_t __n)); - -/* Append SRC onto DEST. */ -extern wchar_t *wcscat __P ((wchar_t *__dest, __const wchar_t *__src)); -/* Append no more than N wide-characters of SRC onto DEST. */ -extern wchar_t *wcsncat __P ((wchar_t *__dest, __const wchar_t *__src, - size_t __n)); - -/* Compare S1 and S2. */ -extern int wcscmp __P ((__const wchar_t *__s1, __const wchar_t *__s2)); -/* Compare N wide-characters of S1 and S2. */ -extern int wcsncmp __P ((__const wchar_t *__s1, __const wchar_t *__s2, - size_t __n)); - -/* Duplicate S, returning an identical malloc'd string. */ -extern wchar_t *wcsdup __P ((__const wchar_t *__s)); - -/* Find the first occurence of WC in WCS. */ -extern wchar_t *wcschr __P ((__const wchar_t *__wcs, wchar_t __wc)); -/* Find the last occurence of WC in WCS. */ -extern wchar_t *wcsrchr __P ((__const wchar_t *__wcs, wchar_t __wc)); - -/* Return the length of the initial segmet of WCS which - consists entirely of wide-characters not in REJECT. */ -extern size_t wcscspn __P ((__const wchar_t *__wcs, - __const wchar_t *__reject)); -/* Return the length of the initial segmet of WCS which - consists entirely of wide-characters in ACCEPT. */ -extern size_t wcsspn __P ((__const wchar_t *__wcs, __const wchar_t *__accept)); -/* Find the first occurence in WCS of any character in ACCEPT. */ -extern wchar_t *wcspbrk __P ((__const wchar_t *__wcs, - __const wchar_t *__accept)); -/* Find the first occurence of NEEDLE in HAYSTACK. */ -extern wchar_t *wcswcs __P ((__const wchar_t *__haystack, - __const wchar_t *__needle)); -/* Divide WCS into tokens separated by characters in DELIM. */ -extern wchar_t *wcstok __P ((wchar_t *__s, __const wchar_t *__delim)); - -/* Return the number of wide-characters in S. */ -extern size_t wcslen __P ((__const wchar_t *__s)); - -__END_DECLS - -#endif /* wcstring.h */ diff --git a/wcsmbs/wcswcs.c b/wcsmbs/wcswcs.c deleted file mode 100644 index 4b1f2ace54..0000000000 --- a/wcsmbs/wcswcs.c +++ /dev/null @@ -1,97 +0,0 @@ -/* 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. */ - -/* - * The original strstr() file contains the following comment: - * - * My personal strstr() implementation that beats most other algorithms. - * Until someone tells me otherwise, I assume that this is the - * fastest implementation of strstr() in C. - * I deliberately chose not to comment it. You should have at least - * as much fun trying to understand it, as I had to write it :-). - * - * Stephen R. van den Berg, berg@pool.informatik.rwth-aachen.de */ - -#include - -wchar_t * -wcswcs (haystack, needle) - const wchar_t *haystack; - const wchar_t *needle; -{ - register wchar_t b, c; - - if ((b = *needle) != L'\0') - { - haystack--; /* possible ANSI violation */ - do - if ((c = *++haystack) == L'\0') - goto ret0; - while (c != b); - - if (!(c = *++needle)) - goto foundneedle; - ++needle; - goto jin; - - for (;;) - { - register wchar_t a; - register const wchar_t *rhaystack, *rneedle; - - do - { - if (!(a = *++haystack)) - goto ret0; - if (a == b) - break; - if ((a = *++haystack) == L'\0') - goto ret0; -shloop: ; - } - while (a != b); - -jin: if (!(a = *++haystack)) - goto ret0; - - if (a != c) - goto shloop; - - if (*(rhaystack = haystack-- + 1) == (a = *(rneedle = needle))) - do - { - if (a == L'\0') - goto foundneedle; - if (*++rhaystack != (a = *++needle)) - break; - if (a == L'\0') - goto foundneedle; - } - while (*++rhaystack == (a = *++needle)); - - needle=rneedle; /* took the register-poor approach */ - - if (a == L'\0') - break; - } - } -foundneedle: - return (wchar_t*)haystack; -ret0: - return NULL; -} -- cgit v1.2.3