diff options
Diffstat (limited to 'stdio')
102 files changed, 11927 insertions, 0 deletions
diff --git a/stdio/.cvsignore b/stdio/.cvsignore new file mode 100644 index 0000000000..1f69fd919a --- /dev/null +++ b/stdio/.cvsignore @@ -0,0 +1,4 @@ +*.gz *.Z *.tar *.tgz +=* +TODO COPYING* AUTHORS copyr-* copying.* +glibc-* diff --git a/stdio/Makefile b/stdio/Makefile new file mode 100644 index 0000000000..579426186f --- /dev/null +++ b/stdio/Makefile @@ -0,0 +1,114 @@ +# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public License as +# published by the Free Software Foundation; either version 2 of the +# License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. + +# You should have received a copy of the GNU Library General Public +# License along with the GNU C Library; see the file COPYING.LIB. If +# not, write to the Free Software Foundation, Inc., 675 Mass Ave, +# Cambridge, MA 02139, USA. + +# +# Specific makefile for stdio. +# +subdir := stdio + +headers := stdio.h stdio_lim.h printf.h + +routines := \ + ctermid cuserid \ + feof ferror clearerr fileno \ + newstream fopen freopen fdopen fopncook fmemopen \ + setbuf setvbuf setbuffer setlinebuf \ + fseek ftell rewind fgetpos fsetpos \ + vfprintf vprintf printf_fp reg-printf printf-prs _itoa \ + vsnprintf vsprintf vasprintf \ + fprintf printf snprintf sprintf asprintf \ + dprintf vdprintf \ + vfscanf vscanf vsscanf \ + fscanf scanf sscanf \ + fread fwrite \ + ungetc \ + fgetc getc getchar getw \ + fputc putc putchar putw \ + fgets gets fputs puts \ + getdelim getline \ + perror psignal \ + tmpfile tmpnam tempnam tempname \ + fclose fflush \ + remove rename \ + memstream obstream \ + internals sysd-stdio pipestream stdio_init libc_fatal + +# Several mpn functions from GNU MP are used by the printf_fp function. +mpn-routines := add_1 add_n addmul_1 cmp divmod divmod_1 udiv_qrnnd \ + lshift rshift mod_1 mul mul_1 mul_n sub_n submul_1 +mpn-headers = longlong.h gmp.h gmp-impl.h gmp-mparam.h asm-syntax.h + +routines := $(strip $(routines) $(mpn-routines)) \ + dbl2mpn ldbl2mpn \ + mpn2flt mpn2dbl mpn2ldbl +aux := errlist siglist defs glue mp_clz_tab fpioconst +distribute = $(mpn-headers) gen-mpn-copy _itoa.h fpioconst.h + +tests := tst-printf tstscanf test_rdwr test-popen tstgetln test-fseek \ + temptest tst-fileno test-fwrite \ + xbug errnobug \ + bug1 bug2 bug3 bug4 bug5 bug6 bug7 + + +include ../Rules + + +ifdef gmp-srcdir + +gmp-srcdir := $(firstword $(filter-out ..//%,$(..)$(gmp-srcdir) $(gmp-srcdir))) + +# Copy the mpn source files we use from the GNU MP source directory. +# `gmp-srcdir' is set by doing `configure --with-gmp=DIR'. +# (Do not try this at home. You need an as yet unreleased version of GNU MP.) + +mpn-sysdep := $(addsuffix .c,$(mpn-routines)) \ + $(addsuffix .S,$(mpn-routines)) \ + $(addsuffix .s,$(mpn-routines)) gmp-mparam.h asm-syntax.h + +mpn-try := $(addprefix $(gmp-srcdir)/mpn/*/,$(mpn-sysdep)) +mpn-found := $(wildcard $(mpn-try)) +mpn-found := $(filter-out $(patsubst %.S,%.s,$(filter %.s,$(mpn-found))),\ + $(mpn-found)) + +include mpn-copy.mk +%.mk: gen-%; sh $< > $@ + +mpn-copy-1 := $(patsubst $(gmp-srcdir)/mpn/%,$(sysdep_dir)/%,$(mpn-found)) +mpn-copy-sysdep := $(mpn-copy-sysdep) $(mpn-copy-1) +$(mpn-copy-1): $(sysdep_dir)/%: $(ignore gmp2glibc.sed) $(gmp-srcdir)/mpn/% + $(gmp2glibc) + +mpn-stuff = $(mpn-copy-sysdep) $(mpn-copy) + +# chmod so I don't edit them by mistake. +define gmp2glibc +$(ignore sed -f $^ > $@-tmp) +cp $< $@-tmp +chmod a-w $@-tmp +mv -f $@-tmp $@ +endef + +mpn-copy = $(filter-out $(mpn-sysdep),$(mpn-headers) mp_clz_tab.c) +$(mpn-copy): %: $(ignore gmp2glibc.sed) $(gmp-srcdir)/%; $(gmp2glibc) + +.PHONY: copy-mpn clean-mpn +copy-mpn: $(mpn-stuff) +clean-mpn: + rm -f $(mpn-stuff) + +endif diff --git a/stdio/_itoa.c b/stdio/_itoa.c new file mode 100644 index 0000000000..b781b1ea88 --- /dev/null +++ b/stdio/_itoa.c @@ -0,0 +1,45 @@ +/* Internal function for converting integers to ASCII. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include "_itoa.h" + +/* Lower-case digits. */ +CONST char _itoa_lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +/* Upper-case digits. */ +CONST char _itoa_upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +char * +DEFUN(_itoa, (value, buflim, base, upper_case), + unsigned long long int value AND char *buflim AND + unsigned int base AND int upper_case) +{ + /* Base-36 digits for numbers. */ + CONST char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits; + + register char *bp = buflim; + + while (value > 0) + { + *--bp = digits[value % base]; + value /= base; + } + + return bp; +} diff --git a/stdio/_itoa.h b/stdio/_itoa.h new file mode 100644 index 0000000000..791ce6c87f --- /dev/null +++ b/stdio/_itoa.h @@ -0,0 +1,54 @@ +/* Internal function for converting integers to ASCII. +Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _ITOA_H +#define _ITOA_H +#include <sys/cdefs.h> + +extern const char _itoa_lower_digits[], _itoa_upper_digits[]; + +/* Convert VALUE into ASCII in base BASE (2..36). + Write backwards starting the character just before BUFLIM. + Return the address of the first (left-to-right) character in the number. + Use upper case letters iff UPPER_CASE is nonzero. */ + +extern char *_itoa __P ((unsigned long long int value, char *buflim, + unsigned int base, int upper_case)); + +#if defined (__GNUC__) && defined (__OPTIMIZE__) +extern __inline char * +_itoa (unsigned long long int value, char *buflim, + unsigned int base, int upper_case) +{ + /* Base-36 digits for numbers. */ + const char *digits = upper_case ? _itoa_upper_digits : _itoa_lower_digits; + + register char *bp = buflim; + + while (value > 0) + { + *--bp = digits[value % base]; + value /= base; + } + + return bp; +} +#endif + +#endif /* itoa.h */ diff --git a/stdio/asprintf.c b/stdio/asprintf.c new file mode 100644 index 0000000000..9b69800f73 --- /dev/null +++ b/stdio/asprintf.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Write formatted output from FORMAT to a string which is + allocated with malloc and stored in *STRING_PTR. */ +/* VARARGS2 */ +int +DEFUN(asprintf, (string_ptr, format), + char **string_ptr AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vasprintf(string_ptr, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/bug1.c b/stdio/bug1.c new file mode 100644 index 0000000000..755bc4231b --- /dev/null +++ b/stdio/bug1.c @@ -0,0 +1,28 @@ +#include <ansidecl.h> +#include <stdio.h> +#include <string.h> + +int +DEFUN_VOID(main) +{ + char *bp; + size_t size; + FILE *stream; + int lose = 0; + + stream = open_memstream (&bp, &size); + fprintf (stream, "hello"); + fflush (stream); + printf ("buf = %s, size = %d\n", bp, size); + lose |= size != 5; + lose |= strncmp (bp, "hello", size); + fprintf (stream, ", world"); + fclose (stream); + printf ("buf = %s, size = %d\n", bp, size); + lose |= size != 12; + lose |= strncmp (bp, "hello, world", 12); + + puts (lose ? "Test FAILED!" : "Test succeeded."); + + return lose; +} diff --git a/stdio/bug1.input b/stdio/bug1.input new file mode 100644 index 0000000000..5595fa46c0 --- /dev/null +++ b/stdio/bug1.input @@ -0,0 +1 @@ +95 diff --git a/stdio/bug2.c b/stdio/bug2.c new file mode 100644 index 0000000000..2b34c890bf --- /dev/null +++ b/stdio/bug2.c @@ -0,0 +1,12 @@ +#include <ansidecl.h> +#include <stdio.h> + +int +DEFUN_VOID(main) +{ + int i; + puts ("This should print \"wow = I\" for I from 0 to 39 inclusive."); + for (i = 0; i < 40; i++) + printf ("%s = %d\n", "wow", i); + return 0; +} diff --git a/stdio/bug3.c b/stdio/bug3.c new file mode 100644 index 0000000000..0f3c7f1087 --- /dev/null +++ b/stdio/bug3.c @@ -0,0 +1,52 @@ +#include <ansidecl.h> +#include <stdio.h> +#include <string.h> + +int +DEFUN_VOID(main) +{ + FILE *f; + int i; + + f = fopen("bugtest", "w+"); + for (i=0; i<9000; i++) + putc ('x', f); + fseek (f, 8180L, 0); + fwrite ("Where does this text go?", 1, 24, f); + fflush (f); + + rewind (f); + for (i=0; i<9000; i++) + { + int j; + + if ((j = getc(f)) != 'x') + { + if (i != 8180) + { + printf ("Test FAILED!"); + return 1; + } + else + { + char buf[25]; + + buf[0] = j; + fread (buf + 1, 1, 23, f); + buf[24] = '\0'; + if (strcmp (buf, "Where does this text go?") != 0) + { + printf ("%s\nTest FAILED!\n", buf); + return 1; + } + i += 23; + } + } + } + + fclose(f); + + puts ("Test succeeded."); + + return 0; +} diff --git a/stdio/bug4.c b/stdio/bug4.c new file mode 100644 index 0000000000..8e67f1d7b9 --- /dev/null +++ b/stdio/bug4.c @@ -0,0 +1,50 @@ +#ifdef _LIBC +#include <ansidecl.h> +#endif +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +int stdio_block_read = 1, stdio_block_write = 1; + +int +DEFUN(main, (argc, argv), + int argc AND char **argv) +{ + FILE *f; + int i; + char buffer[31]; + + while ((i = getopt (argc, argv, "rw")) != EOF) + switch (i) + { + case 'r': + stdio_block_read = 0; + break; + case 'w': + stdio_block_write = 0; + break; + } + + f = fopen("bugtest", "w+"); + for (i=0; i<9000; i++) { + putc('x', f); + } + fseek(f, 8180L, 0); + fwrite("Where does this text come from?", 1, 31, f); + fseek(f, 8180L, 0); + fread(buffer, 1, 31, f); + fwrite(buffer, 1, 31, stdout); + fclose(f); + + if (!memcmp (buffer, "Where does this text come from?", 31)) + { + puts ("\nTest succeeded."); + return 0; + } + else + { + puts ("\nTest FAILED!"); + return 1; + } +} diff --git a/stdio/bug5.c b/stdio/bug5.c new file mode 100644 index 0000000000..218af31352 --- /dev/null +++ b/stdio/bug5.c @@ -0,0 +1,60 @@ +/* If stdio is working correctly, after this is run infile and outfile + will have the same contents. If the bug (found in GNU C library 0.3) + exhibits itself, outfile will be missing the 2nd through 1023rd + characters. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static char buf[8192]; + +int +DEFUN_VOID(main) +{ + FILE *in; + FILE *out; + static char inname[] = "infile"; + static char outname[] = "outfile"; + int i; + + /* Create a test file. */ + in = fopen (inname, "w+"); + if (in == NULL) + { + perror (inname); + return 1; + } + for (i = 0; i < 1000; ++i) + fprintf (in, "%d\n", i); + + out = fopen (outname, "w"); + if (out == NULL) + { + perror (outname); + return 1; + } + if (fseek (in, 0L, SEEK_SET) != 0) + abort (); + putc (getc (in), out); + i = fread (buf, 1, sizeof (buf), in); + if (i == 0) + { + perror ("fread"); + return 1; + } + if (fwrite (buf, 1, i, out) != i) + { + perror ("fwrite"); + return 1; + } + fclose (in); + fclose (out); + + puts ("There should be no further output from this test."); + fflush (stdout); + execlp ("cmp", "cmp", inname, outname, (char *) NULL); + perror ("execlp: cmp"); + exit (1); +} diff --git a/stdio/bug6.c b/stdio/bug6.c new file mode 100644 index 0000000000..4a37ab2584 --- /dev/null +++ b/stdio/bug6.c @@ -0,0 +1,27 @@ +#include <ansidecl.h> +#include <stdio.h> + +int +DEFUN_VOID(main) +{ + char buf[80]; + int i; + int lost = 0; + + scanf ("%2s", buf); + lost |= (buf[0] != 'X' || buf[1] != 'Y' || buf[2] != '\0'); + if (lost) + puts ("test of %2s failed."); + scanf (" "); + scanf ("%d", &i); + lost |= (i != 1234); + if (lost) + puts ("test of %d failed."); + scanf ("%c", buf); + lost |= (buf[0] != 'L'); + if (lost) + puts ("test of %c failed.\n"); + + puts (lost ? "Test FAILED!" : "Test succeeded."); + return lost; +} diff --git a/stdio/bug6.input b/stdio/bug6.input new file mode 100644 index 0000000000..d996e399c3 --- /dev/null +++ b/stdio/bug6.input @@ -0,0 +1 @@ +XY 1234L diff --git a/stdio/bug7.c b/stdio/bug7.c new file mode 100644 index 0000000000..af06f8d6a5 --- /dev/null +++ b/stdio/bug7.c @@ -0,0 +1,53 @@ +/* Regression test for fseek and freopen bugs. */ + +#include <stdio.h> + +int +main () +{ + int lose = 0; + char filename[] = "/tmp/foo"; + FILE *fp; + + fp = fopen (filename, "w+"); + fprintf (fp, "Hello world!\n"); + fflush (fp); + fseek (fp, 5L, SEEK_SET); + if (fseek (fp, -1L, SEEK_CUR) < 0) + { + printf ("seek failed\n"); + lose = 1; + } + fclose (fp); + remove (filename); + + { + FILE *file1; + FILE *file2; + char filename1[] = "/tmp/foo"; + char filename2[] = "/tmp/bar"; + int ch; + + file1 = fopen (filename1, "w"); + fclose (file1); + + file2 = fopen (filename2, "w"); + fputc ('x', file2); + fclose (file2); + + file1 = fopen (filename1, "r"); + file2 = freopen (filename2, "r", file1); + if ((ch = fgetc (file2)) != 'x') + { + printf ("wrong character in reopened file, value = %d\n", ch); + lose = 1; + } + fclose (file1); + fclose (file2); + remove (filename1); + remove (filename2); + } + + puts (lose ? "Test FAILED!" : "Test succeeded."); + return lose; +} diff --git a/stdio/clearerr.c b/stdio/clearerr.c new file mode 100644 index 0000000000..1a9feaa413 --- /dev/null +++ b/stdio/clearerr.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +#undef clearerr + + +/* Clear the EOF and error indicators for STREAM. */ +void +DEFUN(clearerr, (stream), FILE *stream) +{ + __clearerr(stream); +} diff --git a/stdio/dprintf.c b/stdio/dprintf.c new file mode 100644 index 0000000000..fc9faa4ca2 --- /dev/null +++ b/stdio/dprintf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Write formatted output to D, according to the format string FORMAT. */ +/* VARARGS2 */ +int +DEFUN(dprintf, (d, format), int d AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vdprintf(d, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/errnobug.c b/stdio/errnobug.c new file mode 100644 index 0000000000..cf17be30a2 --- /dev/null +++ b/stdio/errnobug.c @@ -0,0 +1,60 @@ +/* Regression test for reported old bug that errno is clobbered + by the first successful output to a stream on an unseekable object. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + +int +main (void) +{ + int fd[2]; + FILE *f; + + /* Get a stream that cannot seek. */ + + if (pipe (fd)) + { + perror ("pipe"); + return 1; + } + f = fdopen (fd[1], "w"); + if (f == NULL) + { + perror ("fdopen"); + return 1; + } + + errno = 0; + if (fputs ("fnord", f)) + { + perror ("fputs"); + return 1; + } + + if (errno) + { + perror ("errno gratuitously set -- TEST FAILED"); + return 1; + } + + puts ("Test succeeded."); + return 0; +} diff --git a/stdio/fclose.c b/stdio/fclose.c new file mode 100644 index 0000000000..becb85802f --- /dev/null +++ b/stdio/fclose.c @@ -0,0 +1,69 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* Close a stream. */ +int +DEFUN(fclose, (stream), register FILE *stream) +{ + int status; + + if (stream == NULL) + { + /* Close all streams. */ + register FILE *f; + for (f = __stdio_head; f != NULL; f = f->__next) + if (__validfp(f)) + (void) fclose(f); + return 0; + } + + if (!__validfp(stream)) + { + errno = EINVAL; + return EOF; + } + + if (stream->__mode.__write && + /* Flush the buffer. */ + __flshfp (stream, EOF) == EOF) + return EOF; + + /* Free the buffer's storage. */ + if (stream->__buffer != NULL && !stream->__userbuf) + free(stream->__buffer); + + /* Close the system file descriptor. */ + if (stream->__io_funcs.__close != NULL) + status = (*stream->__io_funcs.__close)(stream->__cookie); + else if (!stream->__seen && stream->__cookie != NULL) + status = __stdio_close(stream->__cookie); + else + status = 0; + + /* Nuke the stream, making it available for re-use. */ + __invalidate(stream); + + return status < 0 ? EOF : 0; +} diff --git a/stdio/feof.c b/stdio/feof.c new file mode 100644 index 0000000000..c18300f6b5 --- /dev/null +++ b/stdio/feof.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +#undef feof + + +/* Return non-zero if STREAM has its EOF indicator set. */ +int +DEFUN(feof, (stream), FILE *stream) +{ + if (!__validfp(stream)) + { + errno = EINVAL; + return(-1); + } + + return(stream->__eof); +} diff --git a/stdio/ferror.c b/stdio/ferror.c new file mode 100644 index 0000000000..ed8f74401a --- /dev/null +++ b/stdio/ferror.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +#undef ferror + + +/* Return non-zero if STREAM has its error indicator set. */ +int +DEFUN(ferror, (stream), FILE *stream) +{ + if (!__validfp(stream)) + { + errno = EINVAL; + return(-1); + } + + return(stream->__error); +} diff --git a/stdio/fflush.c b/stdio/fflush.c new file mode 100644 index 0000000000..a6d52ba3e7 --- /dev/null +++ b/stdio/fflush.c @@ -0,0 +1,45 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> + +/* Flush STREAM's buffer. + If STREAM is NULL, flush the buffers of all streams that are writing. */ +int +DEFUN(fflush, (stream), register FILE *stream) +{ + if (stream == NULL) + { + int lossage = 0; + for (stream = __stdio_head; stream != NULL; stream = stream->__next) + if (__validfp(stream) && stream->__mode.__write) + lossage |= fflush(stream) == EOF; + return lossage ? EOF : 0; + } + + if (!__validfp(stream) || !stream->__mode.__write) + { + errno = EINVAL; + return EOF; + } + + return __flshfp(stream, EOF); +} diff --git a/stdio/fgetc.c b/stdio/fgetc.c new file mode 100644 index 0000000000..7f01090294 --- /dev/null +++ b/stdio/fgetc.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + + +/* Read a character from STREAM. */ +int +DEFUN(fgetc, (stream), FILE *stream) +{ + if (!__validfp(stream) || !stream->__mode.__read) + { + errno = EINVAL; + return EOF; + } + + return __getc(stream); +} diff --git a/stdio/fgetpos.c b/stdio/fgetpos.c new file mode 100644 index 0000000000..cb6a1588ba --- /dev/null +++ b/stdio/fgetpos.c @@ -0,0 +1,40 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +#undef fgetpos + + +/* Put the current position of STREAM in *POS. */ +int +DEFUN(fgetpos, (stream, pos), FILE *stream AND fpos_t *pos) +{ + if (!__validfp(stream) || pos == NULL) + { + errno = EINVAL; + return(-1); + } + + *pos = ftell(stream); + if (*pos < 0L) + return(-1); + return(0); +} diff --git a/stdio/fgets.c b/stdio/fgets.c new file mode 100644 index 0000000000..e9e53c88dd --- /dev/null +++ b/stdio/fgets.c @@ -0,0 +1,121 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +/* Reads characters from STREAM into S, until either a newline character + is read, N - 1 characters have been read, or EOF is seen. Returns + the newline, unlike gets. Finishes by appending a null character and + returning S. If EOF is seen before any characters have been written + to S, the function returns NULL without appending the null character. + If there is a file error, always return NULL. */ +char * +DEFUN(fgets, (s, n, stream), char *s AND int n AND register FILE *stream) +{ + register char *p = s; + + if (!__validfp(stream) || s == NULL || n <= 0) + { + errno = EINVAL; + return NULL; + } + + if (ferror (stream)) + return NULL; + + if (stream->__buffer == NULL && stream->__userbuf) + { + /* Unbuffered stream. Not much optimization to do. */ + register int c = 0; + while (--n > 0 && (c = getc (stream)) != EOF) + if ((*p++ = c) == '\n') + break; + if (c == EOF && (p == s || ferror (stream))) + return NULL; + *p = '\0'; + return s; + } + + /* Leave space for the null. */ + --n; + + if (n > 0 && + (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back)) + { + /* Do one with getc to allocate a buffer. */ + int c = getc (stream); + if (c == EOF) + return NULL; + *p++ = c; + if (c == '\n') + { + *p = '\0'; + return s; + } + else + --n; + } + + while (n > 0) + { + size_t i; + char *found; + + i = stream->__get_limit - stream->__bufp; + if (i == 0) + { + /* Refill the buffer. */ + int c = __fillbf (stream); + if (c == EOF) + break; + *p++ = c; + --n; + if (c == '\n') + { + *p = '\0'; + return s; + } + i = stream->__get_limit - stream->__bufp; + } + + if (i > n) + i = n; + + found = (char *) __memccpy ((PTR) p, stream->__bufp, '\n', i); + + if (found != NULL) + { + stream->__bufp += found - p; + p = found; + break; + } + + stream->__bufp += i; + n -= i; + p += i; + } + + if (p == s) + return NULL; + + *p = '\0'; + return ferror (stream) ? NULL : s; +} diff --git a/stdio/fileno.c b/stdio/fileno.c new file mode 100644 index 0000000000..da55300c8b --- /dev/null +++ b/stdio/fileno.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +/* Return the system file descriptor associated with STREAM. */ +int +DEFUN(fileno, (stream), FILE *stream) +{ + extern void __stdio_check_funcs __P ((FILE *)); + + if (! __validfp (stream)) + { + errno = EINVAL; + return -1; + } + + __stdio_check_funcs (stream); + + if (stream->__io_funcs.__fileno == NULL) + { +#ifdef EOPNOTSUPP + errno = EOPNOTSUPP; +#else + errno = ENOSYS; +#endif + return -1; + } + + return (*stream->__io_funcs.__fileno) (stream->__cookie); +} diff --git a/stdio/fmemopen.c b/stdio/fmemopen.c new file mode 100644 index 0000000000..42a137a2c8 --- /dev/null +++ b/stdio/fmemopen.c @@ -0,0 +1,108 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* Defined in fopen.c. */ +extern int EXFUN(__getmode, (CONST char *mode, __io_mode *mptr)); + +/* Open a new stream that will read and/or write from the buffer in + S, which is of LEN bytes. If the mode indicates appending, the + buffer pointer is set to point to the first '\0' in the buffer. + If S is NULL, the buffer is allocated by malloc and will be freed + when the stream is closed. The only purpose of this is to write + things and then read what's been written. If LEN is zero, writes will + always return errors and reads will always return end-of-file. + + The stream is set up such that seeks and tells will always fail and + once the buffer is full of written characters or empty of characters + to read, attempted writes always return an output error and attempted + reads always return end-of-file. */ +FILE * +DEFUN(fmemopen, (s, len, mode), + PTR s AND size_t len AND CONST char *mode) +{ + __io_mode m; + register FILE *stream; + + if (!__getmode (mode, &m)) + return NULL; + + stream = __newstream (); + if (stream == NULL) + return NULL; + + stream->__mode = m; + + /* Input gets EOF. */ + stream->__room_funcs.__input = NULL; + /* Output gets error. */ + stream->__room_funcs.__output = NULL; + + /* Do nothing for close. */ + stream->__io_funcs.__close = NULL; + /* Can't seek outside the buffer. */ + stream->__io_funcs.__seek = NULL; + /* There is no associated file descriptor to fetch. */ + stream->__io_funcs.__fileno = NULL; + + stream->__seen = 1; + + stream->__userbuf = s != NULL && len > 0; + if (s == NULL) + { + s = malloc (len); + if (s == NULL) + { + int save = errno; + (void) fclose (stream); + errno = save; + return NULL; + } + } + + stream->__buffer = (char *) s; + stream->__bufsize = len; + + stream->__bufp = stream->__buffer; + stream->__get_limit = (stream->__buffer + + (stream->__mode.__read ? stream->__bufsize : 0)); + stream->__put_limit = (stream->__buffer + + (stream->__mode.__write ? stream->__bufsize : 0)); + stream->__cookie = NULL; + + if (stream->__mode.__append) + { + char *p = memchr (stream->__bufp, '\0', + stream->__get_limit - stream->__bufp); + if (p == NULL) + stream->__bufp = stream->__get_limit; + else + stream->__bufp = p; + } + else if (stream->__mode.__truncate) + memset ((PTR) stream->__buffer, 0, len); + + return stream; +} diff --git a/stdio/fopen.c b/stdio/fopen.c new file mode 100644 index 0000000000..fba6ac436a --- /dev/null +++ b/stdio/fopen.c @@ -0,0 +1,110 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#define badmode() return ((errno = EINVAL), 0) + +/* Dissect the given mode string into an __io_mode. */ +int +DEFUN(__getmode, (mode, mptr), CONST char *mode AND __io_mode *mptr) +{ + register unsigned char i; + + if (mode == NULL) + badmode (); + + memset ((PTR) mptr, 0, sizeof (*mptr)); + + switch (*mode) + { + case 'a': + mptr->__write = mptr->__create = mptr->__append = 1; + break; + case 'w': + mptr->__write = mptr->__create = mptr->__truncate = 1; + break; + case 'r': + mptr->__read = 1; + break; + default: + badmode (); + } + + for (i = 1; i < 3; ++i) + { + ++mode; + if (*mode == '\0') + break; + switch (*mode) + { + case '+': + mptr->__read = mptr->__write = 1; + break; + case 'b': + mptr->__binary = 1; + break; + } + } + + if (!mptr->__read && !mptr->__write) + badmode (); + + mptr->__exclusive = *mode == 'x'; + + return 1; +} + +/* Open a new stream on the given file. */ +FILE * +DEFUN(fopen, (filename, mode), CONST char *filename AND CONST char *mode) +{ + FILE *stream; + __io_mode m; + + if (filename == NULL) + { + errno = EINVAL; + return NULL; + } + + if (!__getmode (mode, &m)) + return NULL; + + stream = __newstream (); + if (stream == NULL) + return NULL; + + if (__stdio_open (filename, m, &stream->__cookie)) + { + int save = errno; + (void) fclose (stream); + errno = save; + return NULL; + } + + stream->__mode = m; + + return stream; +} diff --git a/stdio/fopncook.c b/stdio/fopncook.c new file mode 100644 index 0000000000..b61bdda959 --- /dev/null +++ b/stdio/fopncook.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + + +/* Defined in fopen.c. */ +extern int EXFUN(__getmode, (CONST char *mode, __io_mode *mptr)); + +/* Open a new stream on the given magic cookie descriptor. */ +FILE * +DEFUN(fopencookie, (cookie, mode, functions), + PTR cookie AND CONST char *mode AND __io_functions functions) +{ + __io_mode m; + FILE *f; + + if (!__getmode (mode, &m)) + return NULL; + + f = __newstream (); + if (f == NULL) + return NULL; + + f->__cookie = cookie; + f->__mode = m; + f->__io_funcs = functions; + f->__room_funcs = __default_room_functions; + f->__seen = 1; + + return f; +} diff --git a/stdio/fpioconst.c b/stdio/fpioconst.c new file mode 100644 index 0000000000..231cae34ed --- /dev/null +++ b/stdio/fpioconst.c @@ -0,0 +1,401 @@ +/* Table of MP integer constants 10^(2^i), used for floating point <-> decimal. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include "fpioconst.h" +#include <gmp-mparam.h> /* This defines BITS_PER_MP_LIMB. */ + +/* First page : 32-bit limbs + Second page : 64-bit limbs + Last page : table of pointers + */ + +#if BITS_PER_MP_LIMB == 32 + +/* Table with constants of 10^(2^i), i=0..12 for 32-bit limbs. */ + +static const mp_limb _ten_p0[] = + { 0x00000000, 0x00000000, 0x0000000a }; +static const mp_limb _ten_p1[] = + { 0x00000000, 0x00000000, 0x00000064 }; +static const mp_limb _ten_p2[] = + { 0x00000000, 0x00000000, 0x00002710 }; +static const mp_limb _ten_p3[] = + { 0x00000000, 0x00000000, 0x05f5e100 }; +static const mp_limb _ten_p4[] = + { 0x00000000, 0x00000000, 0x6fc10000, 0x002386f2 }; +static const mp_limb _ten_p5[] = + { 0x00000000, 0x00000000, 0x00000000, 0x85acef81, 0x2d6d415b, 0x000004ee }; +static const mp_limb _ten_p6[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xbf6a1f01, 0x6e38ed64, + 0xdaa797ed, 0xe93ff9f4, 0x00184f03 }; +static const mp_limb _ten_p7[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x2e953e01, 0x03df9909, 0x0f1538fd, 0x2374e42f, 0xd3cff5ec, 0xc404dc08, + 0xbccdb0da, 0xa6337f19, 0xe91f2603, 0x0000024e }; +static const mp_limb _ten_p8[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x982e7c01, 0xbed3875b, + 0xd8d99f72, 0x12152f87, 0x6bde50c6, 0xcf4a6e70, 0xd595d80f, 0x26b2716e, + 0xadc666b0, 0x1d153624, 0x3c42d35a, 0x63ff540e, 0xcc5573c0, 0x65f9ef17, + 0x55bc28f2, 0x80dcc7f7, 0xf46eeddc, 0x5fdcefce, 0x000553f7 }; +static const mp_limb _ten_p9[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0xfc6cf801, 0x77f27267, 0x8f9546dc, 0x5d96976f, 0xb83a8a97, 0xc31e1ad9, + 0x46c40513, 0x94e65747, 0xc88976c1, 0x4475b579, 0x28f8733b, 0xaa1da1bf, + 0x703ed321, 0x1e25cfea, 0xb21a2f22, 0xbc51fb2e, 0x96e14f5d, 0xbfa3edac, + 0x329c57ae, 0xe7fc7153, 0xc3fc0695, 0x85a91924, 0xf95f635e, 0xb2908ee0, + 0x93abade4, 0x1366732a, 0x9449775c, 0x69be5b0e, 0x7343afac, 0xb099bc81, + 0x45a71d46, 0xa2699748, 0x8cb07303, 0x8a0b1f13, 0x8cab8a97, 0xc1d238d9, + 0x633415d4, 0x0000001c }; +static const mp_limb _ten_p10[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2919f001, 0xf55b2b72, + 0x6e7c215b, 0x1ec29f86, 0x991c4e87, 0x15c51a88, 0x140ac535, 0x4c7d1e1a, + 0xcc2cd819, 0x0ed1440e, 0x896634ee, 0x7de16cfb, 0x1e43f61f, 0x9fce837d, + 0x231d2b9c, 0x233e55c7, 0x65dc60d7, 0xf451218b, 0x1c5cd134, 0xc9635986, + 0x922bbb9f, 0xa7e89431, 0x9f9f2a07, 0x62be695a, 0x8e1042c4, 0x045b7a74, + 0x1abe1de3, 0x8ad822a5, 0xba34c411, 0xd814b505, 0xbf3fdeb3, 0x8fc51a16, + 0xb1b896bc, 0xf56deeec, 0x31fb6bfd, 0xb6f4654b, 0x101a3616, 0x6b7595fb, + 0xdc1a47fe, 0x80d98089, 0x80bda5a5, 0x9a202882, 0x31eb0f66, 0xfc8f1f90, + 0x976a3310, 0xe26a7b7e, 0xdf68368a, 0x3ce3a0b8, 0x8e4262ce, 0x75a351a2, + 0x6cb0b6c9, 0x44597583, 0x31b5653f, 0xc356e38a, 0x35faaba6, 0x0190fba0, + 0x9fc4ed52, 0x88bc491b, 0x1640114a, 0x005b8041, 0xf4f3235e, 0x1e8d4649, + 0x36a8de06, 0x73c55349, 0xa7e6bd2a, 0xc1a6970c, 0x47187094, 0xd2db49ef, + 0x926c3f5b, 0xae6209d4, 0x2d433949, 0x34f4a3c6, 0xd4305d94, 0xd9d61a05, + 0x00000325 }; +static const mp_limb _ten_p11[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x1333e001, 0xe3096865, 0xb27d4d3f, 0x49e28dcf, 0xec2e4721, 0xee87e354, + 0xb6067584, 0x368b8abb, 0xa5e5a191, 0x2ed56d55, 0xfd827773, 0xea50d142, + 0x51b78db2, 0x98342c9e, 0xc850dabc, 0x866ed6f1, 0x19342c12, 0x92794987, + 0xd2f869c2, 0x66912e4a, 0x71c7fd8f, 0x57a7842d, 0x235552eb, 0xfb7fedcc, + 0xf3861ce0, 0x38209ce1, 0x9713b449, 0x34c10134, 0x8c6c54de, 0xa7a8289c, + 0x2dbb6643, 0xe3cb64f3, 0x8074ff01, 0xe3892ee9, 0x10c17f94, 0xa8f16f92, + 0xa8281ed6, 0x967abbb3, 0x5a151440, 0x9952fbed, 0x13b41e44, 0xafe609c3, + 0xa2bca416, 0xf111821f, 0xfb1264b4, 0x91bac974, 0xd6c7d6ab, 0x8e48ff35, + 0x4419bd43, 0xc4a65665, 0x685e5510, 0x33554c36, 0xab498697, 0x0dbd21fe, + 0x3cfe491d, 0x982da466, 0xcbea4ca7, 0x9e110c7b, 0x79c56b8a, 0x5fc5a047, + 0x84d80e2e, 0x1aa9f444, 0x730f203c, 0x6a57b1ab, 0xd752f7a6, 0x87a7dc62, + 0x944545ff, 0x40660460, 0x77c1a42f, 0xc9ac375d, 0xe866d7ef, 0x744695f0, + 0x81428c85, 0xa1fc6b96, 0xd7917c7b, 0x7bf03c19, 0x5b33eb41, 0x5715f791, + 0x8f6cae5f, 0xdb0708fd, 0xb125ac8e, 0x785ce6b7, 0x56c6815b, 0x6f46eadb, + 0x4eeebeee, 0x195355d8, 0xa244de3c, 0x9d7389c0, 0x53761abd, 0xcf99d019, + 0xde9ec24b, 0x0d76ce39, 0x70beb181, 0x2e55ecee, 0xd5f86079, 0xf56d9d4b, + 0xfb8886fb, 0x13ef5a83, 0x408f43c5, 0x3f3389a4, 0xfad37943, 0x58ccf45c, + 0xf82df846, 0x415c7f3e, 0x2915e818, 0x8b3d5cf4, 0x6a445f27, 0xf8dbb57a, + 0xca8f0070, 0x8ad803ec, 0xb2e87c34, 0x038f9245, 0xbedd8a6c, 0xc7c9dee0, + 0x0eac7d56, 0x2ad3fa14, 0xe0de0840, 0xf775677c, 0xf1bd0ad5, 0x92be221e, + 0x87fa1fb9, 0xce9d04a4, 0xd2c36fa9, 0x3f6f7024, 0xb028af62, 0x907855ee, + 0xd83e49d6, 0x4efac5dc, 0xe7151aab, 0x77cd8c6b, 0x0a753b7d, 0x0af908b4, + 0x8c983623, 0xe50f3027, 0x94222771, 0x1d08e2d6, 0xf7e928e6, 0xf2ee5ca6, + 0x1b61b93c, 0x11eb962b, 0x9648b21c, 0xce2bcba1, 0x34f77154, 0x7bbebe30, + 0xe526a319, 0x8ce329ac, 0xde4a74d2, 0xb5dc53d5, 0x0009e8b3 }; +static const mp_limb _ten_p12[] = + { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x2a67c001, 0xd4724e8d, + 0x8efe7ae7, 0xf89a1e90, 0xef084117, 0x54e05154, 0x13b1bb51, 0x506be829, + 0xfb29b172, 0xe599574e, 0xf0da6146, 0x806c0ed3, 0xb86ae5be, 0x45155e93, + 0xc0591cc2, 0x7e1e7c34, 0x7c4823da, 0x1d1f4cce, 0x9b8ba1e8, 0xd6bfdf75, + 0xe341be10, 0xc2dfae78, 0x016b67b2, 0x0f237f1a, 0x3dbeabcd, 0xaf6a2574, + 0xcab3e6d7, 0x142e0e80, 0x61959127, 0x2c234811, 0x87009701, 0xcb4bf982, + 0xf8169c84, 0x88052f8c, 0x68dde6d4, 0xbc131761, 0xff0b0905, 0x54ab9c41, + 0x7613b224, 0x1a1c304e, 0x3bfe167b, 0x441c2d47, 0x4f6cea9c, 0x78f06181, + 0xeb659fb8, 0x30c7ae41, 0x947e0d0e, 0xa1ebcad7, 0xd97d9556, 0x2130504d, + 0x1a8309cb, 0xf2acd507, 0x3f8ec72a, 0xfd82373a, 0x95a842bc, 0x280f4d32, + 0xf3618ac0, 0x811a4f04, 0x6dc3a5b4, 0xd3967a1b, 0x15b8c898, 0xdcfe388f, + 0x454eb2a0, 0x8738b909, 0x10c4e996, 0x2bd9cc11, 0x3297cd0c, 0x655fec30, + 0xae0725b1, 0xf4090ee8, 0x037d19ee, 0x398c6fed, 0x3b9af26b, 0xc994a450, + 0xb5341743, 0x75a697b2, 0xac50b9c1, 0x3ccb5b92, 0xffe06205, 0xa8329761, + 0xdfea5242, 0xeb83cadb, 0xe79dadf7, 0x3c20ee69, 0x1e0a6817, 0x7021b97a, + 0x743074fa, 0x176ca776, 0x77fb8af6, 0xeca19beb, 0x92baf1de, 0xaf63b712, + 0xde35c88b, 0xa4eb8f8c, 0xe137d5e9, 0x40b464a0, 0x87d1cde8, 0x42923bbd, + 0xcd8f62ff, 0x2e2690f3, 0x095edc16, 0x59c89f1b, 0x1fa8fd5d, 0x5138753d, + 0x390a2b29, 0x80152f18, 0x2dd8d925, 0xf984d83e, 0x7a872e74, 0xc19e1faf, + 0xed4d542d, 0xecf9b5d0, 0x9462ea75, 0xc53c0adf, 0x0caea134, 0x37a2d439, + 0xc8fa2e8a, 0x2181327e, 0x6e7bb827, 0x2d240820, 0x50be10e0, 0x5893d4b8, + 0xab312bb9, 0x1f2b2322, 0x440b3f25, 0xbf627ede, 0x72dac789, 0xb608b895, + 0x78787e2a, 0x86deb3f0, 0x6fee7aab, 0xbb9373f4, 0x27ecf57b, 0xf7d8b57e, + 0xfca26a9f, 0x3d04e8d2, 0xc9df13cb, 0x3172826a, 0xcd9e8d7c, 0xa8fcd8e0, + 0xb2c39497, 0x307641d9, 0x1cc939c1, 0x2608c4cf, 0xb6d1c7bf, 0x3d326a7e, + 0xeeaf19e6, 0x8e13e25f, 0xee63302b, 0x2dfe6d97, 0x25971d58, 0xe41d3cc4, + 0x0a80627c, 0xab8db59a, 0x9eea37c8, 0xe90afb77, 0x90ca19cf, 0x9ee3352c, + 0x3613c850, 0xfe78d682, 0x788f6e50, 0x5b060904, 0xb71bd1a4, 0x3fecb534, + 0xb32c450c, 0x20c33857, 0xa6e9cfda, 0x0239f4ce, 0x48497187, 0xa19adb95, + 0xb492ed8a, 0x95aca6a8, 0x4dcd6cd9, 0xcf1b2350, 0xfbe8b12a, 0x1a67778c, + 0x38eb3acc, 0xc32da383, 0xfb126ab1, 0xa03f40a8, 0xed5bf546, 0xe9ce4724, + 0x4c4a74fd, 0x73a130d8, 0xd9960e2d, 0xa2ebd6c1, 0x94ab6feb, 0x6f233b7c, + 0x49126080, 0x8e7b9a73, 0x4b8c9091, 0xd298f999, 0x35e836b5, 0xa96ddeff, + 0x96119b31, 0x6b0dd9bc, 0xc6cc3f8d, 0x282566fb, 0x72b882e7, 0xd6769f3b, + 0xa674343d, 0x00fc509b, 0xdcbf7789, 0xd6266a3f, 0xae9641fd, 0x4e89541b, + 0x11953407, 0x53400d03, 0x8e0dd75a, 0xe5b53345, 0x108f19ad, 0x108b89bc, + 0x41a4c954, 0xe03b2b63, 0x437b3d7f, 0x97aced8e, 0xcbd66670, 0x2c5508c2, + 0x650ebc69, 0x5c4f2ef0, 0x904ff6bf, 0x9985a2df, 0x9faddd9e, 0x5ed8d239, + 0x25585832, 0xe3e51cb9, 0x0ff4f1d4, 0x56c02d9a, 0x8c4ef804, 0xc1a08a13, + 0x13fd01c8, 0xe6d27671, 0xa7c234f4, 0x9d0176cc, 0xd0d73df2, 0x4d8bfa89, + 0x544f10cd, 0x2b17e0b2, 0xb70a5c7d, 0xfd86fe49, 0xdf373f41, 0x214495bb, + 0x84e857fd, 0x00d313d5, 0x0496fcbe, 0xa4ba4744, 0xe8cac982, 0xaec29e6e, + 0x87ec7038, 0x7000a519, 0xaeee333b, 0xff66e42c, 0x8afd6b25, 0x03b4f63b, + 0xbd7991dc, 0x5ab8d9c7, 0x2ed4684e, 0x48741a6c, 0xaf06940d, 0x2fdc6349, + 0xb03d7ecd, 0xe974996f, 0xac7867f9, 0x52ec8721, 0xbcdd9d4a, 0x8edd2d00, + 0x3557de06, 0x41c759f8, 0x3956d4b9, 0xa75409f2, 0x123cd8a1, 0xb6100fab, + 0x3e7b21e2, 0x2e8d623b, 0x92959da2, 0xbca35f77, 0x200c03a5, 0x35fcb457, + 0x1bb6c6e4, 0xf74eb928, 0x3d5d0b54, 0x87cc1d21, 0x4964046f, 0x18ae4240, + 0xd868b275, 0x8bd2b496, 0x1c5563f4, 0xc234d8f5, 0xf868e970, 0xf9151fff, + 0xae7be4a2, 0x271133ee, 0xbb0fd922, 0x25254932, 0xa60a9fc0, 0x104bcd64, + 0x30290145, 0x00000062 }; + +#define LAST_POW10 12 + +#elif BITS_PER_MP_LIMB == 64 + +/* Table with constants of 10^(2^i), i=0..12 for 64-bit limbs. */ + +static const mp_limb _ten_p0[] = + { 0x0000000000000000, 0x000000000000000a }; +static const mp_limb _ten_p1[] = + { 0x0000000000000000, 0x0000000000000064 }; +static const mp_limb _ten_p2[] = + { 0x0000000000000000, 0x0000000000002710 }; +static const mp_limb _ten_p3[] = + { 0x0000000000000000, 0x0000000005f5e100 }; +static const mp_limb _ten_p4[] = + { 0x0000000000000000, 0x002386f26fc10000 }; +static const mp_limb _ten_p5[] = + { 0x0000000000000000, 0x85acef8100000000, 0x000004ee2d6d415b }; +static const mp_limb _ten_p6[] = + { 0x0000000000000000, 0x0000000000000000, 0x6e38ed64bf6a1f01, + 0xe93ff9f4daa797ed, 0x0000000000184f03 }; +static const mp_limb _ten_p7[] = + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x03df99092e953e01, 0x2374e42f0f1538fd, 0xc404dc08d3cff5ec, + 0xa6337f19bccdb0da, 0x0000024ee91f2603 }; +static const mp_limb _ten_p8[] = + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xbed3875b982e7c01, + 0x12152f87d8d99f72, 0xcf4a6e706bde50c6, 0x26b2716ed595d80f, + 0x1d153624adc666b0, 0x63ff540e3c42d35a, 0x65f9ef17cc5573c0, + 0x80dcc7f755bc28f2, 0x5fdcefcef46eeddc, 0x00000000000553f7 }; +static const mp_limb _ten_p9[] = + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x77f27267fc6cf801, 0x5d96976f8f9546dc, 0xc31e1ad9b83a8a97, + 0x94e6574746c40513, 0x4475b579c88976c1, 0xaa1da1bf28f8733b, + 0x1e25cfea703ed321, 0xbc51fb2eb21a2f22, 0xbfa3edac96e14f5d, + 0xe7fc7153329c57ae, 0x85a91924c3fc0695, 0xb2908ee0f95f635e, + 0x1366732a93abade4, 0x69be5b0e9449775c, 0xb099bc817343afac, + 0xa269974845a71d46, 0x8a0b1f138cb07303, 0xc1d238d98cab8a97, + 0x0000001c633415d4 }; +static const mp_limb _ten_p10[] = + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xf55b2b722919f001, + 0x1ec29f866e7c215b, 0x15c51a88991c4e87, 0x4c7d1e1a140ac535, + 0x0ed1440ecc2cd819, 0x7de16cfb896634ee, 0x9fce837d1e43f61f, + 0x233e55c7231d2b9c, 0xf451218b65dc60d7, 0xc96359861c5cd134, + 0xa7e89431922bbb9f, 0x62be695a9f9f2a07, 0x045b7a748e1042c4, + 0x8ad822a51abe1de3, 0xd814b505ba34c411, 0x8fc51a16bf3fdeb3, + 0xf56deeecb1b896bc, 0xb6f4654b31fb6bfd, 0x6b7595fb101a3616, + 0x80d98089dc1a47fe, 0x9a20288280bda5a5, 0xfc8f1f9031eb0f66, + 0xe26a7b7e976a3310, 0x3ce3a0b8df68368a, 0x75a351a28e4262ce, + 0x445975836cb0b6c9, 0xc356e38a31b5653f, 0x0190fba035faaba6, + 0x88bc491b9fc4ed52, 0x005b80411640114a, 0x1e8d4649f4f3235e, + 0x73c5534936a8de06, 0xc1a6970ca7e6bd2a, 0xd2db49ef47187094, + 0xae6209d4926c3f5b, 0x34f4a3c62d433949, 0xd9d61a05d4305d94, + 0x0000000000000325 }; +static const mp_limb _ten_p11[] = + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0xe30968651333e001, 0x49e28dcfb27d4d3f, 0xee87e354ec2e4721, + 0x368b8abbb6067584, 0x2ed56d55a5e5a191, 0xea50d142fd827773, + 0x98342c9e51b78db2, 0x866ed6f1c850dabc, 0x9279498719342c12, + 0x66912e4ad2f869c2, 0x57a7842d71c7fd8f, 0xfb7fedcc235552eb, + 0x38209ce1f3861ce0, 0x34c101349713b449, 0xa7a8289c8c6c54de, + 0xe3cb64f32dbb6643, 0xe3892ee98074ff01, 0xa8f16f9210c17f94, + 0x967abbb3a8281ed6, 0x9952fbed5a151440, 0xafe609c313b41e44, + 0xf111821fa2bca416, 0x91bac974fb1264b4, 0x8e48ff35d6c7d6ab, + 0xc4a656654419bd43, 0x33554c36685e5510, 0x0dbd21feab498697, + 0x982da4663cfe491d, 0x9e110c7bcbea4ca7, 0x5fc5a04779c56b8a, + 0x1aa9f44484d80e2e, 0x6a57b1ab730f203c, 0x87a7dc62d752f7a6, + 0x40660460944545ff, 0xc9ac375d77c1a42f, 0x744695f0e866d7ef, + 0xa1fc6b9681428c85, 0x7bf03c19d7917c7b, 0x5715f7915b33eb41, + 0xdb0708fd8f6cae5f, 0x785ce6b7b125ac8e, 0x6f46eadb56c6815b, + 0x195355d84eeebeee, 0x9d7389c0a244de3c, 0xcf99d01953761abd, + 0x0d76ce39de9ec24b, 0x2e55ecee70beb181, 0xf56d9d4bd5f86079, + 0x13ef5a83fb8886fb, 0x3f3389a4408f43c5, 0x58ccf45cfad37943, + 0x415c7f3ef82df846, 0x8b3d5cf42915e818, 0xf8dbb57a6a445f27, + 0x8ad803ecca8f0070, 0x038f9245b2e87c34, 0xc7c9dee0bedd8a6c, + 0x2ad3fa140eac7d56, 0xf775677ce0de0840, 0x92be221ef1bd0ad5, + 0xce9d04a487fa1fb9, 0x3f6f7024d2c36fa9, 0x907855eeb028af62, + 0x4efac5dcd83e49d6, 0x77cd8c6be7151aab, 0x0af908b40a753b7d, + 0xe50f30278c983623, 0x1d08e2d694222771, 0xf2ee5ca6f7e928e6, + 0x11eb962b1b61b93c, 0xce2bcba19648b21c, 0x7bbebe3034f77154, + 0x8ce329ace526a319, 0xb5dc53d5de4a74d2, 0x000000000009e8b3 }; +static const mp_limb _ten_p12[] = + { 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xd4724e8d2a67c001, + 0xf89a1e908efe7ae7, 0x54e05154ef084117, 0x506be82913b1bb51, + 0xe599574efb29b172, 0x806c0ed3f0da6146, 0x45155e93b86ae5be, + 0x7e1e7c34c0591cc2, 0x1d1f4cce7c4823da, 0xd6bfdf759b8ba1e8, + 0xc2dfae78e341be10, 0x0f237f1a016b67b2, 0xaf6a25743dbeabcd, + 0x142e0e80cab3e6d7, 0x2c23481161959127, 0xcb4bf98287009701, + 0x88052f8cf8169c84, 0xbc13176168dde6d4, 0x54ab9c41ff0b0905, + 0x1a1c304e7613b224, 0x441c2d473bfe167b, 0x78f061814f6cea9c, + 0x30c7ae41eb659fb8, 0xa1ebcad7947e0d0e, 0x2130504dd97d9556, + 0xf2acd5071a8309cb, 0xfd82373a3f8ec72a, 0x280f4d3295a842bc, + 0x811a4f04f3618ac0, 0xd3967a1b6dc3a5b4, 0xdcfe388f15b8c898, + 0x8738b909454eb2a0, 0x2bd9cc1110c4e996, 0x655fec303297cd0c, + 0xf4090ee8ae0725b1, 0x398c6fed037d19ee, 0xc994a4503b9af26b, + 0x75a697b2b5341743, 0x3ccb5b92ac50b9c1, 0xa8329761ffe06205, + 0xeb83cadbdfea5242, 0x3c20ee69e79dadf7, 0x7021b97a1e0a6817, + 0x176ca776743074fa, 0xeca19beb77fb8af6, 0xaf63b71292baf1de, + 0xa4eb8f8cde35c88b, 0x40b464a0e137d5e9, 0x42923bbd87d1cde8, + 0x2e2690f3cd8f62ff, 0x59c89f1b095edc16, 0x5138753d1fa8fd5d, + 0x80152f18390a2b29, 0xf984d83e2dd8d925, 0xc19e1faf7a872e74, + 0xecf9b5d0ed4d542d, 0xc53c0adf9462ea75, 0x37a2d4390caea134, + 0x2181327ec8fa2e8a, 0x2d2408206e7bb827, 0x5893d4b850be10e0, + 0x1f2b2322ab312bb9, 0xbf627ede440b3f25, 0xb608b89572dac789, + 0x86deb3f078787e2a, 0xbb9373f46fee7aab, 0xf7d8b57e27ecf57b, + 0x3d04e8d2fca26a9f, 0x3172826ac9df13cb, 0xa8fcd8e0cd9e8d7c, + 0x307641d9b2c39497, 0x2608c4cf1cc939c1, 0x3d326a7eb6d1c7bf, + 0x8e13e25feeaf19e6, 0x2dfe6d97ee63302b, 0xe41d3cc425971d58, + 0xab8db59a0a80627c, 0xe90afb779eea37c8, 0x9ee3352c90ca19cf, + 0xfe78d6823613c850, 0x5b060904788f6e50, 0x3fecb534b71bd1a4, + 0x20c33857b32c450c, 0x0239f4cea6e9cfda, 0xa19adb9548497187, + 0x95aca6a8b492ed8a, 0xcf1b23504dcd6cd9, 0x1a67778cfbe8b12a, + 0xc32da38338eb3acc, 0xa03f40a8fb126ab1, 0xe9ce4724ed5bf546, + 0x73a130d84c4a74fd, 0xa2ebd6c1d9960e2d, 0x6f233b7c94ab6feb, + 0x8e7b9a7349126080, 0xd298f9994b8c9091, 0xa96ddeff35e836b5, + 0x6b0dd9bc96119b31, 0x282566fbc6cc3f8d, 0xd6769f3b72b882e7, + 0x00fc509ba674343d, 0xd6266a3fdcbf7789, 0x4e89541bae9641fd, + 0x53400d0311953407, 0xe5b533458e0dd75a, 0x108b89bc108f19ad, + 0xe03b2b6341a4c954, 0x97aced8e437b3d7f, 0x2c5508c2cbd66670, + 0x5c4f2ef0650ebc69, 0x9985a2df904ff6bf, 0x5ed8d2399faddd9e, + 0xe3e51cb925585832, 0x56c02d9a0ff4f1d4, 0xc1a08a138c4ef804, + 0xe6d2767113fd01c8, 0x9d0176cca7c234f4, 0x4d8bfa89d0d73df2, + 0x2b17e0b2544f10cd, 0xfd86fe49b70a5c7d, 0x214495bbdf373f41, + 0x00d313d584e857fd, 0xa4ba47440496fcbe, 0xaec29e6ee8cac982, + 0x7000a51987ec7038, 0xff66e42caeee333b, 0x03b4f63b8afd6b25, + 0x5ab8d9c7bd7991dc, 0x48741a6c2ed4684e, 0x2fdc6349af06940d, + 0xe974996fb03d7ecd, 0x52ec8721ac7867f9, 0x8edd2d00bcdd9d4a, + 0x41c759f83557de06, 0xa75409f23956d4b9, 0xb6100fab123cd8a1, + 0x2e8d623b3e7b21e2, 0xbca35f7792959da2, 0x35fcb457200c03a5, + 0xf74eb9281bb6c6e4, 0x87cc1d213d5d0b54, 0x18ae42404964046f, + 0x8bd2b496d868b275, 0xc234d8f51c5563f4, 0xf9151ffff868e970, + 0x271133eeae7be4a2, 0x25254932bb0fd922, 0x104bcd64a60a9fc0, + 0x0000006230290145 }; + +#define LAST_POW10 12 + +#else +# error "mp_limb size " BITS_PER_MP_LIMB "not accounted for" +#endif + + +/* Each of array variable above defines one mpn integer which is a power of 10. + This table points to those variables, indexed by the exponent. */ + +const struct mp_power _fpioconst_pow10[LDBL_MAX_10_EXP_LOG + 1] = + { + { _ten_p0, sizeof (_ten_p0) / sizeof (_ten_p0[0]), 4, }, + { _ten_p1, sizeof (_ten_p1) / sizeof (_ten_p0[1]), 7, 4 }, + { _ten_p2, sizeof (_ten_p2) / sizeof (_ten_p0[2]), 14, 10 }, + { _ten_p3, sizeof (_ten_p3) / sizeof (_ten_p0[3]), 27, 24 }, + { _ten_p4, sizeof (_ten_p4) / sizeof (_ten_p0[4]), 54, 50 }, + { _ten_p5, sizeof (_ten_p5) / sizeof (_ten_p0[5]), 107, 103 }, + { _ten_p6, sizeof (_ten_p6) / sizeof (_ten_p0[6]), 213, 210 }, + { _ten_p7, sizeof (_ten_p7) / sizeof (_ten_p0[7]), 426, 422 }, + { _ten_p8, sizeof (_ten_p8) / sizeof (_ten_p0[8]), 851, 848 }, + { _ten_p9, sizeof (_ten_p9) / sizeof (_ten_p0[9]), 1701, 1698 }, + { _ten_p10, sizeof (_ten_p10) / sizeof (_ten_p0[10]), 3402, 3399 }, + { _ten_p11, sizeof (_ten_p11) / sizeof (_ten_p0[11]), 6804, 6800 }, + { _ten_p12, sizeof (_ten_p12) / sizeof (_ten_p0[12]), 13607, 13604 } + }; + +#if LDBL_MAX_10_EXP_LOG > LAST_POW10 +#error "Need to expand 10^(2^i) table for i up to" LDBL_MAX_10_EXP_LOG +#endif diff --git a/stdio/fpioconst.h b/stdio/fpioconst.h new file mode 100644 index 0000000000..8edbdccb17 --- /dev/null +++ b/stdio/fpioconst.h @@ -0,0 +1,52 @@ +/* Header file for constants used in floating point <-> decimal conversions. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _FPIOCONST_H +#define _FPIOCONST_H + +#include <float.h> +#include "gmp.h" + + +/* These values are used by __printf_fp, where they are noncritical (if the + value is not large enough, it will just be slower); and by + strtof/strtod/strtold, where it is critical (it's used for overflow + detection). + + XXX These should be defined in <float.h>. For the time being, we have the + IEEE754 values here. */ + +#define LDBL_MAX_10_EXP_LOG 12 /* = floor(log_2(LDBL_MAX_10_EXP)) */ +#define DBL_MAX_10_EXP_LOG 8 /* = floor(log_2(DBL_MAX_10_EXP)) */ +#define FLT_MAX_10_EXP_LOG 5 /* = floor(log_2(FLT_MAX_10_EXP)) */ + + +/* Table of powers of ten. This is used by __printf_fp and by + strtof/strtod/strtold. */ +struct mp_power + { + const mp_limb *array; /* The array with the number representation. */ + mp_size_t arraysize; /* Size of the array. */ + int p_expo; /* Exponent of the number 10^(2^i). */ + int m_expo; /* Exponent of the number 10^-(2^i-1). */ + }; +extern const struct mp_power _fpioconst_pow10[LDBL_MAX_10_EXP_LOG + 1]; + + +#endif /* fpioconst.h */ diff --git a/stdio/fprintf.c b/stdio/fprintf.c new file mode 100644 index 0000000000..bc6d1003b7 --- /dev/null +++ b/stdio/fprintf.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Write formatted output to STREAM from the format string FORMAT. */ +/* VARARGS2 */ +int +DEFUN(fprintf, (stream, format), + FILE *stream AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vfprintf(stream, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/fputc.c b/stdio/fputc.c new file mode 100644 index 0000000000..36b9501195 --- /dev/null +++ b/stdio/fputc.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + + +/* Write the character C to STREAM. */ +int +DEFUN(fputc, (c, stream), int c AND FILE *stream) +{ + if (!__validfp(stream) || !stream->__mode.__write) + { + errno = EINVAL; + return EOF; + } + + return __putc(c, stream); +} diff --git a/stdio/fputs.c b/stdio/fputs.c new file mode 100644 index 0000000000..a149a1c329 --- /dev/null +++ b/stdio/fputs.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + + +/* Write the string S to STREAM. */ +int +DEFUN(fputs, (s, stream), CONST char *s AND FILE *stream) +{ + register CONST size_t len = strlen (s); + if (len == 1) + return putc (*s, stream) == EOF ? EOF : 0; + if (fwrite ((PTR) s, 1, len, stream) != len) + return EOF; + return 0; +} diff --git a/stdio/fread.c b/stdio/fread.c new file mode 100644 index 0000000000..347e8446e1 --- /dev/null +++ b/stdio/fread.c @@ -0,0 +1,128 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + + +#define default_func __default_room_functions.__input + +/* Read NMEMB chunks of SIZE bytes each from STREAM into P. */ +size_t +DEFUN(fread, (p, size, nmemb, stream), + PTR p AND size_t size AND size_t nmemb AND register FILE *stream) +{ + register char *ptr = (char *) p; + register size_t to_read = size * nmemb; + size_t bytes = to_read; + + if (!__validfp(stream) || !stream->__mode.__read) + { + errno = EINVAL; + return 0; + } + if (feof(stream) || ferror(stream)) + return 0; + if (p == NULL || to_read == 0) + return 0; + + if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back) + { + /* This stream has never been seen before, or it has a character + pushed back. Call __fillbf to deal with those cases. Life will + be simpler after this call. */ + int c = __fillbf(stream); + if (c == EOF) + return 0; + *ptr++ = c; + if (--to_read == 0) + return 1; + } + + read_from_buffer:; + if (stream->__bufp < stream->__get_limit) + { + /* First off, empty out the buffer. */ + register size_t copy = stream->__get_limit - stream->__bufp; + if (copy > to_read) + copy = to_read; + to_read -= copy; + if (copy > 20) + memcpy((PTR) ptr, (PTR) stream->__bufp, copy); + else + { + register size_t i; + for (i = 0; i < copy; ++i) + ptr[i] = stream->__bufp[i]; + } + stream->__bufp += copy; + if (to_read == 0) + return nmemb; + ptr += copy; + } + + /* Reading directly into the user's buffer doesn't help when + using a user-specified input buffer filling/expanding function, + so we don't do it in that case. */ + if (to_read >= stream->__bufsize && + stream->__room_funcs.__input == default_func && + stream->__offset == stream->__target) + { + /* Read directly into the user's buffer. */ + if (stream->__io_funcs.__read != NULL) + while (to_read > 0) + { + register int count; + count = (*stream->__io_funcs.__read)(stream->__cookie, + ptr, to_read); + if (count > 0) + { + to_read -= count; + stream->__offset += count; + stream->__target += count; + ptr += count; + } + else if (count == 0) + { + stream->__eof = 1; + break; + } + else + { + stream->__error = 1; + break; + } + } + else + stream->__eof = 1; + } + else + { + int c = __fillbf(stream); + if (c == EOF) + return (bytes - to_read) / size; + *ptr++ = (char) c; + --to_read; + if (to_read > 0) + goto read_from_buffer; + } + + return (bytes - to_read) / size; +} diff --git a/stdio/freopen.c b/stdio/freopen.c new file mode 100644 index 0000000000..bedddb1a63 --- /dev/null +++ b/stdio/freopen.c @@ -0,0 +1,74 @@ +/* Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + + +/* Defined in fopen.c. */ +extern int __getmode __P ((const char *, __io_mode *)); + +/* Defined in sysd-stdio.c. */ +extern int __stdio_reopen __P ((const char *filename, __io_mode mode, + PTR *cookieptr, __io_close_fn closefn)); + +/* Replace STREAM, opening it on FILENAME. */ +FILE * +DEFUN(freopen, (filename, mode, stream), + CONST char *filename AND CONST char *mode AND register FILE *stream) +{ + __io_mode m; + PTR cookie; + + if (!__getmode (mode, &m)) + { + (void) fclose (stream); + errno = EINVAL; + return NULL; + } + + if (stream->__mode.__write) + /* Flush the stream. */ + (void) fflush (stream); + + /* Open the file, attempting to preserve the old cookie value. */ + cookie = stream->__cookie; + if (__stdio_reopen (filename, m, &cookie, + stream->__seen ? + stream->__io_funcs.__close : + __stdio_close)) + { + int save = errno; + (void) fclose (stream); + errno = save; + return NULL; + } + + /* Close the stream, first disabling its cookie close function because + __stdio_reopen has already dealt with closing the old cookie. */ + stream->__seen = 1; /* It might have no functions yet. */ + stream->__io_funcs.__close = NULL; + (void) fclose (stream); + + stream->__magic = _IOMAGIC; + stream->__cookie = cookie; + stream->__mode = m; + + return stream; +} diff --git a/stdio/fscanf.c b/stdio/fscanf.c new file mode 100644 index 0000000000..cbe0103368 --- /dev/null +++ b/stdio/fscanf.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Read formatted input from STREAM according to the format string FORMAT. */ +/* VARARGS2 */ +int +DEFUN(fscanf, (stream, format), + FILE *stream AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = __vfscanf(stream, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/fseek.c b/stdio/fseek.c new file mode 100644 index 0000000000..a5abfe4866 --- /dev/null +++ b/stdio/fseek.c @@ -0,0 +1,177 @@ +/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + + +/* Move the file position of STREAM to OFFSET + bytes from the beginning of the file if WHENCE + is SEEK_SET, the end of the file is it is SEEK_END, + or the current position if it is SEEK_CUR. */ +int +DEFUN(fseek, (stream, offset, whence), + register FILE *stream AND long int offset AND int whence) +{ + long int o; + + if (!__validfp (stream)) + { + errno = EINVAL; + return EOF; + } + + /* Write out any pending data. */ + if (stream->__mode.__write && __flshfp (stream, EOF) == EOF) + return EOF; + + /* Make sure we know the current offset info. */ + if (__stdio_check_offset (stream) == EOF) + return EOF; + + /* We are moving the file position, so we are no longer at EOF. */ + stream->__eof = 0; + + if (stream->__pushed_back) + { + /* Discard the character pushed back by ungetc. */ + stream->__bufp = stream->__pushback_bufp; + stream->__pushed_back = 0; + } + + /* Check the WHENCE argument for validity, and process OFFSET + into an absolute position in O. By the end of this switch, + either we have returned, or O contains an absolute position. */ + o = offset; + switch (whence) + { + default: + errno = EINVAL; + return EOF; + + case SEEK_END: + /* We don't know where the end of the file is, + so seek to the position in the file the user asked + for, and then look where that is. */ + if (stream->__io_funcs.__seek == NULL) + { + errno = ESPIPE; + return EOF; + } + else + { + fpos_t pos = (fpos_t) o; + if ((*stream->__io_funcs.__seek) + (stream->__cookie, &pos, SEEK_END) < 0) + { + if (errno == ESPIPE) + stream->__io_funcs.__seek = NULL; + return EOF; + } + stream->__offset = pos; + /* Make O be absolute, rather than + relative to the end of the file. */ + o = pos; + } + + /* Fall through to try an absolute seek. */ + + case SEEK_SET: + /* Make O be relative to the buffer. */ + o -= stream->__target; + /* Make O be relative to the current position in the buffer. */ + o -= stream->__bufp - stream->__buffer; + + /* Fall through to see if we can do it by + moving the pointer around in the buffer. */ + + case SEEK_CUR: + /* If the offset is small enough, we can just + move the pointer around in the buffer. */ + +#if 0 /* Why did I think this would ever work??? */ + if (stream->__put_limit > stream->__buffer) + { + /* We are writing. */ + if (stream->__bufp + o >= stream->__buffer && + stream->__put_limit > stream->__bufp + o && + stream->__get_limit > stream->__bufp + o) + { + /* We have read all the data we will change soon. + We can just move the pointer around. */ + stream->__bufp += o; + return 0; + } + else + { + /* Flush the buffer. */ + if (__flshfp(stream, EOF) == EOF) + return EOF; + } + } else +#endif + if (o < 0 ? + (-o <= stream->__bufp - stream->__buffer) : + (o <= stream->__get_limit - stream->__bufp)) + { + stream->__bufp += o; + return 0; + } + + /* Turn it into an absolute seek. */ + o += stream->__bufp - stream->__buffer; + o += stream->__target; + break; + } + + if (o < 0) + { + /* Negative file position is meaningless. */ + errno = EINVAL; + return -1; + } + + /* O is now an absolute position, the new target. */ + stream->__target = o; + + /* Set bufp and both end pointers to the beginning of the buffer. + The next i/o will force a call to the input/output room function. */ + stream->__bufp + = stream->__get_limit = stream->__put_limit = stream->__buffer; + + /* Make sure __flshfp doesn't think the put_limit is at the beginning + of the buffer because of line-buffering magic. */ + stream->__linebuf_active = 0; + + /* If there is no seek function, seeks always fail. */ + if (stream->__io_funcs.__seek == NULL) + { + /* This is preemptive, since we don't actually do the seeking. + But it makes more sense for fseek to to fail with ESPIPE + than for the next reading or writing operation to fail + that way. */ + errno = ESPIPE; + return EOF; + } + + /* Don't actually seek. The next reading or writing operation + will force a call to the input or output room function, + which will move to the target file position before reading or writing. */ + return 0; +} diff --git a/stdio/fsetpos.c b/stdio/fsetpos.c new file mode 100644 index 0000000000..7c8fcb78bb --- /dev/null +++ b/stdio/fsetpos.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +#undef fsetpos + + +/* Set the file position of STREAM to *POS. */ +int +DEFUN(fsetpos, (stream, pos), FILE *stream AND CONST fpos_t *pos) +{ + if (pos == NULL) + { + errno = EINVAL; + return EOF; + } + + return fseek(stream, *pos, SEEK_SET); +} diff --git a/stdio/ftell.c b/stdio/ftell.c new file mode 100644 index 0000000000..d27eaf7598 --- /dev/null +++ b/stdio/ftell.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + +/* Return the offset in bytes from the beginning + of the file of the file position of STREAM. */ +long int +DEFUN(ftell, (stream), FILE *stream) +{ + long int pos; + + if (!__validfp (stream)) + { + errno = EINVAL; + return -1L; + } + + if (__stdio_check_offset (stream) == EOF) + return -1L; + + /* Start with the file position associated with the beginning + of our buffer. */ + pos = stream->__target; + + if (stream->__pushed_back) + /* ungetc was just called, so our real buffer pointer is squirreled + away in STREAM->__pushback_bufp, not in STREAM->__bufp as normal. + Calling ungetc is supposed to decrement the file position. ANSI + says the file position is unspecified if you ungetc when the + position is zero; -1 seems as good as anything to me. */ + pos += stream->__pushback_bufp - stream->__buffer - 1; + else + pos += stream->__bufp - stream->__buffer; + + return pos; +} diff --git a/stdio/fwrite.c b/stdio/fwrite.c new file mode 100644 index 0000000000..4d012f1779 --- /dev/null +++ b/stdio/fwrite.c @@ -0,0 +1,208 @@ +/* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + + +/* Write NMEMB chunks of SIZE bytes each from PTR onto STREAM. */ +size_t +DEFUN(fwrite, (ptr, size, nmemb, stream), + CONST PTR ptr AND size_t size AND + size_t nmemb AND register FILE *stream) +{ + register CONST unsigned char *p = (CONST unsigned char *) ptr; + register size_t to_write = size * nmemb; + register size_t written = 0; + int newlinep; + size_t buffer_space; + int default_func; + + if (!__validfp (stream) || !stream->__mode.__write) + { + errno = EINVAL; + return 0; + } + + if (ferror (stream)) + return 0; + if (p == NULL || to_write == 0) + return 0; + + if (!stream->__seen || stream->__put_limit == stream->__buffer) + { + /* This stream has never been seen before. + Calling __flshfp will give it a buffer + and I/O functions if it needs them. */ + if (__flshfp (stream, *p++) == EOF) + return 0; + if (--to_write == 0) + return 1; + else + ++written; + } + + default_func + = stream->__room_funcs.__output == __default_room_functions.__output; + + { + int save = errno; + + if (__stdio_check_offset (stream) == EOF && errno != ESPIPE) + { + stream->__error = 1; + goto done; + } + + errno = save; + } + + if (stream->__buffer == NULL && default_func && + stream->__offset == stream->__target) + write_through: + /* This is an unbuffered stream using the standard output + buffer-flushing function, so we just do a straight write. */ + { + int count = (stream->__io_funcs.__write == NULL ? to_write : + (*stream->__io_funcs.__write) (stream->__cookie, + (CONST char *) p, + to_write)); + if (count > 0) + { + written += count; + if (stream->__offset != -1) + { + stream->__offset += count; + stream->__target = stream->__offset; + } + to_write -= count; + p += count; + } + else + stream->__error = 1; + goto done; + } + + /* We ignore the end pointer here since we want to find out how much space + is really in the buffer, even for a line-buffered stream. */ + buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer); + + newlinep = (stream->__linebuf && + memchr ((CONST PTR) p, '\n', to_write) != NULL); + + if (newlinep && stream->__bufp == stream->__buffer && + stream->__offset == stream->__target) + /* The buffer's empty, and we want to write our data + out soon anyway, so just write it straight out. */ + goto write_through; + + if (stream->__bufsize == 0 && !default_func) + { + /* No buffer, and a special function. + We can't do much better than putc. */ + while (to_write-- > 0) + { + if (__flshfp (stream, *p++) == EOF) + break; + else + ++written; + } + } + else if (!default_func || buffer_space >= to_write) + fill_buffer: + /* There is enough room in the buffer for everything we + want to write or the user has specified his own output + buffer-flushing/expanding function. */ + while (to_write > 0) + { + register size_t n = to_write; + + if (n > buffer_space) + n = buffer_space; + + buffer_space -= n; + + written += n; + to_write -= n; + + if (n < 20) + while (n-- > 0) + *stream->__bufp++ = *p++; + else + { + memcpy ((PTR) stream->__bufp, (PTR) p, n); + stream->__bufp += n; + p += n; + } + + if (buffer_space == 0 || (to_write == 0 && newlinep)) + { + /* We've filled the buffer, so flush it. */ + if (fflush (stream) == EOF) + break; + + /* Reset our record of the space available in the buffer, + since we have just flushed it. */ + check_space: + buffer_space = (stream->__bufsize - + (stream->__bufp - stream->__buffer)); + if (buffer_space == 0) + { + /* With a custom output-room function, flushing might + not create any buffer space. Try writing a single + character to create the space. */ + if (__flshfp (stream, *p++) == EOF) + goto done; + ++written; + --to_write; + goto check_space; + } + } + } + else + { + /* It won't all fit in the buffer. */ + + if (stream->__bufp != stream->__buffer) + { + /* There are characters in the buffer. Flush them. */ + if (__flshfp (stream, EOF) == EOF) + goto done; + } + + /* The buffer has been flushed. + Now either fill it or write directly. */ + + buffer_space = stream->__bufsize - (stream->__bufp - stream->__buffer); + + if (stream->__offset == stream->__target && + (buffer_space < to_write || newlinep)) + /* What we have to write is bigger than the buffer, + or it contains a newline and we're line-buffered, + so write it out. */ + goto write_through; + else + /* It will fit in the buffer. */ + goto fill_buffer; + } + + done:; + return (size_t) written / size; +} diff --git a/stdio/gen-mpn-copy b/stdio/gen-mpn-copy new file mode 100644 index 0000000000..b403f27a55 --- /dev/null +++ b/stdio/gen-mpn-copy @@ -0,0 +1,31 @@ +#!/bin/sh + +translations=' +pentium i386/i586 +sparc8 sparc/sparc8 +sparc9 sparc/sparc9 +mc68000 m68k/m68000 +mc68020 m68k/m68020 +mc88100 m88k/m88100 +mc88110 m88k/m88110 +r3000 mips +r4000 mips/mips64 +hppa1_0 hppa/hppa1.0 +hppa1_1 hppa/hppa1.1 +' + +set $translations +while [ $# -ge 2 ]; do + gmp=$1 glibc=$2 + shift; shift + echo 'mpn-found-1 := $(filter $(gmp-srcdir)/mpn/'$gmp'/%,$(mpn-found)) +mpn-copy-1 := $(patsubst $(gmp-srcdir)/mpn/'$gmp'/%,$(sysdep_dir)/'$glibc\ +'/%,$(mpn-found-1)) +mpn-found := $(filter-out $(mpn-found-1),$(mpn-found)) +mpn-copy-sysdep := $(mpn-copy-sysdep) $(mpn-copy-1) +$(mpn-copy-1): $(sysdep_dir)/'$glibc'/%: \ + $(ignore gmp2glibc.sed) $(gmp-srcdir)/mpn/'$gmp'/% + $(gmp2glibc)' +done + +exit 0 diff --git a/stdio/getc.c b/stdio/getc.c new file mode 100644 index 0000000000..00aee33d31 --- /dev/null +++ b/stdio/getc.c @@ -0,0 +1,5 @@ +#include <ansidecl.h> +#include <stdio.h> +#undef getc +#define fgetc getc +#include <fgetc.c> diff --git a/stdio/getchar.c b/stdio/getchar.c new file mode 100644 index 0000000000..427de7738f --- /dev/null +++ b/stdio/getchar.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + +#undef getchar + + +/* Read a character from stdin. */ +int +DEFUN_VOID(getchar) +{ + return __getc(stdin); +} diff --git a/stdio/getdelim.c b/stdio/getdelim.c new file mode 100644 index 0000000000..8047c1fe0c --- /dev/null +++ b/stdio/getdelim.c @@ -0,0 +1,173 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR + (and null-terminate it). *LINEPTR is a pointer returned from malloc (or + NULL), pointing to *N characters of space. It is realloc'd as + necessary. Returns the number of characters read (not including the + null terminator), or -1 on error or EOF. */ + +ssize_t +DEFUN(__getdelim, (lineptr, n, terminator, stream), + char **lineptr AND size_t *n AND int terminator AND FILE *stream) +{ + char *line, *p; + size_t size, copy; + + if (!__validfp (stream) || lineptr == NULL || n == NULL) + { + errno = EINVAL; + return -1; + } + + if (ferror (stream)) + return -1; + + /* Make sure we have a line buffer to start with. */ + if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars. */ + { +#ifndef MAX_CANON +#define MAX_CANON 256 +#endif + line = realloc (*lineptr, MAX_CANON); + if (line == NULL) + return -1; + *lineptr = line; + *n = MAX_CANON; + } + + line = *lineptr; + size = *n; + + copy = size; + p = line; + + if (stream->__buffer == NULL && stream->__userbuf) + { + /* Unbuffered stream. Not much optimization to do. */ + + while (1) + { + size_t len; + + while (--copy > 0) + { + register int c = getc (stream); + if (c == EOF) + goto lose; + else if ((*p++ = c) == terminator) + goto win; + } + + /* Need to enlarge the line buffer. */ + len = p - line; + size *= 2; + line = realloc (line, size); + if (line == NULL) + goto lose; + *lineptr = line; + *n = size; + p = line + len; + copy = size - len; + } + } + else + { + /* Leave space for the terminating null. */ + --copy; + + if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back) + { + /* Do one with getc to allocate a buffer. */ + int c = getc (stream); + if (c == EOF) + goto lose; + *p++ = c; + if (c == terminator) + goto win; + --copy; + } + + while (1) + { + size_t i; + char *found; + + i = stream->__get_limit - stream->__bufp; + if (i == 0) + { + /* Refill the buffer. */ + int c = __fillbf (stream); + if (c == EOF) + goto lose; + *p++ = c; + if (c == terminator) + goto win; + --copy; + i = stream->__get_limit - stream->__bufp; + } + + if (i > copy) + i = copy; + + found = (char *) __memccpy ((PTR) p, stream->__bufp, terminator, i); + if (found != NULL) + { + stream->__bufp += found - p; + p = found; + goto win; + } + + stream->__bufp += i; + p += i; + copy -= i; + if (copy == 0) + { + /* Need to enlarge the line buffer. */ + size_t len = p - line; + size *= 2; + line = realloc (line, size); + if (line == NULL) + goto lose; + *lineptr = line; + *n = size; + p = line + len; + copy = size - len; + /* Leave space for the terminating null. */ + --copy; + } + } + } + + lose: + if (p == *lineptr) + return -1; + /* Return a partial line since we got an error in the middle. */ + win: + *p = '\0'; + return p - *lineptr; +} + +weak_alias (__getdelim, getdelim) diff --git a/stdio/getline.c b/stdio/getline.c new file mode 100644 index 0000000000..1a2f975c75 --- /dev/null +++ b/stdio/getline.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> + +#undef __getline + +/* Like getdelim, but always looks for a newline. */ +ssize_t +DEFUN(__getline, (lineptr, n, stream), + char **lineptr AND size_t *n AND FILE *stream) +{ + return __getdelim (lineptr, n, '\n', stream); +} + +weak_alias (__getline, getline) diff --git a/stdio/gets.c b/stdio/gets.c new file mode 100644 index 0000000000..2267792fb0 --- /dev/null +++ b/stdio/gets.c @@ -0,0 +1,59 @@ +/* Copyright (C) 1991, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> + +link_warning ("the `gets' function is unreliable and should not be used.") + +/* Read a newline-terminated string from stdin into S, + removing the trailing newline. Return S or NULL. */ +char * +DEFUN(gets, (s), char *s) +{ + register char *p = s; + register int c; + FILE *stream = stdin; + + if (!__validfp(stream) || p == NULL) + { + errno = EINVAL; + return NULL; + } + + if (feof(stream) || ferror(stream)) + return NULL; + + while ((c = getchar()) != EOF) + if (c == '\n') + break; + else + *p++ = c; + + *p = '\0'; + + /* Return null if we had an error, or if we got EOF + before writing any characters. */ + + if (ferror (stream) || (feof (stream) && p == s)) + return NULL; + + return s; +} diff --git a/stdio/getw.c b/stdio/getw.c new file mode 100644 index 0000000000..45d4d8875d --- /dev/null +++ b/stdio/getw.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + + +/* Read a word (int) from STREAM. */ +int +DEFUN(getw, (stream), FILE *stream) +{ + int w; + + /* Is there a better way? */ + if (fread((PTR) &w, sizeof(w), 1, stream) != 1) + return(EOF); + return(w); +} diff --git a/stdio/glue.c b/stdio/glue.c new file mode 100644 index 0000000000..6ef52a7ada --- /dev/null +++ b/stdio/glue.c @@ -0,0 +1,114 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* This file provides glue between Unix stdio and GNU stdio. + It supports use of Unix stdio `getc' and `putc' (and, by extension, + `getchar' and `putchar') macros on GNU stdio streams (they are slow, but + they work). It also supports all stdio operations (including Unix + `getc' and `putc') on Unix's stdin, stdout, and stderr (the elements of + `_iob'). + + The reasoning behind this is to allow programs (and especially + libraries) compiled with Unix header files to work with the GNU C + library. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <errno.h> + +typedef union + { + struct + { + int magic; + FILE **streamp; /* Overlaps GNU stdio `bufp' member. */ + /* These two overlap the GNU stdio `get_limit' and `put_limit' + members. They must be <= `streamp'/`bufp' for GNU getc and putc + to do the right thing. */ + FILE **streamp2, **streamp3; + } glue; + struct _iobuf + { + int _cnt; + unsigned char *_ptr; + unsigned char *_base; + int _bufsiz; + short int _flag; + char _file; + } unix_iobuf; + FILE gnu_stream; + } unix_FILE; + +/* These are the Unix stdio's stdin, stdout, and stderr. + In Unix stdin is (&_iob[0]), stdout is (&_iob[1]), and stderr is + (&_iob[2]). The magic number marks these as glued streams. The + __validfp macro in stdio.h is used by every stdio function. It checks + for glued streams, and replaces them with the GNU stdio stream. */ +unix_FILE _iob[] = + { +#define S(name) { { _GLUEMAGIC, &name, &name, &name } } + S (stdin), + S (stdout), + S (stderr), +#undef S + }; + +/* Called by the Unix stdio `getc' macro. + The macro is assumed to look something like: + (--file->_cnt < 0 ? _filbuf (file) ...) + In a Unix stdio FILE `_cnt' is the first element. + In a GNU stdio or glued FILE, the first element is the magic number. */ +int +DEFUN(_filbuf, (file), unix_FILE *file) +{ + switch (++file->glue.magic) /* Compensate for Unix getc's decrement. */ + { + case _GLUEMAGIC: + /* This is a glued stream. */ + return getc (*file->glue.streamp); + + case _IOMAGIC: + /* This is a normal GNU stdio stream. */ + return getc ((FILE *) file); + + default: + /* Bogus stream. */ + errno = EINVAL; + return EOF; + } +} + +/* Called by the Unix stdio `putc' macro. Much like getc, above. */ +int +DEFUN(_flsbuf, (c, file), + int c AND unix_FILE *file) +{ + /* Compensate for putc's decrement. */ + switch (++file->glue.magic) + { + case _GLUEMAGIC: + return putc (c, *file->glue.streamp); + + case _IOMAGIC: + return putc (c, (FILE *) file); + + default: + errno = EINVAL; + return EOF; + } +} diff --git a/stdio/gmp-impl.h b/stdio/gmp-impl.h new file mode 100644 index 0000000000..ccffe7bb1e --- /dev/null +++ b/stdio/gmp-impl.h @@ -0,0 +1,283 @@ +/* Include file for internal GNU MP types and definitions. + +Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if ! defined (alloca) +#if defined (__GNUC__) || defined (__sparc__) || defined (sparc) +#define alloca __builtin_alloca +#endif +#endif + +#ifndef NULL +#define NULL 0L +#endif + +#if ! defined (__GNUC__) +#define inline /* Empty */ +void *alloca(); +#endif + +#define ABS(x) (x >= 0 ? x : -x) +#define MIN(l,o) ((l) < (o) ? (l) : (o)) +#define MAX(h,i) ((h) > (i) ? (h) : (i)) + +#include "gmp-mparam.h" +/* #include "longlong.h" */ + +#ifdef __STDC__ +void *malloc (size_t); +void *realloc (void *, size_t); +void free (void *); + +extern void * (*_mp_allocate_func) (size_t); +extern void * (*_mp_reallocate_func) (void *, size_t, size_t); +extern void (*_mp_free_func) (void *, size_t); + +void *_mp_default_allocate (size_t); +void *_mp_default_reallocate (void *, size_t, size_t); +void _mp_default_free (void *, size_t); + +#else + +#define const /* Empty */ +#define signed /* Empty */ + +void *malloc (); +void *realloc (); +void free (); + +extern void * (*_mp_allocate_func) (); +extern void * (*_mp_reallocate_func) (); +extern void (*_mp_free_func) (); + +void *_mp_default_allocate (); +void *_mp_default_reallocate (); +void _mp_default_free (); +#endif + +/* Copy NLIMBS *limbs* from SRC to DST. */ +#define MPN_COPY_INCR(DST, SRC, NLIMBS) \ + do { \ + mp_size_t __i; \ + for (__i = 0; __i < (NLIMBS); __i++) \ + (DST)[__i] = (SRC)[__i]; \ + } while (0) +#define MPN_COPY_DECR(DST, SRC, NLIMBS) \ + do { \ + mp_size_t __i; \ + for (__i = (NLIMBS) - 1; __i >= 0; __i--) \ + (DST)[__i] = (SRC)[__i]; \ + } while (0) +#define MPN_COPY MPN_COPY_INCR + +/* Zero NLIMBS *limbs* AT DST. */ +#define MPN_ZERO(DST, NLIMBS) \ + do { \ + mp_size_t __i; \ + for (__i = 0; __i < (NLIMBS); __i++) \ + (DST)[__i] = 0; \ + } while (0) + +#define MPN_NORMALIZE(DST, NLIMBS) \ + do { \ + while (NLIMBS > 0) \ + { \ + if ((DST)[(NLIMBS) - 1] != 0) \ + break; \ + NLIMBS--; \ + } \ + } while (0) +#define MPN_NORMALIZE_NOT_ZERO(DST, NLIMBS) \ + do { \ + while (1) \ + { \ + if ((DST)[(NLIMBS) - 1] != 0) \ + break; \ + NLIMBS--; \ + } \ + } while (0) + +/* Swap (mp_ptr, mp_size_t) (U, UL) with (V, VL) */ +#define MPN_SWAP(u, l, v, m) \ + do { \ + { mp_ptr _; _ = (u), (u) = (v), (v) = _;} \ + { mp_size_t _; _ = (l), (l) = (m), (m) = _;} \ + } while (0) + +/* Return true iff the limb X has less bits than the limb Y. */ +#define MPN_LESS_BITS_LIMB(x,y) ((x) < (y) && (x) < ((x) ^ (y))) + +/* Return true iff (mp_ptr, mp_size_t) (U, UL) has less bits than (V, VL). */ +#define MPN_LESS_BITS(u, l, v, m) \ + ((l) < (m) \ + || ((l) == (m) && (l) != 0 && MPN_LESS_BITS_LIMB ((u)[(l - 1)], (v)[(l) - 1]))) + +/* Return true iff (mp_ptr, mp_size_t) (U, UL) has more bits than (V, VL). */ +#define MPN_MORE_BITS(u, l, v, m) MPN_LESS_BITS (v, m, u, l) + +/* Perform twos complement on (mp_ptr, mp_size_t) (U, UL), + putting result at (v, VL). Precondition: U[0] != 0. */ +#define MPN_COMPL_INCR(u, v, l) \ + do { \ + mp_size_t _ = 0; \ + (u)[0] = -(v)[_]; \ + while (_++ < (l)) \ + (u)[_] = ~(v)[_]; \ + } while (0) +#define MPN_COMPL MPN_COMPL_INCR + +/* Initialize the MP_INT X with space for NLIMBS limbs. + X should be a temporary variable, and it will be automatically + cleared out when the running function returns. + We use __x here to make it possible to accept both mpz_ptr and mpz_t + arguments. */ +#define MPZ_TMP_INIT(X, NLIMBS) \ + do { \ + mpz_ptr __x = (X); \ + __x->alloc = (NLIMBS); \ + __x->d = (mp_ptr) alloca ((NLIMBS) * BYTES_PER_MP_LIMB); \ + } while (0) + +#define MPN_MUL_N_RECURSE(prodp, up, vp, size, tspace) \ + do { \ + if ((size) < KARATSUBA_THRESHOLD) \ + ____mpn_mul_n_basecase (prodp, up, vp, size); \ + else \ + ____mpn_mul_n (prodp, up, vp, size, tspace); \ + } while (0); +#define MPN_SQR_N_RECURSE(prodp, up, size, tspace) \ + do { \ + if ((size) < KARATSUBA_THRESHOLD) \ + ____mpn_sqr_n_basecase (prodp, up, size); \ + else \ + ____mpn_sqr_n (prodp, up, size, tspace); \ + } while (0); + +/* Structure for conversion between internal binary format and + strings in base 2..36. */ +struct bases +{ + /* Number of digits in the conversion base that always fits in + an mp_limb. For example, for base 10 this is 10, since + 2**32 = 4294967296 has ten digits. */ + int chars_per_limb; + + /* log(2)/log(conversion_base) */ + float chars_per_bit_exactly; + + /* big_base is conversion_base**chars_per_limb, i.e. the biggest + number that fits a word, built by factors of conversion_base. + Exception: For 2, 4, 8, etc, big_base is log2(base), i.e. the + number of bits used to represent each digit in the base. */ + mp_limb big_base; + + /* big_base_inverted is a BITS_PER_MP_LIMB bit approximation to + 1/big_base, represented as a fixed-point number. Instead of + dividing by big_base an application can choose to multiply + by big_base_inverted. */ + mp_limb big_base_inverted; +}; + +extern const struct bases __mp_bases[]; +extern mp_size_t __gmp_default_fp_limb_precision; + +/* Divide the two-limb number in (NH,,NL) by D, with DI being a 32 bit + approximation to (2**(2*BITS_PER_MP_LIMB))/D - (2**BITS_PER_MP_LIMB). + Put the quotient in Q and the remainder in R. */ +#define udiv_qrnnd_preinv(q, r, nh, nl, d, di) \ + do { \ + mp_limb _q, _ql, _r; \ + mp_limb _xh, _xl; \ + umul_ppmm (_q, _ql, (nh), (di)); \ + _q += (nh); /* DI is 2**BITS_PER_MP_LIMB too small */\ + umul_ppmm (_xh, _xl, _q, (d)); \ + sub_ddmmss (_xh, _r, (nh), (nl), _xh, _xl); \ + if (_xh != 0) \ + { \ + sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \ + _q += 1; \ + if (_xh != 0) \ + { \ + sub_ddmmss (_xh, _r, _xh, _r, 0, (d)); \ + _q += 1; \ + } \ + } \ + if (_r >= (d)) \ + { \ + _r -= (d); \ + _q += 1; \ + } \ + (r) = _r; \ + (q) = _q; \ + } while (0) +#define udiv_qrnnd_preinv2gen(q, r, nh, nl, d, di, dnorm, lgup) \ + do { \ + mp_limb n2, n10, n1, nadj, q1; \ + mp_limb _xh, _xl; \ + n2 = ((nh) << (BITS_PER_MP_LIMB - (lgup))) + ((nl) >> 1 >> (l - 1));\ + n10 = (nl) << (BITS_PER_MP_LIMB - (lgup)); \ + n1 = ((mp_limb_signed) n10 >> (BITS_PER_MP_LIMB - 1)); \ + nadj = n10 + (n1 & (dnorm)); \ + umul_ppmm (_xh, _xl, di, n2 - n1); \ + add_ssaaaa (_xh, _xl, _xh, _xl, 0, nadj); \ + q1 = ~(n2 + _xh); \ + umul_ppmm (_xh, _xl, q1, d); \ + add_ssaaaa (_xh, _xl, _xh, _xl, nh, nl); \ + _xh -= (d); \ + (r) = _xl + ((d) & _xh); \ + (q) = _xh - q1; \ + } while (0) +#define udiv_qrnnd_preinv2norm(q, r, nh, nl, d, di) \ + do { \ + mp_limb n2, n10, n1, nadj, q1; \ + mp_limb _xh, _xl; \ + n2 = (nh); \ + n10 = (nl); \ + n1 = ((mp_limb_signed) n10 >> (BITS_PER_MP_LIMB - 1)); \ + nadj = n10 + (n1 & (d)); \ + umul_ppmm (_xh, _xl, di, n2 - n1); \ + add_ssaaaa (_xh, _xl, _xh, _xl, 0, nadj); \ + q1 = ~(n2 + _xh); \ + umul_ppmm (_xh, _xl, q1, d); \ + add_ssaaaa (_xh, _xl, _xh, _xl, nh, nl); \ + _xh -= (d); \ + (r) = _xl + ((d) & _xh); \ + (q) = _xh - q1; \ + } while (0) + +#if defined (__GNUC__) +/* Define stuff for longlong.h asm macros. */ +#if __GNUC_NEW_ATTR_MODE_SYNTAX +typedef unsigned int UQItype __attribute__ ((mode ("QI"))); +typedef int SItype __attribute__ ((mode ("SI"))); +typedef unsigned int USItype __attribute__ ((mode ("SI"))); +typedef int DItype __attribute__ ((mode ("DI"))); +typedef unsigned int UDItype __attribute__ ((mode ("DI"))); +#else +typedef unsigned int UQItype __attribute__ ((mode (QI))); +typedef int SItype __attribute__ ((mode (SI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); +#endif +#endif + +typedef mp_limb UWtype; +typedef unsigned int UHWtype; +#define W_TYPE_SIZE BITS_PER_MP_LIMB diff --git a/stdio/gmp.h b/stdio/gmp.h new file mode 100644 index 0000000000..95c2f1beba --- /dev/null +++ b/stdio/gmp.h @@ -0,0 +1,525 @@ +/* gmp.h -- Definitions for GNU multiple precision functions. + +Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#ifndef __GMP_H__ + +#ifndef __GNU_MP__ +#define __need_size_t +#include <stddef.h> + +#ifdef __STDC__ +#define __gmp_const const +#else +#define __gmp_const +#endif + +#ifdef __GNUC__ +#define __gmp_inline inline +#else +#define __gmp_inline +#endif + +#ifdef _SHORT_LIMB +typedef unsigned int mp_limb; +typedef int mp_limb_signed; +#else +typedef unsigned long int mp_limb; +typedef long int mp_limb_signed; +#endif + +typedef mp_limb * mp_ptr; +typedef __gmp_const mp_limb * mp_srcptr; +typedef int mp_size_t; +typedef long int mp_exp_t; + +#ifndef __MP_SMALL__ +typedef struct +{ + long int alloc; /* Number of *limbs* allocated and pointed + to by the D field. */ + long int size; /* abs(SIZE) is the number of limbs + the last field points to. If SIZE + is negative this is a negative + number. */ + mp_limb *d; /* Pointer to the limbs. */ +} __mpz_struct; +#else +typedef struct +{ + short int alloc; /* Number of *limbs* allocated and pointed + to by the D field. */ + short int size; /* abs(SIZE) is the number of limbs + the last field points to. If SIZE + is negative this is a negative + number. */ + mp_limb *d; /* Pointer to the limbs. */ +} __mpz_struct; +#endif +#endif /* __GNU_MP__ */ + +/* User-visible types. */ +typedef __mpz_struct MP_INT; +typedef __mpz_struct mpz_t[1]; + +/* Structure for rational numbers. Zero is represented as 0/any, i.e. + the denominator is ignored. Negative numbers have the sign in + the numerator. */ +typedef struct +{ + __mpz_struct num; + __mpz_struct den; +#if 0 + long int num_alloc; /* Number of limbs allocated + for the numerator. */ + long int num_size; /* The absolute value of this field is the + length of the numerator; the sign is the + sign of the entire rational number. */ + mp_ptr num; /* Pointer to the numerator limbs. */ + long int den_alloc; /* Number of limbs allocated + for the denominator. */ + long int den_size; /* Length of the denominator. (This field + should always be positive.) */ + mp_ptr den; /* Pointer to the denominator limbs. */ +#endif +} __mpq_struct; + +typedef __mpq_struct MP_RAT; +typedef __mpq_struct mpq_t[1]; + +typedef struct +{ + mp_size_t alloc; /* Number of *limbs* allocated and pointed + to by the D field. */ + mp_size_t prec; /* Max precision, in number of `mp_limb's. + Set by mpf_init and modified by + mpf_set_prec. */ + mp_size_t size; /* abs(SIZE) is the number of limbs + the last field points to. If SIZE + is negative this is a negative + number. */ + mp_exp_t exp; /* Exponent, in the base of `mp_limb'. */ + mp_limb *d; /* Pointer to the limbs. */ +} __mpf_struct; + +/* typedef __mpf_struct MP_FLOAT; */ +typedef __mpf_struct mpf_t[1]; + +/* Types for function declarations in gmp files. */ +/* ??? Should not pollute user name space ??? */ +typedef __gmp_const __mpz_struct *mpz_srcptr; +typedef __mpz_struct *mpz_ptr; +typedef __gmp_const __mpf_struct *mpf_srcptr; +typedef __mpf_struct *mpf_ptr; +typedef __gmp_const __mpq_struct *mpq_srcptr; +typedef __mpq_struct *mpq_ptr; + +#ifdef __STDC__ +#define _PROTO(x) x +#else +#define _PROTO(x) () +#endif + +void mp_set_memory_functions _PROTO((void *(*) (size_t), + void *(*) (void *, size_t, size_t), + void (*) (void *, size_t))); + +/**************** Integer (i.e. Z) routines. ****************/ + +void *_mpz_realloc _PROTO ((mpz_ptr, mp_size_t)); + +void mpz_abs _PROTO ((mpz_ptr, mpz_srcptr)); +void mpz_add _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_add_ui _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_and _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_clear _PROTO ((mpz_ptr)); +void mpz_clrbit _PROTO ((mpz_ptr, unsigned long int)); +int mpz_cmp _PROTO ((mpz_srcptr, mpz_srcptr)); +int mpz_cmp_si _PROTO ((mpz_srcptr, signed long int)); +int mpz_cmp_ui _PROTO ((mpz_srcptr, unsigned long int)); +void mpz_com _PROTO ((mpz_ptr, mpz_srcptr)); +void mpz_div_2exp _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_fac_ui _PROTO ((mpz_ptr, unsigned long int)); +void mpz_gcd _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +unsigned long int mpz_gcd_ui _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_gcdext _PROTO ((mpz_ptr, mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); +/* signed */ long int mpz_get_si _PROTO ((mpz_srcptr)); +char *mpz_get_str _PROTO ((char *, int, mpz_srcptr)); +unsigned long int mpz_get_ui _PROTO ((mpz_srcptr)); +mp_limb mpz_getlimbn _PROTO ((mpz_srcptr, mp_size_t)); +mp_size_t mpz_hamdist _PROTO ((mpz_srcptr, mpz_srcptr)); +void mpz_init _PROTO ((mpz_ptr)); +#ifdef FILE +void mpz_inp_raw _PROTO ((mpz_ptr, FILE *)); +int mpz_inp_str _PROTO ((mpz_ptr, FILE *, int)); +#endif +void mpz_ior _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_init_set _PROTO ((mpz_ptr, mpz_srcptr)); +void mpz_init_set_si _PROTO ((mpz_ptr, signed long int)); +int mpz_init_set_str _PROTO ((mpz_ptr, const char *, int)); +void mpz_init_set_ui _PROTO ((mpz_ptr, unsigned long int)); +void mpz_lcm _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_mod_2exp _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_mul _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_mul_2exp _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_mul_ui _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_neg _PROTO ((mpz_ptr, mpz_srcptr)); +#ifdef FILE +void mpz_out_raw _PROTO ((FILE *, mpz_srcptr)); +void mpz_out_str _PROTO ((FILE *, int, mpz_srcptr)); +#endif +int mpz_perfect_square_p _PROTO ((mpz_srcptr)); +mp_size_t mpz_popcount _PROTO ((mpz_srcptr)); +void mpz_pow_ui _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_powm _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr, mpz_srcptr)); +void mpz_powm_ui _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int, mpz_srcptr)); +int mpz_probab_prime_p _PROTO ((mpz_srcptr, int)); +void mpz_random _PROTO ((mpz_ptr, mp_size_t)); +void mpz_random2 _PROTO ((mpz_ptr, mp_size_t)); +void mpz_set _PROTO ((mpz_ptr, mpz_srcptr)); +void mpz_set_si _PROTO ((mpz_ptr, signed long int)); +int mpz_set_str _PROTO ((mpz_ptr, const char *, int)); +void mpz_set_ui _PROTO ((mpz_ptr, unsigned long int)); +size_t mpz_size _PROTO ((mpz_srcptr)); +size_t mpz_sizeinbase _PROTO ((mpz_srcptr, int)); +void mpz_sqrt _PROTO ((mpz_ptr, mpz_srcptr)); +void mpz_sqrtrem _PROTO ((mpz_ptr, mpz_ptr, mpz_srcptr)); +void mpz_sub _PROTO ((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_sub_ui _PROTO ((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_ui_pow_ui _PROTO ((mpz_ptr, unsigned long int, unsigned long int)); + +void mpz_fdiv_q _PROTO((mpz_ptr, mpz_srcptr, mpz_srcptr)); +unsigned long int mpz_fdiv_q_ui _PROTO((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_fdiv_qr _PROTO((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); +unsigned long int mpz_fdiv_qr_ui _PROTO((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_fdiv_r _PROTO((mpz_ptr, mpz_srcptr, mpz_srcptr)); +unsigned long int mpz_fdiv_r_ui _PROTO((mpz_ptr, mpz_srcptr, unsigned long int)); +unsigned long int mpz_fdiv_ui _PROTO((mpz_srcptr, unsigned long int)); +void mpz_tdiv_q _PROTO((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_tdiv_q_ui _PROTO((mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_tdiv_qr _PROTO((mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_tdiv_qr_ui _PROTO((mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long int)); +void mpz_tdiv_r _PROTO((mpz_ptr, mpz_srcptr, mpz_srcptr)); +void mpz_tdiv_r_ui _PROTO((mpz_ptr, mpz_srcptr, unsigned long int)); + +/**************** Rational (i.e. Q) routines. ****************/ + +void mpq_init _PROTO ((mpq_ptr)); +void mpq_clear _PROTO ((mpq_ptr)); +void mpq_set _PROTO ((mpq_ptr, mpq_srcptr)); +void mpq_set_ui _PROTO ((mpq_ptr, unsigned long int, unsigned long int)); +void mpq_set_si _PROTO ((mpq_ptr, signed long int, unsigned long int)); +void mpq_add _PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); +void mpq_sub _PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); +void mpq_mul _PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); +void mpq_div _PROTO ((mpq_ptr, mpq_srcptr, mpq_srcptr)); +void mpq_neg _PROTO ((mpq_ptr, mpq_srcptr)); +int mpq_cmp _PROTO ((mpq_srcptr, mpq_srcptr)); +void mpq_inv _PROTO ((mpq_ptr, mpq_srcptr)); +void mpq_set_num _PROTO ((mpq_ptr, mpz_srcptr)); +void mpq_set_den _PROTO ((mpq_ptr, mpz_srcptr)); +void mpq_get_num _PROTO ((mpz_ptr, mpq_srcptr)); +void mpq_get_den _PROTO ((mpz_ptr, mpq_srcptr)); + +/**************** Float (i.e. F) routines. ****************/ + +void mpf_abs _PROTO ((mpf_ptr, mpf_srcptr)); +void mpf_add _PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); +void mpf_add_ui _PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +void mpf_clear _PROTO ((mpf_ptr)); +int mpf_cmp _PROTO ((mpf_srcptr, mpf_srcptr)); +int mpf_cmp_si _PROTO ((mpf_srcptr, long int)); +int mpf_cmp_ui _PROTO ((mpf_srcptr, unsigned long int)); +void mpf_div _PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); +void mpf_div_2exp _PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +void mpf_div_ui _PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +void mpf_dump _PROTO ((mpf_srcptr)); +char *mpf_get_str _PROTO ((char *, mp_exp_t *, int, size_t, mpf_srcptr)); +void mpf_init _PROTO ((mpf_ptr)); +void mpf_init2 _PROTO ((mpf_ptr, mp_size_t)); +#ifdef FILE +void mpf_inp_str _PROTO ((mpf_ptr, FILE *, int)); +#endif +void mpf_init_set _PROTO ((mpf_ptr, mpf_srcptr)); +void mpf_init_set_d _PROTO ((mpf_ptr, double)); +void mpf_init_set_si _PROTO ((mpf_ptr, long int)); +int mpf_init_set_str _PROTO ((mpf_ptr, char *, int)); +void mpf_init_set_ui _PROTO ((mpf_ptr, unsigned long int)); +void mpf_mul _PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); +void mpf_mul_2exp _PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +void mpf_mul_ui _PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +void mpf_neg _PROTO ((mpf_ptr, mpf_srcptr)); +#ifdef FILE +void mpf_out_str _PROTO ((mpf_ptr, int, size_t, FILE *)); +#endif +void mpf_set _PROTO ((mpf_ptr, mpf_srcptr)); +void mpf_set_d _PROTO ((mpf_ptr, double)); +mp_size_t mpf_set_default_prec _PROTO ((mp_size_t)); +void mpf_set_si _PROTO ((mpf_ptr, long int)); +int mpf_set_str _PROTO ((mpf_ptr, const char *, int)); +void mpf_set_ui _PROTO ((mpf_ptr, unsigned long int)); +size_t mpf_size _PROTO ((mpf_srcptr)); +void mpf_sqrt _PROTO ((mpf_ptr, mpf_srcptr)); +void mpf_sqrt_ui _PROTO ((mpf_ptr, unsigned long int)); +void mpf_sub _PROTO ((mpf_ptr, mpf_srcptr, mpf_srcptr)); +void mpf_sub_ui _PROTO ((mpf_ptr, mpf_srcptr, unsigned long int)); +void mpf_ui_div _PROTO ((mpf_ptr, unsigned long int, mpf_srcptr)); + +/************ Low level positive-integer (i.e. N) routines. ************/ + +/* This is ugly, but we need to make usr calls reach the prefixed function. */ +#define mpn_add_n __mpn_add_n +#define mpn_sub_n __mpn_sub_n +#define mpn_mul_1 __mpn_mul_1 +#define mpn_addmul_1 __mpn_addmul_1 +#define mpn_submul_1 __mpn_submul_1 +#define mpn_lshift __mpn_lshift +#define mpn_rshift __mpn_rshift +#define mpn_sub __mpn_sub +#define mpn_add __mpn_add +#define mpn_normal_size __mpn_normal_size +#define mpn_cmp __mpn_cmp +#define mpn_add_1 __mpn_add_1 +#define mpn_sub_1 __mpn_sub_1 +#define mpn_mul_n __mpn_mul_n +#define mpn_mul __mpn_mul +#define mpn_divmod __mpn_divmod +#define mpn_divmod_1 __mpn_divmod_1 +#define mpn_mod_1 __mpn_mod_1 +#define mpn_sqrt __mpn_sqrt +#define mpn_next_bit_set __mpn_next_bit_set +#define mpn_popcount __mpn_popcount +#define mpn_hamdist __mpn_hamdist +#define mpn_random2 __mpn_random2 +#define mpn_set_str __mpn_set_str +#define mpn_get_str __mpn_get_str +#define mpn_gcd_1 __mpn_gcd_1 + +mp_limb __mpn_add_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); +mp_limb __mpn_sub_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); +mp_limb __mpn_mul _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_srcptr, mp_size_t)); +void __mpn_mul_n _PROTO ((mp_ptr, mp_srcptr, mp_srcptr, mp_size_t)); +mp_limb __mpn_mul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb)); +mp_limb __mpn_addmul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb)); +mp_limb __mpn_submul_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb)); +mp_limb __mpn_divmod _PROTO ((mp_ptr, mp_ptr, mp_size_t, mp_srcptr, mp_size_t)); +mp_limb __mpn_divmod_1 _PROTO ((mp_ptr, mp_srcptr, mp_size_t, mp_limb)); +mp_limb __mpn_mod_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb)); +mp_limb __mpn_lshift _PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); +mp_limb __mpn_rshift _PROTO ((mp_ptr, mp_srcptr, mp_size_t, unsigned int)); +mp_size_t __mpn_sqrt _PROTO ((mp_ptr, mp_ptr, mp_srcptr, mp_size_t)); +int __mpn_cmp _PROTO ((mp_srcptr, mp_srcptr, mp_size_t)); +mp_size_t __mpn_next_bit_set _PROTO ((mp_srcptr, mp_size_t)); +mp_size_t __mpn_popcount _PROTO ((mp_srcptr, mp_size_t)); +mp_size_t __mpn_hamdist _PROTO ((mp_srcptr, mp_srcptr, mp_size_t)); +void __mpn_random2 _PROTO ((mp_ptr, mp_size_t)); +mp_size_t __mpn_set_str _PROTO ((mp_ptr, const unsigned char *, size_t, int)); +size_t __mpn_get_str _PROTO ((unsigned char *, int, mp_ptr, mp_size_t)); +mp_limb __mpn_gcd_1 _PROTO ((mp_srcptr, mp_size_t, mp_limb)); + + +static __gmp_inline mp_limb +#if __STDC__ +__mpn_add_1 (register mp_ptr res_ptr, + register mp_srcptr s1_ptr, + register mp_size_t s1_size, + register mp_limb s2_limb) +#else +__mpn_add_1 (res_ptr, s1_ptr, s1_size, s2_limb) + register mp_ptr res_ptr; + register mp_srcptr s1_ptr; + register mp_size_t s1_size; + register mp_limb s2_limb; +#endif +{ + register mp_limb x; + + x = *s1_ptr++; + s2_limb = x + s2_limb; + *res_ptr++ = s2_limb; + if (s2_limb < x) + { + while (--s1_size != 0) + { + x = *s1_ptr++ + 1; + *res_ptr++ = x; + if (x != 0) + goto fin; + } + + return 1; + } + + fin: + if (res_ptr != s1_ptr) + { + mp_size_t i; + for (i = 0; i < s1_size - 1; i++) + res_ptr[i] = s1_ptr[i]; + } + return 0; +} + +static __gmp_inline mp_limb +#if __STDC__ +__mpn_add (register mp_ptr res_ptr, + register mp_srcptr s1_ptr, + register mp_size_t s1_size, + register mp_srcptr s2_ptr, + register mp_size_t s2_size) +#else +__mpn_add (res_ptr, s1_ptr, s1_size, s2_ptr, s2_size) + register mp_ptr res_ptr; + register mp_srcptr s1_ptr; + register mp_size_t s1_size; + register mp_srcptr s2_ptr; + register mp_size_t s2_size; +#endif +{ + mp_limb cy_limb = 0; + + if (s2_size != 0) + cy_limb = __mpn_add_n (res_ptr, s1_ptr, s2_ptr, s2_size); + + if (s1_size - s2_size != 0) + cy_limb = __mpn_add_1 (res_ptr + s2_size, + s1_ptr + s2_size, + s1_size - s2_size, + cy_limb); + return cy_limb; +} + +static __gmp_inline mp_limb +#if __STDC__ +__mpn_sub_1 (register mp_ptr res_ptr, + register mp_srcptr s1_ptr, + register mp_size_t s1_size, + register mp_limb s2_limb) +#else +__mpn_sub_1 (res_ptr, s1_ptr, s1_size, s2_limb) + register mp_ptr res_ptr; + register mp_srcptr s1_ptr; + register mp_size_t s1_size; + register mp_limb s2_limb; +#endif +{ + register mp_limb x; + + x = *s1_ptr++; + s2_limb = x - s2_limb; + *res_ptr++ = s2_limb; + if (s2_limb > x) + { + while (--s1_size != 0) + { + x = *s1_ptr++; + *res_ptr++ = x - 1; + if (x != 0) + goto fin; + } + + return 1; + } + + fin: + if (res_ptr != s1_ptr) + { + mp_size_t i; + for (i = 0; i < s1_size - 1; i++) + res_ptr[i] = s1_ptr[i]; + } + return 0; +} + +static __gmp_inline mp_limb +#if __STDC__ +__mpn_sub (register mp_ptr res_ptr, + register mp_srcptr s1_ptr, + register mp_size_t s1_size, + register mp_srcptr s2_ptr, + register mp_size_t s2_size) +#else +__mpn_sub (res_ptr, s1_ptr, s1_size, s2_ptr, s2_size) + register mp_ptr res_ptr; + register mp_srcptr s1_ptr; + register mp_size_t s1_size; + register mp_srcptr s2_ptr; + register mp_size_t s2_size; +#endif +{ + mp_limb cy_limb = 0; + + if (s2_size != 0) + cy_limb = __mpn_sub_n (res_ptr, s1_ptr, s2_ptr, s2_size); + + if (s1_size - s2_size != 0) + cy_limb = __mpn_sub_1 (res_ptr + s2_size, + s1_ptr + s2_size, + s1_size - s2_size, + cy_limb); + return cy_limb; +} + +static __gmp_inline mp_size_t +#if __STDC__ +__mpn_normal_size (mp_srcptr ptr, mp_size_t size) +#else +__mpn_normal_size (ptr, size) + mp_srcptr ptr; + mp_size_t size; +#endif +{ + while (size) + { + size--; + if (ptr[size] != 0) + return size + 1; + } + return 0; +} + +/* Compatibility with GMP 1. */ + +#define mpz_mdiv mpz_fdiv_q +#define mpz_mdivmod mpz_fdiv_qr +#define mpz_mmod mpz_fdiv_r +#define mpz_mdiv_ui mpz_fdiv_q_ui +#define mpz_mdivmod_ui(q,r,n,d) \ + ((r == 0) ? mpz_fdiv_q_ui (q,n,d) : mpz_fdiv_qr_ui (q,r,n,d)) +#define mpz_mmod_ui(r,n,d) \ + ((r == 0) ? mpz_fdiv_ui (n,d) : mpz_fdiv_r_ui (r,n,d)) +/* ??? Before release... +#define mpz_div_2exp mpz_fdiv_q_2exp +#define mpz_mod_2exp mpz_fdiv_r_2exp +*/ + +/* Useful synonyms, but not quite compatible with GMP 1. */ +#define mpz_div mpz_fdiv_q +#define mpz_divmod mpz_fdiv_qr +#define mpz_mod mpz_fdiv_r +#define mpz_div_ui mpz_fdiv_q_ui +#define mpz_divmod_ui mpz_fdiv_qr_ui +#define mpz_mod_ui mpz_fdiv_r_ui + + +#define __GNU_MP__ 2 +#define __GNU_MP_VERSION 2 +#define __GNU_MP_VERSION_MINOR -900 /* ??? */ +#define __GMP_H__ +#endif /* __GMP_H__ */ diff --git a/stdio/internals.c b/stdio/internals.c new file mode 100644 index 0000000000..b01c5bd531 --- /dev/null +++ b/stdio/internals.c @@ -0,0 +1,667 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* Make sure that FP has its functions set. */ +void +DEFUN(__stdio_check_funcs, (fp), register FILE *fp) +{ + if (!fp->__seen) + { + /* Initialize the stream's info, including buffering info. + This may give a buffer, change I/O functions, etc. + If no buffer is set (and the stream is not made explicitly + unbuffered), we allocate a buffer below, using the bufsize + set by this function. */ + extern void EXFUN(__stdio_init_stream, (FILE *)); + fp->__room_funcs = __default_room_functions; + fp->__io_funcs = __default_io_functions; + __stdio_init_stream (fp); + fp->__seen = 1; + } +} + + +/* Minimum size of a buffer we will allocate by default. + If this much memory is not available, + the stream in question will be made unbuffered instead. */ +#define MIN_BUFSIZE 128 + +/* Figure out what kind of buffering (none, line, or full) + and what buffer size to give FP. */ +static void +DEFUN(init_stream, (fp), register FILE *fp) +{ + __stdio_check_funcs (fp); + + if (fp->__buffer == NULL && !fp->__userbuf) + { + int save; + + if (fp->__bufsize == 0) + fp->__bufsize = BUFSIZ; + + /* Try to get however many bytes of buffering __stdio_pickbuf + specified, but if that much memory isn't available, + try half as much each time until it succeeds or the buffer + size becomes too small to be useful. */ + save = errno; + while (fp->__bufsize >= MIN_BUFSIZE) + { + fp->__buffer = (char *) malloc(fp->__bufsize); + if (fp->__buffer == NULL) + fp->__bufsize /= 2; + else + break; + } + errno = save; + + if (fp->__buffer == NULL) + { + /* We can't get space for the buffer, so make it unbuffered. */ + fp->__userbuf = 1; + fp->__bufsize = 0; + } + } + + if (fp->__bufp == NULL) + { + /* Set the buffer pointer to the beginning of the buffer. */ + fp->__bufp = fp->__buffer; + fp->__put_limit = fp->__get_limit = fp->__buffer; + } +} + + +/* Determine the current file position of STREAM if it is unknown. */ +int +DEFUN(__stdio_check_offset, (stream), FILE *stream) +{ + init_stream (stream); + + if (stream->__offset == (fpos_t) -1) + { + /* This stream's offset is unknown or unknowable. */ + if (stream->__io_funcs.__seek == NULL) + { + /* Unknowable. */ + errno = ESPIPE; + return EOF; + } + else + { + /* Unknown. Find it out. */ + fpos_t pos = (fpos_t) 0; + if ((*stream->__io_funcs.__seek)(stream->__cookie, + &pos, SEEK_CUR) < 0) + { + if (errno == ESPIPE) + /* Object is incapable of seeking. */ + stream->__io_funcs.__seek = NULL; + return EOF; + } + stream->__offset = pos; + } + } + + if (stream->__target == (fpos_t) -1) + /* This stream was opened on an existing object with + an unknown file position. The position is now known. + Make this the target position. */ + stream->__target = stream->__offset; + + return 0; +} + + +/* Move FP's file position to its target file position, + seeking as necessary and updating its `offset' field. + Sets ferror(FP) (and possibly errno) for errors. */ +static void +DEFUN(seek_to_target, (fp), FILE *fp) +{ + int save = errno; + if (__stdio_check_offset (fp) == EOF) + { + if (errno == ESPIPE) + errno = save; + else + fp->__error = 1; + } + else if (fp->__target != fp->__offset) + { + /* We are not at the target file position. + Seek to that position. */ + if (fp->__io_funcs.__seek == NULL) + { + /* We can't seek! */ + errno = ESPIPE; + fp->__error = 1; + } + else + { + fpos_t pos = fp->__target; + if ((*fp->__io_funcs.__seek)(fp->__cookie, &pos, SEEK_SET) < 0) + /* Seek failed! */ + fp->__error = 1; + else + { + fp->__offset = pos; + if (pos != fp->__target) + /* Seek didn't go to the right place! */ + fp->__error = 1; + } + } + } +} + +/* Flush the buffer for FP. + If C is not EOF, it is also to be written. + If the stream is line buffered and C is a newline, it is written + to the output, otherwise it is put in the buffer after it has been + flushed to avoid a system call for a single character. + This is the default `output room' function. */ +static void +DEFUN(flushbuf, (fp, c), + register FILE *fp AND int c) +{ + int flush_only = c == EOF; + size_t buffer_written; + size_t to_write; + + /* Set if target and get_limit have already been twiddled appropriately. */ + int twiddled = 0; + + if (fp->__put_limit == fp->__buffer) + { + /* The stream needs to be primed for writing. */ + + size_t buffer_offset = 0; + + /* If the user has read some of the buffer, the target position + is incremented for each character he has read. */ + fp->__target += fp->__bufp - fp->__buffer; + + if (fp->__mode.__read && fp->__room_funcs.__input != NULL && + !fp->__mode.__append) + { + int save = errno; + CONST int aligned = (fp->__buffer == NULL || + __stdio_check_offset(fp) == EOF || + fp->__target % fp->__bufsize == 0); + errno = save; + + if (!aligned) + { + /* Move to a block (buffer size) boundary and read in a block. + Then the output will be written as a whole block, too. */ + CONST size_t o = fp->__target % fp->__bufsize; + fp->__target -= o; + if ((*fp->__room_funcs.__input)(fp) == EOF && ferror(fp)) + return; + else + __clearerr(fp); + + if (fp->__get_limit - fp->__buffer < o) + /* Oops. We didn't read enough (probably because we got EOF). + Forget we even mentioned it. */ + fp->__target += o; + else + /* Start bufp as far into the buffer as we were into + this block before we read it. */ + buffer_offset = o; + } + + /* The target position is now set to where the beginning of the + buffer maps to; and the get_limit was set by the input-room + function. */ + twiddled = 1; + } + + if (fp->__buffer != NULL) + { + /* Set up to write output into the buffer. */ + fp->__put_limit = fp->__buffer + fp->__bufsize; + fp->__bufp = fp->__buffer + buffer_offset; + + if (!flush_only) + { + /* Put C in the buffer to be written out. + We only need to actually write it out now if + it is a newline on a line-buffered stream. */ + *fp->__bufp++ = (unsigned char) c; + if (!fp->__linebuf || (unsigned char) c != '\n') + { + /* There is no need to flush C from the buffer right now. + Record that nothing was written from the buffer, + and go do clean-up at end. */ + buffer_written = 0; + goto end; + } + else + /* We put C in the buffer, so don't write it again later. */ + flush_only = 1; + } + } + + if (fp->__bufp - fp->__buffer <= buffer_offset) + { + /* There is nothing new in the buffer, only data that + was read back aligned from the file. */ + buffer_written = 0; + goto end; + } + } + + /* If there is read data in the buffer past what was written, + write all of that as well. Otherwise, just write what has been + written into the buffer. */ + buffer_written = fp->__bufp - fp->__buffer; + to_write = (buffer_written == 0 ? 0 : + fp->__get_limit > fp->__bufp ? + fp->__get_limit - fp->__buffer : + buffer_written); + + if (fp->__io_funcs.__write == NULL || (to_write == 0 && flush_only)) + { + /* There is no writing function or we're coming from an fflush + call with nothing in the buffer, so just say the buffer's + been flushed, increment the file offset, and return. */ + fp->__bufp = fp->__buffer; + fp->__offset += to_write; + goto end; + } + + if (to_write > 0) + { + int wrote; + + /* Go to the target file position. Don't bother if appending; + the write will just ignore the file position anyway. */ + if (!fp->__mode.__append) + seek_to_target (fp); + + if (!ferror(fp)) + { + /* Write out the buffered data. */ + wrote = (*fp->__io_funcs.__write)(fp->__cookie, fp->__buffer, + to_write); + if (wrote > 0) + { + if (fp->__mode.__append) + /* The write has written the data to the end of the file + and updated the file position to after the data. Don't + bother to find the current position; we can get it + later if we need it. */ + fp->__offset = fp->__target = -1; + else + /* Record that we've moved forward in the file. */ + fp->__offset += wrote; + } + if (wrote < (int) to_write) + /* The writing function should always write + the whole buffer unless there is an error. */ + fp->__error = 1; + } + } + + /* Reset the buffer pointer to the beginning of the buffer. */ + fp->__bufp = fp->__buffer; + + /* If we're not just flushing, write the last character, C. */ + if (!flush_only && !ferror(fp)) + { + if (fp->__buffer == NULL || (fp->__linebuf && (unsigned char) c == '\n')) + { + /* Either we're unbuffered, or we're line-buffered and + C is a newline, so really write it out immediately. */ + char cc = (unsigned char) c; + if ((*fp->__io_funcs.__write)(fp->__cookie, &cc, 1) < 1) + fp->__error = 1; + else + { + /* Record that we've moved forward in the file. */ + ++fp->__offset; + ++fp->__target; + } + } + else + /* Just put C in the buffer. */ + *fp->__bufp++ = (unsigned char) c; + } + + end: + + if (!twiddled) + { + /* The new target position moves up as + much as the user wrote into the buffer. */ + fp->__target += buffer_written; + + /* Set the reading limit to the beginning of the buffer, + so the next `getc' will call __fillbf. */ + fp->__get_limit = fp->__buffer; + } + + if (feof(fp) || ferror(fp)) + fp->__bufp = fp->__put_limit; +} + + +/* Fill the buffer for FP and return the first character read (or EOF). + This is the default `input_room' function. */ +static int +DEFUN(fillbuf, (fp), register FILE *fp) +{ + /* How far into the buffer we read we want to start bufp. */ + size_t buffer_offset = 0; + register char *buffer; + register size_t to_read, nread = 0; + /* This must be unsigned to avoid sign extension in return. */ + unsigned char c; + + if (fp->__io_funcs.__read == NULL) + { + /* There is no read function, so always return EOF. */ + fp->__eof = 1; + goto end; + } + + if (fp->__buffer == NULL) + { + /* We're unbuffered, so we want to read only one character. */ + buffer = (char *) &c; + to_read = 1; + } + else + { + /* We're buffered, so try to fill the buffer. */ + buffer = fp->__buffer; + to_read = fp->__bufsize; + } + + /* We're reading, so we're not at the end-of-file. */ + fp->__eof = 0; + + /* Go to the target file position. */ + { + int save = errno; + if (__stdio_check_offset (fp) == 0 && fp->__target != fp->__offset) + { + /* Move to a block (buffer size) boundary. */ + if (fp->__bufsize != 0) + { + buffer_offset = fp->__target % fp->__bufsize; + fp->__target -= buffer_offset; + } + seek_to_target (fp); + } + errno = save; + } + + while (!ferror(fp) && !feof(fp) && nread <= buffer_offset) + { + /* Try to fill the buffer. */ + int count = (*fp->__io_funcs.__read)(fp->__cookie, buffer, to_read); + if (count == 0) + fp->__eof = 1; + else if (count < 0) + fp->__error = 1; + else + { + buffer += count; + nread += count; + to_read -= count; + /* Record that we've moved forward in the file. */ + fp->__offset += count; + } + } + + if (fp->__buffer == NULL) + /* There is no buffer, so return the character we read + without all the buffer pointer diddling. */ + return (feof(fp) || ferror(fp)) ? EOF : c; + + /* Reset the buffer pointer to the beginning of the buffer + (plus whatever offset we may have set above). */ + fp->__bufp = fp->__buffer + buffer_offset; + + end:; + + if (feof(fp) || ferror(fp)) + { + /* Set both end pointers to the beginning of the buffer so + the next i/o call will force a call to __fillbf/__flshfp. */ + fp->__put_limit = fp->__get_limit = fp->__buffer; + return EOF; + } + + /* Set the end pointer to one past the last character we read. */ + fp->__get_limit = fp->__buffer + nread; + + /* Make it so the next `putc' will call __flshfp. */ + fp->__put_limit = fp->__buffer; + + /* Return the first character in the buffer. */ + return *((unsigned char *) (fp->__bufp++)); +} + + +/* Default I/O and room functions. */ + +extern __io_read_fn __stdio_read; +extern __io_write_fn __stdio_write; +extern __io_seek_fn __stdio_seek; +extern __io_close_fn __stdio_close; +extern __io_fileno_fn __stdio_fileno; +CONST __io_functions __default_io_functions = + { + __stdio_read, __stdio_write, __stdio_seek, __stdio_close, __stdio_fileno + }; + +CONST __room_functions __default_room_functions = + { + fillbuf, flushbuf + }; + + +/* Flush the buffer for FP and also write C if FLUSH_ONLY is nonzero. + This is the function used by putc and fflush. */ +int +DEFUN(__flshfp, (fp, c), + register FILE *fp AND int c) +{ + int flush_only = c == EOF; + + if (!__validfp(fp) || !fp->__mode.__write) + { + errno = EINVAL; + return EOF; + } + + if (ferror(fp)) + return EOF; + + if (fp->__pushed_back) + { + /* Discard the char pushed back by ungetc. */ + fp->__bufp = fp->__pushback_bufp; + fp->__pushed_back = 0; + } + + /* Make sure the stream is initialized (has functions and buffering). */ + init_stream(fp); + + /* Do this early, so a `putc' on such a stream will never return success. */ + if (fp->__room_funcs.__output == NULL) + { + /* A NULL `output room' function means + to always return an output error. */ + fp->__error = 1; + return EOF; + } + + if (!flush_only && + /* Will C fit into the buffer? + See below about linebuf_active. */ + fp->__bufp < (fp->__linebuf_active ? fp->__buffer + fp->__bufsize : + fp->__put_limit)) + { + /* The character will fit in the buffer, so put it there. */ + *fp->__bufp++ = (unsigned char) c; + if (fp->__linebuf && (unsigned char) c == '\n') + flush_only = 1; + else + return (unsigned char) c; + } + + if (fp->__linebuf_active) + /* This is an active line-buffered stream, so its put-limit is set + to the beginning of the buffer in order to force a __flshfp call + on each putc (see below). We undo this hack here (by setting + the limit to the end of the buffer) to simplify the interface + with the output-room function. */ + fp->__put_limit = fp->__buffer + fp->__bufsize; + + /* Make room in the buffer. */ + (*fp->__room_funcs.__output) (fp, flush_only ? EOF : (unsigned char) c); + + if (fp->__linebuf) + { + /* This is a line-buffered stream, and it is now ready to do + some output. We call this an "active line-buffered stream". + We set the put_limit to the beginning of the buffer, + so the next `putc' call will force a call to this function. + Setting the linebuf_active flag tells the code above + (on the next call) to undo this hackery. */ + fp->__put_limit = fp->__buffer; + fp->__linebuf_active = 1; + } + + if (ferror (fp)) + return EOF; + if (flush_only) + return 0; + return (unsigned char) c; +} + + +/* Fill the buffer for FP and return the first character read. + This is the function used by getc. */ +int +DEFUN(__fillbf, (fp), register FILE *fp) +{ + register int c; + fpos_t new_target; + + if (!__validfp(fp) || !fp->__mode.__read) + { + errno = EINVAL; + return EOF; + } + + if (fp->__pushed_back) + { + /* Return the char pushed back by ungetc. */ + fp->__bufp = fp->__pushback_bufp; + fp->__pushed_back = 0; + return fp->__pushback; + } + + /* Make sure the stream is initialized (has functions and buffering). */ + init_stream(fp); + + /* If we're trying to read the first character of a new + line of input from an unbuffered or line buffered stream, + we must flush all line-buffered output streams. */ + if (fp->__buffer == NULL || fp->__linebuf) + { + register FILE *f; + for (f = __stdio_head; f != NULL; f = f->__next) + if (__validfp (f) && f->__linebuf && f->__mode.__write) + (void) __flshfp (f, EOF); + } + + /* Note we must do this after flushing all line-buffered + streams, or else __flshfp would undo it! */ + if (fp->__linebuf_active) + { + /* This is an active line-buffered stream, meaning it is in the midst + of writing, but has a bogus put_limit. Restore it to normality. */ + fp->__put_limit = fp->__buffer + fp->__bufsize; + fp->__linebuf_active = 0; + } + + /* We want the beginning of the buffer to now + map to just past the last data we read. */ + new_target = fp->__target + (fp->__get_limit - fp->__buffer); + + if (fp->__put_limit > fp->__buffer) + { + /* There is written data in the buffer. + Flush it out. */ + if (fp->__room_funcs.__output == NULL) + fp->__error = 1; + else + (*fp->__room_funcs.__output) (fp, EOF); + } + + fp->__target = new_target; + + if (ferror(fp)) + c = EOF; + else if (fp->__room_funcs.__input != NULL) + { + c = (*fp->__room_funcs.__input)(fp); + if (fp->__buffer == NULL) + /* This is an unbuffered stream, so the target sync above + won't do anything the next time around. Instead, note that + we have read one character. The (nonexistent) buffer now + maps to the position just past that character. */ + ++fp->__target; + } + else + { + /* A NULL `input_room' function means always return EOF. */ + fp->__eof = 1; + c = EOF; + } + + return c; +} + + +/* Nuke a stream, but don't kill its link in the chain. */ +void +DEFUN(__invalidate, (stream), register FILE *stream) +{ + /* Save its link. */ + register FILE *next = stream->__next; + + /* Pulverize the fucker. */ + memset((PTR) stream, 0, sizeof(FILE)); + + /* Restore the deceased's link. */ + stream->__next = next; +} diff --git a/stdio/longlong.h b/stdio/longlong.h new file mode 100644 index 0000000000..97c469d8c0 --- /dev/null +++ b/stdio/longlong.h @@ -0,0 +1,1295 @@ +/* longlong.h -- definitions for mixed size 32/64 bit arithmetic. + +Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. + +This file is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +This file is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with this file; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* You have to define the following before including this file: + + UWtype -- An unsigned type, default type for operations (typically a "word") + UHWtype -- An unsigned type, at least half the size of UWtype. + UDWtype -- An unsigned type, at least twice as large a UWtype + W_TYPE_SIZE -- size in bits of UWtype + + SItype, USItype -- Signed and unsigned 32 bit types. + DItype, UDItype -- Signed and unsigned 64 bit types. + + On a 32 bit machine UWtype should typically be USItype; + on a 64 bit machine, UWtype should typically be UDItype. +*/ + +#define __BITS4 (W_TYPE_SIZE / 4) +#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1)) +#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2)) + +/* Define auxiliary asm macros. + + 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two + UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype + word product in HIGH_PROD and LOW_PROD. + + 2) __umulsidi3(a,b) multiplies two UWtype integers A and B, and returns a + UDWtype product. This is just a variant of umul_ppmm. + + 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator) divides a UDWtype, composed by the UWtype integers + HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient + in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less + than DENOMINATOR for correct operation. If, in addition, the most + significant bit of DENOMINATOR must be 1, then the pre-processor symbol + UDIV_NEEDS_NORMALIZATION is defined to 1. + + 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator). Like udiv_qrnnd but the numbers are signed. The quotient + is rounded towards 0. + + 5) count_leading_zeros(count, x) counts the number of zero-bits from the + msb to the first non-zero bit in the UWtype X. This is the number of + steps X needs to be shifted left to set the msb. Undefined for X == 0, + unless the symbol COUNT_LEADING_ZEROS_0 is defined to some value. + + 6) count_trailing_zeros(count, x) like count_leading_zeros, but counts + from the least significant end. + + 7) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + high_addend_2, low_addend_2) adds two UWtype integers, composed by + HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2 + respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow + (i.e. carry out) is not stored anywhere, and is lost. + + 8) sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend, + high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers, + composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and + LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE + and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + and is lost. + + If any of these macros are left undefined for a particular CPU, + C macros are used. */ + +/* The CPUs come in alphabetical order below. + + Please add support for more CPUs here, or improve the current support + for the CPUs below! */ + +#if defined (__GNUC__) && !defined (NO_ASM) + +/* We sometimes need to clobber "cc" with gcc2, but that would not be + understood by gcc1. Use cpp to avoid major code duplication. */ +#if __GNUC__ < 2 +#define __CLOBBER_CC +#define __AND_CLOBBER_CC +#else /* __GNUC__ >= 2 */ +#define __CLOBBER_CC : "cc" +#define __AND_CLOBBER_CC , "cc" +#endif /* __GNUC__ < 2 */ + +#if (defined (__a29k__) || defined (___AM29K__)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %1,%4,%5 + addc %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %1,%4,%5 + subc %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("multiplu %0,%1,%2" \ + : "=r" ((USItype)(xl)) \ + : "r" (__m0), \ + "r" (__m1)); \ + __asm__ ("multmu %0,%1,%2" \ + : "=r" ((USItype)(xh)) \ + : "r" (__m0), \ + "r" (__m1)); \ + } while (0) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("dividu %0,%3,%4" \ + : "=r" ((USItype)(q)), \ + "=q" ((USItype)(r)) \ + : "1" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "r" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x))) +#endif /* __a29k__ */ + +#if defined (__alpha__) && W_TYPE_SIZE == 64 +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + UDItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("umulh %r1,%2,%0" \ + : "=r" ((UDItype) ph) \ + : "%rJ" (__m0), \ + "rI" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 46 +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { UDItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern UDItype __udiv_qrnnd (); +#define UDIV_TIME 220 +#endif + +#if defined (__arm__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("adds %1,%4,%5 + adc %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1,%4,%5 + sbc %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "r" ((USItype)(al)), \ + "rI" ((USItype)(bl))) +#define umul_ppmm(xh, xl, a, b) \ + __asm__ ("; Inlined umul_ppmm + mov r0,%2 lsr 16 + mov r2,%3 lsr 16 + bic r1,%2,r0 lsl 16 + bic r2,%3,r2 lsl 16 + mul %1,r1,r2 + mul r2,r0,r2 + mul r1,%0,r1 + mul %0,r0,%0 + adds r1,r2,r1 + addcs %0,%0,0x10000 + adds %1,%1,r1 lsl 16 + adc %0,%0,r1 lsr 16" \ + : "=&r" ((USItype)(xh)), \ + "=r" ((USItype)(xl)) \ + : "r" ((USItype)(a)), \ + "r" ((USItype)(b)) \ + : "r0", "r1", "r2") +#define UMUL_TIME 20 +#define UDIV_TIME 100 +#endif /* __arm__ */ + +#if defined (__clipper__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("mulwux %2,%0" \ + : "=r" (__xx.__ll) \ + : "%0" ((USItype)(u)), \ + "r" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define smul_ppmm(w1, w0, u, v) \ + ({union {DItype __ll; \ + struct {SItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("mulwx %2,%0" \ + : "=r" (__xx.__ll) \ + : "%0" ((SItype)(u)), \ + "r" ((SItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("mulwux %2,%0" \ + : "=r" (__w) \ + : "%0" ((USItype)(u)), \ + "r" ((USItype)(v))); \ + __w; }) +#endif /* __clipper__ */ + +#if defined (__gmicro__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add.w %5,%1 + addx %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub.w %5,%1 + subx %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define umul_ppmm(ph, pl, m0, m1) \ + __asm__ ("mulx %3,%0,%1" \ + : "=g" ((USItype)(ph)), \ + "=r" ((USItype)(pl)) \ + : "%0" ((USItype)(m0)), \ + "g" ((USItype)(m1))) +#define udiv_qrnnd(q, r, nh, nl, d) \ + __asm__ ("divx %4,%0,%1" \ + : "=g" ((USItype)(q)), \ + "=r" ((USItype)(r)) \ + : "1" ((USItype)(nh)), \ + "0" ((USItype)(nl)), \ + "g" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + __asm__ ("bsch/1 %1,%0" \ + : "=g" (count) \ + : "g" ((USItype)(x)), \ + "0" ((USItype)0)) +#endif + +#if defined (__hppa) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %4,%5,%1 + addc %2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%rM" ((USItype)(ah)), \ + "rM" ((USItype)(bh)), \ + "%rM" ((USItype)(al)), \ + "rM" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %4,%5,%1 + subb %2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "rM" ((USItype)(ah)), \ + "rM" ((USItype)(bh)), \ + "rM" ((USItype)(al)), \ + "rM" ((USItype)(bl))) +#if defined (_PA_RISC1_1) +#define umul_ppmm(wh, wl, u, v) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("xmpyu %1,%2,%0" \ + : "=x" (__xx.__ll) \ + : "x" ((USItype)(u)), \ + "x" ((USItype)(v))); \ + (wh) = __xx.__i.__h; \ + (wl) = __xx.__i.__l; \ + } while (0) +#define UMUL_TIME 8 +#define UDIV_TIME 60 +#else +#define UMUL_TIME 40 +#define UDIV_TIME 80 +#endif +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { USItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern USItype __udiv_qrnnd (); +#define count_leading_zeros(count, x) \ + do { \ + USItype __tmp; \ + __asm__ ( \ + "ldi 1,%0 + extru,= %1,15,16,%%r0 ; Bits 31..16 zero? + extru,tr %1,15,16,%1 ; No. Shift down, skip add. + ldo 16(%0),%0 ; Yes. Perform add. + extru,= %1,23,8,%%r0 ; Bits 15..8 zero? + extru,tr %1,23,8,%1 ; No. Shift down, skip add. + ldo 8(%0),%0 ; Yes. Perform add. + extru,= %1,27,4,%%r0 ; Bits 7..4 zero? + extru,tr %1,27,4,%1 ; No. Shift down, skip add. + ldo 4(%0),%0 ; Yes. Perform add. + extru,= %1,29,2,%%r0 ; Bits 3..2 zero? + extru,tr %1,29,2,%1 ; No. Shift down, skip add. + ldo 2(%0),%0 ; Yes. Perform add. + extru %1,30,1,%1 ; Extract bit 1. + sub %0,%1,%0 ; Subtract it. + " : "=r" (count), "=r" (__tmp) : "1" (x)); \ + } while (0) +#endif + +#if (defined (__i370__) || defined (__mvs__)) && W_TYPE_SIZE == 32 +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mr %0,%3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "r" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define smul_ppmm(xh, xl, m0, m1) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("mr %0,%3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (m0), \ + "r" (m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("dr %0,%2" \ + : "=r" (__xx.__ll) \ + : "0" (__xx.__ll), "r" (d)); \ + (q) = __xx.__i.__l; (r) = __xx.__i.__h; \ + } while (0) +#endif + +#if (defined (__i386__) || defined (__i486__)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl %5,%1 + adcl %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl %5,%1 + sbbl %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mull %3" \ + : "=a" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "%0" ((USItype)(u)), \ + "rm" ((USItype)(v))) +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divl %4" \ + : "=a" ((USItype)(q)), \ + "=d" ((USItype)(r)) \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "rm" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("bsrl %1,%0" \ + : "=r" (__cbtmp) : "rm" ((USItype)(x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#define count_trailing_zeros(count, x) \ + __asm__ ("bsfl %1,%0" : "=r" (count) : "rm" ((USItype)(x))) +#define UMUL_TIME 40 +#define UDIV_TIME 40 +#endif /* 80x86 */ + +#if defined (__i960__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__xx.__ll) \ + : "%dI" ((USItype)(u)), \ + "dI" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("emul %2,%1,%0" \ + : "=d" (__w) \ + : "%dI" ((USItype)(u)), \ + "dI" ((USItype)(v))); \ + __w; }) +#endif /* __i960__ */ + +#if defined (__mc68000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add%.l %5,%1 + addx%.l %3,%0" \ + : "=d" ((USItype)(sh)), \ + "=&d" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "d" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub%.l %5,%1 + subx%.l %3,%0" \ + : "=d" ((USItype)(sh)), \ + "=&d" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "d" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#if (defined (__mc68020__) || defined (__NeXT__) || defined(mc68020)) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("mulu%.l %3,%1:%0" \ + : "=d" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "%0" ((USItype)(u)), \ + "dmi" ((USItype)(v))) +#define UMUL_TIME 45 +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divu%.l %4,%1:%0" \ + : "=d" ((USItype)(q)), \ + "=d" ((USItype)(r)) \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "dmi" ((USItype)(d))) +#define UDIV_TIME 90 +#define sdiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("divs%.l %4,%1:%0" \ + : "=d" ((USItype)(q)), \ + "=d" ((USItype)(r)) \ + : "0" ((USItype)(n0)), \ + "1" ((USItype)(n1)), \ + "dmi" ((USItype)(d))) +#define count_leading_zeros(count, x) \ + __asm__ ("bfffo %1{%b2:%b2},%0" \ + : "=d" ((USItype)(count)) \ + : "od" ((USItype)(x)), "n" (0)) +#else /* not mc68020 */ +#define umul_ppmm(xh, xl, a, b) \ + __asm__ ("| Inlined umul_ppmm + move%.l %2,%/d0 + move%.l %3,%/d1 + move%.l %/d0,%/d2 + swap %/d0 + move%.l %/d1,%/d3 + swap %/d1 + move%.w %/d2,%/d4 + mulu %/d3,%/d4 + mulu %/d1,%/d2 + mulu %/d0,%/d3 + mulu %/d0,%/d1 + move%.l %/d4,%/d0 + eor%.w %/d0,%/d0 + swap %/d0 + add%.l %/d0,%/d2 + add%.l %/d3,%/d2 + jcc 1f + add%.l #65536,%/d1 +1: swap %/d2 + moveq #0,%/d0 + move%.w %/d2,%/d0 + move%.w %/d4,%/d2 + move%.l %/d2,%1 + add%.l %/d1,%/d0 + move%.l %/d0,%0" \ + : "=g" ((USItype)(xh)), \ + "=g" ((USItype)(xl)) \ + : "g" ((USItype)(a)), \ + "g" ((USItype)(b)) \ + : "d0", "d1", "d2", "d3", "d4") +#define UMUL_TIME 100 +#define UDIV_TIME 400 +#endif /* not mc68020 */ +#endif /* mc68000 */ + +#if defined (__m88000__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addu.co %1,%r4,%r5 + addu.ci %0,%r2,%r3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%rJ" ((USItype)(ah)), \ + "rJ" ((USItype)(bh)), \ + "%rJ" ((USItype)(al)), \ + "rJ" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subu.co %1,%r4,%r5 + subu.ci %0,%r2,%r3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "rJ" ((USItype)(ah)), \ + "rJ" ((USItype)(bh)), \ + "rJ" ((USItype)(al)), \ + "rJ" ((USItype)(bl))) +#define count_leading_zeros(count, x) \ + do { \ + USItype __cbtmp; \ + __asm__ ("ff1 %0,%1" \ + : "=r" (__cbtmp) \ + : "r" ((USItype)(x))); \ + (count) = __cbtmp ^ 31; \ + } while (0) +#if defined (__mc88110__) +#define umul_ppmm(wh, wl, u, v) \ + do { \ + union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __asm__ ("mulu.d %0,%1,%2" \ + : "=r" (__xx.__ll) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v))); \ + (wh) = __xx.__i.__h; \ + (wl) = __xx.__i.__l; \ + } while (0) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + USItype __q; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("divu.d %0,%1,%2" \ + : "=r" (__q) \ + : "r" (__xx.__ll), \ + "r" ((USItype)(d))); \ + (r) = (n0) - __q * (d); (q) = __q; }) +#define UMUL_TIME 5 +#define UDIV_TIME 25 +#else +#define UMUL_TIME 17 +#define UDIV_TIME 150 +#endif /* __mc88110__ */ +#endif /* __m88000__ */ + +#if defined (__mips__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("multu %2,%3 + mflo %0 + mfhi %1" \ + : "=d" ((USItype)(w0)), \ + "=d" ((USItype)(w1)) \ + : "d" ((USItype)(u)), \ + "d" ((USItype)(v))) +#define UMUL_TIME 10 +#define UDIV_TIME 100 +#endif /* __mips__ */ + +#if (defined (__mips) && __mips >= 3) && W_TYPE_SIZE == 64 +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("dmultu %2,%3 + mflo %0 + mfhi %1" \ + : "=d" ((UDItype)(w0)), \ + "=d" ((UDItype)(w1)) \ + : "d" ((UDItype)(u)), \ + "d" ((UDItype)(v))) +#define UMUL_TIME 10 +#define UDIV_TIME 100 +#endif /* __mips__ */ + +#if defined (__ns32000__) && W_TYPE_SIZE == 32 +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __asm__ ("meid %2,%0" \ + : "=g" (__xx.__ll) \ + : "%0" ((USItype)(u)), \ + "g" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#define __umulsidi3(u, v) \ + ({UDItype __w; \ + __asm__ ("meid %2,%0" \ + : "=g" (__w) \ + : "%0" ((USItype)(u)), \ + "g" ((USItype)(v))); \ + __w; }) +#define udiv_qrnnd(q, r, n1, n0, d) \ + ({union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = (n1); __xx.__i.__l = (n0); \ + __asm__ ("deid %2,%0" \ + : "=g" (__xx.__ll) \ + : "0" (__xx.__ll), \ + "g" ((USItype)(d))); \ + (r) = __xx.__i.__l; (q) = __xx.__i.__h; }) +#define count_trailing_zeros(count,x) \ + do { + __asm__ ("ffsd %2,%0" \ + : "=r" ((USItype) (count)) \ + : "0" ((USItype) 0), \ + "r" ((USItype) (x))); \ + } while (0) +#endif /* __ns32000__ */ + +#if (defined (__powerpc__) || defined (___IBMR2__)) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + else \ + __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "%r" ((USItype)(al)), \ + "rI" ((USItype)(bl))); \ + } while (0) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + if (__builtin_constant_p (ah) && (ah) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) == 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \ + __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + else \ + __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "r" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "rI" ((USItype)(al)), \ + "r" ((USItype)(bl))); \ + } while (0) +#define count_leading_zeros(count, x) \ + __asm__ ("{cntlz|cntlzw} %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x))) +#if defined (__powerpc__) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhwu %0,%1,%2" \ + : "=r" ((USItype) ph) \ + : "%r" (__m0), \ + "r" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define UMUL_TIME 15 +#define smul_ppmm(ph, pl, m0, m1) \ + do { \ + SItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mulhw %0,%1,%2" \ + : "=r" ((SItype) ph) \ + : "%r" (__m0), \ + "r" (__m1)); \ + (pl) = __m0 * __m1; \ + } while (0) +#define SMUL_TIME 14 +#define UDIV_TIME 120 +#else +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("mul %0,%2,%3" \ + : "=r" ((USItype)(xh)), \ + "=q" ((USItype)(xl)) \ + : "r" (__m0), \ + "r" (__m1)); \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define UMUL_TIME 8 +#define smul_ppmm(xh, xl, m0, m1) \ + __asm__ ("mul %0,%2,%3" \ + : "=r" ((SItype)(xh)), \ + "=q" ((SItype)(xl)) \ + : "r" (m0), \ + "r" (m1)) +#define SMUL_TIME 4 +#define sdiv_qrnnd(q, r, nh, nl, d) \ + __asm__ ("div %0,%2,%4" \ + : "=r" ((SItype)(q)), "=q" ((SItype)(r)) \ + : "r" ((SItype)(nh)), "1" ((SItype)(nl)), "r" ((SItype)(d))) +#define UDIV_TIME 100 +#endif +#endif /* Power architecture variants. */ + +#if defined (__pyr__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addw %5,%1 + addwc %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subw %5,%1 + subwb %3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +/* This insn doesn't work on ancient pyramids. */ +#define umul_ppmm(w1, w0, u, v) \ + ({union {UDItype __ll; \ + struct {USItype __h, __l;} __i; \ + } __xx; \ + __xx.__i.__l = u; \ + __asm__ ("uemul %3,%0" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "1" (__xx.__i.__l), \ + "g" ((USItype)(v))); \ + (w1) = __xx.__i.__h; (w0) = __xx.__i.__l;}) +#endif /* __pyr__ */ + +#if defined (__ibm032__) /* RT/ROMP */ && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("a %1,%5 + ae %0,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "r" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("s %1,%5 + se %0,%3" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "r" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "r" ((USItype)(bl))) +#define umul_ppmm(ph, pl, m0, m1) \ + do { \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ( \ + "s r2,r2 + mts r10,%2 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + m r2,%3 + cas %0,r2,r0 + mfs r10,%1" \ + : "=r" ((USItype)(ph)), \ + "=r" ((USItype)(pl)) \ + : "%r" (__m0), \ + "r" (__m1) \ + : "r2"); \ + (ph) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define UMUL_TIME 20 +#define UDIV_TIME 200 +#define count_leading_zeros(count, x) \ + do { \ + if ((x) >= 0x10000) \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x) >> 16)); \ + else \ + { \ + __asm__ ("clz %0,%1" \ + : "=r" ((USItype)(count)) \ + : "r" ((USItype)(x))); \ + (count) += 16; \ + } \ + } while (0) +#endif + +#if defined (__sparc__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addcc %r4,%5,%1 + addx %r2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "%rJ" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "%rJ" ((USItype)(al)), \ + "rI" ((USItype)(bl)) \ + __CLOBBER_CC) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subcc %r4,%5,%1 + subx %r2,%3,%0" \ + : "=r" ((USItype)(sh)), \ + "=&r" ((USItype)(sl)) \ + : "rJ" ((USItype)(ah)), \ + "rI" ((USItype)(bh)), \ + "rJ" ((USItype)(al)), \ + "rI" ((USItype)(bl)) \ + __CLOBBER_CC) +#if defined (__sparc_v8__) +/* Don't match immediate range because, 1) it is not often useful, + 2) the 'I' flag thinks of the range as a 13 bit signed interval, + while we want to match a 13 bit interval, sign extended to 32 bits, + but INTERPRETED AS UNSIGNED. */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v))) +#define UMUL_TIME 5 +/* We might want to leave this undefined for `SuperSPARC (tm)' since + its implementation is crippled and often traps. */ +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("mov %2,%%y;nop;nop;nop;udiv %3,%4,%0;umul %0,%4,%1;sub %3,%1,%1"\ + : "=&r" ((USItype)(q)), \ + "=&r" ((USItype)(r)) \ + : "r" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "r" ((USItype)(d))) +#define UDIV_TIME 25 +#else +#if defined (__sparclite__) +/* This has hardware multiply but not divide. It also has two additional + instructions scan (ffs from high bit) and divscc. */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("umul %2,%3,%1;rd %%y,%0" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "r" ((USItype)(u)), \ + "r" ((USItype)(v))) +#define UMUL_TIME 5 +#define udiv_qrnnd(q, r, n1, n0, d) \ + __asm__ ("! Inlined udiv_qrnnd + wr %%g0,%2,%%y ! Not a delayed write for sparclite + tst %%g0 + divscc %3,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%%g1 + divscc %%g1,%4,%0 + rd %%y,%1 + bl,a 1f + add %1,%4,%1 +1: ! End of inline udiv_qrnnd" \ + : "=r" ((USItype)(q)), \ + "=r" ((USItype)(r)) \ + : "r" ((USItype)(n1)), \ + "r" ((USItype)(n0)), \ + "rI" ((USItype)(d)) \ + : "%g1" __AND_CLOBBER_CC) +#define UDIV_TIME 37 +#define count_leading_zeros(count, x) \ + __asm__ ("scan %1,0,%0" \ + : "=r" ((USItype)(x)) \ + : "r" ((USItype)(count))) +#else +/* SPARC without integer multiplication and divide instructions. + (i.e. at least Sun4/20,40,60,65,75,110,260,280,330,360,380,470,490) */ +#define umul_ppmm(w1, w0, u, v) \ + __asm__ ("! Inlined umul_ppmm + wr %%g0,%2,%%y ! SPARC has 0-3 delay insn after a wr + sra %3,31,%%g2 ! Don't move this insn + and %2,%%g2,%%g2 ! Don't move this insn + andcc %%g0,0,%%g1 ! Don't move this insn + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,%3,%%g1 + mulscc %%g1,0,%%g1 + add %%g1,%%g2,%0 + rd %%y,%1" \ + : "=r" ((USItype)(w1)), \ + "=r" ((USItype)(w0)) \ + : "%rI" ((USItype)(u)), \ + "r" ((USItype)(v)) \ + : "%g1", "%g2" __AND_CLOBBER_CC) +#define UMUL_TIME 39 /* 39 instructions */ +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { USItype __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern USItype __udiv_qrnnd (); +#define UDIV_TIME 140 +#endif /* __sparclite__ */ +#endif /* __sparc_v8__ */ +#endif /* __sparc__ */ + +#if defined (__vax__) && W_TYPE_SIZE == 32 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("addl2 %5,%1 + adwc %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "%0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "%1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subl2 %5,%1 + sbwc %3,%0" \ + : "=g" ((USItype)(sh)), \ + "=&g" ((USItype)(sl)) \ + : "0" ((USItype)(ah)), \ + "g" ((USItype)(bh)), \ + "1" ((USItype)(al)), \ + "g" ((USItype)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {UDItype __ll; \ + struct {USItype __l, __h;} __i; \ + } __xx; \ + USItype __m0 = (m0), __m1 = (m1); \ + __asm__ ("emul %1,%2,$0,%0" \ + : "=g" (__xx.__ll) \ + : "g" (__m0), \ + "g" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((SItype) __m0 >> 31) & __m1) \ + + (((SItype) __m1 >> 31) & __m0)); \ + } while (0) +#define sdiv_qrnnd(q, r, n1, n0, d) \ + do { \ + union {DItype __ll; \ + struct {SItype __l, __h;} __i; \ + } __xx; \ + __xx.__i.__h = n1; __xx.__i.__l = n0; \ + __asm__ ("ediv %3,%2,%0,%1" \ + : "=g" (q), "=g" (r) \ + : "g" (__n1n0.ll), "g" (d)); \ + } while (0) +#endif /* __vax__ */ + +#if defined (__z8000__) && W_TYPE_SIZE == 16 +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("add %H1,%H5\n\tadc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "%0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "%1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("sub %H1,%H5\n\tsbc %H0,%H3" \ + : "=r" ((unsigned int)(sh)), \ + "=&r" ((unsigned int)(sl)) \ + : "0" ((unsigned int)(ah)), \ + "r" ((unsigned int)(bh)), \ + "1" ((unsigned int)(al)), \ + "rQR" ((unsigned int)(bl))) +#define umul_ppmm(xh, xl, m0, m1) \ + do { \ + union {long int __ll; \ + struct {unsigned int __h, __l;} __i; \ + } __xx; \ + unsigned int __m0 = (m0), __m1 = (m1); \ + __asm__ ("mult %S0,%H3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (__m0), \ + "rQR" (__m1)); \ + (xh) = __xx.__i.__h; (xl) = __xx.__i.__l; \ + (xh) += ((((signed int) __m0 >> 15) & __m1) \ + + (((signed int) __m1 >> 15) & __m0)); \ + } while (0) +#define umul_ppmm_off(xh, xl, m0, m1) \ + do { \ + union {long int __ll; \ + struct {unsigned int __h, __l;} __i; \ + } __xx; \ + __asm__ ("mult %S0,%H3" \ + : "=r" (__xx.__i.__h), \ + "=r" (__xx.__i.__l) \ + : "%1" (m0), \ + "rQR" (m1)); \ + (xh) = __xx.__i.__h + ((((signed int) m0 >> 15) & m1) \ + + (((signed int) m1 >> 15) & m0)); \ + (xl) = __xx.__i.__l; \ + } while (0) +#endif /* __z8000__ */ + +#endif /* __GNUC__ */ + + +#if !defined (umul_ppmm) && defined (__umulsidi3) +#define umul_ppmm(ph, pl, m0, m1) \ + { \ + UDWtype __ll = __umulsidi3 (m0, m1); \ + ph = (UWtype) (__ll >> W_TYPE_SIZE); \ + pl = (UWtype) __ll; \ + } +#endif + +#if !defined (__umulsidi3) +#define __umulsidi3(u, v) \ + ({UWtype __hi, __lo; \ + umul_ppmm (__hi, __lo, u, v); \ + ((UDWtype) __hi << W_TYPE_SIZE) | __lo; }) +#endif + +/* If this machine has no inline assembler, use C macros. */ + +#if !defined (add_ssaaaa) +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) + (bl); \ + (sh) = (ah) + (bh) + (__x < (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (sub_ddmmss) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + do { \ + UWtype __x; \ + __x = (al) - (bl); \ + (sh) = (ah) - (bh) - (__x > (al)); \ + (sl) = __x; \ + } while (0) +#endif + +#if !defined (umul_ppmm) +#define umul_ppmm(w1, w0, u, v) \ + do { \ + UWtype __x0, __x1, __x2, __x3; \ + UHWtype __ul, __vl, __uh, __vh; \ + \ + __ul = __ll_lowpart (u); \ + __uh = __ll_highpart (u); \ + __vl = __ll_lowpart (v); \ + __vh = __ll_highpart (v); \ + \ + __x0 = (UWtype) __ul * __vl; \ + __x1 = (UWtype) __ul * __vh; \ + __x2 = (UWtype) __uh * __vl; \ + __x3 = (UWtype) __uh * __vh; \ + \ + __x1 += __ll_highpart (__x0);/* this can't give carry */ \ + __x1 += __x2; /* but this indeed can */ \ + if (__x1 < __x2) /* did we get it? */ \ + __x3 += __ll_B; /* yes, add it in the proper pos. */ \ + \ + (w1) = __x3 + __ll_highpart (__x1); \ + (w0) = (__ll_lowpart (__x1) << W_TYPE_SIZE/2) + __ll_lowpart (__x0);\ + } while (0) +#endif + +/* Define this unconditionally, so it can be used for debugging. */ +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (UWtype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (UWtype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (UWtype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +/* If the processor has no udiv_qrnnd but sdiv_qrnnd, go through + __udiv_w_sdiv (defined in libgcc or elsewhere). */ +#if !defined (udiv_qrnnd) && defined (sdiv_qrnnd) +#define udiv_qrnnd(q, r, nh, nl, d) \ + do { \ + UWtype __r; \ + (q) = __udiv_w_sdiv (&__r, nh, nl, d); \ + (r) = __r; \ + } while (0) +#endif + +/* If udiv_qrnnd was not defined for this processor, use __udiv_qrnnd_c. */ +#if !defined (udiv_qrnnd) +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c +#endif + +#if !defined (count_leading_zeros) +extern +#ifdef __STDC__ +const +#endif +unsigned char __clz_tab[]; +#define count_leading_zeros(count, x) \ + do { \ + UWtype __xr = (x); \ + UWtype __a; \ + \ + if (W_TYPE_SIZE <= 32) \ + { \ + __a = __xr < ((UWtype) 1 << 2*__BITS4) \ + ? (__xr < ((UWtype) 1 << __BITS4) ? 0 : __BITS4) \ + : (__xr < ((UWtype) 1 << 3*__BITS4) ? 2*__BITS4 : 3*__BITS4);\ + } \ + else \ + { \ + for (__a = W_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + \ + (count) = W_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ + } while (0) +/* This version gives a well-defined value for zero. */ +#define COUNT_LEADING_ZEROS_0 W_TYPE_SIZE +#endif + +#if !defined (count_trailing_zeros) +/* Define count_trailing_zeros using count_leading_zeros. The latter might be + defined in asm, but if it is not, the C version above is good enough. */ +#define count_trailing_zeros(count, x) \ + do { \ + UWtype __ctz_x = (x); \ + UWtype __ctz_c; \ + count_leading_zeros (__ctz_c, __ctz_x & -__ctz_x); \ + (count) = W_TYPE_SIZE - 1 - __ctz_c; \ + } while (0) +#endif + +#ifndef UDIV_NEEDS_NORMALIZATION +#define UDIV_NEEDS_NORMALIZATION 0 +#endif diff --git a/stdio/memstream.c b/stdio/memstream.c new file mode 100644 index 0000000000..704eca53b3 --- /dev/null +++ b/stdio/memstream.c @@ -0,0 +1,177 @@ +/* Copyright (C) 1991, 1992, 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct memstream_info + { + char **buffer; + size_t *bufsize; + }; + +/* Enlarge STREAM's buffer. */ +static void +DEFUN(enlarge_buffer, (stream, c), + register FILE *stream AND int c) +{ + struct memstream_info *info = (struct memstream_info *) stream->__cookie; + size_t need; + + if (stream->__put_limit != stream->__buffer) + /* Record how much has actually been written into the buffer. */ + *info->bufsize = stream->__bufp - stream->__buffer; + + if (stream->__target != -1 + && stream->__target > *info->bufsize) + /* Our target (where the buffer maps to) is always zero except when + the user just did a SEEK_END fseek. If he sought within the + buffer, we need do nothing and will zero the target below. If he + sought past the end of the object, grow and zero-fill the buffer + up to the target address. */ + need = stream->__target; + else + need = *info->bufsize; + + /* We always need an extra character in the buffer. Either we are + writing C, or we are flushing and need to write a NUL terminator. */ + ++need; + + if (stream->__bufsize < need) + { + /* Enlarge the buffer. */ + char *newbuf; + size_t newsize; + if (stream->__bufsize * 2 < need) + newsize = need; + else + newsize = stream->__bufsize * 2; + newbuf = (char *) realloc ((PTR) stream->__buffer, newsize); + if (newbuf == NULL) + { + stream->__error = 1; + return; + } + *info->buffer = stream->__buffer = newbuf; + stream->__bufsize = newsize; + } + + stream->__target = stream->__offset = 0; + stream->__get_limit = stream->__bufp = stream->__buffer + *info->bufsize; + stream->__put_limit = stream->__buffer + stream->__bufsize; + + need -= stream->__bufp - stream->__buffer + 1; + if (need > 0) + { + /* We are extending the buffer after an fseek; zero-fill new space. */ + bzero (stream->__bufp, need); + stream->__bufp += need; + } + + if (c != EOF) + *stream->__bufp++ = (unsigned char) c; + else + *stream->__bufp = '\0'; +} + +/* Seek function for memstreams. + There is no external state to munge. */ + +static int +DEFUN(seek, (cookie, pos, whence), + PTR cookie AND fpos_t *pos AND int whence) +{ + switch (whence) + { + case SEEK_SET: + case SEEK_CUR: + return 0; + + case SEEK_END: + /* Return the position relative to the end of the object. + fseek has just flushed us, so the info is consistent. */ + *pos += *((struct memstream_info *) cookie)->bufsize; + return 0; + + default: + __libc_fatal ("memstream::seek called with bogus WHENCE\n"); + return -1; + } +} + +static int +DEFUN(free_info, (cookie), PTR cookie) +{ +#if 0 + struct memstream_info *info = (struct memstream_info *) cookie; + char *buf; + + buf = (char *) realloc ((PTR) *info->buffer, *info->bufsize); + if (buf != NULL) + *info->buffer = buf; +#endif + + free (cookie); + + return 0; +} + +/* Open a stream that writes into a malloc'd buffer that is expanded as + necessary. *BUFLOC and *SIZELOC are updated with the buffer's location + and the number of characters written on fflush or fclose. */ +FILE * +DEFUN(open_memstream, (bufloc, sizeloc), + char **bufloc AND size_t *sizeloc) +{ + FILE *stream; + struct memstream_info *info; + + if (bufloc == NULL || sizeloc == NULL) + { + errno = EINVAL; + return NULL; + } + + stream = fmemopen ((char *) NULL, BUFSIZ, "w+"); + if (stream == NULL) + return NULL; + + info = (struct memstream_info *) malloc (sizeof (struct memstream_info)); + if (info == NULL) + { + int save = errno; + (void) fclose (stream); + errno = save; + return NULL; + } + + stream->__room_funcs.__output = enlarge_buffer; + stream->__io_funcs.__seek = seek; + stream->__io_funcs.__close = free_info; + stream->__cookie = (PTR) info; + stream->__userbuf = 1; + + info->buffer = bufloc; + info->bufsize = sizeloc; + + *bufloc = stream->__buffer; + + return stream; +} diff --git a/stdio/mp_clz_tab.c b/stdio/mp_clz_tab.c new file mode 100644 index 0000000000..ed1b7eebe8 --- /dev/null +++ b/stdio/mp_clz_tab.c @@ -0,0 +1,39 @@ +/* __clz_tab -- support for longlong.h + +Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. + +This file is part of the GNU MP Library. + +The GNU MP Library is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at your +option) any later version. + +The GNU MP Library is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public +License for more details. + +You should have received a copy of the GNU Library General Public License +along with the GNU MP Library; see the file COPYING.LIB. If not, write to +the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#if 0 +#include "gmp.h" +#include "gmp-impl.h" +#endif + +#if 0 +const +#endif + unsigned char __clz_tab[] = +{ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +}; diff --git a/stdio/newstream.c b/stdio/newstream.c new file mode 100644 index 0000000000..08feb8da6e --- /dev/null +++ b/stdio/newstream.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + + +/* Return a new, zeroed, stream. + You must set its cookie and io_mode. + The first operation will give it a buffer unless you do. + It will also give it the default functions unless you set the `seen' flag. + Returns NULL if a stream can't be created. */ +FILE * +DEFUN_VOID(__newstream) +{ + register FILE *stream; + + stream = __stdio_head; + while (__validfp (stream)) + stream = stream->__next; + if (stream == NULL) + { + /* None to reuse. */ + stream = (FILE *) malloc (sizeof (FILE)); + if (stream == NULL) + return NULL; + stream->__next = __stdio_head; + __stdio_head = stream; + } + + __invalidate (stream); + stream->__magic = _IOMAGIC; + stream->__offset = (fpos_t) -1; + stream->__target = (fpos_t) -1; + + return stream; +} diff --git a/stdio/obstream.c b/stdio/obstream.c new file mode 100644 index 0000000000..32f7220b59 --- /dev/null +++ b/stdio/obstream.c @@ -0,0 +1,187 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <obstack.h> +#include <stdarg.h> +#include <string.h> + +/* Output-room function for obstack streams. */ + +static void +DEFUN(grow, (stream, c), FILE *stream AND int c) +{ + struct obstack *const obstack = (struct obstack *) stream->__cookie; + + /* Move the end of the object back to include only the portion + of the buffer which the user has already written into. */ + obstack_blank_fast (obstack, - (stream->__put_limit - stream->__bufp)); + + if (stream->__target > obstack_object_size (obstack)) + { + /* Our target (where the buffer maps to) is always zero except when + the user just did a SEEK_END fseek. If he sought within the + buffer, we need do nothing and will zero the target below. If he + sought past the end of the object, grow and zero-fill the object + up to the target address. */ + + obstack_blank (obstack, + stream->__target - obstack_object_size (obstack)); + /* fseek has just flushed us, so the put limit points + to the end of the written data. */ + bzero (stream->__put_limit, + stream->__target - stream->__bufsize); + } + + if (c != EOF) + obstack_1grow (obstack, (unsigned char) c); + + /* The stream buffer always maps exactly to the object on the top + of the obstack. The start of the buffer is the start of the object. + The put limit points just past the end of the object. On fflush, the + obstack is sync'd so the end of the object points just past the last + character written to the stream. */ + + stream->__target = stream->__offset = 0; + stream->__buffer = obstack_base (obstack); + stream->__bufsize = obstack_room (obstack); + stream->__bufp = obstack_next_free (obstack); + stream->__get_limit = stream->__bufp; + + if (c == EOF) + /* This is fflush. Make the stream buffer, the object, + and the characters actually written all match. */ + stream->__put_limit = stream->__get_limit; + else + { + /* Extend the buffer (and the object) to include + the rest of the obstack chunk (which is unitialized). + Data past bufp is undefined. */ + stream->__put_limit = stream->__buffer + stream->__bufsize; + obstack_blank_fast (obstack, stream->__put_limit - stream->__bufp); + } +} + +/* Seek function for obstack streams. + There is no external state to munge. */ + +static int +DEFUN(seek, (cookie, pos, whence), + PTR cookie AND fpos_t *pos AND int whence) +{ + switch (whence) + { + case SEEK_SET: + case SEEK_CUR: + return 0; + + case SEEK_END: + /* Return the position relative to the end of the object. + fseek has just flushed us, so the obstack is consistent. */ + *pos += obstack_object_size ((struct obstack *) cookie); + return 0; + + default: + __libc_fatal ("obstream::seek called with bogus WHENCE\n"); + return -1; + } +} + +/* Input room function for obstack streams. + Only what has been written to the stream can be read back. */ + +static int +DEFUN(input, (stream), FILE *stream) +{ + /* Re-sync with the obstack, growing the object if necessary. */ + grow (stream, EOF); + + if (stream->__bufp < stream->__get_limit) + return (unsigned char) *stream->__bufp++; + + stream->__eof = 1; + return EOF; +} + +/* Initialize STREAM to talk to OBSTACK. */ + +static void +DEFUN(init_obstream, (stream, obstack), + FILE *stream AND struct obstack *obstack) +{ + stream->__mode.__write = 1; + stream->__mode.__read = 1; + + /* Input can read only what has been written. */ + stream->__room_funcs.__input = input; + + /* Do nothing for close. */ + stream->__io_funcs.__close = NULL; + + /* When the buffer is full, grow the obstack. */ + stream->__room_funcs.__output = grow; + + /* Seek within the object, and extend it. */ + stream->__io_funcs.__seek = seek; + stream->__target = stream->__offset = 0; + + stream->__seen = 1; + + /* Don't deallocate that buffer! */ + stream->__userbuf = 1; + + /* We don't have to initialize the buffer. + The first read attempt will call grow, which will do all the work. */ +} + +FILE * +open_obstack_stream (obstack) + struct obstack *obstack; +{ + register FILE *stream; + + stream = __newstream (); + if (stream == NULL) + return NULL; + + init_obstream (stream, obstack); + return stream; +} + +int +DEFUN(obstack_vprintf, (obstack, format, args), + struct obstack *obstack AND const char *format AND va_list args) +{ + FILE f; + bzero (&f, sizeof (f)); + init_obstream (&f, obstack); + return vfprintf (&f, format, args); +} + +int +DEFUN(obstack_printf, (obstack, format), + struct obstack *obstack AND const char *format DOTS) +{ + int result; + va_list ap; + va_start (ap, format); + result = obstack_vprintf (obstack, format, ap); + va_end (ap); + return result; +} diff --git a/stdio/perror.c b/stdio/perror.c new file mode 100644 index 0000000000..718a6f2256 --- /dev/null +++ b/stdio/perror.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <errno.h> + +extern char *_strerror_internal __P ((int, char buf[1024])); + +/* Print a line on stderr consisting of the text in S, a colon, a space, + a message describing the meaning of the contents of `errno' and a newline. + If S is NULL or "", the colon and space are omitted. */ +void +DEFUN(perror, (s), register CONST char *s) +{ + char buf[1024]; + int errnum = errno; + CONST char *colon; + + if (s == NULL || *s == '\0') + s = colon = ""; + else + colon = ": "; + + (void) fprintf (stderr, "%s%s%s\n", + s, colon, _strerror_internal (errnum, buf)); +} diff --git a/stdio/printf-prs.c b/stdio/printf-prs.c new file mode 100644 index 0000000000..2f55dd3157 --- /dev/null +++ b/stdio/printf-prs.c @@ -0,0 +1,211 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <printf.h> +#include <limits.h> +#include <string.h> +#include <ctype.h> + +#ifdef __GNUC__ +#define HAVE_LONGLONG +#endif + +extern printf_arginfo_function *__printf_arginfo_table[]; + +size_t +DEFUN(parse_printf_format, (fmt, n, argtypes), + CONST char *fmt AND size_t n AND int *argtypes) +{ + register CONST char *f; + size_t need = 0; + + for (f = strchr (fmt, '%'); f != NULL; f = strchr (f, '%')) + { + struct printf_info info; + printf_arginfo_function *arginfo; + + ++f; + + info.space = info.showsign = info.left = info.alt = info.group = 0; + info.pad = ' '; + while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0' || + *f == '\'') + switch (*f++) + { + case ' ': + info.space = 1; + break; + case '+': + info.showsign = 1; + break; + case '-': + info.left = 1; + break; + case '#': + info.alt = 1; + break; + case '\'': + info.group = 1; + break; + case '0': + info.pad = '0'; + break; + } + if (info.left) + info.pad = ' '; + + /* Get the field width. */ + if (*f == '*') + { + if (++need < n) + *argtypes++ = PA_INT; + info.width = INT_MIN; + ++f; + } + else + { + info.width = 0; + while (isdigit(*f)) + { + info.width *= 10; + info.width += *f++ - '0'; + } + } + + /* Get the precision. */ + /* -1 means none given; 0 means explicit 0. */ + info.prec = -1; + if (*f == '.') + { + ++f; + if (*f == '*') + { + /* The precision is given in an argument. */ + if (++need < n) + *argtypes++ = PA_INT; + info.prec = INT_MIN; + ++f; + } + else if (isdigit(*f)) + { + info.prec = 0; + while (*f != '\0' && isdigit(*f)) + { + info.prec *= 10; + info.prec += *f++ - '0'; + } + } + } + + /* Check for type modifiers. */ + info.is_short = info.is_long = info.is_long_double = 0; + while (*f == 'h' || *f == 'l' || *f == 'L') + switch (*f++) + { + case 'h': + /* int's are short int's. */ + info.is_short = 1; + break; + case 'l': +#ifdef HAVE_LONGLONG + if (info.is_long) + /* A double `l' is equivalent to an `L'. */ + info.is_long_double = 1; + else +#endif + /* int's are long int's. */ + info.is_long = 1; + break; + case 'L': + /* double's are long double's, and int's are long long int's. */ + info.is_long_double = 1; + break; + } + + if (*f == '\0') + return need; + + info.spec = *f++; + + arginfo = __printf_arginfo_table[info.spec]; + if (arginfo != NULL) + { + size_t nargs + = (*arginfo) (&info, need > n ? 0 : n - need, argtypes); + need += nargs; + argtypes += nargs; + } + else + { + int type; + switch (info.spec) + { + case 'i': + case 'd': + case 'u': + case 'o': + case 'X': + case 'x': + type = PA_INT; + break; + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + type = PA_DOUBLE; + break; + + case 'c': + type = PA_CHAR; + break; + + case 's': + type = PA_STRING; + break; + + case 'p': + type = PA_POINTER; + break; + + case 'n': + type = PA_INT | PA_FLAG_PTR; + break; + + default: + /* No arg for an unknown spec. */ + continue; + } + + if (info.is_long_double) + type |= PA_FLAG_LONG_DOUBLE; + if (info.is_long) + type |= PA_FLAG_LONG; + if (info.is_short) + type |= PA_FLAG_SHORT; + + if (++need < n) + *argtypes++ = type; + } + } + + return need; +} diff --git a/stdio/printf.c b/stdio/printf.c new file mode 100644 index 0000000000..9cdae768ae --- /dev/null +++ b/stdio/printf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Write formatted output to stdout from the format string FORMAT. */ +/* VARARGS1 */ +int +DEFUN(printf, (format), CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vprintf(format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/printf.h b/stdio/printf.h new file mode 100644 index 0000000000..c369222281 --- /dev/null +++ b/stdio/printf.h @@ -0,0 +1,114 @@ +/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the, 1992 Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifndef _PRINTF_H + +#define _PRINTF_H 1 +#include <features.h> + +__BEGIN_DECLS + +#define __need_FILE +#include <stdio.h> +#define __need_size_t +#include <stddef.h> + +#include <stdarg.h> /* Need va_list. */ + + +struct printf_info +{ + int prec; /* Precision. */ + int width; /* Width. */ + unsigned char spec; /* Format letter. */ + unsigned int is_long_double:1;/* L flag. */ + unsigned int is_short:1; /* h flag. */ + unsigned int is_long:1; /* l flag. */ + unsigned int alt:1; /* # flag. */ + unsigned int space:1; /* Space flag. */ + unsigned int left:1; /* - flag. */ + unsigned int showsign:1; /* + flag. */ + unsigned int group:1; /* ' flag. */ + char pad; /* Padding character. */ +}; + + +/* Type of a printf specifier-handler function. + STREAM is the FILE on which to write output. + INFO gives information about the format specification. + Arguments can be read from ARGS. + The function should return the number of characters written, + or -1 for errors. */ + +typedef int printf_function __P ((FILE * __stream, + __const struct printf_info * __info, + va_list * __args)); +typedef int printf_arginfo_function __P ((__const struct printf_info * __info, + size_t __n, + int *__argtypes)); + +/* Register FUNC to be called to format SPEC specifiers. + ARGINFO, if not NULL, is a function used by `parse_printf_format' + to determine how many arguments a SPEC conversion requires, + and what their types are. */ +extern int register_printf_function __P ((int __spec, printf_function __func, + printf_arginfo_function __arginfo)); + +/* Parse FMT, and fill in N elements of ARGTYPES with the + types needed for the conversions FMT specifies. Returns + the number of arguments required by FMT. + + The ARGINFO function registered with a user-defined format is passed a + `struct printf_info' describing the format spec being parsed. A width + or precision of INT_MIN means a `*' was used to indicate that the + width/precision will come from an arg. The function should fill in the + array it is passed with the types of the arguments it wants, and return + the number of arguments it wants. */ + +extern size_t parse_printf_format __P ((__const char *__fmt, + size_t __n, + int *__argtypes)); + +/* Codes returned by `parse_printf_format' for basic types. + + These values cover all the standard format specifications. + Users can add new values after PA_LAST for their own types. */ + +enum +{ /* C type: */ + PA_INT, /* int */ + PA_CHAR, /* int, cast to char */ + PA_STRING, /* const char *, a '\0'-terminated string */ + PA_POINTER, /* void * */ + PA_FLOAT, /* float */ + PA_DOUBLE, /* double */ + PA_LAST +}; + +/* Flag bits that can be set in a type returned by `parse_printf_format'. */ +#define PA_FLAG_MASK 0xff00 +#define PA_FLAG_LONG_LONG (1 << 8) +#define PA_FLAG_LONG_DOUBLE PA_FLAG_LONG_LONG +#define PA_FLAG_LONG (1 << 9) +#define PA_FLAG_SHORT (1 << 10) +#define PA_FLAG_PTR (1 << 11) + + +__END_DECLS + +#endif /* printf.h */ diff --git a/stdio/printf_fp.c b/stdio/printf_fp.c new file mode 100644 index 0000000000..ddf025721b --- /dev/null +++ b/stdio/printf_fp.c @@ -0,0 +1,991 @@ +/* Floating point output for `printf'. +Copyright (C) 1995 Free Software Foundation, Inc. +Written by Ulrich Drepper. + +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#ifdef USE_IN_LIBIO +# include <libioP.h> +#else +# include <stdio.h> +#endif +#include <alloca.h> +#include <ansidecl.h> +#include <ctype.h> +#include <float.h> +#include <gmp-mparam.h> +#include <gmp.h> +#include <gmp-impl.h> +#include <longlong.h> +#include <localeinfo.h> +#include <math.h> +#include <printf.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +/* #define NDEBUG 1 */ +#include <assert.h> + +/* This defines make it possible to use the same code for GNU C library and + the GNU I/O library. */ +#ifdef USE_IN_LIBIO +# define PUT(f, s, n) _IO_sputn (f, s, n) +# define PAD(f, c, n) _IO_padn (f, c, n) +/* We use this file GNU C library and GNU I/O library. So make + names equal. */ +# undef putc +# define putc(c, f) _IO_putc (c, f) +# define size_t _IO_size_t +# define FILE _IO_FILE +#else /* ! USE_IN_LIBIO */ +# define PUT(f, s, n) fwrite (s, 1, n, f) +# define PAD(f, c, n) __printf_pad (f, c, n) +ssize_t __printf_pad __P ((FILE *, char pad, int n)); /* In vfprintf.c. */ +#endif /* USE_IN_LIBIO */ + +/* Macros for doing the actual output. */ + +#define outchar(ch) \ + do \ + { \ + register CONST int outc = (ch); \ + if (putc (outc, fp) == EOF) \ + return -1; \ + ++done; \ + } while (0) + +#define PRINT(ptr, len) \ + do \ + { \ + register size_t outlen = (len); \ + if (len > 20) \ + { \ + if (PUT (fp, ptr, outlen) != outlen) \ + return -1; \ + ptr += outlen; \ + done += outlen; \ + } \ + else \ + { \ + while (outlen-- > 0) \ + outchar (*ptr++); \ + } \ + } while (0) + +#define PADN(ch, len) \ + do \ + { \ + if (PAD (fp, ch, len) != len) \ + return -1; \ + done += len; \ + } \ + while (0) + +/* We use the GNU MP library to handle large numbers. + + An MP variable occupies a varying number of entries in its array. We keep + track of this number for efficiency reasons. Otherwise we would always + have to process the whole array. */ +#define MPN_VAR(name) mp_limb *name; mp_size_t name##size + +#define MPN_ASSIGN(dst,src) \ + memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb)) +#define MPN_GE(u,v) \ + (u##size > v##size || (u##size == v##size && __mpn_cmp (u, v, u##size) >= 0)) + +extern int __isinfl (long double), __isnanl (long double); + +extern mp_size_t __mpn_extract_double (mp_ptr res_ptr, mp_size_t size, + int *expt, int *is_neg, + double value); +extern mp_size_t __mpn_extract_long_double (mp_ptr res_ptr, mp_size_t size, + int *expt, int *is_neg, + long double value); + +#include "fpioconst.h" + + +static unsigned int guess_grouping (unsigned int intdig_max, + const char *grouping, wchar_t sepchar); +static char *group_number (char *buf, char *bufend, unsigned int intdig_no, + const char *grouping, wchar_t thousands_sep); + + +int +__printf_fp (fp, info, args) + FILE *fp; + const struct printf_info *info; + va_list *args; +{ + /* The floating-point value to output. */ + union + { + double dbl; + LONG_DOUBLE ldbl; + } + fpnum; + + /* Locale-dependent representation of decimal point. */ + wchar_t decimal; + + /* Locale-dependent thousands separator and grouping specification. */ + wchar_t thousands_sep; + const char *grouping; + + /* "NaN" or "Inf" for the special cases. */ + CONST char *special = NULL; + + /* We need just a few limbs for the input before shifting to the right + position. */ + mp_limb fp_input[(LDBL_MANT_DIG + BITS_PER_MP_LIMB - 1) / BITS_PER_MP_LIMB]; + /* We need to shift the contents of fp_input by this amount of bits. */ + int to_shift; + + /* The significant of the floting-point value in question */ + MPN_VAR(frac); + /* and the exponent. */ + int exponent; + /* Sign of the exponent. */ + int expsign = 0; + /* Sign of float number. */ + int is_neg = 0; + + /* Scaling factor. */ + MPN_VAR(scale); + + /* Temporary bignum value. */ + MPN_VAR(tmp); + + /* Digit which is result of last hack_digit() call. */ + int digit; + + /* The type of output format that will be used: 'e'/'E' or 'f'. */ + int type; + + /* Counter for number of written characters. */ + int done = 0; + + /* General helper (carry limb). */ + mp_limb cy; + + char hack_digit (void) + { + mp_limb hi; + + if (expsign != 0 && type == 'f' && exponent-- > 0) + hi = 0; + else if (scalesize == 0) + { + hi = frac[fracsize - 1]; + cy = __mpn_mul_1 (frac, frac, fracsize - 1, 10); + frac[fracsize - 1] = cy; + } + else + { + if (fracsize < scalesize) + hi = 0; + else + { + hi = __mpn_divmod (tmp, frac, fracsize, scale, scalesize); + tmp[fracsize - scalesize] = hi; + hi = tmp[0]; + + fracsize = __mpn_normal_size (frac, scalesize); + if (fracsize == 0) + { + /* We're not prepared for an mpn variable with zero + limbs. */ + fracsize = 1; + return '0' + hi; + } + } + + cy = __mpn_mul_1 (frac, frac, fracsize, 10); + if (cy != 0) + frac[fracsize++] = cy; + } + + return '0' + hi; + } + + + /* Figure out the decimal point character. */ + if (mbtowc (&decimal, _numeric_info->decimal_point, + strlen (_numeric_info->decimal_point)) <= 0) + decimal = (wchar_t) *_numeric_info->decimal_point; + + + if (info->group) + { + grouping = _numeric_info->grouping; /* Cache the grouping info array. */ + if (*grouping <= 0 || *grouping == CHAR_MAX) + grouping = NULL; + else + { + /* Figure out the thousands seperator character. */ + if (mbtowc (&thousands_sep, _numeric_info->thousands_sep, + strlen (_numeric_info->thousands_sep)) <= 0) + thousands_sep = (wchar_t) *_numeric_info->thousands_sep; + if (thousands_sep == L'\0') + grouping = NULL; + } + } + else + grouping = NULL; + + /* Fetch the argument value. */ + if (info->is_long_double && sizeof (long double) > sizeof (double)) + { + fpnum.ldbl = va_arg (*args, LONG_DOUBLE); + + /* Check for special values: not a number or infinity. */ + if (__isnanl (fpnum.ldbl)) + { + special = "NaN"; + is_neg = 0; + } + else if (__isinfl (fpnum.ldbl)) + { + special = "Inf"; + is_neg = fpnum.ldbl < 0; + } + else + { + fracsize = __mpn_extract_long_double (fp_input, + (sizeof (fp_input) / + sizeof (fp_input[0])), + &exponent, &is_neg, + fpnum.ldbl); + to_shift = 1 + fracsize * BITS_PER_MP_LIMB - LDBL_MANT_DIG; + } + } + else + { + fpnum.dbl = va_arg (*args, double); + + /* Check for special values: not a number or infinity. */ + if (__isnan (fpnum.dbl)) + { + special = "NaN"; + is_neg = 0; + } + else if (__isinf (fpnum.dbl)) + { + special = "Inf"; + is_neg = fpnum.dbl < 0; + } + else + { + fracsize = __mpn_extract_double (fp_input, + (sizeof (fp_input) + / sizeof (fp_input[0])), + &exponent, &is_neg, fpnum.dbl); + to_shift = 1 + fracsize * BITS_PER_MP_LIMB - DBL_MANT_DIG; + } + } + + if (special) + { + int width = info->prec > info->width ? info->prec : info->width; + + if (is_neg || info->showsign || info->space) + --width; + width -= 3; + + if (!info->left && width > 0) + PADN (' ', width); + + if (is_neg) + outchar ('-'); + else if (info->showsign) + outchar ('+'); + else if (info->space) + outchar (' '); + + PRINT (special, 3); + + if (info->left && width > 0) + PADN (' ', width); + + return done; + } + + + /* We need three multiprecision variables. Now that we have the exponent + of the number we can allocate the needed memory. It would be more + efficient to use variables of the fixed maximum size but because this + would be really big it could lead to memory problems. */ + { + mp_size_t bignum_size = ((ABS (exponent) + BITS_PER_MP_LIMB - 1) + / BITS_PER_MP_LIMB + 3) * sizeof (mp_limb); + frac = (mp_limb *) alloca (bignum_size); + tmp = (mp_limb *) alloca (bignum_size); + scale = (mp_limb *) alloca (bignum_size); + } + + /* We now have to distinguish between numbers with positive and negative + exponents because the method used for the one is not applicable/efficient + for the other. */ + scalesize = 0; + if (exponent > 2) + { + /* |FP| >= 1.0. */ + int scaleexpo = 0; + int explog = LDBL_MAX_10_EXP_LOG; + int exp10 = 0; + const struct mp_power *tens = &_fpioconst_pow10[explog + 1]; + int cnt_h, cnt_l, i; + + if ((exponent + to_shift) % BITS_PER_MP_LIMB == 0) + { + MPN_COPY_DECR (frac + (exponent + to_shift) / BITS_PER_MP_LIMB, + fp_input, fracsize); + fracsize += (exponent + to_shift) / BITS_PER_MP_LIMB; + } + else + { + cy = __mpn_lshift (frac + (exponent + to_shift) / BITS_PER_MP_LIMB, + fp_input, fracsize, + (exponent + to_shift) % BITS_PER_MP_LIMB); + fracsize += (exponent + to_shift) / BITS_PER_MP_LIMB; + if (cy) + frac[fracsize++] = cy; + } + MPN_ZERO (frac, (exponent + to_shift) / BITS_PER_MP_LIMB); + + assert (tens > &_fpioconst_pow10[0]); + do + { + --tens; + + /* The number of the product of two binary numbers with n and m + bits respectively has m+n or m+n-1 bits. */ + if (exponent >= scaleexpo + tens->p_expo - 1) + { + if (scalesize == 0) + MPN_ASSIGN (tmp, tens->array); + else + { + cy = __mpn_mul (tmp, scale, scalesize, + tens->array + 2, tens->arraysize - 2); + tmpsize = scalesize + tens->arraysize - 2; + if (cy == 0) + --tmpsize; + } + + if (MPN_GE (frac, tmp)) + { + int cnt; + MPN_ASSIGN (scale, tmp); + count_leading_zeros (cnt, scale[scalesize - 1]); + scaleexpo = (scalesize - 2) * BITS_PER_MP_LIMB - cnt - 1; + exp10 |= 1 << explog; + } + } + --explog; + } + while (tens > &_fpioconst_pow10[0]); + exponent = exp10; + + /* Optimize number representations. We want to represent the numbers + with the lowest number of bytes possible without losing any + bytes. Also the highest bit in the scaling factor has to be set + (this is a requirement of the MPN division routines). */ + if (scalesize > 0) + { + /* Determine minimum number of zero bits at the end of + both numbers. */ + for (i = 0; scale[i] == 0 && frac[i] == 0; i++) + ; + + /* Determine number of bits the scaling factor is misplaced. */ + count_leading_zeros (cnt_h, scale[scalesize - 1]); + + if (cnt_h == 0) + { + /* The highest bit of the scaling factor is already set. So + we only have to remove the trailing empty limbs. */ + if (i > 0) + { + MPN_COPY_INCR (scale, scale + i, scalesize - i); + scalesize -= i; + MPN_COPY_INCR (frac, frac + i, fracsize - i); + fracsize -= i; + } + } + else + { + if (scale[i] != 0) + { + count_trailing_zeros (cnt_l, scale[i]); + if (frac[i] != 0) + { + int cnt_l2; + count_trailing_zeros (cnt_l2, frac[i]); + if (cnt_l2 < cnt_l) + cnt_l = cnt_l2; + } + } + else + count_trailing_zeros (cnt_l, frac[i]); + + /* Now shift the numbers to their optimal position. */ + if (i == 0 && BITS_PER_MP_LIMB - cnt_h > cnt_l) + { + /* We cannot save any memory. So just roll both numbers + so that the scaling factor has its highest bit set. */ + + (void) __mpn_lshift (scale, scale, scalesize, cnt_h); + cy = __mpn_lshift (frac, frac, fracsize, cnt_h); + if (cy != 0) + frac[fracsize++] = cy; + } + else if (BITS_PER_MP_LIMB - cnt_h <= cnt_l) + { + /* We can save memory by removing the trailing zero limbs + and by packing the non-zero limbs which gain another + free one. */ + + (void) __mpn_rshift (scale, scale + i, scalesize - i, + BITS_PER_MP_LIMB - cnt_h); + scalesize -= i + 1; + (void) __mpn_rshift (frac, frac + i, fracsize - i, + BITS_PER_MP_LIMB - cnt_h); + fracsize -= frac[fracsize - i - 1] == 0 ? i + 1 : i; + } + else + { + /* We can only save the memory of the limbs which are zero. + The non-zero parts occupy the same number of limbs. */ + + (void) __mpn_rshift (scale, scale + (i - 1), + scalesize - (i - 1), + BITS_PER_MP_LIMB - cnt_h); + scalesize -= i; + (void) __mpn_rshift (frac, frac + (i - 1), + fracsize - (i - 1), + BITS_PER_MP_LIMB - cnt_h); + fracsize -= frac[fracsize - (i - 1) - 1] == 0 ? i : i - 1; + } + } + } + } + else if (exponent < 0) + { + /* |FP| < 1.0. */ + int exp10 = 0; + int explog = LDBL_MAX_10_EXP_LOG; + const struct mp_power *tens = &_fpioconst_pow10[explog + 1]; + mp_size_t used_limbs = fracsize - 1; + + /* Now shift the input value to its right place. */ + cy = __mpn_lshift (frac, fp_input, fracsize, to_shift); + frac[fracsize++] = cy; + assert (cy == 1 || (frac[fracsize - 2] == 0 && frac[0] == 0)); + + expsign = 1; + exponent = -exponent; + + assert (tens != &_fpioconst_pow10[0]); + do + { + --tens; + + if (exponent >= tens->m_expo) + { + int i, incr, cnt_h, cnt_l; + mp_limb topval[2]; + + /* The __mpn_mul function expects the first argument to be + bigger than the second. */ + if (fracsize < tens->arraysize - 2) + cy = __mpn_mul (tmp, &tens->array[2], tens->arraysize - 2, + frac, fracsize); + else + cy = __mpn_mul (tmp, frac, fracsize, + &tens->array[2], tens->arraysize - 2); + tmpsize = fracsize + tens->arraysize - 2; + if (cy == 0) + --tmpsize; + + count_leading_zeros (cnt_h, tmp[tmpsize - 1]); + incr = (tmpsize - fracsize) * BITS_PER_MP_LIMB + + BITS_PER_MP_LIMB - 1 - cnt_h; + + assert (incr <= tens->p_expo); + + /* If we increased the exponent by exactly 3 we have to test + for overflow. This is done by comparing with 10 shifted + to the right position. */ + if (incr == exponent + 3) + if (cnt_h <= BITS_PER_MP_LIMB - 4) + { + topval[0] = 0; + topval[1] = 10 << (BITS_PER_MP_LIMB - 4 - cnt_h); + } + else + { + topval[0] = 10 << (BITS_PER_MP_LIMB - 4); + topval[1] = 0; + (void) __mpn_lshift (topval, topval, 2, + BITS_PER_MP_LIMB - cnt_h); + } + + /* We have to be careful when multiplying the last factor. + If the result is greater than 1.0 be have to test it + against 10.0. If it is greater or equal to 10.0 the + multiplication was not valid. This is because we cannot + determine the number of bits in the result in advance. */ + if (incr < exponent + 3 + || (incr == exponent + 3 && + (tmp[tmpsize - 1] < topval[1] + || (tmp[tmpsize - 1] == topval[1] + && tmp[tmpsize - 2] < topval[0])))) + { + /* The factor is right. Adapt binary and decimal + exponents. */ + exponent -= incr; + exp10 |= 1 << explog; + + /* If this factor yields a number greater or equal to + 1.0, we must not shift the non-fractional digits down. */ + if (exponent < 0) + cnt_h += -exponent; + + /* Now we optimize the number representation. */ + for (i = 0; tmp[i] == 0; ++i); + if (cnt_h == BITS_PER_MP_LIMB - 1) + { + MPN_COPY (frac, tmp + i, tmpsize - i); + fracsize = tmpsize - i; + } + else + { + count_trailing_zeros (cnt_l, tmp[i]); + + /* Now shift the numbers to their optimal position. */ + if (i == 0 && BITS_PER_MP_LIMB - 1 - cnt_h > cnt_l) + { + /* We cannot save any memory. Just roll the + number so that the leading digit is in a + seperate limb. */ + + cy = __mpn_lshift (frac, tmp, tmpsize, cnt_h + 1); + fracsize = tmpsize + 1; + frac[fracsize - 1] = cy; + } + else if (BITS_PER_MP_LIMB - 1 - cnt_h <= cnt_l) + { + (void) __mpn_rshift (frac, tmp + i, tmpsize - i, + BITS_PER_MP_LIMB - 1 - cnt_h); + fracsize = tmpsize - i; + } + else + { + /* We can only save the memory of the limbs which + are zero. The non-zero parts occupy the same + number of limbs. */ + + (void) __mpn_rshift (frac, tmp + (i - 1), + tmpsize - (i - 1), + BITS_PER_MP_LIMB - 1 - cnt_h); + fracsize = tmpsize - (i - 1); + } + } + used_limbs = fracsize - 1; + } + } + --explog; + } + while (tens != &_fpioconst_pow10[1] && exponent > 0); + /* All factors but 10^-1 are tested now. */ + if (exponent > 0) + { + cy = __mpn_mul_1 (tmp, frac, fracsize, 10); + tmpsize = fracsize; + assert (cy == 0 || tmp[tmpsize - 1] < 20); + + (void) __mpn_rshift (frac, tmp, tmpsize, MIN (4, exponent)); + fracsize = tmpsize; + exp10 |= 1; + assert (frac[fracsize - 1] < 10); + } + exponent = exp10; + } + else + { + /* This is a special case. We don't need a factor because the + numbers are in the range of 0.0 <= fp < 8.0. We simply + shift it to the right place and divide it by 1.0 to get the + leading digit. (Of course this division is not really made.) */ + assert (0 <= exponent && exponent < 3 && + exponent + to_shift < BITS_PER_MP_LIMB); + + /* Now shift the input value to its right place. */ + cy = __mpn_lshift (frac, fp_input, fracsize, (exponent + to_shift)); + frac[fracsize++] = cy; + exponent = 0; + } + + { + int width = info->width; + char *buffer, *startp, *cp; + int chars_needed; + int expscale; + int intdig_max, intdig_no = 0; + int fracdig_min, fracdig_max, fracdig_no = 0; + int dig_max; + int significant; + + if (tolower (info->spec) == 'e') + { + type = info->spec; + intdig_max = 1; + fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec; + chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4; + /* d . ddd e +- ddd */ + dig_max = INT_MAX; /* Unlimited. */ + significant = 1; /* Does not matter here. */ + } + else if (info->spec == 'f') + { + type = 'f'; + fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec; + if (expsign == 0) + { + intdig_max = exponent + 1; + /* This can be really big! */ /* XXX Maybe malloc if too big? */ + chars_needed = exponent + 1 + 1 + fracdig_max; + } + else + { + intdig_max = 1; + chars_needed = 1 + 1 + fracdig_max; + } + dig_max = INT_MAX; /* Unlimited. */ + significant = 1; /* Does not matter here. */ + } + else + { + dig_max = info->prec < 0 ? 6 : (info->prec == 0 ? 1 : info->prec); + if ((expsign == 0 && exponent >= dig_max) + || (expsign != 0 && exponent > 4)) + { + type = isupper (info->spec) ? 'E' : 'e'; + fracdig_max = dig_max - 1; + intdig_max = 1; + chars_needed = 1 + 1 + fracdig_max + 1 + 1 + 4; + } + else + { + type = 'f'; + intdig_max = expsign == 0 ? exponent + 1 : 0; + fracdig_max = dig_max - intdig_max; + /* We need space for the significant digits and perhaps for + leading zeros when < 1.0. Pessimistic guess: dig_max. */ + chars_needed = dig_max + dig_max + 1; + } + fracdig_min = info->alt ? fracdig_max : 0; + significant = 0; /* We count significant digits. */ + } + + if (grouping) + /* Guess the number of groups we will make, and thus how + many spaces we need for separator characters. */ + chars_needed += guess_grouping (intdig_max, grouping, thousands_sep); + + /* Allocate buffer for output. We need two more because while rounding + it is possible that we need two more characters in front of all the + other output. */ + buffer = alloca (2 + chars_needed); + cp = startp = buffer + 2; /* Let room for rounding. */ + + /* Do the real work: put digits in allocated buffer. */ + if (expsign == 0 || type != 'f') + { + assert (expsign == 0 || intdig_max == 1); + while (intdig_no < intdig_max) + { + ++intdig_no; + *cp++ = hack_digit (); + } + significant = 1; + if (info->alt + || fracdig_min > 0 + || (fracdig_max > 0 && (fracsize > 1 || frac[0] != 0))) + *cp++ = decimal; + } + else + { + /* |fp| < 1.0 and the selected type is 'f', so put "0." + in the buffer. */ + *cp++ = '0'; + --exponent; + *cp++ = decimal; + } + + /* Generate the needed number of fractional digits. */ + while (fracdig_no < fracdig_min + || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0))) + { + ++fracdig_no; + *cp = hack_digit (); + if (*cp != '0') + significant = 1; + else if (significant == 0) + { + ++fracdig_max; + if (fracdig_min > 0) + ++fracdig_min; + } + ++cp; + } + + /* Do rounding. */ + digit = hack_digit (); + if (digit > '4') + { + char *tp = cp; + + if (digit == '5') + /* This is the critical case. */ + if (fracsize == 1 && frac[0] == 0) + /* Rest of the number is zero -> round to even. + (IEEE 754-1985 4.1 says this is the default rounding.) */ + if ((*(cp - 1) & 1) == 0) + goto do_expo; + + if (fracdig_no > 0) + { + /* Process fractional digits. Terminate if not rounded or + radix character is reached. */ + while (*--tp != decimal && *tp == '9') + *tp = '0'; + if (*tp != decimal) + /* Round up. */ + (*tp)++; + } + + if (fracdig_no == 0 || *tp == decimal) + { + /* Round the integer digits. */ + if (*(tp - 1) == decimal) + --tp; + + while (--tp >= startp && *tp == '9') + *tp = '0'; + + if (tp >= startp) + /* Round up. */ + (*tp)++; + else + /* It is more citical. All digits were 9's. */ + { + if (type != 'f') + { + *startp = '1'; + exponent += expsign == 0 ? 1 : -1; + } + else if (intdig_no == dig_max) + { + /* This is the case where for type %g the number fits + really in the range for %f output but after rounding + the number of digits is too big. */ + *--startp = decimal; + *--startp = '1'; + + if (info->alt || fracdig_no > 0) + { + /* Overwrite the old radix character. */ + startp[intdig_no + 2] = '0'; + ++fracdig_no; + } + + fracdig_no += intdig_no; + intdig_no = 1; + fracdig_max = intdig_max - intdig_no; + ++exponent; + /* Now we must print the exponent. */ + type = isupper (info->spec) ? 'E' : 'e'; + } + else + { + /* We can simply add another another digit before the + radix. */ + *--startp = '1'; + ++intdig_no; + } + + /* While rounding the number of digits can change. + If the number now exceeds the limits remove some + fractional digits. */ + if (intdig_no + fracdig_no > dig_max) + { + cp -= intdig_no + fracdig_no - dig_max; + fracdig_no -= intdig_no + fracdig_no - dig_max; + } + } + } + } + + do_expo: + /* Now remove unnecessary '0' at the end of the string. */ + while (fracdig_no > fracdig_min && *(cp - 1) == '0') + { + --cp; + --fracdig_no; + } + /* If we eliminate all fractional digits we perhaps also can remove + the radix character. */ + if (fracdig_no == 0 && !info->alt && *(cp - 1) == decimal) + --cp; + + if (grouping) + /* Add in separator characters, overwriting the same buffer. */ + cp = group_number (startp, cp, intdig_no, grouping, thousands_sep); + + /* Write the exponent if it is needed. */ + if (type != 'f') + { + *cp++ = type; + *cp++ = expsign ? '-' : '+'; + + /* Find the magnitude of the exponent. */ + expscale = 10; + while (expscale <= exponent) + expscale *= 10; + + if (exponent < 10) + /* Exponent always has at least two digits. */ + *cp++ = '0'; + else + do + { + expscale /= 10; + *cp++ = '0' + (exponent / expscale); + exponent %= expscale; + } + while (expscale > 10); + *cp++ = '0' + exponent; + } + + /* Compute number of characters which must be filled with the padding + character. */ + if (is_neg || info->showsign || info->space) + --width; + width -= cp - startp; + + if (!info->left && info->pad != '0' && width > 0) + PADN (info->pad, width); + + if (is_neg) + outchar ('-'); + else if (info->showsign) + outchar ('+'); + else if (info->space) + outchar (' '); + + if (!info->left && info->pad == '0' && width > 0) + PADN ('0', width); + + PRINT (startp, cp - startp); + + if (info->left && width > 0) + PADN (info->pad, width); + } + return done; +} + +/* Return the number of extra grouping characters that will be inserted + into a number with INTDIG_MAX integer digits. */ + +static unsigned int +guess_grouping (unsigned int intdig_max, const char *grouping, wchar_t sepchar) +{ + unsigned int groups; + + /* We treat all negative values like CHAR_MAX. */ + + if (*grouping == CHAR_MAX || *grouping <= 0) + /* No grouping should be done. */ + return 0; + + groups = 0; + while (intdig_max > *grouping) + { + ++groups; + intdig_max -= *grouping++; + + if (*grouping == CHAR_MAX || *grouping < 0) + /* No more grouping should be done. */ + break; + else if (*grouping == 0) + { + /* Same grouping repeats. */ + groups += intdig_max / grouping[-1]; + break; + } + } + + return groups; +} + +/* Group the INTDIG_NO integer digits of the number in [BUF,BUFEND). + There is guaranteed enough space past BUFEND to extend it. + Return the new end of buffer. */ + +static char * +group_number (char *buf, char *bufend, unsigned int intdig_no, + const char *grouping, wchar_t thousands_sep) +{ + unsigned int groups = guess_grouping (intdig_no, grouping, thousands_sep); + char *p; + + if (groups == 0) + return bufend; + + /* Move the fractional part down. */ + memmove (buf + intdig_no + groups, buf + intdig_no, + bufend - (buf + intdig_no)); + + p = buf + intdig_no + groups - 1; + do + { + unsigned int len = *grouping++; + do + *p-- = buf[--intdig_no]; + while (--len > 0); + *p-- = thousands_sep; + + if (*grouping == CHAR_MAX || *grouping < 0) + /* No more grouping should be done. */ + break; + else if (*grouping == 0) + /* Same grouping repeats. */ + --grouping; + } while (intdig_no > *grouping); + + /* Copy the remaining ungrouped digits. */ + do + *p-- = buf[--intdig_no]; + while (p > buf); + + return bufend + groups; +} diff --git a/stdio/psignal.c b/stdio/psignal.c new file mode 100644 index 0000000000..8997a2ecdf --- /dev/null +++ b/stdio/psignal.c @@ -0,0 +1,49 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <signal.h> + + +#ifndef HAVE_GNU_LD +#define _sys_siglist sys_siglist +#endif + +/* Defined in sys_siglist.c. */ +extern CONST char *CONST _sys_siglist[]; + + +/* Print out on stderr a line consisting of the test in S, a colon, a space, + a message describing the meaning of the signal number SIG and a newline. + If S is NULL or "", the colon and space are omitted. */ +void +DEFUN(psignal, (sig, s), int sig AND register CONST char *s) +{ + CONST char *colon; + + if (s == NULL || s == '\0') + s = colon = ""; + else + colon = ": "; + + if (sig >= 0 && sig < NSIG) + (void) fprintf(stderr, "%s%s%s\n", s, colon, _sys_siglist[sig]); + else + (void) fprintf(stderr, "%s%sUnknown signal %d\n", s, colon, sig); +} diff --git a/stdio/putc.c b/stdio/putc.c new file mode 100644 index 0000000000..51aae378ae --- /dev/null +++ b/stdio/putc.c @@ -0,0 +1,5 @@ +#include <ansidecl.h> +#include <stdio.h> +#undef putc +#define fputc putc +#include <fputc.c> diff --git a/stdio/putchar.c b/stdio/putchar.c new file mode 100644 index 0000000000..90c037600a --- /dev/null +++ b/stdio/putchar.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + +#undef putchar + + +/* Write the character C on stdout. */ +int +DEFUN(putchar, (c), int c) +{ + return __putc(c, stdout); +} diff --git a/stdio/puts.c b/stdio/puts.c new file mode 100644 index 0000000000..269c607da7 --- /dev/null +++ b/stdio/puts.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + +#undef puts + + +/* Write the string in S and a newline to stdout. */ +int +DEFUN(puts, (s), CONST char *s) +{ + return(fputs(s, stdout) || putchar('\n') == EOF ? EOF : 0); +} diff --git a/stdio/putw.c b/stdio/putw.c new file mode 100644 index 0000000000..1b70baeeaf --- /dev/null +++ b/stdio/putw.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + + +/* Write the word (int) W to STREAM. */ +int +DEFUN(putw, (w, stream), int w AND FILE *stream) +{ + /* Is there a better way? */ + if (fwrite((CONST PTR) &w, sizeof(w), 1, stream) < 1) + return(EOF); + return(0); +} diff --git a/stdio/reg-printf.c b/stdio/reg-printf.c new file mode 100644 index 0000000000..95d7a1f3c9 --- /dev/null +++ b/stdio/reg-printf.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <limits.h> +#include <printf.h> + +/* Array of functions indexed by format character. */ +static printf_function *printf_funcs[UCHAR_MAX + 1]; +printf_arginfo_function *__printf_arginfo_table[UCHAR_MAX + 1]; + +printf_function **__printf_function_table; + +/* Register FUNC to be called to format SPEC specifiers. */ +int +DEFUN(register_printf_function, (spec, converter, arginfo), + int spec AND printf_function converter AND + printf_arginfo_function arginfo) +{ + if (spec < 0 || spec > (int) UCHAR_MAX) + { + errno = EINVAL; + return -1; + } + + __printf_function_table = printf_funcs; + __printf_arginfo_table[spec] = arginfo; + printf_funcs[spec] = converter; + + return 0; +} diff --git a/stdio/rewind.c b/stdio/rewind.c new file mode 100644 index 0000000000..038b0164d8 --- /dev/null +++ b/stdio/rewind.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + +#undef rewind + + +/* Rewind STREAM to the beginning of the + file and clear its error and EOF flags. */ +void +DEFUN(rewind, (stream), FILE *stream) +{ + clearerr(stream); + (void) fseek(stream, 0L, SEEK_SET); + clearerr(stream); +} diff --git a/stdio/scanf.c b/stdio/scanf.c new file mode 100644 index 0000000000..aa7021526f --- /dev/null +++ b/stdio/scanf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Read formatted input from stdin according to the format string FORMAT. */ +/* VARARGS1 */ +int +DEFUN(scanf, (format), CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vscanf(format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/setbuf.c b/stdio/setbuf.c new file mode 100644 index 0000000000..99cfa9dd24 --- /dev/null +++ b/stdio/setbuf.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> + + +/* If BUF is NULL, make STREAM unbuffered. + If not, make BUF, which is BUFSIZ bytes long, be its buffer. */ +void +DEFUN(setbuf, (stream, buf), FILE *stream AND char *buf) +{ + (void) setvbuf(stream, buf, buf != NULL ? _IOFBF : _IONBF, BUFSIZ); +} diff --git a/stdio/setbuffer.c b/stdio/setbuffer.c new file mode 100644 index 0000000000..7677c1e358 --- /dev/null +++ b/stdio/setbuffer.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> + + +/* If BUF is NULL, make stream unbuffered. + If not, make BUF, which is N bytes long, be its buffer. */ +void +DEFUN(setbuffer, (stream, buf, n), FILE *stream AND char *buf AND size_t n) +{ + (void) setvbuf(stream, buf, buf != NULL ? _IOFBF : _IONBF, n); +} diff --git a/stdio/setlinebuf.c b/stdio/setlinebuf.c new file mode 100644 index 0000000000..578cdfa54f --- /dev/null +++ b/stdio/setlinebuf.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + + +/* Make STREAM line buffered. */ +void +DEFUN(setlinebuf, (stream), FILE *stream) +{ + if (stream->__buffer != NULL || !stream->__userbuf) + stream->__linebuf = 1; +} diff --git a/stdio/setvbuf.c b/stdio/setvbuf.c new file mode 100644 index 0000000000..8c33386610 --- /dev/null +++ b/stdio/setvbuf.c @@ -0,0 +1,85 @@ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + + +/* Make STREAM use the buffering method given in MODE. + If MODE indicates full or line buffering, use BUF, + a buffer of SIZE bytes; if BUF is NULL, malloc a buffer. */ +int +DEFUN(setvbuf, (stream, buf, mode, size), + FILE *stream AND char *buf AND int mode AND size_t size) +{ + if (!__validfp(stream)) + { + errno = EINVAL; + return EOF; + } + + /* The ANSI standard says setvbuf can only be called before any I/O is done, + but we allow it to replace an old buffer, flushing it first. */ + if (stream->__buffer != NULL) + { + (void) fflush(stream); + /* Free the old buffer if it was malloc'd. */ + if (!stream->__userbuf) + free(stream->__buffer); + } + + stream->__get_limit = stream->__put_limit = NULL; + stream->__bufp = stream->__buffer = NULL; + stream->__userbuf = stream->__linebuf = stream->__linebuf_active = 0; + + switch (mode) + { + default: + errno = EINVAL; + return EOF; + case _IONBF: /* Unbuffered. */ + stream->__buffer = NULL; + stream->__bufsize = 0; + stream->__userbuf = 1; + break; + case _IOLBF: /* Line buffered. */ + stream->__linebuf = 1; + case _IOFBF: /* Fully buffered. */ + if (size == 0) + { + errno = EINVAL; + return EOF; + } + stream->__bufsize = size; + if (buf != NULL) + stream->__userbuf = 1; + else if ((buf = (char *) malloc(size)) == NULL) + return EOF; + stream->__buffer = buf; + break; + } + + stream->__bufp = stream->__buffer; + stream->__get_limit = stream->__buffer; + /* The next output operation will prime the stream for writing. */ + stream->__put_limit = stream->__buffer; + + return 0; +} diff --git a/stdio/snprintf.c b/stdio/snprintf.c new file mode 100644 index 0000000000..9f3e0c4868 --- /dev/null +++ b/stdio/snprintf.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Write formatted output into S, according to the format + string FORMAT, writing no more than MAXLEN characters. */ +/* VARARGS3 */ +int +DEFUN(snprintf, (s, maxlen, format), + char *s AND size_t maxlen AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vsnprintf(s, maxlen, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/sprintf.c b/stdio/sprintf.c new file mode 100644 index 0000000000..ce3a970074 --- /dev/null +++ b/stdio/sprintf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Write formatted output into S, according to the format string FORMAT. */ +/* VARARGS2 */ +int +DEFUN(sprintf, (s, format), char *s AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = vsprintf(s, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/sscanf.c b/stdio/sscanf.c new file mode 100644 index 0000000000..33bc203577 --- /dev/null +++ b/stdio/sscanf.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1991 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + + +/* Read formatted input from S, according to the format string FORMAT. */ +/* VARARGS2 */ +int +DEFUN(sscanf, (s, format), CONST char *s AND CONST char *format DOTS) +{ + va_list arg; + int done; + + va_start(arg, format); + done = __vsscanf(s, format, arg); + va_end(arg); + + return done; +} diff --git a/stdio/stdio.h b/stdio/stdio.h new file mode 100644 index 0000000000..2994432328 --- /dev/null +++ b/stdio/stdio.h @@ -0,0 +1,681 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +/* + * ANSI Standard: 4.9 INPUT/OUTPUT <stdio.h> + */ + +#ifndef _STDIO_H + +#if !defined(__need_FILE) +#define _STDIO_H 1 +#include <features.h> + +__BEGIN_DECLS + +#define __need_size_t +#define __need_NULL +#include <stddef.h> + +#define __need___va_list +#include <stdarg.h> +#ifndef __GNUC_VA_LIST +#define __gnuc_va_list __ptr_t +#endif + +#include <gnu/types.h> +#endif /* Don't need FILE. */ +#undef __need_FILE + + +#ifndef __FILE_defined + +/* The opaque type of streams. */ +typedef struct __stdio_file FILE; + +#define __FILE_defined 1 +#endif /* FILE not defined. */ + + +#ifdef _STDIO_H + +/* The type of the second argument to `fgetpos' and `fsetpos'. */ +typedef __off_t fpos_t; + +/* The mode of I/O, as given in the MODE argument to fopen, etc. */ +typedef struct +{ + unsigned int __read:1; /* Open for reading. */ + unsigned int __write:1; /* Open for writing. */ + unsigned int __append:1; /* Open for appending. */ + unsigned int __binary:1; /* Opened binary. */ + unsigned int __create:1; /* Create the file. */ + unsigned int __exclusive:1; /* Error if it already exists. */ + unsigned int __truncate:1; /* Truncate the file on opening. */ +} __io_mode; + + +/* Functions to do I/O and file management for a stream. */ + +/* Read NBYTES bytes from COOKIE into a buffer pointed to by BUF. + Return number of bytes read. */ +typedef __ssize_t __io_read_fn __P ((__ptr_t __cookie, char *__buf, + size_t __nbytes)); + +/* Write N bytes pointed to by BUF to COOKIE. Write all N bytes + unless there is an error. Return number of bytes written, or -1 if + there is an error without writing anything. If the file has been + opened for append (__mode.__append set), then set the file pointer + to the end of the file and then do the write; if not, just write at + the current file pointer. */ +typedef __ssize_t __io_write_fn __P ((__ptr_t __cookie, __const char *__buf, + size_t __n)); + +/* Move COOKIE's file position to *POS bytes from the + beginning of the file (if W is SEEK_SET), + the current position (if W is SEEK_CUR), + or the end of the file (if W is SEEK_END). + Set *POS to the new file position. + Returns zero if successful, nonzero if not. */ +typedef int __io_seek_fn __P ((__ptr_t __cookie, fpos_t *__pos, int __w)); + +/* Close COOKIE. */ +typedef int __io_close_fn __P ((__ptr_t __cookie)); + +/* Return the file descriptor associated with COOKIE, + or -1 on error. There need not be any associated file descriptor. */ +typedef int __io_fileno_fn __P ((__ptr_t __cookie)); + +#ifdef __USE_GNU +/* User-visible names for the above. */ +typedef __io_read_fn cookie_read_function_t; +typedef __io_write_fn cookie_write_function_t; +typedef __io_seek_fn cookie_seek_function_t; +typedef __io_close_fn cookie_close_function_t; +typedef __io_fileno_fn cookie_fileno_function_t; +#endif + +/* Low level interface, independent of FILE representation. */ +#if defined (__USE_GNU) && !defined (_LIBC) +/* Define the user-visible type, with user-friendly member names. */ +typedef struct +{ + __io_read_fn *read; /* Read bytes. */ + __io_write_fn *write; /* Write bytes. */ + __io_seek_fn *seek; /* Seek/tell file position. */ + __io_close_fn *close; /* Close file. */ + __io_fileno_fn *fileno; /* Return file descriptor. */ +} cookie_io_functions_t; +/* This name is still used in the prototypes in this file. */ +typedef cookie_io_functions_t __io_functions; +#else +/* Stick to ANSI-safe names. */ +typedef struct +{ + __io_read_fn *__read; /* Read bytes. */ + __io_write_fn *__write; /* Write bytes. */ + __io_seek_fn *__seek; /* Seek/tell file position. */ + __io_close_fn *__close; /* Close file. */ + __io_fileno_fn *__fileno; /* Return file descriptor. */ +} __io_functions; +#endif + +/* Higher level interface, dependent on FILE representation. */ +typedef struct +{ + /* Make room in the input buffer. */ + int (*__input) __P ((FILE *__stream)); + /* Make room in the output buffer. */ + void (*__output) __P ((FILE *__stream, int __c)); +} __room_functions; + +extern __const __io_functions __default_io_functions; +extern __const __room_functions __default_room_functions; + + +/* Default close function. */ +extern __io_close_fn __stdio_close; +/* Open FILE with mode M, store cookie in *COOKIEPTR. */ +extern int __stdio_open __P ((__const char *__file, __io_mode __m, + __ptr_t *__cookieptr)); +/* Put out an error message for when stdio needs to die. */ +extern void __stdio_errmsg __P ((__const char *__msg, size_t __len)); +/* Generate a unique file name (and possibly open it with mode "w+b"). */ +extern char *__stdio_gen_tempname __P ((__const char *__dir, + __const char *__pfx, + int __dir_search, + size_t *__lenptr, + FILE **__streamptr)); + + +/* Print out MESSAGE on the error output and abort. */ +extern void __libc_fatal __P ((__const char *__message)) + __attribute__ ((__noreturn__)); + + +/* The FILE structure. */ +struct __stdio_file +{ + /* Magic number for validation. Must be negative in open streams + for the glue to Unix stdio getc/putc to work. + NOTE: stdio/glue.c has special knowledge of these first four members. */ + int __magic; +#define _IOMAGIC 0xfedabeeb /* Magic number to fill `__magic'. */ +#define _GLUEMAGIC 0xfeedbabe /* Magic for glued Unix streams. */ + + char *__bufp; /* Pointer into the buffer. */ + char *__get_limit; /* Reading limit. */ + char *__put_limit; /* Writing limit. */ + + char *__buffer; /* Base of buffer. */ + size_t __bufsize; /* Size of the buffer. */ + __ptr_t __cookie; /* Magic cookie. */ + __io_mode __mode; /* File access mode. */ + __io_functions __io_funcs; /* I/O functions. */ + __room_functions __room_funcs;/* I/O buffer room functions. */ + fpos_t __offset; /* Current file position. */ + fpos_t __target; /* Target file position. */ + FILE *__next; /* Next FILE in the linked list. */ + char *__pushback_bufp; /* Old bufp if char pushed back. */ + unsigned char __pushback; /* Pushed-back character. */ + unsigned int __pushed_back:1; /* A char has been pushed back. */ + unsigned int __eof:1; /* End of file encountered. */ + unsigned int __error:1; /* Error encountered. */ + unsigned int __userbuf:1; /* Buffer from user (should not be freed). */ + unsigned int __linebuf:1; /* Flush on newline. */ + unsigned int __linebuf_active:1; /* put_limit is not really in use. */ + unsigned int __seen:1; /* This stream has been seen. */ + unsigned int __ispipe:1; /* Nonzero if opened by popen. */ +}; + + +/* All macros used internally by other macros here and by stdio functions begin + with `__'. All of these may evaluate their arguments more than once. */ + + +/* Nonzero if STREAM is a valid stream. + STREAM must be a modifiable lvalue (wow, I got to use that term). + See stdio/glue.c for what the confusing bit is about. */ +#define __validfp(stream) \ + (stream != NULL && \ + ((stream->__magic == _GLUEMAGIC && \ + (stream = *(((struct { int __magic; FILE **__p; } *) stream)->__p))), \ + (stream->__magic == _IOMAGIC))) + +/* Clear the error and EOF indicators of STREAM. */ +#define __clearerr(stream) ((stream)->__error = (stream)->__eof = 0) + +/* Nuke STREAM, making it unusable but available for reuse. */ +extern void __invalidate __P ((FILE *__stream)); + +/* Make sure STREAM->__offset and STREAM->__target are initialized. + Returns 0 if successful, or EOF on + error (but doesn't set STREAM->__error). */ +extern int __stdio_check_offset __P ((FILE *__stream)); + + +/* The possibilities for the third argument to `setvbuf'. */ +#define _IOFBF 0x1 /* Full buffering. */ +#define _IOLBF 0x2 /* Line buffering. */ +#define _IONBF 0x4 /* No buffering. */ + + +/* Default buffer size. */ +#define BUFSIZ 1024 + + +/* End of file character. + Some things throughout the library rely on this being -1. */ +#define EOF (-1) + + +/* The possibilities for the third argument to `fseek'. + These values should not be changed. */ +#define SEEK_SET 0 /* Seek from beginning of file. */ +#define SEEK_CUR 1 /* Seek from current position. */ +#define SEEK_END 2 /* Seek from end of file. */ + + +#ifdef __USE_SVID +/* Default path prefix for `tempnam' and `tmpnam'. */ +#define P_tmpdir "/usr/tmp" +#endif + + +/* Get the values: + L_tmpnam How long an array of chars must be to be passed to `tmpnam'. + TMP_MAX The minimum number of unique filenames generated by tmpnam + (and tempnam when it uses tmpnam's name space), + or tempnam (the two are separate). + L_ctermid How long an array to pass to `ctermid'. + L_cuserid How long an array to pass to `cuserid'. + FOPEN_MAX Mininum number of files that can be open at once. + FILENAME_MAX Maximum length of a filename. */ +#include <stdio_lim.h> + + +/* All the known streams are in a linked list + linked by the `next' field of the FILE structure. */ +extern FILE *__stdio_head; /* Head of the list. */ + +/* Standard streams. */ +extern FILE *stdin, *stdout, *stderr; +#ifdef __STRICT_ANSI__ +/* ANSI says these are macros; satisfy pedants. */ +#define stdin stdin +#define stdout stdout +#define stderr stderr +#endif + + +/* Remove file FILENAME. */ +extern int remove __P ((__const char *__filename)); +/* Rename file OLD to NEW. */ +extern int rename __P ((__const char *__old, __const char *__new)); + + +/* Create a temporary file and open it read/write. */ +extern FILE *tmpfile __P ((void)); +/* Generate a temporary filename. */ +extern char *tmpnam __P ((char *__s)); + + +#ifdef __USE_SVID +/* Generate a unique temporary filename using up to five characters of PFX + if it is not NULL. The directory to put this file in is searched for + as follows: First the environment variable "TMPDIR" is checked. + If it contains the name of a writable directory, that directory is used. + If not and if DIR is not NULL, that value is checked. If that fails, + P_tmpdir is tried and finally "/tmp". The storage for the filename + is allocated by `malloc'. */ +extern char *tempnam __P ((__const char *__dir, __const char *__pfx)); +#endif + + +/* This performs actual output when necessary, flushing + STREAM's buffer and optionally writing another character. */ +extern int __flshfp __P ((FILE *__stream, int __c)); + + +/* Close STREAM, or all streams if STREAM is NULL. */ +extern int fclose __P ((FILE *__stream)); +/* Flush STREAM, or all streams if STREAM is NULL. */ +extern int fflush __P ((FILE *__stream)); + + +/* Open a file and create a new stream for it. */ +extern FILE *fopen __P ((__const char *__filename, __const char *__modes)); +/* Open a file, replacing an existing stream with it. */ +extern FILE *freopen __P ((__const char *__filename, + __const char *__modes, FILE *__stream)); + +/* Return a new, zeroed, stream. + You must set its cookie and io_mode. + The first operation will give it a buffer unless you do. + It will also give it the default functions unless you set the `seen' flag. + The offset is set to -1, meaning it will be determined by doing a + stationary seek. You can set it to avoid the initial tell call. + The target is set to -1, meaning it will be set to the offset + before the target is needed. + Returns NULL if a stream can't be created. */ +extern FILE *__newstream __P ((void)); + +#ifdef __USE_POSIX +/* Create a new stream that refers to an existing system file descriptor. */ +extern FILE *fdopen __P ((int __fd, __const char *__modes)); +#endif + +#ifdef __USE_GNU +/* Create a new stream that refers to the given magic cookie, + and uses the given functions for input and output. */ +extern FILE *fopencookie __P ((__ptr_t __magic_cookie, __const char *__modes, + __io_functions __io_funcs)); + +/* Create a new stream that refers to a memory buffer. */ +extern FILE *fmemopen __P ((__ptr_t __s, size_t __len, __const char *__modes)); + +/* Open a stream that writes into a malloc'd buffer that is expanded as + necessary. *BUFLOC and *SIZELOC are updated with the buffer's location + and the number of characters written on fflush or fclose. */ +extern FILE *open_memstream __P ((char **__bufloc, size_t *__sizeloc)); +#endif + + +/* If BUF is NULL, make STREAM unbuffered. + Else make it use buffer BUF, of size BUFSIZ. */ +extern void setbuf __P ((FILE *__stream, char *__buf)); +/* Make STREAM use buffering mode MODE. + If BUF is not NULL, use N bytes of it for buffering; + else allocate an internal buffer N bytes long. */ +extern int setvbuf __P ((FILE *__stream, char *__buf, + int __modes, size_t __n)); + +#ifdef __USE_BSD +/* If BUF is NULL, make STREAM unbuffered. + Else make it use SIZE bytes of BUF for buffering. */ +extern void setbuffer __P ((FILE *__stream, char *__buf, size_t __size)); + +/* Make STREAM line-buffered. */ +extern void setlinebuf __P ((FILE *__stream)); +#endif + + +/* Write formatted output to STREAM. */ +extern int fprintf __P ((FILE *__stream, __const char *__format, ...)); +/* Write formatted output to stdout. */ +extern int printf __P ((__const char *__format, ...)); +/* Write formatted output to S. */ +extern int sprintf __P ((char *__s, __const char *__format, ...)); + +/* Write formatted output to S from argument list ARG. */ +extern int vfprintf __P ((FILE *__s, __const char *__format, + __gnuc_va_list __arg)); +/* Write formatted output to stdout from argument list ARG. */ +extern int vprintf __P ((__const char *__format, __gnuc_va_list __arg)); +/* Write formatted output to S from argument list ARG. */ +extern int vsprintf __P ((char *__s, __const char *__format, + __gnuc_va_list __arg)); + +#ifdef __OPTIMIZE__ +extern __inline int +vprintf (const char *__fmt, __gnuc_va_list __arg) +{ + return vfprintf (stdout, __fmt, __arg); +} +#endif /* Optimizing. */ + +#ifdef __USE_GNU +/* Maximum chars of output to write in MAXLEN. */ +extern int snprintf __P ((char *__s, size_t __maxlen, + __const char *__format, ...)); + +extern int vsnprintf __P ((char *__s, size_t __maxlen, + __const char *__format, __gnuc_va_list __arg)); + +/* Write formatted output to a string dynamically allocated with `malloc'. + Store the address of the string in *PTR. */ +extern int vasprintf __P ((char **__ptr, __const char *__f, + __gnuc_va_list __arg)); +extern int asprintf __P ((char **__ptr, __const char *__fmt, ...)); + +/* Write formatted output to a file descriptor. */ +extern int vdprintf __P ((int __fd, __const char *__fmt, + __gnuc_va_list __arg)); +extern int dprintf __P ((int __fd, __const char *__fmt, ...)); +#endif + + +/* Read formatted input from STREAM. */ +extern int fscanf __P ((FILE *__stream, __const char *__format, ...)); +/* Read formatted input from stdin. */ +extern int scanf __P ((__const char *__format, ...)); +/* Read formatted input from S. */ +extern int sscanf __P ((__const char *__s, __const char *__format, ...)); + +#ifdef __USE_GNU +/* Read formatted input from S into argument list ARG. */ +extern int __vfscanf __P ((FILE *__s, __const char *__format, + __gnuc_va_list __arg)); +extern int vfscanf __P ((FILE *__s, __const char *__format, + __gnuc_va_list __arg)); + +/* Read formatted input from stdin into argument list ARG. */ +extern int vscanf __P ((__const char *__format, __gnuc_va_list __arg)); + +/* Read formatted input from S into argument list ARG. */ +extern int __vsscanf __P ((__const char *__s, __const char *__format, + __gnuc_va_list __arg)); +extern int vsscanf __P ((__const char *__s, __const char *__format, + __gnuc_va_list __arg)); + + +#ifdef __OPTIMIZE__ +extern __inline int +vfscanf (FILE *__s, const char *__fmt, __gnuc_va_list __arg) +{ + return __vfscanf (__s, __fmt, __arg); +} +extern __inline int +vscanf (const char *__fmt, __gnuc_va_list __arg) +{ + return __vfscanf (stdin, __fmt, __arg); +} +extern __inline int +vsscanf (const char *__s, const char *__fmt, __gnuc_va_list __arg) +{ + return __vsscanf (__s, __fmt, __arg); +} +#endif /* Optimizing. */ +#endif /* Use GNU. */ + + +/* This does actual reading when necessary, filling STREAM's + buffer and returning the first character in it. */ +extern int __fillbf __P ((FILE *__stream)); + + +/* Read a character from STREAM. */ +extern int fgetc __P ((FILE *__stream)); +extern int getc __P ((FILE *__stream)); + +/* Read a character from stdin. */ +extern int getchar __P ((void)); + +/* The C standard explicitly says this can + re-evaluate its argument, so it does. */ +#define __getc(stream) \ + ((stream)->__bufp < (stream)->__get_limit ? \ + (int) ((unsigned char) *(stream)->__bufp++) : __fillbf(stream)) + +/* The C standard explicitly says this is a macro, + so we always do the optimization for it. */ +#define getc(stream) __getc(stream) + +#ifdef __OPTIMIZE__ +extern __inline int +getchar (void) +{ + return __getc (stdin); +} +#endif /* Optimizing. */ + + +/* Write a character to STREAM. */ +extern int fputc __P ((int __c, FILE *__stream)); +extern int putc __P ((int __c, FILE *__stream)); + +/* Write a character to stdout. */ +extern int putchar __P ((int __c)); + + +/* The C standard explicitly says this can + re-evaluate its arguments, so it does. */ +#define __putc(c, stream) \ + ((stream)->__bufp < (stream)->__put_limit ? \ + (int) (unsigned char) (*(stream)->__bufp++ = (unsigned char) (c)) : \ + __flshfp ((stream), (unsigned char) (c))) + +/* The C standard explicitly says this can be a macro, + so we always do the optimization for it. */ +#define putc(c, stream) __putc ((c), (stream)) + +#ifdef __OPTIMIZE__ +extern __inline int +putchar (int __c) +{ + return __putc (__c, stdout); +} +#endif + + +#if defined(__USE_SVID) || defined(__USE_MISC) +/* Get a word (int) from STREAM. */ +extern int getw __P ((FILE *__stream)); + +/* Write a word (int) to STREAM. */ +extern int putw __P ((int __w, FILE *__stream)); +#endif + + +/* Get a newline-terminated string of finite length from STREAM. */ +extern char *fgets __P ((char *__s, int __n, FILE *__stream)); + +/* Get a newline-terminated string from stdin, removing the newline. + DO NOT USE THIS FUNCTION!! There is no limit on how much it will read. */ +extern char *gets __P ((char *__s)); + + +#ifdef __USE_GNU +#include <sys/types.h> + +/* Read up to (and including) a DELIMITER from STREAM into *LINEPTR + (and null-terminate it). *LINEPTR is a pointer returned from malloc (or + NULL), pointing to *N characters of space. It is realloc'd as + necessary. Returns the number of characters read (not including the + null terminator), or -1 on error or EOF. */ +ssize_t __getdelim __P ((char **__lineptr, size_t *__n, + int __delimiter, FILE *__stream)); +ssize_t getdelim __P ((char **__lineptr, size_t *__n, + int __delimiter, FILE *__stream)); + +/* Like `getdelim', but reads up to a newline. */ +ssize_t __getline __P ((char **__lineptr, size_t *__n, FILE *__stream)); +ssize_t getline __P ((char **__lineptr, size_t *__n, FILE *__stream)); + +#ifdef __OPTIMIZE__ +extern __inline ssize_t +__getline (char **__lineptr, size_t *__n, FILE *__stream) +{ + return __getdelim (__lineptr, __n, '\n', __stream); +} + +extern __inline ssize_t +getdelim (char **__lineptr, size_t *__n, int __delimiter, FILE *__stream) +{ + return __getdelim (__lineptr, __n, __delimiter, __stream); +} +extern __inline ssize_t +getline (char **__lineptr, size_t *__n, FILE *__stream) +{ + return __getline (__lineptr, __n, __stream); +} +#endif /* Optimizing. */ +#endif + + +/* Write a string to STREAM. */ +extern int fputs __P ((__const char *__s, FILE *__stream)); +/* Write a string, followed by a newline, to stdout. */ +extern int puts __P ((__const char *__s)); + + +/* Push a character back onto the input buffer of STREAM. */ +extern int ungetc __P ((int __c, FILE *__stream)); + + +/* Read chunks of generic data from STREAM. */ +extern size_t fread __P ((__ptr_t __ptr, size_t __size, + size_t __n, FILE *__stream)); +/* Write chunks of generic data to STREAM. */ +extern size_t fwrite __P ((__const __ptr_t __ptr, size_t __size, + size_t __n, FILE *__s)); + + +/* Seek to a certain position on STREAM. */ +extern int fseek __P ((FILE *__stream, long int __off, int __whence)); +/* Return the current position of STREAM. */ +extern long int ftell __P ((FILE *__stream)); +/* Rewind to the beginning of STREAM. */ +extern void rewind __P ((FILE *__stream)); + +/* Get STREAM's position. */ +extern int fgetpos __P ((FILE *__stream, fpos_t *__pos)); +/* Set STREAM's position. */ +extern int fsetpos __P ((FILE *__stream, __const fpos_t *__pos)); + + +/* Clear the error and EOF indicators for STREAM. */ +extern void clearerr __P ((FILE *__stream)); +/* Return the EOF indicator for STREAM. */ +extern int feof __P ((FILE *__stream)); +/* Return the error indicator for STREAM. */ +extern int ferror __P ((FILE *__stream)); + +#ifdef __OPTIMIZE__ +#define feof(stream) ((stream)->__eof != 0) +#define ferror(stream) ((stream)->__error != 0) +#endif /* Optimizing. */ + + +/* Print a message describing the meaning of the value of errno. */ +extern void perror __P ((__const char *__s)); + +#ifdef __USE_BSD +extern int sys_nerr; +extern char *sys_errlist[]; +#endif +#ifdef __USE_GNU +extern int _sys_nerr; +extern char *_sys_errlist[]; +#endif + + +#ifdef __USE_POSIX +/* Return the system file descriptor for STREAM. */ +extern int fileno __P ((FILE *__stream)); +#endif /* Use POSIX. */ + + +#if (defined (__USE_POSIX2) || defined(__USE_SVID) || defined(__USE_BSD) || \ + defined(__USE_MISC)) +/* Create a new stream connected to a pipe running the given command. */ +extern FILE *popen __P ((__const char *__command, __const char *__modes)); + +/* Close a stream opened by popen and return the status of its child. */ +extern int pclose __P ((FILE *__stream)); +#endif + + +#ifdef __USE_POSIX +/* Return the name of the controlling terminal. */ +extern char *ctermid __P ((char *__s)); +/* Return the name of the current user. */ +extern char *cuserid __P ((char *__s)); +#endif + + +#ifdef __USE_GNU +struct obstack; /* See <obstack.h>. */ + +/* Open a stream that writes to OBSTACK. */ +extern FILE *open_obstack_stream __P ((struct obstack *__obstack)); + +/* Write formatted output to an obstack. */ +extern int obstack_printf __P ((struct obstack *__obstack, + __const char *__format, ...)); +extern int obstack_vprintf __P ((struct obstack *__obstack, + __const char *__format, + __gnuc_va_list __args)); +#endif + + +__END_DECLS + +#endif /* <stdio.h> included. */ + +#endif /* stdio.h */ diff --git a/stdio/tempnam.c b/stdio/tempnam.c new file mode 100644 index 0000000000..14988a8656 --- /dev/null +++ b/stdio/tempnam.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* Generate a unique temporary filename using up to five characters of PFX + if it is not NULL. The directory to put this file in is searched for + as follows: First the environment variable "TMPDIR" is checked. + If it contains the name of a writable directory, that directory is used. + If not and if DIR is not NULL, that value is checked. If that fails, + P_tmpdir is tried and finally "/tmp". The storage for the filename + is allocated by `malloc'. */ +char * +DEFUN(tempnam, (dir, pfx), CONST char *dir AND CONST char *pfx) +{ + size_t len; + register char *s; + register char *t = __stdio_gen_tempname(dir, pfx, 1, &len, (FILE **) NULL); + + if (t == NULL) + return NULL; + + s = (char *) malloc(len); + if (s == NULL) + return NULL; + + (void) memcpy(s, t, len); + return s; +} diff --git a/stdio/temptest.c b/stdio/temptest.c new file mode 100644 index 0000000000..374719896a --- /dev/null +++ b/stdio/temptest.c @@ -0,0 +1,31 @@ +#include <ansidecl.h> +#include <stdio.h> +#include <string.h> + +char *files[500]; + +int +main () +{ + char *fn; + FILE *fp; + int i; + + for (i = 0; i < 500; i++) { + fn = __stdio_gen_tempname((CONST char *) NULL, + "file", 0, (size_t *) NULL, (FILE **) NULL); + if (fn == NULL) { + printf ("__stdio_gen_tempname failed\n"); + exit (1); + } + files[i] = strdup (fn); + printf ("file: %s\n", fn); + fp = fopen (fn, "w"); + fclose (fp); + } + + for (i = 0; i < 500; i++) + remove (files[i]); + + exit (0); +} diff --git a/stdio/test-fseek.c b/stdio/test-fseek.c new file mode 100644 index 0000000000..398cac796f --- /dev/null +++ b/stdio/test-fseek.c @@ -0,0 +1,67 @@ +#include <ansidecl.h> +#include <stdio.h> + +#define TESTFILE "test.dat" + +int +main __P((void)) +{ + FILE *fp; + int i, j; + + puts ("\nFile seek test"); + fp = fopen (TESTFILE, "w"); + if (fp == NULL) + { + perror (TESTFILE); + return 1; + } + + for (i = 0; i < 256; i++) + putc (i, fp); + if (freopen (TESTFILE, "r", fp) != fp) + { + perror ("Cannot open file for reading"); + return 1; + } + + for (i = 1; i <= 255; i++) + { + printf ("%3d\n", i); + fseek (fp, (long) -i, SEEK_END); + if ((j = getc (fp)) != 256 - i) + { + printf ("SEEK_END failed %d\n", j); + break; + } + if (fseek (fp, (long) i, SEEK_SET)) + { + puts ("Cannot SEEK_SET"); + break; + } + if ((j = getc (fp)) != i) + { + printf ("SEEK_SET failed %d\n", j); + break; + } + if (fseek (fp, (long) i, SEEK_SET)) + { + puts ("Cannot SEEK_SET"); + break; + } + if (fseek (fp, (long) (i >= 128 ? -128 : 128), SEEK_CUR)) + { + puts ("Cannot SEEK_CUR"); + break; + } + if ((j = getc (fp)) != (i >= 128 ? i - 128 : i + 128)) + { + printf ("SEEK_CUR failed %d\n", j); + break; + } + } + fclose (fp); + + puts ((i > 255) ? "Test succeeded." : "Test FAILED!"); + return (i > 255) ? 0 : 1; +} diff --git a/stdio/test-fwrite.c b/stdio/test-fwrite.c new file mode 100644 index 0000000000..cc6cdf038e --- /dev/null +++ b/stdio/test-fwrite.c @@ -0,0 +1,68 @@ +#include <stdio.h> +#include <string.h> + +int +main () +{ + FILE *f = tmpfile (); + char obuf[99999], ibuf[sizeof obuf]; + char *line; + size_t linesz; + + if (! f) + { + perror ("tmpfile"); + return 1; + } + + if (fputs ("line\n", f) == EOF) + { + perror ("fputs"); + return 1; + } + + memset (obuf, 'z', sizeof obuf); + memset (ibuf, 'y', sizeof ibuf); + + if (fwrite (obuf, sizeof obuf, 1, f) != 1) + { + perror ("fwrite"); + return 1; + } + + rewind (f); + + line = NULL; + linesz = 0; + if (getline (&line, &linesz, f) != 5) + { + perror ("getline"); + return 1; + } + if (strcmp (line, "line\n")) + { + puts ("Lines differ. Test FAILED!"); + return 1; + } + + if (fread (ibuf, sizeof ibuf, 1, f) != 1) + { + perror ("fread"); + return 1; + } + + if (memcmp (ibuf, obuf, sizeof ibuf)) + { + puts ("Buffers differ. Test FAILED!"); + return 1; + } + + asprintf (&line, "\ +GDB is free software and you are welcome to distribute copies of it\n\ + under certain conditions; type \"show copying\" to see the conditions.\n\ +There is absolutely no warranty for GDB; type \"show warranty\" for details.\n\ +"); + + puts ("Test succeeded."); + return 0; +} diff --git a/stdio/test-popen.c b/stdio/test-popen.c new file mode 100644 index 0000000000..df6138b76f --- /dev/null +++ b/stdio/test-popen.c @@ -0,0 +1,67 @@ +#include <ansidecl.h> +#include <stdio.h> +#include <stdlib.h> + +void +DEFUN(write_data, (stream), FILE *stream) +{ + int i; + for (i=0; i<100; i++) + fprintf (stream, "%d\n", i); + if (ferror (stream)) { + fprintf (stderr, "Output to stream failed.\n"); + exit (1); + } +} + +void +DEFUN(read_data, (stream), FILE *stream) +{ + int i, j; + + for (i=0; i<100; i++) + { + if (fscanf (stream, "%d\n", &j) != 1 || j != i) + { + if (ferror (stream)) + perror ("fscanf"); + puts ("Test FAILED!"); + exit (1); + } + } +} + +int +DEFUN_VOID(main) +{ + FILE *output, *input; + int wstatus, rstatus; + + output = popen ("/bin/cat >tstpopen.tmp", "w"); + if (output == NULL) + { + perror ("popen"); + puts ("Test FAILED!"); + exit (1); + } + write_data (output); + wstatus = pclose (output); + printf ("writing pclose returned %d\n", wstatus); + input = popen ("/bin/cat tstpopen.tmp", "r"); + if (input == NULL) + { + perror ("tstpopen.tmp"); + puts ("Test FAILED!"); + exit (1); + } + read_data (input); + rstatus = pclose (input); + printf ("reading pclose returned %d\n", rstatus); + + puts (wstatus | rstatus ? "Test FAILED!" : "Test succeeded."); + exit (wstatus | rstatus); +} + + + + diff --git a/stdio/test_rdwr.c b/stdio/test_rdwr.c new file mode 100644 index 0000000000..8e0c1dfade --- /dev/null +++ b/stdio/test_rdwr.c @@ -0,0 +1,129 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +int +DEFUN(main, (argc, argv), int argc AND char **argv) +{ + static CONST char hello[] = "Hello, world.\n"; + static CONST char replace[] = "Hewwo, world.\n"; + static CONST size_t replace_from = 2, replace_to = 4; + char filename[FILENAME_MAX]; + char *name = strrchr(*argv, '/'); + char buf[BUFSIZ]; + FILE *f; + int lose = 0; + + if (name != NULL) + ++name; + else + name = *argv; + + (void) sprintf(filename, "/tmp/%s.test", name); + + f = fopen(filename, "w+"); + if (f == NULL) + { + perror(filename); + exit(1); + } + + (void) fputs(hello, f); + rewind(f); + (void) fgets(buf, sizeof(buf), f); + rewind(f); + (void) fputs(buf, f); + rewind(f); + { + register size_t i; + for (i = 0; i < replace_from; ++i) + { + int c = getc(f); + if (c == EOF) + { + printf("EOF at %u.\n", i); + lose = 1; + break; + } + else if (c != hello[i]) + { + printf("Got '%c' instead of '%c' at %u.\n", + (unsigned char) c, hello[i], i); + lose = 1; + break; + } + } + } + + { + long int where = ftell(f); + if (where == replace_from) + { + register size_t i; + for (i = replace_from; i < replace_to; ++i) + if (putc(replace[i], f) == EOF) + { + printf("putc('%c') got %s at %u.\n", + replace[i], strerror(errno), i); + lose = 1; + break; + } + } + else if (where == -1L) + { + printf("ftell got %s (should be at %u).\n", + strerror(errno), replace_from); + lose = 1; + } + else + { + printf("ftell returns %u; should be %u.\n", where, replace_from); + lose = 1; + } + } + + if (!lose) + { + rewind(f); + if (fgets(buf, sizeof(buf), f) == NULL) + { + printf("fgets got %s.\n", strerror(errno)); + lose = 1; + } + else if (strcmp(buf, replace)) + { + printf("Read \"%s\" instead of \"%s\".\n", buf, replace); + lose = 1; + } + } + + if (lose) + printf("Test FAILED! Losing file is \"%s\".\n", filename); + else + { + (void) remove(filename); + puts("Test succeeded."); + } + + exit(lose ? EXIT_FAILURE : EXIT_SUCCESS); +} diff --git a/stdio/tmpfile.c b/stdio/tmpfile.c new file mode 100644 index 0000000000..dfe11ada50 --- /dev/null +++ b/stdio/tmpfile.c @@ -0,0 +1,43 @@ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + + +/* This returns a new stream opened on a temporary file (generated + by tmpnam) The file is opened with mode "w+b" (binary read/write). + If we couldn't generate a unique filename or the file couldn't + be opened, NULL is returned. */ +FILE * +DEFUN_VOID(tmpfile) +{ + char *filename; + FILE *f; + + filename = __stdio_gen_tempname ((char *) NULL, "tmpf", 0, + (size_t *) NULL, &f); + if (filename == NULL) + return NULL; + + /* Note that this relies on the Unix semantics that + a file is not really removed until it is closed. */ + (void) remove (filename); + + return f; +} diff --git a/stdio/tmpnam.c b/stdio/tmpnam.c new file mode 100644 index 0000000000..88dd0a4ca5 --- /dev/null +++ b/stdio/tmpnam.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> + + +/* Generate a unique filename in P_tmpdir. */ +char * +DEFUN(tmpnam, (s), register char *s) +{ + register char *t = __stdio_gen_tempname((CONST char *) NULL, + (CONST char *) NULL, 0, + (size_t *) NULL, (FILE **) NULL); + + if (t == NULL) + return NULL; + + if (s != NULL) + (void) strcpy(s, t); + else + s = t; + + return s; +} diff --git a/stdio/tst-fileno.c b/stdio/tst-fileno.c new file mode 100644 index 0000000000..81945f7b44 --- /dev/null +++ b/stdio/tst-fileno.c @@ -0,0 +1,37 @@ +/* Copyright (C) 1994 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> +#include <unistd.h> + +static int +DEFUN(check, (name, stream, fd), CONST char *name AND FILE *stream AND int fd) +{ + int sfd = fileno (stream); + printf ("(fileno (%s) = %d) %c= %d\n", name, sfd, sfd == fd ? '=' : '!', fd); + return sfd != fd; +} + +int +DEFUN_VOID(main) +{ + exit (check ("stdin", stdin, STDIN_FILENO) || + check ("stdout", stdout, STDOUT_FILENO) || + check ("stderr", stderr, STDERR_FILENO)); +} diff --git a/stdio/tst-printf.c b/stdio/tst-printf.c new file mode 100644 index 0000000000..c177da18b2 --- /dev/null +++ b/stdio/tst-printf.c @@ -0,0 +1,298 @@ +/* Copyright (C) 1991, 1992, 1993, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#ifdef BSD +#include </usr/include/stdio.h> +#define EXIT_SUCCESS 0 +#else +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#endif + +#include <float.h> + + +void +DEFUN(fmtchk, (fmt), CONST char *fmt) +{ + (void) fputs(fmt, stdout); + (void) printf(":\t`"); + (void) printf(fmt, 0x12); + (void) printf("'\n"); +} + +void +DEFUN(fmtst1chk, (fmt), CONST char *fmt) +{ + (void) fputs(fmt, stdout); + (void) printf(":\t`"); + (void) printf(fmt, 4, 0x12); + (void) printf("'\n"); +} + +void +DEFUN(fmtst2chk, (fmt), CONST char *fmt) +{ + (void) fputs(fmt, stdout); + (void) printf(":\t`"); + (void) printf(fmt, 4, 4, 0x12); + (void) printf("'\n"); +} + +/* This page is covered by the following copyright: */ + +/* (C) Copyright C E Chew + * + * Feel free to copy, use and distribute this software provided: + * + * 1. you do not pretend that you wrote it + * 2. you leave this copyright notice intact. + */ + +/* + * Extracted from exercise.c for glibc-1.05 bug report by Bruce Evans. + */ + +#define DEC -123 +#define INT 255 +#define UNS (~0) + +/* Formatted Output Test + * + * This exercises the output formatting code. + */ + +void +DEFUN_VOID(fp_test) +{ + int i, j, k, l; + char buf[7]; + char *prefix = buf; + char tp[20]; + + puts("\nFormatted output test"); + printf("prefix 6d 6o 6x 6X 6u\n"); + strcpy(prefix, "%"); + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 2; k++) { + for (l = 0; l < 2; l++) { + strcpy(prefix, "%"); + if (i == 0) strcat(prefix, "-"); + if (j == 0) strcat(prefix, "+"); + if (k == 0) strcat(prefix, "#"); + if (l == 0) strcat(prefix, "0"); + printf("%5s |", prefix); + strcpy(tp, prefix); + strcat(tp, "6d |"); + printf(tp, DEC); + strcpy(tp, prefix); + strcat(tp, "6o |"); + printf(tp, INT); + strcpy(tp, prefix); + strcat(tp, "6x |"); + printf(tp, INT); + strcpy(tp, prefix); + strcat(tp, "6X |"); + printf(tp, INT); + strcpy(tp, prefix); + strcat(tp, "6u |"); + printf(tp, UNS); + printf("\n"); + } + } + } + } + printf("%10s\n", (char *) NULL); + printf("%-10s\n", (char *) NULL); +} + +int +DEFUN_VOID(main) +{ + static char shortstr[] = "Hi, Z."; + static char longstr[] = "Good morning, Doctor Chandra. This is Hal. \ +I am ready for my first lesson today."; + + fmtchk("%.4x"); + fmtchk("%04x"); + fmtchk("%4.4x"); + fmtchk("%04.4x"); + fmtchk("%4.3x"); + fmtchk("%04.3x"); + + fmtst1chk("%.*x"); + fmtst1chk("%0*x"); + fmtst2chk("%*.*x"); + fmtst2chk("%0*.*x"); + +#ifndef BSD + printf("bad format:\t\"%z\"\n"); + printf("nil pointer (padded):\t\"%10p\"\n", (PTR) NULL); +#endif + + printf("decimal negative:\t\"%d\"\n", -2345); + printf("octal negative:\t\"%o\"\n", -2345); + printf("hex negative:\t\"%x\"\n", -2345); + printf("long decimal number:\t\"%ld\"\n", -123456L); + printf("long octal negative:\t\"%lo\"\n", -2345L); + printf("long unsigned decimal number:\t\"%lu\"\n", -123456L); + printf("zero-padded LDN:\t\"%010ld\"\n", -123456L); + printf("left-adjusted ZLDN:\t\"%-010ld\"\n", -123456); + printf("space-padded LDN:\t\"%10ld\"\n", -123456L); + printf("left-adjusted SLDN:\t\"%-10ld\"\n", -123456L); + + printf("zero-padded string:\t\"%010s\"\n", shortstr); + printf("left-adjusted Z string:\t\"%-010s\"\n", shortstr); + printf("space-padded string:\t\"%10s\"\n", shortstr); + printf("left-adjusted S string:\t\"%-10s\"\n", shortstr); + printf("null string:\t\"%s\"\n", (char *)NULL); + printf("limited string:\t\"%.22s\"\n", longstr); + + printf("e-style >= 1:\t\"%e\"\n", 12.34); + printf("e-style >= .1:\t\"%e\"\n", 0.1234); + printf("e-style < .1:\t\"%e\"\n", 0.001234); + printf("e-style big:\t\"%.60e\"\n", 1e20); + printf ("e-style == .1:\t\"%e\"\n", 0.1); + printf("f-style >= 1:\t\"%f\"\n", 12.34); + printf("f-style >= .1:\t\"%f\"\n", 0.1234); + printf("f-style < .1:\t\"%f\"\n", 0.001234); + printf("g-style >= 1:\t\"%g\"\n", 12.34); + printf("g-style >= .1:\t\"%g\"\n", 0.1234); + printf("g-style < .1:\t\"%g\"\n", 0.001234); + printf("g-style big:\t\"%.60g\"\n", 1e20); + + printf (" %6.5f\n", .099999999860301614); + printf (" %6.5f\n", .1); + printf ("x%5.4fx\n", .5); + + printf ("%#03x\n", 1); + + { + double d = FLT_MIN; + int niter = 17; + + while (niter-- != 0) + printf ("%.17e\n", d / 2); + fflush (stdout); + } + + printf ("%15.5e\n", 4.9406564584124654e-324); + +#define FORMAT "|%12.4f|%12.4e|%12.4g|\n" + printf (FORMAT, 0.0, 0.0, 0.0); + printf (FORMAT, 1.0, 1.0, 1.0); + printf (FORMAT, -1.0, -1.0, -1.0); + printf (FORMAT, 100.0, 100.0, 100.0); + printf (FORMAT, 1000.0, 1000.0, 1000.0); + printf (FORMAT, 10000.0, 10000.0, 10000.0); + printf (FORMAT, 12345.0, 12345.0, 12345.0); + printf (FORMAT, 100000.0, 100000.0, 100000.0); + printf (FORMAT, 123456.0, 123456.0, 123456.0); +#undef FORMAT + + { + char buf[20]; + printf ("snprintf (\"%%30s\", \"foo\") == %d, \"%.*s\"\n", + snprintf (buf, sizeof (buf), "%30s", "foo"), sizeof (buf), buf); + } + + fp_test (); + + printf ("%e should be 1.234568e+06\n", 1234567.8); + printf ("%f should be 1234567.800000\n", 1234567.8); + printf ("%g should be 1.23457e+06\n", 1234567.8); + printf ("%g should be 123.456\n", 123.456); + printf ("%g should be 1e+06\n", 1000000.0); + printf ("%g should be 10\n", 10.0); + printf ("%g should be 0.02\n", 0.02); + + { + double x=1.0; + printf("%.17f\n",(1.0/x/10.0+1.0)*x-x); + } + + puts ("--- Should be no further output. ---"); + rfg1 (); + rfg2 (); + + exit(EXIT_SUCCESS); +} + +rfg1 () +{ + char buf[100]; + + sprintf (buf, "%5.s", "xyz"); + if (strcmp (buf, " ") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " "); + sprintf (buf, "%5.f", 33.3); + if (strcmp (buf, " 33") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 33"); + sprintf (buf, "%8.e", 33.3e7); + if (strcmp (buf, " 3e+08") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3e+08"); + sprintf (buf, "%8.E", 33.3e7); + if (strcmp (buf, " 3E+08") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3E+08"); + sprintf (buf, "%.g", 33.3); + if (strcmp (buf, "3e+01") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3e+01"); + sprintf (buf, "%.G", 33.3); + if (strcmp (buf, "3E+01") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3E+01"); + return 0; +} + +rfg2 () +{ + int prec; + char buf[100]; + + prec = 0; + sprintf (buf, "%.*g", prec, 3.3); + if (strcmp (buf, "3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3"); + prec = 0; + sprintf (buf, "%.*G", prec, 3.3); + if (strcmp (buf, "3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, "3"); + prec = 0; + sprintf (buf, "%7.*G", prec, 3.33); + if (strcmp (buf, " 3") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 3"); + prec = 3; + sprintf (buf, "%04.*o", prec, 33); + if (strcmp (buf, " 041") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 041"); + prec = 7; + sprintf (buf, "%09.*u", prec, 33); + if (strcmp (buf, " 0000033") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 0000033"); + prec = 3; + sprintf (buf, "%04.*x", prec, 33); + if (strcmp (buf, " 021") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 021"); + prec = 3; + sprintf (buf, "%04.*X", prec, 33); + if (strcmp (buf, " 021") != 0) + printf ("got: '%s', expected: '%s'\n", buf, " 021"); + return 0; +} diff --git a/stdio/tstgetln.c b/stdio/tstgetln.c new file mode 100644 index 0000000000..ea8ea817da --- /dev/null +++ b/stdio/tstgetln.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdio.h> + +int +DEFUN_VOID(main) +{ + char *buf = NULL; + size_t size = 0; + ssize_t len; + + while ((len = getline (&buf, &size, stdin)) != -1) + { + printf ("bufsize %u; read %d: ", size, len); + if (fwrite (buf, len, 1, stdout) != 1) + { + perror ("fwrite"); + return 1; + } + } + + if (ferror (stdin)) + { + perror ("getline"); + return 1; + } + + return 0; +} diff --git a/stdio/tstgetln.input b/stdio/tstgetln.input new file mode 100644 index 0000000000..d04ed5bf78 --- /dev/null +++ b/stdio/tstgetln.input @@ -0,0 +1,3 @@ +xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy +z diff --git a/stdio/tstscanf.c b/stdio/tstscanf.c new file mode 100644 index 0000000000..53d4b0ac47 --- /dev/null +++ b/stdio/tstscanf.c @@ -0,0 +1,100 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#ifdef BSD +#include </usr/include/stdio.h> +#else +#include <stdio.h> +#endif +#include <stdlib.h> +#include <string.h> + + +int +DEFUN(main, (argc, argv), int argc AND char **argv) +{ + char buf[BUFSIZ]; + FILE *in = stdin, *out = stdout; + + if (argc == 2 && !strcmp (argv[1], "-opipe")) + { + out = popen ("/bin/cat", "w"); + if (out == NULL) + { + perror ("popen: /bin/cat"); + exit (EXIT_FAILURE); + } + } + else if (argc == 3 && !strcmp (argv[1], "-ipipe")) + { + sprintf (buf, "/bin/cat %s", argv[2]); + in = popen (buf, "r"); + } + + { + char name[50]; + fprintf (out, + "sscanf (\"thompson\", \"%%s\", name) == %d, name == \"%s\"\n", + sscanf ("thompson", "%s", name), + name); + } + + fputs ("Testing scanf (vfscanf)\n", out); + + fputs ("Test 1:\n", out); + { + int n, i; + float x; + char name[50]; + n = fscanf (in, "%d%f%s", &i, &x, name); + fprintf (out, "n = %d, i = %d, x = %f, name = \"%.50s\"\n", + n, i, x, name); + } + fprintf (out, "Residual: \"%s\"\n", fgets (buf, sizeof (buf), in)); + fputs ("Test 2:\n", out); + { + int i; + float x; + char name[50]; + (void) fscanf (in, "%2d%f%*d %[0123456789]", &i, &x, name); + fprintf (out, "i = %d, x = %f, name = \"%.50s\"\n", i, x, name); + } + fprintf (out, "Residual: \"%s\"\n", fgets (buf, sizeof (buf), in)); + fputs ("Test 3:\n", out); + { + float quant; + char units[21], item[21]; + while (!feof (in) && !ferror (in)) + { + int count; + quant = 0.0; + units[0] = item[0] = '\0'; + count = fscanf (in, "%f%20s of %20s", &quant, units, item); + (void) fscanf (in, "%*[^\n]"); + fprintf (out, "count = %d, quant = %f, item = %.21s, units = %.21s\n", + count, quant, item, units); + } + } + fprintf (out, "Residual: \"%s\"\n", fgets (buf, sizeof (buf), in)); + + if (out != stdout) + pclose (out); + + exit(EXIT_SUCCESS); +} diff --git a/stdio/tstscanf.input b/stdio/tstscanf.input new file mode 100644 index 0000000000..26158652dd --- /dev/null +++ b/stdio/tstscanf.input @@ -0,0 +1,7 @@ +25 54.32E-1 thompson +56789 0123 56a72 +2 quarts of oil +-12.8degrees Celsius +lots of luck +10.0LBS of fertilizer +100ergs of energy diff --git a/stdio/ungetc.c b/stdio/ungetc.c new file mode 100644 index 0000000000..7b22a200f6 --- /dev/null +++ b/stdio/ungetc.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdio.h> + + +/* Push the character C back onto the input stream of STREAM. */ +int +DEFUN(ungetc, (c, stream), register int c AND register FILE *stream) +{ + if (!__validfp(stream) || !stream->__mode.__read) + { + errno = EINVAL; + return EOF; + } + + if (c == EOF) + return EOF; + + if (stream->__pushed_back) + /* There is already a char pushed back. */ + return EOF; + + if ((stream->__linebuf_active || stream->__put_limit > stream->__buffer) && + /* This is a read-write stream with something in its buffer. + Flush the stream. */ + __flshfp (stream, EOF) == EOF) + return EOF; + + stream->__pushback = (unsigned char) c; + /* Tell __fillbf we've pushed back a char. */ + stream->__pushed_back = 1; + stream->__pushback_bufp = stream->__bufp; + /* Make the next getc call __fillbf. It will return C. */ + stream->__bufp = stream->__get_limit; + + /* We just gave it another character to read, so it's not at EOF. */ + stream->__eof = 0; + + return stream->__pushback; +} diff --git a/stdio/vasprintf.c b/stdio/vasprintf.c new file mode 100644 index 0000000000..d2ad6b1da6 --- /dev/null +++ b/stdio/vasprintf.c @@ -0,0 +1,86 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stddef.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + + +/* Enlarge STREAM's buffer. */ +static void +DEFUN(enlarge_buffer, (stream, c), + register FILE *stream AND int c) +{ + ptrdiff_t bufp_offset = stream->__bufp - stream->__buffer; + char *newbuf; + + stream->__bufsize += 100; + newbuf = (char *) realloc ((PTR) stream->__buffer, stream->__bufsize); + if (newbuf == NULL) + { + free ((PTR) stream->__buffer); + stream->__buffer = stream->__bufp + = stream->__put_limit = stream->__get_limit = NULL; + stream->__error = 1; + } + else + { + stream->__buffer = newbuf; + stream->__bufp = stream->__buffer + bufp_offset; + stream->__get_limit = stream->__put_limit; + stream->__put_limit = stream->__buffer + stream->__bufsize; + if (c != EOF) + *stream->__bufp++ = (unsigned char) c; + } +} + +/* Write formatted output from FORMAT to a string which is + allocated with malloc and stored in *STRING_PTR. */ +int +DEFUN(vasprintf, (string_ptr, format, args), + char **string_ptr AND CONST char *format AND va_list args) +{ + FILE f; + int done; + + memset ((PTR) &f, 0, sizeof (f)); + f.__magic = _IOMAGIC; + f.__bufsize = 100; + f.__buffer = (char *) malloc (f.__bufsize); + if (f.__buffer == NULL) + return -1; + f.__bufp = f.__buffer; + f.__put_limit = f.__buffer + f.__bufsize; + f.__mode.__write = 1; + f.__room_funcs.__output = enlarge_buffer; + f.__seen = 1; + + done = vfprintf (&f, format, args); + if (done < 0) + return done; + + *string_ptr = realloc (f.__buffer, (f.__bufp - f.__buffer) + 1); + if (*string_ptr == NULL) + *string_ptr = f.__buffer; + (*string_ptr)[f.__bufp - f.__buffer] = '\0'; + return done; +} diff --git a/stdio/vdprintf.c b/stdio/vdprintf.c new file mode 100644 index 0000000000..9df4e537bc --- /dev/null +++ b/stdio/vdprintf.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + + +/* Write formatted output to file descriptor D according to the format string + FORMAT, using the argument list in ARG. */ +int +DEFUN(vdprintf, (d, format, arg), + int d AND CONST char *format AND va_list arg) +{ + int done; + FILE f; + + /* Create an unbuffered stream talking to D on the stack. */ + memset ((PTR) &f, 0, sizeof(f)); + f.__magic = _IOMAGIC; + f.__mode.__write = 1; + f.__cookie = (PTR) (long int) d; /* Casting to long quiets GCC on Alpha. */ + f.__room_funcs = __default_room_functions; + f.__io_funcs = __default_io_functions; + f.__seen = 1; + f.__userbuf = 1; + + /* vfprintf will use a buffer on the stack for the life of the call, + and flush it when finished. */ + done = vfprintf (&f, format, arg); + + return done; +} diff --git a/stdio/vfprintf.c b/stdio/vfprintf.c new file mode 100644 index 0000000000..c480a93ab9 --- /dev/null +++ b/stdio/vfprintf.c @@ -0,0 +1,907 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <localeinfo.h> +#include <ctype.h> +#include <errno.h> +#include <float.h> +#include <limits.h> +#include <math.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <printf.h> +#include <assert.h> +#include <stddef.h> +#include "_itoa.h" + +/* This function from the GNU C library is also used in libio. + To compile for use in libio, compile with -DUSE_IN_LIBIO. */ + +#ifdef USE_IN_LIBIO +/* This code is for use in libio. */ +#include <libioP.h> +#define PUT(f, s, n) _IO_sputn (f, s, n) +#define PAD(padchar) _IO_padn (s, padchar, width) +#define PUTC(c, f) _IO_putc(c, f) +#define vfprintf _IO_vfprintf +#define size_t _IO_size_t +#define FILE _IO_FILE +#define va_list _IO_va_list +#undef BUFSIZ +#define BUFSIZ _IO_BUFSIZ +#define ARGCHECK(s, format) \ + do \ + { \ + /* Check file argument for consistence. */ \ + CHECK_FILE(s, -1); \ + if (s->_flags & _IO_NO_WRITES || format == NULL) \ + { \ + MAYBE_SET_EINVAL; \ + return -1; \ + } \ + } while (0) +#define UNBUFFERED_P(s) ((s)->_IO_file_flags & _IO_UNBUFFERED) +#else /* ! USE_IN_LIBIO */ +/* This code is for use in the GNU C library. */ +#include <stdio.h> +#define PUTC(c, f) putc (c, f) +#define PUT(f, s, n) fwrite (s, 1, n, f) +ssize_t __printf_pad __P ((FILE *, char pad, int n)); +#define PAD(padchar) __printf_pad (s, padchar, width) +#define ARGCHECK(s, format) \ + do \ + { \ + /* Check file argument for consistence. */ \ + if (!__validfp(s) || !s->__mode.__write || format == NULL) \ + { \ + errno = EINVAL; \ + return -1; \ + } \ + if (!s->__seen) \ + { \ + if (__flshfp (s, EOF) == EOF) \ + return -1; \ + } \ + } while (0) +#define UNBUFFERED_P(s) ((s)->__buffer == NULL) +#endif /* USE_IN_LIBIO */ + + +#define outchar(x) \ + do \ + { \ + register CONST int outc = (x); \ + if (putc(outc, s) == EOF) \ + return -1; \ + else \ + ++done; \ + } while (0) + +/* Advances STRING after writing LEN chars of it. */ +#define outstring(string, len) \ + do \ + { \ + if (len > 20) \ + { \ + if (PUT (s, string, len) != len) \ + return -1; \ + done += len; \ + string += len; \ + } \ + else \ + while (len-- > 0) \ + outchar (*string++); \ + } while (0) + +/* Helper function to provide temporary buffering for unbuffered streams. */ +static int buffered_vfprintf __P ((FILE *stream, const char *fmt, va_list)); + +/* Cast the next arg, of type ARGTYPE, into CASTTYPE, and put it in VAR. */ +#define castarg(var, argtype, casttype) \ + var = (casttype) va_arg(args, argtype) +/* Get the next arg, of type TYPE, and put it in VAR. */ +#define nextarg(var, type) castarg(var, type, type) + +static printf_function printf_unknown; + +extern printf_function **__printf_function_table; + +#ifdef __GNUC__ +#define HAVE_LONGLONG +#define LONGLONG long long +#else +#define LONGLONG long +#endif + +static char *group_number __P ((char *, char *, const char *, wchar_t)); + +int +DEFUN(vfprintf, (s, format, args), + register FILE *s AND CONST char *format AND va_list args) +{ + /* The character used as thousands separator. */ + wchar_t thousands_sep; + + /* The string describing the size of groups of digits. */ + const char *grouping; + + /* Pointer into the format string. */ + register CONST char *f; + + /* Number of characters written. */ + register size_t done = 0; + + ARGCHECK (s, format); + + if (UNBUFFERED_P (s)) + /* Use a helper function which will allocate a local temporary buffer + for the stream and then call us again. */ + return buffered_vfprintf (s, format, args); + + /* Reset multibyte characters to their initial state. */ + (void) mblen ((char *) NULL, 0); + + /* Figure out the thousands seperator character. */ + if (mbtowc (&thousands_sep, _numeric_info->thousands_sep, + strlen (_numeric_info->thousands_sep)) <= 0) + thousands_sep = (wchar_t) *_numeric_info->thousands_sep; + grouping = _numeric_info->grouping; /* Cache the grouping info array. */ + if (*grouping == '\0' || thousands_sep == L'\0') + grouping = NULL; + + f = format; + while (*f != '\0') + { + /* Type modifiers. */ + char is_short, is_long, is_long_double; +#ifdef HAVE_LONGLONG + /* We use the `L' modifier for `long long int'. */ +#define is_longlong is_long_double +#else +#define is_longlong 0 +#endif + /* Format spec modifiers. */ + char space, showsign, left, alt, group; + + /* Padding character: ' ' or '0'. */ + char pad; + /* Width of a field. */ + register int width; + /* Precision of a field. */ + int prec; + + /* Decimal integer is negative. */ + char is_neg; + + /* Current character of the format. */ + char fc; + + /* Base of a number to be written. */ + int base; + /* Integral values to be written. */ + unsigned LONGLONG int num; + LONGLONG int signed_num; + + /* String to be written. */ + CONST char *str; + char errorbuf[1024]; /* Buffer sometimes used by %m. */ + + /* Auxiliary function to do output. */ + printf_function *function; + + if (!isascii(*f)) + { + /* Non-ASCII, may be a multibyte. */ + int len = mblen (f, strlen (f)); + if (len > 0) + { + outstring (f, len); + continue; + } + } + + if (*f != '%') + { + /* This isn't a format spec, so write everything out until the + next one. To properly handle multibyte characters, we cannot + just search for a '%'. Since multibyte characters are hairy + (and dealt with above), if we hit any byte above 127 (only + those can start a multibyte character) we just punt back to + that code. */ + do + outchar (*f++); + while (*f != '\0' && *f != '%' && isascii (*f)); + continue; + } + + ++f; + + /* Check for "%%". Note that although the ANSI standard lists + '%' as a conversion specifier, it says "The complete format + specification shall be `%%'," so we can avoid all the width + and precision processing. */ + if (*f == '%') + { + ++f; + outchar('%'); + continue; + } + + /* Check for spec modifiers. */ + space = showsign = left = alt = group = 0; + pad = ' '; + while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0' || + *f == '\'') + switch (*f++) + { + case ' ': + /* Output a space in place of a sign, when there is no sign. */ + space = 1; + break; + case '+': + /* Always output + or - for numbers. */ + showsign = 1; + break; + case '-': + /* Left-justify things. */ + left = 1; + break; + case '#': + /* Use the "alternate form": + Hex has 0x or 0X, FP always has a decimal point. */ + alt = 1; + break; + case '0': + /* Pad with 0s. */ + pad = '0'; + break; + case '\'': + /* Show grouping in numbers if the locale information + indicates any. */ + group = 1; + break; + } + if (left) + pad = ' '; + + /* Get the field width. */ + width = 0; + if (*f == '*') + { + /* The field width is given in an argument. + A negative field width indicates left justification. */ + nextarg(width, int); + if (width < 0) + { + width = - width; + left = 1; + } + ++f; + } + else + while (isdigit (*f)) + { + width *= 10; + width += *f++ - '0'; + } + + /* Get the precision. */ + /* -1 means none given; 0 means explicit 0. */ + prec = -1; + if (*f == '.') + { + ++f; + if (*f == '*') + { + /* The precision is given in an argument. */ + nextarg(prec, int); + /* Avoid idiocy. */ + if (prec < 0) + prec = -1; + ++f; + } + else if (isdigit (*f)) + { + prec = *f++ - '0'; + while (*f != '\0' && isdigit (*f)) + { + prec *= 10; + prec += *f++ - '0'; + } + } + else + /* "%.?" is treated like "%.0?". */ + prec = 0; + } + + /* If there was a precision specified, ignore the 0 flag and always + pad with spaces. */ + if (prec != -1) + pad = ' '; + + /* Check for type modifiers. */ + is_short = is_long = is_long_double = 0; + while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'q') + switch (*f++) + { + case 'h': + /* int's are short int's. */ + is_short = 1; + break; + case 'l': +#ifdef HAVE_LONGLONG + if (is_long) + /* A double `l' is equivalent to an `L'. */ + is_longlong = 1; + else +#endif + /* int's are long int's. */ + is_long = 1; + break; + case 'L': + /* double's are long double's, and int's are long long int's. */ + is_long_double = 1; + break; + + case 'Z': + /* int's are size_t's. */ +#ifdef HAVE_LONGLONG + assert (sizeof(size_t) <= sizeof(unsigned long long int)); + is_longlong = sizeof(size_t) > sizeof(unsigned long int); +#endif + is_long = sizeof(size_t) > sizeof(unsigned int); + break; + + case 'q': + /* 4.4 uses this for long long. */ +#ifdef HAVE_LONGLONG + is_longlong = 1; +#else + is_long = 1; +#endif + break; + } + + /* Format specification. */ + fc = *f++; + function = (__printf_function_table == NULL ? NULL : + __printf_function_table[fc]); + if (function == NULL) + switch (fc) + { + case 'i': + case 'd': + /* Decimal integer. */ + base = 10; + if (is_longlong) + nextarg(signed_num, LONGLONG int); + else if (is_long) + nextarg(signed_num, long int); + else if (!is_short) + castarg(signed_num, int, long int); + else + castarg(signed_num, int, short int); + + is_neg = signed_num < 0; + num = is_neg ? (- signed_num) : signed_num; + goto number; + + case 'u': + /* Decimal unsigned integer. */ + base = 10; + goto unsigned_number; + + case 'o': + /* Octal unsigned integer. */ + base = 8; + goto unsigned_number; + + case 'X': + /* Hexadecimal unsigned integer. */ + case 'x': + /* Hex with lower-case digits. */ + + base = 16; + + unsigned_number: + /* Unsigned number of base BASE. */ + + if (is_longlong) + castarg(num, LONGLONG int, unsigned LONGLONG int); + else if (is_long) + castarg(num, long int, unsigned long int); + else if (!is_short) + castarg(num, int, unsigned int); + else + castarg(num, int, unsigned short int); + + /* ANSI only specifies the `+' and + ` ' flags for signed conversions. */ + is_neg = showsign = space = 0; + + number: + /* Number of base BASE. */ + { + char work[BUFSIZ]; + char *CONST workend = &work[sizeof(work) - 1]; + register char *w; + + /* Supply a default precision if none was given. */ + if (prec == -1) + prec = 1; + + /* Put the number in WORK. */ + w = _itoa (num, workend + 1, base, fc == 'X') - 1; + if (group && grouping) + w = group_number (w, workend, grouping, thousands_sep); + width -= workend - w; + prec -= workend - w; + + if (alt && base == 8 && prec <= 0) + { + *w-- = '0'; + --width; + } + + if (prec > 0) + { + width -= prec; + while (prec-- > 0) + *w-- = '0'; + } + + if (alt && base == 16) + width -= 2; + + if (is_neg || showsign || space) + --width; + + if (!left && pad == ' ') + PAD (' '); + + if (is_neg) + outchar('-'); + else if (showsign) + outchar('+'); + else if (space) + outchar(' '); + + if (alt && base == 16) + { + outchar ('0'); + outchar (fc); + } + + if (!left && pad == '0') + PAD ('0'); + + /* Write the number. */ + while (++w <= workend) + outchar(*w); + + if (left) + PAD (' '); + } + break; + + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + { + /* Floating-point number. */ + extern printf_function __printf_fp; + function = __printf_fp; + goto use_function; + } + + case 'c': + /* Character. */ + nextarg(num, int); + if (!left) + { + --width; + PAD (' '); + } + outchar ((unsigned char) num); + if (left) + PAD (' '); + break; + + case 's': + { + static CONST char null[] = "(null)"; + size_t len; + + nextarg(str, CONST char *); + + string: + + if (str == NULL) + /* Write "(null)" if there's space. */ + if (prec == -1 || prec >= (int) sizeof(null) - 1) + { + str = null; + len = sizeof(null) - 1; + } + else + { + str = ""; + len = 0; + } + else + len = strlen(str); + + if (prec != -1 && (size_t) prec < len) + len = prec; + width -= len; + + if (!left) + PAD (' '); + outstring (str, len); + if (left) + PAD (' '); + } + break; + + case 'p': + /* Generic pointer. */ + { + CONST PTR ptr; + nextarg(ptr, CONST PTR); + if (ptr != NULL) + { + /* If the pointer is not NULL, write it as a %#x spec. */ + base = 16; + fc = 'x'; + alt = 1; + num = (unsigned LONGLONG int) (unsigned long int) ptr; + is_neg = 0; + group = 0; + goto number; + } + else + { + /* Write "(nil)" for a nil pointer. */ + static CONST char nil[] = "(nil)"; + register CONST char *p; + + width -= sizeof (nil) - 1; + if (!left) + PAD (' '); + for (p = nil; *p != '\0'; ++p) + outchar (*p); + if (left) + PAD (' '); + } + } + break; + + case 'n': + /* Answer the count of characters written. */ + if (is_longlong) + { + LONGLONG int *p; + nextarg(p, LONGLONG int *); + *p = done; + } + else if (is_long) + { + long int *p; + nextarg(p, long int *); + *p = done; + } + else if (!is_short) + { + int *p; + nextarg(p, int *); + *p = done; + } + else + { + short int *p; + nextarg(p, short int *); + *p = done; + } + break; + + case 'm': + { + extern char *_strerror_internal __P ((int, char buf[1024])); + str = _strerror_internal (errno, errorbuf); + goto string; + } + + default: + /* Unrecognized format specifier. */ + function = printf_unknown; + goto use_function; + } + else + use_function: + { + int function_done; + struct printf_info info; + + info.prec = prec; + info.width = width; + info.spec = fc; + info.is_long_double = is_long_double; + info.is_short = is_short; + info.is_long = is_long; + info.alt = alt; + info.space = space; + info.left = left; + info.showsign = showsign; + info.group = group; + info.pad = pad; + + function_done = (*function) (s, &info, &args); + if (function_done < 0) + return -1; + + done += function_done; + } + } + + return done; +} + + +static int +DEFUN(printf_unknown, (s, info, arg), + FILE *s AND CONST struct printf_info *info AND va_list *arg) +{ + int done = 0; + char work[BUFSIZ]; + char *CONST workend = &work[sizeof(work) - 1]; + register char *w; + register int prec = info->prec, width = info->width; + + outchar('%'); + + if (info->alt) + outchar ('#'); + if (info->group) + outchar ('\''); + if (info->showsign) + outchar ('+'); + else if (info->space) + outchar (' '); + if (info->left) + outchar ('-'); + if (info->pad == '0') + outchar ('0'); + + w = workend; + while (width > 0) + { + *w-- = '0' + (width % 10); + width /= 10; + } + while (++w <= workend) + outchar(*w); + + if (info->prec != -1) + { + outchar('.'); + w = workend; + while (prec > 0) + { + *w-- = '0' + (prec % 10); + prec /= 10; + } + while (++w <= workend) + outchar(*w); + } + + outchar(info->spec); + + return done; +} + +/* Group the digits according to the grouping rules of the current locale. + The interpretation of GROUPING is as in `struct lconv' from <locale.h>. */ + +static char * +group_number (char *w, char *workend, const char *grouping, + wchar_t thousands_sep) +{ + int len; + char *src, *s; + + /* We treat all negative values like CHAR_MAX. */ + + if (*grouping == CHAR_MAX || *grouping < 0) + /* No grouping should be done. */ + return w; + + len = *grouping; + + /* Copy existing string so that nothing gets overwritten. */ + src = (char *) alloca (workend - w); + memcpy (src, w + 1, workend - w); + s = &src[workend - w - 1]; + w = workend; + + /* Process all characters in the string. */ + while (s >= src) + { + *w-- = *s--; + + if (--len == 0 && s >= src) + { + /* A new group begins. */ + *w-- = thousands_sep; + + len = *grouping++; + if (*grouping == '\0') + /* The previous grouping repeats ad infinitum. */ + --grouping; + else if (*grouping == CHAR_MAX || *grouping < 0) + { + /* No further grouping to be done. + Copy the rest of the number. */ + do + *w-- = *s--; + while (s >= src); + break; + } + } + } + + return w; +} + +#ifdef USE_IN_LIBIO +/* Helper "class" for `fprintf to unbuffered': creates a temporary buffer. */ +struct helper_file + { + struct _IO_FILE_plus _f; + _IO_FILE *_put_stream; + }; + +static int +DEFUN(_IO_helper_overflow, (s, c), _IO_FILE *s AND int c) +{ + _IO_FILE *target = ((struct helper_file*) s)->_put_stream; + int used = s->_IO_write_ptr - s->_IO_write_base; + if (used) + { + _IO_size_t written = _IO_sputn (target, s->_IO_write_base, used); + s->_IO_write_ptr -= written; + } + return _IO_putc (c, s); +} + +static const struct _IO_jump_t _IO_helper_jumps = + { + _IO_helper_overflow, + _IO_default_underflow, + _IO_default_xsputn, + _IO_default_xsgetn, + _IO_default_read, + _IO_default_write, + _IO_default_doallocate, + _IO_default_pbackfail, + _IO_default_setbuf, + _IO_default_sync, + _IO_default_finish, + _IO_default_close, + _IO_default_stat, + _IO_default_seek, + _IO_default_seekoff, + _IO_default_seekpos, + _IO_default_uflow + }; + +static int +DEFUN(buffered_vfprintf, (s, format, args), + register _IO_FILE *s AND char CONST *format AND _IO_va_list args) +{ + char buf[_IO_BUFSIZ]; + struct helper_file helper; + register _IO_FILE *hp = (_IO_FILE *) &helper; + int result, to_flush; + + /* Initialize helper. */ + helper._put_stream = s; + hp->_IO_write_base = buf; + hp->_IO_write_ptr = buf; + hp->_IO_write_end = buf + sizeof buf; + hp->_IO_file_flags = _IO_MAGIC|_IO_NO_READS; + hp->_jumps = (struct _IO_jump_t *) &_IO_helper_jumps; + + /* Now print to helper instead. */ + result = _IO_vfprintf (hp, format, args); + + /* Now flush anything from the helper to the S. */ + if ((to_flush = hp->_IO_write_ptr - hp->_IO_write_base) > 0) + { + if (_IO_sputn (s, hp->_IO_write_base, to_flush) != to_flush) + return -1; + } + + return result; +} + +#else /* !USE_IN_LIBIO */ + +static int +DEFUN(buffered_vfprintf, (s, format, args), + register FILE *s AND char CONST *format AND va_list args) +{ + char buf[BUFSIZ]; + int result; + + s->__bufp = s->__buffer = buf; + s->__bufsize = sizeof buf; + s->__put_limit = s->__buffer + s->__bufsize; + s->__get_limit = s->__buffer; + + /* Now use buffer to print. */ + result = vfprintf (s, format, args); + + if (fflush (s) == EOF) + return -1; + s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL; + s->__bufsize = 0; + + return result; +} + + +/* Pads string with given number of a specified character. + This code is taken from iopadn.c of the GNU I/O library. */ +#define PADSIZE 16 +static const char blanks[PADSIZE] = +{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; +static const char zeroes[PADSIZE] = +{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + +ssize_t +__printf_pad (s, pad, count) + FILE *s; + char pad; + int count; +{ + CONST char *padptr; + register int i; + size_t written = 0, w; + + padptr = pad == ' ' ? blanks : zeroes; + + for (i = count; i >= PADSIZE; i -= PADSIZE) + { + w = PUT(s, padptr, PADSIZE); + written += w; + if (w != PADSIZE) + return written; + } + if (i > 0) + { + w = PUT(s, padptr, i); + written += w; + } + return written; +} +#undef PADSIZE +#endif /* USE_IN_LIBIO */ diff --git a/stdio/vfscanf.c b/stdio/vfscanf.c new file mode 100644 index 0000000000..681e89819b --- /dev/null +++ b/stdio/vfscanf.c @@ -0,0 +1,570 @@ +/* Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <localeinfo.h> +#include <errno.h> +#include <limits.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#ifdef __GNUC__ +#define HAVE_LONGLONG +#define LONGLONG long long +#else +#define LONGLONG long +#endif + + +#define inchar() ((c = getc(s)) == EOF ? EOF : (++read_in, c)) +#define conv_error() return ((c == EOF || ungetc(c, s)), done) +#define input_error() return (done == 0 ? EOF : done) +#define memory_error() return ((errno = ENOMEM), EOF) + + +/* Read formatted input from S according to the format string + FORMAT, using the argument list in ARG. + Return the number of assignments made, or -1 for an input error. */ +int +DEFUN(__vfscanf, (s, format, arg), + FILE *s AND CONST char *format AND va_list argptr) +{ + va_list arg = (va_list) argptr; + + register CONST char *f = format; + register char fc; /* Current character of the format. */ + register size_t done = 0; /* Assignments done. */ + register size_t read_in = 0; /* Chars read in. */ + register int c; /* Last char read. */ + register int do_assign; /* Whether to do an assignment. */ + register int width; /* Maximum field width. */ + + /* Type modifiers. */ + char is_short, is_long, is_long_double; +#ifdef HAVE_LONGLONG + /* We use the `L' modifier for `long long int'. */ +#define is_longlong is_long_double +#else +#define is_longlong 0 +#endif + int malloc_string; /* Args are char ** to be filled in. */ + /* Status for reading F-P nums. */ + char got_dot, got_e; + /* If a [...] is a [^...]. */ + char not_in; + /* Base for integral numbers. */ + int base; + /* Signedness for integral numbers. */ + int number_signed; + /* Integral holding variables. */ + long int num; + unsigned long int unum; + /* Character-buffer pointer. */ + register char *str, **strptr; + size_t strsize; + /* Workspace. */ + char work[200]; + char *w; /* Pointer into WORK. */ + wchar_t decimal; /* Decimal point character. */ + + if (!__validfp(s) || !s->__mode.__read || format == NULL) + { + errno = EINVAL; + return EOF; + } + + /* Figure out the decimal point character. */ + if (mbtowc(&decimal, _numeric_info->decimal_point, + strlen(_numeric_info->decimal_point)) <= 0) + decimal = (wchar_t) *_numeric_info->decimal_point; + + c = inchar(); + + /* Run through the format string. */ + while (*f != '\0') + { + if (!isascii(*f)) + { + /* Non-ASCII, may be a multibyte. */ + int len = mblen(f, strlen(f)); + if (len > 0) + { + while (len-- > 0) + if (c == EOF) + input_error(); + else if (c == *f++) + (void) inchar(); + else + conv_error(); + continue; + } + } + + fc = *f++; + if (fc != '%') + { + /* Characters other than format specs must just match. */ + if (c == EOF) + input_error(); + if (isspace(fc)) + { + /* Whitespace characters match any amount of whitespace. */ + while (isspace (c)) + inchar (); + continue; + } + else if (c == fc) + (void) inchar(); + else + conv_error(); + continue; + } + + /* Check for the assignment-suppressant. */ + if (*f == '*') + { + do_assign = 0; + ++f; + } + else + do_assign = 1; + + /* Find the maximum field width. */ + width = 0; + while (isdigit(*f)) + { + width *= 10; + width += *f++ - '0'; + } + if (width == 0) + width = -1; + + /* Check for type modifiers. */ + is_short = is_long = is_long_double = malloc_string = 0; + while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'a' || *f == 'q') + switch (*f++) + { + case 'h': + /* int's are short int's. */ + is_short = 1; + break; + case 'l': + if (is_long) + /* A double `l' is equivalent to an `L'. */ + is_longlong = 1; + else + /* int's are long int's. */ + is_long = 1; + break; + case 'q': + case 'L': + /* double's are long double's, and int's are long long int's. */ + is_long_double = 1; + break; + case 'a': + /* String conversions (%s, %[) take a `char **' + arg and fill it in with a malloc'd pointer. */ + malloc_string = 1; + break; + } + + /* End of the format string? */ + if (*f == '\0') + conv_error(); + + /* Find the conversion specifier. */ + w = work; + fc = *f++; + if (fc != '[' && fc != 'c' && fc != 'n') + /* Eat whitespace. */ + while (isspace(c)) + (void) inchar(); + switch (fc) + { + case '%': /* Must match a literal '%'. */ + if (c != fc) + conv_error(); + break; + + case 'n': /* Answer number of assignments done. */ + if (do_assign) + *va_arg(arg, int *) = read_in; + break; + + case 'c': /* Match characters. */ + if (do_assign) + { + str = va_arg (arg, char *); + if (str == NULL) + conv_error (); + } + + if (c == EOF) + input_error(); + + if (width == -1) + width = 1; + + if (do_assign) + { + do + *str++ = c; + while (inchar() != EOF && --width > 0); + } + else + while (inchar() != EOF && width > 0) + --width; + + if (do_assign) + ++done; + + break; + + case 's': /* Read a string. */ +#define STRING_ARG \ + if (do_assign) \ + { \ + if (malloc_string) \ + { \ + /* The string is to be stored in a malloc'd buffer. */ \ + strptr = va_arg (arg, char **); \ + if (strptr == NULL) \ + conv_error (); \ + /* Allocate an initial buffer. */ \ + strsize = 100; \ + *strptr = str = malloc (strsize); \ + } \ + else \ + str = va_arg (arg, char *); \ + if (str == NULL) \ + conv_error (); \ + } + STRING_ARG; + + if (c == EOF) + input_error (); + + do + { + if (isspace (c)) + break; +#define STRING_ADD_CHAR(c) \ + if (do_assign) \ + { \ + *str++ = c; \ + if (malloc_string && str == *strptr + strsize) \ + { \ + /* Enlarge the buffer. */ \ + str = realloc (*strptr, strsize * 2); \ + if (str == NULL) \ + { \ + /* Can't allocate that much. Last-ditch effort. */\ + str = realloc (*strptr, strsize + 1); \ + if (str == NULL) \ + { \ + /* We lose. Oh well. \ + Terminate the string and stop converting, \ + so at least we don't swallow any input. */ \ + (*strptr)[strsize] = '\0'; \ + ++done; \ + conv_error (); \ + } \ + else \ + { \ + *strptr = str; \ + str += strsize; \ + ++strsize; \ + } \ + } \ + else \ + { \ + *strptr = str; \ + str += strsize; \ + strsize *= 2; \ + } \ + } \ + } + STRING_ADD_CHAR (c); + } while (inchar () != EOF && (width <= 0 || --width > 0)); + + if (do_assign) + { + *str = '\0'; + ++done; + } + break; + + case 'x': /* Hexadecimal integer. */ + case 'X': /* Ditto. */ + base = 16; + number_signed = 0; + goto number; + + case 'o': /* Octal integer. */ + base = 8; + number_signed = 0; + goto number; + + case 'u': /* Unsigned decimal integer. */ + base = 10; + number_signed = 0; + goto number; + + case 'd': /* Signed decimal integer. */ + base = 10; + number_signed = 1; + goto number; + + case 'i': /* Generic number. */ + base = 0; + number_signed = 1; + + number: + if (c == EOF) + input_error(); + + /* Check for a sign. */ + if (c == '-' || c == '+') + { + *w++ = c; + if (width > 0) + --width; + (void) inchar(); + } + + /* Look for a leading indication of base. */ + if (c == '0') + { + if (width > 0) + --width; + *w++ = '0'; + + (void) inchar(); + + if (tolower(c) == 'x') + { + if (base == 0) + base = 16; + if (base == 16) + { + if (width > 0) + --width; + (void) inchar(); + } + } + else if (base == 0) + base = 8; + } + + if (base == 0) + base = 10; + + /* Read the number into WORK. */ + do + { + if (base == 16 ? !isxdigit(c) : + (!isdigit(c) || c - '0' >= base)) + break; + *w++ = c; + if (width > 0) + --width; + } while (inchar() != EOF && width != 0); + + if (w == work || + (w - work == 1 && (work[0] == '+' || work[0] == '-'))) + /* There was on number. */ + conv_error(); + + /* Convert the number. */ + *w = '\0'; + if (number_signed) + num = strtol (work, &w, base); + else + unum = strtoul (work, &w, base); + if (w == work) + conv_error (); + + if (do_assign) + { + if (! number_signed) + { + if (is_longlong) + *va_arg (arg, unsigned LONGLONG int *) = unum; + else if (is_long) + *va_arg (arg, unsigned long int *) = unum; + else if (is_short) + *va_arg (arg, unsigned short int *) + = (unsigned short int) unum; + else + *va_arg(arg, unsigned int *) = (unsigned int) unum; + } + else + { + if (is_longlong) + *va_arg(arg, LONGLONG int *) = num; + else if (is_long) + *va_arg(arg, long int *) = num; + else if (is_short) + *va_arg(arg, short int *) = (short int) num; + else + *va_arg(arg, int *) = (int) num; + } + ++done; + } + break; + + case 'e': /* Floating-point numbers. */ + case 'E': + case 'f': + case 'g': + case 'G': + if (c == EOF) + input_error(); + + /* Check for a sign. */ + if (c == '-' || c == '+') + { + *w++ = c; + if (inchar() == EOF) + /* EOF is only an input error before we read any chars. */ + conv_error(); + if (width > 0) + --width; + } + + got_dot = got_e = 0; + do + { + if (isdigit(c)) + *w++ = c; + else if (got_e && w[-1] == 'e' && (c == '-' || c == '+')) + *w++ = c; + else if (!got_e && tolower(c) == 'e') + { + *w++ = 'e'; + got_e = got_dot = 1; + } + else if (c == decimal && !got_dot) + { + *w++ = c; + got_dot = 1; + } + else + break; + if (width > 0) + --width; + } while (inchar() != EOF && width != 0); + + if (w == work) + conv_error(); + if (w[-1] == '-' || w[-1] == '+' || w[-1] == 'e') + conv_error(); + + /* Convert the number. */ + *w = '\0'; + if (is_long_double) + { + long double d = __strtold (work, &w); + if (do_assign && w != work) + *va_arg (arg, long double *) = d; + } + else if (is_long) + { + double d = strtod (work, &w); + if (do_assign && w != work) + *va_arg (arg, double *) = d; + } + else + { + float d = __strtof (work, &w); + if (do_assign && w != work) + *va_arg (arg, float *) = d; + } + + if (w == work) + conv_error (); + + if (do_assign) + ++done; + break; + + case '[': /* Character class. */ + STRING_ARG; + + if (c == EOF) + input_error(); + + if (*f == '^') + { + ++f; + not_in = 1; + } + else + not_in = 0; + + while ((fc = *f++) != '\0' && fc != ']') + { + if (fc == '-' && *f != '\0' && *f != ']' && + w > work && w[-1] <= *f) + /* Add all characters from the one before the '-' + up to (but not including) the next format char. */ + for (fc = w[-1] + 1; fc < *f; ++fc) + *w++ = fc; + else + /* Add the character to the list. */ + *w++ = fc; + } + if (fc == '\0') + conv_error(); + + *w = '\0'; + unum = read_in; + do + { + if ((strchr (work, c) == NULL) != not_in) + break; + STRING_ADD_CHAR (c); + if (width > 0) + --width; + } while (inchar () != EOF && width != 0); + if (read_in == unum) + conv_error (); + + if (do_assign) + { + *str = '\0'; + ++done; + } + break; + + case 'p': /* Generic pointer. */ + base = 16; + /* A PTR must be the same size as a `long int'. */ + is_long = 1; + goto number; + } + } + + conv_error(); +} + +weak_alias (__vfscanf, vfscanf) diff --git a/stdio/vprintf.c b/stdio/vprintf.c new file mode 100644 index 0000000000..97264f475c --- /dev/null +++ b/stdio/vprintf.c @@ -0,0 +1,33 @@ +/* Copyright (C) 1991, 1993 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#undef __OPTIMIZE__ /* Avoid inline `vprintf' function. */ +#include <stdio.h> + +#undef vprintf + + +/* Write formatted output to stdout according to the + format string FORMAT, using the argument list in ARG. */ +int +DEFUN(vprintf, (format, arg), CONST char *format AND __gnuc_va_list arg) +{ + return vfprintf (stdout, format, arg); +} diff --git a/stdio/vscanf.c b/stdio/vscanf.c new file mode 100644 index 0000000000..0d829440e9 --- /dev/null +++ b/stdio/vscanf.c @@ -0,0 +1,32 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> + +#undef vscanf + + +/* Read formatted input from stdin according to the format + string in FORMAT, using the argument list in ARG. */ +int +DEFUN(vscanf, (format, arg), CONST char *format AND va_list arg) +{ + return vfscanf (stdin, format, arg); +} diff --git a/stdio/vsnprintf.c b/stdio/vsnprintf.c new file mode 100644 index 0000000000..a02c259131 --- /dev/null +++ b/stdio/vsnprintf.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + + +/* + * Write formatted output to S according to the format string + * FORMAT, using the argument list in ARG, writing no more + * than MAXLEN characters. + */ +int +DEFUN(vsnprintf, (s, maxlen, format, arg), + char *s AND size_t maxlen AND CONST char *format AND va_list arg) +{ + int done; + FILE f; + + memset((PTR) &f, 0, sizeof(f)); + f.__magic = _IOMAGIC; + f.__mode.__write = 1; + /* The buffer size is one less than MAXLEN + so we have space for the null terminator. */ + f.__bufp = f.__buffer = (char *) s; + f.__bufsize = maxlen - 1; + f.__put_limit = f.__buffer + f.__bufsize; + f.__get_limit = f.__buffer; + /* After the buffer is full (MAXLEN characters have been written), + any more characters written will go to the bit bucket. */ + f.__room_funcs = __default_room_functions; + f.__io_funcs.__write = NULL; + f.__seen = 1; + + done = vfprintf(&f, format, arg); + *f.__bufp = '\0'; + + return done; +} diff --git a/stdio/vsprintf.c b/stdio/vsprintf.c new file mode 100644 index 0000000000..82be90f1fa --- /dev/null +++ b/stdio/vsprintf.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1991, 1992 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + + +/* Write formatted output to S according to the format string + FORMAT, using the argument list in ARG. */ +int +DEFUN(vsprintf, (s, format, arg), + char *s AND CONST char *format AND va_list arg) +{ + int done; + FILE f; + + memset((PTR) &f, 0, sizeof(f)); + f.__magic = _IOMAGIC; + f.__mode.__write = 1; + f.__bufp = f.__buffer = (char *) s; + f.__put_limit = (char *) ULONG_MAX; + f.__bufsize = (size_t) (f.__put_limit - f.__bufp); + f.__get_limit = f.__buffer; + f.__room_funcs.__output = NULL; + f.__seen = 1; + + done = vfprintf(&f, format, arg); + *f.__bufp = '\0'; + + return done; +} diff --git a/stdio/vsscanf.c b/stdio/vsscanf.c new file mode 100644 index 0000000000..6f027d5065 --- /dev/null +++ b/stdio/vsscanf.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1991, 1992, 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include <ansidecl.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <string.h> + +#undef vsscanf + + +/* Read formatted input from S according to the format + string FORMAT, using the argument list in ARG. */ +int +DEFUN(__vsscanf, (s, format, arg), + CONST char *s AND CONST char *format AND va_list arg) +{ + FILE f; + + if (s == NULL) + { + errno = EINVAL; + return -1; + } + + memset((PTR) &f, 0, sizeof(f)); + f.__magic = _IOMAGIC; + f.__mode.__read = 1; + f.__bufp = f.__buffer = (char *) s; + f.__bufsize = strlen(s); + f.__get_limit = f.__buffer + f.__bufsize; + f.__put_limit = f.__buffer; + /* After the buffer is empty (strlen(S) characters have been read), + any more read attempts will get EOF. */ + f.__room_funcs.__input = NULL; + f.__seen = 1; + + return __vfscanf(&f, format, arg); +} + + +weak_alias (__vsscanf, vsscanf) diff --git a/stdio/xbug.c b/stdio/xbug.c new file mode 100644 index 0000000000..ec648f5566 --- /dev/null +++ b/stdio/xbug.c @@ -0,0 +1,63 @@ +#include <stdio.h> + +typedef struct _Buffer { + char *buff; + int room, used; +} Buffer; + +#define INIT_BUFFER_SIZE 10000 + +void InitBuffer(b) + Buffer *b; +{ + b->room = INIT_BUFFER_SIZE; + b->used = 0; + b->buff = (char *)malloc(INIT_BUFFER_SIZE*sizeof(char)); +} + +void AppendToBuffer(b, str, len) + register Buffer *b; + char *str; + register int len; +{ + while (b->used + len > b->room) { + b->buff = (char *)realloc(b->buff, 2*b->room*(sizeof(char))); + b->room *= 2; + } + strncpy(b->buff + b->used, str, len); + b->used += len; +} + +void ReadFile(buffer, input) + register Buffer *buffer; + FILE *input; +{ + char buf[BUFSIZ + 1]; + register int bytes; + + buffer->used = 0; + while (!feof(input) && (bytes = fread(buf, 1, BUFSIZ, input)) > 0) { + AppendToBuffer(buffer, buf, bytes); + } + AppendToBuffer(buffer, "", 1); +} + +main() +{ + char * filename = "xbug.c"; + FILE *input; + Buffer buffer; + + InitBuffer(&buffer); + + if (!freopen (filename, "r", stdin)) + fprintf(stderr, "cannot open file\n"); + + if (!(input = popen("/bin/cat", "r"))) + fprintf(stderr, "cannot run \n"); + + ReadFile(&buffer, input); + pclose(input); + + return 0; +} |