From e0f95098eeba0176864b9cafe6d69b5b7bc0e73f Mon Sep 17 00:00:00 2001 From: Peter Avalos Date: Sun, 19 Apr 2009 05:26:39 +0000 Subject: [PATCH] Sync libc/stdio with FreeBSD: * Rewrite asprintf() as a wrapper around vasprintf(). * Add dprintf() and vdprintf() from POSIX.1-2008. * Remove an obsolete comment from fclose.3 regarding the placement of a FUNLOCKFILE() call. * Remove useless variable 'nofile' in fdopen(). * Remove comment about clearerr() being the only method of clearing the EOF indicator, fseek() may also be used for this. * Add commentary explaining why we return EBADF upon attempts to fflush() a read-only file. * Fix a few style and whitespace nits. * Suggest that fgets() be used instead of gets(). * Don't use __sgetc() to avoid overwriting fwide(3) orientation (__srget() call by __sgetc() uses _SET_ORIENTATION macro). * Fix a sign-compare issue in fgetwln(). * Use C99-style initializers. * Correct some buffer sizes. * Rework the floating point code in printf(). Significant changes: - We used to round long double arguments to double. Now we print them properly. - Bugs involving '%F', corner cases of '#' and 'g' format specifiers, and the '.*' precision specifier have been fixed. - Added support for the "'" specifier to print thousands' grouping characters in a locale-dependent manner. - Implement the __vfprintf() side of hexadecimal floating point support. All that is still needed is a routine to convert the mantissa to hex digits one nibble at a time in the style of ultoa(). * Add restrict qualifier. * Add rewind() to the list of functions which may fail and set errno. * Improve documentation for fgetpos() and fsetpos(), and discourage users from assuming that fpos_t is an integral type. * Describe the restrictions on seeking on wide character streams, and also point out that fseek() clears the ungetwc() buffer. * Save errno from getting clobbered where appropriate. * Resulting fseek() offset must fit in long, required by POSIX, so add LONG_MAX and final tests for it. * Disallow negative seek as POSIX requires for fseek{o}. * Catch few possible off_t overflows. * Make fseek(... SEEK_CUR) fails if current file-position is unspecified. * Move all stdio internal flags processing and setting out of __sread(), __swrite() and __sseek() to higher level. According to funopen(3) they all are just wrappers to something like standard read(2), write(2) and lseek(2), i.e. must not touch stdio internals because they are replaceable with any other functions knows nothing about stdio internals. * Rename cantwrite() to prepwrite(). The latter is less confusing, since the macro isn't really a predicate, and it has side-effects. Also, don't set errno if prepwrite() fails, since this is done in prepwrite() now. * Fix a potential deadlock in _fwalk in a threaded environment. A file flag (__SIGN) was added to stdio.h that, when set, tells _fwalk to ignore it in its walk. This seemed to be needed in refill.c because each file needs to be locked when flushing. * Call __sgetc() directly in getchar() instead of taking an expensive detour through getc(). * Add getdelim() and getline(). * Document dependence of mktemp(3) on the non-reentrant arc4random(3). * Fix a few bugs with the _gettemp() routine which implements mkstemp(), mkstemps(), and mkdtemp(). - Add proper range checking for the 'slen' parameter passed to mkstemps(). - Try all possible permutations of a template if a collision is encountered. Previously, once a single template character reached 'z', it would not wrap around to '0' and keep going until it encountered the original starting letter. In the edge case that the randomly generated starting name used all 'z' characters, only that single name would be tried before giving up. * Use arc4random_uniform(3) since modulo size is not power of 2 in _gettemp. * Write the message to stderr, not file descriptor 2, so that perror() writes to the correct stream if stderr has been redirected with freopen(). * Use strerror_r() to format the error message so that strerror()'s static buffer does not get clobbered in perror(). * Move the positional argument handling code for vfprintf() to a new file, printf-pos.c, and move common definitions to printflocal.h. * Remove advertising clause in the copyrights. * In rewind.c: 1) add missing __sinit() as in fseek() it pretends to be. 2) use clearerr_unlocked() since we already lock stream before _fseeko() 3) don't zero errno at the end, it explicitely required by POSIX as the only one method to test rewind() error condition. 4) don't clearerr() if error happens in _fseeko() * When __SOPT is cleared, clear __SOFF too. * Save a few cycles and don't initialize the locking fields in FILE if they aren't going to be used later. * Add ENVIRONMENT section to tmpnam(3) and mention there that TMPDIR is ignored when issetugid(3) is true. Also add a SECURITY CONSIDERATIONS section. * Describe file-position behaviour from POSIX in ungetc(3). * Remove duplicate check for EOF from ungetc(); __ungetc() already checks. * In vasprintf, free the buffer when __vfprintf() fails and don't bother trying to shrink the buffer with realloc() before returning it. * Rework the floating point code in printf(). Significant changes: - We used to round long double arguments to double. Now we print them properly. - Bugs involving '%F', corner cases of '#' and 'g' format specifiers, and the '.*' precision specifier have been fixed. - Added support for the "'" specifier to print thousands' grouping characters in a locale-dependent manner. - Implement the __vfprintf() side of hexadecimal floating point support. All that is still needed is a routine to convert the mantissa to hex digits one nibble at a time in the style of ultoa(). * %e conversions with precision 0 should not cause a decimal point to be printed. * Fix %f conversions where the number of significant digits is < expt. * %E-like %g and %G conversions should remove trailing zeroes unless the # flag is present. Implement this behavior and add a comment describing it. * Implement __hdtoa() and __hldtoa() and enable printf() support for %a and %A, which print floating-point numbers in hexadecimal. * Add an extensible printf implementation compatible with GLIBC. * Add support for multibyte decimal_point encodings, e.g., U+066B. * Add support for multibyte thousands_sep encodings, e.g., U+066C. The integer thousands' separator code is rewritten in order to avoid having to preallocate a buffer for the largest possible digit string with the most possible instances of the longest possible multibyte thousands' separator. The new version inserts thousands' separators for integers using the same code as floating point. * Introduce a local variable and use it instead of passed in parameter to get rid of restrict qualifier discarding in vswscanf(). * Set the error indicator on an attempt to write to a read-only stream in wsetup.c. * Move the format_arg() attribute handling to where it belongs. Obtained-from: FreeBSD & NetBSD --- include/Makefile | 2 +- include/printf.h | 163 ++ include/stdarg.h | 3 + include/stdio.h | 320 ++-- lib/libc/include/libc_private.h | 8 - lib/libc/stdio/Makefile.inc | 29 +- lib/libc/stdio/_flock_stub.c | 75 +- lib/libc/stdio/asprintf.c | 73 +- lib/libc/stdio/clrerr.c | 16 +- lib/libc/stdio/{wprintf.c => dprintf.c} | 18 +- lib/libc/stdio/fclose.3 | 24 +- lib/libc/stdio/fclose.c | 22 +- lib/libc/stdio/{getwc.c => fcloseall.c} | 26 +- lib/libc/stdio/fdopen.c | 17 +- lib/libc/stdio/feof.c | 21 +- lib/libc/stdio/ferror.3 | 51 +- lib/libc/stdio/ferror.c | 20 +- lib/libc/stdio/fflush.3 | 6 +- lib/libc/stdio/fflush.c | 46 +- lib/libc/stdio/fgetc.c | 6 +- lib/libc/stdio/fgetln.3 | 8 +- lib/libc/stdio/fgetln.c | 19 +- lib/libc/stdio/fgetpos.c | 23 +- lib/libc/stdio/fgets.3 | 17 +- lib/libc/stdio/fgets.c | 8 +- lib/libc/stdio/fgetwc.c | 56 +- lib/libc/stdio/fgetwln.3 | 9 +- lib/libc/stdio/fgetwln.c | 4 +- lib/libc/stdio/fgetws.c | 8 +- lib/libc/stdio/fileno.c | 13 +- lib/libc/stdio/findfp.c | 83 +- lib/libc/stdio/flags.c | 6 +- lib/libc/stdio/floatio.h | 24 +- lib/libc/stdio/fopen.3 | 10 +- lib/libc/stdio/fopen.c | 16 +- lib/libc/stdio/fprintf.c | 8 +- lib/libc/stdio/fpurge.c | 7 +- lib/libc/stdio/fputc.c | 9 +- lib/libc/stdio/fputs.3 | 20 +- lib/libc/stdio/fputs.c | 14 +- lib/libc/stdio/fread.3 | 10 +- lib/libc/stdio/fread.c | 18 +- lib/libc/stdio/freopen.c | 40 +- lib/libc/stdio/fscanf.c | 9 +- lib/libc/stdio/fseek.3 | 110 +- lib/libc/stdio/fseek.c | 134 +- lib/libc/stdio/fsetpos.c | 6 +- lib/libc/stdio/ftell.c | 64 +- lib/libc/stdio/funopen.3 | 20 +- lib/libc/stdio/funopen.c | 12 +- lib/libc/stdio/fvwrite.c | 39 +- lib/libc/stdio/fwalk.c | 16 +- lib/libc/stdio/fwprintf.c | 6 +- lib/libc/stdio/fwrite.c | 11 +- lib/libc/stdio/fwscanf.c | 8 +- lib/libc/stdio/getc.3 | 22 +- lib/libc/stdio/getc.c | 10 +- lib/libc/stdio/getchar.c | 18 +- lib/libc/stdio/getdelim.c | 160 ++ lib/libc/stdio/getline.3 | 164 ++ lib/libc/stdio/{vwscanf.c => getline.c} | 18 +- lib/libc/stdio/gets.c | 19 +- lib/libc/stdio/getw.c | 6 +- lib/libc/stdio/getwc.3 | 26 +- lib/libc/stdio/getwc.c | 21 +- lib/libc/stdio/getwchar.c | 20 +- lib/libc/stdio/local.h | 82 +- lib/libc/stdio/makebuf.c | 10 +- lib/libc/stdio/mktemp.3 | 17 +- lib/libc/stdio/mktemp.c | 57 +- lib/libc/stdio/perror.c | 23 +- lib/libc/stdio/printf-pos.c | 755 ++++++++++ lib/libc/stdio/printf.3 | 201 ++- lib/libc/stdio/printf.c | 8 +- lib/libc/stdio/printfcommon.h | 301 ++++ lib/libc/stdio/{putchar.c => printflocal.h} | 84 +- lib/libc/stdio/priv_stdio.h | 20 +- lib/libc/stdio/putc.3 | 27 +- lib/libc/stdio/putc.c | 19 +- lib/libc/stdio/putchar.c | 30 +- lib/libc/stdio/puts.c | 11 +- lib/libc/stdio/putw.c | 6 +- lib/libc/stdio/putwc.3 | 40 +- lib/libc/stdio/putwc.c | 21 +- lib/libc/stdio/putwchar.c | 20 +- lib/libc/stdio/refill.c | 35 +- lib/libc/stdio/remove.3 | 6 +- lib/libc/stdio/remove.c | 6 +- lib/libc/stdio/rewind.c | 19 +- lib/libc/stdio/rget.c | 7 +- lib/libc/stdio/scanf.3 | 24 +- lib/libc/stdio/scanf.c | 9 +- lib/libc/stdio/setbuf.3 | 28 +- lib/libc/stdio/setbuf.c | 7 +- lib/libc/stdio/setbuffer.c | 6 +- lib/libc/stdio/setvbuf.c | 11 +- lib/libc/stdio/snprintf.c | 14 +- lib/libc/stdio/sprintf.c | 15 +- lib/libc/stdio/sscanf.c | 15 +- lib/libc/stdio/stdio.3 | 88 +- lib/libc/stdio/stdio.c | 124 +- lib/libc/stdio/swprintf.c | 6 +- lib/libc/stdio/swscanf.c | 6 +- lib/libc/stdio/tempnam.c | 8 +- lib/libc/stdio/tmpfile.c | 9 +- lib/libc/stdio/tmpnam.3 | 101 +- lib/libc/stdio/tmpnam.c | 11 +- lib/libc/stdio/ungetc.3 | 14 +- lib/libc/stdio/ungetc.c | 27 +- lib/libc/stdio/vasprintf.c | 21 +- lib/libc/stdio/{fwscanf.c => vdprintf.c} | 42 +- lib/libc/stdio/vfprintf.c | 1340 +++++------------ lib/libc/stdio/vfscanf.c | 77 +- lib/libc/stdio/vfwprintf.c | 1185 +++------------ lib/libc/stdio/vfwscanf.c | 85 +- lib/libc/stdio/vprintf.c | 10 +- lib/libc/stdio/vscanf.c | 10 +- lib/libc/stdio/vsnprintf.c | 17 +- lib/libc/stdio/vsprintf.c | 14 +- lib/libc/stdio/vsscanf.c | 16 +- lib/libc/stdio/vswprintf.c | 17 +- lib/libc/stdio/vswscanf.c | 26 +- lib/libc/stdio/vwprintf.c | 6 +- lib/libc/stdio/vwscanf.c | 6 +- lib/libc/stdio/wbuf.c | 11 +- lib/libc/stdio/wprintf.3 | 9 +- lib/libc/stdio/wprintf.c | 6 +- lib/libc/stdio/wscanf.3 | 9 +- lib/libc/stdio/wscanf.c | 6 +- lib/libc/stdio/wsetup.c | 15 +- lib/libc/stdio/xprintf.c | 694 +++++++++ lib/libc/stdio/{fwscanf.c => xprintf_errno.c} | 49 +- lib/libc/stdio/xprintf_float.c | 429 ++++++ .../stdio/{fgetws.c => xprintf_hexdump.c} | 107 +- lib/libc/stdio/xprintf_int.c | 478 ++++++ lib/libc/stdio/xprintf_quote.c | 103 ++ lib/libc/stdio/xprintf_str.c | 190 +++ lib/libc/stdio/{getc.c => xprintf_time.c} | 94 +- lib/libc/stdio/{fgetws.c => xprintf_vis.c} | 96 +- sys/sys/cdefs.h | 8 + 140 files changed, 6167 insertions(+), 3632 deletions(-) create mode 100644 include/printf.h copy lib/libc/stdio/{wprintf.c => dprintf.c} (83%) copy lib/libc/stdio/{getwc.c => fcloseall.c} (70%) create mode 100644 lib/libc/stdio/getdelim.c create mode 100644 lib/libc/stdio/getline.3 copy lib/libc/stdio/{vwscanf.c => getline.c} (80%) create mode 100644 lib/libc/stdio/printf-pos.c create mode 100644 lib/libc/stdio/printfcommon.h copy lib/libc/stdio/{putchar.c => printflocal.h} (50%) copy lib/libc/stdio/{fwscanf.c => vdprintf.c} (65%) create mode 100644 lib/libc/stdio/xprintf.c copy lib/libc/stdio/{fwscanf.c => xprintf_errno.c} (61%) create mode 100644 lib/libc/stdio/xprintf_float.c copy lib/libc/stdio/{fgetws.c => xprintf_hexdump.c} (53%) create mode 100644 lib/libc/stdio/xprintf_int.c create mode 100644 lib/libc/stdio/xprintf_quote.c create mode 100644 lib/libc/stdio/xprintf_str.c copy lib/libc/stdio/{getc.c => xprintf_time.c} (50%) copy lib/libc/stdio/{fgetws.c => xprintf_vis.c} (57%) diff --git a/include/Makefile b/include/Makefile index 231c074668..2d086fcdaf 100644 --- a/include/Makefile +++ b/include/Makefile @@ -17,7 +17,7 @@ INCS= a.out.h ar.h assert.h bitstring.h complex.h cpio.h ctype.h db.h \ langinfo.h libgen.h limits.h link.h locale.h malloc.h math.h memory.h \ mpool.h monetary.h ndbm.h netconfig.h \ netdb.h nl_types.h nlist.h nss.h nsswitch.h objformat.h \ - paths.h pthread.h pthread_np.h pwd.h \ + paths.h printf.h pthread.h pthread_np.h pwd.h \ ranlib.h readpassphrase.h regex.h regexp.h \ res_update.h resolv.h re_comp.h rmd160.h \ search.h setjmp.h sgtty.h \ diff --git a/include/printf.h b/include/printf.h new file mode 100644 index 0000000000..ffa24e12ee --- /dev/null +++ b/include/printf.h @@ -0,0 +1,163 @@ +/*- + * Copyright (c) 2005 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/include/printf.h,v 1.4 2006/03/02 10:01:52 phk Exp $ + */ + +#ifndef _PRINTF_H_ +#define _PRINTF_H_ + +#include + +/* + * The API defined by glibc allows a renderer to take multiple arguments + * This is obviously usable for things like (ptr+len) pairs etc. + * But the do not actually provide support for it at the end of the day, + * they offer only one argument to the arginfo function, but do accept + * >1 returns, although the do not check the types of those arguments + * argument + * Be compatible for now. + */ +#define __PRINTFMAXARG 2 + +struct printf_info { + /* GLIBC compatible */ + int prec; + int width; + wchar_t spec; + unsigned is_long_double; + unsigned is_char; + unsigned is_short; + unsigned is_long; + unsigned alt; + unsigned space; + unsigned left; + unsigned showsign; + unsigned group; + unsigned extra; + unsigned wide; + wchar_t pad; + + /* FreeBSD extensions */ + + unsigned is_quad; + unsigned is_intmax; + unsigned is_ptrdiff; + unsigned is_size; + + /* private */ + int sofar; + unsigned get_width; + unsigned get_prec; + const char *begin; + const char *end; + void *arg[__PRINTFMAXARG]; +}; + +enum { + PA_INT = (1 << 0), /* int */ + PA_CHAR = (1 << 1), /* int, cast to char */ + PA_WCHAR = (1 << 2), /* wide char */ + PA_STRING = (1 << 3), /* const char * (with '\0') */ + PA_WSTRING = (1 << 4), /* const wchar_t * */ + PA_POINTER = (1 << 5), /* void * */ + PA_FLOAT = (1 << 6), /* float */ + PA_DOUBLE = (1 << 7) /* double */ +}; + +#define PA_FLAG_MASK 0xff0000 +#define PA_FLAG_LONG_LONG (1 << 16) +#define PA_FLAG_LONG (1 << 17) +#define PA_FLAG_SHORT (1 << 18) +#define PA_FLAG_PTR (1 << 19) +#define PA_FLAG_QUAD (1 << 20) +#define PA_FLAG_INTMAX (1 << 21) +#define PA_FLAG_SIZE (1 << 22) +#define PA_FLAG_PTRDIFF (1 << 23) +#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG + +typedef int printf_arginfo_function(const struct printf_info *, size_t, int *); +typedef int printf_function(FILE *, const struct printf_info *, const void *const *); + +/* FreeBSD extension */ +struct __printf_io; +typedef int printf_render(struct __printf_io *, const struct printf_info *, const void *const *); + +/* vprintf.c */ +extern const char __lowercase_hex[17]; +extern const char __uppercase_hex[17]; + +void __printf_flush(struct __printf_io *io); +int __printf_puts(struct __printf_io *io, const void *ptr, int len); +int __printf_pad(struct __printf_io *io, int n, int zero); +int __printf_out(struct __printf_io *io, const struct printf_info *pi, const void *ptr, int len); + +int __xvprintf(FILE *fp, const char *fmt0, va_list ap); +extern int __use_xprintf; + +/* GLIBC compat */ +int register_printf_function(int spec, printf_function *render, printf_arginfo_function *arginfo); + +/* FreeBSD */ +int register_printf_render(int spec, printf_render *render, printf_arginfo_function *arginfo); +int register_printf_render_std(const unsigned char *specs); + +/* vprintf_errno.c */ +printf_arginfo_function __printf_arginfo_errno; +printf_render __printf_render_errno; + +/* vprintf_float.c */ +printf_arginfo_function __printf_arginfo_float; +printf_render __printf_render_float; + +/* vprintf_hexdump.c */ +printf_arginfo_function __printf_arginfo_hexdump; +printf_render __printf_render_hexdump; + +/* vprintf_int.c */ +printf_arginfo_function __printf_arginfo_ptr; +printf_arginfo_function __printf_arginfo_int; +printf_render __printf_render_ptr; +printf_render __printf_render_int; + +/* vprintf_quoute.c */ +printf_arginfo_function __printf_arginfo_quote; +printf_render __printf_render_quote; + +/* vprintf_str.c */ +printf_arginfo_function __printf_arginfo_chr; +printf_render __printf_render_chr; +printf_arginfo_function __printf_arginfo_str; +printf_render __printf_render_str; + +/* vprintf_time.c */ +printf_arginfo_function __printf_arginfo_time; +printf_render __printf_render_time; + +/* vprintf_vis.c */ +printf_arginfo_function __printf_arginfo_vis; +printf_render __printf_render_vis; + +#endif /* !_PRINTF_H */ diff --git a/include/stdarg.h b/include/stdarg.h index f8c48a5034..f26be77db6 100644 --- a/include/stdarg.h +++ b/include/stdarg.h @@ -37,7 +37,10 @@ #include #endif +#ifndef _VA_LIST_DECLARED typedef __va_list va_list; +#define _VA_LIST_DECLARED +#endif #define va_start(ap, last) __va_start(ap, last) #define va_arg(ap, type) __va_arg(ap, type) diff --git a/include/stdio.h b/include/stdio.h index 06ba005b5e..90f6d2973a 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * @(#)stdio.h 8.5 (Berkeley) 4/29/95 - * $FreeBSD: src/include/stdio.h,v 1.24.2.5 2002/11/09 08:07:20 imp Exp $ + * $FreeBSD: src/include/stdio.h,v 1.78 2009/03/25 08:07:52 das Exp $ * $DragonFly: src/include/stdio.h,v 1.14 2008/06/05 17:53:10 swildner Exp $ */ @@ -42,21 +42,35 @@ #define _STDIO_H_ #include -#ifndef _SYS_STDINT_H_ -#include -#endif -#ifndef _MACHINE_STDARG_H_ -#include -#endif +#include +#include + +typedef __off_t fpos_t; #ifndef _SIZE_T_DECLARED -#define _SIZE_T_DECLARED -typedef __size_t size_t; +typedef __size_t size_t; +#define _SIZE_T_DECLARED #endif -#include +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 +#ifndef _OFF_T_DECLARED +#define _OFF_T_DECLARED +typedef __off_t off_t; +#endif +#ifndef _SSIZE_T_DECLARED +#define _SSIZE_T_DECLARED +typedef __ssize_t ssize_t; +#endif +#endif -typedef __off_t fpos_t; +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200112 || __XSI_VISIBLE +#ifndef _VA_LIST_DECLARED +typedef __va_list va_list; +#define _VA_LIST_DECLARED +#endif +#endif + +#define _FSTDIO /* Define for new stdio with functions. */ /* * stdio state variables. @@ -81,7 +95,7 @@ typedef __off_t fpos_t; typedef struct __FILE FILE; struct __FILE_public { - unsigned char *_p; /* current position in (some) buffer */ + unsigned char *_p; /* current position in (some) buffer */ int _flags; /* flags, below; this FILE is free if 0 */ int _fileno; /* fileno, if Unix descriptor, else -1 */ __ssize_t _r; /* read space left for getc() */ @@ -89,9 +103,14 @@ struct __FILE_public { __ssize_t _lbfsize; /* 0 or -_bf._size, for inline putc */ }; +#ifndef _STDSTREAM_DECLARED __BEGIN_DECLS -extern FILE *__stdinp, *__stdoutp, *__stderrp; +extern FILE *__stdinp; +extern FILE *__stdoutp; +extern FILE *__stderrp; __END_DECLS +#define _STDSTREAM_DECLARED +#endif #define __SLBF 0x0001 /* line buffered */ #define __SNBF 0x0002 /* unbuffered */ @@ -109,6 +128,7 @@ __END_DECLS #define __SOFF 0x1000 /* set iff _offset is in fact correct */ #define __SMOD 0x2000 /* true => fgetln modified _p text */ #define __SALC 0x4000 /* allocate string space dynamically */ +#define __SIGN 0x8000 /* ignore this file in _fwalk */ /* * The following three definitions are for ANSI C, which took them @@ -132,11 +152,13 @@ __END_DECLS * (which could fail). Do not use this for anything. */ /* must be == _POSIX_STREAM_MAX */ +#ifndef FOPEN_MAX #define FOPEN_MAX 20 /* must be <= OPEN_MAX */ +#endif #define FILENAME_MAX 1024 /* must be <= PATH_MAX */ /* System V/ANSI C; this is the wrong way to do this, do *not* use these. */ -#ifndef _ANSI_SOURCE +#if __XSI_VISIBLE #define P_tmpdir "/tmp/" #endif #define L_tmpnam 1024 /* XXX must be == PATH_MAX */ @@ -152,178 +174,229 @@ __END_DECLS #define SEEK_END 2 /* set file offset to EOF plus offset */ #endif -#define stdin (__stdinp) -#define stdout (__stdoutp) -#define stderr (__stderrp) +#define stdin __stdinp +#define stdout __stdoutp +#define stderr __stderrp +__BEGIN_DECLS /* * Functions defined in ANSI C standard. */ -__BEGIN_DECLS void clearerr(FILE *); int fclose(FILE *); int feof(FILE *); -int feof_unlocked(FILE *); int ferror(FILE *); -int ferror_unlocked(FILE *); int fflush(FILE *); int fgetc(FILE *); -int fgetpos(FILE *, fpos_t *); -char *fgets(char *, int, FILE *); -FILE *fopen(const char *, const char *); -int fprintf(FILE *, const char *, ...); +int fgetpos(FILE * __restrict, fpos_t * __restrict); +char *fgets(char * __restrict, int, FILE * __restrict); +FILE *fopen(const char * __restrict, const char * __restrict); +int fprintf(FILE * __restrict, const char * __restrict, ...); int fputc(int, FILE *); -int fputs(const char *, FILE *); -size_t fread(void *, size_t, size_t, FILE *); -FILE *freopen(const char *, const char *, FILE *); -int fscanf(FILE *, const char *, ...); +int fputs(const char * __restrict, FILE * __restrict); +size_t fread(void * __restrict, size_t, size_t, FILE * __restrict); +FILE *freopen(const char * __restrict, const char * __restrict, + FILE * __restrict); +int fscanf(FILE * __restrict, const char * __restrict, ...); int fseek(FILE *, long, int); int fsetpos(FILE *, const fpos_t *); long ftell(FILE *); -size_t fwrite(const void *, size_t, size_t, FILE *); +size_t fwrite(const void * __restrict, size_t, size_t, FILE * __restrict); int getc(FILE *); -int getc_unlocked(FILE *); int getchar(void); -int getchar_unlocked(void); char *gets(char *); -#if !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -extern __const int sys_nerr; /* perror(3) external variables */ -extern __const char *__const sys_errlist[]; -#endif void perror(const char *); -int printf(const char *, ...); +int printf(const char * __restrict, ...); int putc(int, FILE *); -int putc_unlocked(int, FILE *); int putchar(int); -int putchar_unlocked(int); int puts(const char *); int remove(const char *); int rename(const char *, const char *); void rewind(FILE *); -int scanf(const char *, ...); -void setbuf(FILE *, char *); -int setvbuf(FILE *, char *, int, size_t); -int sprintf(char *, const char *, ...); -int sscanf(const char *, const char *, ...); +int scanf(const char * __restrict, ...); +void setbuf(FILE * __restrict, char * __restrict); +int setvbuf(FILE * __restrict, char * __restrict, int, size_t); +int sprintf(char * __restrict, const char * __restrict, ...); +int sscanf(const char * __restrict, const char * __restrict, ...); FILE *tmpfile(void); char *tmpnam(char *); int ungetc(int, FILE *); -int vfprintf(FILE *, const char *, __va_list); -int vprintf(const char *, __va_list); -int vsprintf(char *, const char *, __va_list); -__END_DECLS +int vfprintf(FILE * __restrict, const char * __restrict, __va_list); +int vprintf(const char * __restrict, __va_list); +int vsprintf(char * __restrict, const char * __restrict, __va_list); + +#if __ISO_C_VISIBLE >= 1999 +int snprintf(char * __restrict, size_t, const char * __restrict, ...) + __printflike(3, 4); +int vfscanf(FILE * __restrict, const char * __restrict, __va_list) + __scanflike(2, 0); +int vscanf(const char * __restrict, __va_list) __scanflike(1, 0); +int vsnprintf(char * __restrict, size_t, const char * __restrict, + __va_list) __printflike(3, 0); +int vsscanf(const char * __restrict, const char * __restrict, __va_list) + __scanflike(2, 0); +#endif /* - * Functions defined in POSIX 1003.1. + * Functions defined in all versions of POSIX 1003.1. */ -#ifndef _ANSI_SOURCE +#if __BSD_VISIBLE || __POSIX_VISIBLE <= 199506 /* size for cuserid(3); UT_NAMESIZE + 1, see */ -#define L_cuserid 17 +#define L_cuserid 17 /* legacy */ +#endif +#if __POSIX_VISIBLE #define L_ctermid 1024 /* size for ctermid(3); PATH_MAX */ -__BEGIN_DECLS char *ctermid(char *); FILE *fdopen(int, const char *); int fileno(FILE *); -int fileno_unlocked(FILE *); +#endif /* __POSIX_VISIBLE */ + +#if __POSIX_VISIBLE >= 199209 +int pclose(FILE *); +FILE *popen(const char *, const char *); +#endif + +#if __POSIX_VISIBLE >= 199506 int ftrylockfile(FILE *); void flockfile(FILE *); void funlockfile(FILE *); -__END_DECLS -#endif /* not ANSI */ /* - * Portability hacks. See . + * These are normally used through macros as defined below, but POSIX + * requires functions as well. */ -#if !defined (_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -__BEGIN_DECLS -#ifndef _FTRUNCATE_DECLARED -#define _FTRUNCATE_DECLARED -int ftruncate(int, __off_t); +int getc_unlocked(FILE *); +int getchar_unlocked(void); +int putc_unlocked(int, FILE *); +int putchar_unlocked(int); #endif -#ifndef _LSEEK_DECLARED -#define _LSEEK_DECLARED -__off_t lseek(int, __off_t, int); +#if __BSD_VISIBLE +void clearerr_unlocked(FILE *); +int feof_unlocked(FILE *); +int ferror_unlocked(FILE *); +int fileno_unlocked(FILE *); #endif -#ifndef _MMAP_DECLARED -#define _MMAP_DECLARED -void *mmap(void *, size_t, int, int, int, __off_t); + +#if __POSIX_VISIBLE >= 200112 +int fseeko(FILE *, __off_t, int); +__off_t ftello(FILE *); #endif -#ifndef _TRUNCATE_DECLARED -#define _TRUNCATE_DECLARED -int truncate(const char *, __off_t); + +#if __BSD_VISIBLE || __XSI_VISIBLE > 0 && __XSI_VISIBLE < 600 +int getw(FILE *); +int putw(int, FILE *); +#endif /* BSD or X/Open before issue 6 */ + +#if __XSI_VISIBLE +char *tempnam(const char *, const char *); #endif -__END_DECLS -#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ + +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 +ssize_t getdelim(char ** __restrict, size_t * __restrict, int, + FILE * __restrict); +/* int renameat(int, const char *, int, const char *); */ +int vdprintf(int, const char * __restrict, __va_list); + +/* + * Every programmer and his dog wrote functions called getline() and dprintf() + * before POSIX.1-2008 came along and decided to usurp the names, so we + * don't prototype them by default unless one of the following is true: + * a) the app has requested them specifically by defining _WITH_GETLINE or + * _WITH_DPRINTF, respectively + * b) the app has requested a POSIX.1-2008 environment via _POSIX_C_SOURCE + * c) the app defines a GNUism such as _BSD_SOURCE or _GNU_SOURCE + */ +#ifndef _WITH_GETLINE +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#define _WITH_GETLINE +#elif defined(_POSIX_C_SOURCE) +#if _POSIX_C_SOURCE >= 200809 +#define _WITH_GETLINE +#endif +#endif +#endif + +#ifdef _WITH_GETLINE +ssize_t getline(char ** __restrict, size_t * __restrict, FILE * __restrict); +#endif + +#ifndef _WITH_DPRINTF +#if defined(_BSD_SOURCE) || defined(_GNU_SOURCE) +#define _WITH_DPRINTF +#elif defined(_POSIX_C_SOURCE) +#if _POSIX_C_SOURCE >= 200809 +#define _WITH_DPRINTF +#endif +#endif +#endif + +#ifdef _WITH_DPRINTF +int dprintf(int, const char * __restrict, ...); +#endif + +#endif /* __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 */ /* * Routines that are purely local. */ -#if !defined (_ANSI_SOURCE) && !defined(_POSIX_SOURCE) -__BEGIN_DECLS +#if __BSD_VISIBLE int asprintf(char **, const char *, ...) __printflike(2, 3); char *ctermid_r(char *); +void fcloseall(void); void *fcookie(FILE *); char *fgetln(FILE *, size_t *); -#if __GNUC__ == 2 && __GNUC_MINOR__ >= 7 || __GNUC__ >= 3 -#define __ATTR_FORMAT_ARG __attribute__((__format_arg__(2))) -#else -#define __ATTR_FORMAT_ARG -#endif -const char *fmtcheck(const char *, const char *) __ATTR_FORMAT_ARG; +const char *fmtcheck(const char *, const char *) __format_arg(2); __ssize_t __fpending(const FILE *); int fpurge(FILE *); -int fseeko(FILE *, __off_t, int); -__off_t ftello(FILE *); -int getw(FILE *); -int pclose(FILE *); -FILE *popen(const char *, const char *); -int putw(int, FILE *); void setbuffer(FILE *, char *, int); int setlinebuf(FILE *); -char *tempnam(const char *, const char *); -int snprintf(char *, size_t, const char *, ...) __printflike(3, 4); -int vasprintf(char **, const char *, __va_list) - __printflike(2, 0); -int vsnprintf (char *, size_t, const char *, __va_list) - __printflike(3, 0); -int vscanf(const char *, __va_list) __scanflike(1, 0); -int vsscanf(const char *, const char *, __va_list) - __scanflike(2, 0); -__END_DECLS +int vasprintf(char **, const char *, __va_list) __printflike(2, 0); /* - * This is a #define because the function is used internally and - * (unlike vfscanf) the name __vfscanf is guaranteed not to collide - * with a user function when _ANSI_SOURCE or _POSIX_SOURCE is defined. + * The system error table contains messages for the first sys_nerr + * positive errno values. Use strerror() or strerror_r() from + * instead. */ -#define vfscanf __vfscanf +extern __const int sys_nerr; +extern __const char *__const sys_errlist[]; /* * Stdio function-access interface. */ -__BEGIN_DECLS -FILE *funopen(const void *, - int (*)(void *, char *, int), +FILE *funopen(const void *, int (*)(void *, char *, int), int (*)(void *, const char *, int), - fpos_t (*)(void *, fpos_t, int), - int (*)(void *)); -__END_DECLS + fpos_t (*)(void *, fpos_t, int), int (*)(void *)); #define fropen(cookie, fn) funopen(cookie, fn, 0, 0, 0) #define fwopen(cookie, fn) funopen(cookie, 0, fn, 0, 0) -#endif /* !_ANSI_SOURCE && !_POSIX_SOURCE */ + +/* + * Portability hacks. See . + */ +#ifndef _FTRUNCATE_DECLARED +#define _FTRUNCATE_DECLARED +int ftruncate(int, __off_t); +#endif +#ifndef _LSEEK_DECLARED +#define _LSEEK_DECLARED +__off_t lseek(int, __off_t, int); +#endif +#ifndef _MMAP_DECLARED +#define _MMAP_DECLARED +void *mmap(void *, size_t, int, int, int, __off_t); +#endif +#ifndef _TRUNCATE_DECLARED +#define _TRUNCATE_DECLARED +int truncate(const char *, __off_t); +#endif +#endif /* __BSD_VISIBLE */ /* * Functions internal to the implementation. */ -__BEGIN_DECLS int __srget(FILE *); -int __vfscanf(FILE *, const char *, __va_list); -int __svfscanf(FILE *, const char *, __va_list); int __swbuf(int, FILE *); -size_t __sreadahead(FILE *); -__END_DECLS /* * The __sfoo functions are here so that we can @@ -383,6 +456,23 @@ __sfileno(FILE *_fp) return (_p->_fileno); } +extern int __isthreaded; + +#define feof(p) (!__isthreaded ? __sfeof(p) : (feof)(p)) +#define ferror(p) (!__isthreaded ? __sferror(p) : (ferror)(p)) +#define clearerr(p) (!__isthreaded ? __sclearerr(p) : (clearerr)(p)) + +#if __POSIX_VISIBLE +#define fileno(p) (!__isthreaded ? __sfileno(p) : (fileno)(p)) +#endif + +#define getc(fp) (!__isthreaded ? __sgetc(fp) : (getc)(fp)) +#define putc(x, fp) (!__isthreaded ? __sputc(x, fp) : (putc)(x, fp)) + +#define getchar() getc(stdin) +#define putchar(x) putc(x, stdout) + +#if __BSD_VISIBLE /* * See ISO/IEC 9945-1 ANSI/IEEE Std 1003.1 Second Edition 1996-07-12 * B.8.2.7 for the rationale behind the *_unlocked() macros. @@ -390,15 +480,15 @@ __sfileno(FILE *_fp) #define feof_unlocked(p) __sfeof(p) #define ferror_unlocked(p) __sferror(p) #define clearerr_unlocked(p) __sclearerr(p) - -#ifndef _ANSI_SOURCE #define fileno_unlocked(p) __sfileno(p) #endif - -#define getc_unlocked(fp) __sgetc(fp) +#if __POSIX_VISIBLE >= 199506 +#define getc_unlocked(fp) __sgetc(fp) #define putc_unlocked(x, fp) __sputc(x, fp) #define getchar_unlocked() getc_unlocked(stdin) #define putchar_unlocked(x) putc_unlocked(x, stdout) +#endif +__END_DECLS #endif /* !_STDIO_H_ */ diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 18a8e49d8b..7b95fa47cd 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -64,14 +64,6 @@ extern int __isthreaded; #define FLOCKFILE(fp) if (__isthreaded) _FLOCKFILE(fp) #define FUNLOCKFILE(fp) if (__isthreaded) _funlockfile(fp) -/* - * Internal _*() functions (XXX add all of them) - */ - -#ifdef _STDIO_H_ -int _fseeko(FILE *, __off_t, int); -#endif - /* * Initialise TLS static programs */ diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc index f08f176907..376574a3d8 100644 --- a/lib/libc/stdio/Makefile.inc +++ b/lib/libc/stdio/Makefile.inc @@ -6,30 +6,40 @@ .PATH: ${.CURDIR}/../libc/stdio SRCS+= __fpending.c _flock_stub.c \ - asprintf.c clrerr.c fclose.c fcookie.c fdopen.c feof.c ferror.c \ + asprintf.c clrerr.c dprintf.c \ + fclose.c fcloseall.c fcookie.c fdopen.c feof.c ferror.c \ fflush.c fgetc.c fgetln.c fgetpos.c fgets.c fgetwc.c fgetwln.c \ fgetws.c fileno.c findfp.c flags.c fopen.c fprintf.c fpurge.c \ fputc.c fputs.c fputwc.c fputws.c fread.c freopen.c fscanf.c \ fseek.c fsetpos.c ftell.c funopen.c fvwrite.c fwalk.c fwide.c \ - fwprintf.c fwrite.c fwscanf.c getc.c getchar.c gets.c getw.c \ - getwc.c getwchar.c makebuf.c mktemp.c perror.c printf.c putc.c \ + fwprintf.c fwrite.c fwscanf.c getc.c getchar.c \ + getdelim.c getline.c gets.c getw.c \ + getwc.c getwchar.c makebuf.c mktemp.c perror.c \ + printf-pos.c printf.c putc.c \ putchar.c puts.c putw.c putwc.c putwchar.c refill.c remove.c rewind.c \ rget.c scanf.c setbuf.c setbuffer.c setvbuf.c snprintf.c sprintf.c \ sreadahead.c \ sscanf.c stdio.c swprintf.c swscanf.c tempnam.c tmpfile.c tmpnam.c \ - ungetc.c ungetwc.c vasprintf.c vfprintf.c vfscanf.c vfwprintf.c \ + ungetc.c ungetwc.c vasprintf.c vdprintf.c \ + vfprintf.c vfscanf.c vfwprintf.c \ vfwscanf.c vprintf.c vscanf.c vsnprintf.c vsprintf.c vsscanf.c \ vswprintf.c vswscanf.c vwprintf.c vwscanf.c wbuf.c wprintf.c \ - wscanf.c wsetup.c + wscanf.c wsetup.c xprintf.c xprintf_errno.c xprintf_float.c \ + xprintf_hexdump.c xprintf_int.c xprintf_quote.c xprintf_str.c \ + xprintf_time.c xprintf_vis.c .if ${LIB} == "c" MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \ flockfile.3 fopen.3 fputs.3 fputws.3 fread.3 fseek.3 funopen.3 \ - fwide.3 getc.3 getwc.3 mktemp.3 printf.3 putc.3 putwc.3 remove.3 \ + fwide.3 getc.3 getline.3 \ + getwc.3 mktemp.3 printf.3 putc.3 putwc.3 remove.3 \ scanf.3 setbuf.3 stdio.3 tmpnam.3 ungetc.3 ungetwc.3 wprintf.3 wscanf.3 -MLINKS+=ferror.3 clearerr.3 ferror.3 feof.3 ferror.3 fileno.3 +MLINKS+=fclose.3 fcloseall.3 +MLINKS+=ferror.3 clearerr.3 ferror.3 clearerr_unlocked.3 \ + ferror.3 feof.3 ferror.3 feof_unlocked.3 ferror.3 ferror_unlocked.3 \ + ferror.3 fileno.3 ferror.3 fileno_unlocked.3 MLINKS+=fflush.3 fpurge.3 MLINKS+=fgets.3 gets.3 MLINKS+=flockfile.3 funlockfile.3 \ @@ -42,11 +52,12 @@ MLINKS+=fseek.3 fgetpos.3 fseek.3 fseeko.3 fseek.3 fsetpos.3 fseek.3 ftell.3 \ MLINKS+=funopen.3 fropen.3 funopen.3 fwopen.3 MLINKS+=getc.3 fgetc.3 getc.3 getc_unlocked.3 getc.3 getchar_unlocked.3 \ getc.3 getchar.3 getc.3 getw.3 +MLINKS+=getline.3 getdelim.3 MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3 MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3 -MLINKS+=printf.3 asprintf.3 printf.3 fprintf.3 \ +MLINKS+=printf.3 asprintf.3 printf.3 dprintf.3 printf.3 fprintf.3 \ printf.3 snprintf.3 printf.3 sprintf.3 \ - printf.3 vasprintf.3 \ + printf.3 vasprintf.3 printf.3 vdprintf.3 \ printf.3 vfprintf.3 printf.3 vprintf.3 printf.3 vsnprintf.3 \ printf.3 vsprintf.3 MLINKS+=putc.3 fputc.3 putc.3 putc_unlocked.3 putc.3 putchar_unlocked.3 \ diff --git a/lib/libc/stdio/_flock_stub.c b/lib/libc/stdio/_flock_stub.c index c055a25048..97ecc8b730 100644 --- a/lib/libc/stdio/_flock_stub.c +++ b/lib/libc/stdio/_flock_stub.c @@ -10,10 +10,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by John Birrell. - * 4. Neither the name of the author nor the names of any co-contributors + * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -29,8 +26,14 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/_flock_stub.c,v 1.3 1999/08/28 00:00:55 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/_flock_stub.c,v 1.16 2008/04/17 22:17:53 jhb Exp $ * $DragonFly: src/lib/libc/stdio/_flock_stub.c,v 1.10 2005/07/23 23:14:44 joerg Exp $ + */ + +/* + * POSIX stdio FILE locking functions. These assume that the locking + * is only required at FILE structure level, not at file descriptor + * level too. * */ @@ -42,61 +45,57 @@ #include "local.h" #include "priv_stdio.h" -void __flockfile(FILE *fp); -void __flockfile_debug(FILE *fp, char *fname, int lineno); -int __ftrylockfile(FILE *fp); -void __funlockfile(FILE *fp); /* - * Externally visible weak symbols. + * Weak symbols for externally visible functions in this file: */ -__weak_reference(__flockfile, flockfile); -__weak_reference(__flockfile, _flockfile); -__weak_reference(__flockfile_debug, _flockfile_debug); -__weak_reference(__ftrylockfile, ftrylockfile); -__weak_reference(__ftrylockfile, _ftrylockfile); -__weak_reference(__funlockfile, funlockfile); -__weak_reference(__funlockfile, _funlockfile); +__weak_reference(_flockfile, flockfile); +__weak_reference(_flockfile_debug_stub, _flockfile_debug); +__weak_reference(_ftrylockfile, ftrylockfile); +__weak_reference(_funlockfile, funlockfile); void -__flockfile(FILE *fp) +_flockfile(FILE *fp) { pthread_t curthread = _pthread_self(); - if (fp->fl_owner == curthread) - fp->fl_count++; + if (fp->_fl_owner == curthread) + fp->_fl_count++; else { /* * Make sure this mutex is treated as a private * internal mutex: */ - _pthread_mutex_lock(&fp->fl_mutex); - fp->fl_owner = curthread; - fp->fl_count = 1; + _pthread_mutex_lock(&fp->_fl_mutex); + fp->_fl_owner = curthread; + fp->_fl_count = 1; } } +/* + * This can be overriden by the threads library if it is linked in. + */ void -__flockfile_debug(FILE *fp, char *fname __unused, int lineno __unused) +_flockfile_debug_stub(FILE *fp, char *fname __unused, int lineno __unused) { _flockfile(fp); } int -__ftrylockfile(FILE *fp) +_ftrylockfile(FILE *fp) { pthread_t curthread = _pthread_self(); int ret = 0; - if (fp->fl_owner == curthread) - fp->fl_count++; + if (fp->_fl_owner == curthread) + fp->_fl_count++; /* * Make sure this mutex is treated as a private * internal mutex: */ - else if (_pthread_mutex_trylock(&fp->fl_mutex) == 0) { - fp->fl_owner = curthread; - fp->fl_count = 1; + else if (_pthread_mutex_trylock(&fp->_fl_mutex) == 0) { + fp->_fl_owner = curthread; + fp->_fl_count = 1; } else ret = -1; @@ -104,33 +103,33 @@ __ftrylockfile(FILE *fp) } void -__funlockfile(FILE *fp) +_funlockfile(FILE *fp) { pthread_t curthread = _pthread_self(); /* * Check if this file is owned by the current thread: */ - if (fp->fl_owner == curthread) { + if (fp->_fl_owner == curthread) { /* * Check if this thread has locked the FILE * more than once: */ - if (fp->fl_count > 1) + if (fp->_fl_count > 1) { /* * Decrement the count of the number of * times the running thread has locked this * file: */ - fp->fl_count--; - else { + fp->_fl_count--; + } else { /* * The running thread will release the * lock now: */ - fp->fl_count = 0; - fp->fl_owner = NULL; - _pthread_mutex_unlock(&fp->fl_mutex); + fp->_fl_count = 0; + fp->_fl_owner = NULL; + _pthread_mutex_unlock(&fp->_fl_mutex); } } } diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c index b5006aa783..3ece30f99f 100644 --- a/lib/libc/stdio/asprintf.c +++ b/lib/libc/stdio/asprintf.c @@ -1,8 +1,9 @@ -/* $OpenBSD: asprintf.c,v 1.4 1998/06/21 22:13:46 millert Exp $ */ - -/* - * Copyright (c) 1997 Todd C. Miller - * All rights reserved. +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -12,63 +13,37 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/asprintf.c,v 1.6 1999/08/28 00:00:55 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/asprintf.c,v 1.15 2009/03/02 04:11:42 das Exp $ * $DragonFly: src/lib/libc/stdio/asprintf.c,v 1.8 2006/03/02 18:05:30 joerg Exp $ */ -#include -#include -#include #include - -#include "local.h" -#include "priv_stdio.h" +#include int -asprintf(char **str, char const *fmt, ...) +asprintf(char ** __restrict s, const char * __restrict fmt, ...) { int ret; va_list ap; - FILE f; - f.pub._fileno = -1; - f.pub._flags = __SWR | __SSTR | __SALC; - f._bf._base = f.pub._p = (unsigned char *)malloc(128); - if (f._bf._base == NULL) { - *str = NULL; - errno = ENOMEM; - return (-1); - } - f._bf._size = f.pub._w = 127; /* Leave room for the NUL */ - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; - memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); va_start(ap, fmt); - ret = __vfprintf(&f, fmt, ap); /* Use unlocked __vfprintf */ + ret = vasprintf(s, fmt, ap); va_end(ap); - if (ret < 0) { - free(f._bf._base); - *str = NULL; - errno = ENOMEM; - return (-1); - } - *f.pub._p = '\0'; - *str = (char *)f._bf._base; return (ret); } diff --git a/lib/libc/stdio/clrerr.c b/lib/libc/stdio/clrerr.c index 9d6b509e52..53fc843606 100644 --- a/lib/libc/stdio/clrerr.c +++ b/lib/libc/stdio/clrerr.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)clrerr.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/clrerr.c,v 1.7 1999/08/28 00:00:55 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/clrerr.c,v 1.12 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/clrerr.c,v 1.4 2005/01/31 22:29:40 dillon Exp $ */ @@ -42,7 +38,9 @@ #include #include "un-namespace.h" #include "libc_private.h" -#undef clearerr + +#undef clearerr +#undef clearerr_unlocked void clearerr(FILE *fp) @@ -51,3 +49,9 @@ clearerr(FILE *fp) __sclearerr(fp); FUNLOCKFILE(fp); } + +void +clearerr_unlocked(FILE *fp) +{ + __sclearerr(fp); +} diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/dprintf.c similarity index 83% copy from lib/libc/stdio/wprintf.c copy to lib/libc/stdio/dprintf.c index 7441ab2045..9e777fa602 100644 --- a/lib/libc/stdio/wprintf.c +++ b/lib/libc/stdio/dprintf.c @@ -1,8 +1,5 @@ -/* $NetBSD: wprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/wprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c) 2002 Tim J. Robbins + * Copyright (c) 2009 David Schultz * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,21 +22,24 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/dprintf.c,v 1.1 2009/03/04 03:38:51 das Exp $ */ +#define _WITH_DPRINTF +#include "namespace.h" #include #include -#include +#include "un-namespace.h" int -wprintf(const wchar_t * __restrict fmt, ...) +dprintf(int fd, const char * __restrict fmt, ...) { - int ret; va_list ap; + int ret; va_start(ap, fmt); - ret = vfwprintf(stdout, fmt, ap); + ret = vdprintf(fd, fmt, ap); va_end(ap); - return (ret); } diff --git a/lib/libc/stdio/fclose.3 b/lib/libc/stdio/fclose.3 index bb26a8dc76..467daa53fe 100644 --- a/lib/libc/stdio/fclose.3 +++ b/lib/libc/stdio/fclose.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,14 +30,15 @@ .\" SUCH DAMAGE. .\" .\" @(#)fclose.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/fclose.3,v 1.7.2.4 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fclose.3,v 1.15 2007/01/09 00:28:06 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/fclose.3,v 1.4 2004/06/07 16:37:56 hmp Exp $ .\" -.Dd June 4, 1993 +.Dd April 22, 2006 .Dt FCLOSE 3 .Os .Sh NAME -.Nm fclose +.Nm fclose , +.Nm fcloseall .Nd close a stream .Sh LIBRARY .Lb libc @@ -49,6 +46,8 @@ .In stdio.h .Ft int .Fn fclose "FILE *stream" +.Ft void +.Fn fcloseall void .Sh DESCRIPTION The .Fn fclose @@ -59,6 +58,12 @@ from its underlying file or set of functions. If the stream was being used for output, any buffered data is written first, using .Xr fflush 3 . +.Pp +The +.Fn fcloseall +function calls +.Fn fclose +on all open streams. .Sh RETURN VALUES Upon successful completion 0 is returned. Otherwise, @@ -100,3 +105,8 @@ The function conforms to .St -isoC . +.Pp +The +.Fn fcloseall +function first appeared in +.Dx 2.3 . diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c index 1e1a56e9b1..d145475f76 100644 --- a/lib/libc/stdio/fclose.c +++ b/lib/libc/stdio/fclose.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fclose.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fclose.c,v 1.8 1999/11/21 22:34:57 dt Exp $ + * $FreeBSD: src/lib/libc/stdio/fclose.c,v 1.12 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fclose.c,v 1.9 2005/07/23 20:23:05 joerg Exp $ */ @@ -67,23 +63,9 @@ fclose(FILE *fp) FREEUB(fp); if (HASLB(fp)) FREELB(fp); - /* - * XXX-HITEN the FUNLOCKFILE(fp) cannot be moved below because of - * the way the funlockfile() implementation works; it surrounds - * the code with a if (fp->_file >= 0)... terrible, just terrible. - * - * This mess will be cleaned up when I rewrite the file contention - * locking code. - */ - FUNLOCKFILE(fp); fp->pub._fileno = -1; fp->pub._r = fp->pub._w = 0; /* Mess up if reaccessed. */ -#if 0 - if (fp->_lock != NULL) { - _pthread_mutex_destroy((pthread_mutex_t *)&fp->_lock); - fp->_lock = NULL; - } -#endif fp->pub._flags = 0; /* Release this FILE for reuse. */ + FUNLOCKFILE(fp); return (r); } diff --git a/lib/libc/stdio/getwc.c b/lib/libc/stdio/fcloseall.c similarity index 70% copy from lib/libc/stdio/getwc.c copy to lib/libc/stdio/fcloseall.c index 5ef66b5c74..c8f7fe128f 100644 --- a/lib/libc/stdio/getwc.c +++ b/lib/libc/stdio/fcloseall.c @@ -1,9 +1,5 @@ -/* $NetBSD: getwc.c,v 1.3 2005/06/12 05:21:27 lukem Exp $ */ -/* $DragonFly: src/lib/libc/stdio/getwc.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c)2001 Citrus Project, - * All rights reserved. + * Copyright (C) 2006 Daniel M. Eischen. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -14,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) @@ -26,20 +22,16 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Citrus$ + * $FreeBSD: src/lib/libc/stdio/fcloseall.c,v 1.2 2006/04/22 16:47:59 deischen Exp $ */ #include -#include +#include "local.h" -/* - * A subroutine version of the macro getwc. - */ -#undef getwc +__weak_reference(__fcloseall, fcloseall); -wint_t -getwc(FILE *fp) +void +__fcloseall(void) { - - return fgetwc(fp); + _fwalk(fclose); } diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c index 87d1284cc2..eae564d1e4 100644 --- a/lib/libc/stdio/fdopen.c +++ b/lib/libc/stdio/fdopen.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,10 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/fdopen.c,v 1.3 2000/01/27 23:06:44 jasone Exp $ - * $DragonFly: src/lib/libc/stdio/fdopen.c,v 1.6 2005/07/23 20:23:05 joerg Exp $ - * * @(#)fdopen.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/fdopen.c,v 1.11 2008/05/10 18:39:20 antoine Exp $ + * $DragonFly: src/lib/libc/stdio/fdopen.c,v 1.6 2005/07/23 20:23:05 joerg Exp $ */ #include "namespace.h" @@ -54,12 +49,8 @@ FILE * fdopen(int fd, const char *mode) { FILE *fp; - static int nofile; int flags, oflags, fdflags, tmp; - if (nofile == 0) - nofile = getdtablesize(); - if ((flags = __sflags(mode, &oflags)) == 0) return (NULL); @@ -77,8 +68,8 @@ fdopen(int fd, const char *mode) fp->pub._flags = flags; /* * If opened for appending, but underlying descriptor does not have - * O_APPEND bit set, assert __SAPP so that __swrite() will lseek to - * end before each write. + * O_APPEND bit set, assert __SAPP so that __swrite() caller + * will _sseek() to the end before write. */ if ((oflags & O_APPEND) && !(fdflags & O_APPEND)) fp->pub._flags |= __SAPP; diff --git a/lib/libc/stdio/feof.c b/lib/libc/stdio/feof.c index 7ad9c2cb01..6a67ff7b9a 100644 --- a/lib/libc/stdio/feof.c +++ b/lib/libc/stdio/feof.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,26 +30,31 @@ * SUCH DAMAGE. * * @(#)feof.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/feof.c,v 1.6 1999/08/28 00:00:57 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/feof.c,v 1.12 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/feof.c,v 1.6 2005/08/27 21:35:01 joerg Exp $ */ +#include "namespace.h" #include +#include "un-namespace.h" #include "libc_private.h" -/* - * A subroutine version of the macros feof and feof_unlocked. - */ +#undef feof #undef feof_unlocked int feof(FILE *fp) { - return(__sfeof(fp)); + int ret; + + FLOCKFILE(fp); + ret= __sfeof(fp); + FUNLOCKFILE(fp); + return (ret); } int feof_unlocked(FILE *fp) { - return(__sfeof(fp)); + return (__sfeof(fp)); } diff --git a/lib/libc/stdio/ferror.3 b/lib/libc/stdio/ferror.3 index 9f76a048c6..39f5a72feb 100644 --- a/lib/libc/stdio/ferror.3 +++ b/lib/libc/stdio/ferror.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,17 +30,21 @@ .\" SUCH DAMAGE. .\" .\" @(#)ferror.3 8.2 (Berkeley) 4/19/94 -.\" $FreeBSD: src/lib/libc/stdio/ferror.3,v 1.3.2.4 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/ferror.3,v 1.13 2009/01/28 14:38:41 trhodes Exp $ .\" $DragonFly: src/lib/libc/stdio/ferror.3,v 1.2 2003/06/17 04:26:45 dillon Exp $ .\" -.Dd April 19, 1994 +.Dd January 28, 2009 .Dt FERROR 3 .Os .Sh NAME .Nm clearerr , +.Nm clearerr_unlocked , .Nm feof , +.Nm feof_unlocked , .Nm ferror , -.Nm fileno +.Nm ferror_unlocked , +.Nm fileno , +.Nm fileno_unlocked .Nd check and reset stream status .Sh LIBRARY .Lb libc @@ -52,12 +52,20 @@ .In stdio.h .Ft void .Fn clearerr "FILE *stream" +.Ft void +.Fn clearerr_unlocked "FILE *stream" .Ft int .Fn feof "FILE *stream" .Ft int +.Fn feof_unlocked "FILE *stream" +.Ft int .Fn ferror "FILE *stream" .Ft int +.Fn ferror_unlocked "FILE *stream" +.Ft int .Fn fileno "FILE *stream" +.Ft int +.Fn fileno_unlocked "FILE *stream" .Sh DESCRIPTION The function .Fn clearerr @@ -70,23 +78,41 @@ The function tests the end-of-file indicator for the stream pointed to by .Fa stream , returning non-zero if it is set. -The end-of-file indicator can only be cleared by the function -.Fn clearerr . +The end-of-file indicator may be cleared by explicitly calling +.Fn clearerr , +or as a side-effect of other operations, e.g.\& +.Fn fseek . .Pp The function .Fn ferror tests the error indicator for the stream pointed to by .Fa stream , returning non-zero if it is set. -The error indicator can only be reset by the -.Fn clearerr -function. .Pp The function .Fn fileno examines the argument .Fa stream and returns its integer descriptor. +.Pp +The +.Fn clearerr_unlocked , +.Fn feof_unlocked , +.Fn ferror_unlocked , +and +.Fn fileno_unlocked +functions are equivalent to +.Fn clearerr , +.Fn feof , +.Fn ferror , +and +.Fn fileno +respectively, except that the caller is responsible for locking the stream +with +.Xr flockfile 3 +before calling them. +These functions may be used to avoid the overhead of locking the stream +and to prevent races when multiple threads are operating on the same stream. .Sh ERRORS These functions should not fail and do not set the external variable @@ -94,6 +120,7 @@ variable .Sh SEE ALSO .Xr open 2 , .Xr fdopen 3 , +.Xr flockfile 3 , .Xr stdio 3 .Sh STANDARDS The functions diff --git a/lib/libc/stdio/ferror.c b/lib/libc/stdio/ferror.c index 981b23ddad..dbb5243e6f 100644 --- a/lib/libc/stdio/ferror.c +++ b/lib/libc/stdio/ferror.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,21 +30,27 @@ * SUCH DAMAGE. * * @(#)ferror.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/ferror.c,v 1.6 1999/08/28 00:00:57 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/ferror.c,v 1.12 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/ferror.c,v 1.4 2005/08/27 21:35:01 joerg Exp $ */ +#include "namespace.h" #include +#include "un-namespace.h" +#include "libc_private.h" -/* - * A subroutine version of the macros ferror and ferror_unlocked. - */ +#undef ferror #undef ferror_unlocked int ferror(FILE *fp) { - return (__sferror(fp)); + int ret; + + FLOCKFILE(fp); + ret = __sferror(fp); + FUNLOCKFILE(fp); + return (ret); } int diff --git a/lib/libc/stdio/fflush.3 b/lib/libc/stdio/fflush.3 index 20a991897c..e1b1cfcd45 100644 --- a/lib/libc/stdio/fflush.3 +++ b/lib/libc/stdio/fflush.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)fflush.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/fflush.3,v 1.4.2.4 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fflush.3,v 1.11 2007/01/09 00:28:06 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/fflush.3,v 1.3 2004/06/08 00:29:47 hmp Exp $ .\" .Dd June 4, 1993 diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c index 03024c2def..73f7363a45 100644 --- a/lib/libc/stdio/fflush.c +++ b/lib/libc/stdio/fflush.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fflush.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fflush.c,v 1.7 1999/08/28 00:00:58 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fflush.c,v 1.14 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fflush.c,v 1.6 2005/07/23 20:23:05 joerg Exp $ */ @@ -47,6 +43,8 @@ #include "local.h" #include "priv_stdio.h" +static int sflush_locked(FILE *); + /* * Flush a single file, or (if fp is NULL) all files. * MT-safe version @@ -57,14 +55,26 @@ fflush(FILE *fp) int retval; if (fp == NULL) - return (_fwalk(__sflush)); + return (_fwalk(sflush_locked)); FLOCKFILE(fp); + + /* + * There is disagreement about the correct behaviour of fflush() + * when passed a file which is not open for reading. According to + * the ISO C standard, the behaviour is undefined. + * Under linux, such an fflush returns success and has no effect; + * under Windows, such an fflush is documented as behaving instead + * as fpurge(). + * Given that applications may be written with the expectation of + * either of these two behaviours, the only safe (non-astonishing) + * option is to return EBADF and ask that applications be fixed. + */ if ((fp->pub._flags & (__SWR | __SRW)) == 0) { errno = EBADF; retval = EOF; - } else + } else { retval = __sflush(fp); - + } FUNLOCKFILE(fp); return (retval); } @@ -79,12 +89,13 @@ __fflush(FILE *fp) int retval; if (fp == NULL) - return (_fwalk(__sflush)); + return (_fwalk(sflush_locked)); if ((fp->pub._flags & (__SWR | __SRW)) == 0) { errno = EBADF; retval = EOF; - } else + } else { retval = __sflush(fp); + } return (retval); } @@ -101,7 +112,7 @@ __sflush(FILE *fp) if ((p = fp->_bf._base) == NULL) return (0); - n = fp->pub._p - p; /* write this much */ + n = fp->pub._p - p; /* write this much */ /* * Set these immediately to avoid problems with longjmp and to allow @@ -111,7 +122,7 @@ __sflush(FILE *fp) fp->pub._w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size; for (; n > 0; n -= t, p += t) { - t = (*fp->_write)(fp->_cookie, (char *)p, n); + t = _swrite(fp, (char *)p, n); if (t <= 0) { fp->pub._flags |= __SERR; return (EOF); @@ -119,3 +130,14 @@ __sflush(FILE *fp) } return (0); } + +static int +sflush_locked(FILE *fp) +{ + int ret; + + FLOCKFILE(fp); + ret = __sflush(fp); + FUNLOCKFILE(fp); + return (ret); +} diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c index bb4b1f1cd0..807850fa35 100644 --- a/lib/libc/stdio/fgetc.c +++ b/lib/libc/stdio/fgetc.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fgetc.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fgetc.c,v 1.7 1999/08/28 00:00:58 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fgetc.c,v 1.13 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fgetc.c,v 1.5 2005/07/23 20:23:05 joerg Exp $ */ diff --git a/lib/libc/stdio/fgetln.3 b/lib/libc/stdio/fgetln.3 index 4175512209..881e6011dd 100644 --- a/lib/libc/stdio/fgetln.3 +++ b/lib/libc/stdio/fgetln.3 @@ -9,10 +9,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -30,7 +26,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94 -.\" $FreeBSD: src/lib/libc/stdio/fgetln.3,v 1.4.2.3 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fgetln.3,v 1.10 2009/02/28 06:00:58 das Exp $ .\" $DragonFly: src/lib/libc/stdio/fgetln.3,v 1.2 2003/06/17 04:26:45 dillon Exp $ .\" .Dd April 19, 1994 @@ -119,7 +115,9 @@ or .Sh SEE ALSO .Xr ferror 3 , .Xr fgets 3 , +.Xr fgetwln 3 , .Xr fopen 3 , +.Xr getline 3 , .Xr putc 3 .Sh HISTORY The diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c index 6ad3c3c573..92000f2023 100644 --- a/lib/libc/stdio/fgetln.c +++ b/lib/libc/stdio/fgetln.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,13 +30,17 @@ * SUCH DAMAGE. * * @(#)fgetln.c 8.2 (Berkeley) 1/2/94 - * $FreeBSD: src/lib/libc/stdio/fgetln.c,v 1.6 1999/08/28 00:00:59 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fgetln.c,v 1.11 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fgetln.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ +#include "namespace.h" #include #include #include +#include "un-namespace.h" + +#include "libc_private.h" #include "local.h" #include "priv_stdio.h" @@ -82,9 +82,12 @@ fgetln(FILE *fp, size_t *lenp) size_t len; size_t off; + FLOCKFILE(fp); + ORIENT(fp, -1); /* make sure there is input */ if (fp->pub._r <= 0 && __srefill(fp)) { *lenp = 0; + FUNLOCKFILE(fp); return (NULL); } @@ -103,6 +106,7 @@ fgetln(FILE *fp, size_t *lenp) fp->pub._flags |= __SMOD; fp->pub._r -= len; fp->pub._p = p; + FUNLOCKFILE(fp); return (ret); } @@ -141,8 +145,7 @@ fgetln(FILE *fp, size_t *lenp) len += diff; if (__slbexpand(fp, len)) goto error; - memcpy((void *)(fp->_lb._base + off), (void *)fp->pub._p, - diff); + memcpy((void *)(fp->_lb._base + off), (void *)fp->pub._p, diff); fp->pub._r -= diff; fp->pub._p = p; break; @@ -151,9 +154,11 @@ fgetln(FILE *fp, size_t *lenp) #ifdef notdef fp->_lb._base[len] = 0; #endif + FUNLOCKFILE(fp); return ((char *)fp->_lb._base); error: *lenp = 0; /* ??? */ + FUNLOCKFILE(fp); return (NULL); /* ??? */ } diff --git a/lib/libc/stdio/fgetpos.c b/lib/libc/stdio/fgetpos.c index 59f1596880..af5088375f 100644 --- a/lib/libc/stdio/fgetpos.c +++ b/lib/libc/stdio/fgetpos.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,21 +30,20 @@ * SUCH DAMAGE. * * @(#)fgetpos.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fgetpos.c,v 1.8 1999/08/28 00:00:59 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fgetpos.c,v 1.13 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fgetpos.c,v 1.5 2005/01/31 22:29:40 dillon Exp $ */ -#include "namespace.h" #include -#include "un-namespace.h" -#include "libc_private.h" int -fgetpos(FILE *fp, fpos_t *pos) +fgetpos(FILE * __restrict fp, fpos_t * __restrict pos) { - int retval; - FLOCKFILE(fp); - retval = (*pos = ftello(fp)) == (fpos_t)-1 ? -1 : 0; - FUNLOCKFILE(fp); - return(retval); + /* + * ftello is thread-safe; no need to lock fp. + */ + if ((*pos = ftello(fp)) == (fpos_t)-1) + return (-1); + else + return (0); } diff --git a/lib/libc/stdio/fgets.3 b/lib/libc/stdio/fgets.3 index fc95b846d8..12b4a5bc16 100644 --- a/lib/libc/stdio/fgets.3 +++ b/lib/libc/stdio/fgets.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)fgets.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/fgets.3,v 1.6.2.7 2002/07/02 19:51:21 archie Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fgets.3,v 1.22 2009/02/28 06:00:58 das Exp $ .\" $DragonFly: src/lib/libc/stdio/fgets.3,v 1.3 2004/06/08 00:29:03 hmp Exp $ .\" .Dd June 4, 1993 @@ -49,7 +45,7 @@ .Sh SYNOPSIS .In stdio.h .Ft char * -.Fn fgets "char *str" "int size" "FILE *stream" +.Fn fgets "char * restrict str" "int size" "FILE * restrict stream" .Ft char * .Fn gets "char *str" .Sh DESCRIPTION @@ -143,14 +139,19 @@ to reliably determine the length of the next incoming line, the use of this function enables malicious users to arbitrarily change a running program's functionality through a buffer overflow attack. +It is strongly suggested that the +.Fn fgets +function be used in all cases. .Sh SEE ALSO .Xr feof 3 , .Xr ferror 3 , -.Xr fgetln 3 +.Xr fgetln 3 , +.Xr fgetws 3 , +.Xr getline 3 .Sh STANDARDS The functions .Fn fgets and .Fn gets conform to -.St -isoC . +.St -isoC-99 . diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c index 49a56d6050..0958c5b79e 100644 --- a/lib/libc/stdio/fgets.c +++ b/lib/libc/stdio/fgets.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fgets.c 8.2 (Berkeley) 12/22/93 - * $FreeBSD: src/lib/libc/stdio/fgets.c,v 1.9 1999/08/28 00:01:00 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fgets.c,v 1.14 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fgets.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ @@ -43,7 +39,6 @@ #include #include "un-namespace.h" #include "local.h" - #include "libc_private.h" #include "priv_stdio.h" @@ -63,6 +58,7 @@ fgets(char *buf, int n, FILE *fp) return (NULL); FLOCKFILE(fp); + ORIENT(fp, -1); s = buf; n--; /* leave space for NUL */ while (n != 0) { diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c index 8b5084b573..54991f3cb4 100644 --- a/lib/libc/stdio/fgetwc.c +++ b/lib/libc/stdio/fgetwc.c @@ -1,4 +1,4 @@ -/* $NetBSD: fgetwc.c,v 1.4 2005/06/12 05:21:27 lukem Exp $ */ +/* $NetBSD: fgetwc.c,v 1.8 2007/04/01 18:35:53 tnozaki Exp $ */ /* $DragonFly: src/lib/libc/stdio/fgetwc.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ /*- @@ -44,45 +44,43 @@ wint_t __fgetwc_unlock(FILE *fp) { struct wchar_io_data *wcio; - mbstate_t *st; wchar_t wc; - size_t size; + size_t nr; _DIAGASSERT(fp != NULL); _SET_ORIENTATION(fp, 1); wcio = WCIO_GET(fp); - if (wcio == 0) { - errno = ENOMEM; - return WEOF; - } + _DIAGASSERT(wcio != NULL); /* if there're ungetwc'ed wchars, use them */ - if (wcio->wcio_ungetwc_inbuf) { - wc = wcio->wcio_ungetwc_buf[--wcio->wcio_ungetwc_inbuf]; - - return wc; - } - - st = &wcio->wcio_mbstate_in; - - do { - char c; - int ch = __sgetc(fp); - - if (ch == EOF) { - return WEOF; - } + if (wcio->wcio_ungetwc_inbuf) + return(wcio->wcio_ungetwc_buf[--wcio->wcio_ungetwc_inbuf]); - c = ch; - size = mbrtowc(&wc, &c, 1, st); - if (size == (size_t)-1) { - errno = EILSEQ; + if (fp->pub._r <= 0) { +restart: + if (__srefill(fp) != 0) return WEOF; + } + nr = mbrtowc(&wc, (const char *)fp->pub._p, + (size_t)fp->pub._r, &wcio->wcio_mbstate_in); + if (nr == (size_t)-1) { + fp->pub._flags |= __SERR; + return WEOF; + } else if (nr == (size_t)-2) { + fp->pub._p += fp->pub._r; + fp->pub._r = 0; + goto restart; + } + if (wc == L'\0') { + while (*fp->pub._p != '\0') { + ++fp->pub._p; + --fp->pub._r; } - } while (size == (size_t)-2); - - _DIAGASSERT(size == 1); + nr = 1; + } + fp->pub._p += nr; + fp->pub._r -= nr; return wc; } diff --git a/lib/libc/stdio/fgetwln.3 b/lib/libc/stdio/fgetwln.3 index 4e547df6f3..514814efdf 100644 --- a/lib/libc/stdio/fgetwln.3 +++ b/lib/libc/stdio/fgetwln.3 @@ -1,5 +1,3 @@ -.\" $NetBSD: fgetwln.3,v 1.1 2005/05/14 23:51:02 christos Exp $ -.\" $DragonFly: src/lib/libc/stdio/fgetwln.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -11,10 +9,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -32,7 +26,8 @@ .\" SUCH DAMAGE. .\" .\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94 -.\" $FreeBSD: src/lib/libc/stdio/fgetwln.3,v 1.1 2004/07/16 06:06:09 tjr Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fgetwln.3,v 1.3 2007/01/09 00:28:06 imp Exp $ +.\" $DragonFly: src/lib/libc/stdio/fgetwln.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ .\" .Dd July 16, 2004 .Dt FGETWLN 3 diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c index 9f64d3285d..9c7113480d 100644 --- a/lib/libc/stdio/fgetwln.c +++ b/lib/libc/stdio/fgetwln.c @@ -1,4 +1,4 @@ -/* $NetBSD: fgetwln.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ +/* $NetBSD: fgetwln.c,v 1.2 2009/01/31 06:08:28 lukem Exp $ */ /* $DragonFly: src/lib/libc/stdio/fgetwln.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ /*- @@ -48,7 +48,7 @@ fgetwln(FILE * __restrict fp, size_t *lenp) len = 0; while ((wc = __fgetwc_unlock(fp)) != WEOF) { #define GROW 512 - if (len * sizeof(wchar_t) >= fp->_lb._size && + if (len * sizeof(wchar_t) >= (size_t)fp->_lb._size && __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) goto error; *((wchar_t *)(void *)fp->_lb._base + len++) = wc; diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c index 95a8560578..31170da816 100644 --- a/lib/libc/stdio/fgetws.c +++ b/lib/libc/stdio/fgetws.c @@ -1,4 +1,4 @@ -/* $NetBSD: fgetws.c,v 1.1 2003/03/07 07:11:37 tshiozak Exp $ */ +/* $NetBSD: fgetws.c,v 1.2 2006/07/03 17:06:36 tnozaki Exp $ */ /* $DragonFly: src/lib/libc/stdio/fgetws.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ /*- @@ -61,10 +61,10 @@ fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) wsp = ws; while (n-- > 1) { - if ((wc = __fgetwc_unlock(fp)) == WEOF && errno == EILSEQ) { + wc = __fgetwc_unlock(fp); + if (__sferror(fp) != 0) goto error; - } - if (wc == WEOF) { + if (__sfeof(fp) != 0) { if (wsp == ws) { /* EOF/error, no characters read yet. */ goto error; diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c index f755bff5e1..ea1e4bccee 100644 --- a/lib/libc/stdio/fileno.c +++ b/lib/libc/stdio/fileno.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,21 +30,18 @@ * SUCH DAMAGE. * * @(#)fileno.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fileno.c,v 1.6 1999/08/28 00:01:01 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fileno.c,v 1.13 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/fileno.c,v 1.6 2005/08/27 21:35:01 joerg Exp $ */ #include "namespace.h" #include #include "un-namespace.h" - #include "libc_private.h" +#undef fileno #undef fileno_unlocked -/* - * A subroutine version of the macros fileno and fileno_unlocked. - */ int fileno(FILE *fp) { @@ -64,5 +57,5 @@ fileno(FILE *fp) int fileno_unlocked(FILE *fp) { - return(__sfileno(fp)); + return (__sfileno(fp)); } diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c index d37fd6c612..eddf08fcac 100644 --- a/lib/libc/stdio/findfp.c +++ b/lib/libc/stdio/findfp.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)findfp.c 8.2 (Berkeley) 1/4/94 - * $FreeBSD: src/lib/libc/stdio/findfp.c,v 1.7.2.3 2001/08/17 02:56:31 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/findfp.c,v 1.33 2009/03/01 19:25:40 das Exp $ * $DragonFly: src/lib/libc/stdio/findfp.c,v 1.11 2006/03/02 18:05:30 joerg Exp $ */ @@ -47,7 +43,7 @@ #include -#include +#include "libc_private.h" #include "local.h" #include "priv_stdio.h" @@ -55,53 +51,45 @@ int __sdidinit; #define NDYNAMIC 10 /* add ten more whenever necessary */ -#define std(flags, file) \ - {{0,flags,file,0,0,0},{NULL, 0},__sF+file,__sclose,__sread,__sseek,__swrite, \ - {NULL,0}, 0, {0,0,0}, {0}, {NULL,0}, 0,0, NULL, PTHREAD_MUTEX_INITIALIZER, NULL, 0 } -/* p flags file r w _bf cookie close read seek write */ -/* _ub */ - +#define std(flags, file) { \ + .pub._flags = (flags), \ + .pub._fileno = (file), \ + ._cookie = __sF + (file), \ + ._close = __sclose, \ + ._read = __sread, \ + ._seek = __sseek, \ + ._write = __swrite, \ +} /* the usual - (stdin + stdout + stderr) */ static FILE usual[FOPEN_MAX - 3]; static struct glue uglue = { NULL, FOPEN_MAX - 3, usual }; -FILE __sF[3] = { - std(__SRD, STDIN_FILENO), /* stdin */ - std(__SWR, STDOUT_FILENO), /* stdout */ - std(__SWR|__SNBF, STDERR_FILENO) /* stderr */ +static FILE __sF[3] = { + std(__SRD, STDIN_FILENO), + std(__SWR, STDOUT_FILENO), + std(__SWR|__SNBF, STDERR_FILENO) }; -/* - * note: __sglue starts the walk chain for exit flushing and other things. - */ -struct glue __sglue = { &uglue, 3, __sF }; /* GLOBAL, START OF LIST */ -static struct glue *lastglue = &uglue; - -/* - * The following kludge is done to ensure enough binary compatibility - * with future versions of libc. Or rather it allows us to work with - * libraries that have been built with a newer libc that defines these - * symbols and expects libc to provide them. We only have need to support - * i386 and alpha because they are the only "old" systems we have deployed. - */ FILE *__stdinp = &__sF[0]; FILE *__stdoutp = &__sF[1]; FILE *__stderrp = &__sF[2]; -static struct glue * moreglue (int); +struct glue __sglue = { &uglue, 3, __sF }; +static struct glue *lastglue = &uglue; + +static struct glue * moreglue(int); static spinlock_t thread_lock = _SPINLOCK_INITIALIZER; #define THREAD_LOCK() if (__isthreaded) _SPINLOCK(&thread_lock) #define THREAD_UNLOCK() if (__isthreaded) _SPINUNLOCK(&thread_lock) #if NOT_YET -#define SET_GLUE_PTR(ptr, val) atomic_set_ptr(&(ptr), (uintptr_t)(val)) +#define SET_GLUE_PTR(ptr, val) atomic_set_rel_ptr(&(ptr), (uintptr_t)(val)) #else #define SET_GLUE_PTR(ptr, val) ptr = val #endif -static -struct glue * +static struct glue * moreglue(int n) { struct glue *g; @@ -115,10 +103,8 @@ moreglue(int n) g->next = NULL; g->niobs = n; g->iobs = p; - while (--n >= 0) { - *p = empty; - p++; - } + while (--n >= 0) + *p++ = empty; return (g); } @@ -128,8 +114,8 @@ moreglue(int n) FILE * __sfp(void) { - FILE *fp; - int n; + FILE *fp; + int n; struct glue *g; if (!__sdidinit) @@ -165,12 +151,8 @@ found: fp->_ub._size = 0; fp->_lb._base = NULL; /* no line buffer */ fp->_lb._size = 0; - fp->_up = NULL; - fp->fl_mutex = PTHREAD_MUTEX_INITIALIZER; - fp->fl_owner = NULL; - fp->fl_count = 0; +/* fp->_lock = NULL; */ /* once set always set (reused) */ memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); - /* fp->_lock = NULL; */ return (fp); } @@ -178,8 +160,6 @@ found: * XXX. Force immediate allocation of internal memory. Not used by stdio, * but documented historically for certain applications. Bad applications. */ -void f_prealloc(void); - __warn_references(f_prealloc, "warning: this program uses f_prealloc(), which is not recommended."); @@ -225,11 +205,8 @@ _cleanup(void) void __sinit(void) { - THREAD_LOCK(); - if (__sdidinit == 0) { - /* Make sure we clean up on exit. */ - __cleanup = _cleanup; /* conservative */ - __sdidinit = 1; - } - THREAD_UNLOCK(); + + /* Make sure we clean up on exit. */ + __cleanup = _cleanup; /* conservative */ + __sdidinit = 1; } diff --git a/lib/libc/stdio/flags.c b/lib/libc/stdio/flags.c index 0323e37497..42dcd3e92c 100644 --- a/lib/libc/stdio/flags.c +++ b/lib/libc/stdio/flags.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)flags.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/flags.c,v 1.6.2.1 2001/03/05 10:51:22 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/flags.c,v 1.10 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/flags.c,v 1.5 2005/01/31 22:29:40 dillon Exp $ */ diff --git a/lib/libc/stdio/floatio.h b/lib/libc/stdio/floatio.h index 3c4bebf517..24efb032b8 100644 --- a/lib/libc/stdio/floatio.h +++ b/lib/libc/stdio/floatio.h @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,6 +30,7 @@ * SUCH DAMAGE. * * @(#)floatio.h 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/floatio.h,v 1.6 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/floatio.h,v 1.2 2005/08/02 00:44:39 joerg Exp $ */ @@ -41,7 +38,18 @@ * Floating point scanf/printf (input/output) definitions. */ -/* 11-bit exponent (VAX G floating point) is 308 decimal digits */ -#define MAXEXPDIG 308 -/* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ -#define MAXFRACT 39 +/* + * MAXEXPDIG is the maximum number of decimal digits needed to store a + * floating point exponent in the largest supported format. It should + * be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point + * conversions are supported, ceil(log10(LDBL_MAX_EXP)). But since it + * is presently never greater than 5 in practice, we fudge it. + */ +#define MAXEXPDIG 6 +#if LDBL_MAX_EXP > 999999 +#error "floating point buffers too small" +#endif + +char *__hdtoa(double, const char *, int, int *, int *, char **); +char *__hldtoa(long double, const char *, int, int *, int *, char **); +char *__ldtoa(long double *, int, int, int *, int *, char **); diff --git a/lib/libc/stdio/fopen.3 b/lib/libc/stdio/fopen.3 index 369d6990a4..e9f0ed5a13 100644 --- a/lib/libc/stdio/fopen.3 +++ b/lib/libc/stdio/fopen.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)fopen.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/fopen.3,v 1.7.2.6 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fopen.3,v 1.20 2007/01/09 00:28:06 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/fopen.3,v 1.4 2007/04/04 18:36:55 swildner Exp $ .\" .Dd June 8, 2004 @@ -50,7 +46,7 @@ .Sh SYNOPSIS .In stdio.h .Ft FILE * -.Fn fopen "const char *path" "const char *mode" +.Fn fopen "const char * restrict path" "const char * restrict mode" .Ft FILE * .Fn fdopen "int fildes" "const char *mode" .Ft FILE * @@ -75,7 +71,7 @@ The stream is positioned at the beginning of the file. Open for reading and writing. The stream is positioned at the beginning of the file. .It Dq Li w -Truncate file to zero length or create text file for writing. +Truncate to zero length or create text file for writing. The stream is positioned at the beginning of the file. .It Dq Li w+ Open for reading and writing. diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c index dade4e4721..f12b2baf74 100644 --- a/lib/libc/stdio/fopen.c +++ b/lib/libc/stdio/fopen.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,10 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/fopen.c,v 1.3.2.1 2001/03/05 10:53:51 obrien Exp $ - * $DragonFly: src/lib/libc/stdio/fopen.c,v 1.6 2005/11/20 11:07:30 swildner Exp $ - * * @(#)fopen.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/fopen.c,v 1.14 2008/04/22 17:03:32 jhb Exp $ + * $DragonFly: src/lib/libc/stdio/fopen.c,v 1.6 2005/11/20 11:07:30 swildner Exp $ */ #include "namespace.h" @@ -51,7 +46,7 @@ #include "priv_stdio.h" FILE * -fopen(const char *file, const char *mode) +fopen(const char * __restrict file, const char * __restrict mode) { FILE *fp; int f; @@ -62,7 +57,7 @@ fopen(const char *file, const char *mode) if ((fp = __sfp()) == NULL) return (NULL); if ((f = _open(file, oflags, DEFFILEMODE)) < 0) { - fp->pub._flags = 0; /* release */ + fp->pub._flags = 0; /* release */ return (NULL); } fp->pub._fileno = f; @@ -72,7 +67,6 @@ fopen(const char *file, const char *mode) fp->_write = __swrite; fp->_seek = __sseek; fp->_close = __sclose; - /* fp->_lock = NULL; */ /* * When opening in append mode, even though we use O_APPEND, * we need to seek to the end so that ftell() gets the right @@ -82,6 +76,6 @@ fopen(const char *file, const char *mode) * fseek and ftell.) */ if (oflags & O_APPEND) - __sseek((void *)fp, (fpos_t)0, SEEK_END); + _sseek(fp, (fpos_t)0, SEEK_END); return (fp); } diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c index 6dcc6d81e0..508430216b 100644 --- a/lib/libc/stdio/fprintf.c +++ b/lib/libc/stdio/fprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fprintf.c,v 1.6 1999/08/28 00:01:02 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fprintf.c,v 1.11 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fprintf.c,v 1.4 2004/07/27 07:59:10 asmodai Exp $ */ @@ -42,7 +38,7 @@ #include int -fprintf(FILE *fp, const char *fmt, ...) +fprintf(FILE * __restrict fp, const char * __restrict fmt, ...) { int ret; va_list ap; diff --git a/lib/libc/stdio/fpurge.c b/lib/libc/stdio/fpurge.c index 54e3333f5e..2150149b70 100644 --- a/lib/libc/stdio/fpurge.c +++ b/lib/libc/stdio/fpurge.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fpurge.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fpurge.c,v 1.7 1999/08/28 00:01:02 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fpurge.c,v 1.11 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fpurge.c,v 1.6 2005/07/23 20:23:06 joerg Exp $ */ @@ -43,7 +39,6 @@ #include #include #include "un-namespace.h" - #include "local.h" #include "libc_private.h" #include "priv_stdio.h" diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c index 5837049583..1f9859b951 100644 --- a/lib/libc/stdio/fputc.c +++ b/lib/libc/stdio/fputc.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,13 +30,14 @@ * SUCH DAMAGE. * * @(#)fputc.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fputc.c,v 1.7 1999/08/28 00:01:03 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fputc.c,v 1.14 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fputc.c,v 1.5 2005/01/31 22:29:40 dillon Exp $ */ #include "namespace.h" #include #include "un-namespace.h" +#include "local.h" #include "libc_private.h" int @@ -48,7 +45,7 @@ fputc(int c, FILE *fp) { int retval; FLOCKFILE(fp); - retval = putc(c, fp); + retval = __sputc(c, fp); FUNLOCKFILE(fp); return (retval); } diff --git a/lib/libc/stdio/fputs.3 b/lib/libc/stdio/fputs.3 index 56ff190f4f..19d6acdc1a 100644 --- a/lib/libc/stdio/fputs.3 +++ b/lib/libc/stdio/fputs.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)fputs.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/fputs.3,v 1.4.2.4 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fputs.3,v 1.14 2007/04/19 14:01:04 phk Exp $ .\" $DragonFly: src/lib/libc/stdio/fputs.3,v 1.2 2003/06/17 04:26:46 dillon Exp $ .\" .Dd June 4, 1993 @@ -69,16 +65,13 @@ writes the string .Fa str , and a terminating newline character, to the stream -.Em stdout . +.Dv stdout . .Sh RETURN VALUES -The +The functions .Fn fputs -function -returns 0 on success and -.Dv EOF -on error; +and .Fn puts -returns a nonnegative integer on success and +return a nonnegative integer on success and .Dv EOF on error. .Sh ERRORS @@ -86,7 +79,7 @@ on error. .It Bq Er EBADF The .Fa stream -supplied +argument is not a writable stream. .El .Pp @@ -100,6 +93,7 @@ for any of the errors specified for the routines .Xr write 2 . .Sh SEE ALSO .Xr ferror 3 , +.Xr fputws 3 , .Xr putc 3 , .Xr stdio 3 .Sh STANDARDS diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c index b8f410060a..e4d052391b 100644 --- a/lib/libc/stdio/fputs.c +++ b/lib/libc/stdio/fputs.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,24 +30,23 @@ * SUCH DAMAGE. * * @(#)fputs.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fputs.c,v 1.7 1999/08/28 00:01:03 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fputs.c,v 1.12 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fputs.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ #include "namespace.h" -#include #include #include #include "un-namespace.h" -#include "priv_stdio.h" - #include "libc_private.h" +#include "local.h" +#include "priv_stdio.h" /* * Write the given string to the given file. */ int -fputs(const char *s, FILE *fp) +fputs(const char * __restrict s, FILE * __restrict fp) { int retval; struct __suio uio; @@ -62,6 +57,7 @@ fputs(const char *s, FILE *fp) uio.uio_iov = &iov; uio.uio_iovcnt = 1; FLOCKFILE(fp); + ORIENT(fp, -1); retval = __sfvwrite(fp, &uio); FUNLOCKFILE(fp); return (retval); diff --git a/lib/libc/stdio/fread.3 b/lib/libc/stdio/fread.3 index 1a8fd3013a..7e72970763 100644 --- a/lib/libc/stdio/fread.3 +++ b/lib/libc/stdio/fread.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)fread.3 8.2 (Berkeley) 3/8/94 -.\" $FreeBSD: src/lib/libc/stdio/fread.3,v 1.5.2.3 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fread.3,v 1.10 2007/01/09 00:28:06 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/fread.3,v 1.2 2003/06/17 04:26:46 dillon Exp $ .\" .Dd March 8, 1994 @@ -49,9 +45,9 @@ .Sh SYNOPSIS .In stdio.h .Ft size_t -.Fn fread "void *ptr" "size_t size" "size_t nmemb" "FILE *stream" +.Fn fread "void * restrict ptr" "size_t size" "size_t nmemb" "FILE * restrict stream" .Ft size_t -.Fn fwrite "const void *ptr" "size_t size" "size_t nmemb" "FILE *stream" +.Fn fwrite "const void * restrict ptr" "size_t size" "size_t nmemb" "FILE * restrict stream" .Sh DESCRIPTION The function .Fn fread diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c index 521eef61c4..db3e24512c 100644 --- a/lib/libc/stdio/fread.c +++ b/lib/libc/stdio/fread.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fread.c 8.2 (Berkeley) 12/11/93 - * $FreeBSD: src/lib/libc/stdio/fread.c,v 1.7 1999/08/28 00:01:04 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fread.c,v 1.15 2008/12/01 14:33:34 ru Exp $ * $DragonFly: src/lib/libc/stdio/fread.c,v 1.8 2005/12/20 00:21:53 davidxu Exp $ */ @@ -42,13 +38,16 @@ #include #include #include "un-namespace.h" - #include "local.h" #include "libc_private.h" #include "priv_stdio.h" +/* + * MT-safe version + */ + size_t -fread(void *buf, size_t size, size_t count, FILE *fp) +fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) { size_t ret; @@ -59,7 +58,7 @@ fread(void *buf, size_t size, size_t count, FILE *fp) } size_t -__fread(void *buf, size_t size, size_t count, FILE *fp) +__fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp) { size_t resid; char *p; @@ -73,6 +72,7 @@ __fread(void *buf, size_t size, size_t count, FILE *fp) */ if ((resid = count * size) == 0) return (0); + ORIENT(fp, -1); if (fp->pub._r < 0) fp->pub._r = 0; total = resid; @@ -80,7 +80,7 @@ __fread(void *buf, size_t size, size_t count, FILE *fp) while (resid > (r = fp->pub._r)) { memcpy((void *)p, (void *)fp->pub._p, (size_t)r); fp->pub._p += r; - /* fp->_r = 0 ... done in __srefill */ + /* fp->pub._r = 0 ... done in __srefill */ p += r; resid -= r; if (__srefill(fp)) { diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c index 3967116980..4692597749 100644 --- a/lib/libc/stdio/freopen.c +++ b/lib/libc/stdio/freopen.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)freopen.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/freopen.c,v 1.5.2.1 2001/03/05 10:54:53 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/freopen.c,v 1.21 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/freopen.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ @@ -47,7 +43,6 @@ #include #include #include "un-namespace.h" - #include "libc_private.h" #include "local.h" #include "priv_stdio.h" @@ -58,13 +53,15 @@ * all possible, no matter what. */ FILE * -freopen(const char *file, const char *mode, FILE *fp) +freopen(const char * __restrict file, const char * __restrict mode, FILE *fp) { int f; int dflags, flags, isopen, oflags, sverrno, wantfd; if ((flags = __sflags(mode, &oflags)) == 0) { + sverrno = errno; fclose(fp); + errno = sverrno; return (NULL); } @@ -73,8 +70,6 @@ freopen(const char *file, const char *mode, FILE *fp) if (!__sdidinit) __sinit(); - sverrno = 0; - /* * If the filename is a NULL pointer, the caller is asking us to * re-open the same file with a different mode. We allow this only @@ -101,6 +96,8 @@ freopen(const char *file, const char *mode, FILE *fp) errno = EINVAL; return (NULL); } + if (fp->pub._flags & __SWR) + __sflush(fp); if ((oflags ^ dflags) & O_APPEND) { dflags &= ~O_APPEND; dflags |= oflags & O_APPEND; @@ -113,15 +110,9 @@ freopen(const char *file, const char *mode, FILE *fp) } } if (oflags & O_TRUNC) - ftruncate(fp->pub._fileno, 0); - if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET) < 0 && - errno != ESPIPE) { - sverrno = errno; - fclose(fp); - FUNLOCKFILE(fp); - errno = sverrno; - return (NULL); - } + ftruncate(fp->pub._fileno, (off_t)0); + if (!(oflags & O_APPEND)) + _sseek(fp, (fpos_t)0, SEEK_SET); f = fp->pub._fileno; isopen = 0; wantfd = -1; @@ -186,11 +177,12 @@ finish: if (HASLB(fp)) FREELB(fp); fp->_lb._size = 0; + memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); if (f < 0) { /* did not get it after all */ fp->pub._flags = 0; /* set it free */ - errno = sverrno; /* restore in case _close clobbered */ FUNLOCKFILE(fp); + errno = sverrno; /* restore in case _close clobbered */ return (NULL); } @@ -213,6 +205,16 @@ finish: fp->_write = __swrite; fp->_seek = __sseek; fp->_close = __sclose; + /* + * When opening in append mode, even though we use O_APPEND, + * we need to seek to the end so that ftell() gets the right + * answer. If the user then alters the seek pointer, or + * the file extends, this will fail, but there is not much + * we can do about this. (We could set __SAPP and check in + * fseek and ftell.) + */ + if (oflags & O_APPEND) + _sseek(fp, (fpos_t)0, SEEK_END); FUNLOCKFILE(fp); return (fp); } diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c index 7cb4519eb7..f43263007c 100644 --- a/lib/libc/stdio/fscanf.c +++ b/lib/libc/stdio/fscanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fscanf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fscanf.c,v 1.7 1999/08/28 00:01:04 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fscanf.c,v 1.13 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fscanf.c,v 1.4 2005/01/31 22:29:40 dillon Exp $ */ @@ -43,9 +39,10 @@ #include #include "un-namespace.h" #include "libc_private.h" +#include "local.h" int -fscanf(FILE *fp, char const *fmt, ...) +fscanf(FILE * __restrict fp, const char * __restrict fmt, ...) { int ret; va_list ap; diff --git a/lib/libc/stdio/fseek.3 b/lib/libc/stdio/fseek.3 index a73ca9028c..18c2465802 100644 --- a/lib/libc/stdio/fseek.3 +++ b/lib/libc/stdio/fseek.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,10 +30,10 @@ .\" SUCH DAMAGE. .\" .\" @(#)fseek.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/fseek.3,v 1.5.2.7 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/fseek.3,v 1.27 2007/06/18 02:13:04 ache Exp $ .\" $DragonFly: src/lib/libc/stdio/fseek.3,v 1.3 2007/07/30 22:11:33 swildner Exp $ .\" -.Dd March 5, 1999 +.Dd March 19, 2004 .Dt FSEEK 3 .Os .Sh NAME @@ -60,7 +56,7 @@ .Ft void .Fn rewind "FILE *stream" .Ft int -.Fn fgetpos "FILE *stream" "fpos_t *pos" +.Fn fgetpos "FILE * restrict stream" "fpos_t * restrict pos" .Ft int .Fn fsetpos "FILE *stream" "const fpos_t *pos" .In sys/types.h @@ -93,7 +89,9 @@ A successful call to the function clears the end-of-file indicator for the stream and undoes any effects of the .Xr ungetc 3 -function on the same stream. +and +.Xr ungetwc 3 +functions on the same stream. .Pp The .Fn ftell @@ -116,6 +114,17 @@ except that the error indicator for the stream is also cleared (see .Xr clearerr 3 ) . .Pp +Since +.Fn rewind +does not return a value, +an application wishing to detect errors should clear +.Va errno , +then call +.Fn rewind , +and if +.Va errno +is non-zero, assume an error has occurred. +.Pp The .Fn fseeko function is identical to @@ -137,21 +146,37 @@ The and .Fn fsetpos functions -are alternate interfaces equivalent to +are alternate interfaces for retrieving and setting the current position in +the file, similar to .Fn ftell and -.Fn fseek -(with whence set to -.Dv SEEK_SET ) , -setting and storing the current value of -the file offset into or from the object referenced by +.Fn fseek , +except that the current position is stored in an opaque object of +type +.Vt fpos_t +pointed to by .Fa pos . -On some -.Pq non- Ns Ux -systems an -.Dq Fa fpos_t -object may be a complex object -and these routines may be the only way to portably reposition a text stream. +These functions provide a portable way to seek to offsets larger than +those that can be represented by a +.Vt long int . +They may also store additional state information in the +.Vt fpos_t +object to facilitate seeking within files containing multibyte +characters with state-dependent encodings. +Although +.Vt fpos_t +has traditionally been an integral type, +applications cannot assume that it is; +in particular, they must not perform arithmetic on objects +of this type. +.Pp +If the stream is a wide character stream (see +.Xr fwide 3 ) , +the position specified by the combination of +.Fa offset +and +.Fa whence +must contain the first byte of a multibyte sequence. .Sh RETURN VALUES The .Fn rewind @@ -173,23 +198,33 @@ is set to indicate the error. .It Bq Er EBADF The .Fa stream -specified +argument is not a seekable stream. .It Bq Er EINVAL The .Fa whence -argument to -.Fn fseek -was not -.Dv SEEK_SET , -.Dv SEEK_END , -or -.Dv SEEK_CUR . +argument is invalid or +the resulting file-position +indicator would be set to a negative value. .It Bq Er EOVERFLOW -For -.Fn ftell , -the resulting file offset would be a value which -cannot be represented correctly in an object of type long. +The resulting file offset would be a value which +cannot be represented correctly in an object of type +.Fa off_t +for +.Fn fseeko +and +.Fn ftello +or +.Fa long +for +.Fn fseek +and +.Fn ftell . +.It Bq Er ESPIPE +The file descriptor underlying stream is associated with a pipe or FIFO +or file-position indicator value is unspecified +(see +.Xr ungetc 3 ) . .El .Pp The functions @@ -198,8 +233,9 @@ The functions .Fn fseeko , .Fn fsetpos , .Fn ftell , +.Fn ftello , and -.Fn ftello +.Fn rewind may also fail and set .Va errno for any of the errors specified for the routines @@ -209,7 +245,11 @@ for any of the errors specified for the routines and .Xr malloc 3 . .Sh SEE ALSO -.Xr lseek 2 +.Xr lseek 2 , +.Xr clearerr 3 , +.Xr fwide 3 , +.Xr ungetc 3 , +.Xr ungetwc 3 .Sh STANDARDS The .Fn fgetpos , @@ -227,4 +267,4 @@ The and .Fn ftello functions conform to -.St -susv2 . +.St -p1003.1-2001 . diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c index 0a428f9dc5..8ba8afe84d 100644 --- a/lib/libc/stdio/fseek.c +++ b/lib/libc/stdio/fseek.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,19 +30,19 @@ * SUCH DAMAGE. * * @(#)fseek.c 8.3 (Berkeley) 1/2/94 - * $FreeBSD: src/lib/libc/stdio/fseek.c,v 1.9.2.1 2001/03/05 10:56:58 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/fseek.c,v 1.44 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/fseek.c,v 1.10 2005/11/20 11:07:30 swildner Exp $ */ #include "namespace.h" #include #include +#include #include +#include #include #include -#include #include "un-namespace.h" - #include "local.h" #include "libc_private.h" #include "priv_stdio.h" @@ -56,21 +52,36 @@ int fseek(FILE *fp, long offset, int whence) { - return (fseeko(fp, offset, whence)); + int ret; + int serrno = errno; + + /* make sure stdio is set up */ + if (!__sdidinit) + __sinit(); + + FLOCKFILE(fp); + ret = _fseeko(fp, (off_t)offset, whence, 1); + FUNLOCKFILE(fp); + if (ret == 0) + errno = serrno; + return (ret); } int fseeko(FILE *fp, off_t offset, int whence) { int ret; + int serrno = errno; /* make sure stdio is set up */ if (!__sdidinit) __sinit(); FLOCKFILE(fp); - ret = _fseeko(fp, offset, whence); + ret = _fseeko(fp, offset, whence, 0); FUNLOCKFILE(fp); + if (ret == 0) + errno = serrno; return (ret); } @@ -79,10 +90,10 @@ fseeko(FILE *fp, off_t offset, int whence) * `Whence' must be one of the three SEEK_* macros. */ int -_fseeko(FILE *fp, off_t offset, int whence) +_fseeko(FILE *fp, off_t offset, int whence, int ltest) { - fpos_t (*seekfn) (void *, fpos_t, int); - fpos_t target, curoff; + fpos_t (*seekfn)(void *, fpos_t, int); + fpos_t target, curoff, ret; size_t n; struct stat st; int havepos; @@ -92,7 +103,7 @@ _fseeko(FILE *fp, off_t offset, int whence) */ if ((seekfn = fp->_seek) == NULL) { errno = ESPIPE; /* historic practice */ - return (EOF); + return (-1); } /* @@ -104,30 +115,38 @@ _fseeko(FILE *fp, off_t offset, int whence) case SEEK_CUR: /* * In order to seek relative to the current stream offset, - * we have to first find the current stream offset a la + * we have to first find the current stream offset via * ftell (see ftell for details). */ - if (fp->pub._flags & __SOFF) - curoff = fp->_offset; - else { - curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR); - if (curoff == -1) { - return (EOF); - } + if (_ftello(fp, &curoff)) + return (-1); + if (curoff < 0) { + /* Unspecified position because of ungetc() at 0 */ + errno = ESPIPE; + return (-1); + } + if (offset > 0 && curoff > OFF_MAX - offset) { + errno = EOVERFLOW; + return (-1); } - if (fp->pub._flags & __SRD) { - curoff -= fp->pub._r; - if (HASUB(fp)) - curoff -= fp->_ur; - } else if (fp->pub._flags & __SWR && fp->pub._p != NULL) - curoff += fp->pub._p - fp->_bf._base; - offset += curoff; + if (offset < 0) { + errno = EINVAL; + return (-1); + } + if (ltest && offset > LONG_MAX) { + errno = EOVERFLOW; + return (-1); + } whence = SEEK_SET; havepos = 1; break; case SEEK_SET: + if (offset < 0) { + errno = EINVAL; + return (-1); + } case SEEK_END: curoff = 0; /* XXX just to keep gcc quiet */ havepos = 0; @@ -135,7 +154,7 @@ _fseeko(FILE *fp, off_t offset, int whence) default: errno = EINVAL; - return (EOF); + return (-1); } /* @@ -170,22 +189,31 @@ _fseeko(FILE *fp, off_t offset, int whence) else { if (_fstat(fp->pub._fileno, &st)) goto dumb; + if (offset > 0 && st.st_size > OFF_MAX - offset) { + errno = EOVERFLOW; + return (-1); + } target = st.st_size + offset; - } - - if (!havepos) { - if (fp->pub._flags & __SOFF) - curoff = fp->_offset; - else { - curoff = (*seekfn)(fp->_cookie, (fpos_t)0, SEEK_CUR); - if (curoff == POS_ERR) - goto dumb; + if ((off_t)target < 0) { + errno = EINVAL; + return (-1); + } + if (ltest && (off_t)target > LONG_MAX) { + errno = EOVERFLOW; + return (-1); } - curoff -= fp->pub._r; - if (HASUB(fp)) - curoff -= fp->_ur; } + if (!havepos && _ftello(fp, &curoff)) + goto dumb; + + /* + * (If the buffer was modified, we have to + * skip this; see fgetln.c.) + */ + if (fp->pub._flags & __SMOD) + goto abspos; + /* * Compute the number of bytes in the input buffer (pretending * that any ungetc() input has been discarded). Adjust current @@ -206,21 +234,21 @@ _fseeko(FILE *fp, off_t offset, int whence) /* * If the target offset is within the current buffer, * simply adjust the pointers, clear EOF, undo ungetc(), - * and return. (If the buffer was modified, we have to - * skip this; see fgetln.c.) + * and return. */ - if ((fp->pub._flags & __SMOD) == 0 && - target >= curoff && target < curoff + n) { - int o = target - curoff; + if (target >= curoff && target < curoff + n) { + size_t o = target - curoff; fp->pub._p = fp->_bf._base + o; fp->pub._r = n - o; if (HASUB(fp)) FREEUB(fp); fp->pub._flags &= ~__SEOF; + memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); return (0); } +abspos: /* * The place we want to get to is not within the current buffer, * but we can still be kind to the kernel copyout mechanism. @@ -230,13 +258,12 @@ _fseeko(FILE *fp, off_t offset, int whence) * ensures that we only read one block, rather than two. */ curoff = target & ~(fp->_blksize - 1); - if ((*seekfn)(fp->_cookie, curoff, SEEK_SET) == POS_ERR) + if (_sseek(fp, curoff, SEEK_SET) == POS_ERR) goto dumb; fp->pub._r = 0; fp->pub._p = fp->_bf._base; if (HASUB(fp)) FREEUB(fp); - fp->pub._flags &= ~__SEOF; n = target - curoff; if (n) { if (__srefill(fp) || fp->pub._r < n) @@ -244,6 +271,8 @@ _fseeko(FILE *fp, off_t offset, int whence) fp->pub._p += n; fp->pub._r -= n; } + fp->pub._flags &= ~__SEOF; + memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); return (0); /* @@ -252,8 +281,12 @@ _fseeko(FILE *fp, off_t offset, int whence) */ dumb: if (__sflush(fp) || - (*seekfn)(fp->_cookie, (fpos_t)offset, whence) == POS_ERR) { - return (EOF); + (ret = _sseek(fp, (fpos_t)offset, whence)) == POS_ERR) + return (-1); + if (ltest && ret > LONG_MAX) { + fp->pub._flags |= __SERR; + errno = EOVERFLOW; + return (-1); } /* success: clear EOF indicator and discard ungetc() data */ if (HASUB(fp)) @@ -262,5 +295,6 @@ dumb: fp->pub._r = 0; /* fp->pub._w = 0; */ /* unnecessary (I think...) */ fp->pub._flags &= ~__SEOF; + memset(WCIO_GET(fp), 0, sizeof(struct wchar_io_data)); return (0); } diff --git a/lib/libc/stdio/fsetpos.c b/lib/libc/stdio/fsetpos.c index a74be9e18e..326638865a 100644 --- a/lib/libc/stdio/fsetpos.c +++ b/lib/libc/stdio/fsetpos.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)fsetpos.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fsetpos.c,v 1.7 1999/08/28 00:01:05 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fsetpos.c,v 1.9 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fsetpos.c,v 1.3 2004/06/07 20:35:41 hmp Exp $ */ diff --git a/lib/libc/stdio/ftell.c b/lib/libc/stdio/ftell.c index 9837c59dbe..2e53caeb49 100644 --- a/lib/libc/stdio/ftell.c +++ b/lib/libc/stdio/ftell.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,16 +30,16 @@ * SUCH DAMAGE. * * @(#)ftell.c 8.2 (Berkeley) 5/4/95 - * $FreeBSD: src/lib/libc/stdio/ftell.c,v 1.11 1999/08/28 00:01:06 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/ftell.c,v 1.27 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/ftell.c,v 1.6 2005/07/23 20:23:06 joerg Exp $ */ #include "namespace.h" #include -#include #include +#include +#include #include "un-namespace.h" - #include "local.h" #include "libc_private.h" #include "priv_stdio.h" @@ -55,8 +51,9 @@ long ftell(FILE *fp) { off_t rv; + rv = ftello(fp); - if ((long)rv != rv) { + if (rv > LONG_MAX) { errno = EOVERFLOW; return (-1); } @@ -68,15 +65,33 @@ ftell(FILE *fp) */ off_t ftello(FILE *fp) +{ + fpos_t rv; + int ret; + + FLOCKFILE(fp); + ret = _ftello(fp, &rv); + FUNLOCKFILE(fp); + if (ret) + return (-1); + if (rv < 0) { /* Unspecified value because of ungetc() at 0 */ + errno = ESPIPE; + return (-1); + } + return (rv); +} + +int +_ftello(FILE *fp, fpos_t *offset) { fpos_t pos; + size_t n; if (fp->_seek == NULL) { errno = ESPIPE; /* historic practice */ - return (-1L); + return (1); } - FLOCKFILE(fp); /* * Find offset of underlying I/O object, then * adjust for buffered bytes. @@ -84,11 +99,9 @@ ftello(FILE *fp) if (fp->pub._flags & __SOFF) pos = fp->_offset; else { - pos = (*fp->_seek)(fp->_cookie, (fpos_t)0, SEEK_CUR); - if (pos == -1) { - FUNLOCKFILE(fp); - return (pos); - } + pos = _sseek(fp, (fpos_t)0, SEEK_CUR); + if (pos == -1) + return (1); } if (fp->pub._flags & __SRD) { /* @@ -96,17 +109,26 @@ ftello(FILE *fp) * those from ungetc) cause the position to be * smaller than that in the underlying object. */ - pos -= fp->pub._r; + if ((pos -= (HASUB(fp) ? fp->_ur : fp->pub._r)) < 0) { + fp->pub._flags |= __SERR; + errno = EIO; + return (1); + } if (HASUB(fp)) - pos -= fp->_ur; - } else if (fp->pub._flags & __SWR && fp->pub._p != NULL) { + pos -= fp->pub._r; /* Can be negative at this point. */ + } else if ((fp->pub._flags & __SWR) && fp->pub._p != NULL) { /* * Writing. Any buffered characters cause the * position to be greater than that in the * underlying object. */ - pos += fp->pub._p - fp->_bf._base; + n = fp->pub._p - fp->_bf._base; + if (pos > OFF_MAX - n) { + errno = EOVERFLOW; + return (1); + } + pos += n; } - FUNLOCKFILE(fp); - return (pos); + *offset = pos; + return (0); } diff --git a/lib/libc/stdio/funopen.3 b/lib/libc/stdio/funopen.3 index 7bcc2ddb02..6696319084 100644 --- a/lib/libc/stdio/funopen.3 +++ b/lib/libc/stdio/funopen.3 @@ -11,10 +11,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -32,10 +28,10 @@ .\" SUCH DAMAGE. .\" .\" @(#)funopen.3 8.1 (Berkeley) 6/9/93 -.\" $FreeBSD: src/lib/libc/stdio/funopen.3,v 1.7.2.4 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/funopen.3,v 1.16 2007/01/09 00:28:06 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/funopen.3,v 1.3 2006/05/26 19:39:37 swildner Exp $ .\" -.Dd June 9, 1993 +.Dd March 19, 2004 .Dt FUNOPEN 3 .Os .Sh NAME @@ -50,9 +46,9 @@ .Ft FILE * .Fn funopen "const void *cookie" "int (*readfn)(void *, char *, int)" "int (*writefn)(void *, const char *, int)" "fpos_t (*seekfn)(void *, fpos_t, int)" "int (*closefn)(void *)" .Ft FILE * -.Fn fropen "void *cookie" "int (*readfn)(void *, char *, int)" +.Fn fropen "void *cookie" "int (*readfn)(void *, char *, int)" .Ft FILE * -.Fn fwopen "void *cookie" "int (*writefn)(void *, const char *, int)" +.Fn fwopen "void *cookie" "int (*writefn)(void *, const char *, int)" .Sh DESCRIPTION The .Fn funopen @@ -171,3 +167,11 @@ The function may not be portable to systems other than .Bx . +.Pp +The +.Fn funopen +interface erroneously assumes that +.Vt fpos_t +is an integral type; see +.Xr fseek 3 +for a discussion of this issue. diff --git a/lib/libc/stdio/funopen.c b/lib/libc/stdio/funopen.c index 2d55b8633a..3a9c073008 100644 --- a/lib/libc/stdio/funopen.c +++ b/lib/libc/stdio/funopen.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,10 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/funopen.c,v 1.1.1.1.14.1 2001/03/05 10:57:52 obrien Exp $ - * $DragonFly: src/lib/libc/stdio/funopen.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ - * * @(#)funopen.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/funopen.c,v 1.6 2007/01/09 00:28:06 imp Exp $ + * $DragonFly: src/lib/libc/stdio/funopen.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ #include @@ -48,8 +43,7 @@ FILE * funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), - fpos_t (*seekfn)(void *cookie, fpos_t off, int whence), - int (*closefn)(void *)) + fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)) { FILE *fp; int flags; diff --git a/lib/libc/stdio/fvwrite.c b/lib/libc/stdio/fvwrite.c index f2cb447b87..b709f8dc87 100644 --- a/lib/libc/stdio/fvwrite.c +++ b/lib/libc/stdio/fvwrite.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,11 +30,10 @@ * SUCH DAMAGE. * * @(#)fvwrite.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fvwrite.c,v 1.10 1999/08/28 00:01:06 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fvwrite.c,v 1.18 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fvwrite.c,v 1.7 2005/07/23 20:23:06 joerg Exp $ */ -#include #include #include #include @@ -64,24 +59,22 @@ __sfvwrite(FILE *fp, struct __suio *uio) if ((len = uio->uio_resid) == 0) return (0); /* make sure we can write */ - if (cantwrite(fp)) { - errno = EBADF; + if (prepwrite(fp) != 0) return (EOF); - } -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define COPY(n) (void)memcpy((void *)fp->pub._p, (void *)p, (size_t)(n)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define COPY(n) memcpy((void *)fp->pub._p, (void *)p, (size_t)(n)) iov = uio->uio_iov; p = iov->iov_base; len = iov->iov_len; iov++; -#define GETIOV(extra_work) \ - while (len == 0) { \ - extra_work; \ - p = iov->iov_base; \ - len = iov->iov_len; \ - iov++; \ +#define GETIOV(extra_work) \ + while (len == 0) { \ + extra_work; \ + p = iov->iov_base; \ + len = iov->iov_len; \ + iov++; \ } if (fp->pub._flags & __SNBF) { /* @@ -89,7 +82,7 @@ __sfvwrite(FILE *fp, struct __suio *uio) */ do { GETIOV(;); - w = (*fp->_write)(fp->_cookie, p, MIN(len, BUFSIZ)); + w = _swrite(fp, p, MIN(len, BUFSIZ)); if (w <= 0) goto err; p += w; @@ -130,7 +123,7 @@ __sfvwrite(FILE *fp, struct __suio *uio) if (len < w) w = len; if (w > 0) { - COPY(w); /* copy MIN(fp->_w,len), */ + COPY(w); /* copy MIN(fp->pub._w, len), */ fp->pub._w -= w; fp->pub._p += w; } @@ -138,13 +131,13 @@ __sfvwrite(FILE *fp, struct __suio *uio) } else if (fp->pub._p > fp->_bf._base && len > w) { /* fill and flush */ COPY(w); - /* fp->_w -= w; */ /* unneeded */ + /* fp->pub._w -= w; */ /* unneeded */ fp->pub._p += w; if (__fflush(fp)) goto err; } else if (len >= (w = fp->_bf._size)) { /* write directly */ - w = (*fp->_write)(fp->_cookie, p, w); + w = _swrite(fp, p, w); if (w <= 0) goto err; } else { @@ -178,12 +171,12 @@ __sfvwrite(FILE *fp, struct __suio *uio) w = fp->pub._w + fp->_bf._size; if (fp->pub._p > fp->_bf._base && s > w) { COPY(w); - /* fp->_w -= w; */ + /* fp->pub._w -= w; */ fp->pub._p += w; if (__fflush(fp)) goto err; } else if (s >= (w = fp->_bf._size)) { - w = (*fp->_write)(fp->_cookie, p, w); + w = _swrite(fp, p, w); if (w <= 0) goto err; } else { diff --git a/lib/libc/stdio/fwalk.c b/lib/libc/stdio/fwalk.c index b54d52143b..2e9f07db8e 100644 --- a/lib/libc/stdio/fwalk.c +++ b/lib/libc/stdio/fwalk.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,13 +30,13 @@ * SUCH DAMAGE. * * @(#)fwalk.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fwalk.c,v 1.6.2.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/fwalk.c,v 1.10 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fwalk.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ -#include #include #include +#include #include "local.h" #include "priv_stdio.h" @@ -53,13 +49,17 @@ _fwalk(int (*function)(FILE *)) ret = 0; /* - * It should be safe to walk the list without locking it; + * It should be safe to walk the list without locking it; * new nodes are only added to the end and none are ever * removed. + * + * Avoid locking this list while walking it or else you will + * introduce a potential deadlock in [at least] refill.c. */ for (g = &__sglue; g != NULL; g = g->next) for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) - if (fp->pub._flags != 0) + if ((fp->pub._flags != 0) && + ((fp->pub._flags & __SIGN) == 0)) ret |= (*function)(fp); return (ret); } diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c index 27b43b6d10..479f9b3832 100644 --- a/lib/libc/stdio/fwprintf.c +++ b/lib/libc/stdio/fwprintf.c @@ -1,6 +1,3 @@ -/* $NetBSD: fwprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/fwprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/fwprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/fwprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c index 61e720e66c..65825b37e4 100644 --- a/lib/libc/stdio/fwrite.c +++ b/lib/libc/stdio/fwrite.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,12 +30,11 @@ * SUCH DAMAGE. * * @(#)fwrite.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/fwrite.c,v 1.7 1999/08/28 00:01:07 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/fwrite.c,v 1.12 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/fwrite.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ #include "namespace.h" -#include #include #include "un-namespace.h" #include "local.h" @@ -51,7 +46,8 @@ * Return the number of whole objects written. */ size_t -fwrite(const void *buf, size_t size, size_t count, FILE *fp) +fwrite(const void * __restrict buf, size_t size, size_t count, + FILE * __restrict fp) { size_t n; struct __suio uio; @@ -63,6 +59,7 @@ fwrite(const void *buf, size_t size, size_t count, FILE *fp) uio.uio_iovcnt = 1; FLOCKFILE(fp); + ORIENT(fp, -1); /* * The usual case is success (__sfvwrite returns 0); * skip the divide if this happens, since divides are diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c index 71f4244548..fd4ecdf3f8 100644 --- a/lib/libc/stdio/fwscanf.c +++ b/lib/libc/stdio/fwscanf.c @@ -1,6 +1,3 @@ -/* $NetBSD: fwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/fwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,14 +22,15 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/fwscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/fwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include #include #include -#include "local.h" - int fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) { diff --git a/lib/libc/stdio/getc.3 b/lib/libc/stdio/getc.3 index 78fd31c431..a26c8ad006 100644 --- a/lib/libc/stdio/getc.3 +++ b/lib/libc/stdio/getc.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)getc.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/getc.3,v 1.5.2.6 2002/05/19 00:24:57 fanf Exp $ +.\" $FreeBSD: src/lib/libc/stdio/getc.3,v 1.21 2007/01/09 00:28:06 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/getc.3,v 1.3 2005/09/25 20:49:55 asmodai Exp $ .\" .Dd March 22, 2009 @@ -59,7 +55,7 @@ .Ft int .Fn getc_unlocked "FILE *stream" .Ft int -.Fn getchar "void" +.Fn getchar void .Ft int .Fn getchar_unlocked "void" .Ft int @@ -77,7 +73,8 @@ The .Fn getc function acts essentially identically to -.Fn fgetc . +.Fn fgetc , +but is a macro that expands in-line. .Pp The .Fn getchar @@ -89,7 +86,7 @@ The .Fn getw function obtains the next -.Em int +.Vt int (if present) from the stream pointed at by .Fa stream . @@ -105,7 +102,7 @@ and respectively, except that the caller is responsible for locking the stream with -.Fn flockfile +.Xr flockfile 3 before calling them. These functions may be used to avoid the overhead of locking the stream for each character, and to avoid input being dispersed among multiple @@ -115,9 +112,9 @@ If successful, these routines return the next requested object from the .Fa stream . Character values are returned as an -.Li unsigned char +.Vt "unsigned char" converted to an -.Li int . +.Vt int . If the stream is at end-of-file or a read error occurs, the routines return .Dv EOF . @@ -139,6 +136,7 @@ until the condition is cleared with .Xr flockfile 3 , .Xr fopen 3 , .Xr fread 3 , +.Xr getwc 3 , .Xr putc 3 , .Xr ungetc 3 .Sh STANDARDS @@ -166,7 +164,7 @@ and must be used to check for failure after calling .Fn getw . The size and byte order of an -.Em int +.Vt int varies from one machine to another, and .Fn getw is not recommended for portable applications. diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c index e2853b3249..f559b0cef0 100644 --- a/lib/libc/stdio/getc.c +++ b/lib/libc/stdio/getc.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)getc.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/getc.c,v 1.7.2.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/getc.c,v 1.16 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/getc.c,v 1.4 2005/08/27 21:35:01 joerg Exp $ */ @@ -42,7 +38,9 @@ #include #include "un-namespace.h" #include "libc_private.h" +#include "local.h" +#undef getc #undef getc_unlocked int @@ -58,5 +56,5 @@ getc(FILE *fp) int getc_unlocked(FILE *fp) { - return(__sgetc(fp)); + return (__sgetc(fp)); } diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c index 3d03ff5acb..0c275d293d 100644 --- a/lib/libc/stdio/getchar.c +++ b/lib/libc/stdio/getchar.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,28 +30,34 @@ * SUCH DAMAGE. * * @(#)getchar.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/getchar.c,v 1.7 1999/08/28 00:01:09 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/getchar.c,v 1.15 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/getchar.c,v 1.5 2005/08/27 21:35:01 joerg Exp $ */ /* - * A subroutine version of the macros getchar and getchar_unlocked. + * A subroutine version of the macro getchar. */ #include "namespace.h" #include #include "un-namespace.h" +#include "local.h" #include "libc_private.h" +#undef getchar #undef getchar_unlocked int getchar(void) { - return(getc(stdin)); + int retval; + FLOCKFILE(stdin); + retval = __sgetc(stdin); + FUNLOCKFILE(stdin); + return (retval); } int getchar_unlocked(void) { - return(getc_unlocked(stdin)); + return (__sgetc(stdin)); } diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c new file mode 100644 index 0000000000..bb88633a12 --- /dev/null +++ b/lib/libc/stdio/getdelim.c @@ -0,0 +1,160 @@ +/*- + * Copyright (c) 2009 David Schultz + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/getdelim.c,v 1.2 2009/04/06 13:50:04 das Exp $ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "libc_private.h" +#include "local.h" +#include "priv_stdio.h" + +static inline size_t +p2roundup(size_t n) +{ + + if (!powerof2(n)) { + n--; + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; +#if SIZE_T_MAX > 0xffffffffU + n |= n >> 32; +#endif + n++; + } + return (n); +} + +/* + * Expand *linep to hold len bytes (up to SSIZE_MAX + 1). + */ +static inline int +expandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp) +{ + char *newline; + size_t newcap; + + if (len > (size_t)SSIZE_MAX + 1) { + errno = EOVERFLOW; + return (-1); + } + if (len > *capp) { + if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */ + newcap = (size_t)SSIZE_MAX + 1; + else + newcap = p2roundup(len); + newline = realloc(*linep, newcap); + if (newline == NULL) + return (-1); + *capp = newcap; + *linep = newline; + } + return (0); +} + +/* + * Append the src buffer to the *dstp buffer. The buffers are of + * length srclen and *dstlenp, respectively, and dst has space for + * *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated + * appropriately, and *dstp is reallocated if needed. Returns 0 on + * success, -1 on allocation failure. + */ +static int +sappend(char ** __restrict dstp, size_t * __restrict dstlenp, + size_t * __restrict dstcapp, char * __restrict src, size_t srclen) +{ + + /* ensure room for srclen + dstlen + terminating NUL */ + if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp)) + return (-1); + memcpy(*dstp + *dstlenp, src, srclen); + *dstlenp += srclen; + return (0); +} + +ssize_t +getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim, + FILE * __restrict fp) +{ + u_char *endp; + size_t linelen; + + FLOCKFILE(fp); + ORIENT(fp, -1); + + if (linep == NULL || linecapp == NULL) { + errno = EINVAL; + goto error; + } + + if (*linecapp == 0) + *linep = NULL; + + if (fp->pub._r <= 0 && __srefill(fp)) { + /* If fp is at EOF already, we just need space for the NUL. */ + if (__sferror(fp) || expandtofit(linep, 1, linecapp)) + goto error; + FUNLOCKFILE(fp); + (*linep)[0] = '\0'; + return (-1); + } + + linelen = 0; + while ((endp = memchr(fp->pub._p, delim, fp->pub._r)) == NULL) { + if (sappend(linep, &linelen, linecapp, fp->pub._p, fp->pub._r)) + goto error; + if (__srefill(fp)) { + if (__sferror(fp)) + goto error; + goto done; /* hit EOF */ + } + } + endp++; /* snarf the delimiter, too */ + if (sappend(linep, &linelen, linecapp, fp->pub._p, endp - fp->pub._p)) + goto error; + fp->pub._r -= endp - fp->pub._p; + fp->pub._p = endp; +done: + /* Invariant: *linep has space for at least linelen+1 bytes. */ + (*linep)[linelen] = '\0'; + FUNLOCKFILE(fp); + return (linelen); + +error: + fp->pub._flags |= __SERR; + FUNLOCKFILE(fp); + return (-1); +} diff --git a/lib/libc/stdio/getline.3 b/lib/libc/stdio/getline.3 new file mode 100644 index 0000000000..40c5701424 --- /dev/null +++ b/lib/libc/stdio/getline.3 @@ -0,0 +1,164 @@ +.\" Copyright (c) 2009 David Schultz +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: src/lib/libc/stdio/getline.3,v 1.2 2009/04/06 13:50:04 das Exp $ +.\" +.Dd March 29, 2009 +.Dt GETLINE 3 +.Os +.Sh NAME +.Nm getdelim , +.Nm getline +.Nd get a line from a stream +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.Fd "#define _WITH_GETLINE" +.In stdio.h +.Ft ssize_t +.Fn getdelim "char ** restrict linep" "size_t * restrict linecapp" "int delimiter" " FILE * restrict stream" +.Ft ssize_t +.Fn getline "char ** restrict linep" "size_t * restrict linecapp" " FILE * restrict stream" +.Sh DESCRIPTION +The +.Fn getdelim +function reads a line from +.Fa stream , +delimited by the character +.Fa delimiter . +The +.Fn getline +function is equivalent to +.Fn getdelim +with the newline character as the delimiter. +The delimiter character is included as part of the line, unless +the end of the file is reached. +The caller may provide a pointer to a malloc buffer for the line in +.Fa *linep , +and the capacity of that buffer in +.Fa *linecapp ; +if +.Fa *linecapp +is 0, then +.Fa *linep +is treated as +.Dv NULL . +These functions may expand the buffer as needed, as if via +.Fn realloc , +and update +.Fa *linep +and +.Fa *linecapp +accordingly. +.Sh RETURN VALUES +The +.Fn getdelim +and +.Fn getline +functions return the number of characters written, excluding the +terminating +.Dv NUL . +The value \-1 is returned if an error occurs, or if end-of-file is reached. +.Sh EXAMPLES +The following code fragment reads lines from a file and +writes them to standard output. +The +.Fn fwrite +function is used in case the line contains embedded +.Dv NUL +characters. +.Bd -literal -offset indent +char *line = NULL; +size_t linecap = 0; +ssize_t linelen; +while ((linelen = getline(&line, &linecap, fp)) > 0) + fwrite(line, linelen, 1, stdout); +.Ed +.Sh COMPATIBILITY +Many application writers used the name +.Va getline +before the +.Fn getline +function was introduced in +.St -p1003.1 , +so a prototype is not provided by default in order to avoid +compatibility problems. +Applications that wish to use the +.Fn getline +function described herein should either request a strict +.St -p1003.1-2008 +environment by defining the macro +.Dv _POSIX_C_SOURCE +to the value 200809 or greater, or by defining the macro +.Dv _WITH_GETLINE , +prior to the inclusion of +.In stdio.h . +For compatibility with GNU libc, defining either +.Dv _BSD_SOURCE +or +.Dv _GNU_SOURCE +prior to the inclusion of +.In stdio.h +will also make +.Fn getline +available. +.Sh ERRORS +These functions may fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +Either +.Fa linep +or +.Fa linecapp +is +.Dv NULL . +.It Bq Er EOVERFLOW +No delimiter was found in the first +.Dv SSIZE_MAX +characters. +.El +.Pp +These functions may also fail for any of the errors specified for +.Fn fgets +and +.Fn malloc . +.Sh SEE ALSO +.Xr fgetln 3 , +.Xr fgets 3 , +.Xr malloc 3 +.Sh STANDARDS +The +.Fn getdelim +and +.Fn getline +functions conform to +.St -p1003.1-2008 . +.Sh HISTORY +These routines first appeared in +.Dx 2.3 . +.Sh BUGS +There are no wide character versions of +.Fn getdelim +or +.Fn getline . diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/getline.c similarity index 80% copy from lib/libc/stdio/vwscanf.c copy to lib/libc/stdio/getline.c index e1d2529ba9..82ec92d0e4 100644 --- a/lib/libc/stdio/vwscanf.c +++ b/lib/libc/stdio/getline.c @@ -1,8 +1,5 @@ -/* $NetBSD: vwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/vwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c) 2002 Tim J. Robbins + * Copyright (c) 2009 David Schultz * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,15 +22,16 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/getline.c,v 1.1 2009/02/28 06:00:58 das Exp $ */ -#include +#define _WITH_GETLINE #include -#include -int -vwscanf(const wchar_t * __restrict fmt, va_list ap) +ssize_t +getline(char ** __restrict linep, size_t * __restrict linecapp, + FILE * __restrict fp) { - - return (vfwscanf(stdin, fmt, ap)); + return (getdelim(linep, linecapp, '\n', fp)); } diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c index 907e700e30..df2be712bf 100644 --- a/lib/libc/stdio/gets.c +++ b/lib/libc/stdio/gets.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)gets.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/gets.c,v 1.9 2000/01/27 23:06:45 jasone Exp $ + * $FreeBSD: src/lib/libc/stdio/gets.c,v 1.17 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/gets.c,v 1.6 2005/11/20 11:07:30 swildner Exp $ */ @@ -43,6 +39,9 @@ #include #include #include "un-namespace.h" +#include "libc_private.h" +#include "local.h" +#include "priv_stdio.h" __warn_references(gets, "warning: this program uses gets(), which is unsafe."); @@ -55,18 +54,22 @@ gets(char *buf) static char w[] = "warning: this program uses gets(), which is unsafe.\n"; + FLOCKFILE(stdin); + ORIENT(stdin, -1); if (!warned) { _write(STDERR_FILENO, w, sizeof(w) - 1); warned = 1; } - for (s = buf; (c = getchar()) != '\n';) + for (s = buf; (c = __sgetc(stdin)) != '\n';) if (c == EOF) - if (s == buf) + if (s == buf) { + FUNLOCKFILE(stdin); return (NULL); - else + } else break; else *s++ = c; *s = 0; + FUNLOCKFILE(stdin); return (buf); } diff --git a/lib/libc/stdio/getw.c b/lib/libc/stdio/getw.c index ccdb05bce4..2b4b7f4120 100644 --- a/lib/libc/stdio/getw.c +++ b/lib/libc/stdio/getw.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)getw.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/getw.c,v 1.6 1999/08/28 00:01:09 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/getw.c,v 1.8 2007/01/09 00:28:06 imp Exp $ * $DragonFly: src/lib/libc/stdio/getw.c,v 1.3 2004/06/07 20:35:41 hmp Exp $ */ diff --git a/lib/libc/stdio/getwc.3 b/lib/libc/stdio/getwc.3 index 2118b199d7..fe4f138107 100644 --- a/lib/libc/stdio/getwc.3 +++ b/lib/libc/stdio/getwc.3 @@ -1,5 +1,4 @@ -.\" $NetBSD: getwc.3,v 1.7 2003/09/08 17:54:32 wiz Exp $ -.\" $DragonFly: src/lib/libc/stdio/getwc.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ +.\" $NetBSD: getwc.3,v 1.3 2002/02/07 07:00:26 ross Exp $ .\" .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -16,7 +15,7 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors +.\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" @@ -33,15 +32,17 @@ .\" SUCH DAMAGE. .\" .\" @(#)getc.3 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD: src/lib/libc/stdio/getwc.3,v 1.8 2007/01/09 00:28:06 imp Exp $ +.\" $DragonFly: src/lib/libc/stdio/getwc.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ .\" -.Dd October 24, 2001 +.Dd March 3, 2004 .Dt GETWC 3 .Os .Sh NAME .Nm fgetwc , .Nm getwc , -.Nm getwchar , -.Nd get next wide-character from input stream +.Nm getwchar +.Nd get next wide character from input stream .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -52,12 +53,12 @@ .Ft wint_t .Fn getwc "FILE *stream" .Ft wint_t -.Fn getwchar +.Fn getwchar void .Sh DESCRIPTION The .Fn fgetwc function -obtains the next input wide-character (if present) from the stream pointed at by +obtains the next input wide character (if present) from the stream pointed at by .Fa stream , or the next character pushed back on the stream via .Xr ungetwc 3 . @@ -66,17 +67,17 @@ The .Fn getwc function acts essentially identically to -.Fn fgetwc , -but is a macro that expands in-line. +.Fn fgetwc . .Pp The .Fn getwchar function is equivalent to .Fn getwc -with the argument stdin. +with the argument +.Dv stdin . .Sh RETURN VALUES -If successful, these routines return the next wide-character +If successful, these routines return the next wide character from the .Fa stream . If the stream is at end-of-file or a read error occurs, @@ -99,6 +100,7 @@ until the condition is cleared with .Xr ferror 3 , .Xr fopen 3 , .Xr fread 3 , +.Xr getc 3 , .Xr putwc 3 , .Xr stdio 3 , .Xr ungetwc 3 diff --git a/lib/libc/stdio/getwc.c b/lib/libc/stdio/getwc.c index 5ef66b5c74..4eb88d0e5c 100644 --- a/lib/libc/stdio/getwc.c +++ b/lib/libc/stdio/getwc.c @@ -1,8 +1,5 @@ -/* $NetBSD: getwc.c,v 1.3 2005/06/12 05:21:27 lukem Exp $ */ -/* $DragonFly: src/lib/libc/stdio/getwc.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c)2001 Citrus Project, + * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,20 +23,26 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Citrus$ + * $FreeBSD: src/lib/libc/stdio/getwc.c,v 1.3 2004/05/25 10:42:52 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/getwc.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ +#include "namespace.h" #include #include +#include "un-namespace.h" +#include "libc_private.h" +#include "local.h" -/* - * A subroutine version of the macro getwc. - */ #undef getwc +/* + * Synonym for fgetwc(). The only difference is that getwc(), if it is a + * macro, may evaluate `fp' more than once. + */ wint_t getwc(FILE *fp) { - return fgetwc(fp); + return (fgetwc(fp)); } diff --git a/lib/libc/stdio/getwchar.c b/lib/libc/stdio/getwchar.c index 95028cd8ce..00f40d8eaa 100644 --- a/lib/libc/stdio/getwchar.c +++ b/lib/libc/stdio/getwchar.c @@ -1,8 +1,5 @@ -/* $NetBSD: getwchar.c,v 1.3 2005/06/12 05:21:27 lukem Exp $ */ -/* $DragonFly: src/lib/libc/stdio/getwchar.c,v 1.2 2005/11/20 11:07:30 swildner Exp $ */ - /*- - * Copyright (c)2001 Citrus Project, + * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,20 +23,25 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Citrus$ + * $FreeBSD: src/lib/libc/stdio/getwchar.c,v 1.3 2004/05/25 10:42:52 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/getwchar.c,v 1.2 2005/11/20 11:07:30 swildner Exp $ */ +#include "namespace.h" #include #include +#include "un-namespace.h" +#include "libc_private.h" +#include "local.h" -/* - * A subroutine version of the macro getwchar. - */ #undef getwchar +/* + * Synonym for fgetwc(stdin). + */ wint_t getwchar(void) { - return fgetwc(stdin); + return (fgetwc(stdin)); } diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h index 258edc0bb0..6c8b010bcf 100644 --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,53 +30,65 @@ * SUCH DAMAGE. * * @(#)local.h 8.3 (Berkeley) 7/3/94 - * - * $FreeBSD: src/lib/libc/stdio/local.h,v 1.1.1.2.6.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/local.h,v 1.33 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/local.h,v 1.11 2007/11/25 01:28:22 swildner Exp $ */ -#include /* for off_t */ +#include /* for off_t */ +#include #include -#include /* for wchar_t */ +#include -#ifndef _MACHINE_STDINT_H_ -#include /* __size_t */ -#endif +#include "wcio.h" /* * Information local to this implementation of stdio, * in particular, macros and private variables. */ -extern int __slbexpand(FILE *, size_t); -extern int __sflush (FILE *); -extern FILE *__sfp (void); -extern int __srefill (FILE *); -extern int __sread (void *, char *, int); -extern int __swrite (void *, char const *, int); -extern fpos_t __sseek (void *, fpos_t, int); -extern int __sclose (void *); -extern void __sinit (void); -extern void _cleanup (void); -extern void (*__cleanup) (void); -extern void __smakebuf (FILE *); -extern int __swhatbuf (FILE *, __size_t *, int *); -extern int _fwalk (int (*)(FILE *)); -extern int __swsetup (FILE *); -extern int __sflags (const char *, int *); -extern int __vfprintf(FILE *, const char *, __va_list); +extern int _sread(FILE *, char *, int); +extern int _swrite(FILE *, const char *, int); +extern fpos_t _sseek(FILE *, fpos_t, int); +extern int _ftello(FILE *, fpos_t *); +extern int _fseeko(FILE *, off_t, int, int); +extern int __fflush(FILE *fp); +extern void __fcloseall(void); extern wint_t __fgetwc_unlock(FILE *); extern wint_t __fputwc_unlock(wchar_t, FILE *); -extern int __vfwprintf_unlocked(FILE *, const wchar_t *, __va_list); -extern size_t __fread(void *buf, size_t size, size_t count, FILE *fp); - +extern int __sflush(FILE *); +extern FILE *__sfp(void); +extern int __slbexpand(FILE *, size_t); +extern int __srefill(FILE *); +extern int __sread(void *, char *, int); +extern int __swrite(void *, const char *, int); +extern fpos_t __sseek(void *, fpos_t, int); +extern int __sclose(void *); +extern void __sinit(void); +extern void _cleanup(void); +extern void __smakebuf(FILE *); +extern int __swhatbuf(FILE *, size_t *, int *); +extern int _fwalk(int (*)(FILE *)); +extern int __svfscanf(FILE *, const char *, __va_list); +extern int __swsetup(FILE *); +extern int __sflags(const char *, int *); +extern int __ungetc(int, FILE *); +extern int __vfprintf(FILE *, const char *, __va_list); +extern int __vfscanf(FILE *, const char *, __va_list); +extern int __vfwprintf(FILE *, const wchar_t *, __va_list); +extern int __vfwscanf(FILE * __restrict, const wchar_t * __restrict, + __va_list); +extern size_t __fread(void * __restrict buf, size_t size, size_t count, + FILE * __restrict fp); extern int __sdidinit; + /* - * Return true iff the given FILE cannot be written now. + * Prepare the given FILE for writing, and return 0 iff it + * can be written now. Otherwise, return EOF and set errno. */ -#define cantwrite(fp) \ - ((((fp)->pub._flags & __SWR) == 0 || (fp)->_bf._base == NULL) && \ +#define prepwrite(fp) \ + ((((fp)->pub._flags & __SWR) == 0 || \ + ((fp)->_bf._base == NULL && ((fp)->pub._flags & __SSTR) == 0)) && \ __swsetup(fp)) /* @@ -102,3 +110,9 @@ extern int __sdidinit; free((char *)(fp)->_lb._base); \ (fp)->_lb._base = NULL; \ } + +/* + * Set the orientation for a stream. If o > 0, the stream has wide- + * orientation. If o < 0, the stream has byte-orientation. + */ +#define ORIENT(fp, o) _SET_ORIENTATION(fp, o) diff --git a/lib/libc/stdio/makebuf.c b/lib/libc/stdio/makebuf.c index 97208edc51..47e3a38e0d 100644 --- a/lib/libc/stdio/makebuf.c +++ b/lib/libc/stdio/makebuf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,10 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/makebuf.c,v 1.1.1.1.14.1 2001/03/05 11:27:49 obrien Exp $ - * $DragonFly: src/lib/libc/stdio/makebuf.c,v 1.6 2005/07/23 20:23:06 joerg Exp $ - * * @(#)makebuf.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/makebuf.c,v 1.6 2007/01/09 00:28:07 imp Exp $ + * $DragonFly: src/lib/libc/stdio/makebuf.c,v 1.6 2005/07/23 20:23:06 joerg Exp $ */ #include "namespace.h" @@ -47,6 +42,7 @@ #include #include "un-namespace.h" +#include "libc_private.h" #include "local.h" #include "priv_stdio.h" diff --git a/lib/libc/stdio/mktemp.3 b/lib/libc/stdio/mktemp.3 index 1f831c11cd..e7c019de4f 100644 --- a/lib/libc/stdio/mktemp.3 +++ b/lib/libc/stdio/mktemp.3 @@ -9,10 +9,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -30,7 +26,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)mktemp.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/mktemp.3,v 1.11.2.6 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/mktemp.3,v 1.22 2007/01/09 00:28:07 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/mktemp.3,v 1.3 2006/02/17 19:35:06 swildner Exp $ .\" .Dd February 11, 1998 @@ -95,13 +91,15 @@ function acts the same as except it permits a suffix to exist in the template. The template should be of the form .Pa /tmp/tmpXXXXXXsuffix . +The .Fn mkstemps +function is told the length of the suffix string. .Pp The .Fn mkdtemp function makes the same replacement to the template as in -.Xr mktemp 3 +.Fn mktemp and creates the template directory, mode 0700. .Sh RETURN VALUES The @@ -245,3 +243,10 @@ and the return status of the call should be tested for failure. This will ensure that the program does not continue blindly in the event that an attacker has already created the file with the intention of manipulating or reading its contents. +.Pp +The implementation of these functions calls +.Xr arc4random 3 , +which is not reentrant. +You must provide your own locking around this and other consumers of the +.Xr arc4random 3 +API. diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c index b9e8a03d3f..97c9159b20 100644 --- a/lib/libc/stdio/mktemp.c +++ b/lib/libc/stdio/mktemp.c @@ -10,10 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -31,12 +27,12 @@ * SUCH DAMAGE. * * @(#)mktemp.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/mktemp.c,v 1.19.2.3 2002/06/18 09:53:07 robert Exp $ + * $FreeBSD: src/lib/libc/stdio/mktemp.c,v 1.31 2008/07/28 21:18:59 jhb Exp $ * $DragonFly: src/lib/libc/stdio/mktemp.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ -/* #include "namespace.h" */ -#include +#include "namespace.h" +#include #include #include #include @@ -45,11 +41,11 @@ #include #include #include -/* #include "un-namespace.h" */ +#include "un-namespace.h" -char *_mktemp (char *); +char *_mktemp(char *); -static int _gettemp (char *, int *, int, int); +static int _gettemp(char *, int *, int, int); static const unsigned char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; @@ -94,13 +90,14 @@ mktemp(char *path) static int _gettemp(char *path, int *doopen, int domkdir, int slen) { - char *start, *trv, *suffp; + char *start, *trv, *suffp, *carryp; char *pad; struct stat sbuf; int rval; - uint32_t psrand; + uint32_t rand; + char carrybuf[MAXPATHLEN]; - if (doopen != NULL && domkdir) { + if ((doopen != NULL && domkdir) || slen < 0) { errno = EINVAL; return (0); } @@ -110,18 +107,21 @@ _gettemp(char *path, int *doopen, int domkdir, int slen) trv -= slen; suffp = trv; --trv; - if (trv < path) { + if (trv < path || NULL != strchr(suffp, '/')) { errno = EINVAL; return (0); } /* Fill space with random characters */ while (trv >= path && *trv == 'X') { - psrand = arc4random() % (sizeof(padchar) - 1); - *trv-- = padchar[psrand]; + rand = arc4random_uniform(sizeof(padchar) - 1); + *trv-- = padchar[rand]; } start = trv + 1; + /* save first combination of random characters */ + memcpy(carrybuf, start, suffp - start); + /* * check the target directory. */ @@ -158,14 +158,25 @@ _gettemp(char *path, int *doopen, int domkdir, int slen) return (errno == ENOENT); /* If we have a collision, cycle through the space of filenames */ - for (trv = start;;) { - if (*trv == '\0' || trv == suffp) - return (0); + for (trv = start, carryp = carrybuf;;) { + /* have we tried all possible permutations? */ + if (trv == suffp) + return (0); /* yes - exit with EEXIST */ pad = strchr(padchar, *trv); - if (pad == NULL || *++pad == '\0') - *trv++ = padchar[0]; - else { - *trv++ = *pad; + if (pad == NULL) { + /* this should never happen */ + errno = EIO; + return (0); + } + /* increment character */ + *trv = (*++pad == '\0') ? padchar[0] : *pad; + /* carry to next position? */ + if (*trv == *carryp) { + /* increment position and loop */ + ++trv; + ++carryp; + } else { + /* try with new name */ break; } } diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c index 09091a9f2a..9c8fd5932b 100644 --- a/lib/libc/stdio/perror.c +++ b/lib/libc/stdio/perror.c @@ -10,10 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -30,10 +26,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/perror.c,v 1.3.6.1 2001/03/05 11:27:49 obrien Exp $ - * $DragonFly: src/lib/libc/stdio/perror.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ - * * @(#)perror.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/perror.c,v 1.9 2007/01/09 00:28:07 imp Exp $ + * $DragonFly: src/lib/libc/stdio/perror.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ #include "namespace.h" @@ -41,13 +36,18 @@ #include #include #include +#include #include #include #include "un-namespace.h" +#include "libc_private.h" +#include "local.h" +#include "priv_stdio.h" void perror(const char *s) { + char msgbuf[NL_TEXTMAX]; struct iovec *v; struct iovec iov[4]; @@ -60,10 +60,15 @@ perror(const char *s) v->iov_len = 2; v++; } - v->iov_base = strerror(errno); + strerror_r(errno, msgbuf, sizeof(msgbuf)); + v->iov_base = msgbuf; v->iov_len = strlen(v->iov_base); v++; v->iov_base = __DECONST(char *, "\n"); v->iov_len = 1; - _writev(STDERR_FILENO, iov, (v - iov) + 1); + FLOCKFILE(stderr); + __sflush(stderr); + _writev(stderr->pub._fileno, iov, (v - iov) + 1); + stderr->pub._flags &= ~__SOFF; + FUNLOCKFILE(stderr); } diff --git a/lib/libc/stdio/printf-pos.c b/lib/libc/stdio/printf-pos.c new file mode 100644 index 0000000000..9344661bab --- /dev/null +++ b/lib/libc/stdio/printf-pos.c @@ -0,0 +1,755 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)vfprintf.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/printf-pos.c,v 1.6 2009/03/02 04:07:58 das Exp $ + */ + +/* + * This is the code responsible for handling positional arguments + * (%m$ and %m$.n$) for vfprintf() and vfwprintf(). + */ + +#include "namespace.h" +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "un-namespace.h" +#include "printflocal.h" + +/* + * Type ids for argument type table. + */ +enum typeid { + T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, + T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, + T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET, + T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, + T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR +}; + +/* An expandable array of types. */ +struct typetable { + enum typeid *table; /* table of types */ + enum typeid stattable[STATIC_ARG_TBL_SIZE]; + int tablesize; /* current size of type table */ + int tablemax; /* largest used index in table */ + int nextarg; /* 1-based argument index */ +}; + +static int __grow_type_table(struct typetable *); +static void build_arg_table (struct typetable *, va_list, union arg **); + +/* + * Initialize a struct typetable. + */ +static inline void +inittypes(struct typetable *types) +{ + int n; + + types->table = types->stattable; + types->tablesize = STATIC_ARG_TBL_SIZE; + types->tablemax = 0; + types->nextarg = 1; + for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) + types->table[n] = T_UNUSED; +} + +/* + * struct typetable destructor. + */ +static inline void +freetypes(struct typetable *types) +{ + + if (types->table != types->stattable) + free(types->table); +} + +/* + * Ensure that there is space to add a new argument type to the type table. + * Expand the table if necessary. Returns 0 on success. + */ +static inline int +_ensurespace(struct typetable *types) +{ + + if (types->nextarg >= types->tablesize) { + if (__grow_type_table(types)) + return (-1); + } + if (types->nextarg > types->tablemax) + types->tablemax = types->nextarg; + return (0); +} + +/* + * Add an argument type to the table, expanding if necessary. + * Returns 0 on success. + */ +static inline int +addtype(struct typetable *types, enum typeid type) +{ + + if (_ensurespace(types)) + return (-1); + types->table[types->nextarg++] = type; + return (0); +} + +static inline int +addsarg(struct typetable *types, int flags) +{ + + if (_ensurespace(types)) + return (-1); + if (flags & INTMAXT) + types->table[types->nextarg++] = T_INTMAXT; + else if (flags & SIZET) + types->table[types->nextarg++] = T_SSIZET; + else if (flags & PTRDIFFT) + types->table[types->nextarg++] = T_PTRDIFFT; + else if (flags & LLONGINT) + types->table[types->nextarg++] = T_LLONG; + else if (flags & LONGINT) + types->table[types->nextarg++] = T_LONG; + else + types->table[types->nextarg++] = T_INT; + return (0); +} + +static inline int +adduarg(struct typetable *types, int flags) +{ + + if (_ensurespace(types)) + return (-1); + if (flags & INTMAXT) + types->table[types->nextarg++] = T_UINTMAXT; + else if (flags & SIZET) + types->table[types->nextarg++] = T_SIZET; + else if (flags & PTRDIFFT) + types->table[types->nextarg++] = T_SIZET; + else if (flags & LLONGINT) + types->table[types->nextarg++] = T_U_LLONG; + else if (flags & LONGINT) + types->table[types->nextarg++] = T_U_LONG; + else + types->table[types->nextarg++] = T_U_INT; + return (0); +} + +/* + * Add * arguments to the type array. + */ +static inline int +addaster(struct typetable *types, char **fmtp) +{ + char *cp; + int n2; + + n2 = 0; + cp = *fmtp; + while (is_digit(*cp)) { + n2 = 10 * n2 + to_digit(*cp); + cp++; + } + if (*cp == '$') { + int hold = types->nextarg; + types->nextarg = n2; + if (addtype(types, T_INT)) + return (-1); + types->nextarg = hold; + *fmtp = ++cp; + } else { + if (addtype(types, T_INT)) + return (-1); + } + return (0); +} + +static inline int +addwaster(struct typetable *types, wchar_t **fmtp) +{ + wchar_t *cp; + int n2; + + n2 = 0; + cp = *fmtp; + while (is_digit(*cp)) { + n2 = 10 * n2 + to_digit(*cp); + cp++; + } + if (*cp == '$') { + int hold = types->nextarg; + types->nextarg = n2; + if (addtype(types, T_INT)) + return (-1); + types->nextarg = hold; + *fmtp = ++cp; + } else { + if (addtype(types, T_INT)) + return (-1); + } + return (0); +} + +/* + * Find all arguments when a positional parameter is encountered. Returns a + * table, indexed by argument number, of pointers to each arguments. The + * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. + * It will be replaces with a malloc-ed one if it overflows. + * Returns 0 on success. On failure, returns nonzero and sets errno. + */ +int +__find_arguments(const char *fmt0, va_list ap, union arg **argtable) +{ + char *fmt; /* format string */ + int ch; /* character from fmt */ + int n; /* handy integer (short term usage) */ + int error; + int flags; /* flags as above */ + int width; /* width from format (%8d), or 0 */ + struct typetable types; /* table of types */ + + fmt = __DECONST(char *, fmt0); + inittypes(&types); + error = 0; + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + while ((ch = *fmt) != '\0' && ch != '%') + fmt++; + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + width = 0; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + case '#': + goto rflag; + case '*': + if ((error = addaster(&types, &fmt))) + goto error; + goto rflag; + case '-': + case '+': + case '\'': + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + if ((error = addaster(&types, &fmt))) + goto error; + goto rflag; + } + while (is_digit(ch)) { + ch = *fmt++; + } + goto reswitch; + case '0': + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + if (ch == '$') { + types.nextarg = n; + goto rflag; + } + width = n; + goto reswitch; +#ifndef NO_FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (flags & SHORTINT) { + flags &= ~SHORTINT; + flags |= CHARINT; + } else + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= INTMAXT; + goto rflag; + case 'l': + if (flags & LONGINT) { + flags &= ~LONGINT; + flags |= LLONGINT; + } else + flags |= LONGINT; + goto rflag; + case 'q': + flags |= LLONGINT; /* not necessarily */ + goto rflag; + case 't': + flags |= PTRDIFFT; + goto rflag; + case 'z': + flags |= SIZET; + goto rflag; + case 'C': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'c': + error = addtype(&types, + (flags & LONGINT) ? T_WINT : T_INT); + if (error) + goto error; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + if ((error = addsarg(&types, flags))) + goto error; + break; +#ifndef NO_FLOATING_POINT + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + error = addtype(&types, + (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE); + if (error) + goto error; + break; +#endif /* !NO_FLOATING_POINT */ + case 'n': + if (flags & INTMAXT) + error = addtype(&types, TP_INTMAXT); + else if (flags & PTRDIFFT) + error = addtype(&types, TP_PTRDIFFT); + else if (flags & SIZET) + error = addtype(&types, TP_SSIZET); + else if (flags & LLONGINT) + error = addtype(&types, TP_LLONG); + else if (flags & LONGINT) + error = addtype(&types, TP_LONG); + else if (flags & SHORTINT) + error = addtype(&types, TP_SHORT); + else if (flags & CHARINT) + error = addtype(&types, TP_SCHAR); + else + error = addtype(&types, TP_INT); + if (error) + goto error; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + if ((error = adduarg(&types, flags))) + goto error; + break; + case 'p': + if ((error = addtype(&types, TP_VOID))) + goto error; + break; + case 'S': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 's': + error = addtype(&types, + (flags & LONGINT) ? TP_WCHAR : TP_CHAR); + if (error) + goto error; + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + case 'X': + case 'x': + if ((error = adduarg(&types, flags))) + goto error; + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + break; + } + } +done: + build_arg_table(&types, ap, argtable); +error: + freetypes(&types); + return (error || *argtable == NULL); +} + +/* wchar version of __find_arguments. */ +int +__find_warguments(const wchar_t *fmt0, va_list ap, union arg **argtable) +{ + wchar_t *fmt; /* format string */ + wchar_t ch; /* character from fmt */ + int n; /* handy integer (short term usage) */ + int error; + int flags; /* flags as above */ + int width; /* width from format (%8d), or 0 */ + struct typetable types; /* table of types */ + + fmt = __DECONST(wchar_t *, fmt0); + inittypes(&types); + error = 0; + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + while ((ch = *fmt) != '\0' && ch != '%') + fmt++; + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + width = 0; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + case '#': + goto rflag; + case '*': + if ((error = addwaster(&types, &fmt))) + goto error; + goto rflag; + case '-': + case '+': + case '\'': + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + if ((error = addwaster(&types, &fmt))) + goto error; + goto rflag; + } + while (is_digit(ch)) { + ch = *fmt++; + } + goto reswitch; + case '0': + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + if (ch == '$') { + types.nextarg = n; + goto rflag; + } + width = n; + goto reswitch; +#ifndef NO_FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (flags & SHORTINT) { + flags &= ~SHORTINT; + flags |= CHARINT; + } else + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= INTMAXT; + goto rflag; + case 'l': + if (flags & LONGINT) { + flags &= ~LONGINT; + flags |= LLONGINT; + } else + flags |= LONGINT; + goto rflag; + case 'q': + flags |= LLONGINT; /* not necessarily */ + goto rflag; + case 't': + flags |= PTRDIFFT; + goto rflag; + case 'z': + flags |= SIZET; + goto rflag; + case 'C': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'c': + error = addtype(&types, + (flags & LONGINT) ? T_WINT : T_INT); + if (error) + goto error; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + if ((error = addsarg(&types, flags))) + goto error; + break; +#ifndef NO_FLOATING_POINT + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + error = addtype(&types, + (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE); + if (error) + goto error; + break; +#endif /* !NO_FLOATING_POINT */ + case 'n': + if (flags & INTMAXT) + error = addtype(&types, TP_INTMAXT); + else if (flags & PTRDIFFT) + error = addtype(&types, TP_PTRDIFFT); + else if (flags & SIZET) + error = addtype(&types, TP_SSIZET); + else if (flags & LLONGINT) + error = addtype(&types, TP_LLONG); + else if (flags & LONGINT) + error = addtype(&types, TP_LONG); + else if (flags & SHORTINT) + error = addtype(&types, TP_SHORT); + else if (flags & CHARINT) + error = addtype(&types, TP_SCHAR); + else + error = addtype(&types, TP_INT); + if (error) + goto error; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + if ((error = adduarg(&types, flags))) + goto error; + break; + case 'p': + if ((error = addtype(&types, TP_VOID))) + goto error; + break; + case 'S': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 's': + error = addtype(&types, + (flags & LONGINT) ? TP_WCHAR : TP_CHAR); + if (error) + goto error; + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + case 'X': + case 'x': + if ((error = adduarg(&types, flags))) + goto error; + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + break; + } + } +done: + build_arg_table(&types, ap, argtable); +error: + freetypes(&types); + return (error || *argtable == NULL); +} + +/* + * Increase the size of the type table. Returns 0 on success. + */ +static int +__grow_type_table(struct typetable *types) +{ + enum typeid *const oldtable = types->table; + const int oldsize = types->tablesize; + enum typeid *newtable; + int n, newsize = oldsize * 2; + + if (newsize < types->nextarg + 1) + newsize = types->nextarg + 1; + if (oldsize == STATIC_ARG_TBL_SIZE) { + if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) + return (-1); + bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); + } else { + newtable = realloc(oldtable, newsize * sizeof(enum typeid)); + if (newtable == NULL) + return (-1); + } + for (n = oldsize; n < newsize; n++) + newtable[n] = T_UNUSED; + + types->table = newtable; + types->tablesize = newsize; + + return (0); +} + +/* + * Build the argument table from the completed type table. + * On malloc failure, *argtable is set to NULL. + */ +static void +build_arg_table(struct typetable *types, va_list ap, union arg **argtable) +{ + int n; + + if (types->tablemax >= STATIC_ARG_TBL_SIZE) { + *argtable = (union arg *) + malloc (sizeof (union arg) * (types->tablemax + 1)); + if (*argtable == NULL) + return; + } + + (*argtable) [0].intarg = 0; + for (n = 1; n <= types->tablemax; n++) { + switch (types->table[n]) { + case T_UNUSED: /* whoops! */ + (*argtable) [n].intarg = va_arg(ap, int); + break; + case TP_SCHAR: + (*argtable) [n].pschararg = va_arg(ap, signed char *); + break; + case TP_SHORT: + (*argtable) [n].pshortarg = va_arg(ap, short *); + break; + case T_INT: + (*argtable) [n].intarg = va_arg(ap, int); + break; + case T_U_INT: + (*argtable) [n].uintarg = va_arg(ap, unsigned int); + break; + case TP_INT: + (*argtable) [n].pintarg = va_arg(ap, int *); + break; + case T_LONG: + (*argtable) [n].longarg = va_arg(ap, long); + break; + case T_U_LONG: + (*argtable) [n].ulongarg = va_arg(ap, unsigned long); + break; + case TP_LONG: + (*argtable) [n].plongarg = va_arg(ap, long *); + break; + case T_LLONG: + (*argtable) [n].longlongarg = va_arg(ap, long long); + break; + case T_U_LLONG: + (*argtable) [n].ulonglongarg = va_arg(ap, unsigned long long); + break; + case TP_LLONG: + (*argtable) [n].plonglongarg = va_arg(ap, long long *); + break; + case T_PTRDIFFT: + (*argtable) [n].ptrdiffarg = va_arg(ap, ptrdiff_t); + break; + case TP_PTRDIFFT: + (*argtable) [n].pptrdiffarg = va_arg(ap, ptrdiff_t *); + break; + case T_SIZET: + (*argtable) [n].sizearg = va_arg(ap, size_t); + break; + case T_SSIZET: + (*argtable) [n].sizearg = va_arg(ap, ssize_t); + break; + case TP_SSIZET: + (*argtable) [n].pssizearg = va_arg(ap, ssize_t *); + break; + case T_INTMAXT: + (*argtable) [n].intmaxarg = va_arg(ap, intmax_t); + break; + case T_UINTMAXT: + (*argtable) [n].uintmaxarg = va_arg(ap, uintmax_t); + break; + case TP_INTMAXT: + (*argtable) [n].pintmaxarg = va_arg(ap, intmax_t *); + break; + case T_DOUBLE: +#ifndef NO_FLOATING_POINT + (*argtable) [n].doublearg = va_arg(ap, double); +#endif + break; + case T_LONG_DOUBLE: +#ifndef NO_FLOATING_POINT + (*argtable) [n].longdoublearg = va_arg(ap, long double); +#endif + break; + case TP_CHAR: + (*argtable) [n].pchararg = va_arg(ap, char *); + break; + case TP_VOID: + (*argtable) [n].pvoidarg = va_arg(ap, void *); + break; + case T_WINT: + (*argtable) [n].wintarg = va_arg(ap, wint_t); + break; + case TP_WCHAR: + (*argtable) [n].pwchararg = va_arg(ap, wchar_t *); + break; + } + } +} diff --git a/lib/libc/stdio/printf.3 b/lib/libc/stdio/printf.3 index 835da148e5..c86355f581 100644 --- a/lib/libc/stdio/printf.3 +++ b/lib/libc/stdio/printf.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,10 +30,10 @@ .\" SUCH DAMAGE. .\" .\" @(#)printf.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/printf.3,v 1.59 2005/09/05 09:49:33 tjr Exp $ +.\" $FreeBSD: src/lib/libc/stdio/printf.3,v 1.63 2009/03/04 03:38:51 das Exp $ .\" $DragonFly: src/lib/libc/stdio/printf.3,v 1.6 2006/08/26 10:27:55 swildner Exp $ .\" -.Dd August 26, 2006 +.Dd March 3, 2009 .Dt PRINTF 3 .Os .Sh NAME @@ -46,37 +42,44 @@ .Nm sprintf , .Nm snprintf , .Nm asprintf , +.Nm dprintf , .Nm vprintf , .Nm vfprintf , .Nm vsprintf , .Nm vsnprintf , -.Nm vasprintf +.Nm vasprintf , +.Nm vdprintf .Nd formatted output conversion .Sh LIBRARY .Lb libc .Sh SYNOPSIS +.Fd "#define _WITH_DPRINTF" .In stdio.h .Ft int -.Fn printf "const char *format" ... +.Fn printf "const char * restrict format" ... .Ft int -.Fn fprintf "FILE *stream" "const char *format" ... +.Fn fprintf "FILE * restrict stream" "const char * restrict format" ... .Ft int -.Fn sprintf "char *str" "const char *format" ... +.Fn sprintf "char * restrict str" "const char * restrict format" ... .Ft int -.Fn snprintf "char *str" "size_t size" "const char *format" ... +.Fn snprintf "char * restrict str" "size_t size" "const char * restrict format" ... .Ft int .Fn asprintf "char **ret" "const char *format" ... +.Ft int +.Fn dprintf "int" "const char * restrict format" ... .In stdarg.h .Ft int -.Fn vprintf "const char *format" "va_list ap" +.Fn vprintf "const char * restrict format" "va_list ap" .Ft int -.Fn vfprintf "FILE *stream" "const char *format" "va_list ap" +.Fn vfprintf "FILE * restrict stream" "const char * restrict format" "va_list ap" .Ft int -.Fn vsprintf "char *str" "const char *format" "va_list ap" +.Fn vsprintf "char * restrict str" "const char * restrict format" "va_list ap" .Ft int -.Fn vsnprintf "char *str" "size_t size" "const char *format" "va_list ap" +.Fn vsnprintf "char * restrict str" "size_t size" "const char * restrict format" "va_list ap" .Ft int .Fn vasprintf "char **ret" "const char *format" "va_list ap" +.Ft int +.Fn vdprintf "int fd" "const char * restrict format" "va_list ap" .Sh DESCRIPTION The .Fn printf @@ -96,6 +99,10 @@ and .Fn vfprintf write output to the given output .Fa stream ; +.Fn dprintf +and +.Fn vdprintf +write output to the given file descriptor; .Fn sprintf , .Fn snprintf , .Fn vsprintf , @@ -220,8 +227,7 @@ conversions, this option has no effect. For .Cm o conversions, the precision of the number is increased to force the first -character of the output string to a zero (except if a zero value is printed -with an explicit precision of zero). +character of the output string to a zero. For .Cm x and @@ -234,7 +240,7 @@ for .Cm X conversions) prepended to it. For -.Cm e , E , f , F , g , +.Cm a , A , e , E , f , F , g , and .Cm G conversions, the result will always contain a decimal point, even if no @@ -273,7 +279,7 @@ if both are given. .It So "\ " Sc (space) A blank should be left before a positive number produced by a signed conversion -.Cm ( d , e , E , f , F , g , G , +.Cm ( a , A , d , e , E , f , F , g , G , or .Cm i ) . .It Sq Cm + @@ -282,6 +288,18 @@ number produced by a signed conversion. A .Cm + overrides a space if both are used. +.It Sq Cm ' +Decimal conversions +.Cm ( d , u , +or +.Cm i ) +or the integral portion of a floating point conversion +.Cm ( f +or +.Cm F ) +should be grouped and separated by thousands using +the non-monetary separator returned by +.Xr localeconv 3 . .El .It An optional decimal digit string specifying a minimum field width. @@ -300,7 +318,7 @@ This gives the minimum number of digits to appear for and .Cm X conversions, the number of digits to appear after the decimal-point for -.Cm e , E , f , +.Cm a , A , e , E , f , and .Cm F conversions, the maximum number of significant digits for @@ -356,12 +374,12 @@ equivalent in size to a .Vt size_t . .Pp The following length modifier is valid for the -.Cm e , E , f , F , g , +.Cm a , A , e , E , f , F , g , or .Cm G conversion: .Bl -column ".Sy Modifier" ".Cm a , A , e , E , f , F , g , G" -.It Sy Modifier Ta Cm e , E , f , F , g , G +.It Sy Modifier Ta Cm a , A , e , E , f , F , g , G .It Cm l No (ell) Ta Vt double (ignored, same behavior as without it) .It Cm L Ta Vt "long double" @@ -461,7 +479,7 @@ The exponent always contains at least two digits; if the value is zero, the exponent is 00. .Pp For -.Cm e , E , f , F , g , +.Cm a , A , e , E , f , F , g , and .Cm G conversions, positive and negative infinity are represented as @@ -513,6 +531,55 @@ is used if the exponent from its conversion is less than \-4 or greater than or equal to the precision. Trailing zeros are removed from the fractional part of the result; a decimal point appears only if it is followed by at least one digit. +.It Cm aA +The +.Vt double +argument is rounded and converted to hexadecimal notation in the style +.Sm off +.Oo \- Oc Li 0x Ar h Li \&. Ar hhhp Oo \\*[Pm] Oc Ar d , +.Sm on +where the number of digits after the hexadecimal-point character +is equal to the precision specification. +If the precision is missing, it is taken as enough to represent +the floating-point number exactly, and no rounding occurs. +If the precision is zero, no hexadecimal-point character appears. +The +.Cm p +is a literal character +.Ql p , +and the exponent consists of a positive or negative sign +followed by a decimal number representing an exponent of 2. +The +.Cm A +conversion uses the prefix +.Dq Li 0X +(rather than +.Dq Li 0x ) , +the letters +.Dq Li ABCDEF +(rather than +.Dq Li abcdef ) +to represent the hex digits, and the letter +.Ql P +(rather than +.Ql p ) +to separate the mantissa and exponent. +.Pp +Note that there may be multiple valid ways to represent floating-point +numbers in this hexadecimal format. +For example, +.Li 0x1.92p+1 , 0x3.24p+0 , 0x6.48p-1 , +and +.Li 0xc.9p-2 +are all equivalent. +.Fx 8.0 +and later always prints finite non-zero numbers using +.Ql 1 +as the digit before the hexadecimal point. +Zeroes are always represented with a mantissa of 0 (preceded by a +.Ql - +if appropriate) and an exponent of +.Li +0 . .It Cm C Treated as .Cm c @@ -724,6 +791,57 @@ for later interpolation by Always use the proper secure idiom: .Pp .Dl "snprintf(buffer, sizeof(buffer), \*q%s\*q, string);" +.Sh COMPATIBILITY +Many application writers used the name +.Va dprintf +before the +.Fn dprintf +function was introduced in +.St -p1003.1 , +so a prototype is not provided by default in order to avoid +compatibility problems. +Applications that wish to use the +.Fn dprintf +function described herein should either request a strict +.St -p1003.1-2008 +environment by defining the macro +.Dv _POSIX_C_SOURCE +to the value 200809 or greater, or by defining the macro +.Dv _WITH_DPRINTF , +prior to the inclusion of +.In stdio.h . +For compatibility with GNU libc, defining either +.Dv _BSD_SOURCE +or +.Dv _GNU_SOURCE +prior to the inclusion of +.In stdio.h +will also make +.Fn dprintf +available. +.Pp +The conversion formats +.Cm \&%D , \&%O , +and +.Cm %U +are not standard and +are provided only for backward compatibility. +The effect of padding the +.Cm %p +format with zeros (either by the +.Cm 0 +flag or by specifying a precision), and the benign effect (i.e., none) +of the +.Cm # +flag on +.Cm %n +and +.Cm %p +conversions, as well as other +nonsensical combinations such as +.Cm %Ld , +are not standard; such combinations +should be avoided. .Sh ERRORS In addition to the errors documented for the .Xr write 2 @@ -763,7 +881,13 @@ With the same reservation, the and .Fn vsnprintf functions conform to -.St -isoC-99 . +.St -isoC-99 , +while +.Fn dprintf +and +.Fn vdprintf +conform to +.St -p1003.1-2008 . .Sh HISTORY The functions .Fn asprintf @@ -781,30 +905,13 @@ from .An Todd C. Miller Aq Todd.Miller@courtesan.com for .Ox 2.3 . -.Sh BUGS -The conversion formats -.Cm \&%D , \&%O , -and -.Cm %U -are not standard and -are provided only for backward compatibility. -The effect of padding the -.Cm %p -format with zeros (either by the -.Cm 0 -flag or by specifying a precision), and the benign effect (i.e., none) -of the -.Cm # -flag on -.Cm %n +The +.Fn dprintf and -.Cm %p -conversions, as well as other -nonsensical combinations such as -.Cm %Ld , -are not standard; such combinations -should be avoided. -.Pp +.Fn vdprintf +functions were added in +.Fx 8.0 . +.Sh BUGS The .Nm family of functions do not correctly handle multibyte characters in the diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c index 3bd8d0c330..84f834a34e 100644 --- a/lib/libc/stdio/printf.c +++ b/lib/libc/stdio/printf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)printf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/printf.c,v 1.6 1999/08/28 00:01:11 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/printf.c,v 1.11 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/printf.c,v 1.3 2004/06/07 20:35:41 hmp Exp $ */ @@ -42,7 +38,7 @@ #include int -printf(char const *fmt, ...) +printf(const char * __restrict fmt, ...) { int ret; va_list ap; diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h new file mode 100644 index 0000000000..c41b89274f --- /dev/null +++ b/lib/libc/stdio/printfcommon.h @@ -0,0 +1,301 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/printfcommon.h,v 1.4 2009/01/22 08:14:28 das Exp $ + */ + +/* + * This file defines common routines used by both printf and wprintf. + * You must define CHAR to either char or wchar_t prior to including this. + */ + + +#ifndef NO_FLOATING_POINT + +#define dtoa __dtoa +#define freedtoa __freedtoa + +#include +#include +#include "floatio.h" +#include "gdtoa.h" + +#define DEFPREC 6 + +static int exponent(CHAR *, int, CHAR); + +#endif /* !NO_FLOATING_POINT */ + +static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *); +static CHAR *__ultoa(u_long, CHAR *, int, int, const char *); + +#define NIOV 8 +struct io_state { + FILE *fp; + struct __suio uio; /* output information: summary */ + struct __siov iov[NIOV];/* ... and individual io vectors */ +}; + +static inline void +io_init(struct io_state *iop, FILE *fp) +{ + + iop->uio.uio_iov = iop->iov; + iop->uio.uio_resid = 0; + iop->uio.uio_iovcnt = 0; + iop->fp = fp; +} + +/* + * WARNING: The buffer passed to io_print() is not copied immediately; it must + * remain valid until io_flush() is called. + */ +static inline int +io_print(struct io_state *iop, const CHAR * __restrict ptr, int len) +{ + + iop->iov[iop->uio.uio_iovcnt].iov_base = __DECONST(char *, ptr); + iop->iov[iop->uio.uio_iovcnt].iov_len = len; + iop->uio.uio_resid += len; + if (++iop->uio.uio_iovcnt >= NIOV) + return (__sprint(iop->fp, &iop->uio)); + else + return (0); +} + +/* + * Choose PADSIZE to trade efficiency vs. size. If larger printf + * fields occur frequently, increase PADSIZE and make the initialisers + * below longer. + */ +#define PADSIZE 16 /* pad chunk size */ +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'}; + +/* + * Pad with blanks or zeroes. 'with' should point to either the blanks array + * or the zeroes array. + */ +static inline int +io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) +{ + int n; + + while (howmany > 0) { + n = (howmany >= PADSIZE) ? PADSIZE : howmany; + if (io_print(iop, with, n)) + return (-1); + howmany -= n; + } + return (0); +} + +/* + * Print exactly len characters of the string spanning p to ep, truncating + * or padding with 'with' as necessary. + */ +static inline int +io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, + int len, const CHAR * __restrict with) +{ + int p_len; + + p_len = ep - p; + if (p_len > len) + p_len = len; + if (p_len > 0) { + if (io_print(iop, p, p_len)) + return (-1); + } else { + p_len = 0; + } + return (io_pad(iop, len - p_len, with)); +} + +static inline int +io_flush(struct io_state *iop) +{ + + return (__sprint(iop->fp, &iop->uio)); +} + +/* + * Convert an unsigned long to ASCII for printf purposes, returning + * a pointer to the first character of the string representation. + * Octal numbers can be forced to have a leading zero; hex numbers + * use the given digits. + */ +static CHAR * +__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs) +{ + CHAR *cp = endp; + long sval; + + /* + * Handle the three cases separately, in the hope of getting + * better/faster code. + */ + switch (base) { + case 10: + if (val < 10) { /* many numbers are 1 digit */ + *--cp = to_char(val); + return (cp); + } + /* + * On many machines, unsigned arithmetic is harder than + * signed arithmetic, so we do at most one unsigned mod and + * divide; this is sufficient to reduce the range of + * the incoming value to where signed arithmetic works. + */ + if (val > LONG_MAX) { + *--cp = to_char(val % 10); + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: /* oops */ + abort(); + } + return (cp); +} + +/* Identical to __ultoa, but for intmax_t. */ +static CHAR * +__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs) +{ + CHAR *cp = endp; + intmax_t sval; + + /* quick test for small values; __ultoa is typically much faster */ + /* (perhaps instead we should run until small, then call __ultoa?) */ + if (val <= ULONG_MAX) + return (__ultoa((u_long)val, endp, base, octzero, xdigs)); + switch (base) { + case 10: + if (val < 10) { + *--cp = to_char(val % 10); + return (cp); + } + if (val > INTMAX_MAX) { + *--cp = to_char(val % 10); + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: + abort(); + } + return (cp); +} + +#ifndef NO_FLOATING_POINT + +static int +exponent(CHAR *p0, int exp, CHAR fmtch) +{ + CHAR *p, *t; + CHAR expbuf[MAXEXPDIG]; + + p = p0; + *p++ = fmtch; + if (exp < 0) { + exp = -exp; + *p++ = '-'; + } + else + *p++ = '+'; + t = expbuf + MAXEXPDIG; + if (exp > 9) { + do { + *--t = to_char(exp % 10); + } while ((exp /= 10) > 9); + *--t = to_char(exp); + for (; t < expbuf + MAXEXPDIG; *p++ = *t++); + } + else { + /* + * Exponents for decimal floating point conversions + * (%[eEgG]) must be at least two characters long, + * whereas exponents for hexadecimal conversions can + * be only one character long. + */ + if (fmtch == 'e' || fmtch == 'E') + *p++ = '0'; + *p++ = to_char(exp); + } + return (p - p0); +} + +#endif /* !NO_FLOATING_POINT */ diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/printflocal.h similarity index 50% copy from lib/libc/stdio/putchar.c copy to lib/libc/stdio/printflocal.h index aa84b08105..ca7e05de17 100644 --- a/lib/libc/stdio/putchar.c +++ b/lib/libc/stdio/printflocal.h @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,36 +29,66 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)putchar.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/putchar.c,v 1.7 1999/08/28 00:01:12 peter Exp $ - * $DragonFly: src/lib/libc/stdio/putchar.c,v 1.6 2005/08/27 21:35:01 joerg Exp $ + * $FreeBSD: src/lib/libc/stdio/printflocal.h,v 1.3 2009/03/02 04:07:58 das Exp $ */ -#include "namespace.h" -#include -#include "un-namespace.h" -#include "libc_private.h" - -#undef putchar_unlocked - /* - * putchar has traditionally been a macro in . That is no - * longer true because POSIX requires it to be thread-safe. POSIX - * does define putchar_unlocked() which is defined as a macro and is - * probably what you want to use instead. + * Flags used during conversion. */ +#define ALT 0x001 /* alternate form */ +#define LADJUST 0x004 /* left adjustment */ +#define LONGDBL 0x008 /* long double */ +#define LONGINT 0x010 /* long integer */ +#define LLONGINT 0x020 /* long long integer */ +#define SHORTINT 0x040 /* short integer */ +#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ +#define FPT 0x100 /* Floating point number */ +#define GROUPING 0x200 /* use grouping ("'" flag) */ + /* C99 additional size modifiers: */ +#define SIZET 0x400 /* size_t */ +#define PTRDIFFT 0x800 /* ptrdiff_t */ +#define INTMAXT 0x1000 /* intmax_t */ +#define CHARINT 0x2000 /* print char using int format */ /* - * A subroutine version of the macros putchar and putchar_unlocked. + * Macros for converting digits to letters and vice versa */ -int -putchar(int c) -{ - return(putc(c, stdout)); -} +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) ((n) + '0') + +/* Size of the static argument table. */ +#define STATIC_ARG_TBL_SIZE 8 + +union arg { + int intarg; + u_int uintarg; + long longarg; + u_long ulongarg; + long long longlongarg; + unsigned long long ulonglongarg; + ptrdiff_t ptrdiffarg; + size_t sizearg; + intmax_t intmaxarg; + uintmax_t uintmaxarg; + void *pvoidarg; + char *pchararg; + signed char *pschararg; + short *pshortarg; + int *pintarg; + long *plongarg; + long long *plonglongarg; + ptrdiff_t *pptrdiffarg; + ssize_t *pssizearg; + intmax_t *pintmaxarg; +#ifndef NO_FLOATING_POINT + double doublearg; + long double longdoublearg; +#endif + wint_t wintarg; + wchar_t *pwchararg; +}; -int -putchar_unlocked(int c) -{ - return(putc_unlocked(c, stdout)); -} +/* Handle positional parameters. */ +int __find_arguments(const char *, va_list, union arg **); +int __find_warguments(const wchar_t *, va_list, union arg **); diff --git a/lib/libc/stdio/priv_stdio.h b/lib/libc/stdio/priv_stdio.h index 8b99a54e1a..de4e67226c 100644 --- a/lib/libc/stdio/priv_stdio.h +++ b/lib/libc/stdio/priv_stdio.h @@ -40,6 +40,12 @@ #include "wcio.h" +/* + * NB: to fit things in six character monocase externals, the stdio + * code uses the prefix `__s' for stdio objects, typically followed + * by a three-character attempt at a mnemonic. + */ + /* stdio buffers */ struct __sbuf { unsigned char *_base; @@ -60,10 +66,10 @@ struct __FILE { /* operations */ void *_cookie; /* cookie passed to io functions */ - int (*_close) (void *); - int (*_read) (void *, char *, int); - fpos_t (*_seek) (void *, fpos_t, int); - int (*_write) (void *, const char *, int); + int (*_close)(void *); + int (*_read)(void *, char *, int); + fpos_t (*_seek)(void *, fpos_t, int); + int (*_write)(void *, const char *, int); /* separate buffer for long sequences of ungetc() */ struct __sbuf _ub; /* ungetc buffer */ @@ -81,9 +87,9 @@ struct __FILE { fpos_t _offset; /* current lseek offset (see WARNING) */ unsigned char *_up; /* saved _p when _p is doing ungetc data */ - pthread_mutex_t fl_mutex; /* used for MT-safety */ - pthread_t fl_owner; /* current owner */ - int fl_count; /* recursive lock count */ + pthread_mutex_t _fl_mutex; /* used for MT-safety */ + pthread_t _fl_owner; /* current owner */ + int _fl_count; /* recursive lock count */ struct wchar_io_data _wcio; }; diff --git a/lib/libc/stdio/putc.3 b/lib/libc/stdio/putc.3 index 99e7c27fef..07c7be69bf 100644 --- a/lib/libc/stdio/putc.3 +++ b/lib/libc/stdio/putc.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)putc.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/putc.3,v 1.5.2.3 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/putc.3,v 1.16 2007/01/09 00:28:07 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/putc.3,v 1.2 2003/06/17 04:26:46 dillon Exp $ .\" .Dd March 22, 2009 @@ -76,8 +72,14 @@ to the output stream pointed to by .Pp The .Fn putc -function acts essentially identically to -.Fn fputc . +macro acts essentially identically to +.Fn fputc , +but is a macro that expands in-line. +It may evaluate +.Fa stream +more than once, so arguments given to +.Fn putc +should not be expressions with potential side effects. .Pp The .Fn putchar @@ -85,13 +87,13 @@ function is identical to .Fn putc with an output stream of -.Em stdout . +.Dv stdout . .Pp The .Fn putw function writes the specified -.Em int +.Vt int to the named output .Fa stream . .Pp @@ -106,7 +108,7 @@ and respectively, except that the caller is responsible for locking the stream with -.Fn flockfile +.Xr flockfile 3 before calling them. These functions may be used to avoid the overhead of locking the stream for each character, and to avoid output being interspersed from multiple @@ -136,6 +138,7 @@ or if an attempt is made to write a read-only stream. .Xr flockfile 3 , .Xr fopen 3 , .Xr getc 3 , +.Xr putwc 3 , .Xr stdio 3 .Sh STANDARDS The functions @@ -151,13 +154,13 @@ and .Fn putchar_unlocked functions conform to .St -p1003.1-2001 . -A +A function .Fn putw function appeared in .At v6 . .Sh BUGS The size and byte order of an -.Em int +.Vt int varies from one machine to another, and .Fn putw is not recommended for portable applications. diff --git a/lib/libc/stdio/putc.c b/lib/libc/stdio/putc.c index 490724b1e7..46b4ca06a5 100644 --- a/lib/libc/stdio/putc.c +++ b/lib/libc/stdio/putc.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,23 +30,19 @@ * SUCH DAMAGE. * * @(#)putc.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/putc.c,v 1.7 1999/08/28 00:01:12 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/putc.c,v 1.16 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/putc.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ #include "namespace.h" #include #include "un-namespace.h" +#include "local.h" #include "libc_private.h" +#undef putc #undef putc_unlocked -/* - * putc has traditionally been a macro in . That is no - * longer true because POSIX requires it to be thread-safe. POSIX - * does define putc_unlocked() which is defined as a macro and is - * probably what you want to use instead. - */ int putc(int c, FILE *fp) { @@ -62,7 +54,8 @@ putc(int c, FILE *fp) } int -putc_unlocked(int c, FILE *fp) +putc_unlocked(int ch, FILE *fp) { - return(__sputc(c, fp)); + + return (__sputc(ch, fp)); } diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c index aa84b08105..a2ce7b06f8 100644 --- a/lib/libc/stdio/putchar.c +++ b/lib/libc/stdio/putchar.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,35 +30,37 @@ * SUCH DAMAGE. * * @(#)putchar.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/putchar.c,v 1.7 1999/08/28 00:01:12 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/putchar.c,v 1.16 2008/05/05 16:03:52 jhb Exp $ * $DragonFly: src/lib/libc/stdio/putchar.c,v 1.6 2005/08/27 21:35:01 joerg Exp $ */ #include "namespace.h" #include #include "un-namespace.h" +#include "local.h" #include "libc_private.h" +#undef putchar #undef putchar_unlocked /* - * putchar has traditionally been a macro in . That is no - * longer true because POSIX requires it to be thread-safe. POSIX - * does define putchar_unlocked() which is defined as a macro and is - * probably what you want to use instead. - */ - -/* - * A subroutine version of the macros putchar and putchar_unlocked. + * A subroutine version of the macro putchar */ int putchar(int c) { - return(putc(c, stdout)); + int retval; + FILE *so = stdout; + + FLOCKFILE(so); + retval = __sputc(c, so); + FUNLOCKFILE(so); + return (retval); } int -putchar_unlocked(int c) +putchar_unlocked(int ch) { - return(putc_unlocked(c, stdout)); + + return (__sputc(ch, stdout)); } diff --git a/lib/libc/stdio/puts.c b/lib/libc/stdio/puts.c index dc93ae8503..383db881b3 100644 --- a/lib/libc/stdio/puts.c +++ b/lib/libc/stdio/puts.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,23 +30,23 @@ * SUCH DAMAGE. * * @(#)puts.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/puts.c,v 1.7 1999/08/28 00:01:12 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/puts.c,v 1.11 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/puts.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ #include "namespace.h" -#include #include #include #include "un-namespace.h" #include "priv_stdio.h" #include "libc_private.h" +#include "local.h" /* * Write the given string to stdout, appending a newline. */ int -puts(char const *s) +puts(const char *s) { int retval; size_t c = strlen(s); @@ -65,6 +61,7 @@ puts(char const *s) uio.uio_iov = &iov[0]; uio.uio_iovcnt = 2; FLOCKFILE(stdout); + ORIENT(stdout, -1); retval = __sfvwrite(stdout, &uio) ? EOF : '\n'; FUNLOCKFILE(stdout); return (retval); diff --git a/lib/libc/stdio/putw.c b/lib/libc/stdio/putw.c index 9d4c29df2b..6ae63d3cb2 100644 --- a/lib/libc/stdio/putw.c +++ b/lib/libc/stdio/putw.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)putw.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/putw.c,v 1.7 1999/08/28 00:01:13 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/putw.c,v 1.10 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/putw.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ diff --git a/lib/libc/stdio/putwc.3 b/lib/libc/stdio/putwc.3 index 94e9e6f55c..94b2d6cb34 100644 --- a/lib/libc/stdio/putwc.3 +++ b/lib/libc/stdio/putwc.3 @@ -1,5 +1,4 @@ -.\" $NetBSD: putwc.3,v 1.8 2004/01/24 16:59:30 wiz Exp $ -.\" $DragonFly: src/lib/libc/stdio/putwc.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ +.\" $NetBSD: putwc.3,v 1.2 2002/02/07 07:00:26 ross Exp $ .\" .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -16,7 +15,7 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. Neither the name of the University nor the names of its contributors +.\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. .\" @@ -33,15 +32,17 @@ .\" SUCH DAMAGE. .\" .\" @(#)putc.3 8.1 (Berkeley) 6/4/93 +.\" $FreeBSD: src/lib/libc/stdio/putwc.3,v 1.8 2007/01/09 00:28:07 imp Exp $ +.\" $DragonFly: src/lib/libc/stdio/putwc.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ .\" -.Dd October 20, 2001 +.Dd March 3, 2004 .Dt PUTWC 3 .Os .Sh NAME .Nm fputwc , .Nm putwc , -.Nm putwchar , -.Nd output a wide-character to a stream +.Nm putwchar +.Nd output a wide character to a stream .Sh LIBRARY .Lb libc .Sh SYNOPSIS @@ -57,33 +58,32 @@ The .Fn fputwc function -writes the wide-character +writes the wide character .Fa wc to the output stream pointed to by .Fa stream . .Pp +The .Fn putwc +function acts essentially identically to -.Fn fputwc , -but is a macro that expands in-line. -It may evaluate -.Fa stream -more than once, so arguments given to -.Fn putwc -should not be expressions with potential side effects. +.Fn fputwc . .Pp +The .Fn putwchar +function is identical to .Fn putwc with an output stream of -.Em stdout . +.Dv stdout . .Sh RETURN VALUES -The functions +The .Fn fputwc , .Fn putwc , and .Fn putwchar -return the wide-character written. +functions +return the wide character written. If an error occurs, the value .Dv WEOF is returned. @@ -91,12 +91,14 @@ is returned. .Xr ferror 3 , .Xr fopen 3 , .Xr getwc 3 , +.Xr putc 3 , .Xr stdio 3 .Sh STANDARDS -The functions +The .Fn fputwc , .Fn putwc , and -.Fn putwchar , +.Fn putwchar +functions conform to .St -isoC-99 . diff --git a/lib/libc/stdio/putwc.c b/lib/libc/stdio/putwc.c index 06e262c960..6c0aebf93d 100644 --- a/lib/libc/stdio/putwc.c +++ b/lib/libc/stdio/putwc.c @@ -1,8 +1,5 @@ -/* $NetBSD: putwc.c,v 1.4 2005/06/12 05:21:27 lukem Exp $ */ -/* $DragonFly: src/lib/libc/stdio/putwc.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c)2001 Citrus Project, + * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,20 +23,26 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Citrus$ + * $FreeBSD: src/lib/libc/stdio/putwc.c,v 1.3 2004/05/25 10:42:52 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/putwc.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ +#include "namespace.h" #include #include +#include "un-namespace.h" +#include "libc_private.h" +#include "local.h" -/* - * A subroutine version of the macro putwc. - */ #undef putwc +/* + * Synonym for fputwc(). The only difference is that putwc(), if it is a + * macro, may evaluate `fp' more than once. + */ wint_t putwc(wchar_t wc, FILE *fp) { - return fputwc(wc, fp); + return (fputwc(wc, fp)); } diff --git a/lib/libc/stdio/putwchar.c b/lib/libc/stdio/putwchar.c index 6f2f2d40f8..038a14eb81 100644 --- a/lib/libc/stdio/putwchar.c +++ b/lib/libc/stdio/putwchar.c @@ -1,8 +1,5 @@ -/* $NetBSD: putwchar.c,v 1.4 2005/06/12 05:21:27 lukem Exp $ */ -/* $DragonFly: src/lib/libc/stdio/putwchar.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c)2001 Citrus Project, + * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,20 +23,25 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Citrus$ + * $FreeBSD: src/lib/libc/stdio/putwchar.c,v 1.3 2004/05/25 10:42:52 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/putwchar.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ +#include "namespace.h" #include #include +#include "un-namespace.h" +#include "libc_private.h" +#include "local.h" -/* - * A subroutine version of the macro putwchar. - */ #undef putwchar +/* + * Synonym for fputwc(wc, stdout). + */ wint_t putwchar(wchar_t wc) { - return fputwc(wc, stdout); + return (fputwc(wc, stdout)); } diff --git a/lib/libc/stdio/refill.c b/lib/libc/stdio/refill.c index 16b70debf0..da51bf5e2e 100644 --- a/lib/libc/stdio/refill.c +++ b/lib/libc/stdio/refill.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,26 +30,33 @@ * SUCH DAMAGE. * * @(#)refill.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/refill.c,v 1.8.2.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/refill.c,v 1.20 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/refill.c,v 1.10 2005/11/20 11:07:30 swildner Exp $ */ +#include "namespace.h" #include #include #include +#include "un-namespace.h" +#include "libc_private.h" #include "local.h" #include "priv_stdio.h" -static int lflush (FILE *); +static int lflush(FILE *); static int lflush(FILE *fp) { + int ret = 0; - if ((fp->pub._flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) - return (__sflush(fp)); - return (0); + if ((fp->pub._flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) { + FLOCKFILE(fp); + ret = __sflush(fp); + FUNLOCKFILE(fp); + } + return (ret); } /* @@ -68,6 +71,8 @@ __srefill(FILE *fp) if (!__sdidinit) __sinit(); + ORIENT(fp, -1); + fp->pub._r = 0; /* largely a convenience for callers */ /* SysV does not make this test; take it out for compatibility */ @@ -114,10 +119,18 @@ __srefill(FILE *fp) * flush all line buffered output files, per the ANSI C * standard. */ - if (fp->pub._flags & (__SLBF|__SNBF)) + if (fp->pub._flags & (__SLBF|__SNBF)) { + /* Ignore this file in _fwalk to avoid potential deadlock. */ + fp->pub._flags |= __SIGN; _fwalk(lflush); + fp->pub._flags &= ~__SIGN; + + /* Now flush this file without locking it. */ + if ((fp->pub._flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) + __sflush(fp); + } fp->pub._p = fp->_bf._base; - fp->pub._r = (*fp->_read)(fp->_cookie, (char *)fp->pub._p, fp->_bf._size); + fp->pub._r = _sread(fp, (char *)fp->pub._p, fp->_bf._size); fp->pub._flags &= ~__SMOD; /* buffer contents are again pristine */ if (fp->pub._r <= 0) { if (fp->pub._r == 0) diff --git a/lib/libc/stdio/remove.3 b/lib/libc/stdio/remove.3 index 0bd75ac31f..a08f5ad7a7 100644 --- a/lib/libc/stdio/remove.3 +++ b/lib/libc/stdio/remove.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)remove.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/remove.3,v 1.3.2.6 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/remove.3,v 1.10 2007/01/09 00:28:07 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/remove.3,v 1.2 2003/06/17 04:26:46 dillon Exp $ .\" .Dd June 4, 1993 diff --git a/lib/libc/stdio/remove.c b/lib/libc/stdio/remove.c index cd869669bd..b9bbce77f0 100644 --- a/lib/libc/stdio/remove.c +++ b/lib/libc/stdio/remove.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)remove.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/remove.c,v 1.6.2.1 2000/09/20 04:43:12 jkh Exp $ + * $FreeBSD: src/lib/libc/stdio/remove.c,v 1.9 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/remove.c,v 1.3 2004/06/07 20:35:41 hmp Exp $ */ diff --git a/lib/libc/stdio/rewind.c b/lib/libc/stdio/rewind.c index b81406f6df..cbb909d095 100644 --- a/lib/libc/stdio/rewind.c +++ b/lib/libc/stdio/rewind.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)rewind.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/rewind.c,v 1.7.2.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/rewind.c,v 1.12 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/rewind.c,v 1.4 2005/11/20 11:07:30 swildner Exp $ */ @@ -48,9 +44,16 @@ void rewind(FILE *fp) { + int serrno = errno; + + /* make sure stdio is set up */ + if (!__sdidinit) + __sinit(); + FLOCKFILE(fp); - _fseeko(fp, 0L, SEEK_SET); - clearerr(fp); + if (_fseeko(fp, (off_t)0, SEEK_SET, 1) == 0) { + clearerr_unlocked(fp); + errno = serrno; + } FUNLOCKFILE(fp); - errno = 0; /* not required, but seems reasonable */ } diff --git a/lib/libc/stdio/rget.c b/lib/libc/stdio/rget.c index 70d4035838..56fb777fd7 100644 --- a/lib/libc/stdio/rget.c +++ b/lib/libc/stdio/rget.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,12 +30,11 @@ * SUCH DAMAGE. * * @(#)rget.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/rget.c,v 1.2.8.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/rget.c,v 1.6 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/rget.c,v 1.3 2005/07/23 20:23:06 joerg Exp $ */ #include - #include "local.h" #include "priv_stdio.h" diff --git a/lib/libc/stdio/scanf.3 b/lib/libc/stdio/scanf.3 index 39cd6f1edd..52fc1fb26a 100644 --- a/lib/libc/stdio/scanf.3 +++ b/lib/libc/stdio/scanf.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)scanf.3 8.2 (Berkeley) 12/11/93 -.\" $FreeBSD: src/lib/libc/stdio/scanf.3,v 1.24 2003/06/28 09:03:25 das Exp $ +.\" $FreeBSD: src/lib/libc/stdio/scanf.3,v 1.25 2007/01/09 00:28:07 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/scanf.3,v 1.3 2006/08/26 10:27:55 swildner Exp $ .\" .Dd August 26, 2006 @@ -53,18 +49,18 @@ .Sh SYNOPSIS .In stdio.h .Ft int -.Fn scanf "const char *format" ... +.Fn scanf "const char * restrict format" ... .Ft int -.Fn fscanf "FILE *stream" "const char *format" ... +.Fn fscanf "FILE * restrict stream" "const char * restrict format" ... .Ft int -.Fn sscanf "const char *str" "const char *format" ... +.Fn sscanf "const char * restrict str" "const char * restrict format" ... .In stdarg.h .Ft int -.Fn vscanf "const char *format" "va_list ap" +.Fn vscanf "const char * restrict format" "va_list ap" .Ft int -.Fn vsscanf "const char *str" "const char *format" "va_list ap" +.Fn vsscanf "const char * restrict str" "const char * restrict format" "va_list ap" .Ft int -.Fn vfscanf "FILE *stream" "const char *format" "va_list ap" +.Fn vfscanf "FILE * restrict stream" "const char * restrict format" "va_list ap" .Sh DESCRIPTION The .Fn scanf @@ -173,7 +169,7 @@ and the next pointer is a pointer to a (rather than .Vt int ) , that the conversion will be one of -.Cm e , f , +.Cm a , e , f , or .Cm g and the next pointer is a pointer to @@ -200,7 +196,7 @@ and the next pointer is a pointer to a .Vt int ) . .It Cm L Indicates that the conversion will be one of -.Cm e , f , +.Cm a , e , f , or .Cm g and the next pointer is a pointer to @@ -308,7 +304,7 @@ the next pointer must be a pointer to Matches an optionally signed hexadecimal integer; the next pointer must be a pointer to .Vt "unsigned int" . -.It Cm e , E , f , F , g , G +.It Cm a , A , e , E , f , F , g , G Matches a floating-point number in the style of .Xr strtod 3 . The next pointer must be a pointer to diff --git a/lib/libc/stdio/scanf.c b/lib/libc/stdio/scanf.c index 9e0686e3f7..c05a2045ef 100644 --- a/lib/libc/stdio/scanf.c +++ b/lib/libc/stdio/scanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)scanf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/scanf.c,v 1.7 1999/08/28 00:01:15 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/scanf.c,v 1.13 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/scanf.c,v 1.4 2005/01/31 22:29:40 dillon Exp $ */ @@ -43,9 +39,10 @@ #include #include "un-namespace.h" #include "libc_private.h" +#include "local.h" int -scanf(char const *fmt, ...) +scanf(const char * __restrict fmt, ...) { int ret; va_list ap; diff --git a/lib/libc/stdio/setbuf.3 b/lib/libc/stdio/setbuf.3 index 3934824acb..5f43b83024 100644 --- a/lib/libc/stdio/setbuf.3 +++ b/lib/libc/stdio/setbuf.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)setbuf.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/setbuf.3,v 1.5.2.5 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/setbuf.3,v 1.17 2007/01/09 00:28:07 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/setbuf.3,v 1.2 2003/06/17 04:26:46 dillon Exp $ .\" .Dd June 4, 1993 @@ -51,13 +47,13 @@ .Sh SYNOPSIS .In stdio.h .Ft void -.Fn setbuf "FILE *stream" "char *buf" +.Fn setbuf "FILE * restrict stream" "char * restrict buf" .Ft void .Fn setbuffer "FILE *stream" "char *buf" "int size" .Ft int .Fn setlinebuf "FILE *stream" .Ft int -.Fn setvbuf "FILE *stream" "char *buf" "int mode" "size_t size" +.Fn setvbuf "FILE * restrict stream" "char * restrict buf" "int mode" "size_t size" .Sh DESCRIPTION The three types of buffering available are unbuffered, block buffered, and line buffered. @@ -66,7 +62,8 @@ destination file or terminal as soon as written; when it is block buffered many characters are saved up and written as a block; when it is line buffered characters are saved up until a newline is output or input is read from any stream attached to a terminal device -(typically stdin). +(typically +.Dv stdin ) . The function .Xr fflush 3 may be used to force the block out early. @@ -82,10 +79,10 @@ is called, and an optimally-sized buffer is obtained. If a stream refers to a terminal (as -.Em stdout +.Dv stdout normally does) it is line buffered. The standard error stream -.Em stderr +.Dv stderr is always unbuffered. .Pp The @@ -94,7 +91,7 @@ function may be used to alter the buffering behavior of a stream. The .Fa mode -parameter must be one of the following three macros: +argument must be one of the following three macros: .Bl -tag -width _IOFBF -offset indent .It Dv _IONBF unbuffered @@ -106,7 +103,7 @@ fully buffered .Pp The .Fa size -parameter may be given as zero +argument may be given as zero to obtain deferred optimal-size buffer allocation as usual. If it is not zero, then except for unbuffered files, the @@ -115,6 +112,13 @@ argument should point to a buffer at least .Fa size bytes long; this buffer will be used instead of the current buffer. +If +.Fa buf +is not +.Dv NULL , +it is the caller's responsibility to +.Xr free 3 +this buffer after closing the stream. (If the .Fa size argument diff --git a/lib/libc/stdio/setbuf.c b/lib/libc/stdio/setbuf.c index e4b0c32fea..c78b28fbd9 100644 --- a/lib/libc/stdio/setbuf.c +++ b/lib/libc/stdio/setbuf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,6 +30,7 @@ * SUCH DAMAGE. * * @(#)setbuf.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/setbuf.c,v 1.5 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/setbuf.c,v 1.4 2005/11/20 11:07:30 swildner Exp $ */ @@ -41,7 +38,7 @@ #include "local.h" void -setbuf(FILE *fp, char *buf) +setbuf(FILE * __restrict fp, char * __restrict buf) { setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ); } diff --git a/lib/libc/stdio/setbuffer.c b/lib/libc/stdio/setbuffer.c index 9c4bb487fc..9b4fba32c8 100644 --- a/lib/libc/stdio/setbuffer.c +++ b/lib/libc/stdio/setbuffer.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)setbuffer.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/setbuffer.c,v 1.5 1999/08/28 00:01:15 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/setbuffer.c,v 1.8 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/setbuffer.c,v 1.5 2005/11/20 11:07:30 swildner Exp $ */ diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c index bb0a7bdb80..57c63bdc2e 100644 --- a/lib/libc/stdio/setvbuf.c +++ b/lib/libc/stdio/setvbuf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)setvbuf.c 8.2 (Berkeley) 11/16/93 - * $FreeBSD: src/lib/libc/stdio/setvbuf.c,v 1.7 1999/08/28 00:01:16 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/setvbuf.c,v 1.14 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/setvbuf.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ @@ -42,7 +38,6 @@ #include #include #include "un-namespace.h" - #include "local.h" #include "libc_private.h" #include "priv_stdio.h" @@ -52,7 +47,7 @@ * a buffer. */ int -setvbuf(FILE *fp, char *buf, int mode, size_t size) +setvbuf(FILE * __restrict fp, char * __restrict buf, int mode, size_t size) { int ret, flags; size_t iosize; @@ -82,7 +77,7 @@ setvbuf(FILE *fp, char *buf, int mode, size_t size) flags = fp->pub._flags; if (flags & __SMBF) free((void *)fp->_bf._base); - flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT | __SEOF); + flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SOFF | __SNPT | __SEOF); /* If setting unbuffered mode, skip all the hard work. */ if (mode == _IONBF) diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c index 3139b68708..835c088a4d 100644 --- a/lib/libc/stdio/snprintf.c +++ b/lib/libc/stdio/snprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)snprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/snprintf.c,v 1.12 1999/08/28 00:01:16 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/snprintf.c,v 1.22 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/snprintf.c,v 1.7 2006/03/02 18:05:30 joerg Exp $ */ @@ -46,7 +42,7 @@ #include "priv_stdio.h" int -snprintf(char *str, size_t n, char const *fmt, ...) +snprintf(char * __restrict str, size_t n, const char * __restrict fmt, ...) { size_t on; int ret; @@ -63,12 +59,8 @@ snprintf(char *str, size_t n, char const *fmt, ...) f.pub._flags = __SWR | __SSTR; f._bf._base = f.pub._p = (unsigned char *)str; f._bf._size = f.pub._w = n; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); - ret = __vfprintf(&f, fmt, ap); /* Use unlocked __vfprintf */ + ret = __vfprintf(&f, fmt, ap); if (on > 0) *f.pub._p = '\0'; va_end(ap); diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c index d5c350e276..43038e956b 100644 --- a/lib/libc/stdio/sprintf.c +++ b/lib/libc/stdio/sprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,19 +30,18 @@ * SUCH DAMAGE. * * @(#)sprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/sprintf.c,v 1.6 1999/08/28 00:01:17 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/sprintf.c,v 1.16 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/sprintf.c,v 1.7 2006/03/02 18:05:30 joerg Exp $ */ #include #include #include - #include "local.h" #include "priv_stdio.h" int -sprintf(char *str, char const *fmt, ...) +sprintf(char * __restrict str, const char * __restrict fmt, ...) { int ret; va_list ap; @@ -56,13 +51,9 @@ sprintf(char *str, char const *fmt, ...) f.pub._flags = __SWR | __SSTR; f._bf._base = f.pub._p = (unsigned char *)str; f._bf._size = f.pub._w = INT_MAX; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); va_start(ap, fmt); - ret = __vfprintf(&f, fmt, ap); /* Use unlocked __vfprintf */ + ret = __vfprintf(&f, fmt, ap); va_end(ap); *f.pub._p = 0; return (ret); diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c index c531b12944..3aa4cfc2b9 100644 --- a/lib/libc/stdio/sscanf.c +++ b/lib/libc/stdio/sscanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,18 +30,17 @@ * SUCH DAMAGE. * * @(#)sscanf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/sscanf.c,v 1.6 1999/08/28 00:01:17 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/sscanf.c,v 1.13 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/sscanf.c,v 1.9 2006/03/02 18:05:30 joerg Exp $ */ #include #include #include - #include "local.h" #include "priv_stdio.h" -static int eofread (void *, char *, int); +static int eofread(void *, char *, int); /* ARGSUSED */ static int @@ -56,7 +51,7 @@ eofread(void *cookie __unused, char *buf __unused, int len __unused) } int -sscanf(const char *str, char const *fmt, ...) +sscanf(const char * __restrict str, const char * __restrict fmt, ...) { int ret; va_list ap; @@ -69,10 +64,6 @@ sscanf(const char *str, char const *fmt, ...) f._read = eofread; f._ub._base = NULL; f._lb._base = NULL; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); va_start(ap, fmt); ret = __svfscanf(&f, fmt, ap); diff --git a/lib/libc/stdio/stdio.3 b/lib/libc/stdio/stdio.3 index 51e2ad168f..c7f7ff1723 100644 --- a/lib/libc/stdio/stdio.3 +++ b/lib/libc/stdio/stdio.3 @@ -9,10 +9,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -30,10 +26,10 @@ .\" SUCH DAMAGE. .\" .\" @(#)stdio.3 8.7 (Berkeley) 4/19/94 -.\" $FreeBSD: src/lib/libc/stdio/stdio.3,v 1.10.2.8 2003/02/19 05:12:44 gshapiro Exp $ +.\" $FreeBSD: src/lib/libc/stdio/stdio.3,v 1.30 2009/03/04 03:38:51 das Exp $ .\" $DragonFly: src/lib/libc/stdio/stdio.3,v 1.3 2006/02/17 19:35:06 swildner Exp $ .\" -.Dd April 19, 1994 +.Dd March 3, 2009 .Dt STDIO 3 .Os .Sh NAME @@ -93,15 +89,19 @@ object is indeterminate (garbage) after a file is closed. .Pp A file may be subsequently reopened, by the same or another program execution, and its contents reclaimed or modified (if it can be repositioned -at the start). If the main function returns to its original caller, or +at the start). +If the main function returns to its original caller, or the .Xr exit 3 function is called, all open files are closed (hence all output -streams are flushed) before program termination. Other methods +streams are flushed) before program termination. +Other methods of program termination may not close files properly and hence -buffered output may be lost. In particular, +buffered output may be lost. +In particular, .Xr _exit 2 -does not flush stdio files. Neither does an exit due to a signal. +does not flush stdio files. +Neither does an exit due to a signal. Buffers are flushed by .Xr abort 3 as required by POSIX, although previous implementations did not. @@ -128,9 +128,9 @@ opened explicitly: (for writing diagnostic output). .El These streams are abbreviated -.Em stdin , stdout +.Dv stdin , stdout and -.Em stderr . +.Dv stderr . Initially, the standard error stream is unbuffered; the standard input and output streams are fully buffered if and only if the streams do not refer to @@ -173,13 +173,13 @@ looks like and which external variables are of interest. The following are defined as macros; these names may not be re-used without first removing their current definitions with -.Dv #undef : +.Ic #undef : .Dv BUFSIZ , .Dv EOF , .Dv FILENAME_MAX , .Dv FOPEN_MAX , -.Dv L_cuserid , .Dv L_ctermid , +.Dv L_cuserid , .Dv L_tmpnam , .Dv NULL , .Dv P_tmpdir , @@ -188,29 +188,45 @@ without first removing their current definitions with .Dv SEEK_SET , .Dv TMP_MAX , .Dv clearerr , +.Dv clearerr_unlocked , .Dv feof , +.Dv feof_unlocked , .Dv ferror , +.Dv ferror_unlocked , .Dv fileno , +.Dv fileno_unlocked , .Dv fropen , .Dv fwopen , .Dv getc , +.Dv getc_unlocked , .Dv getchar , +.Dv getchar_unlocked , .Dv putc , +.Dv putc_unlocked , .Dv putchar , +.Dv putchar_unlocked , .Dv stderr , -.Dv stdin , -.Dv stdout , -.Dv vfscanf . +.Dv stdin +and +.Dv stdout . Function versions of the macro functions -.Fn clearerr , -.Fn feof , -.Fn ferror , -.Fn fileno , -.Fn getc , -.Fn getchar , -.Fn putc , +.Dv clearerr , +.Dv clearerr_unlocked , +.Dv feof , +.Dv feof_unlocked , +.Dv ferror , +.Dv ferror_unlocked , +.Dv fileno , +.Dv fileno_unlocked , +.Dv getc , +.Dv getc_unlocked , +.Dv getchar , +.Dv getchar_unlocked , +.Dv putc , +.Dv putc_unlocked , +.Dv putchar , and -.Fn putchar +.Dv putchar_unlocked exist and will be used if the macro definitions are explicitly removed. .Sh SEE ALSO @@ -222,12 +238,13 @@ definitions are explicitly removed. The .Nm library conforms to -.St -isoC . +.St -isoC-99 . .Sh LIST OF FUNCTIONS .Bl -column "Description" .It Sy "Function Description" .It "asprintf formatted output conversion" .It "clearerr check and reset stream status" +.It "dprintf formatted output conversion" .It "fclose close a stream" .It "fdopen stream open functions" .It "feof check and reset stream status" @@ -237,12 +254,16 @@ library conforms to .It "fgetln get a line from a stream" .It "fgetpos reposition a stream" .It "fgets get a line from a stream" +.It "fgetwc get next wide character from input stream" +.It "fgetws get a line of wide characters from a stream" .It "fileno check and reset stream status" .It "fopen stream open functions" .It "fprintf formatted output conversion" .It "fpurge flush a stream" .It "fputc output a character or word to a stream" .It "fputs output a line to a stream" +.It "fputwc output a wide character to a stream" +.It "fputws output a line of wide characters to a stream" .It "fread binary stream input/output" .It "freopen stream open functions" .It "fropen open a stream" @@ -251,12 +272,18 @@ library conforms to .It "fsetpos reposition a stream" .It "ftell reposition a stream" .It "funopen open a stream" +.It "fwide set/get orientation of stream" .It "fwopen open a stream" +.It "fwprintf formatted wide character output conversion" .It "fwrite binary stream input/output" .It "getc get next character or word from input stream" .It "getchar get next character or word from input stream" +.It "getdelim get a line from a stream" +.It "getline get a line from a stream" .It "gets get a line from a stream" .It "getw get next character or word from input stream" +.It "getwc get next wide character from input stream" +.It "getwchar get next wide character from input stream" .It "mkdtemp create unique temporary directory" .It "mkstemp create unique temporary file" .It "mktemp create unique temporary file" @@ -266,6 +293,8 @@ library conforms to .It "putchar output a character or word to a stream" .It "puts output a line to a stream" .It "putw output a character or word to a stream" +.It "putwc output a wide character to a stream" +.It "putwchar output a wide character to a stream" .It "remove remove directory entry" .It "rewind reposition a stream" .It "scanf input format conversion" @@ -277,20 +306,27 @@ library conforms to .It "sprintf formatted output conversion" .It "sscanf input format conversion" .It "strerror system error messages" +.It "swprintf formatted wide character output conversion" .It "sys_errlist system error messages" .It "sys_nerr system error messages" .It "tempnam temporary file routines" .It "tmpfile temporary file routines" .It "tmpnam temporary file routines" .It "ungetc un-get character from input stream" +.It "ungetwc un-get wide character from input stream" .It "vasprintf formatted output conversion" +.It "vdprintf formatted output conversion" .It "vfprintf formatted output conversion" .It "vfscanf input format conversion" +.It "vfwprintf formatted wide character output conversion" .It "vprintf formatted output conversion" .It "vscanf input format conversion" .It "vsnprintf formatted output conversion" .It "vsprintf formatted output conversion" .It "vsscanf input format conversion" +.It "vswprintf formatted wide character output conversion" +.It "vwprintf formatted wide character output conversion" +.It "wprintf formatted wide character output conversion" .El .Sh BUGS The standard buffered functions do not interact well with certain other diff --git a/lib/libc/stdio/stdio.c b/lib/libc/stdio/stdio.c index 2b4545828c..4f40b0421a 100644 --- a/lib/libc/stdio/stdio.c +++ b/lib/libc/stdio/stdio.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,46 +30,37 @@ * SUCH DAMAGE. * * @(#)stdio.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/stdio.c,v 1.9 2000/01/27 23:06:46 jasone Exp $ + * $FreeBSD: src/lib/libc/stdio/stdio.c,v 1.28 2008/05/05 16:14:02 jhb Exp $ * $DragonFly: src/lib/libc/stdio/stdio.c,v 1.7 2005/11/20 11:07:30 swildner Exp $ */ #include "namespace.h" +#include #include -#include +#include #include +#include +#include #include "un-namespace.h" - #include "local.h" #include "priv_stdio.h" /* * Small standard I/O/seek/close functions. - * These maintain the `known seek offset' for seek optimisation. */ int __sread(void *cookie, char *buf, int n) { FILE *fp = cookie; - int ret; - ret = _read(fp->pub._fileno, buf, (size_t)n); - /* if the read succeeded, update the current offset */ - if (ret >= 0) - fp->_offset += ret; - else - fp->pub._flags &= ~__SOFF; /* paranoia */ - return (ret); + return(_read(fp->pub._fileno, buf, (size_t)n)); } int -__swrite(void *cookie, char const *buf, int n) +__swrite(void *cookie, const char *buf, int n) { FILE *fp = cookie; - if (fp->pub._flags & __SAPP) - lseek(fp->pub._fileno, (off_t)0, SEEK_END); - fp->pub._flags &= ~__SOFF; /* in case FAPPEND mode is set */ return (_write(fp->pub._fileno, buf, (size_t)n)); } @@ -81,16 +68,8 @@ fpos_t __sseek(void *cookie, fpos_t offset, int whence) { FILE *fp = cookie; - off_t ret; - ret = lseek(fp->pub._fileno, (off_t)offset, whence); - if (ret == -1) - fp->pub._flags &= ~__SOFF; - else { - fp->pub._flags |= __SOFF; - fp->_offset = ret; - } - return (ret); + return (lseek(fp->pub._fileno, (off_t)offset, whence)); } int @@ -99,3 +78,90 @@ __sclose(void *cookie) return (_close(((FILE *)cookie)->pub._fileno)); } + +/* + * Higher level wrappers. + */ +int +_sread(FILE *fp, char *buf, int n) +{ + int ret; + + ret = (*fp->_read)(fp->_cookie, buf, n); + if (ret > 0) { + if (fp->pub._flags & __SOFF) { + if (fp->_offset <= OFF_MAX - ret) + fp->_offset += ret; + else + fp->pub._flags &= ~__SOFF; + } + } else if (ret < 0) + fp->pub._flags &= ~__SOFF; + return (ret); +} + +int +_swrite(FILE *fp, const char *buf, int n) +{ + int ret; + int serrno; + + if (fp->pub._flags & __SAPP) { + serrno = errno; + if (_sseek(fp, (fpos_t)0, SEEK_END) == -1 && + (fp->pub._flags & __SOPT)) + return (-1); + errno = serrno; + } + ret = (*fp->_write)(fp->_cookie, buf, n); + /* __SOFF removed even on success in case O_APPEND mode is set. */ + if (ret >= 0) { + if ((fp->pub._flags & (__SAPP|__SOFF)) == (__SAPP|__SOFF) && + fp->_offset <= OFF_MAX - ret) + fp->_offset += ret; + else + fp->pub._flags &= ~__SOFF; + + } else if (ret < 0) + fp->pub._flags &= ~__SOFF; + return (ret); +} + +fpos_t +_sseek(FILE *fp, fpos_t offset, int whence) +{ + fpos_t ret; + int serrno, errret; + + serrno = errno; + errno = 0; + ret = (*fp->_seek)(fp->_cookie, offset, whence); + errret = errno; + if (errno == 0) + errno = serrno; + /* + * Disallow negative seeks per POSIX. + * It is needed here to help upper level caller + * in the cases it can't detect. + */ + if (ret < 0) { + if (errret == 0) { + if (offset != 0 || whence != SEEK_CUR) { + if (HASUB(fp)) + FREEUB(fp); + fp->pub._p = fp->_bf._base; + fp->pub._r = 0; + fp->pub._flags &= ~__SEOF; + } + fp->pub._flags |= __SERR; + errno = EINVAL; + } else if (errret == ESPIPE) + fp->pub._flags &= ~__SAPP; + fp->pub._flags &= ~__SOFF; + ret = -1; + } else if (fp->pub._flags & __SOPT) { + fp->pub._flags |= __SOFF; + fp->_offset = ret; + } + return (ret); +} diff --git a/lib/libc/stdio/swprintf.c b/lib/libc/stdio/swprintf.c index 3bd844cc26..5de2ff2bc5 100644 --- a/lib/libc/stdio/swprintf.c +++ b/lib/libc/stdio/swprintf.c @@ -1,6 +1,3 @@ -/* $NetBSD: swprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/swprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/swprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/swprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c index be8d5c47dc..ec911d0449 100644 --- a/lib/libc/stdio/swscanf.c +++ b/lib/libc/stdio/swscanf.c @@ -1,6 +1,3 @@ -/* $NetBSD: swscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/swscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/swscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/swscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/tempnam.c b/lib/libc/stdio/tempnam.c index a30d62a180..32365da5e7 100644 --- a/lib/libc/stdio/tempnam.c +++ b/lib/libc/stdio/tempnam.c @@ -10,10 +10,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -31,7 +27,7 @@ * SUCH DAMAGE. * * @(#)tempnam.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/tempnam.c,v 1.8 1999/10/24 11:57:24 ache Exp $ + * $FreeBSD: src/lib/libc/stdio/tempnam.c,v 1.11 2007/01/09 00:28:07 imp Exp $ * $DragonFly: src/lib/libc/stdio/tempnam.c,v 1.5 2005/11/20 11:07:30 swildner Exp $ */ @@ -46,7 +42,7 @@ __warn_references(tempnam, "warning: tempnam() possibly used unsafely; consider using mkstemp()"); -extern char *_mktemp (char *); +extern char *_mktemp(char *); char * tempnam(const char *dir, const char *pfx) diff --git a/lib/libc/stdio/tmpfile.c b/lib/libc/stdio/tmpfile.c index cc87e75a12..b721609217 100644 --- a/lib/libc/stdio/tmpfile.c +++ b/lib/libc/stdio/tmpfile.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,10 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/tmpfile.c,v 1.4.2.2 2003/02/15 05:34:52 kris Exp $ - * $DragonFly: src/lib/libc/stdio/tmpfile.c,v 1.4 2005/11/20 11:07:30 swildner Exp $ - * * @(#)tmpfile.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/tmpfile.c,v 1.10 2007/01/09 00:28:07 imp Exp $ + * $DragonFly: src/lib/libc/stdio/tmpfile.c,v 1.4 2005/11/20 11:07:30 swildner Exp $ */ #include "namespace.h" diff --git a/lib/libc/stdio/tmpnam.3 b/lib/libc/stdio/tmpnam.3 index 242e6806e9..683a8c821a 100644 --- a/lib/libc/stdio/tmpnam.3 +++ b/lib/libc/stdio/tmpnam.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,10 +30,10 @@ .\" SUCH DAMAGE. .\" .\" @(#)tmpnam.3 8.2 (Berkeley) 11/17/93 -.\" $FreeBSD: src/lib/libc/stdio/tmpnam.3,v 1.5.2.5 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/tmpnam.3,v 1.20 2007/03/16 21:46:24 maxim Exp $ .\" $DragonFly: src/lib/libc/stdio/tmpnam.3,v 1.4 2008/09/24 19:48:40 swildner Exp $ .\" -.Dd November 17, 1993 +.Dd March 18, 2007 .Dt TMPFILE 3 .Os .Sh NAME @@ -133,7 +129,9 @@ if .Pf non- Dv NULL , is used to specify a file name prefix, which will be the first part of the created file name. -.Fn Tempnam +The +.Fn tempnam +function allocates memory in which to store the file name; the returned pointer may be used as a subsequent argument to .Xr free 3 . @@ -149,12 +147,49 @@ on error. The .Fn tmpnam and -.Fn tempnam +.Fn tempfile functions return a pointer to a file name on success, and a .Dv NULL pointer on error. +.Sh ENVIRONMENT +.Bl -tag -width Ds +.It Ev TMPDIR +.Pf [ Fn tempnam +only] +If set, +the directory in which the temporary file is stored. +.Ev TMPDIR +is ignored for processes +for which +.Xr issetugid 2 +is true. +.El +.Sh COMPATIBILITY +These interfaces are provided from System V and +.Tn ANSI +compatibility only. +.Pp +Most historic implementations of these functions provide +only a limited number of possible temporary file names +(usually 26) +before file names will start being recycled. +System V implementations of these functions +(and of +.Xr mktemp 3 ) +use the +.Xr access 2 +system call to determine whether or not the temporary file +may be created. +This has obvious ramifications for setuid or setgid programs, +complicating the portable use of these interfaces in such programs. +.Pp +The +.Fn tmpfile +interface should not be used in software expected to be used on other systems +if there is any possibility that the user does not wish the temporary file to +be publicly readable and writable. .Sh ERRORS The .Fn tmpfile @@ -183,6 +218,22 @@ for any of the errors specified for the library functions .Xr malloc 3 or .Xr mktemp 3 . +.Sh SECURITY CONSIDERATIONS +The +.Fn tmpnam +and +.Fn tempnam +functions are susceptible to a race condition +occurring between the selection of the file name +and the creation of the file, +which allows malicious users +to potentially overwrite arbitrary files in the system, +depending on the level of privilege of the running program. +Additionally, there is no means by which +file permissions may be specified. +It is strongly suggested that +.Xr mkstemp 3 +be used in place of these functions. .Sh SEE ALSO .Xr mkstemp 3 , .Xr mktemp 3 @@ -194,37 +245,3 @@ and functions conform to .St -isoC . -.Sh BUGS -These interfaces are provided for System V and -.Tn ANSI -compatibility only. -The -.Xr mkstemp 3 -interface is strongly preferred. -.Pp -There are four important problems with these interfaces (as well as -with the historic -.Xr mktemp 3 -interface). -First, there is an obvious race between file name selection and file -creation and deletion. -Second, most historic implementations provide only a limited number -of possible temporary file names (usually 26) before file names will -start being recycled. -Third, the System V implementations of these functions (and of -.Xr mktemp 3 ) -use the -.Xr access 2 -function to determine whether or not the temporary file may be created. -This has obvious ramifications for setuid or setgid programs, complicating -the portable use of these interfaces in such programs. -Finally, there is no specification of the permissions with which the -temporary files are created. -.Pp -This implementation does not have these flaws, but portable software -cannot depend on that. -In particular, the -.Fn tmpfile -interface should not be used in software expected to be used on other systems -if there is any possibility that the user does not wish the temporary file to -be publicly readable and writable. diff --git a/lib/libc/stdio/tmpnam.c b/lib/libc/stdio/tmpnam.c index 40ca8deebf..73f563c028 100644 --- a/lib/libc/stdio/tmpnam.c +++ b/lib/libc/stdio/tmpnam.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,10 +29,9 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/tmpnam.c,v 1.3 1999/10/24 11:57:24 ache Exp $ - * $DragonFly: src/lib/libc/stdio/tmpnam.c,v 1.5 2005/11/20 11:07:30 swildner Exp $ - * * @(#)tmpnam.c 8.3 (Berkeley) 3/28/94 + * $FreeBSD: src/lib/libc/stdio/tmpnam.c,v 1.6 2007/01/09 00:28:07 imp Exp $ + * $DragonFly: src/lib/libc/stdio/tmpnam.c,v 1.5 2005/11/20 11:07:30 swildner Exp $ */ #include @@ -47,7 +42,7 @@ __warn_references(tmpnam, "warning: tmpnam() possibly used unsafely; consider using mkstemp()"); -extern char *_mktemp (char *); +extern char *_mktemp(char *); char * tmpnam(char *s) diff --git a/lib/libc/stdio/ungetc.3 b/lib/libc/stdio/ungetc.3 index 1d06a39aa2..3b88221814 100644 --- a/lib/libc/stdio/ungetc.3 +++ b/lib/libc/stdio/ungetc.3 @@ -13,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -34,7 +30,7 @@ .\" SUCH DAMAGE. .\" .\" @(#)ungetc.3 8.1 (Berkeley) 6/4/93 -.\" $FreeBSD: src/lib/libc/stdio/ungetc.3,v 1.4.2.5 2001/12/14 18:33:57 ru Exp $ +.\" $FreeBSD: src/lib/libc/stdio/ungetc.3,v 1.14 2007/01/09 00:28:07 imp Exp $ .\" $DragonFly: src/lib/libc/stdio/ungetc.3,v 1.2 2003/06/17 04:26:46 dillon Exp $ .\" .Dd June 4, 1993 @@ -74,6 +70,11 @@ an effectively infinite amount of pushback is allowed. .Pp If a character is successfully pushed-back, the end-of-file indicator for the stream is cleared. +The file-position indicator is decremented +by each successful call to +.Fn ungetc ; +if its value was 0 before a call, its value is unspecified after +the call. .Sh RETURN VALUES The .Fn ungetc @@ -89,7 +90,8 @@ the operation will fail and the stream will remain unchanged. .Sh SEE ALSO .Xr fseek 3 , .Xr getc 3 , -.Xr setvbuf 3 +.Xr setvbuf 3 , +.Xr ungetwc 3 .Sh STANDARDS The .Fn ungetc diff --git a/lib/libc/stdio/ungetc.c b/lib/libc/stdio/ungetc.c index f455705d3b..f80d9b945d 100644 --- a/lib/libc/stdio/ungetc.c +++ b/lib/libc/stdio/ungetc.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)ungetc.c 8.2 (Berkeley) 11/3/93 - * $FreeBSD: src/lib/libc/stdio/ungetc.c,v 1.7.2.1 2001/03/05 11:27:49 obrien Exp $ + * $FreeBSD: src/lib/libc/stdio/ungetc.c,v 1.18 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/ungetc.c,v 1.8 2005/11/20 11:07:30 swildner Exp $ */ @@ -43,15 +39,14 @@ #include #include #include "un-namespace.h" - #include "local.h" #include "libc_private.h" #include "priv_stdio.h" -static int __submore (FILE *); +static int __submore(FILE *); /* - * Expand the ungetc buffer `in place'. That is, adjust fp->_p when + * Expand the ungetc buffer `in place'. That is, adjust fp->pub._p when * the buffer moves, so that it points the same distance from the end, * and move the bytes in the buffer around as necessary so that they * are all at the end (stack-style). @@ -96,14 +91,13 @@ ungetc(int c, FILE *fp) { int ret; - if (c == EOF) - return (EOF); if (!__sdidinit) __sinit(); FLOCKFILE(fp); + ORIENT(fp, -1); ret = __ungetc(c, fp); FUNLOCKFILE(fp); - return(ret); + return (ret); } /* @@ -113,19 +107,17 @@ int __ungetc(int c, FILE *fp) { if (c == EOF) - return(EOF); + return (EOF); if ((fp->pub._flags & __SRD) == 0) { /* * Not already reading: no good unless reading-and-writing. * Otherwise, flush any current write stuff. */ - if ((fp->pub._flags & __SRW) == 0) { + if ((fp->pub._flags & __SRW) == 0) return (EOF); - } if (fp->pub._flags & __SWR) { - if (__sflush(fp)) { + if (__sflush(fp)) return (EOF); - } fp->pub._flags &= ~__SWR; fp->pub._w = 0; fp->pub._lbfsize = 0; @@ -139,9 +131,8 @@ __ungetc(int c, FILE *fp) * This may require expanding the current ungetc buffer. */ if (HASUB(fp)) { - if (fp->pub._r >= fp->_ub._size && __submore(fp)) { + if (fp->pub._r >= fp->_ub._size && __submore(fp)) return (EOF); - } *--fp->pub._p = c; fp->pub._r++; return (c); diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c index 06c77be675..4b1772cad7 100644 --- a/lib/libc/stdio/vasprintf.c +++ b/lib/libc/stdio/vasprintf.c @@ -26,20 +26,18 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.11 1999/08/28 00:01:19 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.19 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/vasprintf.c,v 1.8 2006/03/02 18:05:30 joerg Exp $ */ #include #include -#include #include - #include "local.h" #include "priv_stdio.h" int -vasprintf(char **str, const char *fmt, va_list ap) +vasprintf(char **str, const char *fmt, __va_list ap) { int ret; FILE f; @@ -52,19 +50,16 @@ vasprintf(char **str, const char *fmt, va_list ap) errno = ENOMEM; return (-1); } - f._bf._size = f.pub._w = 127; /* Leave room for the NULL */ - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; + f._bf._size = f.pub._w = 127; /* Leave room for the NUL */ memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); ret = __vfprintf(&f, fmt, ap); - *f.pub._p = '\0'; - f._bf._base = reallocf(f._bf._base, f._bf._size + 1); - if (f._bf._base == NULL) { + if (ret < 0) { + free(f._bf._base); + *str = NULL; errno = ENOMEM; - ret = -1; + return (-1); } + *f.pub._p = '\0'; *str = (char *)f._bf._base; return (ret); } diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/vdprintf.c similarity index 65% copy from lib/libc/stdio/fwscanf.c copy to lib/libc/stdio/vdprintf.c index 71f4244548..18c5495d11 100644 --- a/lib/libc/stdio/fwscanf.c +++ b/lib/libc/stdio/vdprintf.c @@ -1,8 +1,5 @@ -/* $NetBSD: fwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/fwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c) 2002 Tim J. Robbins + * Copyright (c) 2009 David Schultz * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,23 +22,44 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/vdprintf.c,v 1.1 2009/03/04 03:38:51 das Exp $ */ +#include "namespace.h" +#include +#include #include #include -#include +#include "un-namespace.h" #include "local.h" +#include "priv_stdio.h" int -fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) +vdprintf(int fd, const char * __restrict fmt, va_list ap) { - va_list ap; - int r; + FILE f; + unsigned char buf[BUFSIZ]; + int ret; + + if (fd > SHRT_MAX) { + errno = EMFILE; + return (EOF); + } + + f.pub._p = buf; + f.pub._w = sizeof(buf); + f.pub._flags = __SWR; + f.pub._fileno = fd; + f._cookie = &f; + f._write = __swrite; + f._bf._base = buf; + f._bf._size = sizeof(buf); + memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); - va_start(ap, fmt); - r = vfwscanf(fp, fmt, ap); - va_end(ap); + if ((ret = __vfprintf(&f, fmt, ap)) < 0) + return (ret); - return (r); + return (__fflush(&f) ? EOF : ret); } diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index 29b913f457..26b30a5bfe 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)vfprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.34 2001/12/13 19:45:41 phantom Exp $ + * $FreeBSD: src/lib/libc/stdio/vfprintf.c,v 1.90 2009/02/28 06:06:57 das Exp $ * $DragonFly: src/lib/libc/stdio/vfprintf.c,v 1.16 2006/07/05 15:04:54 joerg Exp $ */ @@ -56,6 +52,7 @@ #include #include #include +#include #include #include "un-namespace.h" @@ -63,63 +60,84 @@ #include "libc_private.h" #include "local.h" #include "priv_stdio.h" +#include "printflocal.h" -/* Borrowed from sys/systm.h, which is _KERNEL-only: */ -#define CTASSERT(x) _CTASSERT(x, __LINE__) -#define _CTASSERT(x, y) __CTASSERT(x, y) -#define __CTASSERT(x, y) typedef char __assert ## y[(x) ? 1 : -1] - -/* This code assumes that a quad_t can fit in a long long: */ -CTASSERT(sizeof(quad_t) == sizeof(long long)); - -union arg { - int intarg; - unsigned int uintarg; - long longarg; - unsigned long ulongarg; - long long longlongarg; - unsigned long long ulonglongarg; - ptrdiff_t ptrdiffarg; - size_t sizearg; - intmax_t intmaxarg; - uintmax_t uintmaxarg; - void *pvoidarg; - char *pchararg; - signed char *pschararg; - short *pshortarg; - int *pintarg; - long *plongarg; - long long *plonglongarg; - ptrdiff_t *pptrdiffarg; - size_t *psizearg; - intmax_t *pintmaxarg; -#ifndef NO_FLOATING_POINT - double doublearg; - long double longdoublearg; -#endif - wint_t wintarg; - wchar_t *pwchararg; +static int __sprint(FILE *, struct __suio *); +static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0) + __noinline; +static char *__wcsconv(wchar_t *, int); + +#define CHAR char +#include "printfcommon.h" + +struct grouping_state { + char *thousands_sep; /* locale-specific thousands separator */ + int thousep_len; /* length of thousands_sep */ + const char *grouping; /* locale-specific numeric grouping rules */ + int lead; /* sig figs before decimal or group sep */ + int nseps; /* number of group separators with ' */ + int nrepeats; /* number of repeats of the last group */ }; /* - * Type ids for argument type table. + * Initialize the thousands' grouping state in preparation to print a + * number with ndigits digits. This routine returns the total number + * of bytes that will be needed. */ -enum typeid { - T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, - T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, - T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, - T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, - T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR -}; +static int +grouping_init(struct grouping_state *gs, int ndigits) +{ + struct lconv *locale; + + locale = localeconv(); + gs->grouping = locale->grouping; + gs->thousands_sep = locale->thousands_sep; + gs->thousep_len = strlen(gs->thousands_sep); + + gs->nseps = gs->nrepeats = 0; + gs->lead = ndigits; + while (*gs->grouping != CHAR_MAX) { + if (gs->lead <= *gs->grouping) + break; + gs->lead -= *gs->grouping; + if (*(gs->grouping+1)) { + gs->nseps++; + gs->grouping++; + } else + gs->nrepeats++; + } + return ((gs->nseps + gs->nrepeats) * gs->thousep_len); +} -static int __sprint(FILE *, struct __suio *); -static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0); -static char * __ujtoa(uintmax_t, char *, int, int, const char *, int, - char, const char *); -static char * __ultoa(u_long, char *, int, int, const char *, int, - char, const char *); -static void __find_arguments(const char *, va_list, union arg **); -static void __grow_type_table(int, enum typeid **, int *); +/* + * Print a number with thousands' separators. + */ +static int +grouping_print(struct grouping_state *gs, struct io_state *iop, + const CHAR *cp, const CHAR *ep) +{ + const CHAR *cp0 = cp; + + if (io_printandpad(iop, cp, ep, gs->lead, zeroes)) + return (-1); + cp += gs->lead; + while (gs->nseps > 0 || gs->nrepeats > 0) { + if (gs->nrepeats > 0) + gs->nrepeats--; + else { + gs->grouping--; + gs->nseps--; + } + if (io_print(iop, gs->thousands_sep, gs->thousep_len)) + return (-1); + if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes)) + return (-1); + cp += *gs->grouping; + } + if (cp > ep) + cp = ep; + return (cp - cp0); +} /* * Flush out all the vectors defined by the given uio, @@ -152,17 +170,16 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap) FILE fake; unsigned char buf[BUFSIZ]; + /* XXX This is probably not needed. */ + if (prepwrite(fp) != 0) + return (EOF); + /* copy the important variables */ fake.pub._flags = fp->pub._flags & ~__SNBF; fake.pub._fileno = fp->pub._fileno; fake._cookie = fp->_cookie; fake._write = fp->_write; - - fake._up = fp->_up; - fake.fl_mutex = fp->fl_mutex; - fake.fl_owner = fp->fl_owner; - fake.fl_count = fp->fl_count; - memset(WCIO_GET(&fake), 0, sizeof(struct wchar_io_data)); + memcpy(WCIO_GET(&fake), WCIO_GET(fp), sizeof(struct wchar_io_data)); /* set up the buffer */ fake._bf._base = fake.pub._p = buf; @@ -178,167 +195,6 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap) return (ret); } -/* - * Macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) ((n) + '0') - -/* - * Convert an unsigned long to ASCII for printf purposes, returning - * a pointer to the first character of the string representation. - * Octal numbers can be forced to have a leading zero; hex numbers - * use the given digits. - */ -static char * -__ultoa(u_long val, char *endp, int base, int octzero, const char *xdigs, - int needgrp, char thousep, const char *grp) -{ - char *cp = endp; - long sval; - int ndig; - - /* - * Handle the three cases separately, in the hope of getting - * better/faster code. - */ - switch (base) { - case 10: - if (val < 10) { /* many numbers are 1 digit */ - *--cp = to_char(val); - return (cp); - } - ndig = 0; - /* - * On many machines, unsigned arithmetic is harder than - * signed arithmetic, so we do at most one unsigned mod and - * divide; this is sufficient to reduce the range of - * the incoming value to where signed arithmetic works. - */ - if (val > LONG_MAX) { - *--cp = to_char(val % 10); - ndig++; - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - ndig++; - /* - * If (*grp == CHAR_MAX) then no more grouping - * should be performed. - */ - if (needgrp && ndig == *grp && *grp != CHAR_MAX && - sval > 9) { - *--cp = thousep; - ndig = 0; - /* - * If (*(grp+1) == '\0') then we have to - * use *grp character (last grouping rule) - * for all next cases - */ - if (*(grp + 1) != '\0') - grp++; - } - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[(size_t)val & 15]; - val >>= 4; - } while (val); - break; - - default: /* oops */ - abort(); - } - return (cp); -} - -/* Identical to __ultoa, but for intmax_t. */ -static char * -__ujtoa(uintmax_t val, char *endp, int base, int octzero, const char *xdigs, - int needgrp, char thousep, const char *grp) -{ - char *cp = endp; - intmax_t sval; - int ndig; - - /* quick test for small values; __ultoa is typically much faster */ - /* (perhaps instead we should run until small, then call __ultoa?) */ - if (val <= ULONG_MAX) - return (__ultoa((u_long)val, endp, base, octzero, xdigs, - needgrp, thousep, grp)); - switch (base) { - case 10: - if (val < 10) { - *--cp = to_char(val % 10); - return (cp); - } - ndig = 0; - if (val > INTMAX_MAX) { - *--cp = to_char(val % 10); - ndig++; - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - ndig++; - /* - * If (*grp == CHAR_MAX) then no more grouping - * should be performed. - */ - if (needgrp && *grp != CHAR_MAX && ndig == *grp && - sval > 9) { - *--cp = thousep; - ndig = 0; - /* - * If (*(grp+1) == '\0') then we have to - * use *grp character (last grouping rule) - * for all next cases - */ - if (*(grp + 1) != '\0') - grp++; - } - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[(size_t)val & 15]; - val >>= 4; - } while (val); - break; - - default: - abort(); - } - return (cp); -} - /* * Convert a wide character string argument for the %ls format to a multibyte * string representation. If not -1, prec specifies the maximum number of @@ -402,55 +258,32 @@ __wcsconv(wchar_t *wcsarg, int prec) * MT-safe version */ int -vfprintf(FILE *fp, const char *fmt0, va_list ap) +vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) { int ret; FLOCKFILE(fp); - ret = __vfprintf(fp, fmt0, ap); + /* optimise fprintf(stderr) (and other unbuffered Unix files) */ + if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && + fp->pub._fileno >= 0) + ret = __sbprintf(fp, fmt0, ap); + else + ret = __vfprintf(fp, fmt0, ap); FUNLOCKFILE(fp); return (ret); } -#ifndef NO_FLOATING_POINT -#include -#include "floatio.h" - -#define BUF ((MAXEXPDIG * 2) + MAXFRACT + 1) /* + decimal point */ -#define DEFPREC 6 - -extern char *__dtoa(double, int, int, int *, int *, char **); -extern void __freedtoa(char *s); - -static char *cvt(double, int, int, char *, int *, int, int *); -static int exponent (char *, int, int); - -#else /* no NO_FLOATING_POINT */ - -#define BUF 136 - -#endif /* NO_FLOATING_POINT */ - -#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ - /* - * Flags used during conversion. + * The size of the buffer we use as scratch space for integer + * conversions, among other things. We need enough space to + * write a uintmax_t in octal (plus one byte). */ -#define ALT 0x001 /* alternate form */ -#define HEXPREFIX 0x002 /* add 0x or 0X prefix */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double */ -#define LONGINT 0x010 /* long integer */ -#define LLONGINT 0x020 /* long long integer */ -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ -#define FPT 0x100 /* Floating point number */ -#define GROUPING 0x200 /* use grouping ("'" flag) */ - /* C99 additional size modifiers: */ -#define SIZET 0x400 /* size_t */ -#define PTRDIFFT 0x800 /* ptrdiff_t */ -#define INTMAXT 0x1000 /* intmax_t */ -#define CHARINT 0x2000 /* print char using int format */ +#if UINTMAX_MAX <= UINT64_MAX +#define BUF 32 +#else +#error "BUF must be large enough to format a uintmax_t" +#endif + /* * Non-MT-safe version */ @@ -461,22 +294,41 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) int ch; /* character from fmt */ int n, n2; /* handy integer (short term usage) */ char *cp; /* handy char pointer (short term usage) */ - struct __siov *iovp; /* for PRINT macro */ int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ - int prec; /* precision from format (%.3d), or -1 */ + int prec; /* precision from format; <0 for N/A */ char sign; /* sign prefix (' ', '+', '-', or \0) */ - char thousands_sep; /* locale specific thousands separator */ - const char *grouping; /* locale specific numeric grouping rules */ + struct grouping_state gs; /* thousands' grouping info */ + #ifndef NO_FLOATING_POINT - const char *decimal_point; /* locale specific decimal point */ - char softsign; /* temporary negative sign for floats */ - double _double; /* double precision arguments %[eEfgG] */ + /* + * We can decompose the printed representation of floating + * point numbers into several parts, some of which may be empty: + * + * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ + * A B ---C--- D E F + * + * A: 'sign' holds this value if present; '\0' otherwise + * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal + * C: cp points to the string MMMNNN. Leading and trailing + * zeros are not in the string and must be added. + * D: expchar holds this character; '\0' if no exponent, e.g. %f + * F: at least two digits for decimal, at least one digit for hex + */ + char *decimal_point; /* locale specific decimal point */ + int decpt_len; /* length of decimal_point */ + int signflag; /* true if float is negative */ + union { /* floating point arguments %[aAeEfFgG] */ + double dbl; + long double ldbl; + } fparg; int expt; /* integer value of exponent */ + char expchar; /* exponent character: [eEpP\0] */ + char *dtoaend; /* pointer to end of converted digits */ int expsize; /* character count for expstr */ - int ndig; /* actual number of digits returned by cvt */ - char expstr[7]; /* buffer for exponent string */ + int ndig; /* actual number of digits returned by dtoa */ + char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ char *dtoaresult; /* buffer allocated by dtoa */ #endif u_long ulval; /* integer arguments %[diouxX] */ @@ -486,73 +338,45 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) int realsz; /* field size expanded by dprec, sign, etc */ int size; /* size of converted field or string */ int prsize; /* max size of printed field */ - const char *xdigs; /* digits for [xX] conversion */ -#define NIOV 8 - struct __suio uio; /* output information: summary */ - struct __siov iov[NIOV];/* ... and individual io vectors */ - char buf[BUF]; /* space for %c, %[diouxX], %[eEfFgG] */ - char ox[2]; /* space for 0x hex-prefix */ - union arg *argtable; /* args, built due to positional arg */ - union arg statargtable[STATIC_ARG_TBL_SIZE]; - int nextarg; /* 1-based argument index */ - va_list orgap; /* original argument pointer */ + const char *xdigs; /* digits for %[xX] conversion */ + struct io_state io; /* I/O buffering state */ + char buf[BUF]; /* buffer with space for digits of uintmax_t */ + char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ + union arg *argtable; /* args, built due to positional arg */ + union arg statargtable [STATIC_ARG_TBL_SIZE]; + int nextarg; /* 1-based argument index */ + va_list orgap; /* original argument pointer */ char *convbuf; /* wide to multibyte conversion result */ - _double = 0; - expsize = 0; - ulval = 0; - ujval = 0; - xdigs = NULL; - - /* - * Choose PADSIZE to trade efficiency vs. size. If larger printf - * fields occur frequently, increase PADSIZE and make the initialisers - * below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static char blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static char zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + static const char xdigs_lower[16] = "0123456789abcdef"; + static const char xdigs_upper[16] = "0123456789ABCDEF"; - /* - * BEWARE, these `goto error' on error, and PAD uses `n'. - */ + /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) { \ - iovp->iov_base = __DECONST(void *, ptr); \ - iovp->iov_len = (len); \ - uio.uio_resid += (len); \ - iovp++; \ - if (++uio.uio_iovcnt >= NIOV) { \ - if (__sprint(fp, &uio)) \ - goto error; \ - iovp = iov; \ - } \ + if (io_print(&io, (ptr), (len))) \ + goto error; \ } #define PAD(howmany, with) { \ - if ((n = (howmany)) > 0) { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ + if (io_pad(&io, (howmany), (with))) \ + goto error; \ +} +#define PRINTANDPAD(p, ep, len, with) { \ + if (io_printandpad(&io, (p), (ep), (len), (with))) \ + goto error; \ } #define FLUSH() { \ - if (uio.uio_resid && __sprint(fp, &uio)) \ + if (io_flush(&io)) \ goto error; \ - uio.uio_iovcnt = 0; \ - iovp = iov; \ } - /* - * Get the argument indexed by nextarg. If the argument table is - * built, use it to get the argument. If its not, get the next - * argument (and arguments must be gotten sequentially). - */ -#define GETARG(type) \ - ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ - (nextarg++, va_arg(ap, type))) + /* + * Get the argument indexed by nextarg. If the argument table is + * built, use it to get the argument. If its not, get the next + * argument (and arguments must be gotten sequentially). + */ +#define GETARG(type) \ + ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ + (nextarg++, va_arg(ap, type))) /* * To extend shorts properly, we need both signed and unsigned @@ -571,7 +395,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) #define SJARG() \ (flags&INTMAXT ? GETARG(intmax_t) : \ - flags&SIZET ? (intmax_t)GETARG(size_t) : \ + flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ (intmax_t)GETARG(long long)) #define UJARG() \ @@ -580,58 +404,56 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ (uintmax_t)GETARG(unsigned long long)) - /* - * Get * arguments, including the form *nn$. Preserve the nextarg - * that the argument can be gotten once the type is determined. - */ -#define GETASTER(val) \ - n2 = 0; \ - cp = fmt; \ - while (is_digit(*cp)) { \ - n2 = 10 * n2 + to_digit(*cp); \ - cp++; \ - } \ - if (*cp == '$') { \ - int hold = nextarg; \ - if (argtable == NULL) { \ - argtable = statargtable; \ - __find_arguments (fmt0, orgap, &argtable); \ - } \ - nextarg = n2; \ - val = GETARG (int); \ - nextarg = hold; \ - fmt = ++cp; \ - } else { \ + /* + * Get * arguments, including the form *nn$. Preserve the nextarg + * that the argument can be gotten once the type is determined. + */ +#define GETASTER(val) \ + n2 = 0; \ + cp = fmt; \ + while (is_digit(*cp)) { \ + n2 = 10 * n2 + to_digit(*cp); \ + cp++; \ + } \ + if (*cp == '$') { \ + int hold = nextarg; \ + if (argtable == NULL) { \ + argtable = statargtable; \ + if (__find_arguments (fmt0, orgap, &argtable)) { \ + ret = EOF; \ + goto error; \ + } \ + } \ + nextarg = n2; \ + val = GETARG (int); \ + nextarg = hold; \ + fmt = ++cp; \ + } else { \ val = GETARG (int); \ - } + } + + if (__use_xprintf == 0 && getenv("USE_XPRINTF")) + __use_xprintf = 1; + if (__use_xprintf > 0) + return (__xvprintf(fp, fmt0, ap)); + /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ + if (prepwrite(fp) != 0) + return (EOF); - thousands_sep = '\0'; - grouping = NULL; convbuf = NULL; + fmt = __DECONST(char *, fmt0); + argtable = NULL; + nextarg = 1; + va_copy(orgap, ap); + io_init(&io, fp); + ret = 0; #ifndef NO_FLOATING_POINT dtoaresult = NULL; decimal_point = localeconv()->decimal_point; + /* The overwhelmingly common case is decpt_len == 1. */ + decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point)); #endif - /* sorry, fprintf(read_only_file, "") returns EOF, not 0 */ - if (cantwrite(fp)) { - return (EOF); - } - - /* optimise fprintf(stderr) (and other unbuffered Unix files) */ - if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && - fp->pub._fileno >= 0) { - return (__sbprintf(fp, fmt0, ap)); - } - - fmt = (char *)fmt0; - argtable = NULL; - nextarg = 1; - va_copy(orgap, ap); - uio.uio_iov = iovp = iov; - uio.uio_resid = 0; - uio.uio_iovcnt = 0; - ret = 0; /* * Scan the format for conversions (`%' character). @@ -655,12 +477,14 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) dprec = 0; width = 0; prec = -1; + gs.grouping = NULL; sign = '\0'; + ox[1] = '\0'; rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': - /* + /*- * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 @@ -672,13 +496,13 @@ reswitch: switch (ch) { flags |= ALT; goto rflag; case '*': - /* + /*- * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ - GETASTER (width); + GETASTER(width); if (width >= 0) goto rflag; width = -width; @@ -691,24 +515,20 @@ reswitch: switch (ch) { goto rflag; case '\'': flags |= GROUPING; - thousands_sep = *(localeconv()->thousands_sep); - grouping = localeconv()->grouping; goto rflag; case '.': if ((ch = *fmt++) == '*') { - GETASTER (n); - prec = n < 0 ? -1 : n; + GETASTER(prec); goto rflag; } - n = 0; + prec = 0; while (is_digit(ch)) { - n = 10 * n + to_digit(ch); + prec = 10 * prec + to_digit(ch); ch = *fmt++; } - prec = n < 0 ? -1 : n; goto reswitch; case '0': - /* + /*- * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 @@ -724,13 +544,16 @@ reswitch: switch (ch) { } while (is_digit(ch)); if (ch == '$') { nextarg = n; - if (argtable == NULL) { - argtable = statargtable; - __find_arguments (fmt0, orgap, - &argtable); + if (argtable == NULL) { + argtable = statargtable; + if (__find_arguments (fmt0, orgap, + &argtable)) { + ret = EOF; + goto error; + } } goto rflag; - } + } width = n; goto reswitch; #ifndef NO_FLOATING_POINT @@ -756,7 +579,7 @@ reswitch: switch (ch) { flags |= LONGINT; goto rflag; case 'q': - flags |= LLONGINT; + flags |= LLONGINT; /* not necessarily */ goto rflag; case 't': flags |= PTRDIFFT; @@ -808,91 +631,125 @@ reswitch: switch (ch) { base = 10; goto number; #ifndef NO_FLOATING_POINT -#ifdef HEXFLOAT case 'a': case 'A': -#endif + if (ch == 'a') { + ox[1] = 'x'; + xdigs = xdigs_lower; + expchar = 'p'; + } else { + ox[1] = 'X'; + xdigs = xdigs_upper; + expchar = 'P'; + } + if (prec >= 0) + prec++; + if (dtoaresult != NULL) + freedtoa(dtoaresult); + if (flags & LONGDBL) { + fparg.ldbl = GETARG(long double); + dtoaresult = cp = + __hldtoa(fparg.ldbl, xdigs, prec, + &expt, &signflag, &dtoaend); + } else { + fparg.dbl = GETARG(double); + dtoaresult = cp = + __hdtoa(fparg.dbl, xdigs, prec, + &expt, &signflag, &dtoaend); + } + if (prec < 0) + prec = dtoaend - cp; + if (expt == INT_MAX) + ox[1] = '\0'; + goto fp_common; case 'e': case 'E': - /* - * Grouping apply to %i, %d, %u, %f, %F, %g, %G - * conversion specifiers only. For other conversions - * behavior is undefined. - * -- POSIX - */ - flags &= ~GROUPING; - /*FALLTHROUGH*/ + expchar = ch; + if (prec < 0) /* account for digit before decpt */ + prec = DEFPREC + 1; + else + prec++; + goto fp_begin; case 'f': case 'F': + expchar = '\0'; goto fp_begin; case 'g': case 'G': + expchar = ch - ('g' - 'e'); if (prec == 0) prec = 1; -fp_begin: if (prec == -1) +fp_begin: + if (prec < 0) prec = DEFPREC; - if (flags & LONGDBL) - /* XXX this loses precision. */ - _double = (double)GETARG(long double); - else - _double = GETARG(double); - /* do this before tricky precision changes */ - if (isinf(_double)) { - if (_double < 0) - sign = '-'; - if (isupper(ch)) - cp = "INF"; - else - cp = "inf"; - size = 3; - break; + if (dtoaresult != NULL) + freedtoa(dtoaresult); + if (flags & LONGDBL) { + fparg.ldbl = GETARG(long double); + dtoaresult = cp = + __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, + &expt, &signflag, &dtoaend); + } else { + fparg.dbl = GETARG(double); + dtoaresult = cp = + dtoa(fparg.dbl, expchar ? 2 : 3, prec, + &expt, &signflag, &dtoaend); + if (expt == 9999) + expt = INT_MAX; } - if (isnan(_double)) { - if (isupper(ch)) - cp = "NAN"; - else - cp = "nan"; +fp_common: + if (signflag) + sign = '-'; + if (expt == INT_MAX) { /* inf or nan */ + if (*cp == 'N') { + cp = (ch >= 'a') ? "nan" : "NAN"; + sign = '\0'; + } else + cp = (ch >= 'a') ? "inf" : "INF"; size = 3; + flags &= ~ZEROPAD; break; } flags |= FPT; - if (dtoaresult != NULL) { - __freedtoa(dtoaresult); - dtoaresult = NULL; - } - dtoaresult = cp = cvt(_double, prec, flags, &softsign, - &expt, ch, &ndig); + ndig = dtoaend - cp; if (ch == 'g' || ch == 'G') { - if (expt <= -4 || expt > prec) - ch = (ch == 'g') ? 'e' : 'E'; - else - ch = 'g'; + if (expt > -4 && expt <= prec) { + /* Make %[gG] smell like %[fF] */ + expchar = '\0'; + if (flags & ALT) + prec -= expt; + else + prec = ndig - expt; + if (prec < 0) + prec = 0; + } else { + /* + * Make %[gG] smell like %[eE], but + * trim trailing zeroes if no # flag. + */ + if (!(flags & ALT)) + prec = ndig; + } } - if (ch == 'e' || ch == 'E') { - --expt; - expsize = exponent(expstr, expt, ch); - size = expsize + ndig; - if (ndig > 1 || flags & ALT) - ++size; - } else if (ch == 'f' || ch == 'F') { - if (expt > 0) { + if (expchar) { + expsize = exponent(expstr, expt - 1, expchar); + size = expsize + prec; + if (prec > 1 || flags & ALT) + size += decpt_len; + } else { + /* space for digits before decimal point */ + if (expt > 0) size = expt; - if (prec || flags & ALT) - size += prec + 1; - } else /* "0.X" */ - size = prec + 2; - } else if (expt >= ndig) { /* fixed g fmt */ - size = expt; - if (flags & ALT) - ++size; - } else - size = ndig + (expt > 0 ? - 1 : 2 - expt); - - if (softsign) - sign = '-'; + else /* "0" */ + size = 1; + /* space for decimal pt and following digits */ + if (prec || flags & ALT) + size += prec + decpt_len; + if ((flags & GROUPING) && expt > 0) + size += grouping_init(&gs, expt); + } break; -#endif /* NO_FLOATING_POINT */ +#endif /* !NO_FLOATING_POINT */ case 'n': /* * Assignment-like behavior is specified if the @@ -927,7 +784,7 @@ fp_begin: if (prec == -1) base = 8; goto nosign; case 'p': - /* + /*- * ``The argument shall be a pointer to void. The * value of the pointer is converted to a sequence * of printable characters, in an implementation- @@ -936,9 +793,9 @@ fp_begin: if (prec == -1) */ ujval = (uintmax_t)(uintptr_t)GETARG(void *); base = 16; - xdigs = "0123456789abcdef"; - flags = flags | INTMAXT | HEXPREFIX; - ch = 'x'; + xdigs = xdigs_lower; + flags = flags | INTMAXT; + ox[1] = 'x'; goto nosign; case 'S': flags |= LONGINT; @@ -961,22 +818,7 @@ fp_begin: if (prec == -1) } } else if ((cp = GETARG(char *)) == NULL) cp = "(null)"; - if (prec >= 0) { - /* - * can't use strlen; can only look for the - * NUL in the first `prec' characters, and - * strlen() will go further. - */ - char *p = memchr(cp, 0, (size_t)prec); - - if (p != NULL) { - size = p - cp; - if (size > prec) - size = prec; - } else - size = prec; - } else - size = strlen(cp); + size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp); sign = '\0'; break; case 'U': @@ -990,10 +832,10 @@ fp_begin: if (prec == -1) base = 10; goto nosign; case 'X': - xdigs = "0123456789ABCDEF"; + xdigs = xdigs_upper; goto hex; case 'x': - xdigs = "0123456789abcdef"; + xdigs = xdigs_lower; hex: if (flags & INTMAX_SIZE) ujval = UJARG(); @@ -1003,12 +845,12 @@ hex: /* leading 0x/X only if non-zero */ if (flags & ALT && (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) - flags |= HEXPREFIX; + ox[1] = ch; flags &= ~GROUPING; /* unsigned conversions */ nosign: sign = '\0'; - /* + /*- * ``... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored.'' * -- ANSI X3J11 @@ -1016,26 +858,32 @@ nosign: sign = '\0'; number: if ((dprec = prec) >= 0) flags &= ~ZEROPAD; - /* + /*- * ``The result of converting a zero value with an * explicit precision of zero is no characters.'' * -- ANSI X3J11 + * + * ``The C Standard is clear enough as is. The call + * printf("%#.0o", 0) should print 0.'' + * -- Defect Report #151 */ cp = buf + BUF; - if (flags & INTMAX_SIZE) { - if (ujval != 0 || prec != 0) - cp = __ujtoa(ujval, cp, base, - flags & ALT, xdigs, - flags & GROUPING, thousands_sep, - grouping); - } else { - if (ulval != 0 || prec != 0) - cp = __ultoa(ulval, cp, base, - flags & ALT, xdigs, - flags & GROUPING, thousands_sep, - grouping); - } + if (flags & INTMAX_SIZE) { + if (ujval != 0 || prec != 0 || + (flags & ALT && base == 8)) + cp = __ujtoa(ujval, cp, base, + flags & ALT, xdigs); + } else { + if (ulval != 0 || prec != 0 || + (flags & ALT && base == 8)) + cp = __ultoa(ulval, cp, base, + flags & ALT, xdigs); + } size = buf + BUF - cp; + if (size > BUF) /* should never happen */ + abort(); + if ((flags & GROUPING) && size != 0) + size += grouping_init(&gs, size); break; default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') @@ -1065,7 +913,7 @@ number: if ((dprec = prec) >= 0) realsz = dprec > size ? dprec : size; if (sign) realsz++; - else if (flags & HEXPREFIX) + if (ox[1]) realsz += 2; prsize = width > realsz ? width : realsz; @@ -1079,11 +927,11 @@ number: if ((dprec = prec) >= 0) PAD(width - realsz, blanks); /* prefix */ - if (sign) { + if (sign) PRINT(&sign, 1); - } else if (flags & HEXPREFIX) { + + if (ox[1]) { /* ox[1] is either x, X, or \0 */ ox[0] = '0'; - ox[1] = ch; PRINT(ox, 2); } @@ -1091,55 +939,55 @@ number: if ((dprec = prec) >= 0) if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) PAD(width - realsz, zeroes); - /* leading zeroes from decimal precision */ - PAD(dprec - size, zeroes); - /* the string or number proper */ #ifndef NO_FLOATING_POINT if ((flags & FPT) == 0) { - PRINT(cp, size); +#endif + /* leading zeroes from decimal precision */ + PAD(dprec - size, zeroes); + if (gs.grouping) { + if (grouping_print(&gs, &io, cp, buf+BUF) < 0) + goto error; + } else { + PRINT(cp, size); + } +#ifndef NO_FLOATING_POINT } else { /* glue together f_p fragments */ - if (ch >= 'f') { /* 'f' or 'g' */ - if (_double == 0) { - /* kludge for __dtoa irregularity */ - PRINT("0", 1); - if (expt < ndig || (flags & ALT) != 0) { - PRINT(decimal_point, 1); - PAD(ndig - 1, zeroes); - } - } else if (expt <= 0) { - PRINT("0", 1); - PRINT(decimal_point, 1); + if (!expchar) { /* %[fF] or sufficiently short %[gG] */ + if (expt <= 0) { + PRINT(zeroes, 1); + if (prec || flags & ALT) + PRINT(decimal_point,decpt_len); PAD(-expt, zeroes); - PRINT(cp, ndig); - } else if (expt >= ndig) { - PRINT(cp, ndig); - PAD(expt - ndig, zeroes); - if (flags & ALT) - PRINT(decimal_point, 1); + /* already handled initial 0's */ + prec += expt; } else { - PRINT(cp, expt); - cp += expt; - PRINT(decimal_point, 1); - PRINT(cp, ndig-expt); + if (gs.grouping) { + n = grouping_print(&gs, &io, + cp, dtoaend); + if (n < 0) + goto error; + cp += n; + } else { + PRINTANDPAD(cp, dtoaend, + expt, zeroes); + cp += expt; + } + if (prec || flags & ALT) + PRINT(decimal_point,decpt_len); } - } else { /* 'e' or 'E' */ - if (ndig > 1 || flags & ALT) { - ox[0] = *cp++; - ox[1] = *decimal_point; - PRINT(ox, 2); - if (_double) { - PRINT(cp, ndig-1); - } else /* 0.[0..] */ - /* __dtoa irregularity */ - PAD(ndig - 1, zeroes); + PRINTANDPAD(cp, dtoaend, prec, zeroes); + } else { /* %[eE] or sufficiently long %[gG] */ + if (prec > 1 || flags & ALT) { + PRINT(cp++, 1); + PRINT(decimal_point, decpt_len); + PRINT(cp, ndig-1); + PAD(prec - ndig, zeroes); } else /* XeYYY */ PRINT(cp, 1); PRINT(expstr, expsize); } } -#else - PRINT(cp, size); #endif /* left-adjusting padding (always blank) */ if (flags & LADJUST) @@ -1153,438 +1001,18 @@ number: if ((dprec = prec) >= 0) done: FLUSH(); error: + va_end(orgap); #ifndef NO_FLOATING_POINT if (dtoaresult != NULL) - __freedtoa(dtoaresult); + freedtoa(dtoaresult); #endif if (convbuf != NULL) free(convbuf); if (__sferror(fp)) ret = EOF; - if ((argtable != NULL) && (argtable != statargtable)) - free (argtable); + if ((argtable != NULL) && (argtable != statargtable)) + free(argtable); return (ret); /* NOTREACHED */ } -/* - * Find all arguments when a positional parameter is encountered. Returns a - * table, indexed by argument number, of pointers to each arguments. The - * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. - * It will be replaces with a malloc-ed one if it overflows. - */ -static void -__find_arguments (const char *fmt0, va_list ap, union arg **argtable) -{ - char *fmt; /* format string */ - int ch; /* character from fmt */ - int n, n2; /* handy integer (short term usage) */ - char *cp; /* handy char pointer (short term usage) */ - int flags; /* flags as above */ - int width; /* width from format (%8d), or 0 */ - enum typeid *typetable; /* table of types */ - enum typeid stattypetable[STATIC_ARG_TBL_SIZE]; - int tablesize; /* current size of type table */ - int tablemax; /* largest used index in table */ - int nextarg; /* 1-based argument index */ - - /* - * Add an argument type to the table, expanding if necessary. - */ -#define ADDTYPE(type) \ - ((nextarg >= tablesize) ? \ - __grow_type_table(nextarg, &typetable, &tablesize) : 0, \ - (nextarg > tablemax) ? tablemax = nextarg : 0, \ - typetable[nextarg++] = type) - -#define ADDSARG() \ - ((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ - ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ - ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ - ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ - ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) - -#define ADDUARG() \ - ((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ - ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ - ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ - ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ - ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) - - /* - * Add * arguments to the type array. - */ -#define ADDASTER() \ - n2 = 0; \ - cp = fmt; \ - while (is_digit(*cp)) { \ - n2 = 10 * n2 + to_digit(*cp); \ - cp++; \ - } \ - if (*cp == '$') { \ - int hold = nextarg; \ - nextarg = n2; \ - ADDTYPE (T_INT); \ - nextarg = hold; \ - fmt = ++cp; \ - } else { \ - ADDTYPE (T_INT); \ - } - fmt = (char *)fmt0; - typetable = stattypetable; - tablesize = STATIC_ARG_TBL_SIZE; - tablemax = 0; - nextarg = 1; - memset (typetable, T_UNUSED, STATIC_ARG_TBL_SIZE); - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) - /* void */; - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - width = 0; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - case '#': - goto rflag; - case '*': - ADDASTER (); - goto rflag; - case '-': - case '+': - case '\'': - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - ADDASTER (); - goto rflag; - } - while (is_digit(ch)) { - ch = *fmt++; - } - goto reswitch; - case '0': - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - if (ch == '$') { - nextarg = n; - goto rflag; - } - width = n; - goto reswitch; -#ifndef NO_FLOATING_POINT - case 'L': - flags |= LONGDBL; - goto rflag; -#endif - case 'h': - if (flags & SHORTINT) { - flags &= ~SHORTINT; - flags |= CHARINT; - } else - flags |= SHORTINT; - goto rflag; - case 'j': - flags |= INTMAXT; - goto rflag; - case 'l': - if (flags & LONGINT) { - flags &= ~LONGINT; - flags |= LLONGINT; - } else - flags |= LONGINT; - goto rflag; - case 'q': - flags |= LLONGINT; - goto rflag; - case 't': - flags |= PTRDIFFT; - goto rflag; - case 'z': - flags |= SIZET; - goto rflag; - case 'C': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'c': - if (flags & LONGINT) - ADDTYPE(T_WINT); - else - ADDTYPE(T_INT); - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - ADDSARG(); - break; -#ifndef NO_FLOATING_POINT -#ifdef HEXFLOAT - case 'a': - case 'A': -#endif - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (flags & LONGDBL) - ADDTYPE(T_LONG_DOUBLE); - else - ADDTYPE(T_DOUBLE); - break; -#endif /* NO_FLOATING_POINT */ - case 'n': - if (flags & INTMAXT) - ADDTYPE(TP_INTMAXT); - else if (flags & PTRDIFFT) - ADDTYPE(TP_PTRDIFFT); - else if (flags & SIZET) - ADDTYPE(TP_SIZET); - else if (flags & LLONGINT) - ADDTYPE(TP_LLONG); - else if (flags & LONGINT) - ADDTYPE(TP_LONG); - else if (flags & SHORTINT) - ADDTYPE(TP_SHORT); - else if (flags & CHARINT) - ADDTYPE(TP_SCHAR); - else - ADDTYPE(TP_INT); - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - ADDUARG(); - break; - case 'p': - ADDTYPE(TP_VOID); - break; - case 'S': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 's': - if (flags & LONGINT) - ADDTYPE(TP_WCHAR); - else - ADDTYPE(TP_CHAR); - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - case 'X': - case 'x': - ADDUARG(); - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - break; - } - } -done: - /* - * Build the argument table. - */ - if (tablemax >= STATIC_ARG_TBL_SIZE) { - *argtable = (union arg *) - malloc(sizeof(union arg) * (tablemax + 1)); - } - (*argtable)[0].intarg = 0; - for (n = 1; n <= tablemax; n++) { - switch (typetable [n]) { - case T_UNUSED: /* "whoops" */ - case T_INT: - (*argtable)[n].intarg = va_arg(ap, int); - break; - case TP_SCHAR: - (*argtable) [n].pschararg = va_arg (ap, signed char *); - break; - case TP_SHORT: - (*argtable)[n].pshortarg = va_arg(ap, short *); - break; - case T_U_INT: - (*argtable)[n].uintarg = va_arg(ap, unsigned int); - break; - case TP_INT: - (*argtable)[n].pintarg = va_arg(ap, int *); - break; - case T_LONG: - (*argtable)[n].longarg = va_arg(ap, long); - break; - case T_U_LONG: - (*argtable)[n].ulongarg = va_arg(ap, unsigned long); - break; - case TP_LONG: - (*argtable)[n].plongarg = va_arg(ap, long *); - break; - case T_LLONG: - (*argtable)[n].longlongarg = va_arg(ap, long long); - break; - case T_U_LLONG: - (*argtable)[n].ulonglongarg = va_arg(ap, unsigned long long); - break; - case TP_LLONG: - (*argtable)[n].plonglongarg = va_arg(ap, long long *); - break; - case T_PTRDIFFT: - (*argtable)[n].ptrdiffarg = va_arg(ap, ptrdiff_t); - break; - case TP_PTRDIFFT: - (*argtable)[n].pptrdiffarg = va_arg(ap, ptrdiff_t *); - break; - case T_SIZET: - (*argtable)[n].sizearg = va_arg(ap, size_t); - break; - case TP_SIZET: - (*argtable)[n].psizearg = va_arg(ap, ssize_t *); - break; - case T_INTMAXT: - (*argtable)[n].intmaxarg = va_arg(ap, intmax_t); - break; - case T_UINTMAXT: - (*argtable)[n].uintmaxarg = va_arg(ap, uintmax_t); - break; - case TP_INTMAXT: - (*argtable)[n].pintmaxarg = va_arg (ap, intmax_t *); - break; - case T_DOUBLE: - (*argtable)[n].doublearg = va_arg(ap, double); - break; - case T_LONG_DOUBLE: - (*argtable)[n].longdoublearg = va_arg(ap, long double); - break; - case TP_CHAR: - (*argtable)[n].pchararg = va_arg(ap, char *); - break; - case TP_VOID: - (*argtable)[n].pvoidarg = va_arg(ap, void *); - break; - case T_WINT: - (*argtable)[n].wintarg = va_arg(ap, wint_t); - break; - case TP_WCHAR: - (*argtable)[n].pwchararg = va_arg(ap, wchar_t *); - break; - } - } - - if ((typetable != NULL) && (typetable != stattypetable)) - free (typetable); -} - -/* - * Increase the size of the type table. - */ -static void -__grow_type_table(int nextarg, enum typeid **typetable, int *tablesize) -{ - enum typeid * const oldtable = *typetable; - const int oldsize = *tablesize; - enum typeid *newtable; - int n, newsize = oldsize * 2; - - if (newsize < nextarg + 1) - newsize = nextarg + 1; - if (oldsize == STATIC_ARG_TBL_SIZE) { - if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) - abort(); /* XXX handle better */ - bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); - } else { - if ((newtable = reallocf(oldtable, newsize * sizeof(enum typeid))) == NULL) - abort(); /* XXX handle better */ - } - for (n = oldsize; n < newsize; n++) - newtable[n] = T_UNUSED; - - *typetable = newtable; - *tablesize = newsize; -} - - -#ifndef NO_FLOATING_POINT - -static char * -cvt(double value, int ndigits, int flags, char *sign, int *decpt, - int ch, int *length) -{ - int mode, dsgn; - char *digits, *bp, *rve; - - if (ch == 'f') - mode = 3; /* ndigits after the decimal point */ - else { - /* - * To obtain ndigits after the decimal point for the 'e' - * and 'E' formats, round to ndigits + 1 significant - * figures. - */ - if (ch == 'e' || ch == 'E') - ndigits++; - mode = 2; /* ndigits significant digits */ - } - digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); - *sign = dsgn != 0; - if ((ch != 'g' && ch != 'G') || flags & ALT) { - /* print trailing zeros */ - bp = digits + ndigits; - if (ch == 'f') { - if ((*digits == '0' || *digits == '\0') && value) - *decpt = -ndigits + 1; - bp += *decpt; - } - if (value == 0) /* kludge for __dtoa irregularity */ - rve = bp; - while (rve < bp) - *rve++ = '0'; - } - *length = rve - digits; - return (digits); -} - -static int -exponent(char *p0, int expo, int fmtch) -{ - char *p, *t; - char expbuf[MAXEXPDIG]; - - p = p0; - *p++ = fmtch; - if (expo < 0) { - expo = -expo; - *p++ = '-'; - } - else - *p++ = '+'; - t = expbuf + MAXEXPDIG; - if (expo > 9) { - do { - *--t = to_char(expo % 10); - } while ((expo /= 10) > 9); - *--t = to_char(expo); - for (; t < expbuf + MAXEXPDIG; *p++ = *t++); - } - else { - *p++ = '0'; - *p++ = to_char(expo); - } - return (p - p0); -} -#endif /* NO_FLOATING_POINT */ diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c index 07ac0c4f72..12bbf922e3 100644 --- a/lib/libc/stdio/vfscanf.c +++ b/lib/libc/stdio/vfscanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,7 +30,7 @@ * SUCH DAMAGE. * * @(#)vfscanf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: /repoman/r/ncvs/src/lib/libc/stdio/vfscanf.c,v 1.35 2004/01/31 23:16:09 das Exp $ + * $FreeBSD: src/lib/libc/stdio/vfscanf.c,v 1.43 2009/01/19 06:19:51 das Exp $ * $DragonFly: src/lib/libc/stdio/vfscanf.c,v 1.11 2006/02/18 17:55:52 joerg Exp $ */ @@ -55,8 +51,9 @@ #include "local.h" #include "priv_stdio.h" +#ifndef NO_FLOATING_POINT #include -#include "floatio.h" +#endif #define BUF 513 /* Maximum length of numeric string. */ @@ -96,9 +93,9 @@ #define CT_FLOAT 4 /* %[efgEFG] conversion */ static const u_char *__sccl(char *, const u_char *); +#ifndef NO_FLOATING_POINT static int parsefloat(FILE *, char *, char *); - -int __scanfdebug = 0; +#endif __weak_reference(__vfscanf, vfscanf); @@ -154,7 +151,8 @@ __svfscanf(FILE *fp, const char *fmt0, va_list ap) if (c == 0) return (nassigned); if (isspace(c)) { - while ((fp->pub._r > 0 || __srefill(fp) == 0) && isspace(*fp->pub._p)) + while ((fp->pub._r > 0 || __srefill(fp) == 0) && + isspace(*fp->pub._p)) nread++, fp->pub._r--, fp->pub._p++; continue; } @@ -307,6 +305,7 @@ literal: else *va_arg(ap, int *) = nread; continue; + default: goto match_failure; @@ -412,7 +411,7 @@ literal: nread += sum; } else { size_t r = __fread((void *)va_arg(ap, char *), - 1, width, fp); + 1, width, fp); if (r == 0) goto input_failure; @@ -773,27 +772,15 @@ literal: goto match_failure; if ((flags & SUPPRESS) == 0) { if (flags & LONGDBL) { -#if 0 /* XXX no strtold (yet) */ long double res = strtold(buf, &p); *va_arg(ap, long double *) = res; -#else - double res = strtod(buf, &p); - *va_arg(ap, long double *) = res; -#endif } else if (flags & LONG) { double res = strtod(buf, &p); *va_arg(ap, double *) = res; } else { -#if 0 /* XXX no strtof (yet) */ float res = strtof(buf, &p); *va_arg(ap, float *) = res; -#else - float res = strtod(buf, &p); - *va_arg(ap, float *) = res; -#endif } - if (__scanfdebug && p - buf != width) - abort(); nassigned++; } nread += width; @@ -924,13 +911,13 @@ static int parsefloat(FILE *fp, char *buf, char *end) { char *commit, *p; - int infnanpos = 0; + int infnanpos = 0, decptpos = 0; enum { - S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX, - S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS + S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX, + S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS } state = S_START; unsigned char c; - char decpt = *localeconv()->decimal_point; + const char *decpt = localeconv()->decimal_point; _Bool gotmantdig = 0, ishex = 0; /* @@ -983,8 +970,6 @@ reswitch: break; case S_NAN: switch (infnanpos) { - case -1: /* XXX kludge to deal with nan(...) */ - goto parsedone; case 0: if (c != 'A' && c != 'a') goto parsedone; @@ -1002,13 +987,15 @@ reswitch: default: if (c == ')') { commit = p; - infnanpos = -2; + state = S_DONE; } else if (!isalnum(c) && c != '_') goto parsedone; break; } infnanpos++; break; + case S_DONE: + goto parsedone; case S_MAYBEHEX: state = S_DIGITS; if (c == 'X' || c == 'x') { @@ -1019,16 +1006,34 @@ reswitch: goto reswitch; } case S_DIGITS: - if ((ishex && isxdigit(c)) || isdigit(c)) + if ((ishex && isxdigit(c)) || isdigit(c)) { gotmantdig = 1; - else { + commit = p; + break; + } else { + state = S_DECPT; + goto reswitch; + } + case S_DECPT: + if (c == decpt[decptpos]) { + if (decpt[++decptpos] == '\0') { + /* We read the complete decpt seq. */ + state = S_FRAC; + if (gotmantdig) + commit = p; + } + break; + } else if (!decptpos) { + /* We didn't read any decpt characters. */ state = S_FRAC; - if (c != decpt) - goto reswitch; + goto reswitch; + } else { + /* + * We read part of a multibyte decimal point, + * but the rest is invalid, so bail. + */ + goto parsedone; } - if (gotmantdig) - commit = p; - break; case S_FRAC: if (((c == 'E' || c == 'e') && !ishex) || ((c == 'P' || c == 'p') && ishex)) { diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index a3f9da515e..3ce55305df 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -33,8 +29,8 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.24 2005/04/16 22:36:51 das Exp $ - * $NetBSD: vfwprintf.c,v 1.3 2005/06/15 09:31:27 he Exp $ + * @(#)vfprintf.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.41 2009/02/28 06:06:57 das Exp $ * $DragonFly: src/lib/libc/stdio/vfwprintf.c,v 1.3 2006/03/02 18:05:30 joerg Exp $ */ @@ -48,9 +44,7 @@ #include "namespace.h" #include -#include #include -#include #include #include #include @@ -61,63 +55,145 @@ #include #include #include - #include "un-namespace.h" #include "libc_private.h" #include "local.h" #include "priv_stdio.h" +#include "printflocal.h" +static int __sprint(FILE *, struct __suio *); +static int __sbprintf(FILE *, const wchar_t *, va_list) __noinline; +static wint_t __xfputwc(wchar_t, FILE *); +static wchar_t *__mbsconv(char *, int); -union arg { - int intarg; - unsigned int uintarg; - long longarg; - unsigned long ulongarg; - long long longlongarg; - unsigned long long ulonglongarg; - ptrdiff_t ptrdiffarg; - size_t sizearg; - intmax_t intmaxarg; - uintmax_t uintmaxarg; - void *pvoidarg; - char *pchararg; - signed char *pschararg; - short *pshortarg; - int *pintarg; - long *plongarg; - quad_t *plonglongarg; - ptrdiff_t *pptrdiffarg; - size_t *psizearg; - intmax_t *pintmaxarg; -#ifndef NO_FLOATING_POINT - double doublearg; - long double longdoublearg; -#endif - wint_t wintarg; - wchar_t *pwchararg; +#define CHAR wchar_t +#include "printfcommon.h" + +struct grouping_state { + wchar_t thousands_sep; /* locale-specific thousands separator */ + const char *grouping; /* locale-specific numeric grouping rules */ + int lead; /* sig figs before decimal or group sep */ + int nseps; /* number of group separators with ' */ + int nrepeats; /* number of repeats of the last group */ }; +static const mbstate_t initial_mbs; + +static inline wchar_t +get_decpt(void) +{ + mbstate_t mbs; + wchar_t decpt; + int nconv; + + mbs = initial_mbs; + nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs); + if (nconv == (size_t)-1 || nconv == (size_t)-2) + decpt = '.'; /* failsafe */ + return (decpt); +} + +static inline wchar_t +get_thousep(void) +{ + mbstate_t mbs; + wchar_t thousep; + int nconv; + + mbs = initial_mbs; + nconv = mbrtowc(&thousep, localeconv()->thousands_sep, + MB_CUR_MAX, &mbs); + if (nconv == (size_t)-1 || nconv == (size_t)-2) + thousep = '\0'; /* failsafe */ + return (thousep); +} + /* - * Type ids for argument type table. + * Initialize the thousands' grouping state in preparation to print a + * number with ndigits digits. This routine returns the total number + * of wide characters that will be printed. */ -enum typeid { - T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, - T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, - T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, - T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, - T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR -}; +static int +grouping_init(struct grouping_state *gs, int ndigits) +{ + + gs->grouping = localeconv()->grouping; + gs->thousands_sep = get_thousep(); + + gs->nseps = gs->nrepeats = 0; + gs->lead = ndigits; + while (*gs->grouping != CHAR_MAX) { + if (gs->lead <= *gs->grouping) + break; + gs->lead -= *gs->grouping; + if (*(gs->grouping+1)) { + gs->nseps++; + gs->grouping++; + } else + gs->nrepeats++; + } + return (gs->nseps + gs->nrepeats); +} + +/* + * Print a number with thousands' separators. + */ +static int +grouping_print(struct grouping_state *gs, struct io_state *iop, + const CHAR *cp, const CHAR *ep) +{ + const CHAR *cp0 = cp; + + if (io_printandpad(iop, cp, ep, gs->lead, zeroes)) + return (-1); + cp += gs->lead; + while (gs->nseps > 0 || gs->nrepeats > 0) { + if (gs->nrepeats > 0) + gs->nrepeats--; + else { + gs->grouping--; + gs->nseps--; + } + if (io_print(iop, &gs->thousands_sep, 1)) + return (-1); + if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes)) + return (-1); + cp += *gs->grouping; + } + if (cp > ep) + cp = ep; + return (cp - cp0); +} -static int __sbprintf(FILE *, const wchar_t *, va_list); -static wint_t __xfputwc(wchar_t, FILE *); -static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int, - char, const char *); -static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int, - char, const char *); -static wchar_t *__mbsconv(char *, int); -static void __find_arguments(const wchar_t *, va_list, union arg **); -static void __grow_type_table(int, enum typeid **, int *); + +/* + * Flush out all the vectors defined by the given uio, + * then reset it so that it can be reused. + * + * XXX The fact that we do this a character at a time and convert to a + * multibyte character sequence even if the destination is a wide + * string eclipses the benefits of buffering. + */ +static int +__sprint(FILE *fp, struct __suio *uio) +{ + struct __siov *iov; + wchar_t *p; + int i, len; + + iov = uio->uio_iov; + for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) { + p = (wchar_t *)iov->iov_base; + len = iov->iov_len; + for (i = 0; i < len; i++) { + if (__xfputwc(p[i], fp) == WEOF) + return (-1); + } + } + uio->uio_iovcnt = 0; + return (0); +} /* * Helper function for `fprintf to unbuffered unix file': creates a @@ -131,17 +207,16 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) FILE fake; unsigned char buf[BUFSIZ]; + /* XXX This is probably not needed. */ + if (prepwrite(fp) != 0) + return (EOF); + /* copy the important variables */ fake.pub._flags = fp->pub._flags & ~__SNBF; fake.pub._fileno = fp->pub._fileno; fake._cookie = fp->_cookie; fake._write = fp->_write; - - fake._up = fp->_up; - fake.fl_mutex = fp->fl_mutex; - fake.fl_owner = fp->fl_owner; - fake.fl_count = fp->fl_count; - memset(WCIO_GET(&fake), 0, sizeof(struct wchar_io_data)); + memcpy(WCIO_GET(&fake), WCIO_GET(fp), sizeof(struct wchar_io_data)); /* set up the buffer */ fake._bf._base = fake.pub._p = buf; @@ -149,7 +224,7 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) fake.pub._lbfsize = 0; /* not actually used, but Just In Case */ /* do the work, then copy any error status */ - ret = __vfwprintf_unlocked(&fake, fmt, ap); + ret = __vfwprintf(&fake, fmt, ap); if (ret >= 0 && __fflush(&fake)) ret = WEOF; if (fake.pub._flags & __SERR) @@ -164,7 +239,6 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) static wint_t __xfputwc(wchar_t wc, FILE *fp) { - static const mbstate_t initial; mbstate_t mbs; char buf[MB_LEN_MAX]; struct __suio uio; @@ -174,7 +248,7 @@ __xfputwc(wchar_t wc, FILE *fp) if ((fp->pub._flags & __SSTR) == 0) return (__fputwc_unlock(wc, fp)); - mbs = initial; + mbs = initial_mbs; if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { fp->pub._flags |= __SERR; return (WEOF); @@ -187,167 +261,6 @@ __xfputwc(wchar_t wc, FILE *fp) return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); } -/* - * Macros for converting digits to letters and vice versa - */ -#define to_digit(c) ((c) - '0') -#define is_digit(c) ((unsigned)to_digit(c) <= 9) -#define to_char(n) (wchar_t)((n) + '0') - -/* - * Convert an unsigned long to ASCII for printf purposes, returning - * a pointer to the first character of the string representation. - * Octal numbers can be forced to have a leading zero; hex numbers - * use the given digits. - */ -static wchar_t * -__ultoa(u_long val, wchar_t *endp, int base, int octzero, const char *xdigs, - int needgrp, char thousep, const char *grp) -{ - wchar_t *cp = endp; - long sval; - int ndig; - - /* - * Handle the three cases separately, in the hope of getting - * better/faster code. - */ - switch (base) { - case 10: - if (val < 10) { /* many numbers are 1 digit */ - *--cp = to_char(val); - return (cp); - } - ndig = 0; - /* - * On many machines, unsigned arithmetic is harder than - * signed arithmetic, so we do at most one unsigned mod and - * divide; this is sufficient to reduce the range of - * the incoming value to where signed arithmetic works. - */ - if (val > LONG_MAX) { - *--cp = to_char(val % 10); - ndig++; - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - ndig++; - /* - * If (*grp == CHAR_MAX) then no more grouping - * should be performed. - */ - if (needgrp && ndig == *grp && *grp != CHAR_MAX && - sval > 9) { - *--cp = thousep; - ndig = 0; - /* - * If (*(grp+1) == '\0') then we have to - * use *grp character (last grouping rule) - * for all next cases - */ - if (*(grp+1) != '\0') - grp++; - } - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[(size_t)val & 15]; - val >>= 4; - } while (val); - break; - - default: /* oops */ - abort(); - } - return (cp); -} - -/* Identical to __ultoa, but for intmax_t. */ -static wchar_t * -__ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero, - const char *xdigs, int needgrp, char thousep, const char *grp) -{ - wchar_t *cp = endp; - intmax_t sval; - int ndig; - - /* quick test for small values; __ultoa is typically much faster */ - /* (perhaps instead we should run until small, then call __ultoa?) */ - if (val <= ULONG_MAX) - return (__ultoa((u_long)val, endp, base, octzero, xdigs, - needgrp, thousep, grp)); - switch (base) { - case 10: - if (val < 10) { - *--cp = to_char(val % 10); - return (cp); - } - ndig = 0; - if (val > INTMAX_MAX) { - *--cp = to_char(val % 10); - ndig++; - sval = val / 10; - } else - sval = val; - do { - *--cp = to_char(sval % 10); - ndig++; - /* - * If (*grp == CHAR_MAX) then no more grouping - * should be performed. - */ - if (needgrp && *grp != CHAR_MAX && ndig == *grp && - sval > 9) { - *--cp = thousep; - ndig = 0; - /* - * If (*(grp+1) == '\0') then we have to - * use *grp character (last grouping rule) - * for all next cases - */ - if (*(grp+1) != '\0') - grp++; - } - sval /= 10; - } while (sval != 0); - break; - - case 8: - do { - *--cp = to_char(val & 7); - val >>= 3; - } while (val); - if (octzero && *cp != '0') - *--cp = '0'; - break; - - case 16: - do { - *--cp = xdigs[(size_t)val & 15]; - val >>= 4; - } while (val); - break; - - default: - abort(); - } - return (cp); -} - /* * Convert a multibyte character string argument for the %s format to a wide * string representation. ``prec'' specifies the maximum number of bytes @@ -357,7 +270,6 @@ __ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero, static wchar_t * __mbsconv(char *mbsarg, int prec) { - static const mbstate_t initial; mbstate_t mbs; wchar_t *convbuf, *wcp; const char *p; @@ -376,8 +288,8 @@ __mbsconv(char *mbsarg, int prec) * number of characters to print. */ p = mbsarg; - insize = nchars = nconv = 0; - mbs = initial; + insize = nchars = 0; + mbs = initial_mbs; while (nchars != (size_t)prec) { nconv = mbrlen(p, MB_CUR_MAX, &mbs); if (nconv == 0 || nconv == (size_t)-1 || @@ -389,8 +301,10 @@ __mbsconv(char *mbsarg, int prec) } if (nconv == (size_t)-1 || nconv == (size_t)-2) return (NULL); - } else + } else { insize = strlen(mbsarg); + nconv = 0; + } /* * Allocate buffer for the result and perform the conversion, @@ -402,8 +316,7 @@ __mbsconv(char *mbsarg, int prec) return (NULL); wcp = convbuf; p = mbsarg; - mbs = initial; - nconv = 0; + mbs = initial_mbs; while (insize != 0) { nconv = mbrtowc(wcp, p, insize, &mbs); if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) @@ -430,73 +343,43 @@ vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) int ret; FLOCKFILE(fp); - ret = __vfwprintf_unlocked(fp, fmt0, ap); + /* optimise fprintf(stderr) (and other unbuffered Unix files) */ + if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && + fp->pub._fileno >= 0) + ret = __sbprintf(fp, fmt0, ap); + else + ret = __vfwprintf(fp, fmt0, ap); FUNLOCKFILE(fp); return (ret); } -#ifndef NO_FLOATING_POINT - -#define dtoa __dtoa -#define freedtoa __freedtoa - -#include -#include -#include "floatio.h" - -#define DEFPREC 6 - -static int exponent(wchar_t *, int, wchar_t); -static wchar_t *cvt(double, int, int, char *, int *, int, int *, char **); - -#endif /* !NO_FLOATING_POINT */ - /* * The size of the buffer we use as scratch space for integer - * conversions, among other things. Technically, we would need the - * most space for base 10 conversions with thousands' grouping - * characters between each pair of digits. 100 bytes is a - * conservative overestimate even for a 128-bit uintmax_t. + * conversions, among other things. We need enough space to + * write a uintmax_t in octal (plus one byte). */ -#define BUF 100 - -#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ - -/* - * Flags used during conversion. - */ -#define ALT 0x001 /* alternate form */ -#define LADJUST 0x004 /* left adjustment */ -#define LONGDBL 0x008 /* long double */ -#define LONGINT 0x010 /* long integer */ -#define LLONGINT 0x020 /* quad_t integer */ -#define SHORTINT 0x040 /* short integer */ -#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ -#define FPT 0x100 /* Floating point number */ -#define GROUPING 0x200 /* use grouping ("'" flag) */ - /* C99 additional size modifiers: */ -#define SIZET 0x400 /* size_t */ -#define PTRDIFFT 0x800 /* ptrdiff_t */ -#define INTMAXT 0x1000 /* intmax_t */ -#define CHARINT 0x2000 /* print char using int format */ +#if UINTMAX_MAX <= UINT64_MAX +#define BUF 32 +#else +#error "BUF must be large enough to format a uintmax_t" +#endif /* * Non-MT-safe version */ int -__vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) +__vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) { wchar_t *fmt; /* format string */ wchar_t ch; /* character from fmt */ - int n, n2, n3; /* handy integer (short term usage) */ + int n, n2; /* handy integer (short term usage) */ wchar_t *cp; /* handy char pointer (short term usage) */ int flags; /* flags as above */ int ret; /* return value accumulator */ int width; /* width from format (%8d), or 0 */ int prec; /* precision from format; <0 for N/A */ wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ - char thousands_sep; /* locale specific thousands separator */ - const char *grouping; /* locale specific numeric grouping rules */ + struct grouping_state gs; /* thousands' grouping info */ #ifndef NO_FLOATING_POINT /* * We can decompose the printed representation of floating @@ -512,27 +395,19 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) * D: expchar holds this character; '\0' if no exponent, e.g. %f * F: at least two digits for decimal, at least one digit for hex */ - const char *decimal_point; /* locale specific decimal point */ -#ifdef notyet + wchar_t decimal_point; /* locale specific decimal point */ int signflag; /* true if float is negative */ union { /* floating point arguments %[aAeEfFgG] */ double dbl; long double ldbl; } fparg; - char *dtoaend; /* pointer to end of converted digits */ -#else - double _double; /* double precision arguments %[eEfgG] */ - char softsign; /* temporary negative sign for floats */ -#endif int expt; /* integer value of exponent */ char expchar; /* exponent character: [eEpP\0] */ + char *dtoaend; /* pointer to end of converted digits */ int expsize; /* character count for expstr */ - char *dtoaresult; /* buffer allocated by dtoa */ - int lead; /* sig figs before decimal or group sep */ int ndig; /* actual number of digits returned by dtoa */ wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ - int nseps; /* number of group separators with ' */ - int nrepeats; /* number of repeats of the last group */ + char *dtoaresult; /* buffer allocated by dtoa */ #endif u_long ulval; /* integer arguments %[diouxX] */ uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ @@ -542,6 +417,7 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) int size; /* size of converted field or string */ int prsize; /* max size of printed field */ const char *xdigs; /* digits for [xX] conversion */ + struct io_state io; /* I/O buffering state */ wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ wchar_t ox[2]; /* space for 0x hex-prefix */ union arg *argtable; /* args, built due to positional arg */ @@ -550,53 +426,34 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) va_list orgap; /* original argument pointer */ wchar_t *convbuf; /* multibyte to wide conversion result */ - /* - * Choose PADSIZE to trade efficiency vs. size. If larger printf - * fields occur frequently, increase PADSIZE and make the initialisers - * below longer. - */ -#define PADSIZE 16 /* pad chunk size */ - static wchar_t blanks[PADSIZE] = - {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; - static wchar_t zeroes[PADSIZE] = - {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; - static const char xdigs_lower[16] = "0123456789abcdef"; static const char xdigs_upper[16] = "0123456789ABCDEF"; - /* - * BEWARE, these `goto error' on error, PRINT uses `n2' and - * PAD uses `n'. - */ + /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) do { \ - for (n3 = 0; n3 < (len); n3++) \ - __xfputwc((ptr)[n3], fp); \ -} while (/*CONSTCOND*/0) -#define PAD(howmany, with) do { \ - if ((n = (howmany)) > 0) { \ - while (n > PADSIZE) { \ - PRINT(with, PADSIZE); \ - n -= PADSIZE; \ - } \ - PRINT(with, n); \ - } \ -} while (/*CONSTCOND*/0) -#define PRINTANDPAD(p, ep, len, with) do { \ - n2 = (ep) - (p); \ - if (n2 > (len)) \ - n2 = (len); \ - if (n2 > 0) \ - PRINT((p), n2); \ - PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ -} while(/*CONSTCOND*/0) + if (io_print(&io, (ptr), (len))) \ + goto error; \ +} while (0) +#define PAD(howmany, with) { \ + if (io_pad(&io, (howmany), (with))) \ + goto error; \ +} +#define PRINTANDPAD(p, ep, len, with) { \ + if (io_printandpad(&io, (p), (ep), (len), (with))) \ + goto error; \ +} +#define FLUSH() { \ + if (io_flush(&io)) \ + goto error; \ +} /* * Get the argument indexed by nextarg. If the argument table is * built, use it to get the argument. If its not, get the next * argument (and arguments must be gotten sequentially). */ -#define GETARG(type) \ - ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \ +#define GETARG(type) \ + ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \ (nextarg++, va_arg(ap, type))) /* @@ -614,16 +471,16 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ (u_long)GETARG(u_int)) #define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) -#define SJARG() \ +#define SJARG() \ (flags&INTMAXT ? GETARG(intmax_t) : \ - flags&SIZET ? (intmax_t)GETARG(size_t) : \ + flags&SIZET ? (intmax_t)GETARG(ssize_t) : \ flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ - (intmax_t)GETARG(quad_t)) + (intmax_t)GETARG(long long)) #define UJARG() \ (flags&INTMAXT ? GETARG(uintmax_t) : \ flags&SIZET ? (uintmax_t)GETARG(size_t) : \ flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ - (uintmax_t)GETARG(u_quad_t)) + (uintmax_t)GETARG(unsigned long long)) /* * Get * arguments, including the form *nn$. Preserve the nextarg @@ -640,7 +497,10 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) int hold = nextarg; \ if (argtable == NULL) { \ argtable = statargtable; \ - __find_arguments (fmt0, orgap, &argtable); \ + if (__find_warguments(fmt0, orgap, &argtable)) { \ + ret = EOF; \ + goto error; \ + } \ } \ nextarg = n2; \ val = GETARG (int); \ @@ -651,30 +511,20 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) } - thousands_sep = '\0'; - grouping = NULL; -#ifndef NO_FLOATING_POINT - dtoaresult = NULL; - decimal_point = localeconv()->decimal_point; - expsize = 0; /* XXXGCC -Wuninitialized [sh3,m68000] */ -#endif - convbuf = NULL; /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */ - if (cantwrite(fp)) { - errno = EBADF; - return (WEOF); - } - - /* optimise fprintf(stderr) (and other unbuffered Unix files) */ - if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && - fp->pub._fileno >= 0) - return (__sbprintf(fp, fmt0, ap)); + if (prepwrite(fp) != 0) + return (EOF); + convbuf = NULL; fmt = __DECONST(wchar_t *, fmt0); argtable = NULL; nextarg = 1; va_copy(orgap, ap); + io_init(&io, fp); ret = 0; +#ifndef NO_FLOATING_POINT + decimal_point = get_decpt(); +#endif /* * Scan the format for conversions (`%' character). @@ -698,19 +548,14 @@ __vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) dprec = 0; width = 0; prec = -1; + gs.grouping = NULL; sign = '\0'; ox[1] = '\0'; - expchar = '\0'; - lead = 0; - nseps = nrepeats = 0; - ulval = 0; - ujval = 0; - xdigs = NULL; rflag: ch = *fmt++; reswitch: switch (ch) { case ' ': - /* + /*- * ``If the space and + flags both appear, the space * flag will be ignored.'' * -- ANSI X3J11 @@ -722,13 +567,13 @@ reswitch: switch (ch) { flags |= ALT; goto rflag; case '*': - /* + /*- * ``A negative field width argument is taken as a * - flag followed by a positive field width.'' * -- ANSI X3J11 * They don't exclude field widths read from args. */ - GETASTER (width); + GETASTER(width); if (width >= 0) goto rflag; width = -width; @@ -741,12 +586,10 @@ reswitch: switch (ch) { goto rflag; case '\'': flags |= GROUPING; - thousands_sep = *(localeconv()->thousands_sep); - grouping = localeconv()->grouping; goto rflag; case '.': if ((ch = *fmt++) == '*') { - GETASTER (prec); + GETASTER(prec); goto rflag; } prec = 0; @@ -756,7 +599,7 @@ reswitch: switch (ch) { } goto reswitch; case '0': - /* + /*- * ``Note that 0 is taken as a flag, not as the * beginning of a field width.'' * -- ANSI X3J11 @@ -774,8 +617,11 @@ reswitch: switch (ch) { nextarg = n; if (argtable == NULL) { argtable = statargtable; - __find_arguments (fmt0, orgap, - &argtable); + if (__find_warguments(fmt0, orgap, + &argtable)) { + ret = EOF; + goto error; + } } goto rflag; } @@ -790,8 +636,9 @@ reswitch: switch (ch) { if (flags & SHORTINT) { flags &= ~SHORTINT; flags |= CHARINT; - } else + } else { flags |= SHORTINT; + } goto rflag; case 'j': flags |= INTMAXT; @@ -800,8 +647,9 @@ reswitch: switch (ch) { if (flags & LONGINT) { flags &= ~LONGINT; flags |= LLONGINT; - } else + } else { flags |= LONGINT; + } goto rflag; case 'q': flags |= LLONGINT; /* not necessarily */ @@ -844,7 +692,6 @@ reswitch: switch (ch) { base = 10; goto number; #ifndef NO_FLOATING_POINT -#ifdef notyet case 'a': case 'A': if (ch == 'a') { @@ -869,7 +716,6 @@ reswitch: switch (ch) { __hdtoa(fparg.dbl, xdigs, prec, &expt, &signflag, &dtoaend); } - if (prec < 0) prec = dtoaend - dtoaresult; if (expt == INT_MAX) @@ -928,57 +774,9 @@ fp_common: } else cp = (ch >= 'a') ? L"inf" : L"INF"; size = 3; + flags &= ~ZEROPAD; break; } -#else - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - if (prec == -1) { - prec = DEFPREC; - } else if ((ch == 'g' || ch == 'G') && prec == 0) { - prec = 1; - } - - if (flags & LONGDBL) { - _double = (double) GETARG(long double); - } else { - _double = GETARG(double); - } - - /* do this before tricky precision changes */ - if (isinf(_double)) { - if (_double < 0) - sign = '-'; - if (ch == 'E' || ch == 'F' || ch == 'G') - cp = L"INF"; - else - cp = L"inf"; - size = 3; - break; - } - if (isnan(_double)) { - if (ch == 'E' || ch == 'F' || ch == 'G') - cp = L"NAN"; - else - cp = L"nan"; - size = 3; - break; - } - - flags |= FPT; - if (dtoaresult != NULL) { - free(dtoaresult); - dtoaresult = NULL; - } - cp = cvt(_double, prec, flags, &softsign, - &expt, ch, &ndig, &dtoaresult); - if (softsign) - sign = '-'; -#endif flags |= FPT; if (ch == 'g' || ch == 'G') { if (expt > -4 && expt <= prec) { @@ -1013,23 +811,8 @@ fp_common: /* space for decimal pt and following digits */ if (prec || flags & ALT) size += prec + 1; - if (grouping && expt > 0) { - /* space for thousands' grouping */ - nseps = nrepeats = 0; - lead = expt; - while (*grouping != CHAR_MAX) { - if (lead <= *grouping) - break; - lead -= *grouping; - if (*(grouping+1)) { - nseps++; - grouping++; - } else - nrepeats++; - } - size += nseps + nrepeats; - } else - lead = expt; + if ((flags & GROUPING) && expt > 0) + size += grouping_init(&gs, expt); } break; #endif /* !NO_FLOATING_POINT */ @@ -1040,7 +823,7 @@ fp_common: * C99 says to use `signed char' for %hhn conversions. */ if (flags & LLONGINT) - *GETARG(quad_t *) = ret; + *GETARG(long long *) = ret; else if (flags & SIZET) *GETARG(ssize_t *) = (ssize_t)ret; else if (flags & PTRDIFFT) @@ -1067,7 +850,7 @@ fp_common: base = 8; goto nosign; case 'p': - /* + /*- * ``The argument shall be a pointer to void. The * value of the pointer is converted to a sequence * of printable characters, in an implementation- @@ -1103,23 +886,7 @@ fp_common: cp = convbuf; } } - - if (prec >= 0) { - /* - * can't use wcslen; can only look for the - * NUL in the first `prec' characters, and - * wcslen() will go further. - */ - wchar_t *p = wmemchr(cp, 0, (size_t)prec); - - if (p != NULL) { - size = p - cp; - if (size > prec) - size = prec; - } else - size = prec; - } else - size = wcslen(cp); + size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp); sign = '\0'; break; case 'U': @@ -1151,7 +918,7 @@ hex: flags &= ~GROUPING; /* unsigned conversions */ nosign: sign = '\0'; - /* + /*- * ``... diouXx conversions ... if a precision is * specified, the 0 flag will be ignored.'' * -- ANSI X3J11 @@ -1159,7 +926,7 @@ nosign: sign = '\0'; number: if ((dprec = prec) >= 0) flags &= ~ZEROPAD; - /* + /*- * ``The result of converting a zero value with an * explicit precision of zero is no characters.'' * -- ANSI X3J11 @@ -1173,20 +940,18 @@ number: if ((dprec = prec) >= 0) if (ujval != 0 || prec != 0 || (flags & ALT && base == 8)) cp = __ujtoa(ujval, cp, base, - flags & ALT, xdigs, - flags & GROUPING, thousands_sep, - grouping); + flags & ALT, xdigs); } else { if (ulval != 0 || prec != 0 || (flags & ALT && base == 8)) cp = __ultoa(ulval, cp, base, - flags & ALT, xdigs, - flags & GROUPING, thousands_sep, - grouping); + flags & ALT, xdigs); } size = buf + BUF - cp; if (size > BUF) /* should never happen */ abort(); + if ((flags & GROUPING) && size != 0) + size += grouping_init(&gs, size); break; default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') @@ -1242,53 +1007,48 @@ number: if ((dprec = prec) >= 0) if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) PAD(width - realsz, zeroes); - /* leading zeroes from decimal precision */ - PAD(dprec - size, zeroes); - /* the string or number proper */ #ifndef NO_FLOATING_POINT if ((flags & FPT) == 0) { - PRINT(cp, size); +#endif + /* leading zeroes from decimal precision */ + PAD(dprec - size, zeroes); + if (gs.grouping) { + if (grouping_print(&gs, &io, cp, buf+BUF) < 0) + goto error; + } else { + PRINT(cp, size); + } +#ifndef NO_FLOATING_POINT } else { /* glue together f_p fragments */ if (!expchar) { /* %[fF] or sufficiently short %[gG] */ if (expt <= 0) { PRINT(zeroes, 1); if (prec || flags & ALT) - PRINT(decimal_point, 1); + PRINT(&decimal_point, 1); PAD(-expt, zeroes); /* already handled initial 0's */ prec += expt; } else { - PRINTANDPAD(cp, convbuf + ndig, lead, zeroes); - cp += lead; - if (grouping) { - while (nseps>0 || nrepeats>0) { - if (nrepeats > 0) - nrepeats--; - else { - grouping--; - nseps--; - } - PRINT(&thousands_sep, - 1); - PRINTANDPAD(cp, - convbuf + ndig, - *grouping, zeroes); - cp += *grouping; - } - if (cp > convbuf + ndig) - cp = convbuf + ndig; - } - if (prec || flags & ALT) { - buf[0] = *decimal_point; - PRINT(buf, 1); + if (gs.grouping) { + n = grouping_print(&gs, &io, + cp, convbuf + ndig); + if (n < 0) + goto error; + cp += n; + } else { + PRINTANDPAD(cp, convbuf + ndig, + expt, zeroes); + cp += expt; } + if (prec || flags & ALT) + PRINT(&decimal_point, 1); } PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); } else { /* %[eE] or sufficiently long %[gG] */ if (prec > 1 || flags & ALT) { buf[0] = *cp++; - buf[1] = *decimal_point; + buf[1] = decimal_point; PRINT(buf, 2); PRINT(cp, ndig-1); PAD(prec - ndig, zeroes); @@ -1297,8 +1057,6 @@ number: if ((dprec = prec) >= 0) PRINT(expstr, expsize); } } -#else - PRINT(cp, size); #endif /* left-adjusting padding (always blank) */ if (flags & LADJUST) @@ -1306,462 +1064,19 @@ number: if ((dprec = prec) >= 0) /* finally, adjust ret */ ret += prsize; + + FLUSH(); /* copy out the I/O vectors */ } done: + FLUSH(); error: -#ifndef NO_FLOATING_POINT - if (dtoaresult != NULL) - free(dtoaresult); -#endif va_end(orgap); if (convbuf != NULL) free(convbuf); if (__sferror(fp)) ret = EOF; if ((argtable != NULL) && (argtable != statargtable)) - free (argtable); + free(argtable); return (ret); /* NOTREACHED */ } - -/* - * Find all arguments when a positional parameter is encountered. Returns a - * table, indexed by argument number, of pointers to each arguments. The - * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. - * It will be replaces with a malloc-ed one if it overflows. - */ -static void -__find_arguments (const wchar_t *fmt0, va_list ap, union arg **argtable) -{ - wchar_t *fmt; /* format string */ - wchar_t ch; /* character from fmt */ - int n, n2; /* handy integer (short term usage) */ - wchar_t *cp; /* handy char pointer (short term usage) */ - int flags; /* flags as above */ - enum typeid *typetable; /* table of types */ - enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; - int tablesize; /* current size of type table */ - int tablemax; /* largest used index in table */ - int nextarg; /* 1-based argument index */ - - /* - * Add an argument type to the table, expanding if necessary. - */ -#define ADDTYPE(type) \ - /*LINTED null effect*/ \ - (void)((nextarg >= tablesize) ? \ - __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \ - (nextarg > tablemax) ? tablemax = nextarg : 0, \ - typetable[nextarg++] = type) - -#define ADDSARG() \ - (void)((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ - ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ - ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ - ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ - ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) - -#define ADDUARG() \ - (void)((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ - ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ - ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ - ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ - ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) - - /* - * Add * arguments to the type array. - */ -#define ADDASTER() \ - n2 = 0; \ - cp = fmt; \ - while (is_digit(*cp)) { \ - n2 = 10 * n2 + to_digit(*cp); \ - cp++; \ - } \ - if (*cp == '$') { \ - int hold = nextarg; \ - nextarg = n2; \ - ADDTYPE (T_INT); \ - nextarg = hold; \ - fmt = ++cp; \ - } else { \ - ADDTYPE (T_INT); \ - } - fmt = __DECONST(wchar_t *, fmt0); - typetable = stattypetable; - tablesize = STATIC_ARG_TBL_SIZE; - tablemax = 0; - nextarg = 1; - for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) - typetable[n] = T_UNUSED; - - /* - * Scan the format for conversions (`%' character). - */ - for (;;) { - for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) - /* void */; - if (ch == '\0') - goto done; - fmt++; /* skip over '%' */ - - flags = 0; - -rflag: ch = *fmt++; -reswitch: switch (ch) { - case ' ': - case '#': - goto rflag; - case '*': - ADDASTER (); - goto rflag; - case '-': - case '+': - case '\'': - goto rflag; - case '.': - if ((ch = *fmt++) == '*') { - ADDASTER (); - goto rflag; - } - while (is_digit(ch)) { - ch = *fmt++; - } - goto reswitch; - case '0': - goto rflag; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - n = 0; - do { - n = 10 * n + to_digit(ch); - ch = *fmt++; - } while (is_digit(ch)); - if (ch == '$') { - nextarg = n; - goto rflag; - } - goto reswitch; -#ifndef NO_FLOATING_POINT - case 'L': - flags |= LONGDBL; - goto rflag; -#endif - case 'h': - if (flags & SHORTINT) { - flags &= ~SHORTINT; - flags |= CHARINT; - } else - flags |= SHORTINT; - goto rflag; - case 'j': - flags |= INTMAXT; - goto rflag; - case 'l': - if (flags & LONGINT) { - flags &= ~LONGINT; - flags |= LLONGINT; - } else - flags |= LONGINT; - goto rflag; - case 'q': - flags |= LLONGINT; /* not necessarily */ - goto rflag; - case 't': - flags |= PTRDIFFT; - goto rflag; - case 'z': - flags |= SIZET; - goto rflag; - case 'C': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'c': - if (flags & LONGINT) - ADDTYPE(T_WINT); - else - ADDTYPE(T_INT); - break; - case 'D': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'd': - case 'i': - ADDSARG(); - break; -#ifndef NO_FLOATING_POINT - case 'a': - case 'A': - case 'e': - case 'E': - case 'f': - case 'g': - case 'G': - if (flags & LONGDBL) - ADDTYPE(T_LONG_DOUBLE); - else - ADDTYPE(T_DOUBLE); - break; -#endif /* !NO_FLOATING_POINT */ - case 'n': - if (flags & INTMAXT) - ADDTYPE(TP_INTMAXT); - else if (flags & PTRDIFFT) - ADDTYPE(TP_PTRDIFFT); - else if (flags & SIZET) - ADDTYPE(TP_SIZET); - else if (flags & LLONGINT) - ADDTYPE(TP_LLONG); - else if (flags & LONGINT) - ADDTYPE(TP_LONG); - else if (flags & SHORTINT) - ADDTYPE(TP_SHORT); - else if (flags & CHARINT) - ADDTYPE(TP_SCHAR); - else - ADDTYPE(TP_INT); - continue; /* no output */ - case 'O': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'o': - ADDUARG(); - break; - case 'p': - ADDTYPE(TP_VOID); - break; - case 'S': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 's': - if (flags & LONGINT) - ADDTYPE(TP_WCHAR); - else - ADDTYPE(TP_CHAR); - break; - case 'U': - flags |= LONGINT; - /*FALLTHROUGH*/ - case 'u': - case 'X': - case 'x': - ADDUARG(); - break; - default: /* "%?" prints ?, unless ? is NUL */ - if (ch == '\0') - goto done; - break; - } - } -done: - /* - * Build the argument table. - */ - if (tablemax >= STATIC_ARG_TBL_SIZE) { - *argtable = (union arg *) - malloc (sizeof (union arg) * (tablemax + 1)); - } - - (*argtable) [0].intarg = 0; - for (n = 1; n <= tablemax; n++) { - switch (typetable [n]) { - case T_UNUSED: /* whoops! */ - (*argtable) [n].intarg = va_arg (ap, int); - break; - case TP_SCHAR: - (*argtable) [n].pschararg = va_arg (ap, signed char *); - break; - case TP_SHORT: - (*argtable) [n].pshortarg = va_arg (ap, short *); - break; - case T_INT: - (*argtable) [n].intarg = va_arg (ap, int); - break; - case T_U_INT: - (*argtable) [n].uintarg = va_arg (ap, unsigned int); - break; - case TP_INT: - (*argtable) [n].pintarg = va_arg (ap, int *); - break; - case T_LONG: - (*argtable) [n].longarg = va_arg (ap, long); - break; - case T_U_LONG: - (*argtable) [n].ulongarg = va_arg (ap, unsigned long); - break; - case TP_LONG: - (*argtable) [n].plongarg = va_arg (ap, long *); - break; - case T_LLONG: - (*argtable) [n].longlongarg = va_arg (ap, quad_t); - break; - case T_U_LLONG: - (*argtable) [n].ulonglongarg = va_arg (ap, u_quad_t); - break; - case TP_LLONG: - (*argtable) [n].plonglongarg = va_arg (ap, quad_t *); - break; - case T_PTRDIFFT: - (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); - break; - case TP_PTRDIFFT: - (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); - break; - case T_SIZET: - (*argtable) [n].sizearg = va_arg (ap, size_t); - break; - case TP_SIZET: - (*argtable) [n].psizearg = va_arg (ap, size_t *); - break; - case T_INTMAXT: - (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); - break; - case T_UINTMAXT: - (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); - break; - case TP_INTMAXT: - (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); - break; -#ifndef NO_FLOATING_POINT - case T_DOUBLE: - (*argtable) [n].doublearg = va_arg (ap, double); - break; - case T_LONG_DOUBLE: - (*argtable) [n].longdoublearg = va_arg (ap, long double); - break; -#endif - case TP_CHAR: - (*argtable) [n].pchararg = va_arg (ap, char *); - break; - case TP_VOID: - (*argtable) [n].pvoidarg = va_arg (ap, void *); - break; - case T_WINT: - (*argtable) [n].wintarg = va_arg (ap, wint_t); - break; - case TP_WCHAR: - (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); - break; - } - } - - if ((typetable != NULL) && (typetable != stattypetable)) - free (typetable); -} - -/* - * Increase the size of the type table. - */ -static void -__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) -{ - enum typeid *const oldtable = *typetable; - const int oldsize = *tablesize; - enum typeid *newtable; - int n, newsize = oldsize * 2; - - if (newsize < nextarg + 1) - newsize = nextarg + 1; - if (oldsize == STATIC_ARG_TBL_SIZE) { - if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) - abort(); /* XXX handle better */ - bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); - } else { - newtable = realloc(oldtable, newsize * sizeof(enum typeid)); - if (newtable == NULL) - abort(); /* XXX handle better */ - } - for (n = oldsize; n < newsize; n++) - newtable[n] = T_UNUSED; - - *typetable = newtable; - *tablesize = newsize; -} - - -#ifndef NO_FLOATING_POINT -extern char *__dtoa (double, int, int, int *, int *, char **, char **); - -static wchar_t * -cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch, - int *length, char **dtoaresult) -{ - int mode, dsgn; - char *digits, *bp, *rve; - static wchar_t buf[512]; - - _DIAGASSERT(decpt != NULL); - _DIAGASSERT(length != NULL); - _DIAGASSERT(sign != NULL); - - if (ch == 'f') { - mode = 3; /* ndigits after the decimal point */ - } else { - /* To obtain ndigits after the decimal point for the 'e' - * and 'E' formats, round to ndigits + 1 significant - * figures. - */ - if (ch == 'e' || ch == 'E') { - ndigits++; - } - mode = 2; /* ndigits significant digits */ - } - - digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve, dtoaresult); - if (dsgn) { - value = -value; - *sign = '-'; - } else - *sign = '\000'; - if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ - bp = digits + ndigits; - if (ch == 'f') { - if (*digits == '0' && value) - *decpt = -ndigits + 1; - bp += *decpt; - } - if (value == 0) /* kludge for __dtoa irregularity */ - rve = bp; - while (rve < bp) - *rve++ = '0'; - } - *length = rve - digits; - mbstowcs(buf, digits, sizeof(buf)/sizeof(buf[0])); - return buf; -} -static int -exponent(wchar_t *p0, int expo, wchar_t fmtch) -{ - wchar_t *p, *t; - wchar_t expbuf[MAXEXPDIG]; - - p = p0; - *p++ = fmtch; - if (expo < 0) { - expo = -expo; - *p++ = '-'; - } - else - *p++ = '+'; - t = expbuf + MAXEXPDIG; - if (expo > 9) { - do { - *--t = to_char(expo % 10); - } while ((expo /= 10) > 9); - *--t = to_char(expo); - for (; t < expbuf + MAXEXPDIG; *p++ = *t++); - } - else { - /* - * Exponents for decimal floating point conversions - * (%[eEgG]) must be at least two characters long, - * whereas exponents for hexadecimal conversions can - * be only one character long. - */ - if (fmtch == 'e' || fmtch == 'E') - *p++ = '0'; - *p++ = to_char(expo); - } - return (p - p0); -} -#endif /* !NO_FLOATING_POINT */ diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c index 7e23c2e982..9ac24f2980 100644 --- a/lib/libc/stdio/vfwscanf.c +++ b/lib/libc/stdio/vfwscanf.c @@ -1,6 +1,3 @@ -/* $NetBSD: vfwscanf.c,v 1.2 2005/06/12 05:48:41 lukem Exp $ */ -/* $DragonFly: src/lib/libc/stdio/vfwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -16,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -35,17 +28,21 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * @(#)vfscanf.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.17 2009/01/19 06:19:51 das Exp $ + * $DragonFly: src/lib/libc/stdio/vfwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include "namespace.h" #include #include +#include #include #include #include #include #include -#include #include #include #include "un-namespace.h" @@ -69,7 +66,7 @@ #define SUPPRESS 0x08 /* *: suppress assignment */ #define POINTER 0x10 /* p: void * (as hex) */ #define NOSKIP 0x20 /* [ or c: do not skip blanks */ -#define LONGLONG 0x400 /* ll: quad_t (+ deprecated q: quad) */ +#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */ #define INTMAXT 0x800 /* j: intmax_t */ #define PTRDIFFT 0x1000 /* t: ptrdiff_t */ #define SIZET 0x2000 /* z: size_t */ @@ -95,11 +92,15 @@ #define CT_INT 3 /* %[dioupxX] conversion */ #define CT_FLOAT 4 /* %[efgEFG] conversion */ +#ifndef NO_FLOATING_POINT static int parsefloat(FILE *, wchar_t *, wchar_t *); +#endif #define INCCL(_c) \ - (cclcompl ? (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) == NULL) : \ - (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) != NULL)) + (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \ + (wmemchr(ccls, (_c), ccle - ccls) != NULL)) + +static const mbstate_t initial_mbs; /* * MT-safe version. @@ -110,8 +111,8 @@ vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) int ret; FLOCKFILE(fp); - _SET_ORIENTATION(fp, 1); - ret = __vfwscanf_unlocked(fp, fmt, ap); + ORIENT(fp, 1); + ret = __vfwscanf(fp, fmt, ap); FUNLOCKFILE(fp); return (ret); } @@ -120,7 +121,7 @@ vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) * Non-MT-safe version. */ int -__vfwscanf_unlocked(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) +__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) { wint_t c; /* character from format, or conversion */ size_t width; /* field width, or 0 */ @@ -140,7 +141,6 @@ __vfwscanf_unlocked(FILE * __restrict fp, const wchar_t * __restrict fmt, va_lis char *mbp; /* multibyte string pointer for %c %s %[ */ size_t nconv; /* number of bytes in mb. conversion */ char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */ - static const mbstate_t initial; mbstate_t mbs; /* `basefix' is used to avoid `if' tests in the integer scanner */ @@ -151,9 +151,6 @@ __vfwscanf_unlocked(FILE * __restrict fp, const wchar_t * __restrict fmt, va_lis nconversions = 0; nread = 0; ccls = ccle = NULL; - base = 0; - cclcompl = 0; - mbp = NULL; for (;;) { c = *fmt++; if (c == 0) @@ -315,7 +312,7 @@ literal: else if (flags & LONG) *va_arg(ap, long *) = nread; else if (flags & LONGLONG) - *va_arg(ap, quad_t *) = nread; + *va_arg(ap, long long *) = nread; else if (flags & INTMAXT) *va_arg(ap, intmax_t *) = nread; else if (flags & SIZET) @@ -376,7 +373,7 @@ literal: if (!(flags & SUPPRESS)) mbp = va_arg(ap, char *); n = 0; - mbs = initial; + mbs = initial_mbs; while (width != 0 && (wi = __fgetwc_unlock(fp)) != WEOF) { if (width >= MB_CUR_MAX && @@ -441,7 +438,7 @@ literal: if (!(flags & SUPPRESS)) mbp = va_arg(ap, char *); n = 0; - mbs = initial; + mbs = initial_mbs; while ((wi = __fgetwc_unlock(fp)) != WEOF && width != 0 && INCCL(wi)) { if (width >= MB_CUR_MAX && @@ -502,7 +499,7 @@ literal: } else { if (!(flags & SUPPRESS)) mbp = va_arg(ap, char *); - mbs = initial; + mbs = initial_mbs; while ((wi = __fgetwc_unlock(fp)) != WEOF && width != 0 && !iswspace(wi)) { @@ -664,21 +661,21 @@ literal: *va_arg(ap, void **) = (void *)(uintptr_t)res; else if (flags & SHORTSHORT) - *va_arg(ap, char *) = (char)res; + *va_arg(ap, char *) = res; else if (flags & SHORT) - *va_arg(ap, short *) = (short)res; + *va_arg(ap, short *) = res; else if (flags & LONG) - *va_arg(ap, long *) = (long)res; + *va_arg(ap, long *) = res; else if (flags & LONGLONG) - *va_arg(ap, quad_t *) = res; + *va_arg(ap, long long *) = res; else if (flags & INTMAXT) *va_arg(ap, intmax_t *) = res; else if (flags & PTRDIFFT) - *va_arg(ap, ptrdiff_t *) = (ptrdiff_t)res; + *va_arg(ap, ptrdiff_t *) = res; else if (flags & SIZET) - *va_arg(ap, size_t *) = (size_t)res; + *va_arg(ap, size_t *) = res; else - *va_arg(ap, int *) = (int)res; + *va_arg(ap, int *) = res; nassigned++; } nread += p - buf; @@ -694,25 +691,16 @@ literal: if ((width = parsefloat(fp, buf, buf + width)) == 0) goto match_failure; if ((flags & SUPPRESS) == 0) { -#ifdef notyet if (flags & LONGDBL) { long double res = wcstold(buf, &p); *va_arg(ap, long double *) = res; - } else -#endif - if (flags & LONG) { + } else if (flags & LONG) { double res = wcstod(buf, &p); *va_arg(ap, double *) = res; -#ifdef notyet } else { float res = wcstof(buf, &p); *va_arg(ap, float *) = res; -#endif } -#ifdef DEBUG - if (p - buf != width) - abort(); -#endif nassigned++; } nread += width; @@ -731,15 +719,22 @@ match_failure: static int parsefloat(FILE *fp, wchar_t *buf, wchar_t *end) { + mbstate_t mbs; + size_t nconv; wchar_t *commit, *p; int infnanpos = 0; enum { - S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX, + S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX, S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS } state = S_START; wchar_t c; - wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->decimal_point; - int gotmantdig = 0, ishex = 0; + wchar_t decpt; + _Bool gotmantdig = 0, ishex = 0; + + mbs = initial_mbs; + nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs); + if (nconv == (size_t)-1 || nconv == (size_t)-2) + decpt = '.'; /* failsafe */ /* * We set commit = p whenever the string we have read so far @@ -793,8 +788,6 @@ reswitch: break; case S_NAN: switch (infnanpos) { - case -1: /* XXX kludge to deal with nan(...) */ - goto parsedone; case 0: if (c != 'A' && c != 'a') goto parsedone; @@ -812,13 +805,15 @@ reswitch: default: if (c == ')') { commit = p; - infnanpos = -2; + state = S_DONE; } else if (!iswalnum(c) && c != '_') goto parsedone; break; } infnanpos++; break; + case S_DONE: + goto parsedone; case S_MAYBEHEX: state = S_DIGITS; if (c == 'X' || c == 'x') { diff --git a/lib/libc/stdio/vprintf.c b/lib/libc/stdio/vprintf.c index d7dd21f652..24733ea26e 100644 --- a/lib/libc/stdio/vprintf.c +++ b/lib/libc/stdio/vprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,15 +30,15 @@ * SUCH DAMAGE. * * @(#)vprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/vprintf.c,v 1.6 1999/08/28 00:01:21 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/vprintf.c,v 1.11 2007/01/09 00:28:08 imp Exp $ * $DragonFly: src/lib/libc/stdio/vprintf.c,v 1.3 2003/11/09 02:34:02 dillon Exp $ */ #include -#include int -vprintf(char const *fmt, va_list ap) +vprintf(const char * __restrict fmt, __va_list ap) { + return (vfprintf(stdout, fmt, ap)); } diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c index 8d23170906..51fe9521a8 100644 --- a/lib/libc/stdio/vscanf.c +++ b/lib/libc/stdio/vscanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,18 +30,18 @@ * SUCH DAMAGE. * * @(#)vscanf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/vscanf.c,v 1.7 1999/08/28 00:01:21 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/vscanf.c,v 1.13 2007/01/09 00:28:08 imp Exp $ * $DragonFly: src/lib/libc/stdio/vscanf.c,v 1.4 2005/01/31 22:29:40 dillon Exp $ */ #include "namespace.h" #include -#include #include "un-namespace.h" #include "libc_private.h" +#include "local.h" int -vscanf(const char *fmt, va_list ap) +vscanf(const char * __restrict fmt, __va_list ap) { int retval; diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c index cd19c71ca2..fa193345a2 100644 --- a/lib/libc/stdio/vsnprintf.c +++ b/lib/libc/stdio/vsnprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,19 +30,18 @@ * SUCH DAMAGE. * * @(#)vsnprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/vsnprintf.c,v 1.12.2.1 2002/09/23 06:58:17 maxim Exp $ + * $FreeBSD: src/lib/libc/stdio/vsnprintf.c,v 1.24 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/vsnprintf.c,v 1.9 2008/05/15 03:59:59 dillon Exp $ */ #include #include -#include - #include "local.h" #include "priv_stdio.h" int -vsnprintf(char *str, size_t n, const char *fmt, va_list ap) +vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt, + __va_list ap) { size_t on; int ret; @@ -63,16 +58,12 @@ vsnprintf(char *str, size_t n, const char *fmt, va_list ap) if (on > 0) *str = '\0'; str = dummy; - n = 1; + n = 1; } f.pub._fileno = -1; f.pub._flags = __SWR | __SSTR; f._bf._base = f.pub._p = (unsigned char *)str; f._bf._size = f.pub._w = n; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); ret = __vfprintf(&f, fmt, ap); if (on > 0) diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c index 9e75a19709..fb4ab966bd 100644 --- a/lib/libc/stdio/vsprintf.c +++ b/lib/libc/stdio/vsprintf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,19 +30,17 @@ * SUCH DAMAGE. * * @(#)vsprintf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/vsprintf.c,v 1.6 1999/08/28 00:01:21 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/vsprintf.c,v 1.16 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/vsprintf.c,v 1.8 2006/03/02 18:05:30 joerg Exp $ */ #include -#include #include - #include "local.h" #include "priv_stdio.h" int -vsprintf(char *str, const char *fmt, va_list ap) +vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap) { int ret; FILE f; @@ -55,10 +49,6 @@ vsprintf(char *str, const char *fmt, va_list ap) f.pub._flags = __SWR | __SSTR; f._bf._base = f.pub._p = (unsigned char *)str; f._bf._size = f.pub._w = INT_MAX; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); ret = __vfprintf(&f, fmt, ap); *f.pub._p = 0; diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c index 570b7ee317..8e7ce7a573 100644 --- a/lib/libc/stdio/vsscanf.c +++ b/lib/libc/stdio/vsscanf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,19 +30,17 @@ * SUCH DAMAGE. * * @(#)vsscanf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/vsscanf.c,v 1.7 1999/08/28 00:01:22 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/vsscanf.c,v 1.14 2008/04/17 22:17:54 jhb Exp $ * $DragonFly: src/lib/libc/stdio/vsscanf.c,v 1.10 2006/03/02 18:05:30 joerg Exp $ */ #include -#include #include - #include "local.h" #include "priv_stdio.h" static int -eofread (void *, char *, int); +eofread(void *, char *, int); /* ARGSUSED */ static int @@ -57,7 +51,7 @@ eofread(void *cookie __unused, char *buf __unused, int len __unused) } int -vsscanf(const char *str, const char *fmt, va_list ap) +vsscanf(const char * __restrict str, const char * __restrict fmt, __va_list ap) { FILE f; @@ -68,10 +62,6 @@ vsscanf(const char *str, const char *fmt, va_list ap) f._read = eofread; f._ub._base = NULL; f._lb._base = NULL; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); return (__svfscanf(&f, fmt, ap)); } diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c index f3be382e68..026d17f42c 100644 --- a/lib/libc/stdio/vswprintf.c +++ b/lib/libc/stdio/vswprintf.c @@ -1,5 +1,4 @@ -/* $NetBSD: vswprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/vswprintf.c,v 1.2 2006/03/02 18:05:30 joerg Exp $ */ +/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */ /* * Copyright (c) 1997 Todd C. Miller @@ -26,21 +25,21 @@ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/vswprintf.c,v 1.7 2008/04/17 22:17:54 jhb Exp $ + * $DragonFly: src/lib/libc/stdio/vswprintf.c,v 1.2 2006/03/02 18:05:30 joerg Exp $ */ #include #include -#include #include -#include #include - #include "local.h" #include "priv_stdio.h" int vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, - va_list ap) + __va_list ap) { static const mbstate_t initial; mbstate_t mbs; @@ -62,12 +61,8 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, return (-1); } f._bf._size = f.pub._w = 127; /* Leave room for the NUL */ - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); - ret = __vfwprintf_unlocked(&f, fmt, ap); + ret = __vfwprintf(&f, fmt, ap); if (ret < 0) { sverrno = errno; free(f._bf._base); diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c index e041923494..2773d4b428 100644 --- a/lib/libc/stdio/vswscanf.c +++ b/lib/libc/stdio/vswscanf.c @@ -1,6 +1,3 @@ -/* $NetBSD: vswscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/vswscanf.c,v 1.3 2006/03/02 18:05:30 joerg Exp $ */ - /*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -16,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -35,6 +28,10 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * @(#)vsscanf.c 8.1 (Berkeley) 6/4/93 + * $FreeBSD: src/lib/libc/stdio/vswscanf.c,v 1.6 2009/01/15 18:53:52 rdivacky Exp $ + * $DragonFly: src/lib/libc/stdio/vswscanf.c,v 1.3 2006/03/02 18:05:30 joerg Exp $ */ #include @@ -43,14 +40,12 @@ #include #include #include - #include "local.h" #include "priv_stdio.h" static int eofread(void *, char *, int); static int -/*ARGSUSED*/ eofread(void *cookie __unused, char *buf __unused, int len __unused) { @@ -59,7 +54,7 @@ eofread(void *cookie __unused, char *buf __unused, int len __unused) int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, - va_list ap) + va_list ap) { static const mbstate_t initial; mbstate_t mbs; @@ -67,6 +62,7 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, char *mbstr; size_t mlen; int r; + const wchar_t *strp; /* * XXX Convert the wide character string to multibyte, which @@ -75,8 +71,8 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, if ((mbstr = malloc(wcslen(str) * MB_CUR_MAX + 1)) == NULL) return (EOF); mbs = initial; - if ((mlen = wcsrtombs(mbstr, (const wchar_t ** __restrict)&str, - SIZE_T_MAX, &mbs)) == (size_t)-1) { + strp = str; + if ((mlen = wcsrtombs(mbstr, &strp, SIZE_T_MAX, &mbs)) == (size_t)-1) { free(mbstr); return (EOF); } @@ -87,12 +83,8 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, f._read = eofread; f._ub._base = NULL; f._lb._base = NULL; - f._up = NULL; - f.fl_mutex = PTHREAD_MUTEX_INITIALIZER; - f.fl_owner = NULL; - f.fl_count = 0; memset(WCIO_GET(&f), 0, sizeof(struct wchar_io_data)); - r = __vfwscanf_unlocked(&f, fmt, ap); + r = __vfwscanf(&f, fmt, ap); free(mbstr); return (r); diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c index e22d09cfe2..f689d2cc4b 100644 --- a/lib/libc/stdio/vwprintf.c +++ b/lib/libc/stdio/vwprintf.c @@ -1,6 +1,3 @@ -/* $NetBSD: vwprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/vwprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/vwprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/vwprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c index e1d2529ba9..f931e90130 100644 --- a/lib/libc/stdio/vwscanf.c +++ b/lib/libc/stdio/vwscanf.c @@ -1,6 +1,3 @@ -/* $NetBSD: vwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/vwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/vwscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/vwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/wbuf.c b/lib/libc/stdio/wbuf.c index c24747111c..d9f3852a3f 100644 --- a/lib/libc/stdio/wbuf.c +++ b/lib/libc/stdio/wbuf.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,12 +30,11 @@ * SUCH DAMAGE. * * @(#)wbuf.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/wbuf.c,v 1.6 1999/08/28 00:01:22 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/wbuf.c,v 1.12 2007/01/09 00:28:08 imp Exp $ * $DragonFly: src/lib/libc/stdio/wbuf.c,v 1.6 2005/07/23 20:23:06 joerg Exp $ */ #include - #include "local.h" #include "priv_stdio.h" @@ -63,10 +58,12 @@ __swbuf(int c, FILE *fp) * calls might wrap _w from negative to positive. */ fp->pub._w = fp->pub._lbfsize; - if (cantwrite(fp)) + if (prepwrite(fp) != 0) return (EOF); c = (unsigned char)c; + ORIENT(fp, -1); + /* * If it is completely full, flush it out. Then, in any case, * stuff c into the buffer. If this causes the buffer to fill diff --git a/lib/libc/stdio/wprintf.3 b/lib/libc/stdio/wprintf.3 index c806f06980..d56e2458d1 100644 --- a/lib/libc/stdio/wprintf.3 +++ b/lib/libc/stdio/wprintf.3 @@ -1,5 +1,3 @@ -.\" $NetBSD: wprintf.3,v 1.2 2005/06/03 20:32:20 wiz Exp $ -.\" $DragonFly: src/lib/libc/stdio/wprintf.3,v 1.3 2007/11/04 16:23:23 swildner Exp $ .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -15,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -37,7 +31,8 @@ .\" .\" @(#)printf.3 8.1 (Berkeley) 6/4/93 .\" FreeBSD: src/lib/libc/stdio/printf.3,v 1.47 2002/09/06 11:23:55 tjr Exp -.\" $FreeBSD: src/lib/libc/stdio/wprintf.3,v 1.5 2003/07/05 07:55:34 tjr Exp $ +.\" $FreeBSD: src/lib/libc/stdio/wprintf.3,v 1.6 2007/01/09 00:28:08 imp Exp $ +.\" $DragonFly: src/lib/libc/stdio/wprintf.3,v 1.3 2007/11/04 16:23:23 swildner Exp $ .\" .Dd July 5, 2003 .Dt WPRINTF 3 diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c index 7441ab2045..776fd62896 100644 --- a/lib/libc/stdio/wprintf.c +++ b/lib/libc/stdio/wprintf.c @@ -1,6 +1,3 @@ -/* $NetBSD: wprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/wprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/wprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/wprintf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/wscanf.3 b/lib/libc/stdio/wscanf.3 index ed0f5b3381..329b57ef24 100644 --- a/lib/libc/stdio/wscanf.3 +++ b/lib/libc/stdio/wscanf.3 @@ -1,5 +1,3 @@ -.\" $NetBSD: wscanf.3,v 1.1 2005/05/14 23:51:02 christos Exp $ -.\" $DragonFly: src/lib/libc/stdio/wscanf.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ .\" Copyright (c) 1990, 1991, 1993 .\" The Regents of the University of California. All rights reserved. .\" @@ -15,10 +13,6 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed by the University of -.\" California, Berkeley and its contributors. .\" 4. Neither the name of the University nor the names of its contributors .\" may be used to endorse or promote products derived from this software .\" without specific prior written permission. @@ -37,7 +31,8 @@ .\" .\" @(#)scanf.3 8.2 (Berkeley) 12/11/93 .\" FreeBSD: src/lib/libc/stdio/scanf.3,v 1.24 2003/06/28 09:03:25 das Exp -.\" $FreeBSD: src/lib/libc/stdio/wscanf.3,v 1.6 2003/07/05 07:47:55 tjr Exp $ +.\" $FreeBSD: src/lib/libc/stdio/wscanf.3,v 1.7 2007/01/09 00:28:08 imp Exp $ +.\" $DragonFly: src/lib/libc/stdio/wscanf.3,v 1.1 2005/07/25 00:37:41 joerg Exp $ .\" .Dd July 5, 2003 .Dt WSCANF 3 diff --git a/lib/libc/stdio/wscanf.c b/lib/libc/stdio/wscanf.c index a7cf22e01c..cc33ffada6 100644 --- a/lib/libc/stdio/wscanf.c +++ b/lib/libc/stdio/wscanf.c @@ -1,6 +1,3 @@ -/* $NetBSD: wscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/wscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- * Copyright (c) 2002 Tim J. Robbins * All rights reserved. @@ -25,6 +22,9 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/wscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $ + * $DragonFly: src/lib/libc/stdio/wscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ #include diff --git a/lib/libc/stdio/wsetup.c b/lib/libc/stdio/wsetup.c index b2a209ad63..bbd4d34c93 100644 --- a/lib/libc/stdio/wsetup.c +++ b/lib/libc/stdio/wsetup.c @@ -13,10 +13,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -34,20 +30,20 @@ * SUCH DAMAGE. * * @(#)wsetup.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/wsetup.c,v 1.6 1999/08/28 00:01:22 peter Exp $ + * $FreeBSD: src/lib/libc/stdio/wsetup.c,v 1.11 2009/01/08 06:38:06 das Exp $ * $DragonFly: src/lib/libc/stdio/wsetup.c,v 1.5 2005/07/23 20:23:06 joerg Exp $ */ +#include #include #include - #include "local.h" #include "priv_stdio.h" /* * Various output routines call wsetup to be sure it is safe to write, * because either _flags does not include __SWR, or _buf is NULL. - * _wsetup returns 0 if OK to write, nonzero otherwise. + * _wsetup returns 0 if OK to write; otherwise, it returns EOF and sets errno. */ int __swsetup(FILE *fp) @@ -60,8 +56,11 @@ __swsetup(FILE *fp) * If we are not writing, we had better be reading and writing. */ if ((fp->pub._flags & __SWR) == 0) { - if ((fp->pub._flags & __SRW) == 0) + if ((fp->pub._flags & __SRW) == 0) { + errno = EBADF; + fp->pub._flags |= __SERR; return (EOF); + } if (fp->pub._flags & __SRD) { /* clobber any ungetc data */ if (HASUB(fp)) diff --git a/lib/libc/stdio/xprintf.c b/lib/libc/stdio/xprintf.c new file mode 100644 index 0000000000..98634b4c28 --- /dev/null +++ b/lib/libc/stdio/xprintf.c @@ -0,0 +1,694 @@ +/*- + * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/xprintf.c,v 1.8 2008/05/05 16:03:52 jhb Exp $ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "printf.h" +#include "priv_stdio.h" + +int __use_xprintf = -1; + +/* private stuff -----------------------------------------------------*/ + +union arg { + int intarg; + long longarg; + intmax_t intmaxarg; +#ifndef NO_FLOATING_POINT + double doublearg; + long double longdoublearg; +#endif + wint_t wintarg; + char *pchararg; + wchar_t *pwchararg; + void *pvoidarg; +}; + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) (((unsigned)to_digit(c)) <= 9) + +/* various globals ---------------------------------------------------*/ + +const char __lowercase_hex[17] = "0123456789abcdef?"; /*lint !e784 */ +const char __uppercase_hex[17] = "0123456789ABCDEF?"; /*lint !e784 */ + +#define PADSIZE 16 +static char blanks[PADSIZE] = + {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; +static char zeroes[PADSIZE] = + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + +/* printing and padding functions ------------------------------------*/ + +#define NIOV 8 + +struct __printf_io { + FILE *fp; + struct __suio uio; + struct __siov iov[NIOV]; + struct __siov *iovp; +}; + +static void +__printf_init(struct __printf_io *io) +{ + + io->uio.uio_iov = io->iovp = &io->iov[0]; + io->uio.uio_resid = 0; + io->uio.uio_iovcnt = 0; +} + +void +__printf_flush(struct __printf_io *io) +{ + + __sfvwrite(io->fp, &io->uio); + __printf_init(io); +} + +int +__printf_puts(struct __printf_io *io, const void *ptr, int len) +{ + + if (io->fp->pub._flags & __SERR) + return (0); + if (len == 0) + return (0); + io->iovp->iov_base = __DECONST(void *, ptr); + io->iovp->iov_len = len; + io->uio.uio_resid += len; + io->iovp++; + io->uio.uio_iovcnt++; + if (io->uio.uio_iovcnt >= NIOV) + __printf_flush(io); + return (len); +} + +int +__printf_pad(struct __printf_io *io, int howmany, int zero) +{ + int n; + const char *with; + int ret = 0; + + if (zero) + with = zeroes; + else + with = blanks; + + if ((n = (howmany)) > 0) { + while (n > PADSIZE) { + ret += __printf_puts(io, with, PADSIZE); + n -= PADSIZE; + } + ret += __printf_puts(io, with, n); + } + return (ret); +} + +int +__printf_out(struct __printf_io *io, const struct printf_info *pi, + const void *ptr, int len) +{ + int ret = 0; + + if ((!pi->left) && pi->width > len) + ret += __printf_pad(io, pi->width - len, pi->pad == '0'); + ret += __printf_puts(io, ptr, len); + if (pi->left && pi->width > len) + ret += __printf_pad(io, pi->width - len, pi->pad == '0'); + return (ret); +} + + +/* percent handling -------------------------------------------------*/ + +static int +__printf_arginfo_pct(const struct printf_info *pi __unused, size_t n __unused, + int *argt __unused) +{ + + return (0); +} + +static int +__printf_render_pct(struct __printf_io *io, + const struct printf_info *pi __unused, + const void *const *arg __unused) +{ + + return (__printf_puts(io, "%", 1)); +} + +/* 'n' ---------------------------------------------------------------*/ + +static int +__printf_arginfo_n(const struct printf_info *pi, size_t n, int *argt) +{ + + assert(n >= 1); + argt[0] = PA_POINTER; + return (1); +} + +/* + * This is a printf_render so that all output has been flushed before it + * gets called. + */ + +static int +__printf_render_n(FILE *io __unused, const struct printf_info *pi, + const void *const *arg) +{ + + if (pi->is_char) + **((signed char **)arg[0]) = (signed char)pi->sofar; + else if (pi->is_short) + **((short **)arg[0]) = (short)pi->sofar; + else if (pi->is_long) + **((long **)arg[0]) = pi->sofar; + else if (pi->is_long_double) + **((long long **)arg[0]) = pi->sofar; + else if (pi->is_intmax) + **((intmax_t **)arg[0]) = pi->sofar; + else if (pi->is_ptrdiff) + **((ptrdiff_t **)arg[0]) = pi->sofar; + else if (pi->is_quad) + **((quad_t **)arg[0]) = pi->sofar; + else if (pi->is_size) + **((size_t **)arg[0]) = pi->sofar; + else + **((int **)arg[0]) = pi->sofar; + + return (0); +} + +/* table -------------------------------------------------------------*/ + +/*lint -esym(785, printf_tbl) */ +static struct { + printf_arginfo_function *arginfo; + printf_function *gnurender; + printf_render *render; +} printf_tbl[256] = { + ['%'] = { __printf_arginfo_pct, NULL, __printf_render_pct }, + ['A'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['C'] = { __printf_arginfo_chr, NULL, __printf_render_chr }, + ['E'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['F'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['G'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['S'] = { __printf_arginfo_str, NULL, __printf_render_str }, + ['X'] = { __printf_arginfo_int, NULL, __printf_render_int }, + ['a'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['c'] = { __printf_arginfo_chr, NULL, __printf_render_chr }, + ['d'] = { __printf_arginfo_int, NULL, __printf_render_int }, + ['e'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['f'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['g'] = { __printf_arginfo_float, NULL, __printf_render_float }, + ['i'] = { __printf_arginfo_int, NULL, __printf_render_int }, + ['n'] = { __printf_arginfo_n, __printf_render_n, NULL }, + ['o'] = { __printf_arginfo_int, NULL, __printf_render_int }, + ['p'] = { __printf_arginfo_ptr, NULL, __printf_render_ptr }, + ['q'] = { __printf_arginfo_int, NULL, __printf_render_int }, + ['s'] = { __printf_arginfo_str, NULL, __printf_render_str }, + ['u'] = { __printf_arginfo_int, NULL, __printf_render_int }, + ['x'] = { __printf_arginfo_int, NULL, __printf_render_int }, +}; + + +static int +__v2printf(FILE *fp, const char *fmt0, unsigned pct, va_list ap) +{ + struct printf_info *pi, *pil; + const char *fmt; + int ch; + struct printf_info pia[pct + 10]; + int argt[pct + 10]; + union arg args[pct + 10]; + int nextarg; + int maxarg; + int ret = 0; + int n; + struct __printf_io io; + + __printf_init(&io); + io.fp = fp; + + fmt = fmt0; + maxarg = 0; + nextarg = 1; + memset(argt, 0, sizeof argt); + for (pi = pia; ; pi++) { + memset(pi, 0, sizeof *pi); + pil = pi; + if (*fmt == '\0') + break; + pil = pi + 1; + pi->prec = -1; + pi->pad = ' '; + pi->begin = pi->end = fmt; + while (*fmt != '\0' && *fmt != '%') + pi->end = ++fmt; + if (*fmt == '\0') + break; + fmt++; + for (;;) { + pi->spec = *fmt; + switch (pi->spec) { + case ' ': + /*- + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (pi->showsign == 0) + pi->showsign = ' '; + fmt++; + continue; + case '#': + pi->alt = 1; + fmt++; + continue; + case '.': + pi->prec = 0; + fmt++; + if (*fmt == '*') { + fmt++; + pi->get_prec = nextarg; + argt[nextarg++] = PA_INT; + continue; + } + while (*fmt != '\0' && is_digit(*fmt)) { + pi->prec *= 10; + pi->prec += to_digit(*fmt); + fmt++; + } + continue; + case '-': + pi->left = 1; + fmt++; + continue; + case '+': + pi->showsign = '+'; + fmt++; + continue; + case '*': + fmt++; + pi->get_width = nextarg; + argt[nextarg++] = PA_INT; + continue; + case '%': + fmt++; + break; + case '\'': + pi->group = 1; + fmt++; + continue; + case '0': + /*- + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + pi->pad = '0'; + fmt++; + continue; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': + n = 0; + while (*fmt != '\0' && is_digit(*fmt)) { + n *= 10; + n += to_digit(*fmt); + fmt++; + } + if (*fmt == '$') { + if (nextarg > maxarg) + maxarg = nextarg; + nextarg = n; + fmt++; + } else { + pi->width = n; + } + continue; + case 'D': + case 'O': + case 'U': + pi->spec += ('a' - 'A'); + pi->is_intmax = 0; + if (pi->is_long_double || pi->is_quad) { + pi->is_long = 0; + pi->is_long_double = 1; + } else { + pi->is_long = 1; + pi->is_long_double = 0; + } + fmt++; + break; + case 'j': + pi->is_intmax = 1; + fmt++; + continue; + case 'q': + pi->is_long = 0; + pi->is_quad = 1; + fmt++; + continue; + case 'L': + pi->is_long_double = 1; + fmt++; + continue; + case 'h': + fmt++; + if (*fmt == 'h') { + fmt++; + pi->is_char = 1; + } else { + pi->is_short = 1; + } + continue; + case 'l': + fmt++; + if (*fmt == 'l') { + fmt++; + pi->is_long_double = 1; + pi->is_quad = 0; + } else { + pi->is_quad = 0; + pi->is_long = 1; + } + continue; + case 't': + pi->is_ptrdiff = 1; + fmt++; + continue; + case 'z': + pi->is_size = 1; + fmt++; + continue; + default: + fmt++; + break; + } + if (printf_tbl[pi->spec].arginfo == NULL) + errx(1, "arginfo[%c] = NULL", pi->spec); + ch = printf_tbl[pi->spec].arginfo( + pi, __PRINTFMAXARG, &argt[nextarg]); + if (ch > 0) + pi->arg[0] = &args[nextarg]; + if (ch > 1) + pi->arg[1] = &args[nextarg + 1]; + nextarg += ch; + break; + } + } + if (nextarg > maxarg) + maxarg = nextarg; +#if 0 + fprintf(stderr, "fmt0 <%s>\n", fmt0); + fprintf(stderr, "pil %p\n", pil); +#endif + for (ch = 1; ch < maxarg; ch++) { +#if 0 + fprintf(stderr, "arg %d %x\n", ch, argt[ch]); +#endif + switch(argt[ch]) { + case PA_CHAR: + args[ch].intarg = (char)va_arg(ap, int); + break; + case PA_INT: + args[ch].intarg = va_arg(ap, int); + break; + case PA_INT | PA_FLAG_SHORT: + args[ch].intarg = (short)va_arg(ap, int); + break; + case PA_INT | PA_FLAG_LONG: + args[ch].longarg = va_arg(ap, long); + break; + case PA_INT | PA_FLAG_INTMAX: + args[ch].intmaxarg = va_arg(ap, intmax_t); + break; + case PA_INT | PA_FLAG_QUAD: + args[ch].intmaxarg = va_arg(ap, quad_t); + break; + case PA_INT | PA_FLAG_LONG_LONG: + args[ch].intmaxarg = va_arg(ap, long long); + break; + case PA_INT | PA_FLAG_SIZE: + args[ch].intmaxarg = va_arg(ap, size_t); + break; + case PA_INT | PA_FLAG_PTRDIFF: + args[ch].intmaxarg = va_arg(ap, ptrdiff_t); + break; + case PA_WCHAR: + args[ch].wintarg = va_arg(ap, wint_t); + break; + case PA_POINTER: + args[ch].pvoidarg = va_arg(ap, void *); + break; + case PA_STRING: + args[ch].pchararg = va_arg(ap, char *); + break; + case PA_WSTRING: + args[ch].pwchararg = va_arg(ap, wchar_t *); + break; + case PA_DOUBLE: +#ifndef NO_FLOATING_POINT + args[ch].doublearg = va_arg(ap, double); +#endif + break; + case PA_DOUBLE | PA_FLAG_LONG_DOUBLE: +#ifndef NO_FLOATING_POINT + args[ch].longdoublearg = va_arg(ap, long double); +#endif + break; + default: + errx(1, "argtype = %x (fmt = \"%s\")\n", + argt[ch], fmt0); + } + } + for (pi = pia; pi < pil; pi++) { +#if 0 + fprintf(stderr, "pi %p", pi); + fprintf(stderr, " spec '%c'", pi->spec); + fprintf(stderr, " args %d", + ((uintptr_t)pi->arg[0] - (uintptr_t)args) / sizeof args[0]); + if (pi->width) fprintf(stderr, " width %d", pi->width); + if (pi->pad) fprintf(stderr, " pad 0x%x", pi->pad); + if (pi->left) fprintf(stderr, " left"); + if (pi->showsign) fprintf(stderr, " showsign"); + if (pi->prec != -1) fprintf(stderr, " prec %d", pi->prec); + if (pi->is_char) fprintf(stderr, " char"); + if (pi->is_short) fprintf(stderr, " short"); + if (pi->is_long) fprintf(stderr, " long"); + if (pi->is_long_double) fprintf(stderr, " long_double"); + fprintf(stderr, "\n"); + fprintf(stderr, "\t\"%.*s\"\n", pi->end - pi->begin, pi->begin); +#endif + if (pi->get_width) { + pi->width = args[pi->get_width].intarg; + /*- + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + if (pi->width < 0) { + pi->left = 1; + pi->width = -pi->width; + } + } + if (pi->get_prec) + pi->prec = args[pi->get_prec].intarg; + ret += __printf_puts(&io, pi->begin, pi->end - pi->begin); + if (printf_tbl[pi->spec].gnurender != NULL) { + __printf_flush(&io); + pi->sofar = ret; + ret += printf_tbl[pi->spec].gnurender( + fp, pi, (const void *)pi->arg); + } else if (printf_tbl[pi->spec].render != NULL) { + pi->sofar = ret; + n = printf_tbl[pi->spec].render( + &io, pi, (const void *)pi->arg); + if (n < 0) + io.fp->pub._flags |= __SERR; + else + ret += n; + } else if (pi->begin == pi->end) + errx(1, "render[%c] = NULL", *fmt); + } + __printf_flush(&io); + return (ret); +} + +extern int __fflush(FILE *fp); + +/* + * Helper function for `fprintf to unbuffered unix file': creates a + * temporary buffer. We only work on write-only files; this avoids + * worries about ungetc buffers and so forth. + */ +static int +__v3printf(FILE *fp, const char *fmt, int pct, va_list ap) +{ + int ret; + FILE fake; + unsigned char buf[BUFSIZ]; + + /* copy the important variables */ + fake.pub._flags = fp->pub._flags & ~__SNBF; + fake.pub._fileno = fp->pub._fileno; + fake._cookie = fp->_cookie; + fake._write = fp->_write; + memcpy(WCIO_GET(&fake), WCIO_GET(fp), sizeof(struct wchar_io_data)); + + /* set up the buffer */ + fake._bf._base = fake.pub._p = buf; + fake._bf._size = fake.pub._w = sizeof(buf); + fake.pub._lbfsize = 0; /* not actually used, but Just In Case */ + + /* do the work, then copy any error status */ + ret = __v2printf(&fake, fmt, pct, ap); + if (ret >= 0 && __fflush(&fake)) + ret = EOF; + if (fake.pub._flags & __SERR) + fp->pub._flags |= __SERR; + return (ret); +} + +int +__xvprintf(FILE *fp, const char *fmt0, va_list ap) +{ + unsigned u; + const char *p; + + /* Count number of '%' signs handling double '%' signs */ + for (p = fmt0, u = 0; *p; p++) { + if (*p != '%') + continue; + u++; + if (p[1] == '%') + p++; + } + + /* optimise fprintf(stderr) (and other unbuffered Unix files) */ + if ((fp->pub._flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && + fp->pub._fileno >= 0) + return (__v3printf(fp, fmt0, u, ap)); + else + return (__v2printf(fp, fmt0, u, ap)); +} + +/* extending ---------------------------------------------------------*/ + +int +register_printf_function(int spec, printf_function *render, + printf_arginfo_function *arginfo) +{ + + if (spec > 255 || spec < 0) + return (-1); + printf_tbl[spec].gnurender = render; + printf_tbl[spec].arginfo = arginfo; + __use_xprintf = 1; + return (0); +} + +int +register_printf_render(int spec, printf_render *render, + printf_arginfo_function *arginfo) +{ + + if (spec > 255 || spec < 0) + return (-1); + printf_tbl[spec].render = render; + printf_tbl[spec].arginfo = arginfo; + __use_xprintf = 1; + return (0); +} + +int +register_printf_render_std(const unsigned char *specs) +{ + + for (; *specs != '\0'; specs++) { + switch (*specs) { + case 'H': + register_printf_render(*specs, + __printf_render_hexdump, + __printf_arginfo_hexdump); + break; + case 'M': + register_printf_render(*specs, + __printf_render_errno, + __printf_arginfo_errno); + break; + case 'Q': + register_printf_render(*specs, + __printf_render_quote, + __printf_arginfo_quote); + break; + case 'T': + register_printf_render(*specs, + __printf_render_time, + __printf_arginfo_time); + break; + case 'V': + register_printf_render(*specs, + __printf_render_vis, + __printf_arginfo_vis); + break; + default: + return (-1); + } + } + return (0); +} diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/xprintf_errno.c similarity index 61% copy from lib/libc/stdio/fwscanf.c copy to lib/libc/stdio/xprintf_errno.c index 71f4244548..ab1cd7be66 100644 --- a/lib/libc/stdio/fwscanf.c +++ b/lib/libc/stdio/xprintf_errno.c @@ -1,8 +1,5 @@ -/* $NetBSD: fwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ -/* $DragonFly: src/lib/libc/stdio/fwscanf.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c) 2002 Tim J. Robbins + * Copyright (c) 2005 Poul-Henning Kamp * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,23 +22,47 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/xprintf_errno.c,v 1.1 2006/01/25 12:45:24 phk Exp $ */ -#include +#include #include +#include +#include #include - -#include "local.h" +#include +#include +#include +#include "printf.h" int -fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) +__printf_arginfo_errno(const struct printf_info *pi __unused, size_t n, + int *argt) { - va_list ap; - int r; - va_start(ap, fmt); - r = vfwscanf(fp, fmt, ap); - va_end(ap); + assert(n >= 1); + argt[0] = PA_INT; + return (1); +} + +int +__printf_render_errno(struct __printf_io *io, + const struct printf_info *pi __unused, + const void *const *arg) +{ + int ret, error; + char buf[64]; + const char *p; - return (r); + ret = 0; + error = *((const int *)arg[0]); + if (error >= 0 && error < sys_nerr) { + p = strerror(error); + return (__printf_out(io, pi, p, strlen(p))); + } + sprintf(buf, "errno=%d/0x%x", error, error); + ret += __printf_out(io, pi, buf, strlen(buf)); + __printf_flush(io); + return(ret); } diff --git a/lib/libc/stdio/xprintf_float.c b/lib/libc/stdio/xprintf_float.c new file mode 100644 index 0000000000..90b41a790d --- /dev/null +++ b/lib/libc/stdio/xprintf_float.c @@ -0,0 +1,429 @@ +/*- + * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/xprintf_float.c,v 1.1 2005/12/16 18:56:38 phk Exp $ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include + +#define dtoa __dtoa +#define freedtoa __freedtoa + +#include +#include +#include "un-namespace.h" +#include "gdtoa.h" +#include "floatio.h" +#include "printf.h" + +/* + * The size of the buffer we use as scratch space for integer + * conversions, among other things. Technically, we would need the + * most space for base 10 conversions with thousands' grouping + * characters between each pair of digits. 100 bytes is a + * conservative overestimate even for a 128-bit uintmax_t. + */ +#define BUF 100 + +#define DEFPREC 6 /* Default FP precision */ + + +/* various globals ---------------------------------------------------*/ + + +/* padding function---------------------------------------------------*/ + +#define PRINTANDPAD(p, ep, len, with) do { \ + n2 = (ep) - (p); \ + if (n2 > (len)) \ + n2 = (len); \ + if (n2 > 0) \ + ret += __printf_puts(io, (p), n2); \ + ret += __printf_pad(io, (len) - (n2 > 0 ? n2 : 0), (with)); \ +} while(0) + +/* misc --------------------------------------------------------------*/ + +#define to_char(n) ((n) + '0') + +static int +exponent(char *p0, int expo, int fmtch) +{ + char *p, *t; + char expbuf[MAXEXPDIG]; + + p = p0; + *p++ = fmtch; + if (expo < 0) { + expo = -expo; + *p++ = '-'; + } else { + *p++ = '+'; + } + t = expbuf + MAXEXPDIG; + if (expo > 9) { + do { + *--t = to_char(expo % 10); + } while ((expo /= 10) > 9); + *--t = to_char(expo); + for (; t < expbuf + MAXEXPDIG; *p++ = *t++) + ; + } else { + /* + * Exponents for decimal floating point conversions + * (%[eEgG]) must be at least two characters long, + * whereas exponents for hexadecimal conversions can + * be only one character long. + */ + if (fmtch == 'e' || fmtch == 'E') + *p++ = '0'; + *p++ = to_char(expo); + } + return (p - p0); +} + +/* 'f' ---------------------------------------------------------------*/ + +int +__printf_arginfo_float(const struct printf_info *pi, size_t n, int *argt) +{ + assert (n > 0); + argt[0] = PA_DOUBLE; + if (pi->is_long_double) + argt[0] |= PA_FLAG_LONG_DOUBLE; + return (1); +} + +/* + * We can decompose the printed representation of floating + * point numbers into several parts, some of which may be empty: + * + * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ + * A B ---C--- D E F + * + * A: 'sign' holds this value if present; '\0' otherwise + * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal + * C: cp points to the string MMMNNN. Leading and trailing + * zeroes are not in the string and must be added. + * D: expchar holds this character; '\0' if no exponent, e.g. %f + * F: at least two digits for decimal, at least one digit for hex + */ + +int +__printf_render_float(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + int prec; /* precision from format; <0 for N/A */ + char *dtoaresult; /* buffer allocated by dtoa */ + char expchar; /* exponent character: [eEpP\0] */ + char *cp; + int expt; /* integer value of exponent */ + int signflag; /* true if float is negative */ + char *dtoaend; /* pointer to end of converted digits */ + char sign; /* sign prefix (' ', '+', '-', or \0) */ + int size; /* size of converted field or string */ + int ndig; /* actual number of digits returned by dtoa */ + int expsize; /* character count for expstr */ + char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ + int nseps; /* number of group separators with ' */ + int nrepeats; /* number of repeats of the last group */ + const char *grouping; /* locale specific numeric grouping rules */ + int lead; /* sig figs before decimal or group sep */ + long double ld; + double d; + int realsz; /* field size expanded by dprec, sign, etc */ + int dprec; /* a copy of prec if [diouxX], 0 otherwise */ + char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */ + int prsize; /* max size of printed field */ + int ret; /* return value accumulator */ + char *decimal_point; /* locale specific decimal point */ + int n2; /* XXX: for PRINTANDPAD */ + char thousands_sep; /* locale specific thousands separator */ + char buf[BUF]; /* buffer with space for digits of uintmax_t */ + const char *xdigs; + int flag; + + prec = pi->prec; + ox[1] = '\0'; + sign = pi->showsign; + flag = 0; + ret = 0; + + thousands_sep = *(localeconv()->thousands_sep); + grouping = NULL; + if (pi->alt) + grouping = localeconv()->grouping; + decimal_point = localeconv()->decimal_point; + dprec = -1; + + switch(pi->spec) { + case 'a': + case 'A': + if (pi->spec == 'a') { + ox[1] = 'x'; + xdigs = __lowercase_hex; + expchar = 'p'; + } else { + ox[1] = 'X'; + xdigs = __uppercase_hex; + expchar = 'P'; + } + if (prec >= 0) + prec++; + if (pi->is_long_double) { + ld = *((long double *)arg[0]); + dtoaresult = cp = + __hldtoa(ld, xdigs, prec, + &expt, &signflag, &dtoaend); + } else { + d = *((double *)arg[0]); + dtoaresult = cp = + __hdtoa(d, xdigs, prec, + &expt, &signflag, &dtoaend); + } + if (prec < 0) + prec = dtoaend - cp; + if (expt == INT_MAX) + ox[1] = '\0'; + goto fp_common; + case 'e': + case 'E': + expchar = pi->spec; + if (prec < 0) /* account for digit before decpt */ + prec = DEFPREC + 1; + else + prec++; + break; + case 'f': + case 'F': + expchar = '\0'; + break; + case 'g': + case 'G': + expchar = pi->spec - ('g' - 'e'); + if (prec == 0) + prec = 1; + break; + default: + assert(pi->spec == 'f'); + } + + if (prec < 0) + prec = DEFPREC; + if (pi->is_long_double) { + ld = *((long double *)arg[0]); + dtoaresult = cp = + __ldtoa(&ld, expchar ? 2 : 3, prec, + &expt, &signflag, &dtoaend); + } else { + d = *((double *)arg[0]); + dtoaresult = cp = + dtoa(d, expchar ? 2 : 3, prec, + &expt, &signflag, &dtoaend); + if (expt == 9999) + expt = INT_MAX; + } +fp_common: + if (signflag) + sign = '-'; + if (expt == INT_MAX) { /* inf or nan */ + if (*cp == 'N') { + cp = (pi->spec >= 'a') ? "nan" : "NAN"; + sign = '\0'; + } else { + cp = (pi->spec >= 'a') ? "inf" : "INF"; + } + size = 3; + flag = 1; + goto here; + } + ndig = dtoaend - cp; + if (pi->spec == 'g' || pi->spec == 'G') { + if (expt > -4 && expt <= prec) { + /* Make %[gG] smell like %[fF] */ + expchar = '\0'; + if (pi->alt) + prec -= expt; + else + prec = ndig - expt; + if (prec < 0) + prec = 0; + } else { + /* + * Make %[gG] smell like %[eE], but + * trim trailing zeroes if no # flag. + */ + if (!pi->alt) + prec = ndig; + } + } + if (expchar) { + expsize = exponent(expstr, expt - 1, expchar); + size = expsize + prec; + if (prec > 1 || pi->alt) + ++size; + } else { + /* space for digits before decimal point */ + if (expt > 0) + size = expt; + else /* "0" */ + size = 1; + /* space for decimal pt and following digits */ + if (prec || pi->alt) + size += prec + 1; + if (grouping && expt > 0) { + /* space for thousands' grouping */ + nseps = nrepeats = 0; + lead = expt; + while (*grouping != CHAR_MAX) { + if (lead <= *grouping) + break; + lead -= *grouping; + if (*(grouping+1)) { + nseps++; + grouping++; + } else { + nrepeats++; + } + } + size += nseps + nrepeats; + } else { + lead = expt; + } + } + +here: + /* + * All reasonable formats wind up here. At this point, `cp' + * points to a string which (if not flags&LADJUST) should be + * padded out to `width' places. If flags&ZEROPAD, it should + * first be prefixed by any sign or other prefix; otherwise, + * it should be blank padded before the prefix is emitted. + * After any left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print the + * string proper, then emit zeroes required by any leftover + * floating precision; finally, if LADJUST, pad with blanks. + * + * Compute actual size, so we know how much to pad. + * size excludes decimal prec; realsz includes it. + */ + realsz = dprec > size ? dprec : size; + if (sign) + realsz++; + if (ox[1]) + realsz += 2; + + prsize = pi->width > realsz ? pi->width : realsz; + + /* right-adjusting blank padding */ + if (pi->pad != '0' && pi->left == 0) + ret += __printf_pad(io, pi->width - realsz, 0); + + /* prefix */ + if (sign) + ret += __printf_puts(io, &sign, 1); + + if (ox[1]) { /* ox[1] is either x, X, or \0 */ + ox[0] = '0'; + ret += __printf_puts(io, ox, 2); + } + + /* right-adjusting zero padding */ + if (pi->pad == '0' && pi->left == 0) + ret += __printf_pad(io, pi->width - realsz, 1); + + /* leading zeroes from decimal precision */ + ret += __printf_pad(io, dprec - size, 1); + + if (flag) { + ret += __printf_puts(io, cp, size); + } else { + /* glue together f_p fragments */ + if (!expchar) { /* %[fF] or sufficiently short %[gG] */ + if (expt <= 0) { + ret += __printf_puts(io, "0", 1); + if (prec || pi->alt) + ret += __printf_puts(io, decimal_point, 1); + ret += __printf_pad(io, -expt, 1); + /* already handled initial 0's */ + prec += expt; + } else { + PRINTANDPAD(cp, dtoaend, lead, 1); + cp += lead; + if (grouping) { + while (nseps>0 || nrepeats>0) { + if (nrepeats > 0) { + nrepeats--; + } else { + grouping--; + nseps--; + } + ret += __printf_puts(io, &thousands_sep, 1); + PRINTANDPAD(cp,dtoaend, + *grouping, 1); + cp += *grouping; + } + if (cp > dtoaend) + cp = dtoaend; + } + if (prec || pi->alt) + ret += __printf_puts(io, decimal_point,1); + } + PRINTANDPAD(cp, dtoaend, prec, 1); + } else { /* %[eE] or sufficiently long %[gG] */ + if (prec > 1 || pi->alt) { + buf[0] = *cp++; + buf[1] = *decimal_point; + ret += __printf_puts(io, buf, 2); + ret += __printf_puts(io, cp, ndig-1); + ret += __printf_pad(io, prec - ndig, 1); + } else { /* XeYYY */ + ret += __printf_puts(io, cp, 1); + } + ret += __printf_puts(io, expstr, expsize); + } + } + /* left-adjusting padding (always blank) */ + if (pi->left) + ret += __printf_pad(io, pi->width - realsz, 0); + + __printf_flush(io); + if (dtoaresult != NULL) + freedtoa(dtoaresult); + + return (ret); +} diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/xprintf_hexdump.c similarity index 53% copy from lib/libc/stdio/fgetws.c copy to lib/libc/stdio/xprintf_hexdump.c index 95a8560578..32d235d630 100644 --- a/lib/libc/stdio/fgetws.c +++ b/lib/libc/stdio/xprintf_hexdump.c @@ -1,8 +1,5 @@ -/* $NetBSD: fgetws.c,v 1.1 2003/03/07 07:11:37 tshiozak Exp $ */ -/* $DragonFly: src/lib/libc/stdio/fgetws.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c) 2002 Tim J. Robbins. + * Copyright (c) 2005 Poul-Henning Kamp * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,63 +23,77 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Original version ID: - * FreeBSD: src/lib/libc/stdio/fgetws.c,v 1.4 2002/09/20 13:25:40 tjr Exp - * + * $FreeBSD: src/lib/libc/stdio/xprintf_hexdump.c,v 1.1 2005/12/16 18:56:38 phk Exp $ */ #include "namespace.h" -#include -#include #include #include +#include +#include +#include #include "un-namespace.h" +#include "printf.h" -#include "libc_private.h" -#include "local.h" -#include "priv_stdio.h" - -wchar_t * -fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) +int +__printf_arginfo_hexdump(const struct printf_info *pi, size_t n, int *argt) { - wchar_t *wsp; - wint_t wc; - _DIAGASSERT(fp != NULL); - _DIAGASSERT(ws != NULL); + assert(n >= 2); + argt[0] = PA_POINTER; + argt[1] = PA_INT; + return (2); +} - FLOCKFILE(fp); - _SET_ORIENTATION(fp, 1); +int +__printf_render_hexdump(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + unsigned char *p; + unsigned u, l, j, a; + char buf[100], *q; + int ret; - if (n <= 0) { - errno = EINVAL; - goto error; - } + if (pi->width > 0 && pi->width < 16) + l = pi->width; + else + l = 16; + p = *((unsigned char **)arg[0]); + u = *((unsigned *)arg[1]); - wsp = ws; - while (n-- > 1) { - if ((wc = __fgetwc_unlock(fp)) == WEOF && errno == EILSEQ) { - goto error; - } - if (wc == WEOF) { - if (wsp == ws) { - /* EOF/error, no characters read yet. */ - goto error; + ret = 0; + a = 0; + while (u > 0) { + q = buf; + if (pi->showsign) + q += sprintf(q, " %04x", a); + for (j = 0; j < l && j < u; j++) + q += sprintf(q, " %02x", p[j]); + if (pi->alt) { + for (; j < l; j++) + q += sprintf(q, " "); + q += sprintf(q, " |"); + for (j = 0; j < l && j < u; j++) { + if (p[j] < ' ' || p[j] > '~') + *q++ = '.'; + else + *q++ = p[j]; } - break; - } - *wsp++ = (wchar_t)wc; - if (wc == L'\n') { - break; + for (; j < l; j++) + *q++ = ' '; + *q++ = '|'; } + if (l < u) + j = l; + else + j = u; + p += j; + u -= j; + a += j; + if (u > 0) + *q++ = '\n'; + ret += __printf_puts(io, buf + 1, q - (buf + 1)); + __printf_flush(io); } - - *wsp++ = L'\0'; - FUNLOCKFILE(fp); - - return (ws); - -error: - FUNLOCKFILE(fp); - return (NULL); + return (ret); } diff --git a/lib/libc/stdio/xprintf_int.c b/lib/libc/stdio/xprintf_int.c new file mode 100644 index 0000000000..89cba34bcb --- /dev/null +++ b/lib/libc/stdio/xprintf_int.c @@ -0,0 +1,478 @@ +/*- + * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/xprintf_int.c,v 1.2 2005/12/22 14:23:54 cognet Exp $ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "printf.h" + +/* private stuff -----------------------------------------------------*/ + +union arg { + int intarg; + u_int uintarg; + long longarg; + u_long ulongarg; + intmax_t intmaxarg; + uintmax_t uintmaxarg; +}; + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_char(n) ((n) + '0') + +/* various globals ---------------------------------------------------*/ + +/* + * The size of the buffer we use for integer conversions. + * Technically, we would need the most space for base 10 + * conversions with thousands' grouping characters between + * each pair of digits: 60 digits for 128 bit intmax_t. + * Use a bit more for better alignment of stuff. + */ +#define BUF 64 + +/* misc --------------------------------------------------------------*/ + +/* + * Convert an unsigned long to ASCII for printf purposes, returning + * a pointer to the first character of the string representation. + * Octal numbers can be forced to have a leading zero; hex numbers + * use the given digits. + */ +static char * +__ultoa(u_long val, char *endp, int base, const char *xdigs, + int needgrp, char thousep, const char *grp) +{ + char *cp = endp; + long sval; + int ndig; + + /* + * Handle the three cases separately, in the hope of getting + * better/faster code. + */ + switch (base) { + case 10: + if (val < 10) { /* many numbers are 1 digit */ + *--cp = to_char(val); + return (cp); + } + ndig = 0; + /* + * On many machines, unsigned arithmetic is harder than + * signed arithmetic, so we do at most one unsigned mod and + * divide; this is sufficient to reduce the range of + * the incoming value to where signed arithmetic works. + */ + if (val > LONG_MAX) { + *--cp = to_char(val % 10); + ndig++; + sval = val / 10; + } else { + sval = val; + } + do { + *--cp = to_char(sval % 10); + ndig++; + /* + * If (*grp == CHAR_MAX) then no more grouping + * should be performed. + */ + if (needgrp && ndig == *grp && *grp != CHAR_MAX + && sval > 9) { + *--cp = thousep; + ndig = 0; + /* + * If (*(grp+1) == '\0') then we have to + * use *grp character (last grouping rule) + * for all next cases + */ + if (*(grp+1) != '\0') + grp++; + } + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: /* oops */ + assert(base == 16); + } + return (cp); +} + + +/* Identical to __ultoa, but for intmax_t. */ +static char * +__ujtoa(uintmax_t val, char *endp, int base, const char *xdigs, + int needgrp, char thousep, const char *grp) +{ + char *cp = endp; + intmax_t sval; + int ndig; + + switch (base) { + case 10: + if (val < 10) { + *--cp = to_char(val % 10); + return (cp); + } + ndig = 0; + if (val > INTMAX_MAX) { + *--cp = to_char(val % 10); + ndig++; + sval = val / 10; + } else { + sval = val; + } + do { + *--cp = to_char(sval % 10); + ndig++; + /* + * If (*grp == CHAR_MAX) then no more grouping + * should be performed. + */ + if (needgrp && *grp != CHAR_MAX && ndig == *grp + && sval > 9) { + *--cp = thousep; + ndig = 0; + /* + * If (*(grp+1) == '\0') then we have to + * use *grp character (last grouping rule) + * for all next cases + */ + if (*(grp+1) != '\0') + grp++; + } + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + break; + + case 16: + do { + *--cp = xdigs[val & 15]; + val >>= 4; + } while (val); + break; + + default: + abort(); + } + return (cp); +} + + +/* 'd' ---------------------------------------------------------------*/ + +int +__printf_arginfo_int(const struct printf_info *pi, size_t n, int *argt) +{ + assert (n > 0); + argt[0] = PA_INT; + if (pi->is_ptrdiff) + argt[0] |= PA_FLAG_PTRDIFF; + else if (pi->is_size) + argt[0] |= PA_FLAG_SIZE; + else if (pi->is_long) + argt[0] |= PA_FLAG_LONG; + else if (pi->is_intmax) + argt[0] |= PA_FLAG_INTMAX; + else if (pi->is_quad) + argt[0] |= PA_FLAG_QUAD; + else if (pi->is_long_double) + argt[0] |= PA_FLAG_LONG_LONG; + else if (pi->is_short) + argt[0] |= PA_FLAG_SHORT; + else if (pi->is_char) + argt[0] = PA_CHAR; + return (1); +} + +int +__printf_render_int(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + const union arg *argp; + char buf[BUF]; + char *p, *pe; + char ns, l; + int rdx, sign, zext, ngrp; + const char *nalt, *digit; + char thousands_sep; /* locale specific thousands separator */ + const char *grouping; /* locale specific numeric grouping rules */ + uintmax_t uu; + int ret; + + ret = 0; + nalt = NULL; + digit = __lowercase_hex; + ns = '\0'; + pe = buf + sizeof buf - 1; + + if (pi->group) { + thousands_sep = *(localeconv()->thousands_sep); + grouping = localeconv()->grouping; + ngrp = 1; + } else { + thousands_sep = 0; + grouping = NULL; + ngrp = 0; + } + + switch(pi->spec) { + case 'd': + case 'i': + rdx = 10; + sign = 1; + break; + case 'X': + digit = __uppercase_hex; + /*FALLTHOUGH*/ + case 'x': + rdx = 16; + sign = 0; + break; + case 'u': + case 'U': + rdx = 10; + sign = 0; + break; + case 'o': + case 'O': + rdx = 8; + sign = 0; + break; + default: + fprintf(stderr, "pi->spec = '%c'\n", pi->spec); + assert(1 == 0); + } + argp = arg[0]; + + if (sign) + ns = pi->showsign; + + if (pi->is_long_double || pi->is_quad || pi->is_intmax || + pi->is_size || pi->is_ptrdiff) { + if (sign && argp->intmaxarg < 0) { + uu = -argp->intmaxarg; + ns = '-'; + } else { + uu = argp->uintmaxarg; + } + } else if (pi->is_long) { + if (sign && argp->longarg < 0) { + uu = (u_long)-argp->longarg; + ns = '-'; + } else { + uu = argp->ulongarg; + } + } else if (pi->is_short) { + if (sign && (short)argp->intarg < 0) { + uu = -(short)argp->intarg; + ns = '-'; + } else { + uu = (unsigned short)argp->uintarg; + } + } else if (pi->is_char) { + if (sign && (signed char)argp->intarg < 0) { + uu = -(signed char)argp->intarg; + ns = '-'; + } else { + uu = (unsigned char)argp->uintarg; + } + } else { + if (sign && argp->intarg < 0) { + uu = (unsigned)-argp->intarg; + ns = '-'; + } else { + uu = argp->uintarg; + } + } + if (uu <= ULONG_MAX) + p = __ultoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping); + else + p = __ujtoa(uu, pe, rdx, digit, ngrp, thousands_sep, grouping); + + l = 0; + if (uu == 0) { + /*- + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + * + * ``The C Standard is clear enough as is. The call + * printf("%#.0o", 0) should print 0.'' + * -- Defect Report #151 + */ + if (pi->prec == 0 && !(pi->alt && rdx == 8)) + p = pe; + } else if (pi->alt) { + if (rdx == 8) + *--p = '0'; + if (rdx == 16) { + if (pi->spec == 'x') + nalt = "0x"; + else + nalt = "0X"; + l += 2; + } + } + l += pe - p; + if (ns) + l++; + + /*- + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ + if (pi->prec > (pe - p)) + zext = pi->prec - (pe - p); + else if (pi->prec != -1) + zext = 0; + else if (pi->pad == '0' && pi->width > l && !pi->left) + zext = pi->width - l; + else + zext = 0; + + l += zext; + + while (zext > 0 && p > buf) { + *--p = '0'; + zext--; + } + + if (l < BUF) { + if (ns) { + *--p = ns; + } else if (nalt != NULL) { + *--p = nalt[1]; + *--p = nalt[0]; + } + if (pi->width > (pe - p) && !pi->left) { + l = pi->width - (pe - p); + while (l > 0 && p > buf) { + *--p = ' '; + l--; + } + if (l) + ret += __printf_pad(io, l, 0); + } + } else { + if (!pi->left && pi->width > l) + ret += __printf_pad(io, pi->width - l, 0); + if (ns != '\0') + ret += __printf_puts(io, &ns, 1); + else if (nalt != NULL) + ret += __printf_puts(io, nalt, 2); + if (zext > 0) + ret += __printf_pad(io, zext, 1); + } + + ret += __printf_puts(io, p, pe - p); + if (pi->width > ret && pi->left) + ret += __printf_pad(io, pi->width - ret, 0); + __printf_flush(io); + return (ret); +} + +/* 'p' ---------------------------------------------------------------*/ + +int +__printf_arginfo_ptr(const struct printf_info *pi __unused, size_t n, int *argt) +{ + + assert (n > 0); + argt[0] = PA_POINTER; + return (1); +} + +int +__printf_render_ptr(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + struct printf_info p2; + uintmax_t u; + const void *p; + + /*- + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + u = (uintmax_t)(uintptr_t) *((void **)arg[0]); + p2 = *pi; + + p2.spec = 'x'; + p2.alt = 1; + p2.is_long_double = 1; + p = &u; + return (__printf_render_int(io, &p2, &p)); +} diff --git a/lib/libc/stdio/xprintf_quote.c b/lib/libc/stdio/xprintf_quote.c new file mode 100644 index 0000000000..301cca6884 --- /dev/null +++ b/lib/libc/stdio/xprintf_quote.c @@ -0,0 +1,103 @@ +/*- + * Copyright (c) 2005 Poul-Henning Kamp + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/xprintf_quote.c,v 1.2 2006/03/02 08:53:45 phk Exp $ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" +#include "printf.h" + +int +__printf_arginfo_quote(const struct printf_info *pi __unused, size_t n, + int *argt) +{ + + assert(n >= 1); + argt[0] = PA_POINTER; + return (1); +} + +int +__printf_render_quote(struct __printf_io *io, + const struct printf_info *pi __unused, + const void *const *arg) +{ + const char *str, *p, *t, *o; + char r[5]; + int i, ret; + + str = *((const char *const *)arg[0]); + if (str == NULL) + return (__printf_out(io, pi, "\"(null)\"", 8)); + if (*str == '\0') + return (__printf_out(io, pi, "\"\"", 2)); + + for (i = 0, p = str; *p; p++) + if (isspace(*p) || *p == '\\' || *p == '"') + i++; + if (!i) + return (__printf_out(io, pi, str, strlen(str))); + + ret = __printf_out(io, pi, "\"", 1); + for (t = p = str; *p; p++) { + o = NULL; + if (*p == '\\') + o = "\\\\"; + else if (*p == '\n') + o = "\\n"; + else if (*p == '\r') + o = "\\r"; + else if (*p == '\t') + o = "\\t"; + else if (*p == ' ') + o = " "; + else if (*p == '"') + o = "\\\""; + else if (isspace(*p)) { + sprintf(r, "\\%03o", *p); + o = r; + } else { + continue; + } + if (p != t) + ret += __printf_out(io, pi, t, p - t); + ret += __printf_out(io, pi, o, strlen(o)); + t = p + 1; + } + if (p != t) + ret += __printf_out(io, pi, t, p - t); + ret += __printf_out(io, pi, "\"", 1); + __printf_flush(io); + return(ret); +} diff --git a/lib/libc/stdio/xprintf_str.c b/lib/libc/stdio/xprintf_str.c new file mode 100644 index 0000000000..4031f0feb6 --- /dev/null +++ b/lib/libc/stdio/xprintf_str.c @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2005 Poul-Henning Kamp + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/lib/libc/stdio/xprintf_str.c,v 1.1 2005/12/16 18:56:38 phk Exp $ + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" +#include "printf.h" + +/* + * Convert a wide character string argument for the %ls format to a multibyte + * string representation. If not -1, prec specifies the maximum number of + * bytes to output, and also means that we can't assume that the wide char. + * string ends is null-terminated. + */ +static char * +__wcsconv(wchar_t *wcsarg, int prec) +{ + static const mbstate_t initial; + mbstate_t mbs; + char buf[MB_LEN_MAX]; + wchar_t *p; + char *convbuf; + size_t clen, nbytes; + + /* Allocate space for the maximum number of bytes we could output. */ + if (prec < 0) { + p = wcsarg; + mbs = initial; + nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs); + if (nbytes == (size_t)-1) + return (NULL); + } else { + /* + * Optimisation: if the output precision is small enough, + * just allocate enough memory for the maximum instead of + * scanning the string. + */ + if (prec < 128) + nbytes = prec; + else { + nbytes = 0; + p = wcsarg; + mbs = initial; + for (;;) { + clen = wcrtomb(buf, *p++, &mbs); + if (clen == 0 || clen == (size_t)-1 || + (int)(nbytes + clen) > prec) + break; + nbytes += clen; + } + } + } + if ((convbuf = malloc(nbytes + 1)) == NULL) + return (NULL); + + /* Fill the output buffer. */ + p = wcsarg; + mbs = initial; + if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, + nbytes, &mbs)) == (size_t)-1) { + free(convbuf); + return (NULL); + } + convbuf[nbytes] = '\0'; + return (convbuf); +} + + +/* 's' ---------------------------------------------------------------*/ + +int +__printf_arginfo_str(const struct printf_info *pi, size_t n, int *argt) +{ + + assert (n > 0); + if (pi->is_long || pi->spec == 'C') + argt[0] = PA_WSTRING; + else + argt[0] = PA_STRING; + return (1); +} + +int +__printf_render_str(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + const char *p; + wchar_t *wcp; + char *convbuf; + int l; + + if (pi->is_long || pi->spec == 'S') { + wcp = *((wint_t **)arg[0]); + if (wcp == NULL) + return (__printf_out(io, pi, "(null)", 6)); + convbuf = __wcsconv(wcp, pi->prec); + if (convbuf == NULL) + return (-1); + l = __printf_out(io, pi, convbuf, strlen(convbuf)); + free(convbuf); + return (l); + } + p = *((char **)arg[0]); + if (p == NULL) + return (__printf_out(io, pi, "(null)", 6)); + l = strlen(p); + if (pi->prec >= 0 && pi->prec < l) + l = pi->prec; + return (__printf_out(io, pi, p, l)); +} + +/* 'c' ---------------------------------------------------------------*/ + +int +__printf_arginfo_chr(const struct printf_info *pi, size_t n, int *argt) +{ + + assert (n > 0); + if (pi->is_long || pi->spec == 'C') + argt[0] = PA_WCHAR; + else + argt[0] = PA_INT; + return (1); +} + +int +__printf_render_chr(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + int i; + wint_t ii; + unsigned char c; + static const mbstate_t initial; /* XXX: this is bogus! */ + mbstate_t mbs; + size_t mbseqlen; + char buf[MB_CUR_MAX]; + + if (pi->is_long || pi->spec == 'C') { + ii = *((wint_t *)arg[0]); + + mbs = initial; + mbseqlen = wcrtomb(buf, (wchar_t)ii, &mbs); + if (mbseqlen == (size_t) -1) + return (-1); + return (__printf_out(io, pi, buf, mbseqlen)); + } + i = *((int *)arg[0]); + c = i; + i = __printf_out(io, pi, &c, 1); + __printf_flush(io); + return (i); +} diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/xprintf_time.c similarity index 50% copy from lib/libc/stdio/getc.c copy to lib/libc/stdio/xprintf_time.c index e2853b3249..f8711532e5 100644 --- a/lib/libc/stdio/getc.c +++ b/lib/libc/stdio/xprintf_time.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2005 Poul-Henning Kamp * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * @@ -13,11 +14,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -33,30 +30,89 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)getc.c 8.1 (Berkeley) 6/4/93 - * $FreeBSD: src/lib/libc/stdio/getc.c,v 1.7.2.1 2001/03/05 11:27:49 obrien Exp $ - * $DragonFly: src/lib/libc/stdio/getc.c,v 1.4 2005/08/27 21:35:01 joerg Exp $ + * $FreeBSD: src/lib/libc/stdio/xprintf_time.c,v 1.3 2006/02/04 14:35:01 phk Exp $ */ #include "namespace.h" #include +#include +#include +#include +#include #include "un-namespace.h" -#include "libc_private.h" - -#undef getc_unlocked +#include "printf.h" int -getc(FILE *fp) +__printf_arginfo_time(const struct printf_info *pi, size_t n, int *argt) { - int retval; - FLOCKFILE(fp); - retval = __sgetc(fp); - FUNLOCKFILE(fp); - return (retval); + + assert(n >= 1); + argt[0] = PA_POINTER; + return (1); } +#define MINUTE 60 +#define HOUR (60 * MINUTE) +#define DAY (24 * HOUR) +#define YEAR (365 * DAY) int -getc_unlocked(FILE *fp) +__printf_render_time(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) { - return(__sgetc(fp)); + char buf[100]; + char *p; + struct timeval *tv; + struct timespec *ts; + time_t *tp; + intmax_t t, tx; + int i, prec, nsec; + + prec = 0; + if (pi->is_long) { + tv = *((struct timeval **)arg[0]); + t = tv->tv_sec; + nsec = tv->tv_usec * 1000; + prec = 6; + } else if (pi->is_long_double) { + ts = *((struct timespec **)arg[0]); + t = ts->tv_sec; + nsec = ts->tv_nsec; + prec = 9; + } else { + tp = *((time_t **)arg[0]); + t = *tp; + } + + p = buf; + if (pi->alt) { + tx = t; + if (t >= YEAR) { + p += sprintf(p, "%jdy", t / YEAR); + t %= YEAR; + } + if (t >= DAY && t != 0) { + p += sprintf(p, "%jdd", t / DAY); + t %= DAY; + } + if (t >= HOUR && t != 0) { + p += sprintf(p, "%jdh", t / HOUR); + t %= HOUR; + } + if (t >= MINUTE && t != 0) { + p += sprintf(p, "%jdm", t / MINUTE); + t %= MINUTE; + } + if (t != 0 || tx == 0) + p += sprintf(p, "%jds", t); + } else { + p += sprintf(p, "%jd", (intmax_t)t); + } + if (pi->is_long || pi->is_long_double) { + if (pi->prec >= 0) + prec = pi->prec; + for (i = prec; i < 9; i++) + nsec /= 10; + p += sprintf(p, ".%.*d", prec, nsec); + } + return(__printf_out(io, pi, buf, p - buf)); } diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/xprintf_vis.c similarity index 57% copy from lib/libc/stdio/fgetws.c copy to lib/libc/stdio/xprintf_vis.c index 95a8560578..b3f8157959 100644 --- a/lib/libc/stdio/fgetws.c +++ b/lib/libc/stdio/xprintf_vis.c @@ -1,8 +1,5 @@ -/* $NetBSD: fgetws.c,v 1.1 2003/03/07 07:11:37 tshiozak Exp $ */ -/* $DragonFly: src/lib/libc/stdio/fgetws.c,v 1.1 2005/07/25 00:37:41 joerg Exp $ */ - /*- - * Copyright (c) 2002 Tim J. Robbins. + * Copyright (c) 2005 Poul-Henning Kamp * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,63 +23,58 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * Original version ID: - * FreeBSD: src/lib/libc/stdio/fgetws.c,v 1.4 2002/09/20 13:25:40 tjr Exp - * + * $FreeBSD: src/lib/libc/stdio/xprintf_vis.c,v 1.2 2006/01/25 12:45:24 phk Exp $ */ #include "namespace.h" -#include -#include #include +#include +#include #include +#include +#include +#include #include "un-namespace.h" +#include "printf.h" -#include "libc_private.h" -#include "local.h" -#include "priv_stdio.h" - -wchar_t * -fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) +int +__printf_arginfo_vis(const struct printf_info *pi, size_t n, int *argt) { - wchar_t *wsp; - wint_t wc; - - _DIAGASSERT(fp != NULL); - _DIAGASSERT(ws != NULL); - FLOCKFILE(fp); - _SET_ORIENTATION(fp, 1); - - if (n <= 0) { - errno = EINVAL; - goto error; - } - - wsp = ws; - while (n-- > 1) { - if ((wc = __fgetwc_unlock(fp)) == WEOF && errno == EILSEQ) { - goto error; - } - if (wc == WEOF) { - if (wsp == ws) { - /* EOF/error, no characters read yet. */ - goto error; - } - break; - } - *wsp++ = (wchar_t)wc; - if (wc == L'\n') { - break; - } - } - - *wsp++ = L'\0'; - FUNLOCKFILE(fp); + assert(n >= 1); + argt[0] = PA_POINTER; + return (1); +} - return (ws); +int +__printf_render_vis(struct __printf_io *io, const struct printf_info *pi, + const void *const *arg) +{ + char *p, *buf; + unsigned l; + int ret; -error: - FUNLOCKFILE(fp); - return (NULL); + ret = 0; + p = *((char **)arg[0]); + if (p == NULL) + return (__printf_out(io, pi, "(null)", 6)); + if (pi->prec >= 0) + l = pi->prec; + else + l = strlen(p); + buf = malloc(l * 4 + 1); + if (buf == NULL) + return (-1); + if (pi->showsign) + ret = strvisx(buf, p, l, VIS_WHITE | VIS_HTTPSTYLE); + else if (pi->pad == '0') + ret = strvisx(buf, p, l, VIS_WHITE | VIS_OCTAL); + else if (pi->alt) + ret = strvisx(buf, p, l, VIS_WHITE); + else + ret = strvisx(buf, p, l, VIS_WHITE | VIS_CSTYLE | VIS_OCTAL); + ret += __printf_out(io, pi, buf, ret); + __printf_flush(io); + free(buf); + return(ret); } diff --git a/sys/sys/cdefs.h b/sys/sys/cdefs.h index 547399063c..f6d72a4d6d 100644 --- a/sys/sys/cdefs.h +++ b/sys/sys/cdefs.h @@ -176,8 +176,10 @@ #if __GNUC_PREREQ__(3, 1) #define __always_inline __attribute__((__always_inline__)) +#define __noinline __attribute__((__noinline__)) #else #define __always_inline +#define __noinline #endif #if __GNUC_PREREQ__(3, 3) @@ -261,6 +263,7 @@ #define __printflike(fmtarg, firstvararg) #define __scanflike(fmtarg, firstvararg) #define __printf0like(fmtarg, firstvararg) +#define __format_arg(fmtarg) #elif __GNUC_PREREQ__(3, 0) #define __printflike(fmtarg, firstvararg) \ __attribute__((__nonnull__(fmtarg), \ @@ -269,6 +272,8 @@ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #define __scanflike(fmtarg, firstvararg) \ __attribute__((__format__ (__scanf__, fmtarg, firstvararg))) +#define __format_arg(fmtarg) \ + __attribute__((__format_arg__ (fmtarg))) #else #define __printflike(fmtarg, firstvararg) \ @@ -277,6 +282,9 @@ __attribute__((__format__ (__printf0__, fmtarg, firstvararg))) #define __scanflike(fmtarg, firstvararg) \ __attribute__((__format__ (__scanf__, fmtarg, firstvararg))) +#define __format_arg(fmtarg) \ + __attribute__((__format_arg__ (fmtarg))) + #endif #if !__GNUC_PREREQ__(3, 0) -- 2.41.0