From fa090f2c9f5ce8f3a507343469a786f2c569d3ff Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Tue, 22 Jan 2013 18:07:28 +0100 Subject: [PATCH 01/14] Initial version of printf builtin --- Makefile.in | 6 +- builtin.cpp | 2 + builtin_printf.cpp | 634 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 640 insertions(+), 2 deletions(-) create mode 100644 builtin_printf.cpp diff --git a/Makefile.in b/Makefile.in index d0b58f5b0..cde39f26a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -106,7 +106,8 @@ parser_keywords.o wutil.o tokenizer.o # BUILTIN_FILES := builtin_set.cpp builtin_commandline.cpp \ - builtin_ulimit.cpp builtin_complete.cpp builtin_jobs.cpp + builtin_ulimit.cpp builtin_complete.cpp builtin_jobs.cpp \ + builtin_printf.cpp # @@ -871,7 +872,7 @@ builtin.o: wgetopt.h sanity.h tokenizer.h wildcard.h expand.h input_common.h builtin.o: input.h intern.h exec.h highlight.h screen.h color.h parse_util.h builtin.o: autoload.h lru.h parser_keywords.h path.h history.h builtin.o: builtin_set.cpp builtin_commandline.cpp builtin_complete.cpp -builtin.o: builtin_ulimit.cpp builtin_jobs.cpp +builtin.o: builtin_ulimit.cpp builtin_jobs.cpp builtin_printf.cpp builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h common.h builtin_commandline.o: builtin.h io.h wgetopt.h reader.h complete.h proc.h builtin_commandline.o: parser.h event.h function.h tokenizer.h input_common.h @@ -888,6 +889,7 @@ builtin_test.o: config.h common.h util.h builtin.h io.h wutil.h proc.h builtin_test.o: signal.h builtin_ulimit.o: config.h fallback.h signal.h util.h builtin.h io.h common.h builtin_ulimit.o: wgetopt.h +builtin_printf.o: wgetopt.h color.o: color.h config.h common.h util.h fallback.h signal.h common.o: config.h fallback.h signal.h util.h wutil.h common.h expand.h common.o: proc.h io.h wildcard.h parser.h event.h function.h complete.h diff --git a/builtin.cpp b/builtin.cpp index 12c02d6b8..2cd85218e 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -390,6 +390,7 @@ static void builtin_missing_argument(parser_t &parser, const wchar_t *cmd, const #include "builtin_complete.cpp" #include "builtin_ulimit.cpp" #include "builtin_jobs.cpp" +#include "builtin_printf.cpp" /* builtin_test lives in builtin_test.cpp */ int builtin_test(parser_t &parser, wchar_t **argv); @@ -4024,6 +4025,7 @@ static const builtin_data_t builtin_datas[]= { L"jobs", &builtin_jobs, N_(L"Print currently running jobs") }, { L"not", &builtin_generic, N_(L"Negate exit status of job") }, { L"or", &builtin_generic, N_(L"Execute command if previous command failed") }, + { L"printf", &builtin_printf, N_(L"Prints formatted text") }, { L"pwd", &builtin_pwd, N_(L"Print the working directory") }, { L"random", &builtin_random, N_(L"Generate random number") }, { L"read", &builtin_read, N_(L"Read a line of input into variables") }, diff --git a/builtin_printf.cpp b/builtin_printf.cpp new file mode 100644 index 000000000..b633edd16 --- /dev/null +++ b/builtin_printf.cpp @@ -0,0 +1,634 @@ +/* printf - format and print data + Copyright (C) 1990-2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Usage: printf format [argument...] + + A front end to the printf function that lets it be used from the shell. + + Backslash escapes: + + \" = double quote + \\ = backslash + \a = alert (bell) + \b = backspace + \c = produce no further output + \f = form feed + \n = new line + \r = carriage return + \t = horizontal tab + \v = vertical tab + \ooo = octal number (ooo is 1 to 3 digits) + \xhh = hexadecimal number (hhh is 1 to 2 digits) + \uhhhh = 16-bit Unicode character (hhhh is 4 digits) + \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits) + + Additional directive: + + %b = print an argument string, interpreting backslash escapes, + except that octal escapes are of the form \0 or \0ooo. + + The `format' argument is re-used as many times as necessary + to convert all of the given arguments. + + David MacKenzie */ + +#include +#include +#include + +#include "common.h" + +// This file has bee imported from source code of printf command in GNU Coreutils version 6.9 + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "printf" + +#define AUTHORS "David MacKenzie" + +#define isodigit(c) ((c) >= L'0' && (c) <= L'7') +#define hextobin(c) ((c) >= L'a' && (c) <= L'f' ? (c) - L'a' + 10 : \ + (c) >= L'A' && (c) <= L'F' ? (c) - L'A' + 10 : (c) - L'0') +#define octtobin(c) ((c) - L'0') + +# define ISDIGIT(c) ((unsigned int) (c) - L'0' <= 9) + +# define PRIdMAX L"ld" + +/* True if the POSIXLY_CORRECT environment variable is set. */ +static bool posixly_correct; + +/* This message appears in N_() here rather than just in _() below because + the sole use would have been in a #define. */ +static wchar_t const *const cfcc_msg = + N_(L"warning: %s: character(s) following character constant have been ignored"); + +int strtoimax (wchar_t const *ptr, wchar_t **endptr, int base) +{ + return wcstol (ptr, endptr, base); +} + +int strtoumax (wchar_t const *ptr, wchar_t **endptr, int base) +{ + return wcstol (ptr, endptr, base); +} + +# define STRTOD wcstod + +double +C_STRTOD (wchar_t const *nptr, wchar_t **endptr) +{ + double r; + + const wcstring saved_locale = wsetlocale (LC_NUMERIC, NULL); + + if (!saved_locale.empty()) + { + setlocale (LC_NUMERIC, "C"); + } + + r = STRTOD (nptr, endptr); + + if (!saved_locale.empty()) + { + wsetlocale (LC_NUMERIC, saved_locale.c_str()); + } + + return r; +} + +static inline unsigned wchar_t to_uchar (wchar_t ch) +{ + return ch; +} + +static void verify_numeric (const wchar_t *s, const wchar_t *end) +{ + if (errno) + { + append_format(stderr_buffer, L"%ls", s); + } + else if (*end) + { + if (s == end) + append_format(stderr_buffer, _(L"%ls: expected a numeric value"), s); + else + append_format(stderr_buffer, _(L"%ls: value not completely converted"), s); + } +} + +#define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \ +static TYPE \ +FUNC_NAME (wchar_t const *s) \ +{ \ + wchar_t *end; \ + TYPE val; \ + \ + if (*s == L'\"' || *s == L'\'') \ + { \ + unsigned wchar_t ch = *++s; \ + val = ch; \ + /* If POSIXLY_CORRECT is not set, then give a warning that there \ + are characters following the character constant and that GNU \ + printf is ignoring those characters. If POSIXLY_CORRECT *is* \ + set, then don't give the warning. */ \ + if (*++s != 0 && !posixly_correct) \ + append_format(stderr_buffer, _(cfcc_msg), s); \ + } \ + else \ + { \ + errno = 0; \ + val = (LIB_FUNC_EXPR); \ + verify_numeric (s, end); \ + } \ + return val; \ +} \ + +STRTOX (intmax_t, vstrtoimax, strtoimax (s, &end, 0)) +STRTOX (uintmax_t, vstrtoumax, strtoumax (s, &end, 0)) +STRTOX (long double, vstrtold, C_STRTOD(s, &end)) + +/* Output a single-character \ escape. */ + +static void +print_esc_char (wchar_t c) +{ + switch (c) + { + case L'a': /* Alert. */ + append_format(stdout_buffer, L"%lc", L'\a'); + break; + case L'b': /* Backspace. */ + append_format(stdout_buffer, L"%lc", L'\b'); + break; + case L'c': /* Cancel the rest of the output. */ + exit (EXIT_SUCCESS); + break; + case L'f': /* Form feed. */ + append_format(stdout_buffer, L"%lc", L'\f'); + break; + case L'n': /* New line. */ + append_format(stdout_buffer, L"%lc", L'\n'); + break; + case L'r': /* Carriage retturn. */ + append_format(stdout_buffer, L"%lc", L'\r'); + break; + case L't': /* Horizontal tab. */ + append_format(stdout_buffer, L"%lc", L'\t'); + break; + case L'v': /* Vertical tab. */ + append_format(stdout_buffer, L"%lc", L'\v'); + break; + default: + append_format(stdout_buffer, L"%lc", c); + break; + } +} + +/* Print a \ escape sequence starting at ESCSTART. + Return the number of characters in the escape sequence + besides the backslash. + If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o + is an octal digit; otherwise they are of the form \ooo. */ + +static int print_esc (const wchar_t *escstart, bool octal_0) +{ + const wchar_t *p = escstart + 1; + int esc_value = 0; /* Value of \nnn escape. */ + int esc_length; /* Length of \nnn escape. */ + + if (*p == L'x') + { + /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */ + for (esc_length = 0, ++p; + esc_length < 2 && isxdigit (to_uchar (*p)); + ++esc_length, ++p) + esc_value = esc_value * 16 + hextobin (*p); + if (esc_length == 0) + append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); + append_format (stdout_buffer, L"%lc", esc_value); + } + else if (isodigit (*p)) + { + /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise). + Allow \ooo if octal_0 && *p != L'0'; this is an undocumented + extension to POSIX that is compatible with Bash 2.05b. */ + for (esc_length = 0, p += octal_0 && *p == L'0'; + esc_length < 3 && isodigit (*p); + ++esc_length, ++p) + esc_value = esc_value * 8 + octtobin (*p); + append_format(stdout_buffer, L"%c", esc_value); + } + else if (*p && wcschr (L"\"\\abcfnrtv", *p)) + print_esc_char (*p++); + else if (*p == L'u' || *p == L'U') + { + wchar_t esc_char = *p; + unsigned int uni_value; + + uni_value = 0; + for (esc_length = (esc_char == L'u' ? 4 : 8), ++p; + esc_length > 0; + --esc_length, ++p) + { + if (! isxdigit (to_uchar (*p))) + append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); + uni_value = uni_value * 16 + hextobin (*p); + } + + /* A universal character name shall not specify a character short + identifier in the range 00000000 through 00000020, 0000007F through + 0000009F, or 0000D800 through 0000DFFF inclusive. A universal + character name shall not designate a character in the required + character set. */ + if ((uni_value <= 0x9f + && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60) + || (uni_value >= 0xd800 && uni_value <= 0xdfff)) + append_format(stderr_buffer, _(L"invalid universal character name \\%c%0*x"), + esc_char, (esc_char == L'u' ? 4 : 8), uni_value); + + append_format(stdout_buffer, L"%lc", uni_value); + } + else + { + append_format(stdout_buffer, L"%lc", L'\\'); + if (*p) + { + append_format (stdout_buffer, L"%lc", *p); + p++; + } + } + return p - escstart - 1; +} + +/* Print string STR, evaluating \ escapes. */ + +static void +print_esc_string (const wchar_t *str) +{ + for (; *str; str++) + if (*str == L'\\') + str += print_esc (str, true); + else + append_format (stdout_buffer, L"%lc", *str); +} + +/* Evaluate a printf conversion specification. START is the start of + the directive, LENGTH is its length, and CONVERSION specifies the + type of conversion. LENGTH does not include any length modifier or + the conversion specifier itself. FIELD_WIDTH and PRECISION are the + field width and precision for '*' values, if HAVE_FIELD_WIDTH and + HAVE_PRECISION are true, respectively. ARGUMENT is the argument to + be formatted. */ + +static void print_direc (const wchar_t *start, size_t length, wchar_t conversion, + bool have_field_width, int field_width, + bool have_precision, int precision, + wchar_t const *argument) +{ + wchar_t *p; /* Null-terminated copy of % directive. */ + wcstring fmt; + + /* Create a null-terminated copy of the % directive, with an + intmax_t-wide length modifier substituted for any existing + integer length modifier. */ + { + wchar_t *q; + wchar_t const *length_modifier; + size_t length_modifier_len; + + switch (conversion) + { + case L'd': case L'i': case L'o': case L'u': case L'x': case L'X': + length_modifier = PRIdMAX; + length_modifier_len = sizeof PRIdMAX - 2; + break; + + case L'a': case L'e': case L'f': case L'g': + case L'A': case L'E': case L'F': case L'G': + length_modifier = L"L"; + length_modifier_len = 1; + break; + + default: + length_modifier = start; /* Any valid pointer will do. */ + length_modifier_len = 0; + break; + } + + p = static_cast(malloc (length + length_modifier_len + 2)); + q = static_cast(mempcpy (p, start, length)); + q = static_cast(mempcpy (q, length_modifier, length_modifier_len)); + *q++ = conversion; + *q = L'\0'; + } + + append_format(fmt, L"%%l%lc", conversion); + switch (conversion) + { + case L'd': + case L'i': + { + intmax_t arg = vstrtoimax (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'o': + case L'u': + case L'x': + case L'X': + { + + uintmax_t arg = vstrtoumax (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'a': + case L'A': + case L'e': + case L'E': + case L'f': + case L'F': + case L'g': + case L'G': + { +debug(0, "Field width %d, Precision %d", field_width, precision); + + long double arg = vstrtold (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'c': + if (!have_field_width) + append_format(stdout_buffer, fmt.c_str(), *argument); + else + append_format(stdout_buffer, fmt.c_str(), field_width, *argument); + break; + + case L's': + +debug(0, "Field width %d, Precision %d", field_width, precision); + if (!have_field_width) + { + if (!have_precision){ + append_format(stdout_buffer, fmt.c_str(), argument);} + else + append_format(stdout_buffer, fmt.c_str(), precision, argument); + } + else + { + + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, argument); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, argument); + } + break; + } + + free (p); +} + +/* Print the text in FORMAT, using ARGV (with ARGC elements) for + arguments to any `%' directives. + Return the number of elements of ARGV used. */ + + static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) + { + int save_argc = argc; /* Preserve original value. */ + const wchar_t *f; /* Pointer into `format'. */ + const wchar_t *direc_start; /* Start of % directive. */ + size_t direc_length; /* Length of % directive. */ + bool have_field_width; /* True if FIELD_WIDTH is valid. */ + int field_width = 0; /* Arg to first '*'. */ + bool have_precision; /* True if PRECISION is valid. */ + int precision = 0; /* Arg to second '*'. */ + wchar_t ok[UCHAR_MAX + 1]; /* ok['x'] is true if %x is allowed. */ + + for (f = format; *f != L'\0'; ++f) + { + switch (*f) + { + case L'%': + direc_start = f++; + direc_length = 1; + have_field_width = have_precision = false; + if (*f == L'%') + { + append_format(stdout_buffer, L"%lc", L'%'); + break; + } + if (*f == L'b') + { + /* FIXME: Field width and precision are not supported + for %b, even though POSIX requires it. */ + if (argc > 0) + { + print_esc_string (*argv); + ++argv; + --argc; + } + break; + } + + memset (ok, 0, sizeof ok); + ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = + ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = + ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1; + + for (;; f++, direc_length++) + switch (*f) + { +#if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__ + case L'I': +#endif + case L'\'': + ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = + ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0; + break; + case '-': case '+': case ' ': + break; + case L'#': + ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0; + break; + case '0': + ok['c'] = ok['s'] = 0; + break; + default: + goto no_more_flag_characters; + } + no_more_flag_characters:; + + if (*f == L'*') + { + ++f; + ++direc_length; + if (argc > 0) + { + intmax_t width = vstrtoimax (*argv); + if (INT_MIN <= width && width <= INT_MAX) + field_width = width; + else + append_format(stderr_buffer, _(L"invalid field width: %ls"), + *argv); + ++argv; + --argc; + } + else + field_width = 0; + have_field_width = true; + } + else + while (iswdigit(*f)) + { + ++f; + ++direc_length; + } + if (*f == L'.') + { + ++f; + ++direc_length; + ok['c'] = 0; + if (*f == L'*') + { + ++f; + ++direc_length; + if (argc > 0) + { + intmax_t prec = vstrtoimax (*argv); + if (prec < 0) + { + /* A negative precision is taken as if the + precision were omitted, so -1 is safe + here even if prec < INT_MIN. */ + precision = -1; + } + else if (INT_MAX < prec) + append_format(stderr_buffer, _(L"invalid precision: %ls"), + *argv); + else + precision = prec; + ++argv; + --argc; + } + else + precision = 0; + have_precision = true; + } + else + while (iswdigit(*f)) + { + ++f; + ++direc_length; + } + } + + while (*f == L'l' || *f == L'L' || *f == L'h' + || *f == L'j' || *f == L't' || *f == L'z') + ++f; + + { + unsigned wchar_t conversion = *f; + if (! ok[conversion]) + append_format(stderr_buffer, + _("%.*ls: invalid conversion specification"), + (int) (f + 1 - direc_start), direc_start); + } + + print_direc (direc_start, direc_length, *f, + have_field_width, field_width, + have_precision, precision, + (argc <= 0 ? L"" : (argc--, *argv++))); + break; + + case L'\\': + f += print_esc (f, false); + break; + + default: + append_format (stdout_buffer, L"%lc", *f); + } + } + + return save_argc - argc; +} + +static int builtin_printf(parser_t &parser, wchar_t **argv) +{ + wchar_t *format; + int args_used; + int argc=builtin_count_args(argv); + + if (argc <= 1) + { + append_format(stderr_buffer, _(L"missing operand")); + return EXIT_FAILURE; + } + + format = argv[1]; + argc -= 2; + argv += 2; + + do + { + args_used = print_formatted (format, argc, argv); + argc -= args_used; + argv += args_used; + } + while (args_used > 0 && argc > 0); +} From 6ff88a44f0c1cb2e16f948fbd7705d1a68e6ecac Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sat, 2 Mar 2013 16:02:20 +0100 Subject: [PATCH 02/14] Fixed code to support field width and precision --- builtin_printf.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index b633edd16..e5f0e4ae1 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -97,7 +97,7 @@ C_STRTOD (wchar_t const *nptr, wchar_t **endptr) if (!saved_locale.empty()) { - setlocale (LC_NUMERIC, "C"); + wsetlocale (LC_NUMERIC, L"C"); } r = STRTOD (nptr, endptr); @@ -322,21 +322,24 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion length_modifier = L"L"; length_modifier_len = 1; break; - + case L's': + length_modifier = L"l"; + length_modifier_len = 1; + break; default: length_modifier = start; /* Any valid pointer will do. */ length_modifier_len = 0; break; } - p = static_cast(malloc (length + length_modifier_len + 2)); - q = static_cast(mempcpy (p, start, length)); - q = static_cast(mempcpy (q, length_modifier, length_modifier_len)); + p = new wchar_t[length + length_modifier_len + 2]; + q = static_cast(mempcpy (p, start, sizeof(wchar_t) * length)); + q = static_cast(mempcpy (q, length_modifier, sizeof(wchar_t) * length_modifier_len)); *q++ = conversion; *q = L'\0'; } - - append_format(fmt, L"%%l%lc", conversion); + + fmt = p; switch (conversion) { case L'd': @@ -393,7 +396,6 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'g': case L'G': { -debug(0, "Field width %d, Precision %d", field_width, precision); long double arg = vstrtold (argument); if (!have_field_width) @@ -421,8 +423,6 @@ debug(0, "Field width %d, Precision %d", field_width, precision); break; case L's': - -debug(0, "Field width %d, Precision %d", field_width, precision); if (!have_field_width) { if (!have_precision){ @@ -529,16 +529,18 @@ debug(0, "Field width %d, Precision %d", field_width, precision); ++argv; --argc; } - else - field_width = 0; + else{ + field_width = 0; + } have_field_width = true; } - else + else { while (iswdigit(*f)) { ++f; ++direc_length; } + } if (*f == L'.') { ++f; From d9c9760aaca353da3deeb503da0a191b34683309 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Tue, 22 Jan 2013 18:07:28 +0100 Subject: [PATCH 03/14] Initial version of printf builtin --- Makefile.in | 7 +- builtin.cpp | 2 + builtin_printf.cpp | 634 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 640 insertions(+), 3 deletions(-) create mode 100644 builtin_printf.cpp diff --git a/Makefile.in b/Makefile.in index 717de724d..6cd355aa5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -105,8 +105,8 @@ parser_keywords.o wutil.o tokenizer.o # BUILTIN_FILES := builtin_set.cpp builtin_commandline.cpp \ - builtin_ulimit.cpp builtin_complete.cpp builtin_jobs.cpp \ - builtin_set_color.cpp + builtin_ulimit.cpp builtin_complete.cpp builtin_jobs.cpp \ + builtin_set_color.cpp builtin_printf.cpp # @@ -880,7 +880,7 @@ builtin.o: wgetopt.h sanity.h tokenizer.h wildcard.h expand.h input_common.h builtin.o: input.h intern.h exec.h highlight.h screen.h color.h parse_util.h builtin.o: autoload.h lru.h parser_keywords.h path.h history.h builtin.o: builtin_set.cpp builtin_commandline.cpp builtin_complete.cpp -builtin.o: builtin_ulimit.cpp builtin_jobs.cpp +builtin.o: builtin_ulimit.cpp builtin_jobs.cpp builtin_printf.cpp builtin_commandline.o: config.h signal.h fallback.h util.h wutil.h common.h builtin_commandline.o: builtin.h io.h wgetopt.h reader.h complete.h proc.h builtin_commandline.o: parser.h event.h function.h tokenizer.h input_common.h @@ -897,6 +897,7 @@ builtin_test.o: config.h common.h util.h builtin.h io.h wutil.h proc.h builtin_test.o: signal.h builtin_ulimit.o: config.h fallback.h signal.h util.h builtin.h io.h common.h builtin_ulimit.o: wgetopt.h +builtin_printf.o: wgetopt.h color.o: color.h config.h common.h util.h fallback.h signal.h common.o: config.h fallback.h signal.h util.h wutil.h common.h expand.h common.o: proc.h io.h wildcard.h parser.h event.h function.h complete.h diff --git a/builtin.cpp b/builtin.cpp index 619fc20a3..bd41923ed 100644 --- a/builtin.cpp +++ b/builtin.cpp @@ -391,6 +391,7 @@ static void builtin_missing_argument(parser_t &parser, const wchar_t *cmd, const #include "builtin_ulimit.cpp" #include "builtin_jobs.cpp" #include "builtin_set_color.cpp" +#include "builtin_printf.cpp" /* builtin_test lives in builtin_test.cpp */ int builtin_test(parser_t &parser, wchar_t **argv); @@ -4026,6 +4027,7 @@ static const builtin_data_t builtin_datas[]= { L"jobs", &builtin_jobs, N_(L"Print currently running jobs") }, { L"not", &builtin_generic, N_(L"Negate exit status of job") }, { L"or", &builtin_generic, N_(L"Execute command if previous command failed") }, + { L"printf", &builtin_printf, N_(L"Prints formatted text") }, { L"pwd", &builtin_pwd, N_(L"Print the working directory") }, { L"random", &builtin_random, N_(L"Generate random number") }, { L"read", &builtin_read, N_(L"Read a line of input into variables") }, diff --git a/builtin_printf.cpp b/builtin_printf.cpp new file mode 100644 index 000000000..b633edd16 --- /dev/null +++ b/builtin_printf.cpp @@ -0,0 +1,634 @@ +/* printf - format and print data + Copyright (C) 1990-2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Usage: printf format [argument...] + + A front end to the printf function that lets it be used from the shell. + + Backslash escapes: + + \" = double quote + \\ = backslash + \a = alert (bell) + \b = backspace + \c = produce no further output + \f = form feed + \n = new line + \r = carriage return + \t = horizontal tab + \v = vertical tab + \ooo = octal number (ooo is 1 to 3 digits) + \xhh = hexadecimal number (hhh is 1 to 2 digits) + \uhhhh = 16-bit Unicode character (hhhh is 4 digits) + \Uhhhhhhhh = 32-bit Unicode character (hhhhhhhh is 8 digits) + + Additional directive: + + %b = print an argument string, interpreting backslash escapes, + except that octal escapes are of the form \0 or \0ooo. + + The `format' argument is re-used as many times as necessary + to convert all of the given arguments. + + David MacKenzie */ + +#include +#include +#include + +#include "common.h" + +// This file has bee imported from source code of printf command in GNU Coreutils version 6.9 + +/* The official name of this program (e.g., no `g' prefix). */ +#define PROGRAM_NAME "printf" + +#define AUTHORS "David MacKenzie" + +#define isodigit(c) ((c) >= L'0' && (c) <= L'7') +#define hextobin(c) ((c) >= L'a' && (c) <= L'f' ? (c) - L'a' + 10 : \ + (c) >= L'A' && (c) <= L'F' ? (c) - L'A' + 10 : (c) - L'0') +#define octtobin(c) ((c) - L'0') + +# define ISDIGIT(c) ((unsigned int) (c) - L'0' <= 9) + +# define PRIdMAX L"ld" + +/* True if the POSIXLY_CORRECT environment variable is set. */ +static bool posixly_correct; + +/* This message appears in N_() here rather than just in _() below because + the sole use would have been in a #define. */ +static wchar_t const *const cfcc_msg = + N_(L"warning: %s: character(s) following character constant have been ignored"); + +int strtoimax (wchar_t const *ptr, wchar_t **endptr, int base) +{ + return wcstol (ptr, endptr, base); +} + +int strtoumax (wchar_t const *ptr, wchar_t **endptr, int base) +{ + return wcstol (ptr, endptr, base); +} + +# define STRTOD wcstod + +double +C_STRTOD (wchar_t const *nptr, wchar_t **endptr) +{ + double r; + + const wcstring saved_locale = wsetlocale (LC_NUMERIC, NULL); + + if (!saved_locale.empty()) + { + setlocale (LC_NUMERIC, "C"); + } + + r = STRTOD (nptr, endptr); + + if (!saved_locale.empty()) + { + wsetlocale (LC_NUMERIC, saved_locale.c_str()); + } + + return r; +} + +static inline unsigned wchar_t to_uchar (wchar_t ch) +{ + return ch; +} + +static void verify_numeric (const wchar_t *s, const wchar_t *end) +{ + if (errno) + { + append_format(stderr_buffer, L"%ls", s); + } + else if (*end) + { + if (s == end) + append_format(stderr_buffer, _(L"%ls: expected a numeric value"), s); + else + append_format(stderr_buffer, _(L"%ls: value not completely converted"), s); + } +} + +#define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \ +static TYPE \ +FUNC_NAME (wchar_t const *s) \ +{ \ + wchar_t *end; \ + TYPE val; \ + \ + if (*s == L'\"' || *s == L'\'') \ + { \ + unsigned wchar_t ch = *++s; \ + val = ch; \ + /* If POSIXLY_CORRECT is not set, then give a warning that there \ + are characters following the character constant and that GNU \ + printf is ignoring those characters. If POSIXLY_CORRECT *is* \ + set, then don't give the warning. */ \ + if (*++s != 0 && !posixly_correct) \ + append_format(stderr_buffer, _(cfcc_msg), s); \ + } \ + else \ + { \ + errno = 0; \ + val = (LIB_FUNC_EXPR); \ + verify_numeric (s, end); \ + } \ + return val; \ +} \ + +STRTOX (intmax_t, vstrtoimax, strtoimax (s, &end, 0)) +STRTOX (uintmax_t, vstrtoumax, strtoumax (s, &end, 0)) +STRTOX (long double, vstrtold, C_STRTOD(s, &end)) + +/* Output a single-character \ escape. */ + +static void +print_esc_char (wchar_t c) +{ + switch (c) + { + case L'a': /* Alert. */ + append_format(stdout_buffer, L"%lc", L'\a'); + break; + case L'b': /* Backspace. */ + append_format(stdout_buffer, L"%lc", L'\b'); + break; + case L'c': /* Cancel the rest of the output. */ + exit (EXIT_SUCCESS); + break; + case L'f': /* Form feed. */ + append_format(stdout_buffer, L"%lc", L'\f'); + break; + case L'n': /* New line. */ + append_format(stdout_buffer, L"%lc", L'\n'); + break; + case L'r': /* Carriage retturn. */ + append_format(stdout_buffer, L"%lc", L'\r'); + break; + case L't': /* Horizontal tab. */ + append_format(stdout_buffer, L"%lc", L'\t'); + break; + case L'v': /* Vertical tab. */ + append_format(stdout_buffer, L"%lc", L'\v'); + break; + default: + append_format(stdout_buffer, L"%lc", c); + break; + } +} + +/* Print a \ escape sequence starting at ESCSTART. + Return the number of characters in the escape sequence + besides the backslash. + If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o + is an octal digit; otherwise they are of the form \ooo. */ + +static int print_esc (const wchar_t *escstart, bool octal_0) +{ + const wchar_t *p = escstart + 1; + int esc_value = 0; /* Value of \nnn escape. */ + int esc_length; /* Length of \nnn escape. */ + + if (*p == L'x') + { + /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */ + for (esc_length = 0, ++p; + esc_length < 2 && isxdigit (to_uchar (*p)); + ++esc_length, ++p) + esc_value = esc_value * 16 + hextobin (*p); + if (esc_length == 0) + append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); + append_format (stdout_buffer, L"%lc", esc_value); + } + else if (isodigit (*p)) + { + /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise). + Allow \ooo if octal_0 && *p != L'0'; this is an undocumented + extension to POSIX that is compatible with Bash 2.05b. */ + for (esc_length = 0, p += octal_0 && *p == L'0'; + esc_length < 3 && isodigit (*p); + ++esc_length, ++p) + esc_value = esc_value * 8 + octtobin (*p); + append_format(stdout_buffer, L"%c", esc_value); + } + else if (*p && wcschr (L"\"\\abcfnrtv", *p)) + print_esc_char (*p++); + else if (*p == L'u' || *p == L'U') + { + wchar_t esc_char = *p; + unsigned int uni_value; + + uni_value = 0; + for (esc_length = (esc_char == L'u' ? 4 : 8), ++p; + esc_length > 0; + --esc_length, ++p) + { + if (! isxdigit (to_uchar (*p))) + append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); + uni_value = uni_value * 16 + hextobin (*p); + } + + /* A universal character name shall not specify a character short + identifier in the range 00000000 through 00000020, 0000007F through + 0000009F, or 0000D800 through 0000DFFF inclusive. A universal + character name shall not designate a character in the required + character set. */ + if ((uni_value <= 0x9f + && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60) + || (uni_value >= 0xd800 && uni_value <= 0xdfff)) + append_format(stderr_buffer, _(L"invalid universal character name \\%c%0*x"), + esc_char, (esc_char == L'u' ? 4 : 8), uni_value); + + append_format(stdout_buffer, L"%lc", uni_value); + } + else + { + append_format(stdout_buffer, L"%lc", L'\\'); + if (*p) + { + append_format (stdout_buffer, L"%lc", *p); + p++; + } + } + return p - escstart - 1; +} + +/* Print string STR, evaluating \ escapes. */ + +static void +print_esc_string (const wchar_t *str) +{ + for (; *str; str++) + if (*str == L'\\') + str += print_esc (str, true); + else + append_format (stdout_buffer, L"%lc", *str); +} + +/* Evaluate a printf conversion specification. START is the start of + the directive, LENGTH is its length, and CONVERSION specifies the + type of conversion. LENGTH does not include any length modifier or + the conversion specifier itself. FIELD_WIDTH and PRECISION are the + field width and precision for '*' values, if HAVE_FIELD_WIDTH and + HAVE_PRECISION are true, respectively. ARGUMENT is the argument to + be formatted. */ + +static void print_direc (const wchar_t *start, size_t length, wchar_t conversion, + bool have_field_width, int field_width, + bool have_precision, int precision, + wchar_t const *argument) +{ + wchar_t *p; /* Null-terminated copy of % directive. */ + wcstring fmt; + + /* Create a null-terminated copy of the % directive, with an + intmax_t-wide length modifier substituted for any existing + integer length modifier. */ + { + wchar_t *q; + wchar_t const *length_modifier; + size_t length_modifier_len; + + switch (conversion) + { + case L'd': case L'i': case L'o': case L'u': case L'x': case L'X': + length_modifier = PRIdMAX; + length_modifier_len = sizeof PRIdMAX - 2; + break; + + case L'a': case L'e': case L'f': case L'g': + case L'A': case L'E': case L'F': case L'G': + length_modifier = L"L"; + length_modifier_len = 1; + break; + + default: + length_modifier = start; /* Any valid pointer will do. */ + length_modifier_len = 0; + break; + } + + p = static_cast(malloc (length + length_modifier_len + 2)); + q = static_cast(mempcpy (p, start, length)); + q = static_cast(mempcpy (q, length_modifier, length_modifier_len)); + *q++ = conversion; + *q = L'\0'; + } + + append_format(fmt, L"%%l%lc", conversion); + switch (conversion) + { + case L'd': + case L'i': + { + intmax_t arg = vstrtoimax (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'o': + case L'u': + case L'x': + case L'X': + { + + uintmax_t arg = vstrtoumax (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'a': + case L'A': + case L'e': + case L'E': + case L'f': + case L'F': + case L'g': + case L'G': + { +debug(0, "Field width %d, Precision %d", field_width, precision); + + long double arg = vstrtold (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'c': + if (!have_field_width) + append_format(stdout_buffer, fmt.c_str(), *argument); + else + append_format(stdout_buffer, fmt.c_str(), field_width, *argument); + break; + + case L's': + +debug(0, "Field width %d, Precision %d", field_width, precision); + if (!have_field_width) + { + if (!have_precision){ + append_format(stdout_buffer, fmt.c_str(), argument);} + else + append_format(stdout_buffer, fmt.c_str(), precision, argument); + } + else + { + + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, argument); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, argument); + } + break; + } + + free (p); +} + +/* Print the text in FORMAT, using ARGV (with ARGC elements) for + arguments to any `%' directives. + Return the number of elements of ARGV used. */ + + static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) + { + int save_argc = argc; /* Preserve original value. */ + const wchar_t *f; /* Pointer into `format'. */ + const wchar_t *direc_start; /* Start of % directive. */ + size_t direc_length; /* Length of % directive. */ + bool have_field_width; /* True if FIELD_WIDTH is valid. */ + int field_width = 0; /* Arg to first '*'. */ + bool have_precision; /* True if PRECISION is valid. */ + int precision = 0; /* Arg to second '*'. */ + wchar_t ok[UCHAR_MAX + 1]; /* ok['x'] is true if %x is allowed. */ + + for (f = format; *f != L'\0'; ++f) + { + switch (*f) + { + case L'%': + direc_start = f++; + direc_length = 1; + have_field_width = have_precision = false; + if (*f == L'%') + { + append_format(stdout_buffer, L"%lc", L'%'); + break; + } + if (*f == L'b') + { + /* FIXME: Field width and precision are not supported + for %b, even though POSIX requires it. */ + if (argc > 0) + { + print_esc_string (*argv); + ++argv; + --argc; + } + break; + } + + memset (ok, 0, sizeof ok); + ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = + ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = + ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1; + + for (;; f++, direc_length++) + switch (*f) + { +#if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__ + case L'I': +#endif + case L'\'': + ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = + ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0; + break; + case '-': case '+': case ' ': + break; + case L'#': + ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0; + break; + case '0': + ok['c'] = ok['s'] = 0; + break; + default: + goto no_more_flag_characters; + } + no_more_flag_characters:; + + if (*f == L'*') + { + ++f; + ++direc_length; + if (argc > 0) + { + intmax_t width = vstrtoimax (*argv); + if (INT_MIN <= width && width <= INT_MAX) + field_width = width; + else + append_format(stderr_buffer, _(L"invalid field width: %ls"), + *argv); + ++argv; + --argc; + } + else + field_width = 0; + have_field_width = true; + } + else + while (iswdigit(*f)) + { + ++f; + ++direc_length; + } + if (*f == L'.') + { + ++f; + ++direc_length; + ok['c'] = 0; + if (*f == L'*') + { + ++f; + ++direc_length; + if (argc > 0) + { + intmax_t prec = vstrtoimax (*argv); + if (prec < 0) + { + /* A negative precision is taken as if the + precision were omitted, so -1 is safe + here even if prec < INT_MIN. */ + precision = -1; + } + else if (INT_MAX < prec) + append_format(stderr_buffer, _(L"invalid precision: %ls"), + *argv); + else + precision = prec; + ++argv; + --argc; + } + else + precision = 0; + have_precision = true; + } + else + while (iswdigit(*f)) + { + ++f; + ++direc_length; + } + } + + while (*f == L'l' || *f == L'L' || *f == L'h' + || *f == L'j' || *f == L't' || *f == L'z') + ++f; + + { + unsigned wchar_t conversion = *f; + if (! ok[conversion]) + append_format(stderr_buffer, + _("%.*ls: invalid conversion specification"), + (int) (f + 1 - direc_start), direc_start); + } + + print_direc (direc_start, direc_length, *f, + have_field_width, field_width, + have_precision, precision, + (argc <= 0 ? L"" : (argc--, *argv++))); + break; + + case L'\\': + f += print_esc (f, false); + break; + + default: + append_format (stdout_buffer, L"%lc", *f); + } + } + + return save_argc - argc; +} + +static int builtin_printf(parser_t &parser, wchar_t **argv) +{ + wchar_t *format; + int args_used; + int argc=builtin_count_args(argv); + + if (argc <= 1) + { + append_format(stderr_buffer, _(L"missing operand")); + return EXIT_FAILURE; + } + + format = argv[1]; + argc -= 2; + argv += 2; + + do + { + args_used = print_formatted (format, argc, argv); + argc -= args_used; + argv += args_used; + } + while (args_used > 0 && argc > 0); +} From b989978dd3db7e27ce62d9b43aef8564c69f3e60 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sat, 2 Mar 2013 16:02:20 +0100 Subject: [PATCH 04/14] Fixed code to support field width and precision --- builtin_printf.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index b633edd16..e5f0e4ae1 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -97,7 +97,7 @@ C_STRTOD (wchar_t const *nptr, wchar_t **endptr) if (!saved_locale.empty()) { - setlocale (LC_NUMERIC, "C"); + wsetlocale (LC_NUMERIC, L"C"); } r = STRTOD (nptr, endptr); @@ -322,21 +322,24 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion length_modifier = L"L"; length_modifier_len = 1; break; - + case L's': + length_modifier = L"l"; + length_modifier_len = 1; + break; default: length_modifier = start; /* Any valid pointer will do. */ length_modifier_len = 0; break; } - p = static_cast(malloc (length + length_modifier_len + 2)); - q = static_cast(mempcpy (p, start, length)); - q = static_cast(mempcpy (q, length_modifier, length_modifier_len)); + p = new wchar_t[length + length_modifier_len + 2]; + q = static_cast(mempcpy (p, start, sizeof(wchar_t) * length)); + q = static_cast(mempcpy (q, length_modifier, sizeof(wchar_t) * length_modifier_len)); *q++ = conversion; *q = L'\0'; } - - append_format(fmt, L"%%l%lc", conversion); + + fmt = p; switch (conversion) { case L'd': @@ -393,7 +396,6 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'g': case L'G': { -debug(0, "Field width %d, Precision %d", field_width, precision); long double arg = vstrtold (argument); if (!have_field_width) @@ -421,8 +423,6 @@ debug(0, "Field width %d, Precision %d", field_width, precision); break; case L's': - -debug(0, "Field width %d, Precision %d", field_width, precision); if (!have_field_width) { if (!have_precision){ @@ -529,16 +529,18 @@ debug(0, "Field width %d, Precision %d", field_width, precision); ++argv; --argc; } - else - field_width = 0; + else{ + field_width = 0; + } have_field_width = true; } - else + else { while (iswdigit(*f)) { ++f; ++direc_length; } + } if (*f == L'.') { ++f; From be7d02ebdde5c30d664496c57c3265469907004e Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 3 Mar 2013 00:45:34 +0530 Subject: [PATCH 05/14] Added test cases for printf builtin --- builtin_printf.cpp | 6 +++--- tests/printf.err | 0 tests/printf.in | 19 +++++++++++++++++++ tests/printf.out | 13 +++++++++++++ tests/printf.status | 1 + 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/printf.err create mode 100644 tests/printf.in create mode 100644 tests/printf.out create mode 100644 tests/printf.status diff --git a/builtin_printf.cpp b/builtin_printf.cpp index e5f0e4ae1..9ff8b363d 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -52,7 +52,7 @@ #include "common.h" -// This file has bee imported from source code of printf command in GNU Coreutils version 6.9 +// This file has been imported from source code of printf command in GNU Coreutils version 6.9 /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "printf" @@ -312,7 +312,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion switch (conversion) { - case L'd': case L'i': case L'o': case L'u': case L'x': case L'X': + case L'd': case L'i': length_modifier = PRIdMAX; length_modifier_len = sizeof PRIdMAX - 2; break; @@ -322,7 +322,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion length_modifier = L"L"; length_modifier_len = 1; break; - case L's': + case L's': case L'u': length_modifier = L"l"; length_modifier_len = 1; break; diff --git a/tests/printf.err b/tests/printf.err new file mode 100644 index 000000000..e69de29bb diff --git a/tests/printf.in b/tests/printf.in new file mode 100644 index 000000000..f06694691 --- /dev/null +++ b/tests/printf.in @@ -0,0 +1,19 @@ +printf "Hello %d %i %f %F %g %G\n" 1 2 3 4 5 6 + +printf "%x %X %o %u\n" 10 11 8 -1 +printf "%a %A\n" 14 15 + +printf "%c %s\n" a hello +printf "%e %E\n" 5 6 + +printf "%20d\n" 50 +printf "%-20d%d\n" 5 10 + +printf "%*d\n" 10 100 + +printf "%%\"\\\n" +printf "%s\b%s\n" x y +printf "abc\rdef\n" +printf "Msg1\fMsg2\n" +printf "foo\vbar\vbaz\n" +printf "\111 \x50" # \u0051 \U00000052 diff --git a/tests/printf.out b/tests/printf.out new file mode 100644 index 000000000..b24cfc7b0 --- /dev/null +++ b/tests/printf.out @@ -0,0 +1,13 @@ +Hello 1 2 3.000000 4.000000 5 6 +a B 10 18446744073709551615 +0xep+0 0XFP+0 +a hello +5.000000e+00 6.000000E+00 + 50 +5 10 + 100 +%"\nxy +abc def +Msg1 Msg2 +foo bar baz +I P \ No newline at end of file diff --git a/tests/printf.status b/tests/printf.status new file mode 100644 index 000000000..573541ac9 --- /dev/null +++ b/tests/printf.status @@ -0,0 +1 @@ +0 From fba984272a79c7eb975a209afd68005491428b08 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 3 Mar 2013 15:16:18 +0530 Subject: [PATCH 06/14] Fixed indentation in builtin_printf.cpp --- builtin_printf.cpp | 812 ++++++++++++++++++++++----------------------- 1 file changed, 394 insertions(+), 418 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index 9ff8b363d..92ace0bc1 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -91,42 +91,42 @@ int strtoumax (wchar_t const *ptr, wchar_t **endptr, int base) double C_STRTOD (wchar_t const *nptr, wchar_t **endptr) { - double r; + double r; - const wcstring saved_locale = wsetlocale (LC_NUMERIC, NULL); + const wcstring saved_locale = wsetlocale (LC_NUMERIC, NULL); - if (!saved_locale.empty()) + if (!saved_locale.empty()) { - wsetlocale (LC_NUMERIC, L"C"); + wsetlocale (LC_NUMERIC, L"C"); } - r = STRTOD (nptr, endptr); + r = STRTOD (nptr, endptr); - if (!saved_locale.empty()) + if (!saved_locale.empty()) { - wsetlocale (LC_NUMERIC, saved_locale.c_str()); + wsetlocale (LC_NUMERIC, saved_locale.c_str()); } - return r; + return r; } static inline unsigned wchar_t to_uchar (wchar_t ch) { - return ch; + return ch; } static void verify_numeric (const wchar_t *s, const wchar_t *end) { - if (errno) + if (errno) { - append_format(stderr_buffer, L"%ls", s); + append_format(stderr_buffer, L"%ls", s); } - else if (*end) + else if (*end) { - if (s == end) - append_format(stderr_buffer, _(L"%ls: expected a numeric value"), s); - else - append_format(stderr_buffer, _(L"%ls: value not completely converted"), s); + if (s == end) + append_format(stderr_buffer, _(L"%ls: expected a numeric value"), s); + else + append_format(stderr_buffer, _(L"%ls: value not completely converted"), s); } } @@ -134,27 +134,27 @@ static void verify_numeric (const wchar_t *s, const wchar_t *end) static TYPE \ FUNC_NAME (wchar_t const *s) \ { \ - wchar_t *end; \ - TYPE val; \ + wchar_t *end; \ + TYPE val; \ \ - if (*s == L'\"' || *s == L'\'') \ + if (*s == L'\"' || *s == L'\'') \ { \ - unsigned wchar_t ch = *++s; \ - val = ch; \ - /* If POSIXLY_CORRECT is not set, then give a warning that there \ - are characters following the character constant and that GNU \ - printf is ignoring those characters. If POSIXLY_CORRECT *is* \ - set, then don't give the warning. */ \ - if (*++s != 0 && !posixly_correct) \ - append_format(stderr_buffer, _(cfcc_msg), s); \ - } \ - else \ + unsigned wchar_t ch = *++s; \ + val = ch; \ + /* If POSIXLY_CORRECT is not set, then give a warning that there \ + are characters following the character constant and that GNU \ + printf is ignoring those characters. If POSIXLY_CORRECT *is* \ + set, then don't give the warning. */ \ + if (*++s != 0 && !posixly_correct) \ + append_format(stderr_buffer, _(cfcc_msg), s); \ + } \ + else \ { \ - errno = 0; \ - val = (LIB_FUNC_EXPR); \ - verify_numeric (s, end); \ + errno = 0; \ + val = (LIB_FUNC_EXPR); \ + verify_numeric (s, end); \ } \ - return val; \ + return val; \ } \ STRTOX (intmax_t, vstrtoimax, strtoimax (s, &end, 0)) @@ -166,35 +166,35 @@ STRTOX (long double, vstrtold, C_STRTOD(s, &end)) static void print_esc_char (wchar_t c) { - switch (c) + switch (c) { case L'a': /* Alert. */ - append_format(stdout_buffer, L"%lc", L'\a'); - break; - case L'b': /* Backspace. */ - append_format(stdout_buffer, L"%lc", L'\b'); - break; + append_format(stdout_buffer, L"%lc", L'\a'); + break; + case L'b': /* Backspace. */ + append_format(stdout_buffer, L"%lc", L'\b'); + break; case L'c': /* Cancel the rest of the output. */ - exit (EXIT_SUCCESS); - break; + exit (EXIT_SUCCESS); + break; case L'f': /* Form feed. */ - append_format(stdout_buffer, L"%lc", L'\f'); - break; + append_format(stdout_buffer, L"%lc", L'\f'); + break; case L'n': /* New line. */ - append_format(stdout_buffer, L"%lc", L'\n'); - break; + append_format(stdout_buffer, L"%lc", L'\n'); + break; case L'r': /* Carriage retturn. */ - append_format(stdout_buffer, L"%lc", L'\r'); - break; + append_format(stdout_buffer, L"%lc", L'\r'); + break; case L't': /* Horizontal tab. */ - append_format(stdout_buffer, L"%lc", L'\t'); - break; + append_format(stdout_buffer, L"%lc", L'\t'); + break; case L'v': /* Vertical tab. */ - append_format(stdout_buffer, L"%lc", L'\v'); - break; + append_format(stdout_buffer, L"%lc", L'\v'); + break; default: - append_format(stdout_buffer, L"%lc", c); - break; + append_format(stdout_buffer, L"%lc", c); + break; } } @@ -203,75 +203,73 @@ print_esc_char (wchar_t c) besides the backslash. If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o is an octal digit; otherwise they are of the form \ooo. */ - static int print_esc (const wchar_t *escstart, bool octal_0) { - const wchar_t *p = escstart + 1; - int esc_value = 0; /* Value of \nnn escape. */ - int esc_length; /* Length of \nnn escape. */ + const wchar_t *p = escstart + 1; + int esc_value = 0; /* Value of \nnn escape. */ + int esc_length; /* Length of \nnn escape. */ - if (*p == L'x') + if (*p == L'x') { - /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */ - for (esc_length = 0, ++p; - esc_length < 2 && isxdigit (to_uchar (*p)); - ++esc_length, ++p) - esc_value = esc_value * 16 + hextobin (*p); - if (esc_length == 0) - append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); - append_format (stdout_buffer, L"%lc", esc_value); + /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */ + for (esc_length = 0, ++p; + esc_length < 2 && isxdigit (to_uchar (*p)); + ++esc_length, ++p) + esc_value = esc_value * 16 + hextobin (*p); + if (esc_length == 0) + append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); + append_format (stdout_buffer, L"%lc", esc_value); } - else if (isodigit (*p)) + else if (isodigit (*p)) { - /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise). - Allow \ooo if octal_0 && *p != L'0'; this is an undocumented - extension to POSIX that is compatible with Bash 2.05b. */ - for (esc_length = 0, p += octal_0 && *p == L'0'; - esc_length < 3 && isodigit (*p); - ++esc_length, ++p) - esc_value = esc_value * 8 + octtobin (*p); - append_format(stdout_buffer, L"%c", esc_value); - } - else if (*p && wcschr (L"\"\\abcfnrtv", *p)) - print_esc_char (*p++); - else if (*p == L'u' || *p == L'U') + /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise). + Allow \ooo if octal_0 && *p != L'0'; this is an undocumented + extension to POSIX that is compatible with Bash 2.05b. */ + for (esc_length = 0, p += octal_0 && *p == L'0'; + esc_length < 3 && isodigit (*p); + ++esc_length, ++p) + esc_value = esc_value * 8 + octtobin (*p); + append_format(stdout_buffer, L"%c", esc_value); + } + else if (*p && wcschr (L"\"\\abcfnrtv", *p)) + print_esc_char (*p++); + else if (*p == L'u' || *p == L'U') { - wchar_t esc_char = *p; - unsigned int uni_value; + wchar_t esc_char = *p; + unsigned int uni_value; - uni_value = 0; - for (esc_length = (esc_char == L'u' ? 4 : 8), ++p; - esc_length > 0; - --esc_length, ++p) - { - if (! isxdigit (to_uchar (*p))) - append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); - uni_value = uni_value * 16 + hextobin (*p); - } + uni_value = 0; + for (esc_length = (esc_char == L'u' ? 4 : 8), ++p; + esc_length > 0; + --esc_length, ++p) + { + if (! isxdigit (to_uchar (*p))) + append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); + uni_value = uni_value * 16 + hextobin (*p); + } - /* A universal character name shall not specify a character short - identifier in the range 00000000 through 00000020, 0000007F through - 0000009F, or 0000D800 through 0000DFFF inclusive. A universal - character name shall not designate a character in the required - character set. */ - if ((uni_value <= 0x9f - && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60) - || (uni_value >= 0xd800 && uni_value <= 0xdfff)) - append_format(stderr_buffer, _(L"invalid universal character name \\%c%0*x"), - esc_char, (esc_char == L'u' ? 4 : 8), uni_value); - - append_format(stdout_buffer, L"%lc", uni_value); + /* A universal character name shall not specify a character short + identifier in the range 00000000 through 00000020, 0000007F through + 0000009F, or 0000D800 through 0000DFFF inclusive. A universal + character name shall not designate a character in the required + character set. */ + if ((uni_value <= 0x9f + && uni_value != 0x24 && uni_value != 0x40 && uni_value != 0x60) + || (uni_value >= 0xd800 && uni_value <= 0xdfff)) + append_format(stderr_buffer, _(L"invalid universal character name \\%c%0*x"), + esc_char, (esc_char == L'u' ? 4 : 8), uni_value); + append_format(stdout_buffer, L"%lc", uni_value); } - else + else { - append_format(stdout_buffer, L"%lc", L'\\'); - if (*p) - { - append_format (stdout_buffer, L"%lc", *p); - p++; - } + append_format(stdout_buffer, L"%lc", L'\\'); + if (*p) + { + append_format (stdout_buffer, L"%lc", *p); + p++; + } } - return p - escstart - 1; + return p - escstart - 1; } /* Print string STR, evaluating \ escapes. */ @@ -279,11 +277,11 @@ static int print_esc (const wchar_t *escstart, bool octal_0) static void print_esc_string (const wchar_t *str) { - for (; *str; str++) - if (*str == L'\\') - str += print_esc (str, true); - else - append_format (stdout_buffer, L"%lc", *str); + for (; *str; str++) + if (*str == L'\\') + str += print_esc (str, true); + else + append_format (stdout_buffer, L"%lc", *str); } /* Evaluate a printf conversion specification. START is the start of @@ -299,338 +297,316 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion bool have_precision, int precision, wchar_t const *argument) { - wchar_t *p; /* Null-terminated copy of % directive. */ - wcstring fmt; + wchar_t *p; /* Null-terminated copy of % directive. */ + wcstring fmt; - /* Create a null-terminated copy of the % directive, with an - intmax_t-wide length modifier substituted for any existing - integer length modifier. */ - { - wchar_t *q; - wchar_t const *length_modifier; - size_t length_modifier_len; - - switch (conversion) - { - case L'd': case L'i': - length_modifier = PRIdMAX; - length_modifier_len = sizeof PRIdMAX - 2; - break; - - case L'a': case L'e': case L'f': case L'g': - case L'A': case L'E': case L'F': case L'G': - length_modifier = L"L"; - length_modifier_len = 1; - break; - case L's': case L'u': - length_modifier = L"l"; - length_modifier_len = 1; - break; - default: - length_modifier = start; /* Any valid pointer will do. */ - length_modifier_len = 0; - break; - } - - p = new wchar_t[length + length_modifier_len + 2]; - q = static_cast(mempcpy (p, start, sizeof(wchar_t) * length)); - q = static_cast(mempcpy (q, length_modifier, sizeof(wchar_t) * length_modifier_len)); - *q++ = conversion; - *q = L'\0'; - } - - fmt = p; - switch (conversion) + /* Create a null-terminated copy of the % directive, with an + intmax_t-wide length modifier substituted for any existing + integer length modifier. */ { - case L'd': - case L'i': - { - intmax_t arg = vstrtoimax (argument); - if (!have_field_width) - { - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), arg); - else - append_format(stdout_buffer, fmt.c_str(), precision, arg); - } - else - { - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), field_width, arg); - else - append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); - } - } - break; + wchar_t *q; + wchar_t const *length_modifier; + size_t length_modifier_len; - case L'o': - case L'u': - case L'x': - case L'X': - { - - uintmax_t arg = vstrtoumax (argument); - if (!have_field_width) - { - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), arg); - else - append_format(stdout_buffer, fmt.c_str(), precision, arg); - } - else - { - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), field_width, arg); - else - append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); - } - } - break; - - case L'a': - case L'A': - case L'e': - case L'E': - case L'f': - case L'F': - case L'g': - case L'G': - { - - long double arg = vstrtold (argument); - if (!have_field_width) - { - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), arg); - else - append_format(stdout_buffer, fmt.c_str(), precision, arg); - } - else - { - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), field_width, arg); - else - append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); - } - } - break; - - case L'c': - if (!have_field_width) - append_format(stdout_buffer, fmt.c_str(), *argument); - else - append_format(stdout_buffer, fmt.c_str(), field_width, *argument); - break; - - case L's': - if (!have_field_width) - { - if (!have_precision){ - append_format(stdout_buffer, fmt.c_str(), argument);} - else - append_format(stdout_buffer, fmt.c_str(), precision, argument); - } - else - { - - if (!have_precision) - append_format(stdout_buffer, fmt.c_str(), field_width, argument); - else - append_format(stdout_buffer, fmt.c_str(), field_width, precision, argument); - } - break; + switch (conversion) + { + case L'd': case L'i': + length_modifier = PRIdMAX; + length_modifier_len = sizeof PRIdMAX - 2; + break; + case L'a': case L'e': case L'f': case L'g': + case L'A': case L'E': case L'F': case L'G': + length_modifier = L"L"; + length_modifier_len = 1; + break; + case L's': case L'u': + length_modifier = L"l"; + length_modifier_len = 1; + break; + default: + length_modifier = start; /* Any valid pointer will do. */ + length_modifier_len = 0; + break; + } + p = new wchar_t[length + length_modifier_len + 2]; + q = static_cast(mempcpy (p, start, sizeof(wchar_t) * length)); + q = static_cast(mempcpy (q, length_modifier, sizeof(wchar_t) * length_modifier_len)); + *q++ = conversion; + *q = L'\0'; } - free (p); + fmt = p; + switch (conversion) + { + case L'd': + case L'i': + { + intmax_t arg = vstrtoimax (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'o': + case L'u': + case L'x': + case L'X': + { + uintmax_t arg = vstrtoumax (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'a': + case L'A': + case L'e': + case L'E': + case L'f': + case L'F': + case L'g': + case L'G': + { + long double arg = vstrtold (argument); + if (!have_field_width) + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), arg); + else + append_format(stdout_buffer, fmt.c_str(), precision, arg); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, arg); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, arg); + } + } + break; + + case L'c': + if (!have_field_width) + append_format(stdout_buffer, fmt.c_str(), *argument); + else + append_format(stdout_buffer, fmt.c_str(), field_width, *argument); + break; + case L's': + if (!have_field_width) + { + if (!have_precision){ + append_format(stdout_buffer, fmt.c_str(), argument);} + else + append_format(stdout_buffer, fmt.c_str(), precision, argument); + } + else + { + if (!have_precision) + append_format(stdout_buffer, fmt.c_str(), field_width, argument); + else + append_format(stdout_buffer, fmt.c_str(), field_width, precision, argument); + } + break; + } + free (p); } /* Print the text in FORMAT, using ARGV (with ARGC elements) for arguments to any `%' directives. Return the number of elements of ARGV used. */ - static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) - { - int save_argc = argc; /* Preserve original value. */ - const wchar_t *f; /* Pointer into `format'. */ - const wchar_t *direc_start; /* Start of % directive. */ - size_t direc_length; /* Length of % directive. */ - bool have_field_width; /* True if FIELD_WIDTH is valid. */ - int field_width = 0; /* Arg to first '*'. */ - bool have_precision; /* True if PRECISION is valid. */ - int precision = 0; /* Arg to second '*'. */ - wchar_t ok[UCHAR_MAX + 1]; /* ok['x'] is true if %x is allowed. */ +static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { + int save_argc = argc; /* Preserve original value. */ + const wchar_t *f; /* Pointer into `format'. */ + const wchar_t *direc_start; /* Start of % directive. */ + size_t direc_length; /* Length of % directive. */ + bool have_field_width; /* True if FIELD_WIDTH is valid. */ + int field_width = 0; /* Arg to first '*'. */ + bool have_precision; /* True if PRECISION is valid. */ + int precision = 0; /* Arg to second '*'. */ + wchar_t ok[UCHAR_MAX + 1]; /* ok['x'] is true if %x is allowed. */ - for (f = format; *f != L'\0'; ++f) - { - switch (*f) - { - case L'%': - direc_start = f++; - direc_length = 1; - have_field_width = have_precision = false; - if (*f == L'%') - { - append_format(stdout_buffer, L"%lc", L'%'); - break; - } - if (*f == L'b') - { - /* FIXME: Field width and precision are not supported - for %b, even though POSIX requires it. */ - if (argc > 0) - { - print_esc_string (*argv); - ++argv; - --argc; - } - break; - } + for (f = format; *f != L'\0'; ++f) { + switch (*f) { + case L'%': + direc_start = f++; + direc_length = 1; + have_field_width = have_precision = false; + if (*f == L'%') { + append_format(stdout_buffer, L"%lc", L'%'); + break; + } + if (*f == L'b') { + /* FIXME: Field width and precision are not supported + for %b, even though POSIX requires it. */ + if (argc > 0) { + print_esc_string (*argv); + ++argv; + --argc; + } + break; + } - memset (ok, 0, sizeof ok); - ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = - ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = - ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1; + memset (ok, 0, sizeof ok); + ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = + ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = + ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1; - for (;; f++, direc_length++) - switch (*f) - { + for (;; f++, direc_length++) { + switch (*f) { #if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__ - case L'I': + case L'I': #endif - case L'\'': - ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = - ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0; - break; - case '-': case '+': case ' ': - break; - case L'#': - ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0; - break; - case '0': - ok['c'] = ok['s'] = 0; - break; - default: - goto no_more_flag_characters; - } - no_more_flag_characters:; + case L'\'': + ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = + ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0; + break; + case '-': case '+': case ' ': + break; + case L'#': + ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0; + break; + case '0': + ok['c'] = ok['s'] = 0; + break; + default: + goto no_more_flag_characters; + } + } + no_more_flag_characters:; - if (*f == L'*') - { - ++f; - ++direc_length; - if (argc > 0) - { - intmax_t width = vstrtoimax (*argv); - if (INT_MIN <= width && width <= INT_MAX) - field_width = width; - else - append_format(stderr_buffer, _(L"invalid field width: %ls"), - *argv); - ++argv; - --argc; - } - else{ - field_width = 0; - } - have_field_width = true; - } - else { - while (iswdigit(*f)) - { - ++f; - ++direc_length; - } - } - if (*f == L'.') - { - ++f; - ++direc_length; - ok['c'] = 0; - if (*f == L'*') - { - ++f; - ++direc_length; - if (argc > 0) - { - intmax_t prec = vstrtoimax (*argv); - if (prec < 0) - { - /* A negative precision is taken as if the - precision were omitted, so -1 is safe - here even if prec < INT_MIN. */ - precision = -1; - } - else if (INT_MAX < prec) - append_format(stderr_buffer, _(L"invalid precision: %ls"), - *argv); - else - precision = prec; - ++argv; - --argc; - } - else - precision = 0; - have_precision = true; - } - else - while (iswdigit(*f)) - { - ++f; - ++direc_length; - } - } + if (*f == L'*') { + ++f; + ++direc_length; + if (argc > 0) { + intmax_t width = vstrtoimax (*argv); + if (INT_MIN <= width && width <= INT_MAX) + field_width = width; + else + append_format(stderr_buffer, _(L"invalid field width: %ls"), *argv); + ++argv; + --argc; + } + else { + field_width = 0; + } + have_field_width = true; + } + else { + while (iswdigit(*f)) { + ++f; + ++direc_length; + } + } + if (*f == L'.') { + ++f; + ++direc_length; + ok['c'] = 0; + if (*f == L'*') { + ++f; + ++direc_length; + if (argc > 0) { + intmax_t prec = vstrtoimax (*argv); + if (prec < 0) { + /* A negative precision is taken as if the + precision were omitted, so -1 is safe + here even if prec < INT_MIN. */ + precision = -1; + } + else if (INT_MAX < prec) + append_format(stderr_buffer, _(L"invalid precision: %ls"), *argv); + else { + precision = prec; + } + ++argv; + --argc; + } + else { + precision = 0; + } + have_precision = true; + } + else { + while (iswdigit(*f)) { + ++f; + ++direc_length; + } + } + } - while (*f == L'l' || *f == L'L' || *f == L'h' - || *f == L'j' || *f == L't' || *f == L'z') - ++f; + while (*f == L'l' || *f == L'L' || *f == L'h' + || *f == L'j' || *f == L't' || *f == L'z') + ++f; + { + unsigned wchar_t conversion = *f; + if (! ok[conversion]) + append_format(stderr_buffer, + _("%.*ls: invalid conversion specification"), + (int) (f + 1 - direc_start), direc_start); + } - { - unsigned wchar_t conversion = *f; - if (! ok[conversion]) - append_format(stderr_buffer, - _("%.*ls: invalid conversion specification"), - (int) (f + 1 - direc_start), direc_start); - } + print_direc (direc_start, direc_length, *f, + have_field_width, field_width, + have_precision, precision, + (argc <= 0 ? L"" : (argc--, *argv++))); + break; - print_direc (direc_start, direc_length, *f, - have_field_width, field_width, - have_precision, precision, - (argc <= 0 ? L"" : (argc--, *argv++))); - break; + case L'\\': + f += print_esc (f, false); + break; - case L'\\': - f += print_esc (f, false); - break; - - default: - append_format (stdout_buffer, L"%lc", *f); - } - } - - return save_argc - argc; + default: + append_format (stdout_buffer, L"%lc", *f); + } + } + return save_argc - argc; } static int builtin_printf(parser_t &parser, wchar_t **argv) { - wchar_t *format; - int args_used; - int argc=builtin_count_args(argv); + wchar_t *format; + int args_used; + int argc = builtin_count_args(argv); - if (argc <= 1) + if (argc <= 1) { - append_format(stderr_buffer, _(L"missing operand")); - return EXIT_FAILURE; + append_format(stderr_buffer, _(L"missing operand")); + return EXIT_FAILURE; } - format = argv[1]; - argc -= 2; - argv += 2; + format = argv[1]; + argc -= 2; + argv += 2; - do + do { - args_used = print_formatted (format, argc, argv); - argc -= args_used; - argv += args_used; + args_used = print_formatted (format, argc, argv); + argc -= args_used; + argv += args_used; } - while (args_used > 0 && argc > 0); -} + while (args_used > 0 && argc > 0); +} \ No newline at end of file From ab52469fbbfa9f0cbd725b259c25bb54bc0fdee7 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 3 Mar 2013 15:32:32 +0530 Subject: [PATCH 07/14] Changed type of ok array in builtin_printf.cpp to bool --- builtin_printf.cpp | 75 +++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index 92ace0bc1..2b78b23c4 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -448,22 +448,27 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { int field_width = 0; /* Arg to first '*'. */ bool have_precision; /* True if PRECISION is valid. */ int precision = 0; /* Arg to second '*'. */ - wchar_t ok[UCHAR_MAX + 1]; /* ok['x'] is true if %x is allowed. */ + bool ok[UCHAR_MAX + 1] = { }; /* ok['x'] is true if %x is allowed. */ - for (f = format; *f != L'\0'; ++f) { - switch (*f) { + for (f = format; *f != L'\0'; ++f) + { + switch (*f) + { case L'%': direc_start = f++; direc_length = 1; have_field_width = have_precision = false; - if (*f == L'%') { + if (*f == L'%') + { append_format(stdout_buffer, L"%lc", L'%'); break; } - if (*f == L'b') { + if (*f == L'b') + { /* FIXME: Field width and precision are not supported for %b, even though POSIX requires it. */ - if (argc > 0) { + if (argc > 0) + { print_esc_string (*argv); ++argv; --argc; @@ -471,27 +476,28 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { break; } - memset (ok, 0, sizeof ok); ok['a'] = ok['A'] = ok['c'] = ok['d'] = ok['e'] = ok['E'] = ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] = - ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1; + ok['s'] = ok['u'] = ok['x'] = ok['X'] = true; - for (;; f++, direc_length++) { - switch (*f) { + for (;; f++, direc_length++) + { + switch (*f) + { #if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__ case L'I': #endif case L'\'': ok['a'] = ok['A'] = ok['c'] = ok['e'] = ok['E'] = - ok['o'] = ok['s'] = ok['x'] = ok['X'] = 0; + ok['o'] = ok['s'] = ok['x'] = ok['X'] = false; break; case '-': case '+': case ' ': break; case L'#': - ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = 0; + ok['c'] = ok['d'] = ok['i'] = ok['s'] = ok['u'] = false; break; case '0': - ok['c'] = ok['s'] = 0; + ok['c'] = ok['s'] = false; break; default: goto no_more_flag_characters; @@ -499,10 +505,12 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { } no_more_flag_characters:; - if (*f == L'*') { + if (*f == L'*') + { ++f; ++direc_length; - if (argc > 0) { + if (argc > 0) + { intmax_t width = vstrtoimax (*argv); if (INT_MIN <= width && width <= INT_MAX) field_width = width; @@ -511,27 +519,34 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { ++argv; --argc; } - else { + else + { field_width = 0; } have_field_width = true; } - else { - while (iswdigit(*f)) { + else + { + while (iswdigit(*f)) + { ++f; ++direc_length; } } - if (*f == L'.') { + if (*f == L'.') + { ++f; ++direc_length; - ok['c'] = 0; - if (*f == L'*') { + ok['c'] = false; + if (*f == L'*') + { ++f; ++direc_length; - if (argc > 0) { + if (argc > 0) + { intmax_t prec = vstrtoimax (*argv); - if (prec < 0) { + if (prec < 0) + { /* A negative precision is taken as if the precision were omitted, so -1 is safe here even if prec < INT_MIN. */ @@ -539,19 +554,23 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { } else if (INT_MAX < prec) append_format(stderr_buffer, _(L"invalid precision: %ls"), *argv); - else { + else + { precision = prec; } ++argv; --argc; } - else { + else + { precision = 0; } have_precision = true; } - else { - while (iswdigit(*f)) { + else + { + while (iswdigit(*f)) + { ++f; ++direc_length; } @@ -609,4 +628,4 @@ static int builtin_printf(parser_t &parser, wchar_t **argv) argv += args_used; } while (args_used > 0 && argc > 0); -} \ No newline at end of file +} From 97c9c9c9d123f1a31f99508d978ad1c77a86f291 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 3 Mar 2013 16:22:26 +0530 Subject: [PATCH 08/14] Use wmemcpy instead of mempcpy in printf builtin --- builtin_printf.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index 2b78b23c4..b579d15ec 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -297,7 +297,6 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion bool have_precision, int precision, wchar_t const *argument) { - wchar_t *p; /* Null-terminated copy of % directive. */ wcstring fmt; /* Create a null-terminated copy of the % directive, with an @@ -328,14 +327,15 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion length_modifier_len = 0; break; } - p = new wchar_t[length + length_modifier_len + 2]; - q = static_cast(mempcpy (p, start, sizeof(wchar_t) * length)); - q = static_cast(mempcpy (q, length_modifier, sizeof(wchar_t) * length_modifier_len)); + + wchar_t p[length + length_modifier_len + 2]; /* Null-terminated copy of % directive. */ + q = wmemcpy(p, start, length) + length; + q = wmemcpy(q, length_modifier, length_modifier_len) + length_modifier_len; *q++ = conversion; *q = L'\0'; + fmt = p; } - fmt = p; switch (conversion) { case L'd': @@ -432,7 +432,6 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion } break; } - free (p); } /* Print the text in FORMAT, using ARGV (with ARGC elements) for @@ -628,4 +627,5 @@ static int builtin_printf(parser_t &parser, wchar_t **argv) argv += args_used; } while (args_used > 0 && argc > 0); + return 0; } From 42be7733fe9b214be187eb7b3719a00b0f43d07d Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Mon, 4 Mar 2013 23:25:14 +0530 Subject: [PATCH 09/14] Return EXIT_FAILURE in printf builtin if conversion to number fails --- builtin_printf.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index b579d15ec..f184c2ad1 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -68,6 +68,8 @@ # define PRIdMAX L"ld" +static int exit_code; + /* True if the POSIXLY_CORRECT environment variable is set. */ static bool posixly_correct; @@ -120,6 +122,7 @@ static void verify_numeric (const wchar_t *s, const wchar_t *end) if (errno) { append_format(stderr_buffer, L"%ls", s); + exit_code = EXIT_FAILURE; } else if (*end) { @@ -127,6 +130,7 @@ static void verify_numeric (const wchar_t *s, const wchar_t *end) append_format(stderr_buffer, _(L"%ls: expected a numeric value"), s); else append_format(stderr_buffer, _(L"%ls: value not completely converted"), s); + exit_code = EXIT_FAILURE; } } @@ -175,7 +179,7 @@ print_esc_char (wchar_t c) append_format(stdout_buffer, L"%lc", L'\b'); break; case L'c': /* Cancel the rest of the output. */ - exit (EXIT_SUCCESS); + return; break; case L'f': /* Form feed. */ append_format(stdout_buffer, L"%lc", L'\f'); @@ -610,6 +614,8 @@ static int builtin_printf(parser_t &parser, wchar_t **argv) int args_used; int argc = builtin_count_args(argv); + exit_code = EXIT_SUCCESS; + if (argc <= 1) { append_format(stderr_buffer, _(L"missing operand")); @@ -627,5 +633,5 @@ static int builtin_printf(parser_t &parser, wchar_t **argv) argv += args_used; } while (args_used > 0 && argc > 0); - return 0; + return exit_code; } From a5a7a324479203b18c20b984cc7740e07bec7e11 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sat, 16 Mar 2013 23:32:26 +0530 Subject: [PATCH 10/14] Use fixed value "lld" instead of PRIdMAX --- builtin_printf.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index f184c2ad1..c63231ae5 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -66,8 +66,6 @@ # define ISDIGIT(c) ((unsigned int) (c) - L'0' <= 9) -# define PRIdMAX L"ld" - static int exit_code; /* True if the POSIXLY_CORRECT environment variable is set. */ @@ -314,8 +312,8 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion switch (conversion) { case L'd': case L'i': - length_modifier = PRIdMAX; - length_modifier_len = sizeof PRIdMAX - 2; + length_modifier = L"lld"; + length_modifier_len = sizeof L"lld" - 2; break; case L'a': case L'e': case L'f': case L'g': case L'A': case L'E': case L'F': case L'G': From 490ead52eb8fa246f882c8993344184904fe1eb0 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 17 Mar 2013 00:04:11 +0530 Subject: [PATCH 11/14] Changed octtobin, hextobin and isodigit macros into functions --- builtin_printf.cpp | 76 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 71 insertions(+), 5 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index c63231ae5..b190b3163 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -59,12 +59,78 @@ #define AUTHORS "David MacKenzie" -#define isodigit(c) ((c) >= L'0' && (c) <= L'7') -#define hextobin(c) ((c) >= L'a' && (c) <= L'f' ? (c) - L'a' + 10 : \ - (c) >= L'A' && (c) <= L'F' ? (c) - L'A' + 10 : (c) - L'0') -#define octtobin(c) ((c) - L'0') +bool isodigit(const wchar_t &c) +{ + return wcschr(L"01234567", c) != NULL; +} -# define ISDIGIT(c) ((unsigned int) (c) - L'0' <= 9) +int hextobin(const wchar_t &c) +{ + switch (c) + { + case L'0': + return 0; + case L'1': + return 1; + case L'2': + return 2; + case L'3': + return 3; + case L'4': + return 4; + case L'5': + return 5; + case L'6': + return 6; + case L'7': + return 7; + case L'8': + return 8; + case L'9': + return 9; + case L'a': + return 10; + case L'b': + return 11; + case L'c': + return 12; + case 'd': + return 13; + case 'e': + return 14; + case 'f': + return 15; + default: + append_format(stderr_buffer, L"Invalid hex number : %lc", c); + return -1; + } +} + +int octtobin(const wchar_t &c) +{ + switch (c) + { + case L'0': + return 0; + case L'1': + return 1; + case L'2': + return 2; + case L'3': + return 3; + case L'4': + return 4; + case L'5': + return 5; + case L'6': + return 6; + case L'7': + return 7; + default: + append_format(stderr_buffer, L"Invalid octal number : %lc", c); + return -1; + } +} static int exit_code; From 359a7cebde1805831e923d414f41f20e0616ed57 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 17 Mar 2013 00:20:02 +0530 Subject: [PATCH 12/14] Use wcstoimax and wcstoumax instead of strtoimax and strtoumax in printf builtin --- builtin_printf.cpp | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index b190b3163..099a2f0d0 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -46,14 +46,15 @@ David MacKenzie */ +/* This file has been imported from source code of printf command in GNU Coreutils version 6.9 */ + #include #include #include +#include #include "common.h" -// This file has been imported from source code of printf command in GNU Coreutils version 6.9 - /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "printf" @@ -142,20 +143,7 @@ static bool posixly_correct; static wchar_t const *const cfcc_msg = N_(L"warning: %s: character(s) following character constant have been ignored"); -int strtoimax (wchar_t const *ptr, wchar_t **endptr, int base) -{ - return wcstol (ptr, endptr, base); -} - -int strtoumax (wchar_t const *ptr, wchar_t **endptr, int base) -{ - return wcstol (ptr, endptr, base); -} - -# define STRTOD wcstod - -double -C_STRTOD (wchar_t const *nptr, wchar_t **endptr) +double C_STRTOD (wchar_t const *nptr, wchar_t **endptr) { double r; @@ -166,7 +154,7 @@ C_STRTOD (wchar_t const *nptr, wchar_t **endptr) wsetlocale (LC_NUMERIC, L"C"); } - r = STRTOD (nptr, endptr); + r = wcstod(nptr, endptr); if (!saved_locale.empty()) { @@ -225,8 +213,8 @@ FUNC_NAME (wchar_t const *s) \ return val; \ } \ -STRTOX (intmax_t, vstrtoimax, strtoimax (s, &end, 0)) -STRTOX (uintmax_t, vstrtoumax, strtoumax (s, &end, 0)) +STRTOX (intmax_t, vwcstoimax, wcstoimax (s, &end, 0)) +STRTOX (uintmax_t, vwcstoumax, wcstoumax (s, &end, 0)) STRTOX (long double, vstrtold, C_STRTOD(s, &end)) /* Output a single-character \ escape. */ @@ -409,7 +397,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'd': case L'i': { - intmax_t arg = vstrtoimax (argument); + intmax_t arg = vwcstoimax (argument); if (!have_field_width) { if (!have_precision) @@ -432,7 +420,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'x': case L'X': { - uintmax_t arg = vstrtoumax (argument); + uintmax_t arg = vwcstoumax (argument); if (!have_field_width) { if (!have_precision) @@ -578,7 +566,7 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { ++direc_length; if (argc > 0) { - intmax_t width = vstrtoimax (*argv); + intmax_t width = vwcstoimax (*argv); if (INT_MIN <= width && width <= INT_MAX) field_width = width; else @@ -611,7 +599,7 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { ++direc_length; if (argc > 0) { - intmax_t prec = vstrtoimax (*argv); + intmax_t prec = vwcstoimax (*argv); if (prec < 0) { /* A negative precision is taken as if the From d8dbdc83c08584968a551624825e07eae0edfb34 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 17 Mar 2013 00:28:12 +0530 Subject: [PATCH 13/14] Cleaned up some code in printf builtin --- builtin_printf.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index 099a2f0d0..3ed4503de 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -55,11 +55,6 @@ #include "common.h" -/* The official name of this program (e.g., no `g' prefix). */ -#define PROGRAM_NAME "printf" - -#define AUTHORS "David MacKenzie" - bool isodigit(const wchar_t &c) { return wcschr(L"01234567", c) != NULL; @@ -141,7 +136,7 @@ static bool posixly_correct; /* This message appears in N_() here rather than just in _() below because the sole use would have been in a #define. */ static wchar_t const *const cfcc_msg = - N_(L"warning: %s: character(s) following character constant have been ignored"); + N_(L"warning: %ls: character(s) following character constant have been ignored"); double C_STRTOD (wchar_t const *nptr, wchar_t **endptr) { @@ -215,12 +210,11 @@ FUNC_NAME (wchar_t const *s) \ STRTOX (intmax_t, vwcstoimax, wcstoimax (s, &end, 0)) STRTOX (uintmax_t, vwcstoumax, wcstoumax (s, &end, 0)) -STRTOX (long double, vstrtold, C_STRTOD(s, &end)) +STRTOX (long double, vwcstold, C_STRTOD(s, &end)) /* Output a single-character \ escape. */ -static void -print_esc_char (wchar_t c) +static void print_esc_char (wchar_t c) { switch (c) { @@ -447,7 +441,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'g': case L'G': { - long double arg = vstrtold (argument); + long double arg = vwcstold (argument); if (!have_field_width) { if (!have_precision) From 5dbda6cd95b9ed74134805e1adc00144ea7a0e84 Mon Sep 17 00:00:00 2001 From: Siteshwar Vashisht Date: Sun, 17 Mar 2013 00:43:06 +0530 Subject: [PATCH 14/14] Fixed some case statements in hextobin function --- builtin_printf.cpp | 84 +++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/builtin_printf.cpp b/builtin_printf.cpp index 3ed4503de..670805aab 100644 --- a/builtin_printf.cpp +++ b/builtin_printf.cpp @@ -90,11 +90,11 @@ int hextobin(const wchar_t &c) return 11; case L'c': return 12; - case 'd': + case L'd': return 13; - case 'e': + case L'e': return 14; - case 'f': + case L'f': return 15; default: append_format(stderr_buffer, L"Invalid hex number : %lc", c); @@ -138,33 +138,33 @@ static bool posixly_correct; static wchar_t const *const cfcc_msg = N_(L"warning: %ls: character(s) following character constant have been ignored"); -double C_STRTOD (wchar_t const *nptr, wchar_t **endptr) +double C_STRTOD(wchar_t const *nptr, wchar_t **endptr) { double r; - const wcstring saved_locale = wsetlocale (LC_NUMERIC, NULL); + const wcstring saved_locale = wsetlocale(LC_NUMERIC, NULL); if (!saved_locale.empty()) { - wsetlocale (LC_NUMERIC, L"C"); + wsetlocale(LC_NUMERIC, L"C"); } r = wcstod(nptr, endptr); if (!saved_locale.empty()) { - wsetlocale (LC_NUMERIC, saved_locale.c_str()); + wsetlocale(LC_NUMERIC, saved_locale.c_str()); } return r; } -static inline unsigned wchar_t to_uchar (wchar_t ch) +static inline unsigned wchar_t to_uwchar_t(wchar_t ch) { return ch; } -static void verify_numeric (const wchar_t *s, const wchar_t *end) +static void verify_numeric(const wchar_t *s, const wchar_t *end) { if (errno) { @@ -183,7 +183,7 @@ static void verify_numeric (const wchar_t *s, const wchar_t *end) #define STRTOX(TYPE, FUNC_NAME, LIB_FUNC_EXPR) \ static TYPE \ -FUNC_NAME (wchar_t const *s) \ +FUNC_NAME(wchar_t const *s) \ { \ wchar_t *end; \ TYPE val; \ @@ -203,18 +203,18 @@ FUNC_NAME (wchar_t const *s) \ { \ errno = 0; \ val = (LIB_FUNC_EXPR); \ - verify_numeric (s, end); \ + verify_numeric(s, end); \ } \ return val; \ } \ -STRTOX (intmax_t, vwcstoimax, wcstoimax (s, &end, 0)) -STRTOX (uintmax_t, vwcstoumax, wcstoumax (s, &end, 0)) -STRTOX (long double, vwcstold, C_STRTOD(s, &end)) +STRTOX(intmax_t, vwcstoimax, wcstoimax(s, &end, 0)) +STRTOX(uintmax_t, vwcstoumax, wcstoumax(s, &end, 0)) +STRTOX(long double, vwcstold, C_STRTOD(s, &end)) /* Output a single-character \ escape. */ -static void print_esc_char (wchar_t c) +static void print_esc_char(wchar_t c) { switch (c) { @@ -253,7 +253,7 @@ static void print_esc_char (wchar_t c) besides the backslash. If OCTAL_0 is nonzero, octal escapes are of the form \0ooo, where o is an octal digit; otherwise they are of the form \ooo. */ -static int print_esc (const wchar_t *escstart, bool octal_0) +static int print_esc(const wchar_t *escstart, bool octal_0) { const wchar_t *p = escstart + 1; int esc_value = 0; /* Value of \nnn escape. */ @@ -263,26 +263,26 @@ static int print_esc (const wchar_t *escstart, bool octal_0) { /* A hexadecimal \xhh escape sequence must have 1 or 2 hex. digits. */ for (esc_length = 0, ++p; - esc_length < 2 && isxdigit (to_uchar (*p)); + esc_length < 2 && isxdigit(to_uwchar_t(*p)); ++esc_length, ++p) - esc_value = esc_value * 16 + hextobin (*p); + esc_value = esc_value * 16 + hextobin(*p); if (esc_length == 0) append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); - append_format (stdout_buffer, L"%lc", esc_value); + append_format(stdout_buffer, L"%lc", esc_value); } - else if (isodigit (*p)) + else if (isodigit(*p)) { /* Parse \0ooo (if octal_0 && *p == L'0') or \ooo (otherwise). Allow \ooo if octal_0 && *p != L'0'; this is an undocumented extension to POSIX that is compatible with Bash 2.05b. */ for (esc_length = 0, p += octal_0 && *p == L'0'; - esc_length < 3 && isodigit (*p); + esc_length < 3 && isodigit(*p); ++esc_length, ++p) - esc_value = esc_value * 8 + octtobin (*p); + esc_value = esc_value * 8 + octtobin(*p); append_format(stdout_buffer, L"%c", esc_value); } - else if (*p && wcschr (L"\"\\abcfnrtv", *p)) - print_esc_char (*p++); + else if (*p && wcschr(L"\"\\abcfnrtv", *p)) + print_esc_char(*p++); else if (*p == L'u' || *p == L'U') { wchar_t esc_char = *p; @@ -293,9 +293,9 @@ static int print_esc (const wchar_t *escstart, bool octal_0) esc_length > 0; --esc_length, ++p) { - if (! isxdigit (to_uchar (*p))) + if (! isxdigit(to_uwchar_t(*p))) append_format(stderr_buffer, _(L"missing hexadecimal number in escape")); - uni_value = uni_value * 16 + hextobin (*p); + uni_value = uni_value * 16 + hextobin(*p); } /* A universal character name shall not specify a character short @@ -315,7 +315,7 @@ static int print_esc (const wchar_t *escstart, bool octal_0) append_format(stdout_buffer, L"%lc", L'\\'); if (*p) { - append_format (stdout_buffer, L"%lc", *p); + append_format(stdout_buffer, L"%lc", *p); p++; } } @@ -325,13 +325,13 @@ static int print_esc (const wchar_t *escstart, bool octal_0) /* Print string STR, evaluating \ escapes. */ static void -print_esc_string (const wchar_t *str) +print_esc_string(const wchar_t *str) { for (; *str; str++) if (*str == L'\\') - str += print_esc (str, true); + str += print_esc(str, true); else - append_format (stdout_buffer, L"%lc", *str); + append_format(stdout_buffer, L"%lc", *str); } /* Evaluate a printf conversion specification. START is the start of @@ -342,7 +342,7 @@ print_esc_string (const wchar_t *str) HAVE_PRECISION are true, respectively. ARGUMENT is the argument to be formatted. */ -static void print_direc (const wchar_t *start, size_t length, wchar_t conversion, +static void print_direc(const wchar_t *start, size_t length, wchar_t conversion, bool have_field_width, int field_width, bool have_precision, int precision, wchar_t const *argument) @@ -391,7 +391,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'd': case L'i': { - intmax_t arg = vwcstoimax (argument); + intmax_t arg = vwcstoimax(argument); if (!have_field_width) { if (!have_precision) @@ -414,7 +414,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'x': case L'X': { - uintmax_t arg = vwcstoumax (argument); + uintmax_t arg = vwcstoumax(argument); if (!have_field_width) { if (!have_precision) @@ -441,7 +441,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion case L'g': case L'G': { - long double arg = vwcstold (argument); + long double arg = vwcstold(argument); if (!have_field_width) { if (!have_precision) @@ -488,7 +488,7 @@ static void print_direc (const wchar_t *start, size_t length, wchar_t conversion arguments to any `%' directives. Return the number of elements of ARGV used. */ -static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { +static int print_formatted(const wchar_t *format, int argc, wchar_t **argv) { int save_argc = argc; /* Preserve original value. */ const wchar_t *f; /* Pointer into `format'. */ const wchar_t *direc_start; /* Start of % directive. */ @@ -518,7 +518,7 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { for %b, even though POSIX requires it. */ if (argc > 0) { - print_esc_string (*argv); + print_esc_string(*argv); ++argv; --argc; } @@ -560,7 +560,7 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { ++direc_length; if (argc > 0) { - intmax_t width = vwcstoimax (*argv); + intmax_t width = vwcstoimax(*argv); if (INT_MIN <= width && width <= INT_MAX) field_width = width; else @@ -593,7 +593,7 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { ++direc_length; if (argc > 0) { - intmax_t prec = vwcstoimax (*argv); + intmax_t prec = vwcstoimax(*argv); if (prec < 0) { /* A negative precision is taken as if the @@ -637,18 +637,18 @@ static int print_formatted (const wchar_t *format, int argc, wchar_t **argv) { (int) (f + 1 - direc_start), direc_start); } - print_direc (direc_start, direc_length, *f, + print_direc(direc_start, direc_length, *f, have_field_width, field_width, have_precision, precision, (argc <= 0 ? L"" : (argc--, *argv++))); break; case L'\\': - f += print_esc (f, false); + f += print_esc(f, false); break; default: - append_format (stdout_buffer, L"%lc", *f); + append_format(stdout_buffer, L"%lc", *f); } } return save_argc - argc; @@ -674,7 +674,7 @@ static int builtin_printf(parser_t &parser, wchar_t **argv) do { - args_used = print_formatted (format, argc, argv); + args_used = print_formatted(format, argc, argv); argc -= args_used; argv += args_used; }