diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 1998-06-29 00:19:07 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 1998-06-29 00:19:07 +0000 |
commit | b0594c55ee89492c0a1d4b8ef6425955998d168c (patch) | |
tree | d7231f13dae2de4fa0af9a9aba0f81d3632777f5 /gnu/usr.bin | |
parent | e038c1555f2e165a35c68bb94f24b03bf9ecc49c (diff) |
GNU bc 1.05a
Diffstat (limited to 'gnu/usr.bin')
64 files changed, 26294 insertions, 0 deletions
diff --git a/gnu/usr.bin/bc/AUTHORS b/gnu/usr.bin/bc/AUTHORS new file mode 100644 index 00000000000..c78d68f108e --- /dev/null +++ b/gnu/usr.bin/bc/AUTHORS @@ -0,0 +1,4 @@ +Phil Nelson <phil@cs.wwu.edu> wrote bc, including the number.c +source in the "lib" directory. + +Ken Pizzini wrote dc. diff --git a/gnu/usr.bin/bc/INSTALL b/gnu/usr.bin/bc/INSTALL new file mode 100644 index 00000000000..3b50ea95726 --- /dev/null +++ b/gnu/usr.bin/bc/INSTALL @@ -0,0 +1,176 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes a while. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. + diff --git a/gnu/usr.bin/bc/Makefile.am b/gnu/usr.bin/bc/Makefile.am new file mode 100644 index 00000000000..cbdde44da09 --- /dev/null +++ b/gnu/usr.bin/bc/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to produce Makefile.in +SUBDIRS = lib bc dc doc + +dist-hook: + mkdir $(distdir)/h $(distdir)/Examples $(distdir)/Test + cp -p $(srcdir)/h/*.h $(distdir)/h + cp -p $(srcdir)/Examples/*.b $(distdir)/Examples + cp -p $(srcdir)/Test/*.b $(srcdir)/Test/*.bc $(distdir)/Test + cp -p $(srcdir)/Test/signum $(srcdir)/Test/timetest $(distdir)/Test diff --git a/gnu/usr.bin/bc/Makefile.bsd-wrapper b/gnu/usr.bin/bc/Makefile.bsd-wrapper new file mode 100644 index 00000000000..68d942e2d19 --- /dev/null +++ b/gnu/usr.bin/bc/Makefile.bsd-wrapper @@ -0,0 +1,62 @@ +# $OpenBSD: Makefile.bsd-wrapper,v 1.1 1998/06/29 00:19:01 millert Exp $ + +MAN= doc/bc.1 doc/dc.1 +#CLEANFILES= +LDFLAGS+= -s ${LDSTATIC} +GNUCFLAGS= CFLAGS="${CFLAGS}" LDFLAGS="${LDFLAGS}" + +all: config.status wrapper + ${MAKE} ${GNUCFLAGS} + +wrapper: + cd ${.CURDIR}/bcwrap && ${MAKE} + +.FORCE: .IGNORE + +.include <bsd.own.mk> + +.ifdef GLOBAL_AUTOCONF_CACHE +CF= --cache-file=${GLOBAL_AUTOCONF_CACHE} +.else +CF= +.endif + +config: .FORCE +.ifndef GLOBAL_AUTOCONF_CACHE + -rm -f config.cache +.endif + INSTALL_PROGRAM="${INSTALL} ${INSTALL_COPY} ${INSTALL_STRIP}" \ + sh ${.CURDIR}/configure --prefix=${PREFIX}/usr --infodir=${PREFIX}/usr/share/info ${CF} + +config.status: + INSTALL_PROGRAM="${INSTALL} ${INSTALL_COPY} ${INSTALL_STRIP}" \ + sh ${.CURDIR}/configure --prefix=${PREFIX}/usr --infodir=${PREFIX}/usr/share/info ${CF} + +.ifdef NOMAN +maninstall: + @echo NOMAN is set +.endif + +install: maninstall + cd ${.CURDIR}/bcwrap && ${MAKE} install + ${MAKE} ${GNUCFLAGS} prefix=${DESTDIR}/usr \ + bindir=${DESTDIR}/usr/bin infodir=${PREFIX}/usr/share/info + +clean cleandir: + -@if [ -e Makefile ]; then ${MAKE} distclean; fi + rm -f ${CLEANFILES} + +depend: + # Nothing here so far... + +lint: + # Nothing here so far... + +tags: + # Nothing here so far... + +.include <bsd.obj.mk> +.include <bsd.subdir.mk> +.ifndef NOMAN +.include <bsd.man.mk> +.endif diff --git a/gnu/usr.bin/bc/NEWS b/gnu/usr.bin/bc/NEWS new file mode 100644 index 00000000000..105795d8fb8 --- /dev/null +++ b/gnu/usr.bin/bc/NEWS @@ -0,0 +1,53 @@ +This is GNU bc version 1.05. (And dc version 1.2) + +Changes in dc from 1.1 to 1.2: + added !< != !> commands + arrays now stack + output is now line buffered, provided setvbuf() is available + fixed known bugs in 'q', 'Q', 'a' commands, '-f' command-line option, + and documentation + changed the 'P' command's behavior on a numeric argument: + due to popular demand it now does the equivalent of 'aP' + (for small values) + added new 'n' command to do what the old 'P' command did + +Changes in bc from 1.04 to 1.05: + Solaris makes work better. + bug fixes + stdout now always does line buffering. + sqrt bug fixed for small numbers. + readline (if support is compiled in) is enabled only for + interactive executions of bc. + + +This is GNU bc version 1.04. (And dc version 1.1) + +Changes from 1.03 + + reorganization of source tree + use of automake + + new commands for dc (|, ~, r, a) + new command line options for dc + + fixed infinite loop in sqrt in bc + fixed an I/O bug in bc + made bc conform to POSIX for array parameters + added long option support for bc + new commandline options for bc (-q) + added support for readline to bc (use configure --with-readline) + command line argumens can now be taken from an environment variable + + +Changes from 1.02 + + minor bug fixes in bc. + + addition of Ken Pizzini's dc program that uses the GNU bc + arbitrary precision arithmetic routines. + +Changes from 1.01 + + minor bug fixes. + + diff --git a/gnu/usr.bin/bc/Test/TESTS.bc b/gnu/usr.bin/bc/Test/TESTS.bc new file mode 100644 index 00000000000..ec42172a422 --- /dev/null +++ b/gnu/usr.bin/bc/Test/TESTS.bc @@ -0,0 +1,565 @@ +From phil@cs.wwu.edu Mon Mar 20 23:13:22 1995 +Date: Mon, 20 Mar 1995 23:12:17 -0800 +From: Phil Nelson <phil@cs.wwu.edu> +To: phil@steelhead.cs.wwu.edu +Subject: [jhn@ironwood.cray.com: XPG4 bc(1) failures] + +From: jhn@ironwood.cray.com (James Nordby) +Subject: XPG4 bc(1) failures +To: phil@cs.wwu.edu +Date: Fri, 17 Mar 1995 12:14:13 -0600 (CST) +X-Mailer: ELM [version 2.4 PL24-CRI-b] +Mime-Version: 1.0 +Content-Type: text/plain; charset=US-ASCII +Content-Transfer-Encoding: 7bit +Content-Length: 14277 + + +Phil, + +Here are the test results I'm getting from the XPG4 test suite, +with some explanation and fixes so far. Let me know what you +think... + +Thanks much, +Jim Nordby (jhn@cray.com) + + +-------- bc 08:38:34 -------- + +Assertion #20 (A): bc reads text files +Expected exit code = 0; Received 139 +Standard output isn't the same as file 'bc_eso_20_1' +diff of "out.stdout" and "bc_eso_20_1": +*** out.stdout Fri Mar 17 08:39:22 1995 +--- bc_eso_20_1 Fri Mar 17 08:39:22 1995 +*************** +*** 0 **** +--- 1,31 ---- ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 11111111111111111111111111111111111111111111111111111111111111111111 ++ 1111111 +Assertion Result: FAIL + +I couldn't reproduce this problem; when I rebuilt your bc and +ran it, I got a different problem with printing out a large +number. The XPG4 tests expected lines to be 70 characters +long, INCLUDING the newline (this comes from the POSIX definition +of a line). To fix it, I changed util.c like so: + +*** util.c Thu Mar 16 10:47:36 1995 +--- util.c.old Thu Mar 16 10:50:10 1995 +*************** +*** 309,323 **** + else + { + out_col++; +- #ifdef _CRAY +- /* +- * XPG4 considers a line to include the <newline>; +- * therefore we want 68 numerals, <backslash>, <newline> +- */ +- if (out_col == 69) +- #else + if (out_col == 70) +- #endif + { + putchar ('\\'); + putchar ('\n'); +--- 309,315 ---- + + + + + + +Assertion #42 (A): check reserved words +Standard error isn't empty +Contents of out.stderr: +(standard_in) 6: syntax error +(standard_in) 15: syntax error +Standard output isn't the same as file 'bc_eso_42_1' +diff of "out.stdout" and "bc_eso_42_1": +*** out.stdout Fri Mar 17 08:39:43 1995 +--- bc_eso_42_1 Fri Mar 17 08:39:43 1995 +*************** +*** 1,2 **** +--- 1,3 ---- + 2 + 1 ++ 0 +Assertion Result: FAIL + +This one is debatable, based on the grammar in the POSIX manual. +Here's the input file: + +cat << \VSC-EOF > input +define a() { + auto b; + for ( b = 0; b < 10; b++ ) { + b; + if ( b == 1 ) + break; + } + return ( 5 ) ; +} +ibase = 10; +length ( obase ); +scale = 0; +sqrt(1); +while ( a() != 5 ) +VSC-EOF + +They want these constructs to be accepted: + + +if (b == 1) + whatever; +for (x = 0; x < 10; x++) + whatever; +while (x < 10) + whatever; + +rather than just + +if (b == 1) { + whatever +} +etc. + +The grammar as it's currently worded requires a '{' before hitting +a NEWLINE for these constructs. It's easy enough to change in bc.y +(see below), but if I do change it, it still barfs on the last +line of the file ( 'while (a() != 5)' ). Since the while lacks +a body, it gives a syntax error; they're expecting a '0' to be +returned. The grammar could be changed to support this, but is +it a good idea? + + +*** bc.y Thu Mar 16 10:47:20 1995 +--- bc.y.old Thu Mar 16 10:50:11 1995 +*************** +*** 142,150 **** + | error statement + { $$ = $2; } + ; +- allow_newlines : /* empty */ +- | NEWLINE allow_newlines +- ; + statement : Warranty + { warranty (""); } + | Limits +--- 142,147 ---- +*************** +*** 231,237 **** + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } +! allow_newlines statement + { + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); +--- 228,234 ---- + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } +! statement + { + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); +*************** +*** 246,252 **** + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + } +! allow_newlines statement opt_else + { + sprintf (genstr, "N%1d:", if_label); + generate (genstr); +--- 243,249 ---- + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + } +! statement opt_else + { + sprintf (genstr, "N%1d:", if_label); + generate (genstr); +*************** +*** 265,271 **** + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } +! ')' allow_newlines statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); +--- 262,268 ---- + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } +! ')' statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + + + + +Assertion #49 (A): check strings +Expected exit code = 0; Received 1 +Standard error isn't empty +Contents of out.stderr: +File (NULL) is unavailable. +Standard output isn't the same as file 'bc_eso_49_1' +diff of "out.stdout" and "bc_eso_49_1": +cmd-1794 diff: Missing newline at end of file 'bc_eso_49_1'. +*** out.stdout Fri Mar 17 08:40:01 1995 +--- bc_eso_49_1 Fri Mar 17 08:40:01 1995 +*************** +*** 0 **** +--- 1 ---- ++ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +*LINE CONTINUATION -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +*LINE CONTINUATION -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +Assertion Result: FAIL + +This gist of this is that the standard expects numbers to +be truncated to 70 characters, but STRINGS should not. +My changes to fix this are: + + +*** execute.c Thu Mar 16 13:06:39 1995 +--- execute.c.old Thu Mar 16 10:50:09 1995 +*************** +*** 208,218 **** + case 'O' : /* Write a string to the output with processing. */ + while ((ch = byte(&pc)) != '"') + if (ch != '\\') +- #ifdef _CRAY +- putchar (ch); +- #else + out_char (ch); +- #endif + else + { + ch = byte(&pc); +--- 207,213 ---- +*************** +*** 219,234 **** + if (ch == '"') break; + switch (ch) + { +- #ifdef _CRAY +- case 'a': putchar (007); break; +- case 'b': putchar ('\b'); break; +- case 'f': putchar ('\f'); break; +- case 'n': putchar ('\n'); break; +- case 'q': putchar ('"'); break; +- case 'r': putchar ('\r'); break; +- case 't': putchar ('\t'); break; +- case '\\': putchar ('\\'); break; +- #else + case 'a': out_char (007); break; + case 'b': out_char ('\b'); break; + case 'f': out_char ('\f'); break; +--- 214,219 ---- +*************** +*** 237,243 **** + case 'r': out_char ('\r'); break; + case 't': out_char ('\t'); break; + case '\\': out_char ('\\'); break; +- #endif + default: break; + } + } +--- 222,227 ---- +*************** +*** 350,360 **** + break; + + case 'w' : /* Write a string to the output. */ +- #ifdef _CRAY +- while ((ch = byte(&pc)) != '"') putchar (ch); +- #else + while ((ch = byte(&pc)) != '"') out_char (ch); +- #endif + if (interactive) fflush (stdout); + break; + + + + +Assertion #77 (C): output longer than 70 characters +Standard output isn't the same as file 'bc_eso_77_1' +diff of "out.stdout" and "bc_eso_77_1": +*** out.stdout Fri Mar 17 08:41:13 1995 +--- bc_eso_77_1 Fri Mar 17 08:41:13 1995 +*************** +*** 1,2 **** +! 3.3333333333333333333333333333333333333333333333333333333333333333333 +! 33333333333333333333333333333333 +--- 1,2 ---- +! 3.333333333333333333333333333333333333333333333333333333333333333333 +! 333333333333333333333333333333333 +Assertion Result: FAIL + +Same as assertion #20 above... + + + + +Assertion #92 (A): check % +Standard output isn't the same as file 'bc_eso_92_1' +diff of "out.stdout" and "bc_eso_92_1": +*** out.stdout Fri Mar 17 08:41:33 1995 +--- bc_eso_92_1 Fri Mar 17 08:41:33 1995 +*************** +*** 4,8 **** + 4 + 15 + 1 +! 0 +! 0 +--- 4,8 ---- + 4 + 15 + 1 +! 6 +! 5 +Assertion Result: FAIL + +This one is a pain. The failing code looks like this: + +scale = 4 +scale ( 5.000000 % 2.0 ) +scale ( 5.00 % 2.0 ) + +They expect '6' and '5' for output, instead of '0', based on +the explanation of the modulus operator ("scale of the result +shall be 'max(scale + scale(b), scale(a)'"), even though the +result is a 0. I was able to fix this problem by the change +below: + +*** number.c Thu Mar 16 13:15:43 1995 +--- number.c.old Thu Mar 16 10:50:09 1995 +*************** +*** 614,623 **** + case 0: + /* They are equal! return zero! */ + diff = copy_num (_zero_); +- #ifdef _CRAY +- /* correct the scale here */ +- diff->n_scale = MAX (n1->n_scale, n2->n_scale); +- #endif + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + +but this causes another test failure that I haven't looked at. + + + + +Assertion #130 (A): functions are call by value +Standard output isn't the same as file 'bc_eso_130_1' +diff of "out.stdout" and "bc_eso_130_1": +*** out.stdout Fri Mar 17 08:42:24 1995 +--- bc_eso_130_1 Fri Mar 17 08:42:24 1995 +*************** +*** 4,10 **** + 5 + 4 + 0 +! 4 + 3 + 3 + 5 +--- 4,10 ---- + 5 + 4 + 0 +! 5 + 3 + 3 + 5 +Assertion Result: FAIL + +Assertion #131 (A): functions are call by value +Standard output isn't the same as file 'bc_eso_131_1' +diff of "out.stdout" and "bc_eso_131_1": +*** out.stdout Fri Mar 17 08:42:28 1995 +--- bc_eso_131_1 Fri Mar 17 08:42:28 1995 +*************** +*** 4,10 **** + 5 + 4 + 0 +! 4 + 3 + 3 + 5 +--- 4,10 ---- + 5 + 4 + 0 +! 5 + 3 + 3 + 5 +Assertion Result: FAIL + + +Both of these are the 'arrays are passed by value' problem. +One of the test cases is below: + +cat << \VSC-EOF > bc_in_130_1 +a[0] = 3 +a[0] +define b(a[]) { +a[0] +a[0] = 4 +a[0] +} +a[0] +a[0] = 5 +a[0] +b(a[]) +a[0] +VSC-EOF + +They expect the assignment of a[0] inside the b() function +to not affect a[0] outside of the function. + + + + + +Assertion #139 (A): check sin +Standard output isn't the same as file 'bc_eso_139_1' +diff of "out.stdout" and "bc_eso_139_1": +*** out.stdout Fri Mar 17 08:42:40 1995 +--- bc_eso_139_1 Fri Mar 17 08:42:39 1995 +*************** +*** 1,5 **** + 0 +! 20 + 1.68294196961579301330 + 20 + 1.6829419696 +--- 1,5 ---- + 0 +! 0 + 1.68294196961579301330 + 20 + 1.6829419696 +Assertion Result: FAIL + +Assertion #141 (A): check arctanngent +Standard output isn't the same as file 'bc_eso_141_1' +diff of "out.stdout" and "bc_eso_141_1": +*** out.stdout Fri Mar 17 08:42:44 1995 +--- bc_eso_141_1 Fri Mar 17 08:42:44 1995 +*************** +*** 1,5 **** + 0 +! 20 + 3.14159265358979323844 + 20 + 3.1415926532 +--- 1,5 ---- + 0 +! 0 + 3.14159265358979323844 + 20 + 3.1415926532 +Assertion Result: FAIL + +Assertion #142 (A): check log +Standard output isn't the same as file 'bc_eso_142_1' +diff of "out.stdout" and "bc_eso_142_1": +*** out.stdout Fri Mar 17 08:42:47 1995 +--- bc_eso_142_1 Fri Mar 17 08:42:47 1995 +*************** +*** 1,5 **** + 0 +! 20 + 2.30258509299404568401 + 20 + 2.3025850929 +--- 1,5 ---- + 0 +! 0 + 2.30258509299404568401 + 20 + 2.3025850929 +Assertion Result: FAIL + +Assertion #144 (A): check bessel +Standard output isn't the same as file 'bc_eso_144_1' +diff of "out.stdout" and "bc_eso_144_1": +*** out.stdout Fri Mar 17 08:42:51 1995 +--- bc_eso_144_1 Fri Mar 17 08:42:51 1995 +*************** +*** 1,5 **** + 0 +! 20 + .57672480775687338720 + 20 + .5767248077 +--- 1,5 ---- + 0 +! 0 + .57672480775687338720 + 20 + .5767248077 +Assertion Result: FAIL + +All of these are the same. I'll give you the test case +for 'sin'; what they're expecting is 0: + +scale(s(0)) + +bc outputs '20' (which is the scale at the time), but the +interpretation of the standard says that it should be '0', +since s(0) is 0, and the scale of 0 is 0. I think that +this interpretation disagrees with one of the previous +assertions (assertion #92). + +/* end of test results */ + + + +-- +Phil Nelson +e-mail: phil@cs.wwu.edu +http://www.cs.wwu.edu/~phil + + diff --git a/gnu/usr.bin/bc/Test/arrayp.b b/gnu/usr.bin/bc/Test/arrayp.b new file mode 100644 index 00000000000..3f3ca505c95 --- /dev/null +++ b/gnu/usr.bin/bc/Test/arrayp.b @@ -0,0 +1,30 @@ +"This tests arrays! +" +define p(a[],x,y) { + auto i; + for (i=x; i<y; i++) a[i]; +} + +define m(a[],x,y) { + auto i; + for (i=x; i<y; i++) a[i] = i; +} + +define m1(*a[],x,y) { + auto i; + print "m1\n" + for (i=x; i<y; i++) a[i] = i; +} + +for (i=0; i<10; i++) a[i] = i; +j = p(a[],0,10); + +j = m(b[],0,10); +j = p(b[],0,10); + +print "---\n"; +j = m1(b[],0,10); +j = p(b[],0,10); + +quit + diff --git a/gnu/usr.bin/bc/Test/sqrt1.b b/gnu/usr.bin/bc/Test/sqrt1.b new file mode 100644 index 00000000000..c3ca2698fcc --- /dev/null +++ b/gnu/usr.bin/bc/Test/sqrt1.b @@ -0,0 +1,13 @@ +for (j=0; j<10; j++) { + a = .9; + b = .9+j; + scale = 2; + for (i=0; i<90; i++) { + scale += 1; + a /= 10; + b += a; + x = sqrt(b); + } + x; +} +quit diff --git a/gnu/usr.bin/bc/Test/sqrt2.b b/gnu/usr.bin/bc/Test/sqrt2.b new file mode 100644 index 00000000000..bd0eaadb76c --- /dev/null +++ b/gnu/usr.bin/bc/Test/sqrt2.b @@ -0,0 +1,10 @@ +scale = 20 +for (a=1; a<5000; a += 1) r=sqrt(a) +r +for (a=1; a<50000; a += 100) r=sqrt(a) +r +for (a=1; a<500000; a+=1000) r=sqrt(a) +r +for (a=1; a<5000000; a+=10000) r=sqrt(a) +r +quit diff --git a/gnu/usr.bin/bc/aclocal.m4 b/gnu/usr.bin/bc/aclocal.m4 new file mode 100644 index 00000000000..8c0d9c0de86 --- /dev/null +++ b/gnu/usr.bin/bc/aclocal.m4 @@ -0,0 +1,145 @@ +dnl aclocal.m4 generated automatically by aclocal 1.3 + +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AM_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") +AC_DEFINE_UNQUOTED(VERSION, "$VERSION")) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + + +# serial 1 + +AC_DEFUN(AM_PROG_INSTALL, +[AC_REQUIRE([AC_PROG_INSTALL]) +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl +]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<<test -z "<<$>>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<<am_indx=1 +for am_file in <<$1>>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + + +dnl AM_PROG_LEX +dnl Look for flex, lex or missing, then run AC_PROG_LEX and AC_DECL_YYTEXT +AC_DEFUN(AM_PROG_LEX, +[missing_dir=ifelse([$1],,`cd $ac_aux_dir && pwd`,$1) +AC_CHECK_PROGS(LEX, flex lex, "$missing_dir/missing flex") +AC_PROG_LEX +AC_DECL_YYTEXT]) + diff --git a/gnu/usr.bin/bc/bc/Makefile.am b/gnu/usr.bin/bc/bc/Makefile.am new file mode 100644 index 00000000000..d02daf0aedc --- /dev/null +++ b/gnu/usr.bin/bc/bc/Makefile.am @@ -0,0 +1,48 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = bc + +bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c + +EXTRA_DIST = bc.h fix-libmath_h libmath.b sbc.y +noinst_HEADERS = libmath.h + +DISTCLEANFILES = sbc sbc.c sbc.h +MAINTAINERCLEANFILES = libmath.h bc.c bc.h + +datadir = $(prefix)/@DATADIRNAME@ + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h +LDADD = ../lib/libbc.a @LEXLIB@ + +YFLAGS = -d + +$(PROGRAMS): $(LDADD) + +scan.o: bc.h +global.o: libmath.h + +libmath.h: libmath.b + echo \"\" > libmath.h + $(MAKE) fbc + ./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h + $(srcdir)/fix-libmath_h + rm -f ./fbc + +install-data-local: + if grep -s "define BC_MATH_FILE" ../config.h; \ + then $(mkinstalldirs) $(libdir); \ + rm -f $(libdir)/libmath.b; \ + $(INSTALL_DATA) $(srcdir)/libmath.b $(libdir); \ + chmod 444 $(libdir)/libmath.b; \ + else true; \ + fi + +fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o +fbc: $(fbcOBJ) + $(LINK) $(fbcOBJ) $(LDADD) $(LIBS) + + +sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o +sbc.o: sbc.c +sbc: $(sbcOBJ) + $(LINK) $(sbcOBJ) $(LDADD) $(LIBS) diff --git a/gnu/usr.bin/bc/bc/Makefile.in b/gnu/usr.bin/bc/bc/Makefile.in new file mode 100644 index 00000000000..2398cb00993 --- /dev/null +++ b/gnu/usr.bin/bc/bc/Makefile.in @@ -0,0 +1,314 @@ +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +bin_PROGRAMS = bc + +bc_SOURCES = main.c bc.y scan.l execute.c load.c storage.c util.c global.c + +EXTRA_DIST = bc.h fix-libmath_h libmath.b sbc.y +noinst_HEADERS = libmath.h + +DISTCLEANFILES = sbc sbc.c sbc.h +MAINTAINERCLEANFILES = libmath.h bc.c bc.h + +datadir = $(prefix)/@DATADIRNAME@ + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h +LDADD = ../lib/libbc.a @LEXLIB@ + +YFLAGS = -d + +fbcOBJ = main.o bc.o scan.o execute.o global.o load.o storage.o util.o + +sbcOBJ = main.o sbc.o scan.o execute.o global.o load.o storage.o util.o +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +bc_OBJECTS = main.o bc.o scan.o execute.o load.o storage.o util.o \ +global.o +bc_LDADD = $(LDADD) +bc_DEPENDENCIES = ../lib/libbc.a +bc_LDFLAGS = +LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LEXLIB = @LEXLIB@ +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = Makefile.am Makefile.in bc.c scan.c + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +SOURCES = $(bc_SOURCES) +OBJECTS = $(bc_OBJECTS) + +all: Makefile $(PROGRAMS) $(HEADERS) + +.SUFFIXES: +.SUFFIXES: .S .c .l .o .s .y +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps bc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +bc: $(bc_OBJECTS) $(bc_DEPENDENCIES) + @rm -f bc + $(LINK) $(bc_LDFLAGS) $(bc_OBJECTS) $(bc_LDADD) $(LIBS) +.y.c: + $(YACC) $(YFLAGS) $< && mv y.tab.c $*.c + if test -f y.tab.h; then \ + if cmp -s y.tab.h $*.h; then rm -f y.tab.h; else mv y.tab.h $*.h; fi; \ + else :; fi +bc.h: bc.c + +.l.c: + $(LEX) $(LFLAGS) $< && mv $(LEX_OUTPUT_ROOT).c $@ + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = bc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: install-binPROGRAMS + @$(NORMAL_INSTALL) + +install-data: install-data-local + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: uninstall-binPROGRAMS + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + $(mkinstalldirs) $(DATADIR)$(bindir) + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean + -rm -f config.status + +maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \ + maintainer-clean-tags maintainer-clean-generic \ + distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +scan.o: bc.h +global.o: libmath.h + +libmath.h: libmath.b + echo \"\" > libmath.h + $(MAKE) fbc + ./fbc -c $(srcdir)/libmath.b </dev/null >libmath.h + $(srcdir)/fix-libmath_h + rm -f ./fbc + +install-data-local: + if grep -s "define BC_MATH_FILE" ../config.h; \ + then $(mkinstalldirs) $(libdir); \ + rm -f $(libdir)/libmath.b; \ + $(INSTALL_DATA) $(srcdir)/libmath.b $(libdir); \ + chmod 444 $(libdir)/libmath.b; \ + else true; \ + fi +fbc: $(fbcOBJ) + $(LINK) $(fbcOBJ) $(LDADD) $(LIBS) +sbc.o: sbc.c +sbc: $(sbcOBJ) + $(LINK) $(sbcOBJ) $(LDADD) $(LIBS) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gnu/usr.bin/bc/bc/bc.c b/gnu/usr.bin/bc/bc/bc.c new file mode 100644 index 00000000000..e04bed2e845 --- /dev/null +++ b/gnu/usr.bin/bc/bc/bc.c @@ -0,0 +1,1808 @@ + +/* A Bison parser, made from bc.y + by GNU Bison version 1.25 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#define NEWLINE 258 +#define AND 259 +#define OR 260 +#define NOT 261 +#define STRING 262 +#define NAME 263 +#define NUMBER 264 +#define ASSIGN_OP 265 +#define REL_OP 266 +#define INCR_DECR 267 +#define Define 268 +#define Break 269 +#define Quit 270 +#define Length 271 +#define Return 272 +#define For 273 +#define If 274 +#define While 275 +#define Sqrt 276 +#define Else 277 +#define Scale 278 +#define Ibase 279 +#define Obase 280 +#define Auto 281 +#define Read 282 +#define Warranty 283 +#define Halt 284 +#define Last 285 +#define Continue 286 +#define Print 287 +#define Limits 288 +#define UNARY_MINUS 289 +#define History 290 + +#line 1 "bc.y" + +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" + +#line 38 "bc.y" +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#include <stdio.h> + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 185 +#define YYFLAG -32768 +#define YYNTBASE 50 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 290 ? yytranslate[x] : 83) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 40, 2, 2, 43, + 44, 38, 36, 47, 37, 2, 39, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 42, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 48, 2, 49, 41, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 45, 2, 46, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 1, 4, 7, 9, 12, 13, 15, 16, 18, + 22, 25, 26, 28, 31, 35, 38, 42, 44, 47, + 49, 51, 53, 55, 57, 59, 61, 63, 65, 70, + 71, 72, 73, 74, 89, 90, 99, 100, 101, 110, + 114, 115, 119, 121, 125, 127, 129, 130, 131, 136, + 137, 150, 151, 153, 154, 158, 162, 164, 168, 173, + 177, 183, 190, 191, 193, 195, 199, 203, 209, 210, + 212, 213, 215, 216, 221, 222, 227, 228, 233, 236, + 240, 244, 248, 252, 256, 260, 264, 267, 269, 271, + 275, 280, 283, 286, 291, 296, 301, 305, 307, 312, + 314, 316, 318, 320 +}; + +static const short yyrhs[] = { -1, + 50, 51, 0, 53, 3, 0, 69, 0, 1, 3, + 0, 0, 3, 0, 0, 55, 0, 53, 42, 55, + 0, 53, 42, 0, 0, 55, 0, 54, 3, 0, + 54, 3, 55, 0, 54, 42, 0, 54, 42, 56, + 0, 56, 0, 1, 56, 0, 28, 0, 33, 0, + 78, 0, 7, 0, 14, 0, 31, 0, 15, 0, + 29, 0, 17, 0, 17, 43, 77, 44, 0, 0, + 0, 0, 0, 18, 57, 43, 76, 42, 58, 76, + 42, 59, 76, 44, 60, 52, 56, 0, 0, 19, + 43, 78, 44, 61, 52, 56, 67, 0, 0, 0, + 20, 62, 43, 78, 63, 44, 52, 56, 0, 45, + 54, 46, 0, 0, 32, 64, 65, 0, 66, 0, + 66, 47, 65, 0, 7, 0, 78, 0, 0, 0, + 22, 68, 52, 56, 0, 0, 13, 8, 43, 71, + 44, 52, 45, 3, 72, 70, 54, 46, 0, 0, + 73, 0, 0, 26, 73, 3, 0, 26, 73, 42, + 0, 8, 0, 8, 48, 49, 0, 38, 8, 48, + 49, 0, 73, 47, 8, 0, 73, 47, 8, 48, + 49, 0, 73, 47, 38, 8, 48, 49, 0, 0, + 75, 0, 78, 0, 8, 48, 49, 0, 75, 47, + 78, 0, 75, 47, 8, 48, 49, 0, 0, 78, + 0, 0, 78, 0, 0, 82, 10, 79, 78, 0, + 0, 78, 4, 80, 78, 0, 0, 78, 5, 81, + 78, 0, 6, 78, 0, 78, 11, 78, 0, 78, + 36, 78, 0, 78, 37, 78, 0, 78, 38, 78, + 0, 78, 39, 78, 0, 78, 40, 78, 0, 78, + 41, 78, 0, 37, 78, 0, 82, 0, 9, 0, + 43, 78, 44, 0, 8, 43, 74, 44, 0, 12, + 82, 0, 82, 12, 0, 16, 43, 78, 44, 0, + 21, 43, 78, 44, 0, 23, 43, 78, 44, 0, + 27, 43, 44, 0, 8, 0, 8, 48, 78, 49, + 0, 24, 0, 25, 0, 23, 0, 35, 0, 30, + 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 105, 114, 116, 118, 120, 126, 127, 130, 132, 133, + 134, 136, 138, 139, 140, 141, 142, 144, 145, 148, + 150, 152, 161, 168, 178, 189, 191, 193, 195, 197, + 202, 213, 224, 234, 242, 249, 255, 261, 268, 274, + 276, 279, 280, 281, 283, 289, 292, 293, 301, 302, + 316, 322, 324, 326, 328, 330, 333, 335, 337, 339, + 341, 343, 346, 348, 350, 355, 361, 366, 373, 378, + 380, 385, 391, 403, 418, 426, 431, 439, 447, 453, + 481, 486, 491, 496, 501, 506, 511, 516, 525, 541, + 543, 559, 578, 601, 603, 605, 607, 613, 615, 620, + 622, 624, 626, 630 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","NEWLINE", +"AND","OR","NOT","STRING","NAME","NUMBER","ASSIGN_OP","REL_OP","INCR_DECR","Define", +"Break","Quit","Length","Return","For","If","While","Sqrt","Else","Scale","Ibase", +"Obase","Auto","Read","Warranty","Halt","Last","Continue","Print","Limits","UNARY_MINUS", +"History","'+'","'-'","'*'","'/'","'%'","'^'","';'","'('","')'","'{'","'}'", +"','","'['","']'","program","input_item","opt_newline","semicolon_list","statement_list", +"statement_or_error","statement","@1","@2","@3","@4","@5","@6","@7","@8","print_list", +"print_element","opt_else","@9","function","@10","opt_parameter_list","opt_auto_define_list", +"define_list","opt_argument_list","argument_list","opt_expression","return_expression", +"expression","@11","@12","@13","named_expression", NULL +}; +#endif + +static const short yyr1[] = { 0, + 50, 50, 51, 51, 51, 52, 52, 53, 53, 53, + 53, 54, 54, 54, 54, 54, 54, 55, 55, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, + 58, 59, 60, 56, 61, 56, 62, 63, 56, 56, + 64, 56, 65, 65, 66, 66, 67, 68, 67, 70, + 69, 71, 71, 72, 72, 72, 73, 73, 73, 73, + 73, 73, 74, 74, 75, 75, 75, 75, 76, 76, + 77, 77, 79, 78, 80, 78, 81, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 82, 82, 82, + 82, 82, 82, 82 +}; + +static const short yyr2[] = { 0, + 0, 2, 2, 1, 2, 0, 1, 0, 1, 3, + 2, 0, 1, 2, 3, 2, 3, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 0, + 0, 0, 0, 14, 0, 8, 0, 0, 8, 3, + 0, 3, 1, 3, 1, 1, 0, 0, 4, 0, + 12, 0, 1, 0, 3, 3, 1, 3, 4, 3, + 5, 6, 0, 1, 1, 3, 3, 5, 0, 1, + 0, 1, 0, 4, 0, 4, 0, 4, 2, 3, + 3, 3, 3, 3, 3, 3, 2, 1, 1, 3, + 4, 2, 2, 4, 4, 4, 3, 1, 4, 1, + 1, 1, 1, 1 +}; + +static const short yydefact[] = { 1, + 0, 0, 0, 23, 98, 89, 0, 0, 24, 26, + 0, 28, 30, 0, 37, 0, 102, 100, 101, 0, + 20, 27, 104, 25, 41, 21, 103, 0, 0, 0, + 2, 0, 9, 18, 4, 22, 88, 5, 19, 79, + 63, 0, 98, 102, 92, 0, 0, 71, 0, 0, + 0, 0, 0, 0, 0, 87, 0, 0, 0, 13, + 3, 0, 75, 77, 0, 0, 0, 0, 0, 0, + 0, 73, 93, 98, 0, 64, 65, 0, 52, 0, + 0, 72, 69, 0, 0, 0, 0, 97, 45, 42, + 43, 46, 90, 0, 16, 40, 10, 0, 0, 80, + 81, 82, 83, 84, 85, 86, 0, 0, 91, 0, + 99, 57, 0, 0, 53, 94, 29, 0, 70, 35, + 38, 95, 96, 0, 15, 17, 76, 78, 74, 66, + 98, 67, 0, 0, 6, 0, 31, 6, 0, 44, + 0, 58, 0, 7, 0, 60, 0, 69, 0, 6, + 68, 59, 0, 0, 0, 0, 47, 0, 54, 61, + 0, 32, 48, 36, 39, 0, 50, 62, 69, 6, + 0, 0, 0, 0, 55, 56, 0, 33, 49, 51, + 6, 0, 34, 0, 0 +}; + +static const short yydefgoto[] = { 1, + 31, 145, 32, 59, 60, 34, 49, 148, 169, 181, + 138, 51, 139, 55, 90, 91, 164, 170, 35, 172, + 114, 167, 115, 75, 76, 118, 81, 36, 107, 98, + 99, 37 +}; + +static const short yypact[] = {-32768, + 170, 375, 567,-32768, -37,-32768, 120, 15,-32768,-32768, + -38, -34,-32768, -28,-32768, -19, -16,-32768,-32768, -13, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, 567, 567, 213, +-32768, 17,-32768,-32768,-32768, 642, 6,-32768,-32768, 442, + 597, 567, -9,-32768,-32768, -11, 567, 567, 39, 567, + 41, 567, 567, -4, 537,-32768, 122, 505, 16,-32768, +-32768, 305,-32768,-32768, 567, 567, 567, 567, 567, 567, + 567,-32768,-32768, -36, 42, 43, 642, 40, 5, 410, + 44, 642, 567, 419, 567, 428, 466,-32768,-32768,-32768, + 45, 642,-32768, 259, 505,-32768,-32768, 567, 567, 404, + 34, 34, 46, 46, 46, 46, 567, 88,-32768, 627, +-32768, 53, 83, 58, 56,-32768,-32768, 63, 642,-32768, + 642,-32768,-32768, 537,-32768,-32768, 442, -3, 404,-32768, + -26, 642, 57, 66, 113, 23,-32768, 113, 73,-32768, + 337,-32768, 70,-32768, 75, 74, 121, 567, 505, 113, +-32768,-32768, 118, 81, 84, 92, 114, 505, 109,-32768, + 89,-32768,-32768,-32768,-32768, 5,-32768,-32768, 567, 113, + 7, 213, 95, 505,-32768,-32768, 18,-32768,-32768,-32768, + 113, 505,-32768, 140,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, -124,-32768, -30, 1, -2,-32768,-32768,-32768,-32768, +-32768,-32768,-32768,-32768, 22,-32768,-32768,-32768,-32768,-32768, +-32768,-32768, -17,-32768,-32768, -144,-32768, 0,-32768,-32768, +-32768, 144 +}; + + +#define YYLAST 683 + + +static const short yytable[] = { 39, + 63, 33, 40, 156, 47, 41, 41, 65, 48, 175, + 42, 108, 112, 149, 50, 72, 41, 73, 94, 61, + 94, 141, 46, 52, 173, 158, 53, 56, 57, 54, + 146, 79, 66, 67, 68, 69, 70, 71, 42, 88, + 77, 78, 113, 63, 64, 174, 80, 82, 176, 84, + 65, 86, 87, 136, 92, 39, 182, 95, 62, 95, + 147, 96, 97, 180, 100, 101, 102, 103, 104, 105, + 106, 68, 69, 70, 71, 66, 67, 68, 69, 70, + 71, 83, 119, 85, 121, 109, 71, 117, 111, 110, + 134, 124, 126, 3, 125, 5, 6, 127, 128, 7, + 133, 135, 136, 11, 137, 142, 129, 78, 16, 132, + 17, 18, 19, 143, 20, 144, 150, 23, 152, 153, + 159, 154, 27, 92, 28, 63, 64, 43, 155, 160, + 29, 161, 65, 162, 166, 163, 130, 168, 178, 185, + 78, 177, 44, 18, 19, 140, 157, 119, 171, 23, + 45, 0, 0, 0, 27, 165, 0, 66, 67, 68, + 69, 70, 71, 0, 0, 93, 0, 0, 119, 184, + 2, 179, -8, 0, 0, 3, 4, 5, 6, 183, + 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 0, 17, 18, 19, 0, 20, 21, 22, 23, + 24, 25, 26, 0, 27, 0, 28, 0, 0, 0, + 0, -8, 29, 58, 30, -12, 0, 0, 3, 4, + 5, 6, 0, 0, 7, 0, 9, 10, 11, 12, + 13, 14, 15, 16, 0, 17, 18, 19, 0, 20, + 21, 22, 23, 24, 25, 26, 0, 27, 0, 28, + 0, 0, 0, 0, -12, 29, 0, 30, -12, 58, + 0, -14, 0, 0, 3, 4, 5, 6, 0, 0, + 7, 0, 9, 10, 11, 12, 13, 14, 15, 16, + 0, 17, 18, 19, 0, 20, 21, 22, 23, 24, + 25, 26, 0, 27, 0, 28, 0, 0, 0, 0, + -14, 29, 0, 30, -14, 58, 0, -11, 0, 0, + 3, 4, 5, 6, 0, 0, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 3, 0, 5, 6, -11, 29, 7, 30, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 0, 28, 0, 0, 0, 38, 0, 29, + 3, 4, 5, 6, 0, 151, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 0, 63, 64, 0, 0, 29, 0, 30, + 65, 0, 63, 64, 0, 0, 0, 0, 0, 65, + 0, 63, 64, 0, 0, 0, 0, 0, 65, 66, + 67, 68, 69, 70, 71, 66, 67, 68, 69, 70, + 71, 0, 65, 116, 66, 67, 68, 69, 70, 71, + 0, 0, 120, 66, 67, 68, 69, 70, 71, 63, + 64, 122, 0, 0, 0, 0, 65, 66, 67, 68, + 69, 70, 71, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 66, 67, 68, 69, 70, 71, 0, 0, 123, + 3, 4, 5, 6, 0, 0, 7, 0, 9, 10, + 11, 12, 13, 14, 15, 16, 0, 17, 18, 19, + 0, 20, 21, 22, 23, 24, 25, 26, 0, 27, + 0, 28, 3, 89, 5, 6, 0, 29, 7, 30, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 5, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 74, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 0, 0, 16, 0, 17, + 18, 19, 0, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 3, 28, 131, 6, 0, 0, 7, 29, + 0, 0, 11, 0, 0, 63, 64, 16, 0, 17, + 18, 19, 65, 20, 0, 0, 23, 0, 0, 0, + 0, 27, 0, 28, 0, 0, 0, 0, 0, 29, + 0, 0, 0, 0, 0, 0, 0, 66, 67, 68, + 69, 70, 71 +}; + +static const short yycheck[] = { 2, + 4, 1, 3, 148, 43, 43, 43, 11, 43, 3, + 48, 48, 8, 138, 43, 10, 43, 12, 3, 3, + 3, 48, 8, 43, 169, 150, 43, 28, 29, 43, + 8, 43, 36, 37, 38, 39, 40, 41, 48, 44, + 41, 42, 38, 4, 5, 170, 47, 48, 42, 50, + 11, 52, 53, 47, 55, 58, 181, 42, 42, 42, + 38, 46, 62, 46, 65, 66, 67, 68, 69, 70, + 71, 38, 39, 40, 41, 36, 37, 38, 39, 40, + 41, 43, 83, 43, 85, 44, 41, 44, 49, 47, + 8, 47, 95, 6, 94, 8, 9, 98, 99, 12, + 48, 44, 47, 16, 42, 49, 107, 108, 21, 110, + 23, 24, 25, 48, 27, 3, 44, 30, 49, 45, + 3, 48, 35, 124, 37, 4, 5, 8, 8, 49, + 43, 48, 11, 42, 26, 22, 49, 49, 44, 0, + 141, 172, 23, 24, 25, 124, 149, 148, 166, 30, + 7, -1, -1, -1, 35, 158, -1, 36, 37, 38, + 39, 40, 41, -1, -1, 44, -1, -1, 169, 0, + 1, 174, 3, -1, -1, 6, 7, 8, 9, 182, + -1, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, -1, 23, 24, 25, -1, 27, 28, 29, 30, + 31, 32, 33, -1, 35, -1, 37, -1, -1, -1, + -1, 42, 43, 1, 45, 3, -1, -1, 6, 7, + 8, 9, -1, -1, 12, -1, 14, 15, 16, 17, + 18, 19, 20, 21, -1, 23, 24, 25, -1, 27, + 28, 29, 30, 31, 32, 33, -1, 35, -1, 37, + -1, -1, -1, -1, 42, 43, -1, 45, 46, 1, + -1, 3, -1, -1, 6, 7, 8, 9, -1, -1, + 12, -1, 14, 15, 16, 17, 18, 19, 20, 21, + -1, 23, 24, 25, -1, 27, 28, 29, 30, 31, + 32, 33, -1, 35, -1, 37, -1, -1, -1, -1, + 42, 43, -1, 45, 46, 1, -1, 3, -1, -1, + 6, 7, 8, 9, -1, -1, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, 6, -1, 8, 9, 42, 43, 12, 45, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, -1, 37, -1, -1, -1, 3, -1, 43, + 6, 7, 8, 9, -1, 49, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, -1, 4, 5, -1, -1, 43, -1, 45, + 11, -1, 4, 5, -1, -1, -1, -1, -1, 11, + -1, 4, 5, -1, -1, -1, -1, -1, 11, 36, + 37, 38, 39, 40, 41, 36, 37, 38, 39, 40, + 41, -1, 11, 44, 36, 37, 38, 39, 40, 41, + -1, -1, 44, 36, 37, 38, 39, 40, 41, 4, + 5, 44, -1, -1, -1, -1, 11, 36, 37, 38, + 39, 40, 41, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 36, 37, 38, 39, 40, 41, -1, -1, 44, + 6, 7, 8, 9, -1, -1, 12, -1, 14, 15, + 16, 17, 18, 19, 20, 21, -1, 23, 24, 25, + -1, 27, 28, 29, 30, 31, 32, 33, -1, 35, + -1, 37, 6, 7, 8, 9, -1, 43, 12, 45, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, -1, -1, 21, -1, 23, + 24, 25, -1, 27, -1, -1, 30, -1, -1, -1, + -1, 35, 6, 37, 8, 9, -1, -1, 12, 43, + -1, -1, 16, -1, -1, 4, 5, 21, -1, 23, + 24, 25, 11, 27, -1, -1, 30, -1, -1, -1, + -1, 35, -1, 37, -1, -1, -1, -1, -1, 43, + -1, -1, -1, -1, -1, -1, -1, 36, 37, 38, + 39, 40, 41 +}; +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/gnu/share/bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include <alloca.h> +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#include <malloc.h> +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include <malloc.h> + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 196 "/usr/gnu/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 106 "bc.y" +{ + yyval.i_value = 0; + if (interactive && !quiet) + { + printf ("%s\n", BC_VERSION); + welcome (); + } + ; + break;} +case 3: +#line 117 "bc.y" +{ run_code (); ; + break;} +case 4: +#line 119 "bc.y" +{ run_code (); ; + break;} +case 5: +#line 121 "bc.y" +{ + yyerrok; + init_gen (); + ; + break;} +case 7: +#line 128 "bc.y" +{ warn ("newline not allowed"); ; + break;} +case 8: +#line 131 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 12: +#line 137 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 19: +#line 146 "bc.y" +{ yyval.i_value = yyvsp[0].i_value; ; + break;} +case 20: +#line 149 "bc.y" +{ warranty (""); ; + break;} +case 21: +#line 151 "bc.y" +{ limits (); ; + break;} +case 22: +#line 153 "bc.y" +{ + if (yyvsp[0].i_value & 2) + warn ("comparison in expression"); + if (yyvsp[0].i_value & 1) + generate ("W"); + else + generate ("p"); + ; + break;} +case 23: +#line 162 "bc.y" +{ + yyval.i_value = 0; + generate ("w"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + ; + break;} +case 24: +#line 169 "bc.y" +{ + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + ; + break;} +case 25: +#line 179 "bc.y" +{ + warn ("Continue statement"); + if (continue_label == 0) + yyerror ("Continue outside a for"); + else + { + sprintf (genstr, "J%1d:", continue_label); + generate (genstr); + } + ; + break;} +case 26: +#line 190 "bc.y" +{ exit (0); ; + break;} +case 27: +#line 192 "bc.y" +{ generate ("h"); ; + break;} +case 28: +#line 194 "bc.y" +{ generate ("0R"); ; + break;} +case 29: +#line 196 "bc.y" +{ generate ("R"); ; + break;} +case 30: +#line 198 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + ; + break;} +case 31: +#line 203 "bc.y" +{ + if (yyvsp[-1].i_value > 1) + warn ("Comparison in first for expression"); + yyvsp[-1].i_value = next_label++; + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "N%1d:", yyvsp[-1].i_value); + else + sprintf (genstr, "pN%1d:", yyvsp[-1].i_value); + generate (genstr); + ; + break;} +case 32: +#line 214 "bc.y" +{ + if (yyvsp[-1].i_value < 0) generate ("1"); + yyvsp[-1].i_value = next_label++; + sprintf (genstr, "B%1d:J%1d:", yyvsp[-1].i_value, break_label); + generate (genstr); + yyval.i_value = continue_label; + continue_label = next_label++; + sprintf (genstr, "N%1d:", continue_label); + generate (genstr); + ; + break;} +case 33: +#line 225 "bc.y" +{ + if (yyvsp[-1].i_value > 1) + warn ("Comparison in third for expression"); + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value); + else + sprintf (genstr, "pJ%1d:N%1d:", yyvsp[-7].i_value, yyvsp[-4].i_value); + generate (genstr); + ; + break;} +case 34: +#line 235 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = yyvsp[-13].i_value; + continue_label = yyvsp[-5].i_value; + ; + break;} +case 35: +#line 243 "bc.y" +{ + yyvsp[-1].i_value = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + ; + break;} +case 36: +#line 250 "bc.y" +{ + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = yyvsp[-5].i_value; + ; + break;} +case 37: +#line 256 "bc.y" +{ + yyvsp[0].i_value = next_label++; + sprintf (genstr, "N%1d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 38: +#line 262 "bc.y" +{ + yyvsp[0].i_value = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + ; + break;} +case 39: +#line 269 "bc.y" +{ + sprintf (genstr, "J%1d:N%1d:", yyvsp[-7].i_value, break_label); + generate (genstr); + break_label = yyvsp[-4].i_value; + ; + break;} +case 40: +#line 275 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 41: +#line 277 "bc.y" +{ warn ("print statement"); ; + break;} +case 45: +#line 284 "bc.y" +{ + generate ("O"); + generate (yyvsp[0].s_value); + free (yyvsp[0].s_value); + ; + break;} +case 46: +#line 290 "bc.y" +{ generate ("P"); ; + break;} +case 48: +#line 294 "bc.y" +{ + warn ("else clause in if statement"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "J%d:N%1d:", yyvsp[0].i_value, if_label); + generate (genstr); + if_label = yyvsp[0].i_value; + ; + break;} +case 50: +#line 304 "bc.y" +{ + /* Check auto list against parameter list? */ + check_params (yyvsp[-5].a_value,yyvsp[0].a_value); + sprintf (genstr, "F%d,%s.%s[", + lookup(yyvsp[-7].s_value,FUNCTDEF), + arg_str (yyvsp[-5].a_value), arg_str (yyvsp[0].a_value)); + generate (genstr); + free_args (yyvsp[-5].a_value); + free_args (yyvsp[0].a_value); + yyvsp[-8].i_value = next_label; + next_label = 1; + ; + break;} +case 51: +#line 317 "bc.y" +{ + generate ("0R]"); + next_label = yyvsp[-11].i_value; + ; + break;} +case 52: +#line 323 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 54: +#line 327 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 55: +#line 329 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; ; + break;} +case 56: +#line 331 "bc.y" +{ yyval.a_value = yyvsp[-1].a_value; ; + break;} +case 57: +#line 334 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[0].s_value,SIMPLE), FALSE);; + break;} +case 58: +#line 336 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY), FALSE); ; + break;} +case 59: +#line 338 "bc.y" +{ yyval.a_value = nextarg (NULL, lookup (yyvsp[-2].s_value,ARRAY), TRUE); ; + break;} +case 60: +#line 340 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-2].a_value, lookup (yyvsp[0].s_value,SIMPLE), FALSE); ; + break;} +case 61: +#line 342 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-4].a_value, lookup (yyvsp[-2].s_value,ARRAY), FALSE); ; + break;} +case 62: +#line 344 "bc.y" +{ yyval.a_value = nextarg (yyvsp[-5].a_value, lookup (yyvsp[-2].s_value,ARRAY), TRUE); ; + break;} +case 63: +#line 347 "bc.y" +{ yyval.a_value = NULL; ; + break;} +case 65: +#line 351 "bc.y" +{ + if (yyvsp[0].i_value > 1) warn ("comparison in argument"); + yyval.a_value = nextarg (NULL,0,FALSE); + ; + break;} +case 66: +#line 356 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (NULL,1,FALSE); + ; + break;} +case 67: +#line 362 "bc.y" +{ + if (yyvsp[0].i_value > 1) warn ("comparison in argument"); + yyval.a_value = nextarg (yyvsp[-2].a_value,0,FALSE); + ; + break;} +case 68: +#line 367 "bc.y" +{ + sprintf (genstr, "K%d:", -lookup (yyvsp[-2].s_value,ARRAY)); + generate (genstr); + yyval.a_value = nextarg (yyvsp[-4].a_value,1,FALSE); + ; + break;} +case 69: +#line 374 "bc.y" +{ + yyval.i_value = -1; + warn ("Missing expression in for statement"); + ; + break;} +case 71: +#line 381 "bc.y" +{ + yyval.i_value = 0; + generate ("0"); + ; + break;} +case 72: +#line 386 "bc.y" +{ + if (yyvsp[0].i_value > 1) + warn ("comparison in return expresion"); + ; + break;} +case 73: +#line 392 "bc.y" +{ + if (yyvsp[0].c_value != '=') + { + if (yyvsp[-1].i_value < 0) + sprintf (genstr, "DL%d:", -yyvsp[-1].i_value); + else + sprintf (genstr, "l%d:", yyvsp[-1].i_value); + generate (genstr); + } + ; + break;} +case 74: +#line 403 "bc.y" +{ + if (yyvsp[0].i_value > 1) warn("comparison in assignment"); + if (yyvsp[-2].c_value != '=') + { + sprintf (genstr, "%c", yyvsp[-2].c_value); + generate (genstr); + } + if (yyvsp[-3].i_value < 0) + sprintf (genstr, "S%d:", -yyvsp[-3].i_value); + else + sprintf (genstr, "s%d:", yyvsp[-3].i_value); + generate (genstr); + yyval.i_value = 0; + ; + break;} +case 75: +#line 419 "bc.y" +{ + warn("&& operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "DZ%d:p", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 76: +#line 426 "bc.y" +{ + sprintf (genstr, "DZ%d:p1N%d:", yyvsp[-2].i_value, yyvsp[-2].i_value); + generate (genstr); + yyval.i_value = yyvsp[-3].i_value | yyvsp[0].i_value; + ; + break;} +case 77: +#line 432 "bc.y" +{ + warn("|| operator"); + yyvsp[0].i_value = next_label++; + sprintf (genstr, "B%d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 78: +#line 439 "bc.y" +{ + int tmplab; + tmplab = next_label++; + sprintf (genstr, "B%d:0J%d:N%d:1N%d:", + yyvsp[-2].i_value, tmplab, yyvsp[-2].i_value, tmplab); + generate (genstr); + yyval.i_value = yyvsp[-3].i_value | yyvsp[0].i_value; + ; + break;} +case 79: +#line 448 "bc.y" +{ + yyval.i_value = yyvsp[0].i_value; + warn("! operator"); + generate ("!"); + ; + break;} +case 80: +#line 454 "bc.y" +{ + yyval.i_value = 3; + switch (*(yyvsp[-1].s_value)) + { + case '=': + generate ("="); + break; + + case '!': + generate ("#"); + break; + + case '<': + if (yyvsp[-1].s_value[1] == '=') + generate ("{"); + else + generate ("<"); + break; + + case '>': + if (yyvsp[-1].s_value[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + ; + break;} +case 81: +#line 482 "bc.y" +{ + generate ("+"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + ; + break;} +case 82: +#line 487 "bc.y" +{ + generate ("-"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + ; + break;} +case 83: +#line 492 "bc.y" +{ + generate ("*"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + ; + break;} +case 84: +#line 497 "bc.y" +{ + generate ("/"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + ; + break;} +case 85: +#line 502 "bc.y" +{ + generate ("%"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + ; + break;} +case 86: +#line 507 "bc.y" +{ + generate ("^"); + yyval.i_value = yyvsp[-2].i_value | yyvsp[0].i_value; + ; + break;} +case 87: +#line 512 "bc.y" +{ + generate ("n"); + yyval.i_value = yyvsp[0].i_value; + ; + break;} +case 88: +#line 517 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[0].i_value < 0) + sprintf (genstr, "L%d:", -yyvsp[0].i_value); + else + sprintf (genstr, "l%d:", yyvsp[0].i_value); + generate (genstr); + ; + break;} +case 89: +#line 526 "bc.y" +{ + int len = strlen(yyvsp[0].s_value); + yyval.i_value = 1; + if (len == 1 && *yyvsp[0].s_value == '0') + generate ("0"); + else if (len == 1 && *yyvsp[0].s_value == '1') + generate ("1"); + else + { + generate ("K"); + generate (yyvsp[0].s_value); + generate (":"); + } + free (yyvsp[0].s_value); + ; + break;} +case 90: +#line 542 "bc.y" +{ yyval.i_value = yyvsp[-1].i_value | 1; ; + break;} +case 91: +#line 544 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].a_value != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup (yyvsp[-3].s_value,FUNCT), + call_str (yyvsp[-1].a_value)); + free_args (yyvsp[-1].a_value); + } + else + { + sprintf (genstr, "C%d:", lookup (yyvsp[-3].s_value,FUNCT)); + } + generate (genstr); + ; + break;} +case 92: +#line 560 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[0].i_value < 0) + { + if (yyvsp[-1].c_value == '+') + sprintf (genstr, "DA%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value); + else + sprintf (genstr, "DM%d:L%d:", -yyvsp[0].i_value, -yyvsp[0].i_value); + } + else + { + if (yyvsp[-1].c_value == '+') + sprintf (genstr, "i%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value); + else + sprintf (genstr, "d%d:l%d:", yyvsp[0].i_value, yyvsp[0].i_value); + } + generate (genstr); + ; + break;} +case 93: +#line 579 "bc.y" +{ + yyval.i_value = 1; + if (yyvsp[-1].i_value < 0) + { + sprintf (genstr, "DL%d:x", -yyvsp[-1].i_value); + generate (genstr); + if (yyvsp[0].c_value == '+') + sprintf (genstr, "A%d:", -yyvsp[-1].i_value); + else + sprintf (genstr, "M%d:", -yyvsp[-1].i_value); + } + else + { + sprintf (genstr, "l%d:", yyvsp[-1].i_value); + generate (genstr); + if (yyvsp[0].c_value == '+') + sprintf (genstr, "i%d:", yyvsp[-1].i_value); + else + sprintf (genstr, "d%d:", yyvsp[-1].i_value); + } + generate (genstr); + ; + break;} +case 94: +#line 602 "bc.y" +{ generate ("cL"); yyval.i_value = 1;; + break;} +case 95: +#line 604 "bc.y" +{ generate ("cR"); yyval.i_value = 1;; + break;} +case 96: +#line 606 "bc.y" +{ generate ("cS"); yyval.i_value = 1;; + break;} +case 97: +#line 608 "bc.y" +{ + warn ("read function"); + generate ("cI"); yyval.i_value = 1; + ; + break;} +case 98: +#line 614 "bc.y" +{ yyval.i_value = lookup(yyvsp[0].s_value,SIMPLE); ; + break;} +case 99: +#line 616 "bc.y" +{ + if (yyvsp[-1].i_value > 1) warn("comparison in subscript"); + yyval.i_value = lookup(yyvsp[-3].s_value,ARRAY); + ; + break;} +case 100: +#line 621 "bc.y" +{ yyval.i_value = 0; ; + break;} +case 101: +#line 623 "bc.y" +{ yyval.i_value = 1; ; + break;} +case 102: +#line 625 "bc.y" +{ yyval.i_value = 2; ; + break;} +case 103: +#line 627 "bc.y" +{ yyval.i_value = 3; + warn ("History variable"); + ; + break;} +case 104: +#line 631 "bc.y" +{ yyval.i_value = 4; + warn ("Last variable"); + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 498 "/usr/gnu/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 636 "bc.y" + + diff --git a/gnu/usr.bin/bc/bc/bc.h b/gnu/usr.bin/bc/bc/bc.h new file mode 100644 index 00000000000..e5a100941a0 --- /dev/null +++ b/gnu/usr.bin/bc/bc/bc.h @@ -0,0 +1,42 @@ +typedef union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } YYSTYPE; +#define NEWLINE 258 +#define AND 259 +#define OR 260 +#define NOT 261 +#define STRING 262 +#define NAME 263 +#define NUMBER 264 +#define ASSIGN_OP 265 +#define REL_OP 266 +#define INCR_DECR 267 +#define Define 268 +#define Break 269 +#define Quit 270 +#define Length 271 +#define Return 272 +#define For 273 +#define If 274 +#define While 275 +#define Sqrt 276 +#define Else 277 +#define Scale 278 +#define Ibase 279 +#define Obase 280 +#define Auto 281 +#define Read 282 +#define Warranty 283 +#define Halt 284 +#define Last 285 +#define Continue 286 +#define Print 287 +#define Limits 288 +#define UNARY_MINUS 289 +#define History 290 + + +extern YYSTYPE yylval; diff --git a/gnu/usr.bin/bc/bc/bc.y b/gnu/usr.bin/bc/bc/bc.y new file mode 100644 index 00000000000..81e77a88e58 --- /dev/null +++ b/gnu/usr.bin/bc/bc/bc.y @@ -0,0 +1,637 @@ +%{ +/* bc.y: The grammar for a POSIX compatable bc processor with some + extensions to the language. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" +%} + +%start program + +%union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } + +/* Extensions over POSIX bc. + a) NAME was LETTER. This grammer allows longer names. + Single letter names will still work. + b) Relational_expression allowed only one comparison. + This grammar has added boolean expressions with + && (and) || (or) and ! (not) and allowed all of them in + full expressions. + c) Added an else to the if. + d) Call by variable array parameters + e) read() procedure that reads a number under program control from stdin. + f) halt statement that halts the the program under program control. It + is an executed statement. + g) continue statement for for loops. + h) optional expressions in the for loop. + i) print statement to print multiple numbers per line. + j) warranty statement to print an extended warranty notice. + j) limits statement to print the processor's limits. +*/ + +%token <i_value> NEWLINE AND OR NOT +%token <s_value> STRING NAME NUMBER +/* '-', '+' are tokens themselves */ +/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */ +%token <c_value> ASSIGN_OP +/* '==', '<=', '>=', '!=', '<', '>' */ +%token <s_value> REL_OP +/* '++', '--' */ +%token <c_value> INCR_DECR +/* 'define', 'break', 'quit', 'length' */ +%token <i_value> Define Break Quit Length +/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */ +%token <i_value> Return For If While Sqrt Else +/* 'scale', 'ibase', 'obase', 'auto', 'read' */ +%token <i_value> Scale Ibase Obase Auto Read +/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */ +%token <i_value> Warranty, Halt, Last, Continue, Print, Limits +/* 'history' */ +%token <i_value> UNARY_MINUS History + +/* Types of all other things. */ +%type <i_value> expression return_expression named_expression opt_expression +%type <c_value> '+' '-' '*' '/' '%' +%type <a_value> opt_parameter_list opt_auto_define_list define_list +%type <a_value> opt_argument_list argument_list +%type <i_value> program input_item semicolon_list statement_list +%type <i_value> statement function statement_or_error + +/* precedence */ +%left OR +%left AND +%nonassoc NOT +%left REL_OP +%right ASSIGN_OP +%left '+' '-' +%left '*' '/' '%' +%right '^' +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%% +program : /* empty */ + { + $$ = 0; + if (interactive && !quiet) + { + printf ("%s\n", BC_VERSION); + welcome (); + } + } + | program input_item + ; +input_item : semicolon_list NEWLINE + { run_code (); } + | function + { run_code (); } + | error NEWLINE + { + yyerrok; + init_gen (); + } + ; +opt_newline : /* empty */ + | NEWLINE + { warn ("newline not allowed"); } + ; +semicolon_list : /* empty */ + { $$ = 0; } + | statement_or_error + | semicolon_list ';' statement_or_error + | semicolon_list ';' + ; +statement_list : /* empty */ + { $$ = 0; } + | statement_or_error + | statement_list NEWLINE + | statement_list NEWLINE statement_or_error + | statement_list ';' + | statement_list ';' statement + ; +statement_or_error : statement + | error statement + { $$ = $2; } + ; +statement : Warranty + { warranty (""); } + | Limits + { limits (); } + | expression + { + if ($1 & 2) + warn ("comparison in expression"); + if ($1 & 1) + generate ("W"); + else + generate ("p"); + } + | STRING + { + $$ = 0; + generate ("w"); + generate ($1); + free ($1); + } + | Break + { + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } + | Continue + { + warn ("Continue statement"); + if (continue_label == 0) + yyerror ("Continue outside a for"); + else + { + sprintf (genstr, "J%1d:", continue_label); + generate (genstr); + } + } + | Quit + { exit (0); } + | Halt + { generate ("h"); } + | Return + { generate ("0R"); } + | Return '(' return_expression ')' + { generate ("R"); } + | For + { + $1 = break_label; + break_label = next_label++; + } + '(' opt_expression ';' + { + if ($4 > 1) + warn ("Comparison in first for expression"); + $4 = next_label++; + if ($4 < 0) + sprintf (genstr, "N%1d:", $4); + else + sprintf (genstr, "pN%1d:", $4); + generate (genstr); + } + opt_expression ';' + { + if ($7 < 0) generate ("1"); + $7 = next_label++; + sprintf (genstr, "B%1d:J%1d:", $7, break_label); + generate (genstr); + $<i_value>$ = continue_label; + continue_label = next_label++; + sprintf (genstr, "N%1d:", continue_label); + generate (genstr); + } + opt_expression ')' + { + if ($10 > 1) + warn ("Comparison in third for expression"); + if ($10 < 0) + sprintf (genstr, "J%1d:N%1d:", $4, $7); + else + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } + opt_newline statement + { + sprintf (genstr, "J%1d:N%1d:", + continue_label, break_label); + generate (genstr); + break_label = $1; + continue_label = $<i_value>9; + } + | If '(' expression ')' + { + $3 = if_label; + if_label = next_label++; + sprintf (genstr, "Z%1d:", if_label); + generate (genstr); + } + opt_newline statement opt_else + { + sprintf (genstr, "N%1d:", if_label); + generate (genstr); + if_label = $3; + } + | While + { + $1 = next_label++; + sprintf (genstr, "N%1d:", $1); + generate (genstr); + } + '(' expression + { + $4 = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } + ')' opt_newline statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + break_label = $4; + } + | '{' statement_list '}' + { $$ = 0; } + | Print + { warn ("print statement"); } + print_list + ; +print_list : print_element + | print_element ',' print_list + ; +print_element : STRING + { + generate ("O"); + generate ($1); + free ($1); + } + | expression + { generate ("P"); } + ; +opt_else : /* nothing */ + | Else + { + warn ("else clause in if statement"); + $1 = next_label++; + sprintf (genstr, "J%d:N%1d:", $1, if_label); + generate (genstr); + if_label = $1; + } + opt_newline statement +function : Define NAME '(' opt_parameter_list ')' opt_newline + '{' NEWLINE opt_auto_define_list + { + /* Check auto list against parameter list? */ + check_params ($4,$9); + sprintf (genstr, "F%d,%s.%s[", + lookup($2,FUNCTDEF), + arg_str ($4), arg_str ($9)); + generate (genstr); + free_args ($4); + free_args ($9); + $1 = next_label; + next_label = 1; + } + statement_list /* NEWLINE */ '}' + { + generate ("0R]"); + next_label = $1; + } + ; +opt_parameter_list : /* empty */ + { $$ = NULL; } + | define_list + ; +opt_auto_define_list : /* empty */ + { $$ = NULL; } + | Auto define_list NEWLINE + { $$ = $2; } + | Auto define_list ';' + { $$ = $2; } + ; +define_list : NAME + { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);} + | NAME '[' ']' + { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); } + | '*' NAME '[' ']' + { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); } + | define_list ',' NAME '[' ']' + { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); } + | define_list ',' '*' NAME '[' ']' + { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); } + ; +opt_argument_list : /* empty */ + { $$ = NULL; } + | argument_list + ; +argument_list : expression + { + if ($1 > 1) warn ("comparison in argument"); + $$ = nextarg (NULL,0,FALSE); + } + | NAME '[' ']' + { + sprintf (genstr, "K%d:", -lookup ($1,ARRAY)); + generate (genstr); + $$ = nextarg (NULL,1,FALSE); + } + | argument_list ',' expression + { + if ($3 > 1) warn ("comparison in argument"); + $$ = nextarg ($1,0,FALSE); + } + | argument_list ',' NAME '[' ']' + { + sprintf (genstr, "K%d:", -lookup ($3,ARRAY)); + generate (genstr); + $$ = nextarg ($1,1,FALSE); + } + ; +opt_expression : /* empty */ + { + $$ = -1; + warn ("Missing expression in for statement"); + } + | expression + ; +return_expression : /* empty */ + { + $$ = 0; + generate ("0"); + } + | expression + { + if ($1 > 1) + warn ("comparison in return expresion"); + } + ; +expression : named_expression ASSIGN_OP + { + if ($2 != '=') + { + if ($1 < 0) + sprintf (genstr, "DL%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + } + expression + { + if ($4 > 1) warn("comparison in assignment"); + if ($2 != '=') + { + sprintf (genstr, "%c", $2); + generate (genstr); + } + if ($1 < 0) + sprintf (genstr, "S%d:", -$1); + else + sprintf (genstr, "s%d:", $1); + generate (genstr); + $$ = 0; + } + ; + | expression AND + { + warn("&& operator"); + $2 = next_label++; + sprintf (genstr, "DZ%d:p", $2); + generate (genstr); + } + expression + { + sprintf (genstr, "DZ%d:p1N%d:", $2, $2); + generate (genstr); + $$ = $1 | $4; + } + | expression OR + { + warn("|| operator"); + $2 = next_label++; + sprintf (genstr, "B%d:", $2); + generate (genstr); + } + expression + { + int tmplab; + tmplab = next_label++; + sprintf (genstr, "B%d:0J%d:N%d:1N%d:", + $2, tmplab, $2, tmplab); + generate (genstr); + $$ = $1 | $4; + } + | NOT expression + { + $$ = $2; + warn("! operator"); + generate ("!"); + } + | expression REL_OP expression + { + $$ = 3; + switch (*($2)) + { + case '=': + generate ("="); + break; + + case '!': + generate ("#"); + break; + + case '<': + if ($2[1] == '=') + generate ("{"); + else + generate ("<"); + break; + + case '>': + if ($2[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } + | expression '+' expression + { + generate ("+"); + $$ = $1 | $3; + } + | expression '-' expression + { + generate ("-"); + $$ = $1 | $3; + } + | expression '*' expression + { + generate ("*"); + $$ = $1 | $3; + } + | expression '/' expression + { + generate ("/"); + $$ = $1 | $3; + } + | expression '%' expression + { + generate ("%"); + $$ = $1 | $3; + } + | expression '^' expression + { + generate ("^"); + $$ = $1 | $3; + } + | '-' expression %prec UNARY_MINUS + { + generate ("n"); + $$ = $2; + } + | named_expression + { + $$ = 1; + if ($1 < 0) + sprintf (genstr, "L%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + | NUMBER + { + int len = strlen($1); + $$ = 1; + if (len == 1 && *$1 == '0') + generate ("0"); + else if (len == 1 && *$1 == '1') + generate ("1"); + else + { + generate ("K"); + generate ($1); + generate (":"); + } + free ($1); + } + | '(' expression ')' + { $$ = $2 | 1; } + | NAME '(' opt_argument_list ')' + { + $$ = 1; + if ($3 != NULL) + { + sprintf (genstr, "C%d,%s:", + lookup ($1,FUNCT), + call_str ($3)); + free_args ($3); + } + else + { + sprintf (genstr, "C%d:", lookup ($1,FUNCT)); + } + generate (genstr); + } + | INCR_DECR named_expression + { + $$ = 1; + if ($2 < 0) + { + if ($1 == '+') + sprintf (genstr, "DA%d:L%d:", -$2, -$2); + else + sprintf (genstr, "DM%d:L%d:", -$2, -$2); + } + else + { + if ($1 == '+') + sprintf (genstr, "i%d:l%d:", $2, $2); + else + sprintf (genstr, "d%d:l%d:", $2, $2); + } + generate (genstr); + } + | named_expression INCR_DECR + { + $$ = 1; + if ($1 < 0) + { + sprintf (genstr, "DL%d:x", -$1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "A%d:", -$1); + else + sprintf (genstr, "M%d:", -$1); + } + else + { + sprintf (genstr, "l%d:", $1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "i%d:", $1); + else + sprintf (genstr, "d%d:", $1); + } + generate (genstr); + } + | Length '(' expression ')' + { generate ("cL"); $$ = 1;} + | Sqrt '(' expression ')' + { generate ("cR"); $$ = 1;} + | Scale '(' expression ')' + { generate ("cS"); $$ = 1;} + | Read '(' ')' + { + warn ("read function"); + generate ("cI"); $$ = 1; + } + ; +named_expression : NAME + { $$ = lookup($1,SIMPLE); } + | NAME '[' expression ']' + { + if ($3 > 1) warn("comparison in subscript"); + $$ = lookup($1,ARRAY); + } + | Ibase + { $$ = 0; } + | Obase + { $$ = 1; } + | Scale + { $$ = 2; } + | History + { $$ = 3; + warn ("History variable"); + } + | Last + { $$ = 4; + warn ("Last variable"); + } + ; + +%% + diff --git a/gnu/usr.bin/bc/bc/execute.c b/gnu/usr.bin/bc/bc/execute.c new file mode 100644 index 00000000000..c8f3df26135 --- /dev/null +++ b/gnu/usr.bin/bc/bc/execute.c @@ -0,0 +1,786 @@ +/* execute.c - run a bc program. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include <signal.h> +#include "global.h" +#include "proto.h" + + +/* The SIGINT interrupt handling routine. */ + +int had_sigint; + +void +stop_execution (sig) + int sig; +{ + had_sigint = TRUE; + printf ("\n"); + rt_error ("interrupted execution"); +} + + +/* Get the current byte and advance the PC counter. */ + +unsigned char +byte (pc) + program_counter *pc; +{ + int seg, offset; + + seg = pc->pc_addr >> BC_SEG_LOG; + offset = pc->pc_addr++ % BC_SEG_SIZE; + return (functions[pc->pc_func].f_body[seg][offset]); +} + + +/* The routine that actually runs the machine. */ + +void +execute () +{ + int label_num, l_gp, l_off; + bc_label_group *gp; + + char inst, ch; + int new_func; + int var_name; + + int const_base; + + bc_num temp_num; + arg_list *auto_list; + + /* Initialize this run... */ + pc.pc_func = 0; + pc.pc_addr = 0; + runtime_error = FALSE; + init_num (&temp_num); + + /* Set up the interrupt mechanism for an interactive session. */ + if (interactive) + { + signal (SIGINT, stop_execution); + had_sigint = FALSE; + } + + while (pc.pc_addr < functions[pc.pc_func].f_code_size && !runtime_error) + { + inst = byte(&pc); + +#if DEBUG > 3 + { /* Print out address and the stack before each instruction.*/ + int depth; estack_rec *temp = ex_stack; + + printf ("func=%d addr=%d inst=%c\n",pc.pc_func, pc.pc_addr, inst); + if (temp == NULL) printf ("empty stack.\n", inst); + else + { + depth = 1; + while (temp != NULL) + { + printf (" %d = ", depth); + out_num (temp->s_num, 10, out_char); + depth++; + temp = temp->s_next; + } + } + } +#endif + + switch ( inst ) + { + + case 'A' : /* increment array variable (Add one). */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + incr_array (var_name); + break; + + case 'B' : /* Branch to a label if TOS != 0. Remove value on TOS. */ + case 'Z' : /* Branch to a label if TOS == 0. Remove value on TOS. */ + c_code = !is_zero (ex_stack->s_num); + pop (); + case 'J' : /* Jump to a label. */ + label_num = byte(&pc); /* Low order bits first. */ + label_num += byte(&pc) << 8; + if (inst == 'J' || (inst == 'B' && c_code) + || (inst == 'Z' && !c_code)) { + gp = functions[pc.pc_func].f_label; + l_gp = label_num >> BC_LABEL_LOG; + l_off = label_num % BC_LABEL_GROUP; + while (l_gp-- > 0) gp = gp->l_next; + pc.pc_addr = gp->l_adrs[l_off]; + } + break; + + case 'C' : /* Call a function. */ + /* Get the function number. */ + new_func = byte(&pc); + if ((new_func & 0x80) != 0) + new_func = ((new_func << 8) & 0x7f) + byte(&pc); + + /* Check to make sure it is defined. */ + if (!functions[new_func].f_defined) + { + rt_error ("Function %s not defined.", f_names[new_func]); + break; + } + + /* Check and push parameters. */ + process_params (&pc, new_func); + + /* Push auto variables. */ + for (auto_list = functions[new_func].f_autos; + auto_list != NULL; + auto_list = auto_list->next) + auto_var (auto_list->av_name); + + /* Push pc and ibase. */ + fpush (pc.pc_func); + fpush (pc.pc_addr); + fpush (i_base); + + /* Reset pc to start of function. */ + pc.pc_func = new_func; + pc.pc_addr = 0; + break; + + case 'D' : /* Duplicate top of stack */ + push_copy (ex_stack->s_num); + break; + + case 'K' : /* Push a constant */ + /* Get the input base and convert it to a bc number. */ + if (pc.pc_func == 0) + const_base = i_base; + else + const_base = fn_stack->s_val; + if (const_base == 10) + push_b10_const (&pc); + else + push_constant (prog_char, const_base); + break; + + case 'L' : /* load array variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + load_array (var_name); + break; + + case 'M' : /* decrement array variable (Minus!) */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + decr_array (var_name); + break; + + case 'O' : /* Write a string to the output with processing. */ + while ((ch = byte(&pc)) != '"') + if (ch != '\\') + out_schar (ch); + else + { + ch = byte(&pc); + if (ch == '"') break; + switch (ch) + { + case 'a': out_schar (007); break; + case 'b': out_schar ('\b'); break; + case 'f': out_schar ('\f'); break; + case 'n': out_schar ('\n'); break; + case 'q': out_schar ('"'); break; + case 'r': out_schar ('\r'); break; + case 't': out_schar ('\t'); break; + case '\\': out_schar ('\\'); break; + default: break; + } + } + fflush (stdout); + break; + + case 'R' : /* Return from function */ + if (pc.pc_func != 0) + { + /* "Pop" autos and parameters. */ + pop_vars(functions[pc.pc_func].f_autos); + pop_vars(functions[pc.pc_func].f_params); + /* reset the pc. */ + fpop (); + pc.pc_addr = fpop (); + pc.pc_func = fpop (); + } + else + rt_error ("Return from main program."); + break; + + case 'S' : /* store array variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + store_array (var_name); + break; + + case 'T' : /* Test tos for zero */ + c_code = is_zero (ex_stack->s_num); + assign (c_code); + break; + + case 'W' : /* Write the value on the top of the stack. */ + case 'P' : /* Write the value on the top of the stack. No newline. */ + out_num (ex_stack->s_num, o_base, out_char); + if (inst == 'W') out_char ('\n'); + store_var (4); /* Special variable "last". */ + fflush (stdout); + pop (); + break; + + case 'c' : /* Call special function. */ + new_func = byte(&pc); + + switch (new_func) + { + case 'L': /* Length function. */ + /* For the number 0.xxxx, 0 is not significant. */ + if (ex_stack->s_num->n_len == 1 && + ex_stack->s_num->n_scale != 0 && + ex_stack->s_num->n_value[0] == 0 ) + int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); + else + int2num (&ex_stack->s_num, ex_stack->s_num->n_len + + ex_stack->s_num->n_scale); + break; + + case 'S': /* Scale function. */ + int2num (&ex_stack->s_num, ex_stack->s_num->n_scale); + break; + + case 'R': /* Square Root function. */ + if (!bc_sqrt (&ex_stack->s_num, scale)) + rt_error ("Square root of a negative number"); + break; + + case 'I': /* Read function. */ + push_constant (input_char, i_base); + break; + } + break; + + case 'd' : /* Decrement number */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + decr_var (var_name); + break; + + case 'h' : /* Halt the machine. */ + exit (0); + + case 'i' : /* increment number */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + incr_var (var_name); + break; + + case 'l' : /* load variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + load_var (var_name); + break; + + case 'n' : /* Negate top of stack. */ + bc_sub (_zero_, ex_stack->s_num, &ex_stack->s_num, 0); + break; + + case 'p' : /* Pop the execution stack. */ + pop (); + break; + + case 's' : /* store variable */ + var_name = byte(&pc); + if ((var_name & 0x80) != 0) + var_name = ((var_name << 8) & 0x7f) + byte(&pc); + store_var (var_name); + break; + + case 'w' : /* Write a string to the output. */ + while ((ch = byte(&pc)) != '"') out_schar (ch); + fflush (stdout); + break; + + case 'x' : /* Exchange Top of Stack with the one under the tos. */ + if (check_stack(2)) { + bc_num temp = ex_stack->s_num; + ex_stack->s_num = ex_stack->s_next->s_num; + ex_stack->s_next->s_num = temp; + } + break; + + case '0' : /* Load Constant 0. */ + push_copy (_zero_); + break; + + case '1' : /* Load Constant 0. */ + push_copy (_one_); + break; + + case '!' : /* Negate the boolean value on top of the stack. */ + c_code = is_zero (ex_stack->s_num); + assign (c_code); + break; + + case '&' : /* compare greater than */ + if (check_stack(2)) + { + c_code = !is_zero (ex_stack->s_next->s_num) + && !is_zero (ex_stack->s_num); + pop (); + assign (c_code); + } + break; + + case '|' : /* compare greater than */ + if (check_stack(2)) + { + c_code = !is_zero (ex_stack->s_next->s_num) + || !is_zero (ex_stack->s_num); + pop (); + assign (c_code); + } + break; + + case '+' : /* add */ + if (check_stack(2)) + { + bc_add (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0); + pop(); + pop(); + push_num (temp_num); + init_num (&temp_num); + } + break; + + case '-' : /* subtract */ + if (check_stack(2)) + { + bc_sub (ex_stack->s_next->s_num, ex_stack->s_num, &temp_num, 0); + pop(); + pop(); + push_num (temp_num); + init_num (&temp_num); + } + break; + + case '*' : /* multiply */ + if (check_stack(2)) + { + bc_multiply (ex_stack->s_next->s_num, ex_stack->s_num, + &temp_num, scale); + pop(); + pop(); + push_num (temp_num); + init_num (&temp_num); + } + break; + + case '/' : /* divide */ + if (check_stack(2)) + { + if (bc_divide (ex_stack->s_next->s_num, + ex_stack->s_num, &temp_num, scale) == 0) + { + pop(); + pop(); + push_num (temp_num); + init_num (&temp_num); + } + else + rt_error ("Divide by zero"); + } + break; + + case '%' : /* remainder */ + if (check_stack(2)) + { + if (is_zero (ex_stack->s_num)) + rt_error ("Modulo by zero"); + else + { + bc_modulo (ex_stack->s_next->s_num, + ex_stack->s_num, &temp_num, scale); + pop(); + pop(); + push_num (temp_num); + init_num (&temp_num); + } + } + break; + + case '^' : /* raise */ + if (check_stack(2)) + { + bc_raise (ex_stack->s_next->s_num, + ex_stack->s_num, &temp_num, scale); + if (is_zero (ex_stack->s_next->s_num) && is_neg (ex_stack->s_num)) + rt_error ("divide by zero"); + pop(); + pop(); + push_num (temp_num); + init_num (&temp_num); + } + break; + + case '=' : /* compare equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) == 0; + pop (); + assign (c_code); + } + break; + + case '#' : /* compare not equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) != 0; + pop (); + assign (c_code); + } + break; + + case '<' : /* compare less than */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) == -1; + pop (); + assign (c_code); + } + break; + + case '{' : /* compare less than or equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) <= 0; + pop (); + assign (c_code); + } + break; + + case '>' : /* compare greater than */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) == 1; + pop (); + assign (c_code); + } + break; + + case '}' : /* compare greater than or equal */ + if (check_stack(2)) + { + c_code = bc_compare (ex_stack->s_next->s_num, + ex_stack->s_num) >= 0; + pop (); + assign (c_code); + } + break; + + default : /* error! */ + rt_error ("bad instruction: inst=%c", inst); + } + } + + /* Clean up the function stack and pop all autos/parameters. */ + while (pc.pc_func != 0) + { + pop_vars(functions[pc.pc_func].f_autos); + pop_vars(functions[pc.pc_func].f_params); + fpop (); + pc.pc_addr = fpop (); + pc.pc_func = fpop (); + } + + /* Clean up the execution stack. */ + while (ex_stack != NULL) pop(); + + /* Clean up the interrupt stuff. */ + if (interactive) + { + signal (SIGINT, use_quit); + if (had_sigint) + printf ("Interruption completed.\n"); + } +} + + +/* Prog_char gets another byte from the program. It is used for + conversion of text constants in the code to numbers. */ + +char +prog_char () +{ + return byte(&pc); +} + + +/* Read a character from the standard input. This function is used + by the "read" function. */ + +char +input_char () +{ + char in_ch; + + /* Get a character from the standard input for the read function. */ + in_ch = getchar(); + + /* Check for a \ quoted newline. */ + if (in_ch == '\\') + { + in_ch = getchar(); + if (in_ch == '\n') + in_ch = getchar(); + } + + /* Classify and preprocess the input character. */ + if (isdigit(in_ch)) + return (in_ch - '0'); + if (in_ch >= 'A' && in_ch <= 'F') + return (in_ch + 10 - 'A'); + if (in_ch >= 'a' && in_ch <= 'f') + return (in_ch + 10 - 'a'); + if (in_ch == '.' || in_ch == '+' || in_ch == '-') + return (in_ch); + if (in_ch <= ' ') + return (' '); + + return (':'); +} + + +/* Push_constant converts a sequence of input characters as returned + by IN_CHAR into a number. The number is pushed onto the execution + stack. The number is converted as a number in base CONV_BASE. */ + +void +push_constant (in_char, conv_base) + char (*in_char)(VOID); + int conv_base; +{ + int digits; + bc_num build, temp, result, mult, divisor; + char in_ch, first_ch; + char negative; + + /* Initialize all bc numbers */ + init_num (&temp); + init_num (&result); + init_num (&mult); + build = copy_num (_zero_); + negative = FALSE; + + /* The conversion base. */ + int2num (&mult, conv_base); + + /* Get things ready. */ + in_ch = in_char(); + while (in_ch == ' ') + in_ch = in_char(); + + if (in_ch == '+') + in_ch = in_char(); + else + if (in_ch == '-') + { + negative = TRUE; + in_ch = in_char(); + } + + /* Check for the special case of a single digit. */ + if (in_ch < 16) + { + first_ch = in_ch; + in_ch = in_char(); + if (in_ch < 16 && first_ch >= conv_base) + first_ch = conv_base - 1; + int2num (&build, (int) first_ch); + } + + /* Convert the integer part. */ + while (in_ch < 16) + { + if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; + bc_multiply (build, mult, &result, 0); + int2num (&temp, (int) in_ch); + bc_add (result, temp, &build, 0); + in_ch = in_char(); + } + if (in_ch == '.') + { + in_ch = in_char(); + if (in_ch >= conv_base) in_ch = conv_base-1; + free_num (&result); + free_num (&temp); + divisor = copy_num (_one_); + result = copy_num (_zero_); + digits = 0; + while (in_ch < 16) + { + bc_multiply (result, mult, &result, 0); + int2num (&temp, (int) in_ch); + bc_add (result, temp, &result, 0); + bc_multiply (divisor, mult, &divisor, 0); + digits++; + in_ch = in_char(); + if (in_ch < 16 && in_ch >= conv_base) in_ch = conv_base-1; + } + bc_divide (result, divisor, &result, digits); + bc_add (build, result, &build, 0); + } + + /* Final work. */ + if (negative) + bc_sub (_zero_, build, &build, 0); + + push_num (build); + free_num (&temp); + free_num (&result); + free_num (&mult); +} + + +/* When converting base 10 constants from the program, we use this + more efficient way to convert them to numbers. PC tells where + the constant starts and is expected to be advanced to after + the constant. */ + +void +push_b10_const (pc) + program_counter *pc; +{ + bc_num build; + program_counter look_pc; + int kdigits, kscale; + char inchar; + char *ptr; + + /* Count the digits and get things ready. */ + look_pc = *pc; + kdigits = 0; + kscale = 0; + inchar = byte (&look_pc); + while (inchar != '.' && inchar != ':') + { + kdigits++; + inchar = byte(&look_pc); + } + if (inchar == '.' ) + { + inchar = byte(&look_pc); + while (inchar != ':') + { + kscale++; + inchar = byte(&look_pc); + } + } + + /* Get the first character again and move the pc. */ + inchar = byte(pc); + + /* Secial cases of 0, 1, and A-F single inputs. */ + if (kdigits == 1 && kscale == 0) + { + if (inchar == 0) + { + push_copy (_zero_); + inchar = byte(pc); + return; + } + if (inchar == 1) { + push_copy (_one_); + inchar = byte(pc); + return; + } + if (inchar > 9) + { + init_num (&build); + int2num (&build, inchar); + push_num (build); + inchar = byte(pc); + return; + } + } + + /* Build the new number. */ + if (kdigits == 0) + { + build = new_num (1,kscale); + ptr = build->n_value; + *ptr++ = 0; + } + else + { + build = new_num (kdigits,kscale); + ptr = build->n_value; + } + + while (inchar != ':') + { + if (inchar != '.') + if (inchar > 9) + *ptr++ = 9; + else + *ptr++ = inchar; + inchar = byte(pc); + } + push_num (build); +} + + +/* Put the correct value on the stack for C_CODE. Frees TOS num. */ + +void +assign (c_code) + char c_code; +{ + free_num (&ex_stack->s_num); + if (c_code) + ex_stack->s_num = copy_num (_one_); + else + ex_stack->s_num = copy_num (_zero_); +} diff --git a/gnu/usr.bin/bc/bc/fix-libmath_h b/gnu/usr.bin/bc/bc/fix-libmath_h new file mode 100644 index 00000000000..5a002c4f324 --- /dev/null +++ b/gnu/usr.bin/bc/bc/fix-libmath_h @@ -0,0 +1,8 @@ +ed libmath.h <<EOS-EOS +1,1s/^/"/ +1,\$s/\$/\\\\/ +\$,\$d +\$,\$s/\\\\\$/"/ +w +q +EOS-EOS diff --git a/gnu/usr.bin/bc/bc/global.c b/gnu/usr.bin/bc/bc/global.c new file mode 100644 index 00000000000..3165434fae9 --- /dev/null +++ b/gnu/usr.bin/bc/bc/global.c @@ -0,0 +1,42 @@ +/* global.c: This defines the global variables. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" + +/* Since we want to define them here, we use the following define. */ +#undef EXTERN +#define EXTERN + +/* Define all the global variables for bc. */ +#include "global.h" + +#ifndef BC_MATH_FILE +CONST char libmath[] = +#include "libmath.h" +; +#endif diff --git a/gnu/usr.bin/bc/bc/libmath.b b/gnu/usr.bin/bc/bc/libmath.b new file mode 100644 index 00000000000..7549a576492 --- /dev/null +++ b/gnu/usr.bin/bc/bc/libmath.b @@ -0,0 +1,279 @@ +/* libmath.b for GNU bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +scale = 20 + +/* Uses the fact that e^x = (e^(x/2))^2 + When x is small enough, we use the series: + e^x = 1 + x + x^2/2! + x^3/3! + ... +*/ + +define e(x) { + auto a, d, e, f, i, m, n, v, z + + /* a - holds x^y of x^y/y! */ + /* d - holds y! */ + /* e - is the value x^y/y! */ + /* v - is the sum of the e's */ + /* f - number of times x was divided by 2. */ + /* m - is 1 if x was minus. */ + /* i - iteration count. */ + /* n - the scale to compute the sum. */ + /* z - orignal scale. */ + + /* Check the sign of x. */ + if (x<0) { + m = 1 + x = -x + } + + /* Precondition x. */ + z = scale; + n = 6 + z + .44*x; + scale = scale(x)+1; + while (x > 1) { + f += 1; + x /= 2; + scale += 1; + } + + /* Initialize the variables. */ + scale = n; + v = 1+x + a = x + d = 1 + + for (i=2; 1; i++) { + e = (a *= x) / (d *= i) + if (e == 0) { + if (f>0) while (f--) v = v*v; + scale = z + if (m) return (1/v); + return (v/1); + } + v += e + } +} + +/* Natural log. Uses the fact that ln(x^2) = 2*ln(x) + The series used is: + ln(x) = 2(a+a^3/3+a^5/5+...) where a=(x-1)/(x+1) +*/ + +define l(x) { + auto e, f, i, m, n, v, z + + /* return something for the special case. */ + if (x <= 0) return ((1 - 10^scale)/1) + + /* Precondition x to make .5 < x < 2.0. */ + z = scale; + scale = 6 + scale; + f = 2; + i=0 + while (x >= 2) { /* for large numbers */ + f *= 2; + x = sqrt(x); + } + while (x <= .5) { /* for small numbers */ + f *= 2; + x = sqrt(x); + } + + /* Set up the loop. */ + v = n = (x-1)/(x+1) + m = n*n + + /* Sum the series. */ + for (i=3; 1; i+=2) { + e = (n *= m) / i + if (e == 0) { + v = f*v + scale = z + return (v/1) + } + v += e + } +} + +/* Sin(x) uses the standard series: + sin(x) = x - x^3/3! + x^5/5! - x^7/7! ... */ + +define s(x) { + auto e, i, m, n, s, v, z + + /* precondition x. */ + z = scale + scale = 1.1*z + 2; + v = a(1) + if (x < 0) { + m = 1; + x = -x; + } + scale = 0 + n = (x / v + 2 )/4 + x = x - 4*n*v + if (n%2) x = -x + + /* Do the loop. */ + scale = z + 2; + v = e = x + s = -x*x + for (i=3; 1; i+=2) { + e *= s/(i*(i-1)) + if (e == 0) { + scale = z + if (m) return (-v/1); + return (v/1); + } + v += e + } +} + +/* Cosine : cos(x) = sin(x+pi/2) */ +define c(x) { + auto v; + scale += 1; + v = s(x+a(1)*2); + scale -= 1; + return (v/1); +} + +/* Arctan: Using the formula: + atan(x) = atan(c) + atan((x-c)/(1+xc)) for a small c (.2 here) + For under .2, use the series: + atan(x) = x - x^3/3 + x^5/5 - x^7/7 + ... */ + +define a(x) { + auto a, e, f, i, m, n, s, v, z + + /* a is the value of a(.2) if it is needed. */ + /* f is the value to multiply by a in the return. */ + /* e is the value of the current term in the series. */ + /* v is the accumulated value of the series. */ + /* m is 1 or -1 depending on x (-x -> -1). results are divided by m. */ + /* i is the denominator value for series element. */ + /* n is the numerator value for the series element. */ + /* s is -x*x. */ + /* z is the saved user's scale. */ + + /* Negative x? */ + m = 1; + if (x<0) { + m = -1; + x = -x; + } + + /* Special case and for fast answers */ + if (x==1) { + if (scale <= 25) return (.7853981633974483096156608/m) + if (scale <= 40) return (.7853981633974483096156608458198757210492/m) + if (scale <= 60) \ + return (.785398163397448309615660845819875721049292349843776455243736/m) + } + if (x==.2) { + if (scale <= 25) return (.1973955598498807583700497/m) + if (scale <= 40) return (.1973955598498807583700497651947902934475/m) + if (scale <= 60) \ + return (.197395559849880758370049765194790293447585103787852101517688/m) + } + + + /* Save the scale. */ + z = scale; + + /* Note: a and f are known to be zero due to being auto vars. */ + /* Calculate atan of a known number. */ + if (x > .2) { + scale = z+5; + a = a(.2); + } + + /* Precondition x. */ + scale = z+3; + while (x > .2) { + f += 1; + x = (x-.2) / (1+x*.2); + } + + /* Initialize the series. */ + v = n = x; + s = -x*x; + + /* Calculate the series. */ + for (i=3; 1; i+=2) { + e = (n *= s) / i; + if (e == 0) { + scale = z; + return ((f*a+v)/m); + } + v += e + } +} + + +/* Bessel function of integer order. Uses the following: + j(-n,x) = (-1)^n*j(n,x) + j(n,x) = x^n/(2^n*n!) * (1 - x^2/(2^2*1!*(n+1)) + x^4/(2^4*2!*(n+1)*(n+2)) + - x^6/(2^6*3!*(n+1)*(n+2)*(n+3)) .... ) +*/ +define j(n,x) { + auto a, d, e, f, i, m, s, v, z + + /* Make n an integer and check for negative n. */ + z = scale; + scale = 0; + n = n/1; + if (n<0) { + n = -n; + if (n%2 == 1) m = 1; + } + + /* Compute the factor of x^n/(2^n*n!) */ + f = 1; + for (i=2; i<=n; i++) f = f*i; + scale = 1.5*z; + f = x^n / 2^n / f; + + /* Initialize the loop .*/ + v = e = 1; + s = -x*x/4 + scale = 1.5*z + + /* The Loop.... */ + for (i=1; 1; i++) { + e = e * s / i / (n+i); + if (e == 0) { + scale = z + if (m) return (-f*v/1); + return (f*v/1); + } + v += e; + } +} diff --git a/gnu/usr.bin/bc/bc/libmath.h b/gnu/usr.bin/bc/bc/libmath.h new file mode 100644 index 00000000000..9481bb9301e --- /dev/null +++ b/gnu/usr.bin/bc/bc/libmath.h @@ -0,0 +1,40 @@ +"@iK20:s2:p@r\ +@iF1,5.6,7,8,9,10,11,12,13,14[l5:0<Z1:1s11:pl5:ns5:pN1:l2:s14:\ +pK6:l14:+K.44:l5:*+s12:pl5:cS1+s2:pN2:l5:1>Z3:l9:1+s9:pl5:K2:\ +/s5:pl2:1+s2:pJ2:N3:l12:s2:p1l5:+s13:pl5:s6:p1s7:pK2:s10:pN5:\ +1B6:J4:N7:l10:i10:pJ5:N6:l6:l5:*s6:l7:l10:*s7:/s8:pl8:0=Z8:l9:\ +0>Z9:N10:l9:d9:Z11:l13:l13:*s13:pJ10:N11:N9:l14:s2:pl11:Z12:1\ +l13:/RN12:l13:1/RN8:l13:l8:+s13:pJ7:N4:0R]@r\ +@iF2,5.8,9,10,11,12,13,14[l5:0{Z1:1K10:l2:^-1/RN1:l2:s14:pK6:\ +l2:+s2:pK2:s9:p0s10:pN2:l5:K2:}Z3:l9:K2:*s9:pl5:cRs5:pJ2:N3:N4:\ +l5:K.5:{Z5:l9:K2:*s9:pl5:cRs5:pJ4:N5:l5:1-l5:1+/s12:s13:pl12:\ +l12:*s11:pK3:s10:pN7:1B8:J6:N9:l10:K2:+s10:pJ7:N8:l12:l11:*s12:\ +l10:/s8:pl8:0=Z10:l9:l13:*s13:pl14:s2:pl13:1/RN10:l13:l8:+s13:\ +pJ9:N6:0R]@r\ +@iF3,5.8,10,11,12,15,13,14[l2:s14:pK1.1:l14:*K2:+s2:p1C4,0:s13:\ +pl5:0<Z1:1s11:pl5:ns5:pN1:0s2:pl5:l13:/K2:+K4:/s12:pl5:K4:l12:\ +*l13:*-s5:pl12:K2:%Z2:l5:ns5:pN2:l14:K2:+s2:pl5:s8:s13:pl5:nl5:\ +*s15:pK3:s10:pN4:1B5:J3:N6:l10:K2:+s10:pJ4:N5:l8:l15:l10:l10:\ +1-*/*s8:pl8:0=Z7:l14:s2:pl11:Z8:l13:n1/RN8:l13:1/RN7:l13:l8:+\ +s13:pJ6:N3:0R]@r\ +@iF5,5.13[l2:1+s2:pl5:1C4,0:K2:*+C3,0:s13:pl2:1-s2:pl13:1/R0R]\ +@r\ +@iF4,5.6,8,9,10,11,12,15,13,14[1s11:pl5:0<Z1:1ns11:pl5:ns5:pN1:\ +l5:1=Z2:l2:K25:{Z3:K.7853981633974483096156608:l11:/RN3:l2:K40\ +:{Z4:K.7853981633974483096156608458198757210492:l11:/RN4:l2:K\ +60:{Z5:K.785398163397448309615660845819875721049292349843776455243736\ +:l11:/RN5:N2:l5:K.2:=Z6:l2:K25:{Z7:K.1973955598498807583700497\ +:l11:/RN7:l2:K40:{Z8:K.1973955598498807583700497651947902934475\ +:l11:/RN8:l2:K60:{Z9:K.197395559849880758370049765194790293447585103787852101517688\ +:l11:/RN9:N6:l2:s14:pl5:K.2:>Z10:l14:K5:+s2:pK.2:C4,0:s6:pN10:\ +l14:K3:+s2:pN11:l5:K.2:>Z12:l9:1+s9:pl5:K.2:-1l5:K.2:*+/s5:pJ11:N12:\ +l5:s12:s13:pl5:nl5:*s15:pK3:s10:pN14:1B15:J13:N16:l10:K2:+s10:\ +pJ14:N15:l12:l15:*s12:l10:/s8:pl8:0=Z17:l14:s2:pl9:l6:*l13:+l11:\ +/RN17:l13:l8:+s13:pJ16:N13:0R]@r\ +@iF6,12,5.6,7,8,9,10,11,15,13,14[l2:s14:p0s2:pl12:1/s12:pl12:\ +0<Z1:l12:ns12:pl12:K2:%1=Z2:1s11:pN2:N1:1s9:pK2:s10:pN4:l10:l12:\ +{B5:J3:N6:l10:i10:pJ4:N5:l9:l10:*s9:pJ6:N3:K1.5:l14:*s2:pl5:l12:\ +^K2:l12:^/l9:/s9:p1s8:s13:pl5:nl5:*K4:/s15:pK1.5:l14:*s2:p1s10:\ +pN8:1B9:J7:N10:l10:i10:pJ8:N9:l8:l15:*l10:/l12:l10:+/s8:pl8:0\ +=Z11:l14:s2:pl11:Z12:l9:nl13:*1/RN12:l9:l13:*1/RN11:l13:l8:+s13:\ +pJ10:N7:0R]@r" diff --git a/gnu/usr.bin/bc/bc/load.c b/gnu/usr.bin/bc/bc/load.c new file mode 100644 index 00000000000..055a7c05c96 --- /dev/null +++ b/gnu/usr.bin/bc/bc/load.c @@ -0,0 +1,348 @@ +/* load.c: This code "loads" code into the code segments. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" + +/* Load variables. */ + +program_counter load_adr; +char load_str; +char load_const; + +/* Initialize the load sequence. */ +void +init_load () +{ + clear_func(0); + load_adr.pc_func = 0; + load_adr.pc_addr = 0; + load_str = FALSE; + load_const = FALSE; +} + +/* addbyte adds one BYTE to the current code segment. */ +void +addbyte (byte) + char byte; +{ + int seg, offset, func; + + /* If there was an error, don't continue. */ + if (had_error) return; + + /* Calculate the segment and offset. */ + seg = load_adr.pc_addr >> BC_SEG_LOG; + offset = load_adr.pc_addr++ % BC_SEG_SIZE; + func = load_adr.pc_func; + + if (seg >= BC_MAX_SEGS) + { + yyerror ("Function too big."); + return; + } + + if (functions[func].f_body[seg] == NULL) + functions[func].f_body[seg] = (char *) bc_malloc (BC_SEG_SIZE); + + /* Store the byte. */ + functions[func].f_body[seg][offset] = byte; + functions[func].f_code_size++; +} + + +/* Define a label LAB to be the current program counter. */ + +void +def_label (lab) + long lab; +{ + bc_label_group *temp; + int group, offset, func; + + /* Get things ready. */ + group = lab >> BC_LABEL_LOG; + offset = lab % BC_LABEL_GROUP; + func = load_adr.pc_func; + + /* Make sure there is at least one label group. */ + if (functions[func].f_label == NULL) + { + functions[func].f_label = + (bc_label_group *) bc_malloc (sizeof(bc_label_group)); + functions[func].f_label->l_next = NULL; + } + + /* Add the label group. */ + temp = functions[func].f_label; + while (group > 0) + { + if (temp->l_next == NULL) + { + temp->l_next = (bc_label_group *) bc_malloc (sizeof(bc_label_group)); + temp->l_next->l_next = NULL; + } + temp = temp->l_next; + group --; + } + + /* Define it! */ + temp->l_adrs [offset] = load_adr.pc_addr; +} + +/* Several instructions have integers in the code. They + are all known to be legal longs. So, no error code + is added. STR is the pointer to the load string and + must be moved to the last non-digit character. */ + +long +long_val (str) + char **str; +{ int val = 0; + char neg = FALSE; + + if (**str == '-') + { + neg = TRUE; + (*str)++; + } + while (isdigit(**str)) + val = val*10 + *(*str)++ - '0'; + + if (neg) + return -val; + else + return val; +} + + +/* load_code loads the CODE into the machine. */ + +void +load_code (code) + char *code; +{ + char *str; + long ap_name; /* auto or parameter name. */ + long label_no; + long vaf_name; /* variable, array or function number. */ + long func; + program_counter save_adr; + + /* Initialize. */ + str = code; + + /* Scan the code. */ + while (*str != 0) + { + /* If there was an error, don't continue. */ + if (had_error) return; + + if (load_str) + { + if (*str == '"') load_str = FALSE; + addbyte (*str++); + } + else + if (load_const) + { + if (*str == '\n') + str++; + else + { + if (*str == ':') + { + load_const = FALSE; + addbyte (*str++); + } + else + if (*str == '.') + addbyte (*str++); + else + if (*str >= 'A') + addbyte (*str++ + 10 - 'A'); + else + addbyte (*str++ - '0'); + } + } + else + { + switch (*str) + { + + case '"': /* Starts a string. */ + load_str = TRUE; + break; + + case 'N': /* A label */ + str++; + label_no = long_val (&str); + def_label (label_no); + break; + + case 'B': /* Branch to label. */ + case 'J': /* Jump to label. */ + case 'Z': /* Branch Zero to label. */ + addbyte(*str++); + label_no = long_val (&str); + if (label_no > 65535L) + { /* Better message? */ + fprintf (stderr,"Program too big.\n"); + exit(1); + } + addbyte ( (char) label_no & 0xFF); + addbyte ( (char) label_no >> 8); + break; + + case 'F': /* A function, get the name and initialize it. */ + str++; + func = long_val (&str); + clear_func (func); +#if DEBUG > 2 + printf ("Loading function number %d\n", func); +#endif + /* get the parameters */ + while (*str++ != '.') + { + if (*str == '.') + { + str++; + break; + } + if (*str == '*') + { + str++; + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("var parameter number %d\n", ap_name); +#endif + functions[(int)func].f_params = + nextarg (functions[(int)func].f_params, ap_name, + TRUE); + } + else + { + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("parameter number %d\n", ap_name); +#endif + functions[(int)func].f_params = + nextarg (functions[(int)func].f_params, ap_name, + FALSE); + } + } + + /* get the auto vars */ + while (*str != '[') + { + if (*str == ',') str++; + ap_name = long_val (&str); +#if DEBUG > 2 + printf ("auto number %d\n", ap_name); +#endif + functions[(int)func].f_autos = + nextarg (functions[(int)func].f_autos, ap_name, FALSE); + } + save_adr = load_adr; + load_adr.pc_func = func; + load_adr.pc_addr = 0; + break; + + case ']': /* A function end */ + functions[load_adr.pc_func].f_defined = TRUE; + load_adr = save_adr; + break; + + case 'C': /* Call a function. */ + addbyte (*str++); + func = long_val (&str); + if (func < 128) + addbyte ( (char) func); + else + { + addbyte ((func >> 8) & 0xff | 0x80); + addbyte (func & 0xff); + } + if (*str == ',') str++; + while (*str != ':') + addbyte (*str++); + addbyte (':'); + break; + + case 'c': /* Call a special function. */ + addbyte (*str++); + addbyte (*str); + break; + + case 'K': /* A constant.... may have an "F" in it. */ + addbyte (*str); + load_const = TRUE; + break; + + case 'd': /* Decrement. */ + case 'i': /* Increment. */ + case 'l': /* Load. */ + case 's': /* Store. */ + case 'A': /* Array Increment */ + case 'M': /* Array Decrement */ + case 'L': /* Array Load */ + case 'S': /* Array Store */ + addbyte (*str++); + vaf_name = long_val (&str); + if (vaf_name < 128) + addbyte (vaf_name); + else + { + addbyte ((vaf_name >> 8) & 0xff | 0x80); + addbyte (vaf_name & 0xff); + } + break; + + case '@': /* A command! */ + switch (*(++str)) + { + case 'i': + init_load (); + break; + case 'r': + execute (); + break; + } + break; + + case '\n': /* Ignore the newlines */ + break; + + default: /* Anything else */ + addbyte (*str); + } + str++; + } + } +} diff --git a/gnu/usr.bin/bc/bc/main.c b/gnu/usr.bin/bc/bc/main.c new file mode 100644 index 00000000000..29a334fb0fb --- /dev/null +++ b/gnu/usr.bin/bc/bc/main.c @@ -0,0 +1,330 @@ +/* main.c: The main program for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include <signal.h> +#include "global.h" +#include "proto.h" +#include "getopt.h" + + +/* Variables for processing multiple files. */ +char first_file; +extern FILE *yyin; + +/* Points to the last node in the file name list for easy adding. */ +static file_node *last = NULL; + +#ifdef READLINE +/* Readline support. */ +extern char *rl_readline_name; +extern FILE *rl_instream; +#endif + +/* long option support */ +static struct option long_options[] = +{ + {"compile", 0, &compile_only, TRUE}, + {"mathlib", 0, &use_math, TRUE}, + {"quiet", 0, &quiet, TRUE}, + {"standard", 0, &std_only, TRUE}, + {"version", 0, 0, 'v'}, + {"warn", 0, &warn_not_std, TRUE}, + + {0, 0, 0, 0} +}; + + +void +parse_args (argc, argv) + int argc; + char **argv; +{ + int optch; + int long_index; + file_node *temp; + + /* Force getopt to initialize. Depends on GNU getopt. */ + optind = 0; + + /* Parse the command line */ + while (1) + { + optch = getopt_long (argc, argv, "lciqsvw", long_options, &long_index); + + if (optch == EOF) /* End of arguments. */ + break; + + switch (optch) + { + case 'c': /* compile only */ + compile_only = TRUE; + break; + + case 'l': /* math lib */ + use_math = TRUE; + break; + + case 'i': /* force interactive */ + interactive = TRUE; + break; + + case 'q': /* quiet mode */ + quiet = TRUE; + break; + + case 's': /* Non standard features give errors. */ + std_only = TRUE; + break; + + case 'v': /* Print the version. */ + printf ("%s\n", BC_VERSION); + exit (0); + break; + + case 'w': /* Non standard features give warnings. */ + warn_not_std = TRUE; + break; + } + } + + /* Add file names to a list of files to process. */ + while (optind < argc) + { + temp = (file_node *) bc_malloc(sizeof(file_node)); + temp->name = argv[optind]; + temp->next = NULL; + if (last == NULL) + file_names = temp; + else + last->next = temp; + last = temp; + optind++; + } +} + +/* The main program for bc. */ +int +main (argc, argv) + int argc; + char *argv[]; +{ + char *env_value; + char *env_argv[30]; + int env_argc; + + /* Initialize many variables. */ + compile_only = FALSE; + use_math = FALSE; + warn_not_std = FALSE; + std_only = FALSE; + if (isatty(0) && isatty(1)) + interactive = TRUE; + else + interactive = FALSE; + quiet = FALSE; + file_names = NULL; + +#ifdef HAVE_SETVBUF + /* attempt to simplify interaction with applications such as emacs */ + (void) setvbuf(stdout, NULL, _IOLBF, 0); +#endif + + /* Environment arguments. */ + env_value = getenv ("BC_ENV_ARGS"); + if (env_value != NULL) + { + env_argc = 1; + env_argv[0] = "BC_ENV_ARGS"; + while (*env_value != 0) + { + if (*env_value != ' ') + { + env_argv[env_argc++] = env_value; + while (*env_value != ' ' && *env_value != 0) + env_value++; + if (*env_value != 0) + { + *env_value = 0; + env_value++; + } + } + else + env_value++; + } + parse_args (env_argc, env_argv); + } + + /* Command line arguments. */ + parse_args (argc, argv); + + /* Other environment processing. */ + if (getenv ("POSIXLY_CORRECT") != NULL) + std_only = TRUE; + + env_value = getenv ("BC_LINE_LENGTH"); + if (env_value != NULL) + { + line_size = atoi (env_value); + if (line_size < 2) + line_size = 70; + } + else + line_size = 70; + + /* Initialize the machine. */ + init_storage(); + init_load(); + + /* Set up interrupts to print a message. */ + if (interactive) + signal (SIGINT, use_quit); + + /* Initialize the front end. */ + init_tree(); + init_gen (); + is_std_in = FALSE; + first_file = TRUE; + if (!open_new_file ()) + exit (1); + +#ifdef READLINE + if (interactive) { + /* Readline support. Set both application name and input file. */ + rl_readline_name = "bc"; + rl_instream = stdin; + using_history (); + } +#endif + + /* Do the parse. */ + yyparse (); + + /* End the compile only output with a newline. */ + if (compile_only) + printf ("\n"); + + exit (0); +} + + +/* This is the function that opens all the files. + It returns TRUE if the file was opened, otherwise + it returns FALSE. */ + +int +open_new_file () +{ + FILE *new_file; + file_node *temp; + + /* Set the line number. */ + line_no = 1; + + /* Check to see if we are done. */ + if (is_std_in) return (FALSE); + + /* Open the other files. */ + if (use_math && first_file) + { +#ifdef BC_MATH_FILE + /* Make the first file be the math library. */ + new_file = fopen (BC_MATH_FILE, "r"); + use_math = FALSE; + if (new_file != NULL) + { + new_yy_file (new_file); + return TRUE; + } + else + { + fprintf (stderr, "Math Library unavailable.\n"); + exit (1); + } +#else + /* Load the code from a precompiled version of the math libarary. */ + extern char libmath[]; + char tmp; + /* These MUST be in the order of first mention of each function. + That is why "a" comes before "c" even though "a" is defined after + after "c". "a" is used in "s"! */ + tmp = lookup ("e", FUNCT); + tmp = lookup ("l", FUNCT); + tmp = lookup ("s", FUNCT); + tmp = lookup ("a", FUNCT); + tmp = lookup ("c", FUNCT); + tmp = lookup ("j", FUNCT); + load_code (libmath); +#endif + } + + /* One of the argv values. */ + if (file_names != NULL) + { + new_file = fopen (file_names->name, "r"); + if (new_file != NULL) + { + new_yy_file (new_file); + temp = file_names; + file_name = temp->name; + file_names = temp->next; + free (temp); + return TRUE; + } + fprintf (stderr, "File %s is unavailable.\n", file_names->name); + exit (1); + } + + /* If we fall through to here, we should return stdin. */ + new_yy_file (stdin); + is_std_in = TRUE; + return TRUE; +} + + +/* Set yyin to the new file. */ + +void +new_yy_file (file) + FILE *file; +{ + if (!first_file) fclose (yyin); + yyin = file; + first_file = FALSE; +} + + +/* Message to use quit. */ + +void +use_quit (sig) + int sig; +{ + printf ("\n(interrupt) use quit to exit.\n"); + signal (SIGINT, use_quit); +} diff --git a/gnu/usr.bin/bc/bc/sbc.y b/gnu/usr.bin/bc/bc/sbc.y new file mode 100644 index 00000000000..9e1bd339ead --- /dev/null +++ b/gnu/usr.bin/bc/bc/sbc.y @@ -0,0 +1,446 @@ +%{ +/* sbc.y: A POSIX bc processor written for minix with no extensions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" /* To get the global variables. */ +#include "proto.h" +%} + +%start program + +%union { + char *s_value; + char c_value; + int i_value; + arg_list *a_value; + } + +%token <i_value> NEWLINE AND OR NOT +%token <s_value> STRING NAME NUMBER +/* '-', '+' are tokens themselves */ +%token <c_value> ASSIGN_OP +/* '=', '+=', '-=', '*=', '/=', '%=', '^=' */ +%token <s_value> REL_OP +/* '==', '<=', '>=', '!=', '<', '>' */ +%token <c_value> INCR_DECR +/* '++', '--' */ +%token <i_value> Define Break Quit Length +/* 'define', 'break', 'quit', 'length' */ +%token <i_value> Return For If While Sqrt Else +/* 'return', 'for', 'if', 'while', 'sqrt', 'else' */ +%token <i_value> Scale Ibase Obase Auto Read +/* 'scale', 'ibase', 'obase', 'auto', 'read' */ +%token <i_value> Warranty, Halt, Last, Continue, Print, Limits +/* 'warranty', 'halt', 'last', 'continue', 'print', 'limits' */ + +/* The types of all other non-terminals. */ +%type <i_value> expression named_expression return_expression +%type <a_value> opt_parameter_list parameter_list opt_auto_define_list +%type <a_value> define_list opt_argument_list argument_list +%type <i_value> program input_item semicolon_list statement_list +%type <i_value> statement_or_error statement function relational_expression + +/* precedence */ +%nonassoc REL_OP +%right ASSIGN_OP +%left '+' '-' +%left '*' '/' '%' +%right '^' +%nonassoc UNARY_MINUS +%nonassoc INCR_DECR + +%% +program : /* empty */ + { + $$ = 0; + std_only = TRUE; + if (interactive) + { + printf ("s%s\n", BC_VERSION); + welcome(); + } + } + | program input_item + ; +input_item : semicolon_list NEWLINE + { run_code(); } + | function + { run_code(); } + | error NEWLINE + { + yyerrok; + init_gen() ; + } + ; +semicolon_list : /* empty */ + { $$ = 0; } + | statement_or_error + | semicolon_list ';' statement_or_error + | semicolon_list ';' + ; +statement_list : /* empty */ + { $$ = 0; } + | statement + | statement_list NEWLINE + | statement_list NEWLINE statement + | statement_list ';' + | statement_list ';' statement + ; +statement_or_error : statement + | error statement + { $$ = $2; } + ; +statement : Warranty + { warranty("s"); } + | expression + { + if ($1 & 1) + generate ("W"); + else + generate ("p"); + } + | STRING + { + $$ = 0; + generate ("w"); + generate ($1); + free ($1); + } + | Break + { + if (break_label == 0) + yyerror ("Break outside a for/while"); + else + { + sprintf (genstr, "J%1d:", break_label); + generate (genstr); + } + } + | Quit + { exit(0); } + | Return + { generate ("0R"); } + | Return '(' return_expression ')' + { generate ("R"); } + | For + { + $1 = break_label; + break_label = next_label++; + } + '(' expression ';' + { + $4 = next_label++; + sprintf (genstr, "pN%1d:", $4); + generate (genstr); + } + relational_expression ';' + { + $7 = next_label++; + sprintf (genstr, "B%1d:J%1d:", $7, break_label); + generate (genstr); + $<i_value>$ = next_label++; + sprintf (genstr, "N%1d:", $<i_value>$); + generate (genstr); + } + expression ')' + { + sprintf (genstr, "pJ%1d:N%1d:", $4, $7); + generate (genstr); + } + statement + { + sprintf (genstr, "J%1d:N%1d:", $<i_value>9, + break_label); + generate (genstr); + break_label = $1; + } + | If '(' relational_expression ')' + { + $3 = next_label++; + sprintf (genstr, "Z%1d:", $3); + generate (genstr); + } + statement + { + sprintf (genstr, "N%1d:", $3); + generate (genstr); + } + | While + { + $1 = next_label++; + sprintf (genstr, "N%1d:", $1); + generate (genstr); + } + '(' relational_expression + { + $4 = break_label; + break_label = next_label++; + sprintf (genstr, "Z%1d:", break_label); + generate (genstr); + } + ')' statement + { + sprintf (genstr, "J%1d:N%1d:", $1, break_label); + generate (genstr); + break_label = $4; + } + | '{' statement_list '}' + { $$ = 0; } + ; +function : Define NAME '(' opt_parameter_list ')' '{' + NEWLINE opt_auto_define_list + { + check_params ($4,$8); + sprintf (genstr, "F%d,%s.%s[", lookup($2,FUNCT), + arg_str ($4), arg_str ($8)); + generate (genstr); + free_args ($4); + free_args ($8); + $1 = next_label; + next_label = 0; + } + statement_list NEWLINE '}' + { + generate ("0R]"); + next_label = $1; + } + ; +opt_parameter_list : /* empty */ + { $$ = NULL; } + | parameter_list + ; +parameter_list : NAME + { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); } + ; +opt_auto_define_list : /* empty */ + { $$ = NULL; } + | Auto define_list NEWLINE + { $$ = $2; } + | Auto define_list ';' + { $$ = $2; } + ; +define_list : NAME + { $$ = nextarg (NULL, lookup($1,SIMPLE), FALSE); } + | NAME '[' ']' + { $$ = nextarg (NULL, lookup($1,ARRAY), FALSE); } + | define_list ',' NAME + { $$ = nextarg ($1, lookup($3,SIMPLE), FALSE); } + | define_list ',' NAME '[' ']' + { $$ = nextarg ($1, lookup($3,ARRAY), FALSE); } + ; +opt_argument_list : /* empty */ + { $$ = NULL; } + | argument_list + ; +argument_list : expression + { $$ = nextarg (NULL,0, FALSE); } + | argument_list ',' expression + { $$ = nextarg ($1,0, FALSE); } + ; +relational_expression : expression + { $$ = 0; } + | expression REL_OP expression + { + $$ = 0; + switch (*($2)) + { + case '=': + generate ("="); + break; + case '!': + generate ("#"); + break; + case '<': + if ($2[1] == '=') + generate ("{"); + else + generate ("<"); + break; + case '>': + if ($2[1] == '=') + generate ("}"); + else + generate (">"); + break; + } + } + ; +return_expression : /* empty */ + { + $$ = 0; + generate ("0"); + } + | expression + ; +expression : named_expression ASSIGN_OP + { + if ($2 != '=') + { + if ($1 < 0) + sprintf (genstr, "DL%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + } + expression + { + $$ = 0; + if ($2 != '=') + { + sprintf (genstr, "%c", $2); + generate (genstr); + } + if ($1 < 0) + sprintf (genstr, "S%d:", -$1); + else + sprintf (genstr, "s%d:", $1); + generate (genstr); + } + | expression '+' expression + { generate ("+"); } + | expression '-' expression + { generate ("-"); } + | expression '*' expression + { generate ("*"); } + | expression '/' expression + { generate ("/"); } + | expression '%' expression + { generate ("%"); } + | expression '^' expression + { generate ("^"); } + | '-' expression %prec UNARY_MINUS + { generate ("n"); $$ = 1;} + | named_expression + { + $$ = 1; + if ($1 < 0) + sprintf (genstr, "L%d:", -$1); + else + sprintf (genstr, "l%d:", $1); + generate (genstr); + } + | NUMBER + { + int len = strlen($1); + $$ = 1; + if (len == 1 && *$1 == '0') + generate ("0"); + else + { + if (len == 1 && *$1 == '1') + generate ("1"); + else + { + generate ("K"); + generate ($1); + generate (":"); + } + free ($1); + } + } + | '(' expression ')' + { $$ = 1; } + | NAME '(' opt_argument_list ')' + { + $$ = 1; + if ($3 != NULL) + { + sprintf (genstr, "C%d,%s:", lookup($1,FUNCT), + arg_str ($3)); + free_args ($3); + } + else + sprintf (genstr, "C%d:", lookup($1,FUNCT)); + generate (genstr); + } + | INCR_DECR named_expression + { + $$ = 1; + if ($2 < 0) + { + if ($1 == '+') + sprintf (genstr, "DA%d:L%d:", -$2, -$2); + else + sprintf (genstr, "DM%d:L%d:", -$2, -$2); + } + else + { + if ($1 == '+') + sprintf (genstr, "i%d:l%d:", $2, $2); + else + sprintf (genstr, "d%d:l%d:", $2, $2); + } + generate (genstr); + } + | named_expression INCR_DECR + { + $$ = 1; + if ($1 < 0) + { + sprintf (genstr, "DL%d:x", -$1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "A%d:", -$1); + else + sprintf (genstr, "M%d:", -$1); + } + else + { + sprintf (genstr, "l%d:", $1); + generate (genstr); + if ($2 == '+') + sprintf (genstr, "i%d:", $1); + else + sprintf (genstr, "d%d:", $1); + } + generate (genstr); + } + | Length '(' expression ')' + { generate ("cL"); $$ = 1;} + | Sqrt '(' expression ')' + { generate ("cR"); $$ = 1;} + | Scale '(' expression ')' + { generate ("cS"); $$ = 1;} + ; +named_expression : NAME + { $$ = lookup($1,SIMPLE); } + | NAME '[' expression ']' + { $$ = lookup($1,ARRAY); } + | Ibase + { $$ = 0; } + | Obase + { $$ = 1; } + | Scale + { $$ = 2; } + ; + +%% diff --git a/gnu/usr.bin/bc/bc/scan.c b/gnu/usr.bin/bc/bc/scan.c new file mode 100644 index 00000000000..50438796d72 --- /dev/null +++ b/gnu/usr.bin/bc/bc/scan.c @@ -0,0 +1,1612 @@ +/* A lexical scanner generated by flex */ + +/* scanner skeleton version: + * $Header: /cvs/OpenBSD/src/gnu/usr.bin/bc/bc/Attic/scan.c,v 1.1 1998/06/29 00:19:05 millert Exp $ + */ + +#define FLEX_SCANNER + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +#include <osfcn.h> + +/* use prototypes in function declarations */ +#define YY_USE_PROTOS + +/* the "const" storage-class-modifier is valid */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#ifdef __STDC__ + +#ifdef __GNUC__ +#include <stddef.h> +void *malloc( size_t ); +void free( void* ); +#else +#include <stdlib.h> +#endif /* __GNUC__ */ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + + +#ifdef __TURBOC__ +#define YY_USE_CONST +#endif + + +#ifndef YY_USE_CONST +#define const +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +/* we can't get here if it's an ANSI C compiler, or a C++ compiler, + * so it's got to be a K&R compiler, and therefore there's no standard + * place from which to include these definitions + */ +/* char *malloc(); +int free(); */ +int read(); +#endif + + +/* amount of stuff to slurp up with each read */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* returned upon end-of-file */ +#define YY_END_TOK 0 + +/* copy whatever the last rule matched to the standard output */ + +/* cast to (char *) is because for 8-bit chars, yytext is (unsigned char *) */ +/* this used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite() + */ +#define ECHO (void) fwrite( (char *) yytext, yyleng, 1, yyout ) + +/* gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#define YY_INPUT(buf,result,max_size) \ + if ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#define YY_NULL 0 + +/* no semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#define yyterminate() return ( YY_NULL ) + +/* report a fatal error */ + +/* The funky do-while is used to turn this macro definition into + * a single C statement (which needs a semi-colon terminator). + * This avoids problems with code like: + * + * if ( something_happens ) + * YY_FATAL_ERROR( "oops, the something happened" ); + * else + * everything_okay(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the YY_FATAL_ERROR() call. + */ + +#define YY_FATAL_ERROR(msg) \ + do \ + { \ + (void) fputs( msg, stderr ); \ + (void) putc( '\n', stderr ); \ + exit( 1 ); \ + } \ + while ( 0 ) + +/* default yywrap function - always treat EOF as an EOF */ +#define yywrap() 1 + +/* enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN + */ +#define BEGIN yy_start = 1 + 2 * + +/* action number for EOF rule of a given start state */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* special action meaning "start processing a new file" */ +#define YY_NEW_FILE \ + do \ + { \ + yy_init_buffer( yy_current_buffer, yyin ); \ + yy_load_buffer_state(); \ + } \ + while ( 0 ) + +/* default declaration of generated scanner - a define so the user can + * easily add parameters + */ +#define YY_DECL int yylex YY_PROTO(( void )) + +/* code executed at the end of each rule */ +#define YY_BREAK break; + +#define YY_END_OF_BUFFER_CHAR 0 + +#ifndef YY_BUF_SIZE +#define YY_BUF_SIZE (YY_READ_BUF_SIZE * 2) /* size of default input buffer */ +#endif + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +#define YY_CHAR unsigned char +# line 1 "scan.l" +#define INITIAL 0 +# line 2 "scan.l" +/* scan.l: the (f)lex description file for the scanner. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "bc.h" +#include "global.h" +#include "proto.h" +#include <errno.h> + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* Force . as last for now. */ +#define DOT_IS_LAST + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +#ifdef READLINE +/* Support for the readline and history libraries. This allows + nicer input on the interactive part of input. */ + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + rl_input((char *)buf, &result, max_size) + +/* Variables to help interface readline with bc. */ +static char *rl_line = (char *)NULL; +static char *rl_start = (char *)NULL; +static char rl_len = 0; + +/* Definitions for readline access. */ +extern FILE *rl_instream; +_PROTOTYPE(char *readline, (char *)); + +/* Needed here? */ +extern FILE *yyin; + +/* rl_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + rl_instream (stdin), use readline. Otherwise, just read it. +*/ + +static void +rl_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (yyin != rl_instream) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (rl_len == 0) + { + if (rl_line) + free(rl_line); + rl_line = readline (""); + if (rl_line == NULL) { + /* end of file */ + *result = 0; + rl_len = 0; + return; + } + rl_len = strlen (rl_line)+1; + if (rl_len != 1) + add_history (rl_line); + rl_line[rl_len-1] = '\n'; + printf ("\r"); + fflush (stdout); + } + + if (rl_len <= max) + { + strncpy (buf, rl_line, rl_len); + *result = rl_len; + rl_len = 0; + } + else + { + strncpy (buf, rl_line, max); + *result = max; + rl_len -= max; + } +} +#else +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#endif +#define slcomment 1 +# line 141 "scan.l" + +/* done after the current pattern has been matched and before the + * corresponding action - sets up yytext + */ +#define YY_DO_BEFORE_ACTION \ + yytext = yy_bp; \ + yyleng = yy_cp - yy_bp; \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* return all but the first 'n' matched characters back to the input stream */ +#define yyless(n) \ + do \ + { \ + /* undo effects of setting up yytext */ \ + *yy_cp = yy_hold_char; \ + yy_c_buf_p = yy_cp = yy_bp + n; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext ) + + +struct yy_buffer_state + { + FILE *yy_input_file; + + YY_CHAR *yy_ch_buf; /* input buffer */ + YY_CHAR *yy_buf_pos; /* current position in input buffer */ + + /* size of input buffer in bytes, not including room for EOB characters*/ + int yy_buf_size; + + /* number of characters read into yy_ch_buf, not including EOB characters */ + int yy_n_chars; + + int yy_eof_status; /* whether we've seen an EOF on this buffer */ +#define EOF_NOT_SEEN 0 + /* "pending" happens when the EOF has been seen but there's still + * some text process + */ +#define EOF_PENDING 1 +#define EOF_DONE 2 + }; + +static YY_BUFFER_STATE yy_current_buffer; + +/* we provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state" + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed */ +static YY_CHAR yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + + +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +#ifndef YY_USER_INIT +#define YY_USER_INIT +#endif + +extern YY_CHAR *yytext; +extern int yyleng; +extern FILE *yyin, *yyout; + +YY_CHAR *yytext; +int yyleng; + +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +#define YY_END_OF_BUFFER 45 +typedef int yy_state_type; +static const short int yy_accept[298] = + { 0, + 0, 0, 2, 2, 45, 43, 38, 36, 30, 43, + 1, 31, 43, 27, 31, 27, 27, 26, 31, 42, + 34, 32, 34, 43, 27, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 43, 2, 2, 3, 2, 2, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 38, + 34, 0, 41, 32, 28, 35, 42, 0, 39, 42, + 42, 0, 33, 37, 40, 40, 40, 40, 40, 40, + + 40, 40, 40, 40, 10, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 29, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 42, 0, 0, 42, 0, + 40, 40, 40, 40, 40, 9, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + + 2, 2, 2, 2, 2, 2, 16, 40, 40, 40, + 17, 19, 40, 40, 20, 40, 40, 40, 40, 6, + 18, 40, 40, 12, 40, 40, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 5, 40, 40, 40, + 14, 40, 40, 15, 24, 40, 13, 40, 11, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 40, 4, 40, 7, 25, 8, 40, 2, + 2, 2, 2, 2, 2, 2, 40, 21, 40, 2, + 2, 2, 23, 22, 2, 2, 0 + + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 5, 6, 1, 7, 8, 1, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 1, 18, 19, + 20, 21, 1, 1, 22, 22, 22, 22, 22, 22, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 23, 24, 25, 26, 27, 1, 28, 29, 30, 31, + + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 37, 49, 37, + 50, 37, 51, 52, 53, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[54] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1 + } ; + +static const short int yy_base[302] = + { 0, + 0, 0, 53, 0, 525, 526, 522, 526, 503, 517, + 526, 501, 512, 526, 499, 95, 94, 94, 99, 105, + 498, 114, 497, 513, 495, 466, 468, 470, 479, 471, + 467, 0, 81, 102, 105, 479, 462, 458, 473, 94, + 104, 452, 0, 501, 526, 482, 139, 0, 481, 492, + 0, 479, 131, 132, 131, 125, 132, 478, 150, 477, + 493, 475, 160, 115, 117, 126, 130, 125, 446, 183, + 184, 186, 187, 123, 445, 180, 185, 192, 440, 489, + 526, 485, 526, 526, 526, 526, 158, 486, 526, 162, + 221, 485, 526, 526, 0, 440, 454, 444, 451, 437, + + 437, 442, 434, 451, 0, 432, 436, 436, 447, 438, + 437, 195, 444, 426, 425, 433, 526, 0, 466, 0, + 178, 0, 0, 0, 0, 222, 464, 0, 230, 233, + 463, 0, 417, 65, 189, 208, 193, 205, 213, 220, + 214, 235, 416, 218, 224, 227, 241, 234, 237, 243, + 246, 231, 232, 245, 0, 275, 460, 278, 279, 459, + 419, 432, 412, 422, 425, 0, 409, 408, 408, 406, + 418, 415, 404, 408, 401, 416, 398, 406, 397, 398, + 403, 287, 438, 288, 437, 182, 250, 239, 270, 275, + 391, 266, 268, 271, 273, 274, 288, 279, 285, 281, + + 299, 390, 292, 287, 293, 298, 0, 399, 400, 394, + 0, 0, 392, 401, 0, 385, 384, 398, 382, 0, + 0, 383, 395, 0, 398, 393, 376, 294, 303, 302, + 375, 374, 306, 312, 373, 305, 308, 313, 310, 372, + 371, 314, 317, 370, 335, 332, 0, 376, 384, 370, + 0, 379, 367, 0, 0, 371, 0, 370, 0, 362, + 325, 336, 322, 361, 137, 323, 360, 359, 331, 358, + 333, 357, 356, 0, 353, 0, 0, 0, 355, 349, + 343, 327, 342, 340, 334, 338, 346, 0, 238, 344, + 236, 339, 0, 0, 177, 102, 526, 392, 120, 395, + + 398 + } ; + +static const short int yy_def[302] = + { 0, + 297, 1, 297, 3, 297, 297, 297, 297, 297, 298, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 297, 300, 300, 297, 300, 301, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 300, 297, + 297, 298, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 299, 299, 299, 299, 299, 299, + + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 297, 300, 300, 300, + 301, 300, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 300, 297, 297, 297, 297, 297, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 300, 300, 300, 300, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 63, 63, 63, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 299, 299, 299, 299, + 299, 299, 299, 299, 299, 299, 299, 299, 299, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 299, 299, 299, 299, 299, 299, 299, 63, + 63, 63, 63, 63, 63, 63, 299, 299, 299, 63, + 63, 63, 299, 299, 63, 63, 0, 297, 297, 297, + + 297 + } ; + +static const short int yy_nxt[580] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 15, 16, 14, 17, 18, 19, 20, 14, 21, 22, + 23, 20, 14, 24, 14, 25, 6, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 32, 32, 35, 32, + 32, 36, 37, 38, 39, 40, 32, 32, 41, 32, + 14, 42, 14, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 51, 52, 53, 51, 54, 55, 56, 57, + 51, 58, 59, 60, 57, 51, 61, 51, 62, 43, + 63, 64, 65, 66, 67, 68, 69, 70, 71, 69, + 69, 72, 69, 69, 73, 74, 75, 76, 77, 69, + + 69, 78, 69, 51, 79, 51, 86, 86, 102, 89, + 87, 186, 133, 84, 84, 87, 103, 88, 84, 90, + 93, 91, 95, 113, 93, 93, 91, 93, 92, 93, + 104, 115, 106, 81, 105, 128, 107, 114, 116, 93, + 108, 82, 125, 122, 123, 125, 129, 126, 130, 133, + 123, 123, 126, 130, 127, 131, 132, 137, 136, 135, + 132, 132, 133, 132, 133, 132, 139, 148, 138, 120, + 133, 283, 133, 133, 156, 132, 133, 133, 159, 156, + 82, 157, 122, 159, 133, 160, 133, 133, 133, 133, + 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, + + 133, 133, 133, 133, 133, 133, 133, 134, 133, 133, + 140, 150, 142, 144, 151, 147, 143, 145, 141, 153, + 187, 146, 176, 227, 133, 189, 154, 133, 152, 133, + 133, 133, 133, 133, 133, 90, 133, 91, 182, 133, + 133, 177, 91, 182, 92, 183, 184, 129, 188, 130, + 190, 184, 133, 185, 130, 133, 131, 191, 192, 193, + 133, 133, 194, 195, 196, 133, 197, 133, 198, 199, + 201, 133, 200, 203, 133, 204, 205, 228, 133, 133, + 206, 133, 133, 133, 133, 229, 133, 294, 133, 202, + 133, 156, 133, 133, 87, 159, 156, 133, 157, 87, + + 159, 88, 160, 182, 184, 230, 231, 236, 182, 184, + 183, 185, 232, 133, 233, 133, 234, 133, 133, 235, + 133, 133, 133, 237, 238, 239, 133, 240, 133, 241, + 243, 260, 133, 244, 133, 133, 246, 245, 261, 133, + 133, 133, 262, 264, 267, 133, 133, 263, 270, 133, + 133, 265, 133, 133, 266, 133, 268, 133, 269, 133, + 133, 133, 271, 272, 133, 280, 282, 281, 284, 133, + 133, 285, 133, 286, 133, 295, 291, 293, 133, 133, + 133, 133, 133, 133, 292, 133, 133, 133, 296, 133, + 133, 133, 82, 82, 82, 118, 290, 118, 121, 121, + + 121, 289, 288, 287, 133, 133, 133, 133, 133, 133, + 279, 278, 277, 276, 275, 274, 273, 133, 133, 133, + 133, 133, 133, 133, 259, 258, 257, 256, 255, 254, + 253, 252, 251, 250, 249, 248, 247, 242, 133, 159, + 156, 226, 225, 224, 223, 222, 221, 220, 219, 218, + 217, 216, 215, 214, 213, 212, 211, 210, 209, 208, + 207, 159, 156, 133, 133, 91, 158, 119, 181, 180, + 179, 178, 175, 174, 173, 172, 171, 170, 169, 168, + 167, 166, 165, 164, 163, 162, 161, 91, 158, 83, + 80, 155, 149, 133, 123, 94, 120, 120, 123, 124, + + 123, 120, 119, 117, 112, 111, 110, 109, 101, 100, + 99, 98, 97, 96, 84, 94, 81, 81, 84, 85, + 84, 83, 81, 80, 297, 5, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297 + } ; + +static const short int yy_chk[580] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 16, 17, 33, 19, + 18, 134, 134, 17, 16, 18, 33, 18, 19, 20, + 22, 20, 299, 40, 22, 22, 20, 22, 20, 22, + 34, 41, 35, 22, 34, 56, 35, 40, 41, 22, + 35, 47, 53, 47, 56, 54, 57, 55, 57, 296, + 53, 54, 55, 57, 55, 57, 59, 66, 65, 64, + 59, 59, 64, 59, 65, 59, 68, 74, 67, 59, + 74, 265, 68, 66, 87, 59, 63, 67, 90, 87, + 121, 87, 121, 90, 265, 90, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 70, 76, 71, 72, 77, 73, 71, 72, 70, 78, + 135, 72, 112, 186, 295, 137, 78, 76, 77, 186, + 70, 71, 77, 72, 73, 91, 135, 91, 126, 78, + 137, 112, 91, 126, 91, 126, 129, 130, 136, 130, + 138, 129, 138, 129, 130, 136, 130, 139, 140, 141, + 139, 141, 142, 144, 145, 144, 146, 140, 147, 148, + 150, 145, 149, 151, 146, 152, 153, 187, 152, 153, + 154, 148, 142, 291, 149, 188, 188, 289, 147, 150, + 150, 156, 154, 151, 158, 159, 156, 187, 156, 158, + + 159, 158, 159, 182, 184, 189, 190, 196, 182, 184, + 182, 184, 192, 192, 193, 193, 194, 189, 194, 195, + 195, 196, 190, 197, 198, 199, 198, 200, 200, 201, + 203, 228, 199, 204, 204, 197, 206, 205, 229, 203, + 205, 228, 230, 234, 238, 206, 201, 233, 243, 230, + 229, 236, 236, 233, 237, 237, 239, 239, 242, 234, + 238, 242, 245, 246, 243, 261, 263, 262, 266, 263, + 266, 269, 261, 271, 282, 290, 282, 287, 269, 246, + 271, 285, 245, 262, 286, 286, 292, 284, 292, 283, + 281, 290, 298, 298, 298, 300, 280, 300, 301, 301, + + 301, 279, 275, 273, 272, 270, 268, 267, 264, 260, + 258, 256, 253, 252, 250, 249, 248, 244, 241, 240, + 235, 232, 231, 227, 226, 225, 223, 222, 219, 218, + 217, 216, 214, 213, 210, 209, 208, 202, 191, 185, + 183, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 172, 171, 170, 169, 168, 167, 165, 164, 163, 162, + 161, 160, 157, 143, 133, 131, 127, 119, 116, 115, + 114, 113, 111, 110, 109, 108, 107, 106, 104, 103, + 102, 101, 100, 99, 98, 97, 96, 92, 88, 82, + 80, 79, 75, 69, 62, 61, 60, 58, 52, 50, + + 49, 46, 44, 42, 39, 38, 37, 36, 31, 30, + 29, 28, 27, 26, 25, 24, 23, 21, 15, 13, + 12, 10, 9, 7, 5, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297, 297, + 297, 297, 297, 297, 297, 297, 297, 297, 297 + } ; + +static yy_state_type yy_last_accepting_state; +static YY_CHAR *yy_last_accepting_cpos; + +/* the intent behind this definition is that it'll catch + * any uses of REJECT which flex missed + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 + +/* these variables are all declared out here so that section 3 code can + * manipulate them + */ +/* points to current character in buffer */ +static YY_CHAR *yy_c_buf_p = (YY_CHAR *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yyunput YY_PROTO(( YY_CHAR c, YY_CHAR *buf_ptr )); +void yyrestart YY_PROTO(( FILE *input_file )); +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); + +#define yy_new_buffer yy_create_buffer + +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif + +YY_DECL + { + register yy_state_type yy_current_state; + register YY_CHAR *yy_cp, *yy_bp; + register int yy_act; + + + + if ( yy_init ) + { + YY_USER_INIT; + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( yy_current_buffer ) + yy_init_buffer( yy_current_buffer, yyin ); + else + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + + yy_init = 0; + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* support of yytext */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of the + * current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[*yy_cp]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 526 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + YY_USER_ACTION; + +do_action: /* this label is used only to access EOF actions */ + + + switch ( yy_act ) + { + case 0: /* must backtrack */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +# line 142 "scan.l" +{ + if (!std_only) + BEGIN(slcomment); + else + yyerror ("illegal character: #"); + } + YY_BREAK +case 2: +# line 148 "scan.l" +{ BEGIN(INITIAL); } + YY_BREAK +case 3: +# line 149 "scan.l" +{ line_no++; BEGIN(INITIAL); return(NEWLINE); } + YY_BREAK +case 4: +# line 150 "scan.l" +return(Define); + YY_BREAK +case 5: +# line 151 "scan.l" +return(Break); + YY_BREAK +case 6: +# line 152 "scan.l" +return(Quit); + YY_BREAK +case 7: +# line 153 "scan.l" +return(Length); + YY_BREAK +case 8: +# line 154 "scan.l" +return(Return); + YY_BREAK +case 9: +# line 155 "scan.l" +return(For); + YY_BREAK +case 10: +# line 156 "scan.l" +return(If); + YY_BREAK +case 11: +# line 157 "scan.l" +return(While); + YY_BREAK +case 12: +# line 158 "scan.l" +return(Sqrt); + YY_BREAK +case 13: +# line 159 "scan.l" +return(Scale); + YY_BREAK +case 14: +# line 160 "scan.l" +return(Ibase); + YY_BREAK +case 15: +# line 161 "scan.l" +return(Obase); + YY_BREAK +case 16: +# line 162 "scan.l" +return(Auto); + YY_BREAK +case 17: +# line 163 "scan.l" +return(Else); + YY_BREAK +case 18: +# line 164 "scan.l" +return(Read); + YY_BREAK +case 19: +# line 165 "scan.l" +return(Halt); + YY_BREAK +case 20: +# line 166 "scan.l" +return(Last); + YY_BREAK +case 21: +# line 167 "scan.l" +{ +#ifdef READLINE + return(History); +#else + yylval.s_value = strcopyof(yytext); return(NAME); +#endif + } + YY_BREAK +case 22: +# line 175 "scan.l" +return(Warranty); + YY_BREAK +case 23: +# line 176 "scan.l" +return(Continue); + YY_BREAK +case 24: +# line 177 "scan.l" +return(Print); + YY_BREAK +case 25: +# line 178 "scan.l" +return(Limits); + YY_BREAK +case 26: +# line 179 "scan.l" +{ +#ifdef DOT_IS_LAST + return(Last); +#else + yyerror ("illegal character: %s",yytext); +#endif + } + YY_BREAK +case 27: +# line 186 "scan.l" +{ yylval.c_value = yytext[0]; + return((int)yytext[0]); } + YY_BREAK +case 28: +# line 188 "scan.l" +{ return(AND); } + YY_BREAK +case 29: +# line 189 "scan.l" +{ return(OR); } + YY_BREAK +case 30: +# line 190 "scan.l" +{ return(NOT); } + YY_BREAK +case 31: +# line 191 "scan.l" +{ yylval.c_value = yytext[0]; return((int)yytext[0]); } + YY_BREAK +case 32: +# line 192 "scan.l" +{ yylval.c_value = yytext[0]; return(ASSIGN_OP); } + YY_BREAK +case 33: +# line 193 "scan.l" +{ +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned =<op>"); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } + YY_BREAK +case 34: +# line 207 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(REL_OP); } + YY_BREAK +case 35: +# line 208 "scan.l" +{ yylval.c_value = yytext[0]; return(INCR_DECR); } + YY_BREAK +case 36: +# line 209 "scan.l" +{ line_no++; return(NEWLINE); } + YY_BREAK +case 37: +# line 210 "scan.l" +{ line_no++; /* ignore a "quoted" newline */ } + YY_BREAK +case 38: +# line 211 "scan.l" +{ /* ignore spaces and tabs */ } + YY_BREAK +case 39: +# line 212 "scan.l" +{ + int c; + + for (;;) + { + while ( ((c=input()) != '*') && (c != EOF)) + /* eat it */ + if (c == '\n') line_no++; + if (c == '*') + { + while ( (c=input()) == '*') /* eat it*/; + if (c == '/') break; /* at end of comment */ + if (c == '\n') line_no++; + } + if (c == EOF) + { + fprintf (stderr,"EOF encountered in a comment.\n"); + break; + } + } + } + YY_BREAK +case 40: +# line 233 "scan.l" +{ yylval.s_value = strcopyof(yytext); return(NAME); } + YY_BREAK +case 41: +# line 234 "scan.l" +{ + unsigned char *look; + int count = 0; + yylval.s_value = strcopyof(yytext); + for (look = yytext; *look != 0; look++) + { + if (*look == '\n') line_no++; + if (*look == '"') count++; + } + if (count != 2) yyerror ("NUL character in string."); + return(STRING); + } + YY_BREAK +case 42: +# line 246 "scan.l" +{ + unsigned char *src, *dst; + int len; + /* remove a trailing decimal point. */ + len = strlen(yytext); + if (yytext[len-1] == '.') + yytext[len-1] = 0; + /* remove leading zeros. */ + src = yytext; + dst = yytext; + while (*src == '0') src++; + if (*src == 0) src--; + /* Copy strings removing the newlines. */ + while (*src != 0) + { + if (*src == '\\') + { + src++; src++; + line_no++; + } + else + *dst++ = *src++; + } + *dst = 0; + yylval.s_value = strcopyof(yytext); + return(NUMBER); + } + YY_BREAK +case 43: +# line 273 "scan.l" +{ + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%3d", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } + YY_BREAK +case 44: +# line 282 "scan.l" +ECHO; + YY_BREAK +case YY_STATE_EOF(INITIAL): +case YY_STATE_EOF(slcomment): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* amount of text matched not including the EOB char */ + int yy_amount_of_matched_text = yy_cp - yytext - 1; + + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + + /* note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the end- + * of-buffer state). Contrast this with the test in yyinput(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* this was really a NUL */ + { + yy_state_type yy_next_state; + + yy_c_buf_p = yytext + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* okay, we're now positioned to make the + * NUL transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we + * don't want to build jamming into it because + * then it will run more slowly) + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* consume the NUL */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* note: because we've taken care in + * yy_get_next_buffer() to have set up yytext, + * we can now set up yy_c_buf_p so that if some + * total hoser (like flex itself) wants + * to call the scanner after we return the + * YY_NULL, it'll still work - another YY_NULL + * will get returned. + */ + yy_c_buf_p = yytext + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF((yy_start - 1) / 2); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + } + break; + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: +#ifdef FLEX_DEBUG + printf( "action # %d\n", yy_act ); +#endif + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } + } + } + + +/* yy_get_next_buffer - try to read in a new buffer + * + * synopsis + * int yy_get_next_buffer(); + * + * returns a code representing an action + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + + { + register YY_CHAR *dest = yy_current_buffer->yy_ch_buf; + register YY_CHAR *source = yytext - 1; /* copy prev. char, too */ + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + /* try to read more data */ + + /* first move last chars to start of buffer */ + number_to_move = yy_c_buf_p - yytext; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_eof_status != EOF_NOT_SEEN ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_n_chars = 0; + + else + { + int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + else if ( num_to_read <= 0 ) + YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); + + /* read in more data */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == 1 ) + { + ret_val = EOB_ACT_END_OF_FILE; + yy_current_buffer->yy_eof_status = EOF_DONE; + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_eof_status = EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + /* yytext begins at the second character in yy_ch_buf; the first + * character is the one which preceded it before reading in the latest + * buffer; it needs to be kept around in case it's a newline, so + * yy_get_previous_state() will have with '^' rules active + */ + + yytext = &yy_current_buffer->yy_ch_buf[1]; + + return ( ret_val ); + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached + * + * synopsis + * yy_state_type yy_get_previous_state(); + */ + +static yy_state_type yy_get_previous_state() + + { + register yy_state_type yy_current_state; + register YY_CHAR *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[*yy_cp] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return ( yy_current_state ); + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( register yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +register yy_state_type yy_current_state; +#endif + + { + register int yy_is_jam; + register YY_CHAR *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = yy_def[yy_current_state]; + if ( yy_current_state >= 298 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 297); + + return ( yy_is_jam ? 0 : yy_current_state ); + } + + +#ifdef YY_USE_PROTOS +static void yyunput( YY_CHAR c, register YY_CHAR *yy_bp ) +#else +static void yyunput( c, yy_bp ) +YY_CHAR c; +register YY_CHAR *yy_bp; +#endif + + { + register YY_CHAR *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + register int number_to_move = yy_n_chars + 2; /* +2 for EOB chars */ + register YY_CHAR *dest = + &yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size + 2]; + register YY_CHAR *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += dest - source; + yy_bp += dest - source; + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + if ( yy_cp > yy_bp && yy_cp[-1] == '\n' ) + yy_cp[-2] = '\n'; + + *--yy_cp = c; + + /* note: the formal parameter *must* be called "yy_bp" for this + * macro to now work correctly + */ + YY_DO_BEFORE_ACTION; /* set up yytext again */ + } + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + + { + int c; + YY_CHAR *yy_cp = yy_c_buf_p; + + *yy_cp = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* this was really a NUL */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + yytext = yy_c_buf_p; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + { + yy_c_buf_p = yytext + YY_MORE_ADJ; + return ( EOF ); + } + + YY_NEW_FILE; + +#ifdef __cplusplus + return ( yyinput() ); +#else + return ( input() ); +#endif + } + break; + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext + YY_MORE_ADJ; + break; + + case EOB_ACT_LAST_MATCH: +#ifdef __cplusplus + YY_FATAL_ERROR( "unexpected last match in yyinput()" ); +#else + YY_FATAL_ERROR( "unexpected last match in input()" ); +#endif + } + } + } + + c = *yy_c_buf_p; + yy_hold_char = *++yy_c_buf_p; + + return ( c ); + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + + { + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* flush out information for old buffer */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* we don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) malloc( sizeof( struct yy_buffer_state ) ); + + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (YY_CHAR *) malloc( (unsigned) (b->yy_buf_size + 2) ); + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + yy_init_buffer( b, file ); + + return ( b ); + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + free( (char *) b->yy_ch_buf ); + free( (char *) b ); + } + + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + { + b->yy_input_file = file; + + /* we put in the '\n' and start reading from [1] so that an + * initial match-at-newline will be true. + */ + + b->yy_ch_buf[0] = '\n'; + b->yy_n_chars = 1; + + /* we always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[1]; + + b->yy_eof_status = EOF_NOT_SEEN; + } +# line 282 "scan.l" + + + + +/* This is the way to get multiple files input into lex. */ + +int +yywrap() +{ + if (!open_new_file ()) return (1); /* EOF on standard in. */ + return (0); /* We have more input. */ +} diff --git a/gnu/usr.bin/bc/bc/scan.l b/gnu/usr.bin/bc/bc/scan.l new file mode 100644 index 00000000000..8b5b25dc142 --- /dev/null +++ b/gnu/usr.bin/bc/bc/scan.l @@ -0,0 +1,293 @@ +%{ +/* scan.l: the (f)lex description file for the scanner. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "bc.h" +#include "global.h" +#include "proto.h" +#include <errno.h> + +/* Using flex, we can ask for a smaller input buffer. With lex, this + does nothing! */ + +#ifdef SMALL_BUF +#undef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 512 +#endif + +/* Force . as last for now. */ +#define DOT_IS_LAST + +/* We want to define our own yywrap. */ +#undef yywrap +_PROTOTYPE(int yywrap, (void)); + +#ifdef READLINE +/* Support for the readline and history libraries. This allows + nicer input on the interactive part of input. */ + +/* Have input call the following function. */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + rl_input((char *)buf, &result, max_size) + +/* Variables to help interface readline with bc. */ +static char *rl_line = (char *)NULL; +static char *rl_start = (char *)NULL; +static char rl_len = 0; + +/* Definitions for readline access. */ +extern FILE *rl_instream; +_PROTOTYPE(char *readline, (char *)); + +/* Needed here? */ +extern FILE *yyin; + +/* rl_input puts upto MAX characters into BUF with the number put in + BUF placed in *RESULT. If the yy input file is the same as + rl_instream (stdin), use readline. Otherwise, just read it. +*/ + +static void +rl_input (buf, result, max) + char *buf; + int *result; + int max; +{ + if (yyin != rl_instream) + { + while ( (*result = read( fileno(yyin), buf, max )) < 0 ) + if (errno != EINTR) + { + yyerror( "read() in flex scanner failed" ); + exit (1); + } + return; + } + + /* Do we need a new string? */ + if (rl_len == 0) + { + if (rl_line) + free(rl_line); + rl_line = readline (""); + if (rl_line == NULL) { + /* end of file */ + *result = 0; + rl_len = 0; + return; + } + rl_len = strlen (rl_line)+1; + if (rl_len != 1) + add_history (rl_line); + rl_line[rl_len-1] = '\n'; + printf ("\r"); + fflush (stdout); + } + + if (rl_len <= max) + { + strncpy (buf, rl_line, rl_len); + *result = rl_len; + rl_len = 0; + } + else + { + strncpy (buf, rl_line, max); + *result = max; + rl_len -= max; + } +} +#else +/* MINIX returns from read with < 0 if SIGINT is encountered. + In flex, we can redefine YY_INPUT to the following. In lex, this + does nothing! */ +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + if (errno != EINTR) \ + YY_FATAL_ERROR( "read() in flex scanner failed" ); +#endif +%} +DIGIT [0-9A-F] +LETTER [a-z] +%s slcomment +%% +"#" { + if (!std_only) + BEGIN(slcomment); + else + yyerror ("illegal character: #"); + } +<slcomment>[^\n]* { BEGIN(INITIAL); } +<slcomment>"\n" { line_no++; BEGIN(INITIAL); return(NEWLINE); } +define return(Define); +break return(Break); +quit return(Quit); +length return(Length); +return return(Return); +for return(For); +if return(If); +while return(While); +sqrt return(Sqrt); +scale return(Scale); +ibase return(Ibase); +obase return(Obase); +auto return(Auto); +else return(Else); +read return(Read); +halt return(Halt); +last return(Last); +history { +#ifdef READLINE + return(History); +#else + yylval.s_value = strcopyof(yytext); return(NAME); +#endif + } + +warranty return(Warranty); +continue return(Continue); +print return(Print); +limits return(Limits); +"." { +#ifdef DOT_IS_LAST + return(Last); +#else + yyerror ("illegal character: %s",yytext); +#endif + } +"+"|"-"|";"|"("|")"|"{"|"}"|"["|"]"|","|"^" { yylval.c_value = yytext[0]; + return((int)yytext[0]); } +&& { return(AND); } +\|\| { return(OR); } +"!" { return(NOT); } +"*"|"/"|"%" { yylval.c_value = yytext[0]; return((int)yytext[0]); } +"="|\+=|-=|\*=|\/=|%=|\^= { yylval.c_value = yytext[0]; return(ASSIGN_OP); } +=\+|=-|=\*|=\/|=%|=\^ { +#ifdef OLD_EQ_OP + char warn_save; + warn_save = warn_not_std; + warn_not_std = TRUE; + warn ("Old fashioned =<op>"); + warn_not_std = warn_save; + yylval.c_value = yytext[1]; +#else + yylval.c_value = '='; + yyless (1); +#endif + return(ASSIGN_OP); + } +==|\<=|\>=|\!=|"<"|">" { yylval.s_value = strcopyof(yytext); return(REL_OP); } +\+\+|-- { yylval.c_value = yytext[0]; return(INCR_DECR); } +"\n" { line_no++; return(NEWLINE); } +\\\n { line_no++; /* ignore a "quoted" newline */ } +[ \t]+ { /* ignore spaces and tabs */ } +"/*" { + int c; + + for (;;) + { + while ( ((c=input()) != '*') && (c != EOF)) + /* eat it */ + if (c == '\n') line_no++; + if (c == '*') + { + while ( (c=input()) == '*') /* eat it*/; + if (c == '/') break; /* at end of comment */ + if (c == '\n') line_no++; + } + if (c == EOF) + { + fprintf (stderr,"EOF encountered in a comment.\n"); + break; + } + } + } +[a-z][a-z0-9_]* { yylval.s_value = strcopyof(yytext); return(NAME); } +\"[^\"]*\" { + unsigned char *look; + int count = 0; + yylval.s_value = strcopyof(yytext); + for (look = yytext; *look != 0; look++) + { + if (*look == '\n') line_no++; + if (*look == '"') count++; + } + if (count != 2) yyerror ("NUL character in string."); + return(STRING); + } +{DIGIT}({DIGIT}|\\\n)*("."({DIGIT}|\\\n)*)?|"."(\\\n)*{DIGIT}({DIGIT}|\\\n)* { + unsigned char *src, *dst; + int len; + /* remove a trailing decimal point. */ + len = strlen(yytext); + if (yytext[len-1] == '.') + yytext[len-1] = 0; + /* remove leading zeros. */ + src = yytext; + dst = yytext; + while (*src == '0') src++; + if (*src == 0) src--; + /* Copy strings removing the newlines. */ + while (*src != 0) + { + if (*src == '\\') + { + src++; src++; + line_no++; + } + else + *dst++ = *src++; + } + *dst = 0; + yylval.s_value = strcopyof(yytext); + return(NUMBER); + } +. { + if (yytext[0] < ' ') + yyerror ("illegal character: ^%c",yytext[0] + '@'); + else + if (yytext[0] > '~') + yyerror ("illegal character: \\%3d", (int) yytext[0]); + else + yyerror ("illegal character: %s",yytext); + } +%% + + + +/* This is the way to get multiple files input into lex. */ + +int +yywrap() +{ + if (!open_new_file ()) return (1); /* EOF on standard in. */ + return (0); /* We have more input. */ +} diff --git a/gnu/usr.bin/bc/bc/storage.c b/gnu/usr.bin/bc/bc/storage.c new file mode 100644 index 00000000000..781fe96f661 --- /dev/null +++ b/gnu/usr.bin/bc/bc/storage.c @@ -0,0 +1,1070 @@ +/* storage.c: Code and data storage manipulations. This includes labels. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "global.h" +#include "proto.h" + + +/* Initialize the storage at the beginning of the run. */ + +void +init_storage () +{ + + /* Functions: we start with none and ask for more. */ + f_count = 0; + more_functions (); + f_names[0] = "(main)"; + + /* Variables. */ + v_count = 0; + more_variables (); + + /* Arrays. */ + a_count = 0; + more_arrays (); + + /* Other things... */ + ex_stack = NULL; + fn_stack = NULL; + i_base = 10; + o_base = 10; + scale = 0; +#ifdef READLINE + n_history = -1; /* no limit. */ +#endif + c_code = FALSE; + init_numbers(); +} + +/* Three functions for increasing the number of functions, variables, or + arrays that are needed. This adds another 32 of the requested object. */ + +void +more_functions (VOID) +{ + int old_count; + int indx1, indx2; + bc_function *old_f; + bc_function *f; + char **old_names; + + /* Save old information. */ + old_count = f_count; + old_f = functions; + old_names = f_names; + + /* Add a fixed amount and allocate new space. */ + f_count += STORE_INCR; + functions = (bc_function *) bc_malloc (f_count*sizeof (bc_function)); + f_names = (char **) bc_malloc (f_count*sizeof (char *)); + + /* Copy old ones. */ + for (indx1 = 0; indx1 < old_count; indx1++) + { + functions[indx1] = old_f[indx1]; + f_names[indx1] = old_names[indx1]; + } + + /* Initialize the new ones. */ + for (; indx1 < f_count; indx1++) + { + f = &functions[indx1]; + f->f_defined = FALSE; + for (indx2 = 0; indx2 < BC_MAX_SEGS; indx2++) + f->f_body [indx2] = NULL; + f->f_code_size = 0; + f->f_label = NULL; + f->f_autos = NULL; + f->f_params = NULL; + } + + /* Free the old elements. */ + if (old_count != 0) + { + free (old_f); + free (old_names); + } +} + +void +more_variables () +{ + int indx; + int old_count; + bc_var **old_var; + char **old_names; + + /* Save the old values. */ + old_count = v_count; + old_var = variables; + old_names = v_names; + + /* Increment by a fixed amount and allocate. */ + v_count += STORE_INCR; + variables = (bc_var **) bc_malloc (v_count*sizeof(bc_var *)); + v_names = (char **) bc_malloc (v_count*sizeof(char *)); + + /* Copy the old variables. */ + for (indx = 3; indx < old_count; indx++) + variables[indx] = old_var[indx]; + + /* Initialize the new elements. */ + for (; indx < v_count; indx++) + variables[indx] = NULL; + + /* Free the old elements. */ + if (old_count != 0) + { + free (old_var); + free (old_names); + } +} + +void +more_arrays () +{ + int indx; + int old_count; + bc_var_array **old_ary; + char **old_names; + + /* Save the old values. */ + old_count = a_count; + old_ary = arrays; + old_names = a_names; + + /* Increment by a fixed amount and allocate. */ + a_count += STORE_INCR; + arrays = (bc_var_array **) bc_malloc (a_count*sizeof(bc_var_array *)); + a_names = (char **) bc_malloc (a_count*sizeof(char *)); + + /* Copy the old arrays. */ + for (indx = 1; indx < old_count; indx++) + arrays[indx] = old_ary[indx]; + + + /* Initialize the new elements. */ + for (; indx < v_count; indx++) + arrays[indx] = NULL; + + /* Free the old elements. */ + if (old_count != 0) + { + free (old_ary); + free (old_names); + } +} + + +/* clear_func clears out function FUNC and makes it ready to redefine. */ + +void +clear_func (func) + char func; +{ + bc_function *f; + int indx; + bc_label_group *lg; + + /* Set the pointer to the function. */ + f = &functions[func]; + f->f_defined = FALSE; + + /* Clear the code segments. */ + for (indx = 0; indx < BC_MAX_SEGS; indx++) + { + if (f->f_body[indx] != NULL) + { + free (f->f_body[indx]); + f->f_body[indx] = NULL; + } + } + + f->f_code_size = 0; + if (f->f_autos != NULL) + { + free_args (f->f_autos); + f->f_autos = NULL; + } + if (f->f_params != NULL) + { + free_args (f->f_params); + f->f_params = NULL; + } + while (f->f_label != NULL) + { + lg = f->f_label->l_next; + free (f->f_label); + f->f_label = lg; + } +} + + +/* Pop the function execution stack and return the top. */ + +int +fpop() +{ + fstack_rec *temp; + int retval; + + if (fn_stack != NULL) + { + temp = fn_stack; + fn_stack = temp->s_next; + retval = temp->s_val; + free (temp); + } + return (retval); +} + + +/* Push VAL on to the function stack. */ + +void +fpush (val) + int val; +{ + fstack_rec *temp; + + temp = (fstack_rec *) bc_malloc (sizeof (fstack_rec)); + temp->s_next = fn_stack; + temp->s_val = val; + fn_stack = temp; +} + + +/* Pop and discard the top element of the regular execution stack. */ + +void +pop () +{ + estack_rec *temp; + + if (ex_stack != NULL) + { + temp = ex_stack; + ex_stack = temp->s_next; + free_num (&temp->s_num); + free (temp); + } +} + + +/* Push a copy of NUM on to the regular execution stack. */ + +void +push_copy (num) + bc_num num; +{ + estack_rec *temp; + + temp = (estack_rec *) bc_malloc (sizeof (estack_rec)); + temp->s_num = copy_num (num); + temp->s_next = ex_stack; + ex_stack = temp; +} + + +/* Push NUM on to the regular execution stack. Do NOT push a copy. */ + +void +push_num (num) + bc_num num; +{ + estack_rec *temp; + + temp = (estack_rec *) bc_malloc (sizeof (estack_rec)); + temp->s_num = num; + temp->s_next = ex_stack; + ex_stack = temp; +} + + +/* Make sure the ex_stack has at least DEPTH elements on it. + Return TRUE if it has at least DEPTH elements, otherwise + return FALSE. */ + +char +check_stack (depth) + int depth; +{ + estack_rec *temp; + + temp = ex_stack; + while ((temp != NULL) && (depth > 0)) + { + temp = temp->s_next; + depth--; + } + if (depth > 0) + { + rt_error ("Stack error."); + return FALSE; + } + return TRUE; +} + + +/* The following routines manipulate simple variables and + array variables. */ + +/* get_var returns a pointer to the variable VAR_NAME. If one does not + exist, one is created. */ + +bc_var * +get_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + var_ptr = variables[var_name]; + if (var_ptr == NULL) + { + var_ptr = variables[var_name] = (bc_var *) bc_malloc (sizeof (bc_var)); + init_num (&var_ptr->v_value); + } + return var_ptr; +} + + +/* get_array_num returns the address of the bc_num in the array + structure. If more structure is requried to get to the index, + this routine does the work to create that structure. VAR_INDEX + is a zero based index into the arrays storage array. INDEX is + the index into the bc array. */ + +bc_num * +get_array_num (var_index, index) + int var_index; + long index; +{ + bc_var_array *ary_ptr; + bc_array *a_var; + bc_array_node *temp; + int log, ix, ix1; + int sub [NODE_DEPTH]; + + /* Get the array entry. */ + ary_ptr = arrays[var_index]; + if (ary_ptr == NULL) + { + ary_ptr = arrays[var_index] = + (bc_var_array *) bc_malloc (sizeof (bc_var_array)); + ary_ptr->a_value = NULL; + ary_ptr->a_next = NULL; + ary_ptr->a_param = FALSE; + } + + a_var = ary_ptr->a_value; + if (a_var == NULL) { + a_var = ary_ptr->a_value = (bc_array *) bc_malloc (sizeof (bc_array)); + a_var->a_tree = NULL; + a_var->a_depth = 0; + } + + /* Get the index variable. */ + sub[0] = index & NODE_MASK; + ix = index >> NODE_SHIFT; + log = 1; + while (ix > 0 || log < a_var->a_depth) + { + sub[log] = ix & NODE_MASK; + ix >>= NODE_SHIFT; + log++; + } + + /* Build any tree that is necessary. */ + while (log > a_var->a_depth) + { + temp = (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + if (a_var->a_depth != 0) + { + temp->n_items.n_down[0] = a_var->a_tree; + for (ix=1; ix < NODE_SIZE; ix++) + temp->n_items.n_down[ix] = NULL; + } + else + { + for (ix=0; ix < NODE_SIZE; ix++) + temp->n_items.n_num[ix] = copy_num(_zero_); + } + a_var->a_tree = temp; + a_var->a_depth++; + } + + /* Find the indexed variable. */ + temp = a_var->a_tree; + while ( log-- > 1) + { + ix1 = sub[log]; + if (temp->n_items.n_down[ix1] == NULL) + { + temp->n_items.n_down[ix1] = + (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + temp = temp->n_items.n_down[ix1]; + if (log > 1) + for (ix=0; ix < NODE_SIZE; ix++) + temp->n_items.n_down[ix] = NULL; + else + for (ix=0; ix < NODE_SIZE; ix++) + temp->n_items.n_num[ix] = copy_num(_zero_); + } + else + temp = temp->n_items.n_down[ix1]; + } + + /* Return the address of the indexed variable. */ + return &(temp->n_items.n_num[sub[0]]); +} + + +/* Store the top of the execution stack into VAR_NAME. + This includes the special variables ibase, obase, and scale. */ + +void +store_var (var_name) + int var_name; +{ + bc_var *var_ptr; + long temp; + char toobig; + + if (var_name > 3) + { + /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + { + free_num(&var_ptr->v_value); + var_ptr->v_value = copy_num (ex_stack->s_num); + } + } + else + { + /* It is a special variable... */ + toobig = FALSE; + if (is_neg (ex_stack->s_num)) + { + switch (var_name) + { + case 0: + rt_warn ("negative ibase, set to 2"); + temp = 2; + break; + case 1: + rt_warn ("negative obase, set to 2"); + temp = 2; + break; + case 2: + rt_warn ("negative scale, set to 0"); + temp = 0; + break; +#ifdef READLINE + case 3: + temp = -1; + break; +#endif + } + } + else + { + temp = num2long (ex_stack->s_num); + if (!is_zero (ex_stack->s_num) && temp == 0) + toobig = TRUE; + } + switch (var_name) + { + case 0: + if (temp < 2 && !toobig) + { + i_base = 2; + rt_warn ("ibase too small, set to 2"); + } + else + if (temp > 16 || toobig) + { + i_base = 16; + rt_warn ("ibase too large, set to 16"); + } + else + i_base = (int) temp; + break; + + case 1: + if (temp < 2 && !toobig) + { + o_base = 2; + rt_warn ("obase too small, set to 2"); + } + else + if (temp > BC_BASE_MAX || toobig) + { + o_base = BC_BASE_MAX; + rt_warn ("obase too large, set to %d", BC_BASE_MAX); + } + else + o_base = (int) temp; + break; + + case 2: + /* WARNING: The following if statement may generate a compiler + warning if INT_MAX == LONG_MAX. This is NOT a problem. */ + if (temp > BC_SCALE_MAX || toobig ) + { + scale = BC_SCALE_MAX; + rt_warn ("scale too large, set to %d", BC_SCALE_MAX); + } + else + scale = (int) temp; + break; + +#ifdef READLINE + case 3: + if (toobig) + { + temp = -1; + rt_warn ("history too large, set to unlimited"); + unstifle_history (); + } + else + { + n_history = temp; + if (temp == -1) + unstifle_history (); + else + stifle_history (n_history); + } +#endif + } + } +} + + +/* Store the top of the execution stack into array VAR_NAME. + VAR_NAME is the name of an array, and the next to the top + of stack for the index into the array. */ + +void +store_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + if (!check_stack(2)) return; + index = num2long (ex_stack->s_next->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !is_zero(ex_stack->s_next->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + free_num (num_ptr); + *num_ptr = copy_num (ex_stack->s_num); + free_num (&ex_stack->s_next->s_num); + ex_stack->s_next->s_num = ex_stack->s_num; + init_num (&ex_stack->s_num); + pop(); + } + } +} + + +/* Load a copy of VAR_NAME on to the execution stack. This includes + the special variables ibase, obase and scale. */ + +void +load_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + switch (var_name) + { + + case 0: + /* Special variable ibase. */ + push_copy (_zero_); + int2num (&ex_stack->s_num, i_base); + break; + + case 1: + /* Special variable obase. */ + push_copy (_zero_); + int2num (&ex_stack->s_num, o_base); + break; + + case 2: + /* Special variable scale. */ + push_copy (_zero_); + int2num (&ex_stack->s_num, scale); + break; + +#ifdef READLINE + case 3: + /* Special variable history. */ + push_copy (_zero_); + int2num (&ex_stack->s_num, n_history); + break; +#endif + + default: + /* It is a simple variable. */ + var_ptr = variables[var_name]; + if (var_ptr != NULL) + push_copy (var_ptr->v_value); + else + push_copy (_zero_); + } +} + + +/* Load a copy of VAR_NAME on to the execution stack. This includes + the special variables ibase, obase and scale. */ + +void +load_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + if (!check_stack(1)) return; + index = num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !is_zero(ex_stack->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + pop(); + push_copy (*num_ptr); + } + } +} + + +/* Decrement VAR_NAME by one. This includes the special variables + ibase, obase, and scale. */ + +void +decr_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + switch (var_name) + { + + case 0: /* ibase */ + if (i_base > 2) + i_base--; + else + rt_warn ("ibase too small in --"); + break; + + case 1: /* obase */ + if (o_base > 2) + o_base--; + else + rt_warn ("obase too small in --"); + break; + + case 2: /* scale */ + if (scale > 0) + scale--; + else + rt_warn ("scale can not be negative in -- "); + break; + +#ifdef READLINE + case 3: /* history */ + n_history--; + if (n_history > 0) + stifle_history (n_history); + else + { + n_history = -1; + rt_warn ("history is negative, set to unlimited"); + unstifle_history (); + } +#endif + + default: /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + bc_sub (var_ptr->v_value,_one_,&var_ptr->v_value, 0); + } +} + + +/* Decrement VAR_NAME by one. VAR_NAME is an array, and the top of + the execution stack is the index and it is popped off the stack. */ + +void +decr_array (var_name) + char var_name; +{ + bc_num *num_ptr; + long index; + + /* It is an array variable. */ + if (!check_stack (1)) return; + index = num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !is_zero (ex_stack->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + pop (); + bc_sub (*num_ptr, _one_, num_ptr, 0); + } + } +} + + +/* Increment VAR_NAME by one. This includes the special variables + ibase, obase, and scale. */ + +void +incr_var (var_name) + int var_name; +{ + bc_var *var_ptr; + + switch (var_name) + { + + case 0: /* ibase */ + if (i_base < 16) + i_base++; + else + rt_warn ("ibase too big in ++"); + break; + + case 1: /* obase */ + if (o_base < BC_BASE_MAX) + o_base++; + else + rt_warn ("obase too big in ++"); + break; + + case 2: + if (scale < BC_SCALE_MAX) + scale++; + else + rt_warn ("Scale too big in ++"); + break; + +#ifdef READLINE + case 3: /* history */ + n_history++; + if (n_history > 0) + stifle_history (n_history); + else + { + n_history = -1; + rt_warn ("history set to unlimited"); + unstifle_history (); + } +#endif + + default: /* It is a simple variable. */ + var_ptr = get_var (var_name); + if (var_ptr != NULL) + bc_add (var_ptr->v_value, _one_, &var_ptr->v_value, 0); + + } +} + + +/* Increment VAR_NAME by one. VAR_NAME is an array and top of + execution stack is the index and is popped off the stack. */ + +void +incr_array (var_name) + int var_name; +{ + bc_num *num_ptr; + long index; + + if (!check_stack (1)) return; + index = num2long (ex_stack->s_num); + if (index < 0 || index > BC_DIM_MAX || + (index == 0 && !is_zero (ex_stack->s_num))) + rt_error ("Array %s subscript out of bounds.", a_names[var_name]); + else + { + num_ptr = get_array_num (var_name, index); + if (num_ptr != NULL) + { + pop (); + bc_add (*num_ptr, _one_, num_ptr, 0); + } + } +} + + +/* Routines for processing autos variables and parameters. */ + +/* NAME is an auto variable that needs to be pushed on its stack. */ + +void +auto_var (name) + int name; +{ + bc_var *v_temp; + bc_var_array *a_temp; + int ix; + + if (name > 0) + { + /* A simple variable. */ + ix = name; + v_temp = (bc_var *) bc_malloc (sizeof (bc_var)); + v_temp->v_next = variables[ix]; + init_num (&v_temp->v_value); + variables[ix] = v_temp; + } + else + { + /* An array variable. */ + ix = -name; + a_temp = (bc_var_array *) bc_malloc (sizeof (bc_var_array)); + a_temp->a_next = arrays[ix]; + a_temp->a_value = NULL; + a_temp->a_param = FALSE; + arrays[ix] = a_temp; + } +} + + +/* Free_a_tree frees everything associated with an array variable tree. + This is used when popping an array variable off its auto stack. */ + +void +free_a_tree ( root, depth ) + bc_array_node *root; + int depth; +{ + int ix; + + if (root != NULL) + { + if (depth > 1) + for (ix = 0; ix < NODE_SIZE; ix++) + free_a_tree (root->n_items.n_down[ix], depth-1); + else + for (ix = 0; ix < NODE_SIZE; ix++) + free_num ( &(root->n_items.n_num[ix])); + free (root); + } +} + + +/* LIST is an NULL terminated list of varible names that need to be + popped off their auto stacks. */ + +void +pop_vars (list) + arg_list *list; +{ + bc_var *v_temp; + bc_var_array *a_temp; + int ix; + + while (list != NULL) + { + ix = list->av_name; + if (ix > 0) + { + /* A simple variable. */ + v_temp = variables[ix]; + if (v_temp != NULL) + { + variables[ix] = v_temp->v_next; + free_num (&v_temp->v_value); + free (v_temp); + } + } + else + { + /* An array variable. */ + ix = -ix; + a_temp = arrays[ix]; + if (a_temp != NULL) + { + arrays[ix] = a_temp->a_next; + if (!a_temp->a_param && a_temp->a_value != NULL) + { + free_a_tree (a_temp->a_value->a_tree, + a_temp->a_value->a_depth); + free (a_temp->a_value); + } + free (a_temp); + } + } + list = list->next; + } +} + +/* COPY_NODE: Copies an array node for a call by value parameter. */ +bc_array_node * +copy_tree (ary_node, depth) + bc_array_node *ary_node; + int depth; +{ + bc_array_node *res = (bc_array_node *) bc_malloc (sizeof(bc_array_node)); + int i; + + if (depth > 1) + for (i=0; i<NODE_SIZE; i++) + if (ary_node->n_items.n_down[i] != NULL) + res->n_items.n_down[i] = + copy_tree (ary_node->n_items.n_down[i], depth - 1); + else + res->n_items.n_down[i] = NULL; + else + for (i=0; i<NODE_SIZE; i++) + if (ary_node->n_items.n_num[i] != NULL) + res->n_items.n_num[i] = copy_num (ary_node->n_items.n_num[i]); + else + res->n_items.n_num[i] = NULL; + return res; +} + +/* COPY_ARRAY: Copies an array for a call by value array parameter. + ARY is the pointer to the bc_array structure. */ + +bc_array * +copy_array (ary) + bc_array *ary; +{ + bc_array *res = (bc_array *) bc_malloc (sizeof(bc_array)); + res->a_depth = ary->a_depth; + res->a_tree = copy_tree (ary->a_tree, ary->a_depth); + return (res); +} + + +/* A call is being made to FUNC. The call types are at PC. Process + the parameters by doing an auto on the parameter variable and then + store the value at the new variable or put a pointer the the array + variable. */ + +void +process_params (pc, func) + program_counter *pc; + int func; +{ + char ch; + arg_list *params; + int ix, ix1; + bc_var *v_temp; + bc_var_array *a_src, *a_dest; + bc_num *n_temp; + + /* Get the parameter names from the function. */ + params = functions[func].f_params; + + while ((ch = byte(pc)) != ':') + { + if (params != NULL) + { + if ((ch == '0') && params->av_name > 0) + { + /* A simple variable. */ + ix = params->av_name; + v_temp = (bc_var *) bc_malloc (sizeof(bc_var)); + v_temp->v_next = variables[ix]; + v_temp->v_value = ex_stack->s_num; + init_num (&ex_stack->s_num); + variables[ix] = v_temp; + } + else + if ((ch == '1') && (params->av_name < 0)) + { + /* The variables is an array variable. */ + + /* Compute source index and make sure some structure exists. */ + ix = (int) num2long (ex_stack->s_num); + n_temp = get_array_num (ix, 0); + + /* Push a new array and Compute Destination index */ + auto_var (params->av_name); + ix1 = -params->av_name; + + /* Set up the correct pointers in the structure. */ + if (ix == ix1) + a_src = arrays[ix]->a_next; + else + a_src = arrays[ix]; + a_dest = arrays[ix1]; + if (params->arg_is_var) + { + a_dest->a_param = TRUE; + a_dest->a_value = a_src->a_value; + } + else + { + a_dest->a_param = FALSE; + a_dest->a_value = copy_array (a_src->a_value); + } + } + else + { + if (params->av_name < 0) + rt_error ("Parameter type mismatch parameter %s.", + a_names[-params->av_name]); + else + rt_error ("Parameter type mismatch, parameter %s.", + v_names[params->av_name]); + params++; + } + pop (); + } + else + { + rt_error ("Parameter number mismatch"); + return; + } + params = params->next; + } + if (params != NULL) + rt_error ("Parameter number mismatch"); +} diff --git a/gnu/usr.bin/bc/bc/util.c b/gnu/usr.bin/bc/bc/util.c new file mode 100644 index 00000000000..514df266a14 --- /dev/null +++ b/gnu/usr.bin/bc/bc/util.c @@ -0,0 +1,859 @@ +/* util.c: Utility routines for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +#include "bcdefs.h" +#ifndef VARARGS +#include <stdarg.h> +#else +#include <varargs.h> +#endif +#include "global.h" +#include "proto.h" + + +/* strcopyof mallocs new memory and copies a string to to the new + memory. */ + +char * +strcopyof (str) + char *str; +{ + char *temp; + + temp = (char *) bc_malloc (strlen (str)+1); + return (strcpy (temp,str)); +} + + +/* nextarg adds another value to the list of arguments. */ + +arg_list * +nextarg (args, val, is_var) + arg_list *args; + int val; + int is_var; +{ arg_list *temp; + + temp = (arg_list *) bc_malloc (sizeof (arg_list)); + temp->av_name = val; + temp->arg_is_var = is_var; + temp->next = args; + + return (temp); +} + + +/* For generate, we must produce a string in the form + "val,val,...,val". We also need a couple of static variables + for retaining old generated strings. It also uses a recursive + function that builds the string. */ + +static char *arglist1 = NULL, *arglist2 = NULL; + + +/* make_arg_str does the actual construction of the argument string. + ARGS is the pointer to the list and LEN is the maximum number of + characters needed. 1 char is the minimum needed. + */ + +_PROTOTYPE (static char *make_arg_str, (arg_list *args, int len)); + +static char * +make_arg_str (args, len) + arg_list *args; + int len; +{ + char *temp; + char sval[20]; + + /* Recursive call. */ + if (args != NULL) + temp = make_arg_str (args->next, len+12); + else + { + temp = (char *) bc_malloc (len); + *temp = 0; + return temp; + } + + /* Add the current number to the end of the string. */ + if (args->arg_is_var) + if (len != 1) + sprintf (sval, "*%d,", args->av_name); + else + sprintf (sval, "*%d", args->av_name); + else + if (len != 1) + sprintf (sval, "%d,", args->av_name); + else + sprintf (sval, "%d", args->av_name); + temp = strcat (temp, sval); + return (temp); +} + +char * +arg_str (args) + arg_list *args; +{ + if (arglist2 != NULL) + free (arglist2); + arglist2 = arglist1; + arglist1 = make_arg_str (args, 1); + return (arglist1); +} + +char * +call_str (args) + arg_list *args; +{ + arg_list *temp; + int arg_count; + int ix; + + if (arglist2 != NULL) + free (arglist2); + arglist2 = arglist1; + + /* Count the number of args and add the 0's and 1's. */ + for (temp = args, arg_count = 0; temp != NULL; temp = temp->next) + arg_count++; + arglist1 = (char *) bc_malloc(arg_count+1); + for (temp = args, ix=0; temp != NULL; temp = temp->next) + arglist1[ix++] = ( temp->av_name ? '1' : '0'); + arglist1[ix] = 0; + + return (arglist1); +} + +/* free_args frees an argument list ARGS. */ + +void +free_args (args) + arg_list *args; +{ + arg_list *temp; + + temp = args; + while (temp != NULL) + { + args = args->next; + free (temp); + temp = args; + } +} + + +/* Check for valid parameter (PARAMS) and auto (AUTOS) lists. + There must be no duplicates any where. Also, this is where + warnings are generated for array parameters. */ + +void +check_params ( params, autos ) + arg_list *params, *autos; +{ + arg_list *tmp1, *tmp2; + + /* Check for duplicate parameters. */ + if (params != NULL) + { + tmp1 = params; + while (tmp1 != NULL) + { + tmp2 = tmp1->next; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("duplicate parameter names"); + tmp2 = tmp2->next; + } + if (tmp1->arg_is_var) + warn ("Variable array parameter"); + tmp1 = tmp1->next; + } + } + + /* Check for duplicate autos. */ + if (autos != NULL) + { + tmp1 = autos; + while (tmp1 != NULL) + { + tmp2 = tmp1->next; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("duplicate auto variable names"); + tmp2 = tmp2->next; + } + if (tmp1->arg_is_var) + yyerror ("* not allowed here"); + tmp1 = tmp1->next; + } + } + + /* Check for duplicate between parameters and autos. */ + if ((params != NULL) && (autos != NULL)) + { + tmp1 = params; + while (tmp1 != NULL) + { + tmp2 = autos; + while (tmp2 != NULL) + { + if (tmp2->av_name == tmp1->av_name) + yyerror ("variable in both parameter and auto lists"); + tmp2 = tmp2->next; + } + tmp1 = tmp1->next; + } + } +} + + +/* Initialize the code generator the parser. */ + +void +init_gen () +{ + /* Get things ready. */ + break_label = 0; + continue_label = 0; + next_label = 1; + out_count = 2; + if (compile_only) + printf ("@i"); + else + init_load (); + had_error = FALSE; + did_gen = FALSE; +} + + +/* generate code STR for the machine. */ + +void +generate (str) + char *str; +{ + did_gen = TRUE; + if (compile_only) + { + printf ("%s",str); + out_count += strlen(str); + if (out_count > 60) + { + printf ("\n"); + out_count = 0; + } + } + else + load_code (str); +} + + +/* Execute the current code as loaded. */ + +void +run_code() +{ + /* If no compile errors run the current code. */ + if (!had_error && did_gen) + { + if (compile_only) + { + printf ("@r\n"); + out_count = 0; + } + else + execute (); + } + + /* Reinitialize the code generation and machine. */ + if (did_gen) + init_gen(); + else + had_error = FALSE; +} + + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\<cr>". Always used for numbers. */ + +void +out_char (ch) + char ch; +{ + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + out_col++; + if (out_col == line_size-1) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + putchar (ch); + } +} + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\<cr>". This one is for strings. + In POSIX bc, strings are not broken across lines. */ + +void +out_schar (ch) + char ch; +{ + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + if (!std_only) + { + out_col++; + if (out_col == line_size-1) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + } + putchar (ch); + } +} + + +/* The following are "Symbol Table" routines for the parser. */ + +/* find_id returns a pointer to node in TREE that has the correct + ID. If there is no node in TREE with ID, NULL is returned. */ + +id_rec * +find_id (tree, id) + id_rec *tree; + char *id; +{ + int cmp_result; + + /* Check for an empty tree. */ + if (tree == NULL) + return NULL; + + /* Recursively search the tree. */ + cmp_result = strcmp (id, tree->id); + if (cmp_result == 0) + return tree; /* This is the item. */ + else if (cmp_result < 0) + return find_id (tree->left, id); + else + return find_id (tree->right, id); +} + + +/* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is + provided. insert_id_rec returns TRUE if the tree height from + ROOT down is increased otherwise it returns FALSE. This is a + recursive balanced binary tree insertion algorithm. */ + +int insert_id_rec (root, new_id) + id_rec **root; + id_rec *new_id; +{ + id_rec *A, *B; + + /* If root is NULL, this where it is to be inserted. */ + if (*root == NULL) + { + *root = new_id; + new_id->left = NULL; + new_id->right = NULL; + new_id->balance = 0; + return (TRUE); + } + + /* We need to search for a leaf. */ + if (strcmp (new_id->id, (*root)->id) < 0) + { + /* Insert it on the left. */ + if (insert_id_rec (&((*root)->left), new_id)) + { + /* The height increased. */ + (*root)->balance --; + + switch ((*root)->balance) + { + case 0: /* no height increase. */ + return (FALSE); + case -1: /* height increase. */ + return (FALSE); + case -2: /* we need to do a rebalancing act. */ + A = *root; + B = (*root)->left; + if (B->balance <= 0) + { + /* Single Rotate. */ + A->left = B->right; + B->right = A; + *root = B; + A->balance = 0; + B->balance = 0; + } + else + { + /* Double Rotate. */ + *root = B->right; + B->right = (*root)->left; + A->left = (*root)->right; + (*root)->left = B; + (*root)->right = A; + switch ((*root)->balance) + { + case -1: + A->balance = 1; + B->balance = 0; + break; + case 0: + A->balance = 0; + B->balance = 0; + break; + case 1: + A->balance = 0; + B->balance = -1; + break; + } + (*root)->balance = 0; + } + } + } + } + else + { + /* Insert it on the right. */ + if (insert_id_rec (&((*root)->right), new_id)) + { + /* The height increased. */ + (*root)->balance ++; + switch ((*root)->balance) + { + case 0: /* no height increase. */ + return (FALSE); + case 1: /* height increase. */ + return (FALSE); + case 2: /* we need to do a rebalancing act. */ + A = *root; + B = (*root)->right; + if (B->balance >= 0) + { + /* Single Rotate. */ + A->right = B->left; + B->left = A; + *root = B; + A->balance = 0; + B->balance = 0; + } + else + { + /* Double Rotate. */ + *root = B->left; + B->left = (*root)->right; + A->right = (*root)->left; + (*root)->left = A; + (*root)->right = B; + switch ((*root)->balance) + { + case -1: + A->balance = 0; + B->balance = 1; + break; + case 0: + A->balance = 0; + B->balance = 0; + break; + case 1: + A->balance = -1; + B->balance = 0; + break; + } + (*root)->balance = 0; + } + } + } + } + + /* If we fall through to here, the tree did not grow in height. */ + return (FALSE); +} + + +/* Initialize variables for the symbol table tree. */ + +void +init_tree() +{ + name_tree = NULL; + next_array = 1; + next_func = 1; + /* 0 => ibase, 1 => obase, 2 => scale, 3 => history, 4 => last. */ + next_var = 5; +} + + +/* Lookup routines for symbol table names. */ + +int +lookup (name, namekind) + char *name; + int namekind; +{ + id_rec *id; + + /* Warn about non-standard name. */ + if (strlen(name) != 1) + warn ("multiple letter name - %s", name); + + /* Look for the id. */ + id = find_id (name_tree, name); + if (id == NULL) + { + /* We need to make a new item. */ + id = (id_rec *) bc_malloc (sizeof (id_rec)); + id->id = strcopyof (name); + id->a_name = 0; + id->f_name = 0; + id->v_name = 0; + insert_id_rec (&name_tree, id); + } + + /* Return the correct value. */ + switch (namekind) + { + + case ARRAY: + /* ARRAY variable numbers are returned as negative numbers. */ + if (id->a_name != 0) + { + free (name); + return (-id->a_name); + } + id->a_name = next_array++; + a_names[id->a_name] = name; + if (id->a_name < MAX_STORE) + { + if (id->a_name >= a_count) + more_arrays (); + return (-id->a_name); + } + yyerror ("Too many array variables"); + exit (1); + + case FUNCT: + case FUNCTDEF: + if (id->f_name != 0) + { + free(name); + /* Check to see if we are redefining a math lib function. */ + if (use_math && namekind == FUNCTDEF && id->f_name <= 6) + id->f_name = next_func++; + return (id->f_name); + } + id->f_name = next_func++; + f_names[id->f_name] = name; + if (id->f_name < MAX_STORE) + { + if (id->f_name >= f_count) + more_functions (); + return (id->f_name); + } + yyerror ("Too many functions"); + exit (1); + + case SIMPLE: + if (id->v_name != 0) + { + free(name); + return (id->v_name); + } + id->v_name = next_var++; + v_names[id->v_name - 1] = name; + if (id->v_name <= MAX_STORE) + { + if (id->v_name >= v_count) + more_variables (); + return (id->v_name); + } + yyerror ("Too many variables"); + exit (1); + } +} + + +/* Print the welcome banner. */ + +void +welcome() +{ + printf ("This is free software with ABSOLUTELY NO WARRANTY.\n"); + printf ("For details type `warranty'. \n"); +} + + +/* Print out the warranty information. */ + +void +warranty(prefix) + char *prefix; +{ + printf ("\n%s%s\n\n", prefix, BC_VERSION); + printf ("%s%s%s%s%s%s%s%s%s%s%s", +" This program is free software; you can redistribute it and/or modify\n", +" it under the terms of the GNU General Public License as published by\n", +" the Free Software Foundation; either version 2 of the License , or\n", +" (at your option) any later version.\n\n", +" This program is distributed in the hope that it will be useful,\n", +" but WITHOUT ANY WARRANTY; without even the implied warranty of\n", +" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n", +" GNU General Public License for more details.\n\n", +" You should have received a copy of the GNU General Public License\n", +" along with this program. If not, write to the Free Software\n", +" Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n"); +} + +/* Print out the limits of this program. */ + +void +limits() +{ + printf ("BC_BASE_MAX = %d\n", BC_BASE_MAX); + printf ("BC_DIM_MAX = %ld\n", (long) BC_DIM_MAX); + printf ("BC_SCALE_MAX = %d\n", BC_SCALE_MAX); + printf ("BC_STRING_MAX = %d\n", BC_STRING_MAX); + printf ("MAX Exponent = %ld\n", (long) LONG_MAX); + printf ("MAX code = %ld\n", (long) BC_MAX_SEGS * (long) BC_SEG_SIZE); + printf ("multiply digits = %ld\n", (long) LONG_MAX / (long) 90); + printf ("Number of vars = %ld\n", (long) MAX_STORE); +#ifdef OLD_EQ_OP + printf ("Old assignment operatiors are valid. (=-, =+, ...)\n"); +#endif +} + +/* bc_malloc will check the return value so all other places do not + have to do it! SIZE is the number of bytes to allocate. */ + +char * +bc_malloc (size) + int size; +{ + char *ptr; + + ptr = (char *) malloc (size); + if (ptr == NULL) + out_of_memory (); + + return ptr; +} + + +/* The following routines are error routines for various problems. */ + +/* Malloc could not get enought memory. */ + +void +out_of_memory() +{ + fprintf (stderr, "Fatal error: Out of memory for malloc.\n"); + exit (1); +} + + + +/* The standard yyerror routine. Built with variable number of argumnets. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +yyerror (char *str, ...) +#else +void +yyerror (str) + char *str; +#endif +#else +void +yyerror (str, va_alist) + char *str; +#endif +{ + char *name; + va_list args; + +#ifndef VARARGS + va_start (args, str); +#else + va_start (args); +#endif + if (is_std_in) + name = "(standard_in)"; + else + name = file_name; + fprintf (stderr,"%s %d: ",name,line_no); + vfprintf (stderr, str, args); + fprintf (stderr, "\n"); + had_error = TRUE; + va_end (args); +} + + +/* The routine to produce warnings about non-standard features + found during parsing. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +warn (char *mesg, ...) +#else +void +warn (mesg) + char *mesg; +#endif +#else +void +warn (mesg, va_alist) + char *mesg; +#endif +{ + char *name; + va_list args; + +#ifndef VARARGS + va_start (args, mesg); +#else + va_start (args); +#endif + if (std_only) + { + if (is_std_in) + name = "(standard_in)"; + else + name = file_name; + fprintf (stderr,"%s %d: ",name,line_no); + vfprintf (stderr, mesg, args); + fprintf (stderr, "\n"); + had_error = TRUE; + } + else + if (warn_not_std) + { + if (is_std_in) + name = "(standard_in)"; + else + name = file_name; + fprintf (stderr,"%s %d: (Warning) ",name,line_no); + vfprintf (stderr, mesg, args); + fprintf (stderr, "\n"); + } + va_end (args); +} + +/* Runtime error will print a message and stop the machine. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +rt_error (char *mesg, ...) +#else +void +rt_error (mesg) + char *mesg; +#endif +#else +void +rt_error (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + char error_mesg [255]; + +#ifndef VARARGS + va_start (args, mesg); +#else + va_start (args); +#endif + vsprintf (error_mesg, mesg, args); + va_end (args); + + fprintf (stderr, "Runtime error (func=%s, adr=%d): %s\n", + f_names[pc.pc_func], pc.pc_addr, error_mesg); + runtime_error = TRUE; +} + + +/* A runtime warning tells of some action taken by the processor that + may change the program execution but was not enough of a problem + to stop the execution. */ + +#ifndef VARARGS +#ifdef __STDC__ +void +rt_warn (char *mesg, ...) +#else +void +rt_warn (mesg) + char *mesg; +#endif +#else +void +rt_warn (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + char error_mesg [255]; + +#ifndef VARARGS + va_start (args, mesg); +#else + va_start (args); +#endif + vsprintf (error_mesg, mesg, args); + va_end (args); + + fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n", + f_names[pc.pc_func], pc.pc_addr, error_mesg); +} diff --git a/gnu/usr.bin/bc/config.h.in b/gnu/usr.bin/bc/config.h.in new file mode 100644 index 00000000000..1f331618bcb --- /dev/null +++ b/gnu/usr.bin/bc/config.h.in @@ -0,0 +1,71 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if you don't have vprintf but do have _doprnt. */ +#undef HAVE_DOPRNT + +/* Define if you have the vprintf function. */ +#undef HAVE_VPRINTF + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if lex declares yytext as a char * by default, not a char[]. */ +#undef YYTEXT_POINTER + +/* PACKAGE name */ +#undef PACKAGE + +/* Package VERSION number */ +#undef VERSION + +/* define if the math lib is to be loaded from a file. */ +#undef BC_MATH_FILE + +/* Define to use the readline library. */ +#undef READLINE + +/* Define to `size_t' if <sys/types.h> and <stddef.h> don't define. */ +#undef ptrdiff_t + +/* Define if you have the isgraph function. */ +#undef HAVE_ISGRAPH + +/* Define if you have the setvbuf function. */ +#undef HAVE_SETVBUF + +/* Define if you have the <lib.h> header file. */ +#undef HAVE_LIB_H + +/* Define if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the <stdarg.h> header file. */ +#undef HAVE_STDARG_H + +/* Define if you have the <stddef.h> header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H diff --git a/gnu/usr.bin/bc/configure b/gnu/usr.bin/bc/configure new file mode 100644 index 00000000000..dfe4aa29805 --- /dev/null +++ b/gnu/usr.bin/bc/configure @@ -0,0 +1,2447 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-readline support fancy command input editing" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=doc/bc.1 + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:554: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:607: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:664: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=bc + +VERSION=1.05 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <<EOF +#define PACKAGE "$PACKAGE" +EOF + +cat >> confdefs.h <<EOF +#define VERSION "$VERSION" +EOF + + + +missing_dir=`cd $ac_aux_dir && pwd` +echo $ac_n "checking for working aclocal""... $ac_c" 1>&6 +echo "configure:710: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:723: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:736: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:749: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:762: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:782: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:811: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:859: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <<EOF +#line 869 "configure" +#include "confdefs.h" +main(){return(0);} +EOF +if { (eval echo configure:873: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:893: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:898: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:907: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:922: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:950: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 965 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:971: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 982 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:988: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 +echo "configure:1012: checking for minix/config.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1017 "configure" +#include "confdefs.h" +#include <minix/config.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1022: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MINIX=yes +else + echo "$ac_t""no" 1>&6 +MINIX= +fi + +if test "$MINIX" = yes; then + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_1_SOURCE 2 +EOF + + cat >> confdefs.h <<\EOF +#define _MINIX 1 +EOF + +fi + + +missing_dir=`cd $ac_aux_dir && pwd` +for ac_prog in flex lex +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1066: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$LEX" && break +done +test -n "$LEX" || LEX=""$missing_dir/missing flex"" + +# Extract the first word of "flex", so it can be a program name with args. +set dummy flex; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1098: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_LEX'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_LEX="flex" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_LEX" && ac_cv_prog_LEX="lex" +fi +fi +LEX="$ac_cv_prog_LEX" +if test -n "$LEX"; then + echo "$ac_t""$LEX" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$LEXLIB" +then + case "$LEX" in + flex*) ac_lib=fl ;; + *) ac_lib=l ;; + esac + echo $ac_n "checking for yywrap in -l$ac_lib""... $ac_c" 1>&6 +echo "configure:1131: checking for yywrap in -l$ac_lib" >&5 +ac_lib_var=`echo $ac_lib'_'yywrap | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-l$ac_lib $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1139 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char yywrap(); + +int main() { +yywrap() +; return 0; } +EOF +if { (eval echo configure:1150: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LEXLIB="-l$ac_lib" +else + echo "$ac_t""no" 1>&6 +fi + +fi + +echo $ac_n "checking lex output file root""... $ac_c" 1>&6 +echo "configure:1173: checking lex output file root" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_root'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # The minimal lex program is just a single line: %%. But some broken lexes +# (Solaris, I think it was) want two %% lines, so accommodate them. +echo '%% +%%' | $LEX +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { echo "configure: error: cannot find output from $LEX; giving up" 1>&2; exit 1; } +fi +fi + +echo "$ac_t""$ac_cv_prog_lex_root" 1>&6 +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +echo $ac_n "checking whether yytext is a pointer""... $ac_c" 1>&6 +echo "configure:1194: checking whether yytext is a pointer" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_lex_yytext_pointer'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +echo 'extern char *yytext;' >>$LEX_OUTPUT_ROOT.c +ac_save_LIBS="$LIBS" +LIBS="$LIBS $LEXLIB" +cat > conftest.$ac_ext <<EOF +#line 1206 "configure" +#include "confdefs.h" +`cat $LEX_OUTPUT_ROOT.c` +int main() { + +; return 0; } +EOF +if { (eval echo configure:1213: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + ac_cv_prog_lex_yytext_pointer=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +LIBS="$ac_save_LIBS" +rm -f "${LEX_OUTPUT_ROOT}.c" + +fi + +echo "$ac_t""$ac_cv_prog_lex_yytext_pointer" 1>&6 +if test $ac_cv_prog_lex_yytext_pointer = yes; then + cat >> confdefs.h <<\EOF +#define YYTEXT_POINTER 1 +EOF + +fi + +for ac_prog in 'bison -y' byacc +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1239: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_YACC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_YACC="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +YACC="$ac_cv_prog_YACC" +if test -n "$YACC"; then + echo "$ac_t""$YACC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:1279: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +# Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1331: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_RANLIB="ranlib" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":" +fi +fi +RANLIB="$ac_cv_prog_RANLIB" +if test -n "$RANLIB"; then + echo "$ac_t""$RANLIB" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:1358: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + + +for ac_hdr in stdarg.h stddef.h stdlib.h string.h limits.h unistd.h lib.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1390: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1395 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1400: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:1427: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1432 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:1481: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1502: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1507 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1515: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1532 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1550 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 1571 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1582: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:1606: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1611 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for ptrdiff_t""... $ac_c" 1>&6 +echo "configure:1639: checking for ptrdiff_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_ptrdiff_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1644 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "ptrdiff_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_ptrdiff_t=yes +else + rm -rf conftest* + ac_cv_type_ptrdiff_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_ptrdiff_t" 1>&6 +if test $ac_cv_type_ptrdiff_t = no; then + cat >> confdefs.h <<\EOF +#define ptrdiff_t size_t +EOF + +fi + + +echo $ac_n "checking for vprintf""... $ac_c" 1>&6 +echo "configure:1673: checking for vprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1678 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char vprintf(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vprintf) || defined (__stub___vprintf) +choke me +#else +vprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1701: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_vprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VPRINTF 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +if test "$ac_cv_func_vprintf" != yes; then +echo $ac_n "checking for _doprnt""... $ac_c" 1>&6 +echo "configure:1725: checking for _doprnt" >&5 +if eval "test \"`echo '$''{'ac_cv_func__doprnt'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1730 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char _doprnt(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char _doprnt(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub__doprnt) || defined (__stub____doprnt) +choke me +#else +_doprnt(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1753: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func__doprnt=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func__doprnt=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'_doprnt`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_DOPRNT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +fi + +for ac_func in isgraph setvbuf +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:1780: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1785 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1808: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + +SaveCFLAGS="$CFLAGS" +CFLAGS="-g -O -I. -I$srcdir" +echo $ac_n "checking if long strings are accepted by the C compiler""... $ac_c" 1>&6 +echo "configure:1836: checking if long strings are accepted by the C compiler" >&5 +cat > conftest.$ac_ext <<EOF +#line 1838 "configure" +#include "confdefs.h" + +char libmath[] = +#include "bc/libmath.h" +; + +int main() { + +; return 0; } +EOF +if { (eval echo configure:1849: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + echo "$ac_t""yes" 1>&6 +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "$ac_t""no" 1>&6 +echo "configure: warning: libmath.b will not be preloaded into the executable" 1>&2 +if test "${prefix}" = "NONE" ; then +cat >> confdefs.h <<EOF +#define BC_MATH_FILE "/usr/local/lib/libmath.b" +EOF + +else +cat >> confdefs.h <<EOF +#define BC_MATH_FILE "${prefix}/lib/libmath.b" +EOF + +fi +fi +rm -f conftest* +CFLAGS="$SaveCFLAGS" + +echo $LIBS +bcrl=nA +# Check whether --with-readline or --without-readline was given. +if test "${with_readline+set}" = set; then + withval="$with_readline" + + echo $ac_n "checking for tparm in -lncurses""... $ac_c" 1>&6 +echo "configure:1880: checking for tparm in -lncurses" >&5 +ac_lib_var=`echo ncurses'_'tparm | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lncurses $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1888 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tparm(); + +int main() { +tparm() +; return 0; } +EOF +if { (eval echo configure:1899: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + TERMLIB=-lncurses +else + echo "$ac_t""no" 1>&6 +echo $ac_n "checking for tgetent in -ltermcap""... $ac_c" 1>&6 +echo "configure:1918: checking for tgetent in -ltermcap" >&5 +ac_lib_var=`echo termcap'_'tgetent | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ltermcap $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1926 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char tgetent(); + +int main() { +tgetent() +; return 0; } +EOF +if { (eval echo configure:1937: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + TERMLIB=-ltermcap +else + echo "$ac_t""no" 1>&6 +fi + +fi + + saved_LIBS="$LIBS" + LIBS="$LIBS $TERMLIB" + echo $ac_n "checking for readline in -lreadline""... $ac_c" 1>&6 +echo "configure:1962: checking for readline in -lreadline" >&5 +ac_lib_var=`echo readline'_'readline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lreadline $LIBS" +cat > conftest.$ac_ext <<EOF +#line 1970 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char readline(); + +int main() { +readline() +; return 0; } +EOF +if { (eval echo configure:1981: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_safe=`echo "readline/readline.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for readline/readline.h""... $ac_c" 1>&6 +echo "configure:1998: checking for readline/readline.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2003 "configure" +#include "confdefs.h" +#include <readline/readline.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2008: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + LIBS="$saved_LIBS -lreadline $TERMLIB";bcrl=y +else + echo "$ac_t""no" 1>&6 +fi + +else + echo "$ac_t""no" 1>&6 +LIBS="$saved_LIBS" +fi + + if test "$bcrl" = "y" ; then + echo Using the readline library. + cat >> confdefs.h <<\EOF +#define READLINE 1 +EOF + + fi + +fi + +echo $LIBS + + +if test "$LEX" = "flex" ; then + LEX="flex -I8" +else + if test "$bcrl" = "y" ; then + echo "configure: warning: readline works only with flex." 1>&2 + fi +fi + +if test "$LEX" = "lex" -a `uname -s` = "SunOS" ; then + LEXLIB="" + echo "SunOS using lex does not have a -ll." +fi + +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@LEX@%$LEX%g +s%@LEXLIB@%$LEXLIB%g +s%@LEX_OUTPUT_ROOT@%$LEX_OUTPUT_ROOT%g +s%@YACC@%$YACC%g +s%@RANLIB@%$RANLIB%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile bc/Makefile dc/Makefile doc/Makefile lib/Makefile"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="config.h" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + + +EOF +cat >> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/gnu/usr.bin/bc/dc/Makefile.am b/gnu/usr.bin/bc/dc/Makefile.am new file mode 100644 index 00000000000..4de00ab339a --- /dev/null +++ b/gnu/usr.bin/bc/dc/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in +bin_PROGRAMS = dc + +dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c +noinst_HEADERS = dc.h dc-proto.h dc-regdef.h + +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h +LDADD = ../lib/libbc.a + +$(PROGRAMS): $(LDADD) diff --git a/gnu/usr.bin/bc/dc/Makefile.in b/gnu/usr.bin/bc/dc/Makefile.in new file mode 100644 index 00000000000..ae4e460650e --- /dev/null +++ b/gnu/usr.bin/bc/dc/Makefile.in @@ -0,0 +1,266 @@ +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +bin_PROGRAMS = dc + +dc_SOURCES = dc.c misc.c eval.c stack.c array.c numeric.c string.c +noinst_HEADERS = dc.h dc-proto.h dc-regdef.h + +INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../h +LDADD = ../lib/libbc.a +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +dc_OBJECTS = dc.o misc.o eval.o stack.o array.o numeric.o string.o +dc_LDADD = $(LDADD) +dc_DEPENDENCIES = ../lib/libbc.a +dc_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ +HEADERS = $(noinst_HEADERS) + +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +SOURCES = $(dc_SOURCES) +OBJECTS = $(dc_OBJECTS) + +all: Makefile $(PROGRAMS) $(HEADERS) + +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps dc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +dc: $(dc_OBJECTS) $(dc_DEPENDENCIES) + @rm -f dc + $(LINK) $(dc_LDFLAGS) $(dc_OBJECTS) $(dc_LDADD) $(LIBS) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = dc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: install-binPROGRAMS + @$(NORMAL_INSTALL) + +install-data: + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: uninstall-binPROGRAMS + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + $(mkinstalldirs) $(DATADIR)$(bindir) + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-binPROGRAMS clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-binPROGRAMS distclean-compile distclean-tags \ + distclean-generic clean + -rm -f config.status + +maintainer-clean: maintainer-clean-binPROGRAMS maintainer-clean-compile \ + maintainer-clean-tags maintainer-clean-generic \ + distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +$(PROGRAMS): $(LDADD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gnu/usr.bin/bc/dc/array.c b/gnu/usr.bin/bc/dc/array.c new file mode 100644 index 00000000000..bc701a18f90 --- /dev/null +++ b/gnu/usr.bin/bc/dc/array.c @@ -0,0 +1,119 @@ +/* + * implement arrays for dc + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* This module is the only one that knows what arrays look like. */ + +#include "config.h" + +#include <stdio.h> /* "dc-proto.h" wants this */ +#ifdef HAVE_STDLIB_H +/* get size_t definition from "almost ANSI" compiling environments. */ +#include <stdlib.h> +#endif +#include "dc.h" +#include "dc-proto.h" +#include "dc-regdef.h" + +/* what's most useful: quick access or sparse arrays? */ +/* I'll go with sparse arrays for now */ +struct dc_array { + int Index; + dc_data value; + struct dc_array *next; +}; + + +/* initialize the arrays */ +void +dc_array_init DC_DECLVOID() +{ +} + +/* store value into array_id[Index] */ +void +dc_array_set DC_DECLARG((array_id, Index, value)) + int array_id DC_DECLSEP + int Index DC_DECLSEP + dc_data value DC_DECLEND +{ + struct dc_array *cur; + struct dc_array *prev=NULL; + struct dc_array *newentry; + + cur = dc_get_stacked_array(array_id); + while (cur && cur->Index < Index){ + prev = cur; + cur = cur->next; + } + if (cur && cur->Index == Index){ + if (cur->value.dc_type == DC_NUMBER) + dc_free_num(&cur->value.v.number); + else if (cur->value.dc_type == DC_STRING) + dc_free_str(&cur->value.v.string); + else + dc_garbage(" in array", array_id); + cur->value = value; + }else{ + newentry = dc_malloc(sizeof *newentry); + newentry->Index = Index; + newentry->value = value; + newentry->next = cur; + if (prev) + prev->next = newentry; + else + dc_set_stacked_array(array_id, newentry); + } +} + +/* retrieve a dup of a value from array_id[Index] */ +/* A zero value is returned if the specified value is unintialized. */ +dc_data +dc_array_get DC_DECLARG((array_id, Index)) + int array_id DC_DECLSEP + int Index DC_DECLEND +{ + struct dc_array *cur; + + for (cur=dc_get_stacked_array(array_id); cur; cur=cur->next) + if (cur->Index == Index) + return dc_dup(cur->value); + return dc_int2data(0); +} + +/* free an array chain */ +void +dc_array_free DC_DECLARG((a_head)) + struct dc_array *a_head DC_DECLEND +{ + struct dc_array *cur; + struct dc_array *next; + + for (cur=a_head; cur; cur=next) { + next = cur->next; + if (cur->value.dc_type == DC_NUMBER) + dc_free_num(&cur->value.v.number); + else if (cur->value.dc_type == DC_STRING) + dc_free_str(&cur->value.v.string); + else + dc_garbage("in stack", -1); + free(cur); + } +} diff --git a/gnu/usr.bin/bc/dc/dc-proto.h b/gnu/usr.bin/bc/dc/dc-proto.h new file mode 100644 index 00000000000..1e7c52cfc7b --- /dev/null +++ b/gnu/usr.bin/bc/dc/dc-proto.h @@ -0,0 +1,87 @@ +/* + * prototypes of all externally visible dc functions + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +extern const char *dc_str2charp DC_PROTO((dc_str)); +extern const char *dc_system DC_PROTO((const char *)); +extern void *dc_malloc DC_PROTO((size_t)); +extern struct dc_array *dc_get_stacked_array DC_PROTO((int)); + +extern void dc_array_set DC_PROTO((int, int, dc_data)); +extern void dc_array_free DC_PROTO((struct dc_array *)); +extern void dc_array_init DC_PROTO((void)); +extern void dc_binop DC_PROTO((int (*)(dc_num, dc_num, int, dc_num *), int)); +extern void dc_binop2 DC_PROTO((int (*)(dc_num, dc_num, int, + dc_num *, dc_num *), int)); +extern void dc_triop DC_PROTO((int (*)(dc_num, dc_num, dc_num, int, + dc_num *), int)); +extern void dc_clear_stack DC_PROTO((void)); +extern void dc_dump_num(dc_num, dc_discard); +extern void dc_free_num DC_PROTO((dc_num *)); +extern void dc_free_str DC_PROTO((dc_str *)); +extern void dc_garbage DC_PROTO((const char *, int)); +extern void dc_math_init DC_PROTO((void)); +extern void dc_memfail DC_PROTO((void)); +extern void dc_out_num DC_PROTO((dc_num, int, dc_newline, dc_discard)); +extern void dc_out_str DC_PROTO((dc_str, dc_newline, dc_discard)); +extern void dc_print DC_PROTO((dc_data, int, dc_newline, dc_discard)); +extern void dc_printall DC_PROTO((int)); +extern void dc_push DC_PROTO((dc_data)); +extern void dc_register_init DC_PROTO((void)); +extern void dc_register_push DC_PROTO((int, dc_data)); +extern void dc_register_set DC_PROTO((int, dc_data)); +extern void dc_set_stacked_array DC_PROTO((int, struct dc_array *)); +extern void dc_show_id DC_PROTO((FILE *, int, const char *)); +extern void dc_string_init DC_PROTO((void)); + +extern int dc_cmpop DC_PROTO((void)); +extern int dc_compare DC_PROTO((dc_num, dc_num)); +extern int dc_evalfile DC_PROTO((FILE *)); +extern int dc_evalstr DC_PROTO((dc_data)); +extern int dc_num2int DC_PROTO((dc_num, dc_discard)); +extern int dc_numlen DC_PROTO((dc_num)); +extern int dc_pop DC_PROTO((dc_data *)); +extern int dc_register_get DC_PROTO((int, dc_data *)); +extern int dc_register_pop DC_PROTO((int, dc_data *)); +extern int dc_tell_length DC_PROTO((dc_data, dc_discard)); +extern int dc_tell_scale DC_PROTO((dc_num, dc_discard)); +extern int dc_tell_stackdepth DC_PROTO((void)); +extern int dc_top_of_stack DC_PROTO((dc_data *)); + +extern size_t dc_strlen DC_PROTO((dc_str)); + +extern dc_data dc_array_get DC_PROTO((int, int)); +extern dc_data dc_dup DC_PROTO((dc_data)); +extern dc_data dc_dup_num DC_PROTO((dc_num)); +extern dc_data dc_dup_str DC_PROTO((dc_str)); +extern dc_data dc_getnum DC_PROTO((int (*)(void), int, int *)); +extern dc_data dc_int2data DC_PROTO((int)); +extern dc_data dc_makestring DC_PROTO((const char *, size_t)); +extern dc_data dc_readstring DC_PROTO((FILE *, int , int)); + +extern int dc_add DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_div DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_divrem DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)); +extern int dc_exp DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_modexp DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)); +extern int dc_mul DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_rem DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_sub DC_PROTO((dc_num, dc_num, int, dc_num *)); +extern int dc_sqrt DC_PROTO((dc_num, int, dc_num *)); diff --git a/gnu/usr.bin/bc/dc/dc-regdef.h b/gnu/usr.bin/bc/dc/dc-regdef.h new file mode 100644 index 00000000000..129d0ae6596 --- /dev/null +++ b/gnu/usr.bin/bc/dc/dc-regdef.h @@ -0,0 +1,40 @@ +/* + * definitions for dc's "register" declarations + * + * Copyright (C) 1994 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +#ifdef HAVE_LIMITS_H +# include <limits.h> /* UCHAR_MAX */ +#endif + +/* determine how many register stacks there are */ +#ifndef DC_REGCOUNT +# ifndef UCHAR_MAX +# define DC_REGCOUNT 256 +# else +# define DC_REGCOUNT (UCHAR_MAX+1) +# endif +#endif /* not DC_REGCOUNT */ + +/* efficiency hack for masking arbritrary integers to 0..(DC_REGCOUNT-1) */ +#if (DC_REGCOUNT & (DC_REGCOUNT-1)) == 0 /* DC_REGCOUNT is power of 2 */ +# define regmap(r) ((r) & (DC_REGCOUNT-1)) +#else +# define regmap(r) ((r) % DC_REGCOUNT) +#endif diff --git a/gnu/usr.bin/bc/dc/dc.c b/gnu/usr.bin/bc/dc/dc.c new file mode 100644 index 00000000000..fa213bae6e6 --- /dev/null +++ b/gnu/usr.bin/bc/dc/dc.c @@ -0,0 +1,177 @@ +/* + * implement the "dc" Desk Calculator language. + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* Written with strong hiding of implementation details + * in their own specialized modules. + */ +/* This module contains the argument processing/main functions. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +# include <string.h> +#else +# ifdef HAVE_STRINGS_H +# include <strings.h> +# endif +#endif +#include <getopt.h> +#include "dc.h" +#include "dc-proto.h" + +#include "version.h" + +#ifndef EXIT_SUCCESS /* C89 <stdlib.h> */ +# define EXIT_SUCCESS 0 +#endif +#ifndef EXIT_FAILURE /* C89 <stdlib.h> */ +# define EXIT_FAILURE 1 +#endif + +const char *progname; /* basename of program invocation */ + +/* your generic usage function */ +static void +usage DC_DECLARG((f)) + FILE *f DC_DECLEND +{ + fprintf(f, "\ +Usage: %s [OPTION] [file ...]\n\ + -e, --expression=EXPR evaluate expression\n\ + -f, --file=FILE evaluate contents of file\n\ + -h, --help display this help and exit\n\ + -V, --version output version information and exit\n\ +\n\ +Report bugs to bug-gnu-utils@prep.ai.mit.edu\n\ +Be sure to include the word ``dc'' somewhere in the ``Subject:'' field.\n\ +", progname); +} + +static void +show_version DC_DECLVOID() +{ + printf("%s\n\n", DC_VERSION); + printf("Email bug reports to: bug-gnu-utils@prep.ai.mit.edu .\n"); + printf("Be sure to include the word ``dc'' \ +somewhere in the ``Subject:'' field.\n"); +} + +/* returns a pointer to one past the last occurance of c in s, + * or s if c does not occur in s. + */ +static char * +r1bindex DC_DECLARG((s, c)) + char *s DC_DECLSEP + int c DC_DECLEND +{ + char *p = strrchr(s, c); + + if (!p) + return s; + return p + 1; +} + +static void +try_file(const char *filename) +{ + FILE *input; + + if (strcmp(filename, "-") == 0) { + input = stdin; + } else if ( !(input=fopen(filename, "r")) ) { + fprintf(stderr, "Could not open file "); + perror(filename); + exit(EXIT_FAILURE); + } + if (dc_evalfile(input)) + exit(EXIT_FAILURE); + if (input != stdin) + fclose(input); +} + + +int +main DC_DECLARG((argc, argv)) + int argc DC_DECLSEP + char **argv DC_DECLEND +{ + static struct option const long_opts[] = { + {"expression", required_argument, NULL, 'e'}, + {"file", required_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {NULL, 0, NULL, 0} + }; + int did_eval = 0; + int c; + + progname = r1bindex(*argv, '/'); +#ifdef HAVE_SETVBUF + /* attempt to simplify interaction with applications such as emacs */ + (void) setvbuf(stdout, NULL, _IOLBF, 0); +#endif + dc_math_init(); + dc_string_init(); + dc_register_init(); + dc_array_init(); + + while ((c = getopt_long(argc, argv, "hVe:f:", long_opts, (int *)0)) != EOF) { + switch (c) { + case 'e': + { dc_data string = dc_makestring(optarg, strlen(optarg)); + if (dc_evalstr(string)) + return EXIT_SUCCESS; + dc_free_str(&string.v.string); + did_eval = 1; + } + break; + case 'f': + try_file(optarg); + did_eval = 1; + break; + case 'h': + usage(stdout); + return EXIT_SUCCESS; + case 'V': + show_version(); + return EXIT_SUCCESS; + default: + usage(stderr); + return EXIT_FAILURE; + } + } + + for (; optind < argc; ++optind) { + try_file(argv[optind]); + did_eval = 1; + } + if (!did_eval) { + /* if no -e commands and no command files, then eval stdin */ + if (dc_evalfile(stdin)) + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/gnu/usr.bin/bc/dc/dc.h b/gnu/usr.bin/bc/dc/dc.h new file mode 100644 index 00000000000..5e2d65a4d21 --- /dev/null +++ b/gnu/usr.bin/bc/dc/dc.h @@ -0,0 +1,79 @@ +/* + * Header file for dc routines + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +#ifndef DC_DEFS_H +#define DC_DEFS_H + +/* 'I' is a command, and bases 17 and 18 are quite + * unusual, so we limit ourselves to bases 2 to 16 + */ +#define DC_IBASE_MAX 16 + +#define DC_SUCCESS 0 +#define DC_DOMAIN_ERROR 1 +#define DC_FAIL 2 /* generic failure */ + + +#ifndef __STDC__ +# define DC_PROTO(x) () +# define DC_DECLVOID() () +# define DC_DECLARG(arglist) arglist +# define DC_DECLSEP ; +# define DC_DECLEND ; +#else /* __STDC__ */ +# define DC_PROTO(x) x +# define DC_DECLVOID() (void) +# define DC_DECLARG(arglist) ( +# define DC_DECLSEP , +# define DC_DECLEND ) +#endif /* __STDC__ */ + + +typedef enum {DC_TOSS, DC_KEEP} dc_discard; +typedef enum {DC_NONL, DC_WITHNL} dc_newline; + + +/* type discriminant for dc_data */ +typedef enum {DC_UNINITIALIZED, DC_NUMBER, DC_STRING} dc_value_type; + +/* only numeric.c knows what dc_num's *really* look like */ +typedef struct dc_number *dc_num; + +/* only string.c knows what dc_str's *really* look like */ +typedef struct dc_string *dc_str; + + +/* except for the two implementation-specific modules, all + * dc functions only know of this one generic type of object + */ +typedef struct { + dc_value_type dc_type; /* discriminant for union */ + union { + dc_num number; + dc_str string; + } v; +} dc_data; + + +/* This is dc's only global variable: */ +extern const char *progname; /* basename of program invocation */ + +#endif /* not DC_DEFS_H */ diff --git a/gnu/usr.bin/bc/dc/eval.c b/gnu/usr.bin/bc/dc/eval.c new file mode 100644 index 00000000000..0cb2185d901 --- /dev/null +++ b/gnu/usr.bin/bc/dc/eval.c @@ -0,0 +1,679 @@ +/* + * evaluate the dc language, from a FILE* or a string + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* This is the only module which knows about the dc input language */ + +#include "config.h" + +#include <stdio.h> +#ifdef HAVE_STRING_H +# include <string.h> /* memchr */ +#else +# ifdef HAVE_MEMORY_H +# include <memory.h> /* memchr, maybe */ +# else +# ifdef HAVE_STRINGS_H +# include <strings.h> /* memchr, maybe */ +# endif +#endif +#endif +#include "dc.h" +#include "dc-proto.h" + +typedef enum {DC_FALSE, DC_TRUE} dc_boolean; + +typedef enum { + DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */ + DC_EATONE, /* caller needs to eat the lookahead char */ + DC_QUIT, /* quit out of unwind_depth levels of evaluation */ + + /* with the following return values, the caller does not have to + * fret about stdin_lookahead's value + */ + DC_INT, /* caller needs to parse a dc_num from input stream */ + DC_STR, /* caller needs to parse a dc_str from input stream */ + DC_SYSTEM, /* caller needs to run a system() on next input line */ + DC_COMMENT, /* caller needs to skip to the next input line */ + DC_NEGCMP, /* caller needs to re-call dc_func() with `negcmp' set */ + + DC_EOF_ERROR /* unexpected end of input; abort current eval */ +} dc_status; + +static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */ +static int dc_obase=10; /* output base, 2 <= dc_obase */ +static int dc_scale=0; /* scale (see user documentaton) */ + +/* for Quitting evaluations */ +static int unwind_depth=0; + +/* if true, active Quit will not exit program */ +static dc_boolean unwind_noexit=DC_FALSE; + +/* + * Used to synchronize lookahead on stdin for '?' command. + * If set to EOF then lookahead is used up. + */ +static int stdin_lookahead=EOF; + + +/* input_fil and input_str are passed as arguments to dc_getnum */ + +/* used by the input_* functions: */ +static FILE *input_fil_fp; +static const char *input_str_string; + +/* Since we have a need for two characters of pushback, and + * ungetc() only guarantees one, we place the second pushback here + */ +static int input_pushback; + +/* passed as an argument to dc_getnum */ +static int +input_fil DC_DECLVOID() +{ + if (input_pushback != EOF){ + int c = input_pushback; + input_pushback = EOF; + return c; + } + return getc(input_fil_fp); +} + +/* passed as an argument to dc_getnum */ +static int +input_str DC_DECLVOID() +{ + if (!*input_str_string) + return EOF; + return *input_str_string++; +} + + + +/* takes a string and evals it; frees the string when done */ +/* Wrapper around dc_evalstr to avoid duplicating the free call + * at all possible return points. + */ +static int +dc_eval_and_free_str DC_DECLARG((string)) + dc_data string DC_DECLEND +{ + dc_status status; + + status = dc_evalstr(string); + if (string.dc_type == DC_STRING) + dc_free_str(&string.v.string); + return status; +} + + +/* dc_func does the grunt work of figuring out what each input + * character means; used by both dc_evalstr and dc_evalfile + * + * c -> the "current" input character under consideration + * peekc -> the lookahead input character + * negcmp -> negate comparison test (for <,=,> commands) + */ +static dc_status +dc_func DC_DECLARG((c, peekc, negcmp)) + int c DC_DECLSEP + int peekc DC_DECLSEP + int negcmp DC_DECLEND +{ + /* we occasionally need these for temporary data */ + /* Despite the GNU coding standards, it is much easier + * to have these declared once here, since this function + * is just one big switch statement. + */ + dc_data datum; + int tmpint; + + switch (c){ + case '_': case '.': + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': case 'A': case 'B': + case 'C': case 'D': case 'E': case 'F': + return DC_INT; + case ' ': + case '\t': + case '\n': + /* standard command separators */ + break; + + case '+': /* add top two stack elements */ + dc_binop(dc_add, dc_scale); + break; + case '-': /* subtract top two stack elements */ + dc_binop(dc_sub, dc_scale); + break; + case '*': /* multiply top two stack elements */ + dc_binop(dc_mul, dc_scale); + break; + case '/': /* divide top two stack elements */ + dc_binop(dc_div, dc_scale); + break; + case '%': + /* take the remainder from division of the top two stack elements */ + dc_binop(dc_rem, dc_scale); + break; + case '~': + /* Do division on the top two stack elements. Return the + * quotient as next-to-top of stack and the remainder as + * top-of-stack. + */ + dc_binop2(dc_divrem, dc_scale); + break; + case '|': + /* Consider the top three elements of the stack as (base, exp, mod), + * where mod is top-of-stack, exp is next-to-top, and base is + * second-from-top. Mod must be non-zero and exp must be a + * non-negative integer. Push the result of raising base to the exp + * power, reduced modulo mod. If we had base in register b, exp in + * register e, and mod in register m then this is conceptually + * equivalent to "lble^lm%", but it is implemented in a more efficient + * manner, and can handle arbritrarily large values for exp. + */ + dc_triop(dc_modexp, dc_scale); + break; + case '^': /* exponientiation of the top two stack elements */ + dc_binop(dc_exp, dc_scale); + break; + case '<': + /* eval register named by peekc if + * less-than holds for top two stack elements + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if ( (dc_cmpop() < 0) == !negcmp ) + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + return DC_EATONE; + case '=': + /* eval register named by peekc if + * equal-to holds for top two stack elements + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if ( (dc_cmpop() == 0) == !negcmp ) + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + return DC_EATONE; + case '>': + /* eval register named by peekc if + * greater-than holds for top two stack elements + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if ( (dc_cmpop() > 0) == !negcmp ) + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + return DC_EATONE; + case '?': /* read a line from standard-input and eval it */ + if (stdin_lookahead != EOF){ + ungetc(stdin_lookahead, stdin); + stdin_lookahead = EOF; + } + if (dc_eval_and_free_str(dc_readstring(stdin, '\n', '\n')) == DC_QUIT) + return DC_QUIT; + return DC_OKAY; + case '[': /* read to balancing ']' into a dc_str */ + return DC_STR; + case '!': /* read to newline and call system() on resulting string */ + if (peekc == '<' || peekc == '=' || peekc == '>') + return DC_NEGCMP; + return DC_SYSTEM; + case '#': /* comment; skip remainder of current line */ + return DC_COMMENT; + + case 'a': /* Convert top of stack to an ascii character. */ + if (dc_pop(&datum) == DC_SUCCESS){ + char tmps; + if (datum.dc_type == DC_NUMBER){ + tmps = (char) dc_num2int(datum.v.number, DC_TOSS); + }else if (datum.dc_type == DC_STRING){ + tmps = *dc_str2charp(datum.v.string); + dc_free_str(&datum.v.string); + }else{ + dc_garbage("at top of stack", -1); + } + dc_push(dc_makestring(&tmps, 1)); + } + break; + case 'c': /* clear whole stack */ + dc_clear_stack(); + break; + case 'd': /* duplicate the datum on the top of stack */ + if (dc_top_of_stack(&datum) == DC_SUCCESS) + dc_push(dc_dup(datum)); + break; + case 'f': /* print list of all stack items */ + dc_printall(dc_obase); + break; + case 'i': /* set input base to value on top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if ( ! (2 <= tmpint && tmpint <= DC_IBASE_MAX) ) + fprintf(stderr, + "%s: input base must be a number \ +between 2 and %d (inclusive)\n", + progname, DC_IBASE_MAX); + else + dc_ibase = tmpint; + } + break; + case 'k': /* set scale to value on top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = -1; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if ( ! (tmpint >= 0) ) + fprintf(stderr, + "%s: scale must be a nonnegative number\n", + progname); + else + dc_scale = tmpint; + } + break; + case 'l': /* "load" -- push value on top of register stack named + * by peekc onto top of evaluation stack; does not + * modify the register stack + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_register_get(peekc, &datum) == DC_SUCCESS) + dc_push(datum); + return DC_EATONE; + case 'n': /* print the value popped off of top-of-stack; + * do not add a trailing newline + */ + if (dc_pop(&datum) == DC_SUCCESS) + dc_print(datum, dc_obase, DC_NONL, DC_TOSS); + break; + case 'o': /* set output base to value on top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if ( ! (tmpint > 1) ) + fprintf(stderr, + "%s: output base must be a number greater than 1\n", + progname); + else + dc_obase = tmpint; + } + break; + case 'p': /* print the datum on the top of stack, + * with a trailing newline + */ + if (dc_top_of_stack(&datum) == DC_SUCCESS) + dc_print(datum, dc_obase, DC_WITHNL, DC_KEEP); + break; + case 'q': /* quit two levels of evaluation, posibly exiting program */ + unwind_depth = 1; /* the return below is the first level of returns */ + unwind_noexit = DC_FALSE; + return DC_QUIT; + case 'r': /* rotate (swap) the top two elements on the stack + */ + if (dc_pop(&datum) == DC_SUCCESS) { + dc_data datum2; + int two_status; + two_status = dc_pop(&datum2); + dc_push(datum); + if (two_status == DC_SUCCESS) + dc_push(datum2); + } + break; + case 's': /* "store" -- replace top of register stack named + * by peekc with the value popped from the top + * of the evaluation stack + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS) + dc_register_set(peekc, datum); + return DC_EATONE; + case 'v': /* replace top of stack with its square root */ + if (dc_pop(&datum) == DC_SUCCESS){ + dc_num tmpnum; + if (datum.dc_type != DC_NUMBER){ + fprintf(stderr, + "%s: square root of nonnumeric attempted\n", + progname); + }else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){ + dc_free_num(&datum.v.number); + datum.v.number = tmpnum; + dc_push(datum); + } + } + break; + case 'x': /* eval the datum popped from top of stack */ + if (dc_pop(&datum) == DC_SUCCESS){ + if (datum.dc_type == DC_STRING){ + if (dc_eval_and_free_str(datum) == DC_QUIT) + return DC_QUIT; + }else if (datum.dc_type == DC_NUMBER){ + dc_push(datum); + }else{ + dc_garbage("at top of stack", -1); + } + } + break; + case 'z': /* push the current stack depth onto the top of stack */ + dc_push(dc_int2data(dc_tell_stackdepth())); + break; + + case 'I': /* push the current input base onto the stack */ + dc_push(dc_int2data(dc_ibase)); + break; + case 'K': /* push the current scale onto the stack */ + dc_push(dc_int2data(dc_scale)); + break; + case 'L': /* pop a value off of register stack named by peekc + * and push it onto the evaluation stack + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_register_pop(peekc, &datum) == DC_SUCCESS) + dc_push(datum); + return DC_EATONE; + case 'O': /* push the current output base onto the stack */ + dc_push(dc_int2data(dc_obase)); + break; + case 'P': + /* Pop the value off the top of a stack. If it is + * a number, dump out the integer portion of its + * absolute value as a "base UCHAR_MAX+1" byte stream; + * if it is a string, just print it. + * In either case, do not append a trailing newline. + */ + if (dc_pop(&datum) == DC_SUCCESS){ + if (datum.dc_type == DC_NUMBER) + dc_dump_num(datum.v.number, DC_TOSS); + else if (datum.dc_type == DC_STRING) + dc_out_str(datum.v.string, DC_NONL, DC_TOSS); + else + dc_garbage("at top of stack", -1); + } + break; + case 'Q': /* quit out of top-of-stack nested evals; + * pops value from stack; + * does not exit program (stops short if necessary) + */ + if (dc_pop(&datum) == DC_SUCCESS){ + unwind_depth = 0; + unwind_noexit = DC_TRUE; + if (datum.dc_type == DC_NUMBER) + unwind_depth = dc_num2int(datum.v.number, DC_TOSS); + if (unwind_depth-- > 0) + return DC_QUIT; + unwind_depth = 0; /* paranoia */ + fprintf(stderr, + "%s: Q command requires a number >= 1\n", + progname); + } + break; +#if 0 + case 'R': /* pop a value off of the evaluation stack,; + * rotate the top + remaining stack elements that many + * places forward (negative numbers mean rotate + * backward). + */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + dc_stack_rotate(tmpint); + } + break; +#endif + case 'S': /* pop a value off of the evaluation stack + * and push it onto the register stack named by peekc + */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS) + dc_register_push(peekc, datum); + return DC_EATONE; + case 'X': /* replace the number on top-of-stack with its scale factor */ + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = 0; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_tell_scale(datum.v.number, DC_TOSS); + dc_push(dc_int2data(tmpint)); + } + break; + case 'Z': /* replace the datum on the top-of-stack with its length */ + if (dc_pop(&datum) == DC_SUCCESS) + dc_push(dc_int2data(dc_tell_length(datum, DC_TOSS))); + break; + + case ':': /* store into array */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = -1; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if (dc_pop(&datum) == DC_SUCCESS){ + if (tmpint < 0) + fprintf(stderr, + "%s: array index must be a nonnegative integer\n", + progname); + else + dc_array_set(peekc, tmpint, datum); + } + } + return DC_EATONE; + case ';': /* retreive from array */ + if (peekc == EOF) + return DC_EOF_ERROR; + if (dc_pop(&datum) == DC_SUCCESS){ + tmpint = -1; + if (datum.dc_type == DC_NUMBER) + tmpint = dc_num2int(datum.v.number, DC_TOSS); + if (tmpint < 0) + fprintf(stderr, + "%s: array index must be a nonnegative integer\n", + progname); + else + dc_push(dc_array_get(peekc, tmpint)); + } + return DC_EATONE; + + default: /* What did that user mean? */ + fprintf(stderr, "%s: ", progname); + dc_show_id(stdout, c, " unimplemented\n"); + break; + } + return DC_OKAY; +} + + +/* takes a string and evals it */ +int +dc_evalstr DC_DECLARG((string)) + dc_data string DC_DECLEND +{ + const char *s; + const char *end; + const char *p; + size_t len; + int c; + int peekc; + int count; + int negcmp; + int next_negcmp = 0; + + if (string.dc_type != DC_STRING){ + fprintf(stderr, + "%s: eval called with non-string argument\n", + progname); + return DC_OKAY; + } + s = dc_str2charp(string.v.string); + end = s + dc_strlen(string.v.string); + while (s < end){ + c = *(const unsigned char *)s++; + peekc = EOF; + if (s < end) + peekc = *(const unsigned char *)s; + negcmp = next_negcmp; + next_negcmp = 0; + switch (dc_func(c, peekc, negcmp)){ + case DC_OKAY: + break; + case DC_EATONE: + if (peekc != EOF) + ++s; + break; + case DC_QUIT: + if (unwind_depth > 0){ + --unwind_depth; + return DC_QUIT; + } + return DC_OKAY; + + case DC_INT: + input_str_string = s - 1; + dc_push(dc_getnum(input_str, dc_ibase, &peekc)); + s = input_str_string; + if (peekc != EOF) + --s; + break; + case DC_STR: + count = 1; + for (p=s; p<end && count>0; ++p) + if (*p == ']') + --count; + else if (*p == '[') + ++count; + len = p - s; + dc_push(dc_makestring(s, len-1)); + s = p; + break; + case DC_SYSTEM: + s = dc_system(s); + case DC_COMMENT: + s = memchr(s, '\n', (size_t)(end-s)); + if (!s) + s = end; + else + ++s; + break; + case DC_NEGCMP: + next_negcmp = 1; + break; + + case DC_EOF_ERROR: + fprintf(stderr, "%s: unexpected EOS\n", progname); + return DC_OKAY; + } + } + return DC_OKAY; +} + + +/* This is the main function of the whole DC program. + * Reads the file described by fp, calls dc_func to do + * the dirty work, and takes care of dc_func's shortcomings. + */ +int +dc_evalfile DC_DECLARG((fp)) + FILE *fp DC_DECLEND +{ + int c; + int peekc; + int negcmp; + int next_negcmp = 0; + dc_data datum; + + stdin_lookahead = EOF; + for (c=getc(fp); c!=EOF; c=peekc){ + peekc = getc(fp); + /* + * The following if() is the only place where ``stdin_lookahead'' + * might be set to other than EOF: + */ + if (fp == stdin) + stdin_lookahead = peekc; + negcmp = next_negcmp; + next_negcmp = 0; + switch (dc_func(c, peekc, negcmp)){ + case DC_OKAY: + if (stdin_lookahead != peekc && fp == stdin) + peekc = getc(fp); + break; + case DC_EATONE: + peekc = getc(fp); + break; + case DC_QUIT: + if (unwind_noexit != DC_TRUE) + return DC_FAIL; + fprintf(stderr, + "%s: Q command argument exceeded string execution depth\n", + progname); + if (stdin_lookahead != peekc && fp == stdin) + peekc = getc(fp); + break; + + case DC_INT: + input_fil_fp = fp; + input_pushback = c; + ungetc(peekc, fp); + dc_push(dc_getnum(input_fil, dc_ibase, &peekc)); + break; + case DC_STR: + ungetc(peekc, fp); + datum = dc_readstring(fp, '[', ']'); + dc_push(datum); + peekc = getc(fp); + break; + case DC_SYSTEM: + ungetc(peekc, fp); + datum = dc_readstring(stdin, '\n', '\n'); + (void)dc_system(dc_str2charp(datum.v.string)); + dc_free_str(&datum.v.string); + peekc = getc(fp); + break; + case DC_COMMENT: + while (peekc!=EOF && peekc!='\n') + peekc = getc(fp); + if (peekc != EOF) + peekc = getc(fp); + break; + case DC_NEGCMP: + next_negcmp = 1; + break; + + case DC_EOF_ERROR: + fprintf(stderr, "%s: unexpected EOF\n", progname); + return DC_FAIL; + } + } + return DC_SUCCESS; +} diff --git a/gnu/usr.bin/bc/dc/misc.c b/gnu/usr.bin/bc/dc/misc.c new file mode 100644 index 00000000000..65f986b57db --- /dev/null +++ b/gnu/usr.bin/bc/dc/misc.c @@ -0,0 +1,179 @@ +/* + * misc. functions for the "dc" Desk Calculator language. + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* This module contains miscelaneous functions that have no + * special knowledge of any private data structures. + * They could all be moved to their own separate modules, but + * are agglomerated here for convenience. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +# include <string.h> +#else +# ifdef HAVE_STRINGS_H +# include <strings.h> +# endif +#endif +#include <ctype.h> +#ifndef isgraph +# ifndef HAVE_ISGRAPH +# define isgraph isprint +# endif +#endif +#include <getopt.h> +#include "dc.h" +#include "dc-proto.h" + +#include "version.h" + +#ifndef EXIT_FAILURE /* C89 <stdlib.h> */ +# define EXIT_FAILURE 1 +#endif + + +/* print an "out of memory" diagnostic and exit program */ +void +dc_memfail DC_DECLVOID() +{ + fprintf(stderr, "%s: out of memory\n", progname); + exit(EXIT_FAILURE); +} + +/* malloc or die */ +void * +dc_malloc DC_DECLARG((len)) + size_t len DC_DECLEND +{ + void *result = malloc(len); + + if (!result) + dc_memfail(); + return result; +} + + +/* print the id in a human-understandable form + * fp is the output stream to place the output on + * id is the name of the register (or command) to be printed + * suffix is a modifier (such as "stack") to be printed + */ +void +dc_show_id DC_DECLARG((fp, id, suffix)) + FILE *fp DC_DECLSEP + int id DC_DECLSEP + const char *suffix DC_DECLEND +{ + if (isgraph(id)) + fprintf(fp, "'%c' (%#o)%s", id, id, suffix); + else + fprintf(fp, "%#o%s", id, suffix); +} + + +/* report that corrupt data has been detected; + * use the msg and regid (if nonnegative) to give information + * about where the garbage was found, + * + * will abort() so that a debugger might be used to help find + * the bug + */ +/* If this routine is called, then there is a bug in the code; + * i.e. it is _not_ a data or user error + */ +void +dc_garbage DC_DECLARG((msg, regid)) + const char *msg DC_DECLSEP + int regid DC_DECLEND +{ + if (regid < 0) { + fprintf(stderr, "%s: garbage %s\n", progname, msg); + } else { + fprintf(stderr, "%s:%s register ", progname, msg); + dc_show_id(stderr, regid, " is garbage\n"); + } + abort(); +} + + +/* call system() with the passed string; + * if the string contains a newline, terminate the string + * there before calling system. + * Return a pointer to the first unused character in the string + * (i.e. past the '\n' if there was one, to the '\0' otherwise). + */ +const char * +dc_system DC_DECLARG((s)) + const char *s DC_DECLEND +{ + const char *p; + char *tmpstr; + size_t len; + + p = strchr(s, '\n'); + if (p) { + len = p - s; + tmpstr = dc_malloc(len + 1); + strncpy(tmpstr, s, len); + tmpstr[len] = '\0'; + system(tmpstr); + free(tmpstr); + return p + 1; + } + system(s); + return s + strlen(s); +} + + +/* print out the indicated value */ +void +dc_print DC_DECLARG((value, obase, newline_p, discard_p)) + dc_data value DC_DECLSEP + int obase DC_DECLSEP + dc_newline newline_p DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + if (value.dc_type == DC_NUMBER) { + dc_out_num(value.v.number, obase, newline_p, discard_p); + } else if (value.dc_type == DC_STRING) { + dc_out_str(value.v.string, newline_p, discard_p); + } else { + dc_garbage("in data being printed", -1); + } +} + +/* return a duplicate of the passed value, regardless of type */ +dc_data +dc_dup DC_DECLARG((value)) + dc_data value DC_DECLEND +{ + if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING) + dc_garbage("in value being duplicated", -1); + if (value.dc_type == DC_NUMBER) + return dc_dup_num(value.v.number); + /*else*/ + return dc_dup_str(value.v.string); +} diff --git a/gnu/usr.bin/bc/dc/numeric.c b/gnu/usr.bin/bc/dc/numeric.c new file mode 100644 index 00000000000..d5abf13a0d5 --- /dev/null +++ b/gnu/usr.bin/bc/dc/numeric.c @@ -0,0 +1,595 @@ +/* + * interface dc to the bc numeric routines + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* This should be the only module that knows the internals of type dc_num */ +/* In this particular implementation we just slather out some glue and + * make use of bc's numeric routines. + */ + +#include "config.h" + +#include <stdio.h> +#include <ctype.h> +#ifdef HAVE_LIMITS_H +# include <limits.h> +#else +# define UCHAR_MAX ((unsigned char)~0) +#endif +#include "bcdefs.h" +#include "proto.h" +#include "global.h" +#include "dc.h" +#include "dc-proto.h" + +#ifdef __GNUC__ +# define ATTRIB(x) __attribute__(x) +#else +# define ATTRIB(x) +#endif + +/* there is no POSIX standard for dc, so we'll take the GNU definitions */ +int std_only = FALSE; + +/* convert an opaque dc_num into a real bc_num */ +#define CastNum(x) ((bc_num)(x)) + +/* add two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_add DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale ATTRIB((unused)) DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0); + return DC_SUCCESS; +} + +/* subtract two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_sub DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale ATTRIB((unused)) DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0); + return DC_SUCCESS; +} + +/* multiply two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_mul DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale); + return DC_SUCCESS; +} + +/* divide two dc_nums, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_div DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){ + fprintf(stderr, "%s: divide by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +/* divide two dc_nums, place quotient into *quotient and remainder + * into *remainder; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *quotient DC_DECLSEP + dc_num *remainder DC_DECLEND +{ + init_num((bc_num *)quotient); + init_num((bc_num *)remainder); + if (bc_divmod(CastNum(a), CastNum(b), + (bc_num *)quotient, (bc_num *)remainder, kscale)){ + fprintf(stderr, "%s: divide by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +/* place the reminder of dividing a by b into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_rem DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){ + fprintf(stderr, "%s: remainder by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +int +dc_modexp DC_DECLARG((base, expo, mod, kscale, result)) + dc_num base DC_DECLSEP + dc_num expo DC_DECLSEP + dc_num mod DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod), + (bc_num *)result, kscale)){ + if (is_zero(CastNum(mod))) + fprintf(stderr, "%s: remainder by zero\n", progname); + return DC_DOMAIN_ERROR; + } + return DC_SUCCESS; +} + +/* place the result of exponentiationg a by b into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_exp DC_DECLARG((a, b, kscale, result)) + dc_num a DC_DECLSEP + dc_num b DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + init_num((bc_num *)result); + bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale); + return DC_SUCCESS; +} + +/* take the square root of the value, place into *result; + * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error + */ +int +dc_sqrt DC_DECLARG((value, kscale, result)) + dc_num value DC_DECLSEP + int kscale DC_DECLSEP + dc_num *result DC_DECLEND +{ + bc_num tmp; + + tmp = copy_num(CastNum(value)); + if (!bc_sqrt(&tmp, kscale)){ + fprintf(stderr, "%s: square root of negative number\n", progname); + free_num(&tmp); + return DC_DOMAIN_ERROR; + } + *((bc_num *)result) = tmp; + return DC_SUCCESS; +} + +/* compare dc_nums a and b; + * return a negative value if a < b; + * return a positive value if a > b; + * return zero value if a == b + */ +int +dc_compare DC_DECLARG((a, b)) + dc_num a DC_DECLSEP + dc_num b DC_DECLEND +{ + return bc_compare(CastNum(a), CastNum(b)); +} + +/* attempt to convert a dc_num to its corresponding int value + * If discard_p is DC_TOSS then deallocate the value after use. + */ +int +dc_num2int DC_DECLARG((value, discard_p)) + dc_num value DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + long result; + + result = num2long(CastNum(value)); + if (discard_p == DC_TOSS) + dc_free_num(&value); + return (int)result; +} + +/* convert a C integer value into a dc_num */ +/* For convenience of the caller, package the dc_num + * into a dc_data result. + */ +dc_data +dc_int2data DC_DECLARG((value)) + int value DC_DECLEND +{ + dc_data result; + + init_num((bc_num *)&result.v.number); + int2num((bc_num *)&result.v.number, value); + result.dc_type = DC_NUMBER; + return result; +} + +/* get a dc_num from some input stream; + * input is a function which knows how to read the desired input stream + * ibase is the input base (2<=ibase<=DC_IBASE_MAX) + * *readahead will be set to the readahead character consumed while + * looking for the end-of-number + */ +/* For convenience of the caller, package the dc_num + * into a dc_data result. + */ +dc_data +dc_getnum DC_DECLARG((input, ibase, readahead)) + int (*input) DC_PROTO((void)) DC_DECLSEP + int ibase DC_DECLSEP + int *readahead DC_DECLEND +{ + bc_num base; + bc_num result; + bc_num build; + bc_num tmp; + bc_num divisor; + dc_data full_result; + int negative = 0; + int digit; + int decimal; + int c; + + init_num(&tmp); + init_num(&build); + init_num(&base); + result = copy_num(_zero_); + int2num(&base, ibase); + c = (*input)(); + while (isspace(c)) + c = (*input)(); + if (c == '_' || c == '-'){ + negative = c; + c = (*input)(); + }else if (c == '+'){ + c = (*input)(); + } + while (isspace(c)) + c = (*input)(); + for (;;){ + if (isdigit(c)) + digit = c - '0'; + else if ('A' <= c && c <= 'F') + digit = 10 + c - 'A'; + else + break; + c = (*input)(); + int2num(&tmp, digit); + bc_multiply(result, base, &result, 0); + bc_add(result, tmp, &result, 0); + } + if (c == '.'){ + free_num(&build); + free_num(&tmp); + divisor = copy_num(_one_); + build = copy_num(_zero_); + decimal = 0; + for (;;){ + c = (*input)(); + if (isdigit(c)) + digit = c - '0'; + else if ('A' <= c && c <= 'F') + digit = 10 + c - 'A'; + else + break; + int2num(&tmp, digit); + bc_multiply(build, base, &build, 0); + bc_add(build, tmp, &build, 0); + bc_multiply(divisor, base, &divisor, 0); + ++decimal; + } + bc_divide(build, divisor, &build, decimal); + bc_add(result, build, &result, 0); + } + /* Final work. */ + if (negative) + bc_sub(_zero_, result, &result, 0); + + free_num(&tmp); + free_num(&build); + free_num(&base); + if (readahead) + *readahead = c; + full_result.v.number = (dc_num)result; + full_result.dc_type = DC_NUMBER; + return full_result; +} + + +/* return the "length" of the number */ +int +dc_numlen DC_DECLARG((value)) + dc_num value DC_DECLEND +{ + bc_num num = CastNum(value); + + /* is this right??? */ + return num->n_len + num->n_scale; +} + +/* return the scale factor of the passed dc_num + * If discard_p is DC_TOSS then deallocate the value after use. + */ +int +dc_tell_scale DC_DECLARG((value, discard_p)) + dc_num value DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + int kscale; + + kscale = CastNum(value)->n_scale; + if (discard_p == DC_TOSS) + dc_free_num(&value); + return kscale; +} + + +/* initialize the math subsystem */ +void +dc_math_init DC_DECLVOID() +{ + init_numbers(); +} + +/* print out a dc_num in output base obase to stdout; + * if newline_p is DC_WITHNL, terminate output with a '\n'; + * if discard_p is DC_TOSS then deallocate the value after use + */ +void +dc_out_num DC_DECLARG((value, obase, newline_p, discard_p)) + dc_num value DC_DECLSEP + int obase DC_DECLSEP + dc_newline newline_p DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + out_num(CastNum(value), obase, out_char); + if (newline_p == DC_WITHNL) + out_char('\n'); + if (discard_p == DC_TOSS) + dc_free_num(&value); +} + +/* dump out the absolute value of the integer part of a + * dc_num as a byte stream, without any line wrapping; + * if discard_p is DC_TOSS then deallocate the value after use + */ +void +dc_dump_num DC_DECLARG((value, discard_p)) + dc_num dcvalue DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + struct digit_stack { int digit; struct digit_stack *link;}; + struct digit_stack *top_of_stack = NULL; + struct digit_stack *cur; + struct digit_stack *next; + bc_num value; + bc_num obase; + bc_num digit; + + init_num(&value); + init_num(&obase); + init_num(&digit); + + /* we only handle the integer portion: */ + bc_divide(CastNum(dcvalue), _one_, &value, 0); + /* we only handle the absolute value: */ + value->n_sign = PLUS; + /* we're done with the dcvalue parameter: */ + if (discard_p == DC_TOSS) + dc_free_num(&dcvalue); + + int2num(&obase, 1+UCHAR_MAX); + do { + (void) bc_divmod(value, obase, &value, &digit, 0); + cur = dc_malloc(sizeof *cur); + cur->digit = (int)num2long(digit); + cur->link = top_of_stack; + top_of_stack = cur; + } while (!is_zero(value)); + + for (cur=top_of_stack; cur; cur=next) { + putchar(cur->digit); + next = cur->link; + free(cur); + } + + free_num(&digit); + free_num(&obase); + free_num(&value); +} + +/* deallocate an instance of a dc_num */ +void +dc_free_num DC_DECLARG((value)) + dc_num *value DC_DECLEND +{ + free_num((bc_num *)value); +} + +/* return a duplicate of the number in the passed value */ +/* The mismatched data types forces the caller to deal with + * bad dc_type'd dc_data values, and makes it more convenient + * for the caller to not have to do the grunge work of setting + * up a dc_type result. + */ +dc_data +dc_dup_num DC_DECLARG((value)) + dc_num value DC_DECLEND +{ + dc_data result; + + ++CastNum(value)->n_refs; + result.v.number = value; + result.dc_type = DC_NUMBER; + return result; +} + + + +/*---------------------------------------------------------------------------\ +| The rest of this file consists of stubs for bc routines called by numeric.c| +| so as to minimize the amount of bc code needed to build dc. | +| The bulk of the code was just lifted straight out of the bc source. | +\---------------------------------------------------------------------------*/ + +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#ifdef HAVE_STDARG_H +# include <stdarg.h> +#else +# include <varargs.h> +#endif + + +int out_col = 0; + +/* Output routines: Write a character CH to the standard output. + It keeps track of the number of characters output and may + break the output with a "\<cr>". */ + +void +out_char (ch) + char ch; +{ + + if (ch == '\n') + { + out_col = 0; + putchar ('\n'); + } + else + { + out_col++; + if (out_col == 70) + { + putchar ('\\'); + putchar ('\n'); + out_col = 1; + } + putchar (ch); + } +} + +/* Malloc could not get enough memory. */ + +void +out_of_memory() +{ + dc_memfail(); +} + +/* Runtime error will print a message and stop the machine. */ + +#ifdef HAVE_STDARG_H +#ifdef __STDC__ +void +rt_error (char *mesg, ...) +#else +void +rt_error (mesg) + char *mesg; +#endif +#else +void +rt_error (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + char error_mesg [255]; + +#ifdef HAVE_STDARG_H + va_start (args, mesg); +#else + va_start (args); +#endif + vsprintf (error_mesg, mesg, args); + va_end (args); + + fprintf (stderr, "Runtime error: %s\n", error_mesg); +} + + +/* A runtime warning tells of some action taken by the processor that + may change the program execution but was not enough of a problem + to stop the execution. */ + +#ifdef HAVE_STDARG_H +#ifdef __STDC__ +void +rt_warn (char *mesg, ...) +#else +void +rt_warn (mesg) + char *mesg; +#endif +#else +void +rt_warn (mesg, va_alist) + char *mesg; +#endif +{ + va_list args; + char error_mesg [255]; + +#ifdef HAVE_STDARG_H + va_start (args, mesg); +#else + va_start (args); +#endif + vsprintf (error_mesg, mesg, args); + va_end (args); + + fprintf (stderr, "Runtime warning: %s\n", error_mesg); +} diff --git a/gnu/usr.bin/bc/dc/stack.c b/gnu/usr.bin/bc/dc/stack.c new file mode 100644 index 00000000000..0268b70d0ed --- /dev/null +++ b/gnu/usr.bin/bc/dc/stack.c @@ -0,0 +1,489 @@ +/* + * implement stack functions for dc + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* This module is the only one that knows what stacks (both the + * regular evaluation stack and the named register stacks) + * look like. + */ + +#include "config.h" + +#include <stdio.h> +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif +#include "dc.h" +#include "dc-proto.h" +#include "dc-regdef.h" + +/* an oft-used error message: */ +#define Empty_Stack fprintf(stderr, "%s: stack empty\n", progname) + + +/* simple linked-list implementaion suffices: */ +struct dc_list { + dc_data value; + struct dc_array *array; /* opaque */ + struct dc_list *link; +}; +typedef struct dc_list dc_list; + +/* the anonymous evaluation stack */ +static dc_list *dc_stack=NULL; + +/* the named register stacks */ +static dc_list *dc_register[DC_REGCOUNT]; + + +/* allocate a new dc_list item */ +static dc_list * +dc_alloc DC_DECLVOID() +{ + dc_list *result; + + result = dc_malloc(sizeof *result); + result->value.dc_type = DC_UNINITIALIZED; + result->array = NULL; + result->link = NULL; + return result; +} + + +/* check that there are two numbers on top of the stack, + * then call op with the popped numbers. Construct a dc_data + * value from the dc_num returned by op and push it + * on the stack. + * If the op call doesn't return DC_SUCCESS, then leave the stack + * unmodified. + */ +void +dc_binop DC_DECLARG((op, kscale)) + int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *)) DC_DECLSEP + int kscale DC_DECLEND +{ + dc_data a; + dc_data b; + dc_data r; + + if (!dc_stack || !dc_stack->link){ + Empty_Stack; + return; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return; + } + (void)dc_pop(&b); + (void)dc_pop(&a); + if ((*op)(a.v.number, b.v.number, kscale, &r.v.number) == DC_SUCCESS){ + r.dc_type = DC_NUMBER; + dc_push(r); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + }else{ + /* op failed; restore the stack */ + dc_push(a); + dc_push(b); + } +} + +/* check that there are two numbers on top of the stack, + * then call op with the popped numbers. Construct two dc_data + * values from the dc_num's returned by op and push them + * on the stack. + * If the op call doesn't return DC_SUCCESS, then leave the stack + * unmodified. + */ +void +dc_binop2 DC_DECLARG((op, kscale)) + int (*op)DC_PROTO((dc_num, dc_num, int, dc_num *, dc_num *)) DC_DECLSEP + int kscale DC_DECLEND +{ + dc_data a; + dc_data b; + dc_data r1; + dc_data r2; + + if (!dc_stack || !dc_stack->link){ + Empty_Stack; + return; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return; + } + (void)dc_pop(&b); + (void)dc_pop(&a); + if ((*op)(a.v.number, b.v.number, kscale, + &r1.v.number, &r2.v.number) == DC_SUCCESS){ + r1.dc_type = DC_NUMBER; + dc_push(r1); + r2.dc_type = DC_NUMBER; + dc_push(r2); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + }else{ + /* op failed; restore the stack */ + dc_push(a); + dc_push(b); + } +} + +/* check that there are two numbers on top of the stack, + * then call dc_compare with the popped numbers. + * Return negative, zero, or positive based on the ordering + * of the two numbers. + */ +int +dc_cmpop DC_DECLVOID() +{ + int result; + dc_data a; + dc_data b; + + if (!dc_stack || !dc_stack->link){ + Empty_Stack; + return 0; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return 0; + } + (void)dc_pop(&b); + (void)dc_pop(&a); + result = dc_compare(b.v.number, a.v.number); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + return result; +} + +/* check that there are three numbers on top of the stack, + * then call op with the popped numbers. Construct a dc_data + * value from the dc_num returned by op and push it + * on the stack. + * If the op call doesn't return DC_SUCCESS, then leave the stack + * unmodified. + */ +void +dc_triop DC_DECLARG((op, kscale)) + int (*op)DC_PROTO((dc_num, dc_num, dc_num, int, dc_num *)) DC_DECLSEP + int kscale DC_DECLEND +{ + dc_data a; + dc_data b; + dc_data c; + dc_data r; + + if (!dc_stack || !dc_stack->link || !dc_stack->link->link){ + Empty_Stack; + return; + } + if (dc_stack->value.dc_type!=DC_NUMBER + || dc_stack->link->value.dc_type!=DC_NUMBER + || dc_stack->link->link->value.dc_type!=DC_NUMBER){ + fprintf(stderr, "%s: non-numeric value\n", progname); + return; + } + (void)dc_pop(&c); + (void)dc_pop(&b); + (void)dc_pop(&a); + if ((*op)(a.v.number, b.v.number, c.v.number, + kscale, &r.v.number) == DC_SUCCESS){ + r.dc_type = DC_NUMBER; + dc_push(r); + dc_free_num(&a.v.number); + dc_free_num(&b.v.number); + dc_free_num(&c.v.number); + }else{ + /* op failed; restore the stack */ + dc_push(a); + dc_push(b); + dc_push(c); + } +} + + +/* initialize the register stacks to their initial values */ +void +dc_register_init DC_DECLVOID() +{ + int i; + + for (i=0; i<DC_REGCOUNT; ++i) + dc_register[i] = NULL; +} + +/* clear the evaluation stack */ +void +dc_clear_stack DC_DECLVOID() +{ + dc_list *n; + dc_list *t; + + for (n=dc_stack; n; n=t){ + t = n->link; + if (n->value.dc_type == DC_NUMBER) + dc_free_num(&n->value.v.number); + else if (n->value.dc_type == DC_STRING) + dc_free_str(&n->value.v.string); + else + dc_garbage("in stack", -1); + dc_array_free(n->array); + free(n); + } + dc_stack = NULL; +} + +/* push a value onto the evaluation stack */ +void +dc_push DC_DECLARG((value)) + dc_data value DC_DECLEND +{ + dc_list *n = dc_alloc(); + + if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING) + dc_garbage("in data being pushed", -1); + n->value = value; + n->link = dc_stack; + dc_stack = n; +} + +/* push a value onto the named register stack */ +void +dc_register_push DC_DECLARG((stackid, value)) + int stackid DC_DECLSEP + dc_data value DC_DECLEND +{ + dc_list *n = dc_alloc(); + + stackid = regmap(stackid); + n->value = value; + n->link = dc_register[stackid]; + dc_register[stackid] = n; +} + +/* set *result to the value on the top of the evaluation stack */ +/* The caller is responsible for duplicating the value if it + * is to be maintained as anything more than a transient identity. + * + * DC_FAIL is returned if the stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_top_of_stack DC_DECLARG((result)) + dc_data *result DC_DECLEND +{ + if (!dc_stack){ + Empty_Stack; + return DC_FAIL; + } + if (dc_stack->value.dc_type!=DC_NUMBER + && dc_stack->value.dc_type!=DC_STRING) + dc_garbage("at top of stack", -1); + *result = dc_stack->value; + return DC_SUCCESS; +} + +/* set *result to a dup of the value on the top of the named register stack */ +/* + * DC_FAIL is returned if the named stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_register_get DC_DECLARG((regid, result)) + int regid DC_DECLSEP + dc_data *result DC_DECLEND +{ + dc_list *r; + + regid = regmap(regid); + r = dc_register[regid]; + if ( ! r ){ + fprintf(stderr, "%s: register ", progname); + dc_show_id(stderr, regid, " is empty\n"); + return DC_FAIL; + } + *result = dc_dup(r->value); + return DC_SUCCESS; +} + +/* set the top of the named register stack to the indicated value */ +/* If the named stack is empty, craft a stack entry to enter the + * value into. + */ +void +dc_register_set DC_DECLARG((regid, value)) + int regid DC_DECLSEP + dc_data value DC_DECLEND +{ + dc_list *r; + + regid = regmap(regid); + r = dc_register[regid]; + if ( ! r ) + dc_register[regid] = dc_alloc(); + else if (r->value.dc_type == DC_NUMBER) + dc_free_num(&r->value.v.number); + else if (r->value.dc_type == DC_STRING) + dc_free_str(&r->value.v.string); + else + dc_garbage("", regid); + dc_register[regid]->value = value; +} + +/* pop from the evaluation stack + * + * DC_FAIL is returned if the stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_pop DC_DECLARG((result)) + dc_data *result DC_DECLEND +{ + dc_list *r; + + r = dc_stack; + if (!r){ + Empty_Stack; + return DC_FAIL; + } + if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING) + dc_garbage("at top of stack", -1); + *result = r->value; + dc_stack = r->link; + dc_array_free(r->array); + free(r); + return DC_SUCCESS; +} + +/* pop from the named register stack + * + * DC_FAIL is returned if the named stack is empty (and *result unchanged), + * DC_SUCCESS is returned otherwise + */ +int +dc_register_pop DC_DECLARG((stackid, result)) + int stackid DC_DECLSEP + dc_data *result DC_DECLEND +{ + dc_list *r; + + stackid = regmap(stackid); + r = dc_register[stackid]; + if (!r){ + fprintf(stderr, "%s: stack register ", progname); + dc_show_id(stderr, stackid, " is empty\n"); + return DC_FAIL; + } + if (r->value.dc_type!=DC_NUMBER && r->value.dc_type!=DC_STRING) + dc_garbage(" stack", stackid); + *result = r->value; + dc_register[stackid] = r->link; + dc_array_free(r->array); + free(r); + return DC_SUCCESS; +} + + +/* tell how many entries are currently on the evaluation stack */ +int +dc_tell_stackdepth DC_DECLVOID() +{ + dc_list *n; + int depth=0; + + for (n=dc_stack; n; n=n->link) + ++depth; + return depth; +} + + +/* return the length of the indicated data value; + * if discard_p is DC_TOSS, the deallocate the value when done + * + * The definition of a datum's length is deligated to the + * appropriate module. + */ +int +dc_tell_length DC_DECLARG((value, discard_p)) + dc_data value DC_DECLSEP + dc_discard discard_p DC_DECLEND +{ + int length; + + if (value.dc_type == DC_NUMBER){ + length = dc_numlen(value.v.number); + if (discard_p == DC_TOSS) + dc_free_num(&value.v.number); + } else if (value.dc_type == DC_STRING) { + length = dc_strlen(value.v.string); + if (discard_p == DC_TOSS) + dc_free_str(&value.v.string); + } else { + dc_garbage("in tell_length", -1); + /*NOTREACHED*/ + length = 0; /*just to suppress spurious compiler warnings*/ + } + return length; +} + + + +/* print out all of the values on the evaluation stack */ +void +dc_printall DC_DECLARG((obase)) + int obase DC_DECLEND +{ + dc_list *n; + + for (n=dc_stack; n; n=n->link) + dc_print(n->value, obase, DC_WITHNL, DC_KEEP); +} + + + + +/* get the current array head for the named array */ +struct dc_array * +dc_get_stacked_array DC_DECLARG((array_id)) + int array_id DC_DECLEND +{ + dc_list *r = dc_register[regmap(array_id)]; + return r ? r->array : NULL; +} + +/* set the current array head for the named array */ +void +dc_set_stacked_array DC_DECLARG((array_id, new_head)) + int array_id DC_DECLSEP + struct dc_array *new_head DC_DECLEND +{ + dc_list *r; + + array_id = regmap(array_id); + r = dc_register[array_id]; + if ( ! r ) + r = dc_register[array_id] = dc_alloc(); + r->array = new_head; +} diff --git a/gnu/usr.bin/bc/dc/string.c b/gnu/usr.bin/bc/dc/string.c new file mode 100644 index 00000000000..6cffffded51 --- /dev/null +++ b/gnu/usr.bin/bc/dc/string.c @@ -0,0 +1,208 @@ +/* + * implement string functions for dc + * + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +/* This should be the only module that knows the internals of type dc_string */ + +#include "config.h" + +#include <stdio.h> +#ifdef HAVE_STDDEF_H +# include <stddef.h> /* ptrdiff_t */ +#else +# define ptrdiff_t size_t +#endif +#ifdef HAVE_STDLIB_H +# include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +# include <string.h> /* memcpy */ +#else +# ifdef HAVE_MEMORY_H +# include <memory.h> /* memcpy, maybe */ +# else +# ifdef HAVE_STRINGS_H +# include <strings.h> /* memcpy, maybe */ +# endif +# endif +#endif +#include "dc.h" +#include "dc-proto.h" + +/* here is the completion of the dc_string type: */ +struct dc_string { + char *s_ptr; /* pointer to base of string */ + size_t s_len; /* length of counted string */ + int s_refs; /* reference count to cut down on memory use by duplicates */ +}; + + +/* return a duplicate of the string in the passed value */ +/* The mismatched data types forces the caller to deal with + * bad dc_type'd dc_data values, and makes it more convenient + * for the caller to not have to do the grunge work of setting + * up a dc_type result. + */ +dc_data +dc_dup_str DC_DECLARG((value)) + dc_str value DC_DECLEND +{ + dc_data result; + + ++value->s_refs; + result.v.string = value; + result.dc_type = DC_STRING; + return result; +} + +/* free an instance of a dc_str value */ +void +dc_free_str DC_DECLARG((value)) + dc_str *value DC_DECLEND +{ + struct dc_string *string = *value; + + if (--string->s_refs < 1){ + free(string->s_ptr); + free(string); + } +} + +/* Output a dc_str value. + * Add a trailing newline if "newline" is set. + * Free the value after use if discard_flag is set. + */ +void +dc_out_str DC_DECLARG((value, newline, discard_flag)) + dc_str value DC_DECLSEP + dc_newline newline DC_DECLSEP + dc_discard discard_flag DC_DECLEND +{ + fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout); + if (newline == DC_WITHNL) + putchar('\n'); + if (discard_flag == DC_TOSS) + dc_free_str(&value); +} + +/* make a copy of a string (base s, length len) + * into a dc_str value; return a dc_data result + * with this value + */ +dc_data +dc_makestring DC_DECLARG((s, len)) + const char *s DC_DECLSEP + size_t len DC_DECLEND +{ + dc_data result; + struct dc_string *string; + + string = dc_malloc(sizeof *string); + string->s_ptr = dc_malloc(len+1); + memcpy(string->s_ptr, s, len); + string->s_ptr[len] = '\0'; /* nul terminated for those who need it */ + string->s_len = len; + string->s_refs = 1; + result.v.string = string; + result.dc_type = DC_STRING; + return result; +} + +/* read a dc_str value from FILE *fp; + * if ldelim == rdelim, then read until a ldelim char or EOF is reached; + * if ldelim != rdelim, then read until a matching rdelim for the + * (already eaten) first ldelim is read. + * Return a dc_data result with the dc_str value as its contents. + */ +dc_data +dc_readstring DC_DECLARG((fp, ldelim, rdelim)) + FILE *fp DC_DECLSEP + int ldelim DC_DECLSEP + int rdelim DC_DECLEND +{ + static char *line_buf = NULL; /* a buffer to build the string in */ + static size_t buflen = 0; /* the current size of line_buf */ + int depth=1; + int c; + char *p; + const char *end; + + if (!line_buf){ + /* initial buflen should be large enough to handle most cases */ + buflen = 2016; + line_buf = dc_malloc(buflen); + } + p = line_buf; + end = line_buf + buflen; + for (;;){ + c = getc(fp); + if (c == EOF) + break; + else if (c == rdelim && --depth < 1) + break; + else if (c == ldelim) + ++depth; + if (p >= end){ + ptrdiff_t offset = p - line_buf; + /* buflen increment should be big enough + * to avoid execessive reallocs: + */ + buflen += 2048; + line_buf = realloc(line_buf, buflen); + if (!line_buf) + dc_memfail(); + p = line_buf + offset; + end = line_buf + buflen; + } + *p++ = c; + } + return dc_makestring(line_buf, (size_t)(p-line_buf)); +} + +/* return the base pointer of the dc_str value; + * This function is needed because no one else knows what dc_str + * looks like. + */ +const char * +dc_str2charp DC_DECLARG((value)) + dc_str value DC_DECLEND +{ + return value->s_ptr; +} + +/* return the length of the dc_str value; + * This function is needed because no one else knows what dc_str + * looks like, and strlen(dc_str2charp(value)) won't work + * if there's an embedded '\0'. + */ +size_t +dc_strlen DC_DECLARG((value)) + dc_str value DC_DECLEND +{ + return value->s_len; +} + + +/* initialize the strings subsystem */ +void +dc_string_init DC_DECLVOID() +{ + /* nothing to do for this implementation */ +} diff --git a/gnu/usr.bin/bc/doc/Makefile.am b/gnu/usr.bin/bc/doc/Makefile.am new file mode 100644 index 00000000000..d4ed7ebdcc8 --- /dev/null +++ b/gnu/usr.bin/bc/doc/Makefile.am @@ -0,0 +1,10 @@ +## Process this file with automake to produce Makefile.in + +info_TEXINFOS = dc.texi +MAKEINFO = makeinfo --no-split + +# FIXME: remove this when automake has been fixed to include these +# files automatically +EXTRA_DIST = bc.1 dc.1 + +man_MANS = bc.1 dc.1 diff --git a/gnu/usr.bin/bc/doc/Makefile.in b/gnu/usr.bin/bc/doc/Makefile.in new file mode 100644 index 00000000000..2593d258774 --- /dev/null +++ b/gnu/usr.bin/bc/doc/Makefile.in @@ -0,0 +1,329 @@ +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +info_TEXINFOS = dc.texi +MAKEINFO = makeinfo --no-split + +# FIXME: remove this when automake has been fixed to include these +# files automatically +EXTRA_DIST = bc.1 dc.1 + +man_MANS = bc.1 dc.1 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +TEXI2DVI = texi2dvi +TEXINFO_TEX = $(srcdir)/texinfo.tex +INFO_DEPS = dc.info +DVIS = dc.dvi +TEXINFOS = dc.texi +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in texinfo.tex + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +all: Makefile $(INFO_DEPS) $(MANS) + +.SUFFIXES: +.SUFFIXES: .dvi .info .ps .texi .texinfo .txi +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps doc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +dc.info: dc.texi +dc.dvi: dc.texi + + +DVIPS = dvips + +.texi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texi.dvi: + TEXINPUTS=$(srcdir):$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.texi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texinfo.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texinfo: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.texinfo.dvi: + TEXINPUTS=$(srcdir):$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.txi.info: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` + +.txi.dvi: + TEXINPUTS=$(srcdir):$$TEXINPUTS \ + MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $< + +.txi: + @cd $(srcdir) && rm -f $@ $@-[0-9] $@-[0-9][0-9] + cd $(srcdir) \ + && $(MAKEINFO) `echo $< | sed 's,.*/,,'` +.dvi.ps: + $(DVIPS) $< -o $@ + +install-info-am: $(INFO_DEPS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(infodir) + @for file in $(INFO_DEPS); do \ + d=$(srcdir); \ + for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9]`; do \ + if test -f $$d/$$ifile; then \ + echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; \ + $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; \ + else : ; fi; \ + done; \ + done + @$(POST_INSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + for file in $(INFO_DEPS); do \ + echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file";\ + install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :;\ + done; \ + else : ; fi + +uninstall-info: + $(PRE_UNINSTALL) + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then \ + ii=yes; \ + else ii=; fi; \ + for file in $(INFO_DEPS); do \ + test -z "$ii" \ + || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; \ + done + @$(NORMAL_UNINSTALL) + for file in $(INFO_DEPS); do \ + (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9]); \ + done + +dist-info: $(INFO_DEPS) + for base in $(INFO_DEPS); do \ + d=$(srcdir); \ + for file in `cd $$d && eval echo $$base*`; do \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done; \ + done + +mostlyclean-aminfo: + -rm -f dc.aux dc.cp dc.cps dc.dvi dc.fn dc.fns dc.ky dc.kys dc.ps \ + dc.log dc.pg dc.toc dc.tp dc.tps dc.vr dc.vrs dc.op dc.tr \ + dc.cv dc.cn + +clean-aminfo: + +distclean-aminfo: + +maintainer-clean-aminfo: + for i in $(INFO_DEPS); do \ + rm -f $$i; \ + if test "`echo $$i-[0-9]*`" != "$$i-[0-9]*"; then \ + rm -f $$i-[0-9]*; \ + fi; \ + done + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) uninstall-man1 +tags: TAGS +TAGS: + + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = doc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done + $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info +info: $(INFO_DEPS) +dvi: $(DVIS) +check: all + $(MAKE) +installcheck: +install-exec: + @$(NORMAL_INSTALL) + +install-data: install-info-am install-man + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: uninstall-info uninstall-man + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(infodir) $(DESTDIR)$(mandir)/man1 + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-aminfo mostlyclean-generic + +clean: clean-aminfo clean-generic mostlyclean + +distclean: distclean-aminfo distclean-generic clean + -rm -f config.status + +maintainer-clean: maintainer-clean-aminfo maintainer-clean-generic \ + distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: install-info-am uninstall-info mostlyclean-aminfo \ +distclean-aminfo clean-aminfo maintainer-clean-aminfo install-man1 \ +uninstall-man1 install-man uninstall-man tags distdir info dvi \ +installcheck install-exec install-data install uninstall all \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gnu/usr.bin/bc/doc/bc.1 b/gnu/usr.bin/bc/doc/bc.1 new file mode 100644 index 00000000000..e0cef9cff86 --- /dev/null +++ b/gnu/usr.bin/bc/doc/bc.1 @@ -0,0 +1,787 @@ +.\" +.\" bc.1 - the *roff document processor source for the bc manual +.\" +.\" This file is part of GNU bc. +.\" Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License , or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; see the file COPYING. If not, write to +.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.\" You may contact the author by: +.\" e-mail: phil@cs.wwu.edu +.\" us-mail: Philip A. Nelson +.\" Computer Science Department, 9062 +.\" Western Washington University +.\" Bellingham, WA 98226-9062 +.\" +.\" +.TH bc 1 .\" "Command Manual" v1.04 "June 22, 1995" +.SH NAME +bc - An arbitrary precision calculator language +.SH SYNTAX +\fBbc\fR [ \fB-lwsqv\fR ] [long-options] [ \fI file ...\fR ] +.SH VERSION +This man page documents GNU bc version 1.04. +.SH DESCRIPTION +\fBbc\fR is a language that supports arbitrary precision numbers +with interactive execution of statements. There are some similarities +in the syntax to the C programming language. +A standard math library is available by command line option. +If requested, the math library is defined before processing any files. +\fBbc\fR starts by processing code from all the files listed +on the command line in the order listed. After all files have been +processed, \fBbc\fR reads from the standard input. All code is +executed as it is read. (If a file contains a command to halt the +processor, \fBbc\fR will never read from the standard input.) +.PP +This version of \fBbc\fR contains several extensions beyond +traditional \fBbc\fR implementations and the POSIX draft standard. +Command line options can cause these extensions to print a warning +or to be rejected. This +document describes the language accepted by this processor. +Extensions will be identified as such. +.SS OPTIONS +.IP -l +Define the standard math library. +.IP -w +Give warnings for extensions to POSIX \fBbc\fR. +.IP -s +Process exactly the POSIX \fBbc\fR language. +.IP -q +Do not print the normal GNU bc welcome. +.IP -v +Print the version number and copyright and quit. +.IP --mathlib +Define the standard math library. +.IP --warn +Give warnings for extensions to POSIX \fBbc\fR. +.IP --standard +Process exactly the POSIX \fBbc\fR language. +.IP --quiet +Do not print the normal GNU bc welcome. +.IP --version +Print the version number and copyright and quit. +.SS NUMBERS +The most basic element in \fBbc\fR is the number. Numbers are +arbitrary precision numbers. This precision is both in the integer +part and the fractional part. All numbers are represented internally +in decimal and all computation is done in decimal. (This version +truncates results from divide and multiply operations.) There are two +attributes of numbers, the length and the scale. The length is the +total number of significant decimal digits in a number and the scale +is the total number of decimal digits after the decimal point. For +example: +.nf +.RS + .000001 has a length of 6 and scale of 6. + 1935.000 has a length of 7 and a scale of 3. +.RE +.fi +.SS VARIABLES +Numbers are stored in two types of variables, simple variables and +arrays. Both simple variables and array variables are named. Names +begin with a letter followed by any number of letters, digits and +underscores. All letters must be lower case. (Full alpha-numeric +names are an extension. In POSIX \fBbc\fR all names are a single +lower case letter.) The type of variable is clear by the context +because all array variable names will be followed by brackets ([]). +.PP +There are four special variables, \fBscale, ibase, obase,\fR and +\fBlast\fR. \fBscale\fR defines how some operations use digits after the +decimal point. The default value of \fBscale\fR is 0. \fBibase\fR +and \fBobase\fR define the conversion base for input and output +numbers. The default for both input and output is base 10. +\fBlast\fR (an extension) is a variable that has the value of the last +printed number. These will be discussed in further detail where +appropriate. All of these variables may have values assigned to them +as well as used in expressions. +.SS COMMENTS +Comments in \fBbc\fR start with the characters \fB/*\fR and end with +the characters \fB*/\fR. Comments may start anywhere and appear as a +single space in the input. (This causes comments to delimit other +input items. For example, a comment can not be found in the middle of +a variable name.) Comments include any newlines (end of line) between +the start and the end of the comment. +.PP +To support the use of scripts for \fBbc\fR, a single line comment has been +added as an extension. A single line comment starts at a \fB#\fR +character and continues to the next end of the line. The end of line +character is not part of the comment and is processed normally. +.SS EXPRESSIONS +The numbers are manipulated by expressions and statements. Since +the language was designed to be interactive, statements and expressions +are executed as soon as possible. There is no "main" program. Instead, +code is executed as it is encountered. (Functions, discussed in +detail later, are defined when encountered.) +.PP +A simple expression is just a constant. \fBbc\fR converts constants +into internal decimal numbers using the current input base, specified +by the variable \fBibase\fR. (There is an exception in functions.) +The legal values of \fBibase\fR are 2 through 16. Assigning a +value outside this range to \fBibase\fR will result in a value of 2 +or 16. Input numbers may contain the characters 0-9 and A-F. (Note: +They must be capitals. Lower case letters are variable names.) +Single digit numbers always have the value of the digit regardless of +the value of \fBibase\fR. (i.e. A = 10.) For multi-digit numbers, +\fBbc\fR changes all input digits greater or equal to ibase to the +value of \fBibase\fR-1. This makes the number \fBFFF\fR always be +the largest 3 digit number of the input base. +.PP +Full expressions are similar to many other high level languages. +Since there is only one kind of number, there are no rules for mixing +types. Instead, there are rules on the scale of expressions. Every +expression has a scale. This is derived from the scale of original +numbers, the operation performed and in many cases, the value of the +variable \fBscale\fR. Legal values of the variable \fBscale\fR are +0 to the maximum number representable by a C integer. +.PP +In the following descriptions of legal expressions, "expr" refers to a +complete expression and "var" refers to a simple or an array variable. +A simple variable is just a +.RS +\fIname\fR +.RE +and an array variable is specified as +.RS +\fIname\fR[\fIexpr\fR] +.RE +Unless specifically +mentioned the scale of the result is the maximum scale of the +expressions involved. +.IP "- expr" +The result is the negation of the expression. +.IP "++ var" +The variable is incremented by one and the new value is the result of +the expression. +.IP "-- var" +The variable +is decremented by one and the new value is the result of the +expression. +.IP "var ++" + The result of the expression is the value of +the variable and then the variable is incremented by one. +.IP "var --" +The result of the expression is the value of the variable and then +the variable is decremented by one. +.IP "expr + expr" +The result of the expression is the sum of the two expressions. +.IP "expr - expr" +The result of the expression is the difference of the two expressions. +.IP "expr * expr" +The result of the expression is the product of the two expressions. +.IP "expr / expr" +The result of the expression is the quotient of the two expressions. +The scale of the result is the value of the variable \fBscale\fR. +.IP "expr % expr" +The result of the expression is the "remainder" and it is computed in the +following way. To compute a%b, first a/b is computed to \fBscale\fR +digits. That result is used to compute a-(a/b)*b to the scale of the +maximum of \fBscale\fR+scale(b) and scale(a). If \fBscale\fR is set +to zero and both expressions are integers this expression is the +integer remainder function. +.IP "expr ^ expr" +The result of the expression is the value of the first raised to the +second. The second expression must be an integer. (If the second +expression is not an integer, a warning is generated and the +expression is truncated to get an integer value.) The scale of the +result is \fBscale\fR if the exponent is negative. If the exponent +is positive the scale of the result is the minimum of the scale of the +first expression times the value of the exponent and the maximum of +\fBscale\fR and the scale of the first expression. (e.g. scale(a^b) += min(scale(a)*b, max( \fBscale,\fR scale(a))).) It should be noted +that expr^0 will always return the value of 1. +.IP "( expr )" +This alters the standard precedence to force the evaluation of the +expression. +.IP "var = expr" +The variable is assigned the value of the expression. +.IP "var <op>= expr" +This is equivalent to "var = var <op> expr" with the exception that +the "var" part is evaluated only once. This can make a difference if +"var" is an array. +.PP + Relational expressions are a special kind of expression +that always evaluate to 0 or 1, 0 if the relation is false and 1 if +the relation is true. These may appear in any legal expression. +(POSIX bc requires that relational expressions are used only in if, +while, and for statements and that only one relational test may be +done in them.) The relational operators are +.IP "expr1 < expr2" +The result is 1 if expr1 is strictly less than expr2. +.IP "expr1 <= expr2" +The result is 1 if expr1 is less than or equal to expr2. +.IP "expr1 > expr2" +The result is 1 if expr1 is strictly greater than expr2. +.IP "expr1 >= expr2" +The result is 1 if expr1 is greater than or equal to expr2. +.IP "expr1 == expr2" +The result is 1 if expr1 is equal to expr2. +.IP "expr1 != expr2" +The result is 1 if expr1 is not equal to expr2. +.PP +Boolean operations are also legal. (POSIX \fBbc\fR does NOT have +boolean operations). The result of all boolean operations are 0 and 1 +(for false and true) as in relational expressions. The boolean +operators are: +.IP "!expr" +The result is 1 if expr is 0. +.IP "expr && expr" +The result is 1 if both expressions are non-zero. +.IP "expr || expr" +The result is 1 if either expression is non-zero. +.PP +The expression precedence is as follows: (lowest to highest) +.nf +.RS +|| operator, left associative +&& operator, left associative +! operator, nonassociative +Relational operators, left associative +Assignment operator, right associative ++ and - operators, left associative +*, / and % operators, left associative +^ operator, right associative +unary - operator, nonassociative +++ and -- operators, nonassociative +.RE +.fi +.PP +This precedence was chosen so that POSIX compliant \fBbc\fR programs +will run correctly. This will cause the use of the relational and +logical operators to have some unusual behavior when used with +assignment expressions. Consider the expression: +.RS +a = 3 < 5 +.RE +.PP +Most C programmers would assume this would assign the result of "3 < +5" (the value 1) to the variable "a". What this does in \fBbc\fR is +assign the value 3 to the variable "a" and then compare 3 to 5. It is +best to use parenthesis when using relational and logical operators +with the assignment operators. +.PP +There are a few more special expressions that are provided in \fBbc\fR. +These have to do with user defined functions and standard +functions. They all appear as "\fIname\fB(\fIparameters\fB)\fR". +See the section on functions for user defined functions. The standard +functions are: +.IP "length ( expression )" +The value of the length function is the number of significant digits in the +expression. +.IP "read ( )" +The read function (an extension) will read a number from the standard +input, regardless of where the function occurs. Beware, this can +cause problems with the mixing of data and program in the standard input. +The best use for this function is in a previously written program that +needs input from the user, but never allows program code to be input +from the user. The value of the read function is the number read from +the standard input using the current value of the variable +\fBibase\fR for the conversion base. +.IP "scale ( expression )" +The value of the scale function is the number of digits after the decimal +point in the expression. +.IP "sqrt ( expression )" +The value of the sqrt function is the square root of the expression. If +the expression is negative, a run time error is generated. +.SS STATEMENTS +Statements (as in most algebraic languages) provide the sequencing of +expression evaluation. In \fBbc\fR statements are executed "as soon +as possible." Execution happens when a newline in encountered and +there is one or more complete statements. Due to this immediate +execution, newlines are very important in \fBbc\fR. In fact, both a +semicolon and a newline are used as statement separators. An +improperly placed newline will cause a syntax error. Because newlines +are statement separators, it is possible to hide a newline by using +the backslash character. The sequence "\e<nl>", where <nl> is the +newline appears to \fBbc\fR as whitespace instead of a newline. A +statement list is a series of statements separated by semicolons and +newlines. The following is a list of \fBbc\fR statements and what +they do: (Things enclosed in brackets ([]) are optional parts of the +statement.) +.IP "expression" +This statement does one of two things. If the expression starts with +"<variable> <assignment> ...", it is considered to be an assignment +statement. If the expression is not an assignment statement, the +expression is evaluated and printed to the output. After the number +is printed, a newline is printed. For example, "a=1" is an assignment +statement and "(a=1)" is an expression that has an embedded +assignment. All numbers that are printed are printed in the base +specified by the variable \fBobase\fR. The legal values for \fB +obase\fR are 2 through BC_BASE_MAX. (See the section LIMITS.) For +bases 2 through 16, the usual method of writing numbers is used. For +bases greater than 16, \fBbc\fR uses a multi-character digit method +of printing the numbers where each higher base digit is printed as a +base 10 number. The multi-character digits are separated by spaces. +Each digit contains the number of characters required to represent the +base ten value of "obase-1". Since numbers are of arbitrary +precision, some numbers may not be printable on a single output line. +These long numbers will be split across lines using the "\e" as the +last character on a line. The maximum number of characters printed +per line is 70. Due to the interactive nature of \fBbc\fR printing +a number cause the side effect of assigning the printed value the the +special variable \fBlast\fR. This allows the user to recover the +last value printed without having to retype the expression that +printed the number. Assigning to \fBlast\fR is legal and will +overwrite the last printed value with the assigned value. The newly +assigned value will remain until the next number is printed or another +value is assigned to \fBlast\fR. (Some installations may allow the +use of a single period (.) which is not part of a number as a short +hand notation for for \fBlast\fR.) +.IP "string" +The string is printed to the output. Strings start with a double quote +character and contain all characters until the next double quote character. +All characters are take literally, including any newline. No newline +character is printed after the string. +.IP "\fBprint\fR list" +The print statement (an extension) provides another method of output. +The "list" is a list of strings and expressions separated by commas. +Each string or expression is printed in the order of the list. No +terminating newline is printed. Expressions are evaluated and their +value is printed and assigned the the variable \fBlast\fR. Strings +in the print statement are printed to the output and may contain +special characters. Special characters start with the backslash +character (\e). The special characters recognized by \fBbc\fR are +"a" (alert or bell), "b" (backspace), "f" (form feed), "n" (newline), +"r" (carriage return), "q" (double quote), "t" (tab), and "\e" (backslash). +Any other character following the backslash will be ignored. +.IP "{ statement_list }" +This is the compound statement. It allows multiple statements to be +grouped together for execution. +.IP "\fBif\fR ( expression ) statement1 [\fBelse\fR statement2]" +The if statement evaluates the expression and executes statement1 or +statement2 depending on the value of the expression. If the expression +is non-zero, statement1 is executed. If statement2 is present and +the value of the expression is 0, then statement2 is executed. (The +else clause is an extension.) +.IP "\fBwhile\fR ( expression ) statement" +The while statement will execute the statement while the expression +is non-zero. It evaluates the expression before each execution of +the statement. Termination of the loop is caused by a zero +expression value or the execution of a break statement. +.IP "\fBfor\fR ( [expression1] ; [expression2] ; [expression3] ) statement" +The for statement controls repeated execution of the statement. +Expression1 is evaluated before the loop. Expression2 is evaluated +before each execution of the statement. If it is non-zero, the statement +is evaluated. If it is zero, the loop is terminated. After each +execution of the statement, expression3 is evaluated before the reevaluation +of expression2. If expression1 or expression3 are missing, nothing is +evaluated at the point they would be evaluated. +If expression2 is missing, it is the same as substituting +the value 1 for expression2. (The optional expressions are an +extension. POSIX \fBbc\fR requires all three expressions.) +The following is equivalent code for the for statement: +.nf +.RS +expression1; +while (expression2) { + statement; + expression3; +} +.RE +.fi +.IP "\fBbreak\fR" +This statement causes a forced exit of the most recent enclosing while +statement or for statement. +.IP "\fBcontinue\fR" +The continue statement (an extension) causes the most recent enclosing +for statement to start the next iteration. +.IP "\fBhalt\fR" +The halt statement (an extension) is an executed statement that causes +the \fBbc\fR processor to quit only when it is executed. For example, +"if (0 == 1) halt" will not cause \fBbc\fR to terminate because the halt is +not executed. +.IP "\fBreturn\fR" +Return the value 0 from a function. (See the section on functions.) +.IP "\fBreturn\fR ( expression )" +Return the value of the expression from a function. (See the section on +functions.) +.SS PSEUDO STATEMENTS +These statements are not statements in the traditional sense. They are +not executed statements. Their function is performed at "compile" time. +.IP "\fBlimits\fR" +Print the local limits enforced by the local version of \fBbc\fR. This +is an extension. +.IP "\fBquit\fR" +When the quit statement is read, the \fBbc\fR processor +is terminated, regardless of where the quit statement is found. For +example, "if (0 == 1) quit" will cause \fBbc\fR to terminate. +.IP "\fBwarranty\fR" +Print a longer warranty notice. This is an extension. +.SS FUNCTIONS +Functions provide a method of defining a computation that can be executed +later. Functions in +.B bc +always compute a value and return it to the caller. Function definitions +are "dynamic" in the sense that a function is undefined until a definition +is encountered in the input. That definition is then used until another +definition function for the same name is encountered. The new definition +then replaces the older definition. A function is defined as follows: +.nf +.RS +\fBdefine \fIname \fB( \fIparameters \fB) { \fInewline +\fI auto_list statement_list \fB}\fR +.RE +.fi +A function call is just an expression of the form +"\fIname\fB(\fIparameters\fB)\fR". +.PP +Parameters are numbers or arrays (an extension). In the function definition, +zero or more parameters are defined by listing their names separated by +commas. Numbers are only call by value parameters. Arrays are only +call by variable. Arrays are specified in the parameter definition by +the notation "\fIname\fB[]\fR". In the function call, actual parameters +are full expressions for number parameters. The same notation is used +for passing arrays as for defining array parameters. The named array is +passed by variable to the function. Since function definitions are dynamic, +parameter numbers and types are checked when a function is called. Any +mismatch in number or types of parameters will cause a runtime error. +A runtime error will also occur for the call to an undefined function. +.PP +The \fIauto_list\fR is an optional list of variables that are for +"local" use. The syntax of the auto list (if present) is "\fBauto +\fIname\fR, ... ;". (The semicolon is optional.) Each \fIname\fR is +the name of an auto variable. Arrays may be specified by using the +same notation as used in parameters. These variables have their +values pushed onto a stack at the start of the function. The +variables are then initialized to zero and used throughout the +execution of the function. At function exit, these variables are +popped so that the original value (at the time of the function call) +of these variables are restored. The parameters are really auto +variables that are initialized to a value provided in the function +call. Auto variables are different than traditional local variables +in the fact that if function A calls function B, B may access function +A's auto variables by just using the same name, unless function B has +called them auto variables. Due to the fact that auto variables and +parameters are pushed onto a stack, \fBbc\fR supports recursive functions. +.PP +The function body is a list of \fBbc\fR statements. Again, statements +are separated by semicolons or newlines. Return statements cause the +termination of a function and the return of a value. There are two +versions of the return statement. The first form, "\fBreturn\fR", returns +the value 0 to the calling expression. The second form, +"\fBreturn ( \fIexpression \fB)\fR", computes the value of the expression +and returns that value to the calling expression. There is an implied +"\fBreturn (0)\fR" at the end of every function. This allows a function +to terminate and return 0 without an explicit return statement. +.PP +Functions also change the usage of the variable \fBibase\fR. All +constants in the function body will be converted using the value of +\fBibase\fR at the time of the function call. Changes of \fBibase\fR +will be ignored during the execution of the function except for the +standard function \fBread\fR, which will always use the current value +of \fBibase\fR for conversion of numbers. +.SS MATH LIBRARY +If \fBbc\fR is invoked with the \fB-l\fR option, a math library is preloaded +and the default scale is set to 20. The math functions will calculate their +results to the scale set at the time of their call. +The math library defines the following functions: +.IP "s (\fIx\fR)" +The sine of x, x is in radians. +.IP "c (\fIx\fR)" +The cosine of x, x is in radians. +.IP "a (\fIx\fR)" +The arctangent of x, arctangent returns radians. +.IP "l (\fIx\fR)" +The natural logarithm of x. +.IP "e (\fIx\fR)" +The exponential function of raising e to the value x. +.IP "j (\fIn,x\fR)" +The bessel function of integer order n of x. +.SS EXAMPLES +In /bin/sh, the following will assign the value of "pi" to the shell +variable \fBpi\fR. +.RS +\f(CW +pi=$(echo "scale=10; 4*a(1)" | bc -l) +\fR +.RE +.PP +The following is the definition of the exponential function used in the +math library. This function is written in POSIX \fBbc\fR. +.nf +.RS +\f(CW +scale = 20 + +/* Uses the fact that e^x = (e^(x/2))^2 + When x is small enough, we use the series: + e^x = 1 + x + x^2/2! + x^3/3! + ... +*/ + +define e(x) { + auto a, d, e, f, i, m, v, z + + /* Check the sign of x. */ + if (x<0) { + m = 1 + x = -x + } + + /* Precondition x. */ + z = scale; + scale = 4 + z + .44*x; + while (x > 1) { + f += 1; + x /= 2; + } + + /* Initialize the variables. */ + v = 1+x + a = x + d = 1 + + for (i=2; 1; i++) { + e = (a *= x) / (d *= i) + if (e == 0) { + if (f>0) while (f--) v = v*v; + scale = z + if (m) return (1/v); + return (v/1); + } + v += e + } +} +\fR +.RE +.fi +.PP +The following is code that uses the extended features of \fBbc\fR to +implement a simple program for calculating checkbook balances. This +program is best kept in a file so that it can be used many times +without having to retype it at every use. +.nf +.RS +\f(CW +scale=2 +print "\enCheck book program!\en" +print " Remember, deposits are negative transactions.\en" +print " Exit by a 0 transaction.\en\en" + +print "Initial balance? "; bal = read() +bal /= 1 +print "\en" +while (1) { + "current balance = "; bal + "transaction? "; trans = read() + if (trans == 0) break; + bal -= trans + bal /= 1 +} +quit +\fR +.RE +.fi +.PP +The following is the definition of the recursive factorial function. +.nf +.RS +\f(CW +define f (x) { + if (x <= 1) return (1); + return (f(x-1) * x); +} +\fR +.RE +.fi +.SS READLINE OPTION +GNU \fBbc\fR can be compiled (via a configure option) to use the +GNU \fBreadline\fR input editor library. This allows the user +to do more editing of lines before sending them to \fBbc\fR. +It also allows for a history of previous lines typed. When this +option is selected, \fBbc\fR has one more special variable. +This special variable, \fBhistory\fR is the number of lines of +history retained. A value of -1 means that an unlimited number +of history lines are retained. This is the default value. +Setting the value of \fBhistory\fR to a positive number restricts +the number of history lines to the number given. The value of +0 disables the history feature. For more information, read the +user manuals for the GNU \fBreadline\fR and \fBhistory\fR libraries. +.SS DIFFERENCES +This version of +.B bc +was implemented from the POSIX P1003.2/D11 draft and contains +several differences and extensions relative to the draft and +traditional implementations. +It is not implemented in the traditional way using +.I dc(1). +This version is a single process which parses and runs a byte code +translation of the program. There is an "undocumented" option (-c) +that causes the program to output the byte code to +the standard output instead of running it. It was mainly used for +debugging the parser and preparing the math library. +.PP +A major source of differences is +extensions, where a feature is extended to add more functionality and +additions, where new features are added. +The following is the list of differences and extensions. +.IP LANG environment +This version does not conform to the POSIX standard in the processing +of the LANG environment variable and all environment variables starting +with LC_. +.IP names +Traditional and POSIX +.B bc +have single letter names for functions, variables and arrays. They have +been extended to be multi-character names that start with a letter and +may contain letters, numbers and the underscore character. +.IP Strings +Strings are not allowed to contain NUL characters. POSIX says all characters +must be included in strings. +.IP last +POSIX \fBbc\fR does not have a \fBlast\fR variable. Some implementations +of \fBbc\fR use the period (.) in a similar way. +.IP comparisons +POSIX \fBbc\fR allows comparisons only in the if statement, the while +statement, and the second expression of the for statement. Also, only +one relational operation is allowed in each of those statements. +.IP "if statement, else clause" +POSIX \fBbc\fR does not have an else clause. +.IP "for statement" +POSIX \fBbc\fR requires all expressions to be present in the for statement. +.IP "&&, ||, !" +POSIX \fBbc\fR does not have the logical operators. +.IP "read function" +POSIX \fBbc\fR does not have a read function. +.IP "print statement" +POSIX \fBbc\fR does not have a print statement . +.IP "continue statement" +POSIX \fBbc\fR does not have a continue statement. +.IP "array parameters" +POSIX \fBbc\fR does not (currently) support array parameters in full. +The POSIX grammar allows for arrays in function definitions, but does +not provide a method to specify an array as an actual parameter. (This +is most likely an oversight in the grammar.) Traditional implementations +of \fBbc\fR have only call by value array parameters. +.IP "=+, =-, =*, =/, =%, =^" +POSIX \fBbc\fR does not require these "old style" assignment operators to +be defined. This version may allow these "old style" assignments. Use +the limits statement to see if the installed version supports them. If +it does support the "old style" assignment operators, the statement +"a =- 1" will decrement \fBa\fR by 1 instead of setting \fBa\fR to the +value -1. +.IP "spaces in numbers" +Other implementations of \fBbc\fR allow spaces in numbers. For example, +"x=1 3" would assign the value 13 to the variable x. The same statement +would cause a syntax error in this version of \fBbc\fR. +.IP "errors and execution" +This implementation varies from other implementations in terms of what +code will be executed when syntax and other errors are found in the +program. If a syntax error is found in a function definition, error +recovery tries to find the beginning of a statement and continue to +parse the function. Once a syntax error is found in the function, the +function will not be callable and becomes undefined. +Syntax errors in the interactive execution code will invalidate the +current execution block. The execution block is terminated by an +end of line that appears after a complete sequence of statements. +For example, +.nf +.RS +a = 1 +b = 2 +.RE +.fi +has two execution blocks and +.nf +.RS +{ a = 1 + b = 2 } +.RE +.fi +has one execution block. Any runtime error will terminate the execution +of the current execution block. A runtime warning will not terminate the +current execution block. +.IP "Interrupts" +During an interactive session, the SIGINT signal (usually generated by +the control-C character from the terminal) will cause execution of the +current execution block to be interrupted. It will display a "runtime" +error indicating which function was interrupted. After all runtime +structures have been cleaned up, a message will be printed to notify the +user that \fBbc\fR is ready for more input. All previously defined functions +remain defined and the value of all non-auto variables are the value at +the point of interruption. All auto variables and function parameters +are removed during the +clean up process. During a non-interactive +session, the SIGINT signal will terminate the entire run of \fBbc\fR. +.SS LIMITS +The following are the limits currently in place for this +.B bc +processor. Some of them may have been changed by an installation. +Use the limits statement to see the actual values. +.IP BC_BASE_MAX +The maximum output base is currently set at 999. The maximum input base +is 16. +.IP BC_DIM_MAX +This is currently an arbitrary limit of 65535 as distributed. Your +installation may be different. +.IP BC_SCALE_MAX +The number of digits after the decimal point is limited to INT_MAX digits. +Also, the number of digits before the decimal point is limited to INT_MAX +digits. +.IP BC_STRING_MAX +The limit on the number of characters in a string is INT_MAX characters. +.IP exponent +The value of the exponent in the raise operation (^) is limited to LONG_MAX. +.IP multiply +The multiply routine may yield incorrect results if a number +has more than LONG_MAX / 90 total digits. For 32 bit longs, this number is +23,860,929 digits. +.IP "code size" +Each function and the "main" program are limited to 16384 bytes of +compiled byte code each. This limit (BC_MAX_SEGS) can be easily changed +to have more than 16 segments of 1024 bytes. +.IP "variable names" +The current limit on the number of unique names is 32767 for each of +simple variables, arrays and functions. +.SH ENVIRONMENT VARIABLES +The following environment variables are processed by \fBbc\fR: +.IP "POSIXLY_CORRECT" +This is the same as the \fB-s\fR option. +.IP "BC_ENV_ARGS" +This is another mechanism to get arguments to \fBbc\fR. The +format is the same as the command line arguments. These arguments +are processed first, so any files listed in the environent arguments +are processed before any command line argument files. This allows +the user to set up "standard" options and files to be processed +at every invocation of \fBbc\fR. The files in the environment +variables would typically contain function definitions for functions +the user wants defined every time \fBbc\fR is run. +.IP "BC_LINE_LENGTH" +This should be an integer specifing the number of characters in an +output line for numbers. This includes the backslash and newline characters +for long numbers. +.SH FILES +In most installations, \fBbc\fR is completely self-contained. +Where executable size is of importance or the C compiler does +not deal with very long strings, \fBbc\fR will read +the standard math library from the file /usr/local/lib/libmath.b. +(The actual location may vary. It may be /lib/libmath.b.) +.SH DIAGNOSTICS +If any file on the command line can not be opened, \fBbc\fR will report +that the file is unavailable and terminate. Also, there are compile +and run time diagnostics that should be self-explanatory. +.SH BUGS +Error recovery is not very good yet. +.PP +Email bug reports to +.BR bug-gnu-utils@prep.ai.mit.edu . +Be sure to include the word ``bc'' somewhere in the ``Subject:'' field. +.SH AUTHOR +.nf +Philip A. Nelson +phil@cs.wwu.edu +.fi +.SH ACKNOWLEDGEMENTS +The author would like to thank Steve Sommars (Steve.Sommars@att.com) for +his extensive help in testing the implementation. Many great suggestions +were given. This is a much better product due to his involvement. diff --git a/gnu/usr.bin/bc/doc/dc.1 b/gnu/usr.bin/bc/doc/dc.1 new file mode 100644 index 00000000000..dd1357ac27a --- /dev/null +++ b/gnu/usr.bin/bc/doc/dc.1 @@ -0,0 +1,447 @@ +.\" +.\" dc.1 - the *roff document processor source for the dc manual +.\" +.\" This file is part of GNU dc. +.\" Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. +.\" +.\" This program is free software; you can redistribute it and/or modify +.\" it under the terms of the GNU General Public License as published by +.\" the Free Software Foundation; either version 2 of the License , or +.\" (at your option) any later version. +.\" +.\" This program is distributed in the hope that it will be useful, +.\" but WITHOUT ANY WARRANTY; without even the implied warranty of +.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +.\" GNU General Public License for more details. +.\" +.\" You should have received a copy of the GNU General Public License +.\" along with this program; see the file COPYING. If not, write to +.\" the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +.\" +.TH DC 1 "1997-03-25" "GNU Project" +.ds dc \fIdc\fP +.ds Dc \fIDc\fP +.SH NAME +dc \- an arbitrary precision calculator +.SH SYNOPSIS +dc +.SH DESCRIPTION +.PP +\*(Dc is a reverse-polish desk calculator which supports +unlimited precision arithmetic. +It also allows you to define and call macros. +Normally \*(dc reads from the standard input; +if any command arguments are given to it, they are filenames, +and \*(dc reads and executes the contents of the files before reading +from standard input. +All normal output is to standard output; +all error output is to standard error. +.PP +A reverse-polish calculator stores numbers on a stack. +Entering a number pushes it on the stack. +Arithmetic operations pop arguments off the stack and push the results. +.PP +To enter a number in +.IR dc , +type the digits with an optional decimal point. +Exponential notation is not supported. +To enter a negative number, +begin the number with ``_''. +``-'' cannot be used for this, +as it is a binary operator for subtraction instead. +To enter two numbers in succession, +separate them with spaces or newlines. +These have no meaning as commands. +.PD +.SH +Printing Commands +.TP +.B p +Prints the value on the top of the stack, +without altering the stack. +A newline is printed after the value. +.TP +.B n +Prints the value on the top of the stack, popping it off, +and does not print a newline after. +.TP +.B P +Pops off the value on top of the stack. +If it it a string, it is simply printed without a trailing newline. +Otherwise it is a number, and the integer portion of its absolute +value is printed out as a "base (UCHAR_MAX+1)" byte stream. +Assuming that (UCHAR_MAX+1) is 256 +(as it is on most machines with 8-bit bytes), +the sequence \fBKSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk\fP +could also accomplish this function, +except for the side-effect of clobbering the x register. +.TP +.B f +Prints the entire contents of the stack +.ig +and the contents of all of the registers, +.. +without altering anything. +This is a good command to use if you are lost or want +to figure out what the effect of some command has been. +.PD +.SH +Arithmetic +.TP +.B + +Pops two values off the stack, adds them, +and pushes the result. +The precision of the result is determined only +by the values of the arguments, +and is enough to be exact. +.TP +.B - +Pops two values, +subtracts the first one popped from the second one popped, +and pushes the result. +.TP +.B * +Pops two values, multiplies them, and pushes the result. +The number of fraction digits in the result depends on +the current precision value and the number of fraction +digits in the two arguments. +.TP +.B / +Pops two values, +divides the second one popped from the first one popped, +and pushes the result. +The number of fraction digits is specified by the precision value. +.TP +.B % +Pops two values, +computes the remainder of the division that the +.B / +command would do, +and pushes that. +The value computed is the same as that computed by +the sequence \fBSd dld/ Ld*-\fP . +.TP +.B ~ +Pops two values, +divides the second one popped from the first one popped. +The quotient is pushed first, and the remainder is pushed next. +The number of fraction digits used in the division +is specified by the precision value. +(The sequence \fBSdSn lnld/ LnLd%\fP could also accomplish +this function, with slightly different error checking.) +.TP +.B ^ +Pops two values and exponentiates, +using the first value popped as the exponent +and the second popped as the base. +The fraction part of the exponent is ignored. +The precision value specifies the number of fraction +digits in the result. +.TP +.B | +Pops three values and computes a modular exponentiation. +The first value popped is used as the reduction modulus; +this value must be a non-zero number, +and should be an integer. +The second popped is used as the exponent; +this value must be a non-negative number, +and any fractional part of this exponent will be ignored. +The third value popped is the base which gets exponentiated, +which should be an integer. +For small integers this is like the sequence \fBSm^Lm%\fP, +but, unlike \fB^\fP, this command will work with arbritrarily large exponents. +.TP +.B v +Pops one value, +computes its square root, +and pushes that. +The precision value specifies the number of fraction digits in the result. +.PP +Most arithmetic operations are affected by the ``precision value'', +which you can set with the +.B k +command. +The default precision value is zero, +which means that all arithmetic except for +addition and subtraction produces integer results. +.SH +Stack Control +.TP +.B c +Clears the stack, rendering it empty. +.TP +.B d +Duplicates the value on the top of the stack, +pushing another copy of it. +Thus, ``4d*p'' computes 4 squared and prints it. +.TP +.B r +Reverses the order of (swaps) the top two values on the stack. +.SH +Registers +.PP +\*(Dc provides at least 256 memory registers, +each named by a single character. +You can store a number or a string in a register and retrieve it later. +.TP +.BI s r +Pop the value off the top of the stack and store +it into register +.IR r . +.TP +.BI l r +Copy the value in register +.I r +and push it onto the stack. +This does not alter the contents of +.IR r . +.PP +Each register also contains its own stack. +The current register value is the top of the register's stack. +.TP +.BI S r +Pop the value off the top of the (main) stack and +push it onto the stack of register +.IR r . +The previous value of the register becomes inaccessible. +.TP +.BI L r +Pop the value off the top of register +.IR r 's +stack and push it onto the main stack. +The previous value +in register +.IR r 's +stack, if any, +is now accessible via the +.BI l r +command. +.ig +.PP +The +.B f +command prints a list of all registers that have contents stored in them, +together with their contents. +Only the current contents of each register +(the top of its stack) +is printed. +.. +.SH +Parameters +.PP +\*(Dc has three parameters that control its operation: +the precision, the input radix, and the output radix. +The precision specifies the number +of fraction digits to keep in the result of most arithmetic operations. +The input radix controls the interpretation of numbers typed in; +all numbers typed in use this radix. +The output radix is used for printing numbers. +.PP +The input and output radices are separate parameters; +you can make them unequal, +which can be useful or confusing. +The input radix must be between 2 and 16 inclusive. +The output radix must be at least 2. +The precision must be zero or greater. +The precision is always measured in decimal digits, +regardless of the current input or output radix. +.TP +.B i +Pops the value off the top of the stack +and uses it to set the input radix. +.TP +.B o +Pops the value off the top of the stack +and uses it to set the output radix. +.TP +.B k +Pops the value off the top of the stack +and uses it to set the precision. +.TP +.B I +Pushes the current input radix on the stack. +.TP +.B O +Pushes the current output radix on the stack. +.TP +.B K +Pushes the current precision on the stack. +.SH +Strings +.PP +\*(Dc can operate on strings as well as on numbers. +The only things you can do with strings are +print them and execute them as macros +(which means that the contents of the string are processed as +\*(dc commands). +All registers and the stack can hold strings, +and \*(dc always knows whether any given object is a string or a number. +Some commands such as arithmetic operations demand numbers +as arguments and print errors if given strings. +Other commands can accept either a number or a string; +for example, the +.B p +command can accept either and prints the object +according to its type. +.TP +.BI [ characters ] +Makes a string containing +.I characters +(contained between balanced +.B [ +and +.B ] +characters), +and pushes it on the stack. +For example, +.B [foo]P +prints the characters +.B foo +(with no newline). +.TP +.B a +The top-of-stack is popped. +If it was a number, then the low-order byte of this number +is converted into a string and pushed onto the stack. +Otherwise the top-of-stack was a string, +and the first character of that string is pushed back. +.TP +.B x +Pops a value off the stack and executes it as a macro. +Normally it should be a string; +if it is a number, +it is simply pushed back onto the stack. +For example, +.B [1p]x +executes the macro +.B 1p +which pushes +.B 1 +on the stack and prints +.B 1 +on a separate line. +.PP +Macros are most often stored in registers; +.B [1p]sa +stores a macro to print +.B 1 +into register +.BR a , +and +.B lax +invokes this macro. +.TP +.BI > r +Pops two values off the stack and compares them +assuming they are numbers, +executing the contents of register +.I r +as a macro if the original top-of-stack +is greater. +Thus, +.B 1 2>a +will invoke register +.BR a 's +contents and +.B 2 1>a +will not. +.TP +.BI !> r +Similar but invokes the macro if the original top-of-stack is +not greater than (less than or equal to) what was the second-to-top. +.TP +.BI < r +Similar but invokes the macro if the original top-of-stack is less. +.TP +.BI !< r +Similar but invokes the macro if the original top-of-stack is +not less than (greater than or equal to) what was the second-to-top. +.TP +.BI = r +Similar but invokes the macro if the two numbers popped are equal. +.TP +.BI != r +Similar but invokes the macro if the two numbers popped are not equal. +.ig +This can also be validly used to compare two strings for equality. +.. +.TP +.B ? +Reads a line from the terminal and executes it. +This command allows a macro to request input from the user. +.TP +.B q +exits from a macro and also from the macro which invoked it. +If called from the top level, +or from a macro which was called directly from the top level, +the +.B q +command will cause \*(dc to exit. +.TP +.B Q +Pops a value off the stack and uses it as a count +of levels of macro execution to be exited. +Thus, +.B 3Q +exits three levels. +The +.B Q +command will never cause \*(dc to exit. +.SH +Status Inquiry +.TP +.B Z +Pops a value off the stack, +calculates the number of digits it has +(or number of characters, if it is a string) +and pushes that number. +.TP +.B X +Pops a value off the stack, +calculates the number of fraction digits it has, +and pushes that number. +For a string, +the value pushed is +.\" -1. +0. +.TP +.B z +Pushes the current stack depth: +the number of objects on the stack before the execution of the +.B z +command. +.SH +Miscellaneous +.TP +.B ! +Will run the rest of the line as a system command. +Note that parsing of the !<, !=, and !> commands take precidence, +so if you want to run a command starting with <, =, or > you will +need to add a space after the !. +.TP +.B # +Will interpret the rest of the line as a comment. +.TP +.BI : r +Will pop the top two values off of the stack. +The old second-to-top value will be stored in the array +.IR r , +indexed by the old top-of-stack value. +.TP +.BI ; r +Pops the top-of-stack and uses it as an index into +the array +.IR r . +The selected value is then pushed onto the stack. +.P +Note that each stacked instance of a register has its own +array associated with it. +Thus \fB1 0:a 0Sa 2 0:a La 0;ap\fP will print 1, +because the 2 was stored in an instance of 0:a that +was later popped. +.SH +BUGS +.PP +Email bug reports to +.BR bug-gnu-utils@prep.ai.mit.edu . +Be sure to include the word ``dc'' somewhere in the ``Subject:'' field. diff --git a/gnu/usr.bin/bc/doc/dc.info b/gnu/usr.bin/bc/doc/dc.info new file mode 100644 index 00000000000..d795379aa68 --- /dev/null +++ b/gnu/usr.bin/bc/doc/dc.info @@ -0,0 +1,439 @@ +This is Info file dc.info, produced by Makeinfo version 1.68 from the +input file dc.texi. + + This file documents DC, an arbitrary precision calculator. + + Published by the Free Software Foundation, 675 Massachusetts Avenue, +Cambridge, MA 02139 USA + + Copyright (C) 1984, 1994, 1997, 1998 Free Software Foundation, Inc. + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of +this manual under the conditions for verbatim copying, provided that +the entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the Foundation. + + +File: dc.info, Node: Top, Next: Introduction, Prev: (dir), Up: (dir) + +* Menu: + +* Introduction:: Introduction +* Invocation:: Invocation +* Printing Commands:: Printing Commands +* Arithmetic:: Arithmetic +* Stack Control:: Stack Control +* Registers:: Registers +* Parameters:: Parameters +* Strings:: Strings +* Status Inquiry:: Status Inquiry +* Miscellaneous:: Other commands +* Reporting bugs:: Reporting bugs + + +File: dc.info, Node: Introduction, Next: Invocation, Prev: Top, Up: Top + +Introduction +************ + + DC is a reverse-polish desk calculator which supports unlimited +precision arithmetic. It also allows you to define and call macros. +Normally DC reads from the standard input; if any command arguments are +given to it, they are filenames, and DC reads and executes the contents +of the files instead of reading from standard input. All normal output +is to standard output; all error messages are written to standard error. + + To exit, use `q'. `C-c' does not exit; it is used to abort macros +that are looping, etc. (Currently this is not true; `C-c' does exit.) + + A reverse-polish calculator stores numbers on a stack. Entering a +number pushes it on the stack. Arithmetic operations pop arguments off +the stack and push the results. + + To enter a number in DC, type the digits, with an optional decimal +point. Exponential notation is not supported. To enter a negative +number, begin the number with `_'. `-' cannot be used for this, as it +is a binary operator for subtraction instead. To enter two numbers in +succession, separate them with spaces or newlines. These have no +meaning as commands. + + +File: dc.info, Node: Invocation, Next: Printing Commands, Prev: Introduction, Up: Top + +Invocation +********** + + DC may be invoked with the following command-line options: +`-e EXPR' + +`--expression=EXPR' + Evaluate EXPR as DC commands. + +`-f FILE' + +`--file=FILE' + Read and evaluate DC commands from FILE. + +`-h' + +`--help' + Print a usage message summarizing the command-line options, then + exit. + +`-V' + +`--version' + Print the version information for this program, then exit. + + If any command-line parameters remain after processing the options, +these parameters are interpreted as additional FILEs whose contents are +read and evaluated. A file name of `-' refers to the standard input +stream. If no `-e' option was specified, and no files were specified, +then the standard input will be read for commands to evaluate. + + +File: dc.info, Node: Printing Commands, Next: Arithmetic, Prev: Invocation, Up: Top + +Printing Commands +***************** + +`p' + Prints the value on the top of the stack, without altering the + stack. A newline is printed after the value. + +`n' + Prints the value on the top of the stack, popping it off, and does + not print a newline after. (This command is a GNU extension.) + +`P' + Pops off the value on top of the stack. If it it a string, it is + simply printed without a trailing newline. Otherwise it is a + number, and the integer portion of its absolute value is printed + out as a "base (UCHAR_MAX+1)" byte stream. Assuming that + (UCHAR_MAX+1) is 256 (as it is on most machines with 8-bit bytes), + the sequence `KSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk' could + also accomplish this function, except for the side-effect of + clobbering the x register. (Details of the behavior with a number + are a GNU extension.) + +`f' + Prints the entire contents of the stack without altering anything. + This is a good command to use if you are lost or want to figure + out what the effect of some command has been. + + +File: dc.info, Node: Arithmetic, Next: Stack Control, Prev: Printing Commands, Up: Top + +Arithmetic +********** + +`+' + Pops two values off the stack, adds them, and pushes the result. + The precision of the result is determined only by the values of + the arguments, and is enough to be exact. + +`-' + Pops two values, subtracts the first one popped from the second + one popped, and pushes the result. + +`*' + Pops two values, multiplies them, and pushes the result. The + number of fraction digits in the result is the largest of the + precision value, the number of fraction digits in the multiplier, + or the number of fraction digits in the multiplicand; but in no + event exceeding the number of digits required for an exact result. + +`/' + Pops two values, divides the second one popped from the first one + popped, and pushes the result. The number of fraction digits is + specified by the precision value. + +`%' + Pops two values, computes the remainder of the division that the + `/' command would do, and pushes that. The value computed is the + same as that computed by the sequence `Sd dld/ Ld*-' . + +`~' + Pops two values, divides the second one popped from the first one + popped. The quotient is pushed first, and the remainder is pushed + next. The number of fraction digits used in the division is + specified by the precision value. (The sequence `SdSn lnld/ + LnLd%' could also accomplish this function, with slightly + different error checking.) (This command is a GNU extension.) + +`^' + Pops two values and exponentiates, using the first value popped as + the exponent and the second popped as the base. The fraction part + of the exponent is ignored. The precision value specifies the + number of fraction digits in the result. + +`|' + Pops three values and computes a modular exponentiation. The + first value popped is used as the reduction modulus; this value + must be a non-zero number, and the result may not be accurate if + the modulus is not an integer. The second popped is used as the + exponent; this value must be a non-negative number, and any + fractional part of this exponent will be ignored. The third value + popped is the base which gets exponentiated, which should be an + integer. For small integers this is like the sequence `Sm^Lm%', + but, unlike `^', this command will work with arbritrarily large + exponents. (This command is a GNU extension.) + +`v' + Pops one value, computes its square root, and pushes that. The + precision value specifies the number of fraction digits in the + result. + + Most arithmetic operations are affected by the *precision value*, +which you can set with the `k' command. The default precision value is +zero, which means that all arithmetic except for addition and +subtraction produces integer results. + + +File: dc.info, Node: Stack Control, Next: Registers, Prev: Arithmetic, Up: Top + +Stack Control +************* + +`c' + Clears the stack, rendering it empty. + +`d' + Duplicates the value on the top of the stack, pushing another copy + of it. Thus, `4d*p' computes 4 squared and prints it. + +`r' + Reverses the order of (swaps) the top two values on the stack. + (This command is a GNU extension.) + + +File: dc.info, Node: Registers, Next: Parameters, Prev: Stack Control, Up: Top + +Registers +********* + + DC provides at least 256 memory registers, each named by a single +character. You can store a number in a register and retrieve it later. + +`sR' + Pop the value off the top of the stack and store it into register + R. + +`lR' + Copy the value in register R, and push it onto the stack. This + does not alter the contents of R. + + Each register also contains its own stack. The current register + value is the top of the register's stack. + +`SR' + Pop the value off the top of the (main) stack and push it onto the + stack of register R. The previous value of the register becomes + inaccessible. + +`LR' + Pop the value off the top of register R's stack and push it onto + the main stack. The previous value in register R's stack, if any, + is now accessible via the `lR' command. + + +File: dc.info, Node: Parameters, Next: Strings, Prev: Registers, Up: Top + +Parameters +********** + + DC has three parameters that control its operation: the precision, +the input radix, and the output radix. The precision specifies the +number of fraction digits to keep in the result of most arithmetic +operations. The input radix controls the interpretation of numbers +typed in; *all* numbers typed in use this radix. The output radix is +used for printing numbers. + + The input and output radices are separate parameters; you can make +them unequal, which can be useful or confusing. The input radix must +be between 2 and 16 inclusive. The output radix must be at least 2. +The precision must be zero or greater. The precision is always +measured in decimal digits, regardless of the current input or output +radix. + +`i' + Pops the value off the top of the stack and uses it to set the + input radix. + +`o' + Pops the value off the top of the stack and uses it to set the + output radix. + +`k' + Pops the value off the top of the stack and uses it to set the + precision. + +`I' + Pushes the current input radix on the stack. + +`O' + Pushes the current output radix on the stack. + +`K' + Pushes the current precision on the stack. + + +File: dc.info, Node: Strings, Next: Status Inquiry, Prev: Parameters, Up: Top + +Strings +******* + + DC can operate on strings as well as on numbers. The only things +you can do with strings are print them and execute them as macros +(which means that the contents of the string are processed as DC +commands). Both registers and the stack can hold strings, and DC +always knows whether any given object is a string or a number. Some +commands such as arithmetic operations demand numbers as arguments and +print errors if given strings. Other commands can accept either a +number or a string; for example, the `p' command can accept either and +prints the object according to its type. + +`[CHARACTERS]' + Makes a string containing CHARACTERS and pushes it on the stack. + For example, `[foo]P' prints the characters `foo' (with no + newline). + +`a' + The mnemonic for this is somewhat erroneous: asciify. The + top-of-stack is popped. If it was a number, then the low-order + byte of this number is converted into a string and pushed onto the + stack. Otherwise the top-of-stack was a string, and the first + character of that string is pushed back. (This command is a GNU + extension.) + +`x' + Pops a value off the stack and executes it as a macro. Normally + it should be a string; if it is a number, it is simply pushed back + onto the stack. For example, `[1p]x' executes the macro `1p', + which pushes 1 on the stack and prints `1' on a separate line. + + Macros are most often stored in registers; `[1p]sa' stores a macro + to print `1' into register `a', and `lax' invokes the macro. + +`>R' + Pops two values off the stack and compares them assuming they are + numbers, executing the contents of register R as a macro if the + original top-of-stack is greater. Thus, `1 2>a' will invoke + register `a''s contents and `2 1>a' will not. + +`!>R' + Similar but invokes the macro if the original top-of-stack is not + greater (is less than or equal to) what was the second-to-top. + +`<R' + Similar but invokes the macro if the original top-of-stack is less. + +`!<R' + Similar but invokes the macro if the original top-of-stack is not + less (is greater than or equal to) what was the second-to-top. + +`=R' + Similar but invokes the macro if the two numbers popped are equal. + +`!=R' + Similar but invokes the macro if the two numbers popped are not + equal. + +`?' + Reads a line from the terminal and executes it. This command + allows a macro to request input from the user. + +`q' + During the execution of a macro, this command exits from the macro + and also from the macro which invoked it. If called from the top + level, or from a macro which was called directly from the top + level, the `q' command will cause DC to exit. + +`Q' + Pops a value off the stack and uses it as a count of levels of + macro execution to be exited. Thus, `3Q' exits three levels. + + +File: dc.info, Node: Status Inquiry, Next: Miscellaneous, Prev: Strings, Up: Top + +Status Inquiry +************** + +`Z' + Pops a value off the stack, calculates the number of digits it has + (or number of characters, if it is a string) and pushes that + number. + +`X' + Pops a value off the stack, calculates the number of fraction + digits it has, and pushes that number. For a string, the value + pushed is 0. + +`z' + Pushes the current stack depth: the number of objects on the stack + before the execution of the `z' command. + + +File: dc.info, Node: Miscellaneous, Next: Reporting bugs, Prev: Status Inquiry, Up: Top + +Miscellaneous +************* + +`!' + Will run the rest of the line as a system command. Note that + parsing of the !<, !=, and !> commands take precidence, so if you + want to run a command starting with <, =, or > you will need to + add a space after the !. + +`#' + Will interpret the rest of the line as a comment. (This command + is a GNU extension.) + +`:R' + Will pop the top two values off of the stack. The old + second-to-top value will be stored in the array R, indexed by the + old top-of-stack value. + +`;R' + Pops the top-of-stack and uses it as an index into the array R. + The selected value is then pushed onto the stack. + + Note that each stacked instance of a register has its own array +associated with it. Thus `1 0:A 0SA 2 0:A LA 0;Ap' will print 1, +because the 2 was stored in an instance of 0:A that was later popped. + + +File: dc.info, Node: Reporting bugs, Prev: Miscellaneous, Up: Top + +Reporting bugs +************** + + Email bug reports to `bug-gnu-utils@prep.ai.mit.edu'. Be sure to +include the word "dc" somewhere in the "Subject:" field. + + + +Tag Table: +Node: Top983 +Node: Introduction1562 +Node: Invocation2779 +Node: Printing Commands3623 +Node: Arithmetic4801 +Node: Stack Control7714 +Node: Registers8127 +Node: Parameters9053 +Node: Strings10314 +Node: Status Inquiry13284 +Node: Miscellaneous13841 +Node: Reporting bugs14808 + +End Tag Table diff --git a/gnu/usr.bin/bc/doc/dc.texi b/gnu/usr.bin/bc/doc/dc.texi new file mode 100644 index 00000000000..968a81945d4 --- /dev/null +++ b/gnu/usr.bin/bc/doc/dc.texi @@ -0,0 +1,525 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename dc.info +@settitle dc, an arbitrary precision calculator +@c %**end of header + +@c This file has the new style title page commands. +@c Run `makeinfo' rather than `texinfo-format-buffer'. + +@c smallbook + +@c tex +@c \overfullrule=0pt +@c end tex + +@c Combine indices. +@synindex cp fn +@syncodeindex vr fn +@syncodeindex ky fn +@syncodeindex pg fn +@syncodeindex tp fn + +@ifinfo +This file documents @sc{dc}, an arbitrary precision calculator. + +Published by the Free Software Foundation, +675 Massachusetts Avenue, +Cambridge, MA 02139 USA + +Copyright (C) 1984, 1994, 1997, 1998 Free Software Foundation, Inc. + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@ignore +Permission is granted to process this file through TeX and print the +results, provided the printed document carries copying permission +notice identical to this one except for the removal of this paragraph +(this paragraph not being relevant to the printed manual). + +@end ignore +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. +@end ifinfo + +@setchapternewpage off + +@titlepage +@title dc, an arbitrary precision calculator + +@author by Ken Pizzini +@author original manual by Richard Stallman +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1994, 1997, 1998 Free Software Foundation, Inc. + +@sp 2 +Published by the Free Software Foundation, @* +675 Massachusetts Avenue, @* +Cambridge, MA 02139 USA + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the entire +resulting derived work is distributed under the terms of a permission +notice identical to this one. + +Permission is granted to copy and distribute translations of this manual +into another language, under the above conditions for modified versions, +except that this permission notice may be stated in a translation approved +by the Foundation. + +@end titlepage +@page + +@node Top, Introduction, (dir), (dir) + +@menu +* Introduction:: Introduction +* Invocation:: Invocation +* Printing Commands:: Printing Commands +* Arithmetic:: Arithmetic +* Stack Control:: Stack Control +* Registers:: Registers +* Parameters:: Parameters +* Strings:: Strings +* Status Inquiry:: Status Inquiry +* Miscellaneous:: Other commands +* Reporting bugs:: Reporting bugs +@end menu + +@node Introduction, Invocation, Top, Top +@comment node-name, next, previous, up +@chapter Introduction + +@sc{dc} is a reverse-polish desk calculator +which supports unlimited precision arithmetic. +It also allows you to define and call macros. +Normally @sc{dc} reads from the standard input; +if any command arguments are given to it, they are filenames, +and @sc{dc} reads and executes the contents of the files +instead of reading from standard input. +All normal output is to standard output; +all error messages are written to standard error. + +To exit, use @samp{q}. +@kbd{C-c} does not exit; +it is used to abort macros that are looping, etc. +(Currently this is not true; @kbd{C-c} does exit.) + +A reverse-polish calculator stores numbers on a stack. +Entering a number pushes it on the stack. +Arithmetic operations pop arguments off the stack and push the results. + +To enter a number in @sc{dc}, type the digits, +with an optional decimal point. +Exponential notation is not supported. +To enter a negative number, begin the number with @samp{_}. +@samp{-} cannot be used for this, as it is a binary operator +for subtraction instead. +To enter two numbers in succession, +separate them with spaces or newlines. +These have no meaning as commands. + +@node Invocation, Printing Commands, Introduction, Top +@chapter Invocation + +@sc{dc} may be invoked with the following command-line options: +@table @samp + +@item -e @var{expr} +@item --expression=@var{expr} +Evaluate @var{expr} as @sc{dc} commands. + +@item -f @var{file} +@item --file=@var{file} +Read and evaluate @sc{dc} commands from @var{file}. + +@item -h +@item --help +Print a usage message summarizing the command-line options, then exit. + +@item -V +@item --version +Print the version information for this program, then exit. +@end table + +If any command-line parameters remain after processing the options, +these parameters are interpreted as additional @var{file}s whose +contents are read and evaluated. +A file name of @code{-} refers to the standard input stream. +If no @code{-e} option was specified, and no files were specified, +then the standard input will be read for commands to evaluate. + +@node Printing Commands, Arithmetic, Invocation, Top +@chapter Printing Commands + +@table @samp +@item p +Prints the value on the top of the stack, +without altering the stack. +A newline is printed after the value. + +@item n +Prints the value on the top of the stack, popping it off, +and does not print a newline after. +(This command is a GNU extension.) + +@item P +Pops off the value on top of the stack. +If it it a string, it is simply printed without a trailing newline. +Otherwise it is a number, and the integer portion of its absolute +value is printed out as a "base (UCHAR_MAX+1)" byte stream. +Assuming that (UCHAR_MAX+1) is 256 +(as it is on most machines with 8-bit bytes), +the sequence +@code{KSK 0k1/ [_1*]sx d0>x [256~aPd0<x]dsxx sxLKk} +could also accomplish this function, +except for the side-effect of clobbering the x register. +(Details of the behavior with a number are a GNU extension.) + +@item f +Prints the entire contents of the stack +@c and the contents of all of the registers, +without altering anything. +This is a good command to use if you are lost or want +to figure out what the effect of some command has been. +@end table + +@node Arithmetic, Stack Control, Printing Commands, Top +@chapter Arithmetic + +@table @samp +@item + +Pops two values off the stack, adds them, and pushes the result. +The precision of the result is determined only +by the values of the arguments, and is enough to be exact. + +@item - +Pops two values, subtracts the first one popped +from the second one popped, and pushes the result. + +@item * +Pops two values, multiplies them, and pushes the result. +The number of fraction digits in the result is the largest of +the precision value, +the number of fraction digits in the multiplier, +or the number of fraction digits in the multiplicand; +but in no event exceeding the number of digits required for +an exact result. + +@item / +Pops two values, divides the second one popped +from the first one popped, and pushes the result. +The number of fraction digits is specified by the precision value. + +@item % +Pops two values, +computes the remainder of the division that +the @samp{/} command would do, +and pushes that. +The value computed is the same as that computed by +the sequence @code{Sd dld/ Ld*-} . + +@item ~ +Pops two values, +divides the second one popped from the first one popped. +The quotient is pushed first, and the remainder is pushed next. +The number of fraction digits used in the division +is specified by the precision value. +(The sequence @code{SdSn lnld/ LnLd%} could also accomplish +this function, with slightly different error checking.) +(This command is a GNU extension.) + +@item ^ +Pops two values and exponentiates, +using the first value popped as the exponent +and the second popped as the base. +The fraction part of the exponent is ignored. +The precision value specifies the number of fraction +digits in the result. + +@item | +Pops three values and computes a modular exponentiation. +The first value popped is used as the reduction modulus; +this value must be a non-zero number, +and the result may not be accurate if the modulus +is not an integer. +The second popped is used as the exponent; +this value must be a non-negative number, +and any fractional part of this exponent will be ignored. +The third value popped is the base which gets exponentiated, +which should be an integer. +For small integers this is like the sequence @code{Sm^Lm%}, +but, unlike @code{^}, this command will work with arbritrarily large exponents. +(This command is a GNU extension.) + +@item v +Pops one value, computes its square root, and pushes that. +The precision value specifies the number of fraction digits +in the result. +@end table + +Most arithmetic operations are affected by the @emph{precision value}, +which you can set with the @samp{k} command. +The default precision value is zero, +which means that all arithmetic except for +addition and subtraction produces integer results. + +@node Stack Control, Registers, Arithmetic, Top +@chapter Stack Control + +@table @samp +@item c +Clears the stack, rendering it empty. + +@item d +Duplicates the value on the top of the stack, +pushing another copy of it. +Thus, @samp{4d*p} computes 4 squared and prints it. + +@item r +Reverses the order of (swaps) the top two values on the stack. +(This command is a GNU extension.) +@end table + +@node Registers, Parameters, Stack Control, Top +@chapter Registers + +@sc{dc} provides at least 256 memory registers, +each named by a single character. +You can store a number in a register and retrieve it later. + +@table @samp +@item s@var{r} +Pop the value off the top of the stack and +store it into register @var{r}. + +@item l@var{r} +Copy the value in register @var{r}, +and push it onto the stack. +This does not alter the contents of @var{r}. + +Each register also contains its own stack. +The current register value is the top of the register's stack. + +@item S@var{r} +Pop the value off the top of the (main) stack and +push it onto the stack of register @var{r}. +The previous value of the register becomes inaccessible. + +@item L@var{r} +Pop the value off the top of register @var{r}'s stack +and push it onto the main stack. +The previous value in register @var{r}'s stack, if any, +is now accessible via the @samp{l@var{r}} command. +@end table +@c +@c The @samp{f} command prints a list of all registers that have contents +@c stored in them, together with their contents. +@c Only the current contents of each register (the top of its stack) +@c is printed. + +@node Parameters, Strings, Registers, Top +@chapter Parameters + +@sc{dc} has three parameters that control its operation: +the precision, the input radix, and the output radix. +The precision specifies the number of fraction digits +to keep in the result of most arithmetic operations. +The input radix controls the interpretation of numbers typed in; +@emph{all} numbers typed in use this radix. +The output radix is used for printing numbers. + +The input and output radices are separate parameters; +you can make them unequal, which can be useful or confusing. +The input radix must be between 2 and 16 inclusive. +The output radix must be at least 2. +The precision must be zero or greater. +The precision is always measured in decimal digits, +regardless of the current input or output radix. + +@table @samp +@item i +Pops the value off the top of the stack +and uses it to set the input radix. + +@item o +Pops the value off the top of the stack +and uses it to set the output radix. + +@item k +Pops the value off the top of the stack +and uses it to set the precision. + +@item I +Pushes the current input radix on the stack. + +@item O +Pushes the current output radix on the stack. + +@item K +Pushes the current precision on the stack. + +@end table + +@node Strings, Status Inquiry, Parameters, Top +@chapter Strings + +@sc{dc} can operate on strings as well as on numbers. +The only things you can do with strings are print them +and execute them as macros +(which means that the contents of the string are processed as @sc{dc} commands). +Both registers and the stack can hold strings, +and @sc{dc} always knows whether any given object is a string or a number. +Some commands such as arithmetic operations demand numbers +as arguments and print errors if given strings. +Other commands can accept either a number or a string; +for example, the @samp{p} command can accept either and prints the object +according to its type. + +@table @samp +@item [@var{characters}] +Makes a string containing @var{characters} and pushes it on the stack. +For example, @samp{[foo]P} prints the characters @samp{foo} +(with no newline). + +@item a +The mnemonic for this is somewhat erroneous: asciify. +The top-of-stack is popped. +If it was a number, then the low-order byte of this number +is converted into a string and pushed onto the stack. +Otherwise the top-of-stack was a string, +and the first character of that string is pushed back. +(This command is a GNU extension.) + +@item x +Pops a value off the stack and executes it as a macro. +Normally it should be a string; +if it is a number, it is simply pushed back onto the stack. +For example, @samp{[1p]x} executes the macro @samp{1p}, +which pushes 1 on the stack and prints @samp{1} on a separate line. + +Macros are most often stored in registers; +@samp{[1p]sa} stores a macro to print @samp{1} into register @samp{a}, +and @samp{lax} invokes the macro. + +@item >@var{r} +Pops two values off the stack and compares them +assuming they are numbers, +executing the contents of register @var{r} as a macro +if the original top-of-stack is greater. +Thus, @samp{1 2>a} will invoke register @samp{a}'s contents +and @samp{2 1>a} will not. + +@item !>@var{r} +Similar but invokes the macro if the original top-of-stack is not greater +(is less than or equal to) what was the second-to-top. + +@item <@var{r} +Similar but invokes the macro if the original top-of-stack is less. + +@item !<@var{r} +Similar but invokes the macro if the original top-of-stack is not less +(is greater than or equal to) what was the second-to-top. + +@item =@var{r} +Similar but invokes the macro if the two numbers popped are equal. +@c This can also be validly used to compare two strings for equality. + +@item !=@var{r} +Similar but invokes the macro if the two numbers popped are not equal. +@c This can also be validly used to compare two strings for equality. + +@item ? +Reads a line from the terminal and executes it. +This command allows a macro to request input from the user. + +@item q +During the execution of a macro, +this command exits from the macro and also from the macro which invoked it. +If called from the top level, +or from a macro which was called directly from the top level, +the @samp{q} command will cause @sc{dc} to exit. + +@item Q +Pops a value off the stack and uses it as a count +of levels of macro execution to be exited. +Thus, @samp{3Q} exits three levels. +@end table + +@node Status Inquiry, Miscellaneous, Strings, Top +@chapter Status Inquiry + +@table @samp +@item Z +Pops a value off the stack, +calculates the number of digits it has +(or number of characters, if it is a string) +and pushes that number. + +@item X +Pops a value off the stack, +calculates the number of fraction digits it has, +and pushes that number. +For a string, the value pushed is +@c -1. +0. + +@item z +Pushes the current stack depth: +the number of objects on the stack +before the execution of the @samp{z} command. +@end table + +@node Miscellaneous, Reporting bugs, Status Inquiry, Top +@chapter Miscellaneous + +@table @samp +@item ! +Will run the rest of the line as a system command. +Note that parsing of the !<, !=, and !> commands take precidence, +so if you want to run a command starting with <, =, or > you will +need to add a space after the !. + +@item # +Will interpret the rest of the line as a comment. +(This command is a GNU extension.) + +@item :@var{r} +Will pop the top two values off of the stack. +The old second-to-top value will be stored in the array @var{r}, +indexed by the old top-of-stack value. + +@item ;@var{r} +Pops the top-of-stack and uses it as an index into +the array @var{r}. +The selected value is then pushed onto the stack. +@end table + +Note that each stacked instance of a register has its own +array associated with it. +Thus @samp{1 @var{0:a} 0S@var{a} 2 @var{0:a} L@var{a} @var{0;a}p} +will print 1, because the 2 was stored in an instance of @var{0:a} +that was later popped. + +@node Reporting bugs, , Miscellaneous, Top +@chapter Reporting bugs + +Email bug reports to @code{bug-gnu-utils@@prep.ai.mit.edu}. +Be sure to include the word ``dc'' somewhere in the ``Subject:'' field. + +@contents +@bye diff --git a/gnu/usr.bin/bc/doc/texinfo.tex b/gnu/usr.bin/bc/doc/texinfo.tex new file mode 100644 index 00000000000..5957ca0ee81 --- /dev/null +++ b/gnu/usr.bin/bc/doc/texinfo.tex @@ -0,0 +1,4506 @@ +%% TeX macros to handle texinfo files + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, +% 94, 95, 1996 Free Software Foundation, Inc. + +%This texinfo.tex file is free software; you can redistribute it and/or +%modify it under the terms of the GNU General Public License as +%published by the Free Software Foundation; either version 2, or (at +%your option) any later version. + +%This texinfo.tex 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 +%General Public License for more details. + +%You should have received a copy of the GNU General Public License +%along with this texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +%Boston, MA 02111-1307, USA. + + +%In other words, you are welcome to use, share and improve this program. +%You are forbidden to forbid anyone else to use, share and improve +%what you give them. Help stamp out software-hoarding! + + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision: 1.1 $ +\message{Loading texinfo package [Version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptextilde=\~ +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexdots=\dots +\let\ptexdot=\. +\let\ptexstar=\* +\let\ptexend=\end +\let\ptexbullet=\bullet +\let\ptexb=\b +\let\ptexc=\c +\let\ptexi=\i +\let\ptext=\t +\let\ptexl=\l +\let\ptexL=\L + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} +\let\~ = \tie % And make it available as @~. + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset \bindingoffset=0pt +\newdimen \normaloffset \normaloffset=\hoffset +\newdimen\pagewidth \newdimen\pageheight +\pagewidth=\hsize \pageheight=\vsize + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +%---------------------Begin change----------------------- +% +%%%% For @cropmarks command. +% Dimensions to add cropmarks at corners Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen \topandbottommargin +\newdimen \outerhsize \newdimen \outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in +% +%---------------------End change----------------------- + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions itself, but you have to call it yourself. +\chardef\PAGE=255 \output={\onepageout{\pagecontents\PAGE}} +\def\onepageout#1{\hoffset=\normaloffset +\ifodd\pageno \advance\hoffset by \bindingoffset +\else \advance\hoffset by -\bindingoffset\fi +{\escapechar=`\\\relax % makes sure backslash is used in output files. +\shipout\vbox{{\let\hsize=\pagewidth \makeheadline} \pagebody{#1}% +{\let\hsize=\pagewidth \makefootline}}}% +\advancepageno \ifnum\outputpenalty>-20000 \else\dosupereject\fi} + +%%%% For @cropmarks command %%%% + +% Here is a modification of the main output routine for Near East Publications +% This provides right-angle cropmarks at all four corners. +% The contents of the page are centerlined into the cropmarks, +% and any desired binding offset is added as an \hskip on either +% site of the centerlined box. (P. A. MacKay, 12 November, 1986) +% +\def\croppageout#1{\hoffset=0pt % make sure this doesn't mess things up +{\escapechar=`\\\relax % makes sure backslash is used in output files. + \shipout + \vbox to \outervsize{\hsize=\outerhsize + \vbox{\line{\ewtop\hfill\ewtop}} + \nointerlineskip + \line{\vbox{\moveleft\cornerthick\nstop} + \hfill + \vbox{\moveright\cornerthick\nstop}} + \vskip \topandbottommargin + \centerline{\ifodd\pageno\hskip\bindingoffset\fi + \vbox{ + {\let\hsize=\pagewidth \makeheadline} + \pagebody{#1} + {\let\hsize=\pagewidth \makefootline}} + \ifodd\pageno\else\hskip\bindingoffset\fi} + \vskip \topandbottommargin plus1fill minus1fill + \boxmaxdepth\cornerthick + \line{\vbox{\moveleft\cornerthick\nsbot} + \hfill + \vbox{\moveright\cornerthick\nsbot}} + \nointerlineskip + \vbox{\line{\ewbot\hfill\ewbot}} + }} + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi} +% +% Do @cropmarks to get crop marks +\def\cropmarks{\let\onepageout=\croppageout } + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type <Return> to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. + +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\par \vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax + \let\message = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Also ignore @ifinfo, @ifhtml, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. + +\def\dircategory{\comment} + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}} +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. +% +\def\set{\parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value#1{\expandafter + \ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}} + \else \csname SET#1\endcsname \fi} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex always succeeds; we read the text following, through @end +% iftex). But `@end iftex' should be valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\defineunmatchedend{iftex} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\let\refill=\relax + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + \comment % Ignore the actual filename. +} + +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +%% Try out Computer Modern fonts at \magstephalf +\let\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples. +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\slshape{9}{1000} +\let\indsl=\indit +\let\indtt=\ninett +\let\indttsl=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for headings +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{12}{\magstep2} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{\magstep1} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled \magstep1 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\let\authorrm = \secrm + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts} +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp #1{`\tclose{#1}'\null} +\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate an a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +\global\def\indexbreaks{\catcode`\-=\active \let-\realdash \catcode`\_=\active \let_\realunder} +} + +\def\realdash{-} +\def\realunder{_} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\normalunderscore\discretionary{}{}{}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. +% +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\ttsl\look}}\fi +\else{\tclose{\ttsl\look}}\fi} + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of +% @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +\def\l#1{{\li #1}\null} % + +\def\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\def\titlefont#1{{\titlerm #1}} + +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefont{##1}} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx #1{\everyheadingyyy #1@|@|@|@|\finish} +\gdef\everyheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyfootingxxx #1{\everyfootingyyy #1@|@|@|@|\finish} +\gdef\everyfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}} +\global\oddfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +%\pagealignmacro +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + %{\parskip = 0in + %\par + %}% + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. Since that + % text will be indented by \tableindent, we make the item text be in + % a zero-width box. + \noindent + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{\in hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. + + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multicolumn or @endmulticolumn do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip will set vertical space between paragraphs in table. +% @multitableparindent will set paragraph indent in table. +% @multitablecolmargin will set horizontal space to be left between columns. +% @multitablelineskip will set vertical space to be left between lines. + +%%%% +% Dimensions + +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=12pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +%% 2/1/96, to allow fractions to be given with more than one digit. +\def\pickupwholefraction#1 {\global\advance\colcount by1 % +\expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% +\setuptable} + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xcolumnfractions\global\setpercenttrue% + \else + \ifsetpercent + \let\go\pickupwholefraction % In this case arg of setuptable + % is the decimal point before the + % number given in percent of hsize. + % We don't need this so we don't use it. + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1}% + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% +\ifx\go\pickupwholefraction\else\let\go\setuptable\fi% +\fi\go} + +%%%% +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + + +%%%% +% @multitable ... @end multitable definitions: + +\def\multitable#1\item{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\parskip=\multitableparskip +\parindent=\multitableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\def\one{#1}\expandafter\setuptable\one\endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has <not> set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: +\leftskip=\multitablecolspace +\fi +\noindent##}\cr% + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{\nointerlineskip\vskip\multitablelinespace +\filbreak%% keeps underfull box messages off when table breaks over pages. +\global\colcount=0\relax}}} + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\copyright{\realbackslash copyright }% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\t##1{\realbackslash r {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\unsepspaces +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there +\def\doind #1#2{% +% Put the index entry in the margin if desired. +\ifx\SETmarginindex\relax\else% +\insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% +\fi% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% Expand all macros now EXCEPT \folio +\def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now +% so it will be output as is; and it will print as backslash in the indx. +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}}}% +\temp }% +}\penalty\count10}} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% This is what you call to cause a particular index to get printed. +% Write +% @unnumbered Function Index +% @printindex fn + +\def\printindex{\parsearg\doprintindex} + +\def\doprintindex#1{% + \tex + \dobreak \chapheadingskip {10000} + \catcode`\%=\other\catcode`\&=\other\catcode`\#=\other + \catcode`\$=\other + \catcode`\~=\other + \indexbreaks + % + % The following don't help, since the chars were translated + % when the raw index was written, and their fonts were discarded + % due to \indexnofonts. + %\catcode`\"=\active + %\catcode`\^=\active + %\catcode`\_=\active + %\catcode`\|=\active + %\catcode`\<=\active + %\catcode`\>=\active + % % + \def\indexbackslash{\rawbackslashxx} + \indexfonts\rm \tolerance=9500 \advance\baselineskip -1pt + \begindoublecolumns + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + \input \jobname.#1s + \fi + \fi + \closein 1 + \enddoublecolumns + \Etex +} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +%% Define two-column mode, which is used in indexes. +%% Adapted from the TeXbook, page 416. +\catcode `\@=11 + +\newbox\partialpage + +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup + % Grab any single-column material above us. + \output = {\global\setbox\partialpage + =\vbox{\unvbox255\kern -\topskip \kern \baselineskip}}% + \eject + % + % Now switch to the double-column output routine. + \output={\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it once. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +- < + % 1pt) as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize + \doublecolumnpagegoal +} + +\def\enddoublecolumns{\eject \endgroup \pagegoal=\vsize \unvbox\partialpage} + +\def\doublecolumnsplit{\splittopskip=\topskip \splitmaxdepth=\maxdepth + \global\dimen@=\pageheight \global\advance\dimen@ by-\ht\partialpage + \global\setbox1=\vsplit255 to\dimen@ \global\setbox0=\vbox{\unvbox1} + \global\setbox3=\vsplit255 to\dimen@ \global\setbox2=\vbox{\unvbox3} + \ifdim\ht0>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi + \ifdim\ht2>\dimen@ \setbox255=\vbox{\unvbox0\unvbox2} \global\setbox255=\copy5 \fi +} +\def\doublecolumnpagegoal{% + \dimen@=\vsize \advance\dimen@ by-2\ht\partialpage \global\pagegoal=\dimen@ +} +\def\pagesofar{\unvbox\partialpage % + \hsize=\doublecolumnhsize % have to restore this since output routine + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}} +\def\doublecolumnout{% + \setbox5=\copy255 + {\vbadness=10000 \doublecolumnsplit} + \ifvbox255 + \setbox0=\vtop to\dimen@{\unvbox0} + \setbox2=\vtop to\dimen@{\unvbox2} + \onepageout\pagesofar \unvbox255 \penalty\outputpenalty + \else + \setbox0=\vbox{\unvbox5} + \ifvbox0 + \dimen@=\ht0 \advance\dimen@ by\topskip \advance\dimen@ by-\baselineskip + \divide\dimen@ by2 \splittopskip=\topskip \splitmaxdepth=\maxdepth + {\vbadness=10000 + \loop \global\setbox5=\copy0 + \setbox1=\vsplit5 to\dimen@ + \setbox3=\vsplit5 to\dimen@ + \ifvbox5 \global\advance\dimen@ by1pt \repeat + \setbox0=\vbox to\dimen@{\unvbox1} + \setbox2=\vbox to\dimen@{\unvbox3} + \global\setbox\partialpage=\vbox{\pagesofar} + \doublecolumnpagegoal + } + \fi + \fi +} + +\catcode `\@=\other +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount \chapno +\newcount \secno \secno=0 +\newcount \subsecno \subsecno=0 +\newcount \subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount \appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite \contentsfile +% This is called from \setfilename. +\def\opencontents{\openout \contentsfile = \jobname.toc} + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\if \pageno<0 % +\errmessage{@#1 not allowed after generating table of contents}\fi +% +} + +\def\chapternofonts{% +\let\rawbackslash=\relax% +\let\frenchspacing=\relax% +\def\result{\realbackslash result} +\def\equiv{\realbackslash equiv} +\def\expansion{\realbackslash expansion} +\def\print{\realbackslash print} +\def\TeX{\realbackslash TeX} +\def\dots{\realbackslash dots} +\def\copyright{\realbackslash copyright} +\def\tt{\realbackslash tt} +\def\bf{\realbackslash bf } +\def\w{\realbackslash w} +\def\less{\realbackslash less} +\def\gtr{\realbackslash gtr} +\def\hat{\realbackslash hat} +\def\char{\realbackslash char} +\def\tclose##1{\realbackslash tclose {##1}} +\def\code##1{\realbackslash code {##1}} +\def\samp##1{\realbackslash samp {##1}} +\def\r##1{\realbackslash r {##1}} +\def\b##1{\realbackslash b {##1}} +\def\key##1{\realbackslash key {##1}} +\def\file##1{\realbackslash file {##1}} +\def\kbd##1{\realbackslash kbd {##1}} +% These are redefined because @smartitalic wouldn't work inside xdef. +\def\i##1{\realbackslash i {##1}} +\def\cite##1{\realbackslash cite {##1}} +\def\var##1{\realbackslash var {##1}} +\def\emph##1{\realbackslash emph {##1}} +\def\dfn##1{\realbackslash dfn {##1}} +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry {#1}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\edef\temp{{\realbackslash chapentry + {#1}{\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbchapentry {#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\edef\temp{{\realbackslash secentry % +{#1}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsecentry % +{#1}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry % + {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\edef\temp{{\realbackslash subsubsecentry{#1}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\edef\temp{{\realbackslash unnumbsubsubsecentry{#1}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\heading{\parsearg\secheadingi} + +\def\subheading{\parsearg\subsecheadingi} + +\def\subsubheading{\parsearg\subsubsecheadingi} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip \chapheadingskip \chapheadingskip = 30pt plus 8pt minus 4pt + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain} + +\def\chfplain #1#2{% + \pchapsepmacro + {% + \chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #2\enspace #1}% + }% + \bigskip + \penalty5000 +} + +\def\unnchfplain #1{% +\pchapsepmacro % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen} + +% Parameter controlling skip before section headings. + +\newskip \subsecheadingskip \subsecheadingskip = 17pt plus 8pt minus 4pt +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} + +\newskip \secheadingskip \secheadingskip = 21pt plus 8pt minus 4pt +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Section fonts are the base font at magstep2, which produces +% a size a bit more than 14 points in the default situation. + +\def\secheading #1#2#3{\secheadingi {#2.#3\enspace #1}} +\def\plainsecheading #1{\secheadingi {#1}} +\def\secheadingi #1{{\advance \secheadingskip by \parskip % +\secheadingbreak}% +{\secfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + + +% Subsection fonts are the base font at magstep1, +% which produces a size of 12 points. + +\def\subsecheading #1#2#3#4{\subsecheadingi {#2.#3.#4\enspace #1}} +\def\subsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000 } + +\def\subsubsecfonts{\subsecfonts} % Maybe this should change: + % Perhaps make sssec fonts scaled + % magstep half +\def\subsubsecheading #1#2#3#4#5{\subsubsecheadingi {#2.#3.#4.#5\enspace #1}} +\def\subsubsecheadingi #1{{\advance \subsecheadingskip by \parskip % +\subsecheadingbreak}% +{\subsubsecfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}% +\ifdim \parskip<10pt \kern 10pt\kern -\parskip\fi \penalty 10000} + + +\message{toc printing,} + +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + \pagealignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + \catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. +} + + +% Normal (long) toc. +\outer\def\contents{% + \startcontents{\putwordTableofContents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in in \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we would want to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +% \turnoffactive is for the sake of @" used for umlauts. +\def\tocentry#1#2{\begingroup + \hyphenpenalty = 10000 + \entry{\turnoffactive #1}{\turnoffactive #2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +\let\ptexequiv = \equiv + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +\def\point{$\star$} + +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} + +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\~=\ptextilde +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext \let\l=\ptexl +\let\L=\ptexL +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +% This macro is +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller interline space and fonts for small examples. + \setleading{10pt}% + \indexfonts \tt + \rawbackslash % make \ output the \ character from the current font (tt) + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested % +\global\advance\parencount by 1 } +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. +% also in that case restore the outer-level definition of (. +\ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi +\global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}} \def\clnr{{\sf\char`\)}} \def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} \def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 +\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does, putting the result in \tptemp. +% +\def\removeemptybraces\empty#1\relax{\def\tptemp{#1}}% + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + \removeemptybraces#2\relax + #1{\tptemp}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{unbalanced parens in @def arguments}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name. +\def\deftypevarheader #1#2{% +\doind {vr}{\code{#2}}% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\doind {vr}{\code{#3}}% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% cross-reference, #3 the printed node name, #4 the name of the Info +% file, #5 the name of the printed manual. All but the node name can be +% omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \turnoffactive so that punctuation chars such as underscore +% work in node names. +\def\dosetq #1#2{{\let\folio=0 \turnoffactive \auxhat% +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% Read the last existing aux file, if any. No error if none exists. + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{ +{\catcode`\'=\other\expandafter \gdef \csname X#1\endcsname {#2}}} + +\def\readauxfile{% +\begingroup +\catcode `\^^@=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\^^C=\other +\catcode `\^^D=\other +\catcode `\^^E=\other +\catcode `\^^F=\other +\catcode `\^^G=\other +\catcode `\^^H=\other +\catcode `\=\other +\catcode `\^^L=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode `\=\other +\catcode 26=\other +\catcode `\^^[=\other +\catcode `\^^\=\other +\catcode `\^^]=\other +\catcode `\^^^=\other +\catcode `\^^_=\other +\catcode `\@=\other +\catcode `\^=\other +\catcode `\~=\other +\catcode `\[=\other +\catcode `\]=\other +\catcode`\"=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode `\$=\other +\catcode `\#=\other +\catcode `\&=\other +% `\+ does not work, so use 43. +\catcode 43=\other +% Make the characters 128-255 be printing characters +{% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% +}% +% the aux file uses ' as the escape. +% Turn off \ as an escape so we do not lose on +% entries which were dumped with control sequences in their names. +% For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ +% Reference to such entries still does not work the way one would wish, +% but at least they do not bomb out when the aux file is read in. +\catcode `\{=1 \catcode `\}=2 +\catcode `\%=\other +\catcode `\'=0 +\catcode`\^=7 % to make ^^e4 etc usable in xref tags +\catcode `\\=\other +\openin 1 \jobname.aux +\ifeof 1 \else \closein 1 \input \jobname.aux \global\havexrefstrue +\global\warnedobstrue +\fi +% Open the new aux file. Tex will close it automatically at exit. +\openout \auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only.. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +\long\gdef\footnotezzz#1{\insert\footins{% + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + #1\strut}% +} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + + +% End of control word definitions. + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +%\hsize = 6.5in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 18pt plus 1pt +\setleading{15pt} +\advance\topskip by 1.2cm + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. +% +\ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + +% These values for secheadingskip and subsecheadingskip are +% experiments. RJC 7 Aug 1992 +\global\secheadingskip = 17pt plus 6pt minus 3pt +\global\subsecheadingskip = 14pt plus 6pt minus 3pt + +\global\lispnarrowing = 0.3in +\setleading{12pt} +\advance\topskip by -1cm +\global\parskip 3pt plus 1pt +\global\hsize = 5in +\global\vsize=7.5in +\global\tolerance=700 +\global\hfuzz=1pt +\global\contentsrightmargin=0pt +\global\deftypemargin=0pt +\global\defbodyindent=.5cm + +\global\pagewidth=\hsize +\global\pageheight=\vsize + +\global\let\smalllisp=\smalllispx +\global\let\smallexample=\smalllispx +\global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; voffset; hoffset; binding offset; topskip. +% All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5#6{ + \global\vsize= #1 + \global\topskip= #6 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex + {\global\tolerance=700 + \global\hfuzz=1pt + \setleading{12pt} + \global\parskip 15pt plus 1pt + \advance\baselineskip by 1.6pt + \changepagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm} + } + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def\auxhat{\def^{'hat}} +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +%% These look ok in all fonts, so just make them not special. The @rm below +%% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/gnu/usr.bin/bc/h/bcdefs.h b/gnu/usr.bin/bc/h/bcdefs.h new file mode 100644 index 00000000000..0e51b2bb915 --- /dev/null +++ b/gnu/usr.bin/bc/h/bcdefs.h @@ -0,0 +1,166 @@ +/* bcdefs.h: The single file to include all constants and type definitions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +/* Include the configuration file. */ +#include "config.h" + +/* Standard includes for all files. */ +#include <stdio.h> +#include <sys/types.h> +#include <ctype.h> +#ifdef HAVE_STRINGS_H +#include <strings.h> +#else +#include <string.h> +#endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +/* Include the other definitions. */ +#include "const.h" +#include "number.h" + + +/* These definitions define all the structures used in + code and data storage. This includes the representation of + labels. The "guiding" principle is to make structures that + take a minimum of space when unused but can be built to contain + the full structures. */ + +/* Labels are first. Labels are generated sequentially in functions + and full code. They just "point" to a single bye in the code. The + "address" is the byte number. The byte number is used to get an + actual character pointer. */ + +typedef struct bc_label_group + { + long l_adrs [ BC_LABEL_GROUP ]; + struct bc_label_group *l_next; + } bc_label_group; + +/* Argument list. Recorded in the function so arguments can + be checked at call time. */ + +typedef struct arg_list + { + int av_name; + int arg_is_var; /* Extension ... variable parameters. */ + struct arg_list *next; + } arg_list; + +/* Each function has its own code segments and labels. There can be + no jumps between functions so labels are unique to a function. */ + +typedef struct + { + char f_defined; /* Is this function defined yet. */ + char *f_body[BC_MAX_SEGS]; + int f_code_size; + bc_label_group *f_label; + arg_list *f_params; + arg_list *f_autos; + } bc_function; + +/* Code addresses. */ +typedef struct { + int pc_func; + int pc_addr; + } program_counter; + + +/* Variables are "pushable" (auto) and thus we need a stack mechanism. + This is built into the variable record. */ + +typedef struct bc_var + { + bc_num v_value; + struct bc_var *v_next; + } bc_var; + + +/* bc arrays can also be "auto" variables and thus need the same + kind of stacking mechanisms. */ + +typedef struct bc_array_node + { + union + { + bc_num n_num [NODE_SIZE]; + struct bc_array_node *n_down [NODE_SIZE]; + } n_items; + } bc_array_node; + +typedef struct bc_array + { + bc_array_node *a_tree; + short a_depth; + } bc_array; + +typedef struct bc_var_array + { + bc_array *a_value; + char a_param; + struct bc_var_array *a_next; + } bc_var_array; + + +/* For the stacks, execution and function, we need records to allow + for arbitrary size. */ + +typedef struct estack_rec { + bc_num s_num; + struct estack_rec *s_next; +} estack_rec; + +typedef struct fstack_rec { + int s_val; + struct fstack_rec *s_next; +} fstack_rec; + + +/* The following are for the name tree. */ + +typedef struct id_rec { + char *id; /* The program name. */ + /* A name == 0 => nothing assigned yet. */ + int a_name; /* The array variable name (number). */ + int f_name; /* The function name (number). */ + int v_name; /* The variable name (number). */ + short balance; /* For the balanced tree. */ + struct id_rec *left, *right; /* Tree pointers. */ +} id_rec; + + +/* A list of files to process. */ + +typedef struct file_node { + char *name; + struct file_node *next; +} file_node; + diff --git a/gnu/usr.bin/bc/h/const.h b/gnu/usr.bin/bc/h/const.h new file mode 100644 index 00000000000..1ed1465940e --- /dev/null +++ b/gnu/usr.bin/bc/h/const.h @@ -0,0 +1,101 @@ +/* const.h: Constants for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +/* Define INT_MAX and LONG_MAX if not defined. Assuming 32 bits... */ + +#ifndef INT_MAX +#define INT_MAX 0x7FFFFFFF +#endif +#ifndef LONG_MAX +#define LONG_MAX 0x7FFFFFFF +#endif + + +/* Define constants in some reasonable size. The next 4 constants are + POSIX constants. */ + +#ifdef BC_BASE_MAX + /* <limits.h> on a POSIX.2 system may have defined these. Override. */ +# undef BC_BASE_MAX +# undef BC_SCALE_MAX +# undef BC_STRING_MAX +# undef BC_DIM_MAX +#endif + +#define BC_BASE_MAX INT_MAX +#define BC_SCALE_MAX INT_MAX +#define BC_STRING_MAX INT_MAX + + +/* Definitions for arrays. */ + +#define BC_DIM_MAX 65535 /* this should be NODE_SIZE^NODE_DEPTH-1 */ + +#define NODE_SIZE 16 /* Must be a power of 2. */ +#define NODE_MASK 0xf /* Must be NODE_SIZE-1. */ +#define NODE_SHIFT 4 /* Number of 1 bits in NODE_MASK. */ +#define NODE_DEPTH 4 + + +/* Other BC limits defined but not part of POSIX. */ + +#define BC_LABEL_GROUP 64 +#define BC_LABEL_LOG 6 +#define BC_MAX_SEGS 16 /* Code segments. */ +#define BC_SEG_SIZE 1024 +#define BC_SEG_LOG 10 + +/* Maximum number of variables, arrays and functions and the + allocation increment for the dynamic arrays. */ + +#define MAX_STORE 32767 +#define STORE_INCR 32 + +/* Other interesting constants. */ + +#define FALSE 0 +#define TRUE 1 + +/* for use with lookup (). */ +#define SIMPLE 0 +#define ARRAY 1 +#define FUNCT 2 +#define FUNCTDEF 3 + +#define EXTERN extern +#ifdef __STDC__ +#define CONST const +#define VOID void +#else +#define CONST +#define VOID +#endif + +/* Include the version definition. */ +#include "version.h" diff --git a/gnu/usr.bin/bc/h/getopt.h b/gnu/usr.bin/bc/h/getopt.h new file mode 100644 index 00000000000..f3696d955dc --- /dev/null +++ b/gnu/usr.bin/bc/h/getopt.h @@ -0,0 +1,133 @@ +/* Declarations for getopt. + Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +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 _GETOPT_H +#define _GETOPT_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +extern char *optarg; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +extern int optind; + +/* Callers store zero here to inhibit the error message `getopt' prints + for unrecognized options. */ + +extern int opterr; + +/* Set to an option character which was unrecognized. */ + +extern int optopt; + +/* Describe the long-named options requested by the application. + The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector + of `struct option' terminated by an element containing a name which is + zero. + + The field `has_arg' is: + no_argument (or 0) if the option does not take an argument, + required_argument (or 1) if the option requires an argument, + optional_argument (or 2) if the option takes an optional argument. + + If the field `flag' is not NULL, it points to a variable that is set + to the value given in the field `val' when the option is found, but + left unchanged if the option is not found. + + To have a long-named option do something other than set an `int' to + a compiled-in constant, such as set a value from `optarg', set the + option's `flag' field to zero and its `val' field to a nonzero + value (the equivalent single-letter option character, if there is + one). For long options that have a zero `flag' field, `getopt' + returns the contents of the `val' field. */ + +struct option +{ +#if defined (__STDC__) && __STDC__ + const char *name; +#else + char *name; +#endif + /* has_arg can't be an enum because some compilers complain about + type mismatches in all the code that assumes it is an int. */ + int has_arg; + int *flag; + int val; +}; + +/* Names for the values of the `has_arg' field of `struct option'. */ + +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ +/* Many other libraries have conflicting prototypes for getopt, with + differences in the consts, in stdlib.h. To avoid compilation + errors, only prototype getopt for the GNU C library. */ +extern int getopt (int argc, char *const *argv, const char *shortopts); +#else /* not __GNU_LIBRARY__ */ +extern int getopt (); +#endif /* __GNU_LIBRARY__ */ +extern int getopt_long (int argc, char *const *argv, const char *shortopts, + const struct option *longopts, int *longind); +extern int getopt_long_only (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind); + +/* Internal only. Users should not call this directly. */ +extern int _getopt_internal (int argc, char *const *argv, + const char *shortopts, + const struct option *longopts, int *longind, + int long_only); +#else /* not __STDC__ */ +extern int getopt (); +extern int getopt_long (); +extern int getopt_long_only (); + +extern int _getopt_internal (); +#endif /* __STDC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* _GETOPT_H */ diff --git a/gnu/usr.bin/bc/h/global.h b/gnu/usr.bin/bc/h/global.h new file mode 100644 index 00000000000..bc431dcd164 --- /dev/null +++ b/gnu/usr.bin/bc/h/global.h @@ -0,0 +1,147 @@ +/* global.h: The global variables for bc. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +/* The current break level's lable. */ +EXTERN int break_label; + +/* The current if statement's else label or label after else. */ +EXTERN int if_label; + +/* The current for statement label for continuing the loop. */ +EXTERN int continue_label; + +/* Next available label number. */ +EXTERN int next_label; + +/* Byte code character storage. Used in many places for generation of code. */ +EXTERN char genstr[80]; + +/* Count of characters printed to the output in compile_only mode. */ +EXTERN int out_count; + +/* Have we generated any code since the last initialization of the code + generator. */ +EXTERN char did_gen; + +/* Is this run an interactive execution. (Is stdin a terminal?) */ +EXTERN char interactive; + +/* Just generate the byte code. -c flag. */ +EXTERN int compile_only; + +/* Load the standard math functions. -l flag. */ +EXTERN int use_math; + +/* Give a warning on use of any non-standard feature (non-POSIX). -w flag. */ +EXTERN int warn_not_std; + +/* Accept POSIX bc only! -s flag. */ +EXTERN int std_only; + +/* Don't print the banner at start up. -q flag. */ +EXTERN int quiet; + +/* The list of file names to process. */ +EXTERN file_node *file_names; + +/* The name of the current file being processed. */ +EXTERN char *file_name; + +/* Is the current file a named file or standard input? */ +EXTERN char is_std_in; + +/* global variables for the bc machine. All will be dynamic in size.*/ +/* Function storage. main is (0) and functions (1-f_count) */ + +EXTERN bc_function *functions; +EXTERN char **f_names; +EXTERN int f_count; + +/* Variable stoarge and reverse names. */ + +EXTERN bc_var **variables; +EXTERN char **v_names; +EXTERN int v_count; + +/* Array Variable storage and reverse names. */ + +EXTERN bc_var_array **arrays; +EXTERN char **a_names; +EXTERN int a_count; + +/* Execution stack. */ +EXTERN estack_rec *ex_stack; + +/* Function return stack. */ +EXTERN fstack_rec *fn_stack; + +/* Current ibase, obase, scale, and n_history (if needed). */ +EXTERN int i_base; +EXTERN int o_base; +EXTERN int scale; +#ifdef READLINE +EXTERN int n_history; +#endif + +/* "Condition code" -- false (0) or true (1) */ +EXTERN char c_code; + +/* Records the number of the runtime error. */ +EXTERN char runtime_error; + +/* Holds the current location of execution. */ +EXTERN program_counter pc; + +/* For POSIX bc, this is just for number output, not strings. */ +EXTERN int out_col; + +/* Keeps track of the current number of characters per output line. + This includes the \n at the end of the line. */ +EXTERN int line_size; + +/* Input Line numbers and other error information. */ +EXTERN int line_no; +EXTERN int had_error; + +/* For larger identifiers, a tree, and how many "storage" locations + have been allocated. */ + +EXTERN int next_array; +EXTERN int next_func; +EXTERN int next_var; + +EXTERN id_rec *name_tree; + +/* defined in number.c */ +extern bc_num _zero_; +extern bc_num _one_; + +/* For use with getopt. Do not declare them here.*/ +extern int optind; + diff --git a/gnu/usr.bin/bc/h/number.h b/gnu/usr.bin/bc/h/number.h new file mode 100644 index 00000000000..6ead2f573e4 --- /dev/null +++ b/gnu/usr.bin/bc/h/number.h @@ -0,0 +1,65 @@ +/* number.h: Arbitrary precision numbers header file. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + + +typedef enum {PLUS, MINUS} sign; + +typedef struct + { + sign n_sign; + int n_len; /* The number of digits before the decimal point. */ + int n_scale; /* The number of digits after the decimal point. */ + int n_refs; /* The number of pointers to this number. */ + char n_value[1]; /* The storage. Not zero char terminated. It is + allocated with all other fields. */ + } bc_struct; + +typedef bc_struct *bc_num; + +/* The base used in storing the numbers in n_value above. + Currently this MUST be 10. */ + +#define BASE 10 + +/* Some useful macros and constants. */ + +#define CH_VAL(c) (c - '0') +#define BCD_CHAR(d) (d + '0') + +#ifdef MIN +#undef MIN +#undef MAX +#endif +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)>(b)?(b):(a)) +#define ODD(a) ((a)&1) + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif diff --git a/gnu/usr.bin/bc/h/proto.h b/gnu/usr.bin/bc/h/proto.h new file mode 100644 index 00000000000..016a166fe47 --- /dev/null +++ b/gnu/usr.bin/bc/h/proto.h @@ -0,0 +1,171 @@ +/* proto.h: Prototype function definitions for "external" functions. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +/* For the pc version using k&r ACK. (minix1.5 and earlier.) */ +#ifdef SHORTNAMES +#define init_numbers i_numbers +#define push_constant push__constant +#define load_const in_load_const +#define yy_get_next_buffer yyget_next_buffer +#define yy_init_buffer yyinit_buffer +#define yy_last_accepting_state yylast_accepting_state +#define arglist1 arg1list +#endif + +/* Include the standard library header files. */ +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif + +/* Define the _PROTOTYPE macro if it is needed. */ + +#ifndef _PROTOTYPE +#ifdef __STDC__ +#define _PROTOTYPE(func, args) func args +#else +#define _PROTOTYPE(func, args) func() +#endif +#endif + +/* From execute.c */ +_PROTOTYPE(void stop_execution, (int)); +_PROTOTYPE(unsigned char byte, (program_counter *pc)); +_PROTOTYPE(void execute, (void)); +_PROTOTYPE(char prog_char, (void)); +_PROTOTYPE(char input_char, (void)); +_PROTOTYPE(void push_constant, (char (*in_char)(void), int conv_base)); +_PROTOTYPE(void push_b10_const, (program_counter *pc)); +_PROTOTYPE(void assign, (int c_code)); + +/* From util.c */ +_PROTOTYPE(char *strcopyof, (char *str)); +_PROTOTYPE(arg_list *nextarg, (arg_list *args, int val, int is_var)); +_PROTOTYPE(char *arg_str, (arg_list *args)); +_PROTOTYPE(char *call_str, (arg_list *args)); +_PROTOTYPE(void free_args, (arg_list *args)); +_PROTOTYPE(void check_params, (arg_list *params, arg_list *autos)); +_PROTOTYPE(void init_gen, (void)); +_PROTOTYPE(void generate, (char *str)); +_PROTOTYPE(void run_code, (void)); +_PROTOTYPE(void out_char, (int ch)); +_PROTOTYPE(id_rec *find_id, (id_rec *tree, char *id)); +_PROTOTYPE(int insert_id_rec, (id_rec **root, id_rec *new_id)); +_PROTOTYPE(void init_tree, (void)); +_PROTOTYPE(int lookup, (char *name, int namekind)); +_PROTOTYPE(char *bc_malloc, (int)); +_PROTOTYPE(void out_of_memory, (void)); +_PROTOTYPE(void welcome, (void)); +_PROTOTYPE(void warranty, (char *)); +_PROTOTYPE(void limits, (void)); +_PROTOTYPE(void yyerror, (char *str ,...)); +_PROTOTYPE(void warn, (char *mesg ,...)); +_PROTOTYPE(void rt_error, (char *mesg ,...)); +_PROTOTYPE(void rt_warn, (char *mesg ,...)); + +/* From load.c */ +_PROTOTYPE(void init_load, (void)); +_PROTOTYPE(void addbyte, (int byte)); +_PROTOTYPE(void def_label, (long lab)); +_PROTOTYPE(long long_val, (char **str)); +_PROTOTYPE(void load_code, (char *code)); + +/* From main.c */ +_PROTOTYPE(int main, (int argc , char *argv [])); +_PROTOTYPE(int open_new_file, (void)); +_PROTOTYPE(void new_yy_file, (FILE *file)); +_PROTOTYPE(void use_quit, (int)); + +/* From number.c */ +_PROTOTYPE(void free_num, (bc_num *num)); +_PROTOTYPE(bc_num new_num, (int length, int scale)); +_PROTOTYPE(void init_numbers, (void)); +_PROTOTYPE(bc_num copy_num, (bc_num num)); +_PROTOTYPE(void init_num, (bc_num *num)); +_PROTOTYPE(void str2num, (bc_num *num, char *str, int scale)); +_PROTOTYPE(char *num2str, (bc_num num)); +_PROTOTYPE(void int2num, (bc_num *num, int val)); +_PROTOTYPE(long num2long, (bc_num num)); +_PROTOTYPE(int bc_compare, (bc_num n1, bc_num n2)); +_PROTOTYPE(char is_zero, (bc_num num)); +_PROTOTYPE(char is_neg, (bc_num num)); +_PROTOTYPE(void bc_add, (bc_num n1, bc_num n2, bc_num *result, int scale_min)); +_PROTOTYPE(void bc_sub, (bc_num n1, bc_num n2, bc_num *result, int scale_min)); +_PROTOTYPE(void bc_multiply, (bc_num n1, bc_num n2, bc_num *prod, int scale)); +_PROTOTYPE(int bc_divide, (bc_num n1, bc_num n2, bc_num *quot, int scale)); +_PROTOTYPE(int bc_modulo, + (bc_num num1, bc_num num2, bc_num *result, int scale)); +_PROTOTYPE(int bc_divmod, + (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale)); +_PROTOTYPE(int bc_raisemod, + (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)); +_PROTOTYPE(void bc_raise, + (bc_num num1, bc_num num2, bc_num *result, int scale)); +_PROTOTYPE(int bc_sqrt, (bc_num *num, int scale)); +_PROTOTYPE(void out_long, (long val, int size, int space, + void (*out_char)(int))); +_PROTOTYPE(void out_num, (bc_num num, int o_base, void (* out_char)(int))); + + +/* From storage.c */ +_PROTOTYPE(void init_storage, (void)); +_PROTOTYPE(void more_functions, (void)); +_PROTOTYPE(void more_variables, (void)); +_PROTOTYPE(void more_arrays, (void)); +_PROTOTYPE(void clear_func, (int func )); +_PROTOTYPE(int fpop, (void)); +_PROTOTYPE(void fpush, (int val )); +_PROTOTYPE(void pop, (void)); +_PROTOTYPE(void push_copy, (bc_num num )); +_PROTOTYPE(void push_num, (bc_num num )); +_PROTOTYPE(char check_stack, (int depth )); +_PROTOTYPE(bc_var *get_var, (int var_name )); +_PROTOTYPE(bc_num *get_array_num, (int var_index, long index )); +_PROTOTYPE(void store_var, (int var_name )); +_PROTOTYPE(void store_array, (int var_name )); +_PROTOTYPE(void load_var, (int var_name )); +_PROTOTYPE(void load_array, (int var_name )); +_PROTOTYPE(void decr_var, (int var_name )); +_PROTOTYPE(void decr_array, (int var_name )); +_PROTOTYPE(void incr_var, (int var_name )); +_PROTOTYPE(void incr_array, (int var_name )); +_PROTOTYPE(void auto_var, (int name )); +_PROTOTYPE(void free_a_tree, (bc_array_node *root, int depth )); +_PROTOTYPE(void pop_vars, (arg_list *list )); +_PROTOTYPE(void process_params, (program_counter *pc, int func )); + +/* For the scanner and parser.... */ +_PROTOTYPE(int yyparse, (void)); +_PROTOTYPE(int yylex, (void)); + +/* Other things... */ +#ifndef HAVE_UNISTD_H +_PROTOTYPE (int getopt, (int, char *[], CONST char *)); +#endif diff --git a/gnu/usr.bin/bc/h/version.h b/gnu/usr.bin/bc/h/version.h new file mode 100644 index 00000000000..b98222f796a --- /dev/null +++ b/gnu/usr.bin/bc/h/version.h @@ -0,0 +1,28 @@ +/* version.h: version information for GNU bc and GNU dc */ + +/* This file is part of GNU bc and GNU dc. + * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, you can either send email to this + * program's author (see below) or write to: The Free Software Foundation, + * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA. + */ + +#define BC_VERSION \ +"bc 1.05\n\ +Copyright 1991, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc." + +#define DC_VERSION \ +"dc 1.2 (GNU bc 1.05)\n\ +Copyright 1994, 1997, 1998 Free Software Foundation, Inc." diff --git a/gnu/usr.bin/bc/lib/Makefile.am b/gnu/usr.bin/bc/lib/Makefile.am new file mode 100644 index 00000000000..bf33e3fe81c --- /dev/null +++ b/gnu/usr.bin/bc/lib/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to produce Makefile.in +noinst_LIBRARIES = libbc.a + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h + +libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c + +#libbc_LIBADD = @LIBOBJS@ +#libbc_DEPENDENCIES = $(bc_LIBADD) diff --git a/gnu/usr.bin/bc/lib/Makefile.in b/gnu/usr.bin/bc/lib/Makefile.in new file mode 100644 index 00000000000..4d3ca83787b --- /dev/null +++ b/gnu/usr.bin/bc/lib/Makefile.in @@ -0,0 +1,246 @@ +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +LEX = @LEX@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +YACC = @YACC@ + +noinst_LIBRARIES = libbc.a + +INCLUDES = -I$(srcdir) -I$(srcdir)/../h + +libbc_a_SOURCES = getopt.c getopt1.c vfprintf.c number.c +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libbc_a_LIBADD = +libbc_a_OBJECTS = getopt.o getopt1.o vfprintf.o number.o +AR = ar +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +SOURCES = $(libbc_a_SOURCES) +OBJECTS = $(libbc_a_OBJECTS) + +all: Makefile $(LIBRARIES) + +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps lib/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libbc.a: $(libbc_a_OBJECTS) $(libbc_a_DEPENDENCIES) + -rm -f libbc.a + $(AR) cru libbc.a $(libbc_a_OBJECTS) $(libbc_a_LIBADD) + $(RANLIB) libbc.a + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = lib + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: + @$(NORMAL_INSTALL) + +install-data: + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-tags mostlyclean-generic + +clean: clean-noinstLIBRARIES clean-compile clean-tags clean-generic \ + mostlyclean + +distclean: distclean-noinstLIBRARIES distclean-compile distclean-tags \ + distclean-generic clean + -rm -f config.status + +maintainer-clean: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info dvi installcheck \ +install-exec install-data install uninstall all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +#libbc_LIBADD = @LIBOBJS@ +#libbc_DEPENDENCIES = $(bc_LIBADD) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/gnu/usr.bin/bc/lib/getopt.c b/gnu/usr.bin/bc/lib/getopt.c new file mode 100644 index 00000000000..23ce0648b79 --- /dev/null +++ b/gnu/usr.bin/bc/lib/getopt.c @@ -0,0 +1,752 @@ +/* Getopt for GNU. + NOTE: getopt is now part of the C library, so if you don't know what + "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu + before changing it! + + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94 + Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +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 tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +/* Don't include stdlib.h for non-GNU C libraries because some of them + contain conflicting prototypes for getopt. */ +#include <stdlib.h> +#endif /* GNU C library. */ + +/* This version of `getopt' appears to the caller like standard Unix `getopt' + but it behaves differently for the user, since it allows the user + to intersperse the options with the other arguments. + + As `getopt' works, it permutes the elements of ARGV so that, + when it is done, all the options precede everything else. Thus + all application programs are extended to handle flexible argument order. + + Setting the environment variable POSIXLY_CORRECT disables permutation. + Then the behavior is completely standard. + + GNU application programs can use a third alternative mode in which + they can distinguish the relative order of options and other arguments. */ + +#include "getopt.h" + +/* For communication from `getopt' to the caller. + When `getopt' finds an option that takes an argument, + the argument value is returned here. + Also, when `ordering' is RETURN_IN_ORDER, + each non-option ARGV-element is returned here. */ + +char *optarg = NULL; + +/* Index in ARGV of the next element to be scanned. + This is used for communication to and from the caller + and for communication between successive calls to `getopt'. + + On entry to `getopt', zero means this is the first call; initialize. + + When `getopt' returns EOF, this is the index of the first of the + non-option elements that the caller should itself scan. + + Otherwise, `optind' communicates from one call to the next + how much of ARGV has been scanned so far. */ + +/* XXX 1003.2 says this must be 1 before any call. */ +int optind = 0; + +/* The next char to be scanned in the option-element + in which the last option character we returned was found. + This allows us to pick up the scan where we left off. + + If this is zero, or a null string, it means resume the scan + by advancing to the next ARGV-element. */ + +static char *nextchar; + +/* Callers store zero here to inhibit the error message + for unrecognized options. */ + +int opterr = 1; + +/* Set to an option character which was unrecognized. + This must be initialized on some systems to avoid linking in the + system's own getopt implementation. */ + +int optopt = '?'; + +/* Describe how to deal with options that follow non-option ARGV-elements. + + If the caller did not specify anything, + the default is REQUIRE_ORDER if the environment variable + POSIXLY_CORRECT is defined, PERMUTE otherwise. + + REQUIRE_ORDER means don't recognize them as options; + stop option processing when the first non-option is seen. + This is what Unix does. + This mode of operation is selected by either setting the environment + variable POSIXLY_CORRECT, or using `+' as the first character + of the list of option characters. + + PERMUTE is the default. We permute the contents of ARGV as we scan, + so that eventually all the non-options are at the end. This allows options + to be given in any order, even with programs that were not written to + expect this. + + RETURN_IN_ORDER is an option available to programs that were written + to expect options and other ARGV-elements in any order and that care about + the ordering of the two. We describe each non-option ARGV-element + as if it were the argument of an option with character code 1. + Using `-' as the first character of the list of option characters + selects this mode of operation. + + The special argument `--' forces an end of option-scanning regardless + of the value of `ordering'. In the case of RETURN_IN_ORDER, only + `--' can cause `getopt' to return EOF with `optind' != ARGC. */ + +static enum +{ + REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER +} ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; + +#ifdef __GNU_LIBRARY__ +/* We want to avoid inclusion of string.h with non-GNU libraries + because there are many ways it can cause trouble. + On some systems, it contains special magic macros that don't work + in GCC. */ +#include <string.h> +#define my_index strchr +#else + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +char *getenv (); + +static char * +my_index (str, chr) + const char *str; + int chr; +{ + while (*str) + { + if (*str == chr) + return (char *) str; + str++; + } + return 0; +} + +/* If using GCC, we can safely declare strlen this way. + If not using GCC, it is ok not to declare it. */ +#ifdef __GNUC__ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ + +/* Handle permutation of arguments. */ + +/* Describe the part of ARGV that contains non-options that have + been skipped. `first_nonopt' is the index in ARGV of the first of them; + `last_nonopt' is the index after the last of them. */ + +static int first_nonopt; +static int last_nonopt; + +/* Exchange two adjacent subsequences of ARGV. + One subsequence is elements [first_nonopt,last_nonopt) + which contains all the non-options that have been skipped so far. + The other is elements [last_nonopt,optind), which contains all + the options processed since those non-options were skipped. + + `first_nonopt' and `last_nonopt' are relocated so that they describe + the new indices of the non-options in ARGV after they are moved. */ + +static void +exchange (argv) + char **argv; +{ + int bottom = first_nonopt; + int middle = last_nonopt; + int top = optind; + char *tem; + + /* Exchange the shorter segment with the far end of the longer segment. + That puts the shorter segment into the right place. + It leaves the longer segment in the right place overall, + but it consists of two parts that need to be swapped next. */ + + while (top > middle && middle > bottom) + { + if (top - middle > middle - bottom) + { + /* Bottom segment is the short one. */ + int len = middle - bottom; + register int i; + + /* Swap it with the top part of the top segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[top - (middle - bottom) + i]; + argv[top - (middle - bottom) + i] = tem; + } + /* Exclude the moved bottom segment from further swapping. */ + top -= len; + } + else + { + /* Top segment is the short one. */ + int len = top - middle; + register int i; + + /* Swap it with the bottom part of the bottom segment. */ + for (i = 0; i < len; i++) + { + tem = argv[bottom + i]; + argv[bottom + i] = argv[middle + i]; + argv[middle + i] = tem; + } + /* Exclude the moved top segment from further swapping. */ + bottom += len; + } + } + + /* Update records for the slots the non-options now occupy. */ + + first_nonopt += (optind - last_nonopt); + last_nonopt = optind; +} + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} + +/* Scan elements of ARGV (whose length is ARGC) for option characters + given in OPTSTRING. + + If an element of ARGV starts with '-', and is not exactly "-" or "--", + then it is an option element. The characters of this element + (aside from the initial '-') are option characters. If `getopt' + is called repeatedly, it returns successively each of the option characters + from each of the option elements. + + If `getopt' finds another option character, it returns that character, + updating `optind' and `nextchar' so that the next call to `getopt' can + resume the scan with the following option character or ARGV-element. + + If there are no more option characters, `getopt' returns `EOF'. + Then `optind' is the index in ARGV of the first ARGV-element + that is not an option. (The ARGV-elements have been permuted + so that those that are not options now come last.) + + OPTSTRING is a string containing the legitimate option characters. + If an option character is seen that is not listed in OPTSTRING, + return '?' after printing an error message. If you set `opterr' to + zero, the error message is suppressed but we still return '?'. + + If a char in OPTSTRING is followed by a colon, that means it wants an arg, + so the following text in the same ARGV-element, or the text of the following + ARGV-element, is returned in `optarg'. Two colons mean an option that + wants an optional arg; if there is text in the current ARGV-element, + it is returned in `optarg', otherwise `optarg' is set to zero. + + If OPTSTRING starts with `-' or `+', it requests different methods of + handling the non-option ARGV-elements. + See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. + + Long-named options begin with `--' instead of `-'. + Their names may be abbreviated as long as the abbreviation is unique + or is an exact match for some defined option. If they have an + argument, it follows the option name in the same ARGV-element, separated + from the option name by a `=', or else the in next ARGV-element. + When `getopt' finds a long-named option, it returns 0 if that option's + `flag' field is nonzero, the value of the option's `val' field + if the `flag' field is zero. + + The elements of ARGV aren't really const, because we permute them. + But we pretend they're const in the prototype to be compatible + with other systems. + + LONGOPTS is a vector of `struct option' terminated by an + element containing a name which is zero. + + LONGIND returns the index in LONGOPT of the long-named option found. + It is only valid when a long-named option has been found by the most + recent call. + + If LONG_ONLY is nonzero, '-' as well as '--' can introduce + long-named options. */ + +int +_getopt_internal (argc, argv, optstring, longopts, longind, long_only) + int argc; + char *const *argv; + const char *optstring; + const struct option *longopts; + int *longind; + int long_only; +{ + optarg = NULL; + + if (optind == 0) + optstring = _getopt_initialize (optstring); + + if (nextchar == NULL || *nextchar == '\0') + { + /* Advance to the next ARGV-element. */ + + if (ordering == PERMUTE) + { + /* If we have just processed some options following some non-options, + exchange them so that the options come first. */ + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (last_nonopt != optind) + first_nonopt = optind; + + /* Skip any additional non-options + and extend the range of non-options previously skipped. */ + + while (optind < argc + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) + optind++; + last_nonopt = optind; + } + + /* The special ARGV-element `--' means premature end of options. + Skip it like a null option, + then exchange with previous non-options as if it were an option, + then skip everything else like a non-option. */ + + if (optind != argc && !strcmp (argv[optind], "--")) + { + optind++; + + if (first_nonopt != last_nonopt && last_nonopt != optind) + exchange ((char **) argv); + else if (first_nonopt == last_nonopt) + first_nonopt = optind; + last_nonopt = argc; + + optind = argc; + } + + /* If we have done all the ARGV-elements, stop the scan + and back over any non-options that we skipped and permuted. */ + + if (optind == argc) + { + /* Set the next-arg-index to point at the non-options + that we previously skipped, so the caller will digest them. */ + if (first_nonopt != last_nonopt) + optind = first_nonopt; + return EOF; + } + + /* If we have come to a non-option and did not permute it, + either stop the scan or describe it to the caller and pass it by. */ + + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) + { + if (ordering == REQUIRE_ORDER) + return EOF; + optarg = argv[optind++]; + return 1; + } + + /* We have found another option-ARGV-element. + Skip the initial punctuation. */ + + nextchar = (argv[optind] + 1 + + (longopts != NULL && argv[optind][1] == '-')); + } + + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + + if (longopts != NULL + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) + { + char *nameend; + const struct option *p; + const struct option *pfound = NULL; + int exact = 0; + int ambig = 0; + int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; + + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) + { + if (nameend - nextchar == strlen (p->name)) + { + /* Exact match found. */ + pfound = p; + indfound = option_index; + exact = 1; + break; + } + else if (pfound == NULL) + { + /* First nonexact match found. */ + pfound = p; + indfound = option_index; + } + else + /* Second or later nonexact match found. */ + ambig = 1; + } + + if (ambig && !exact) + { + if (opterr) + fprintf (stderr, "%s: option `%s' is ambiguous\n", + argv[0], argv[optind]); + nextchar += strlen (nextchar); + optind++; + return '?'; + } + + if (pfound != NULL) + { + option_index = indfound; + optind++; + if (*nameend) + { + /* Don't test has_arg with >, because some C compilers don't + allow it to be used on enums. */ + if (pfound->has_arg) + optarg = nameend + 1; + else + { + if (opterr) + { + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + "%s: option `%c%s' doesn't allow an argument\n", + argv[0], argv[optind - 1][0], pfound->name); + } + nextchar += strlen (nextchar); + return '?'; + } + } + else if (pfound->has_arg == 1) + { + if (optind < argc) + optarg = argv[optind++]; + else + { + if (opterr) + fprintf (stderr, "%s: option `%s' requires an argument\n", + argv[0], argv[optind - 1]); + nextchar += strlen (nextchar); + return optstring[0] == ':' ? ':' : '?'; + } + } + nextchar += strlen (nextchar); + if (longind != NULL) + *longind = option_index; + if (pfound->flag) + { + *(pfound->flag) = pfound->val; + return 0; + } + return pfound->val; + } + + /* Can't find it as a long option. If this is not getopt_long_only, + or the option starts with '--' or is not a valid short + option, then it's an error. + Otherwise interpret it as a short option. */ + if (!long_only || argv[optind][1] == '-' + || my_index (optstring, *nextchar) == NULL) + { + if (opterr) + { + if (argv[optind][1] == '-') + /* --option */ + fprintf (stderr, "%s: unrecognized option `--%s'\n", + argv[0], nextchar); + else + /* +option or -option */ + fprintf (stderr, "%s: unrecognized option `%c%s'\n", + argv[0], argv[optind][0], nextchar); + } + nextchar = (char *) ""; + optind++; + return '?'; + } + } + + /* Look at and handle the next short option-character. */ + + { + char c = *nextchar++; + char *temp = my_index (optstring, c); + + /* Increment `optind' when we start to process its last character. */ + if (*nextchar == '\0') + ++optind; + + if (temp == NULL || c == ':') + { + if (opterr) + { + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); + else + fprintf (stderr, "%s: invalid option -- %c\n", argv[0], c); + } + optopt = c; + return '?'; + } + if (temp[1] == ':') + { + if (temp[2] == ':') + { + /* This is an option that accepts an argument optionally. */ + if (*nextchar != '\0') + { + optarg = nextchar; + optind++; + } + else + optarg = NULL; + nextchar = NULL; + } + else + { + /* This is an option that requires an argument. */ + if (*nextchar != '\0') + { + optarg = nextchar; + /* If we end this ARGV-element by taking the rest as an arg, + we must advance to the next element now. */ + optind++; + } + else if (optind == argc) + { + if (opterr) + { + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, "%s: option requires an argument -- %c\n", + argv[0], c); + } + optopt = c; + if (optstring[0] == ':') + c = ':'; + else + c = '?'; + } + else + /* We already incremented `optind' once; + increment it again when taking next ARGV-elt as argument. */ + optarg = argv[optind++]; + nextchar = NULL; + } + } + return c; + } +} + +int +getopt (argc, argv, optstring) + int argc; + char *const *argv; + const char *optstring; +{ + return _getopt_internal (argc, argv, optstring, + (const struct option *) 0, + (int *) 0, + 0); +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +/* Compile with -DTEST to make an executable for use in testing + the above definition of `getopt'. */ + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + + c = getopt (argc, argv, "abc:d:0123456789"); + if (c == EOF) + break; + + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/gnu/usr.bin/bc/lib/getopt1.c b/gnu/usr.bin/bc/lib/getopt1.c new file mode 100644 index 00000000000..de8e2ad5674 --- /dev/null +++ b/gnu/usr.bin/bc/lib/getopt1.c @@ -0,0 +1,184 @@ +/* getopt_long and getopt_long_only entry points for GNU getopt. + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 + Free Software Foundation, Inc. + +This file is part of the GNU C Library. Its master source is NOT part of +the C library, however. The master source lives in /gd/gnu/lib. + +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 HAVE_CONFIG_H +#include <config.h> +#endif + +#include "getopt.h" + +#if !defined (__STDC__) || !__STDC__ +/* This is a separate conditional since some stdc systems + reject `defined (const)'. */ +#ifndef const +#define const +#endif +#endif + +#include <stdio.h> + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +/* This needs to come after some library #include + to get __GNU_LIBRARY__ defined. */ +#ifdef __GNU_LIBRARY__ +#include <stdlib.h> +#else +char *getenv (); +#endif + +#ifndef NULL +#define NULL 0 +#endif + +int +getopt_long (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 0); +} + +/* Like getopt_long, but '-' as well as '--' can indicate a long option. + If an option that starts with '-' (not '--') doesn't match a long option, + but does match a short option, it is parsed as a short option + instead. */ + +int +getopt_long_only (argc, argv, options, long_options, opt_index) + int argc; + char *const *argv; + const char *options; + const struct option *long_options; + int *opt_index; +{ + return _getopt_internal (argc, argv, options, long_options, opt_index, 1); +} + + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + +#ifdef TEST + +#include <stdio.h> + +int +main (argc, argv) + int argc; + char **argv; +{ + int c; + int digit_optind = 0; + + while (1) + { + int this_option_optind = optind ? optind : 1; + int option_index = 0; + static struct option long_options[] = + { + {"add", 1, 0, 0}, + {"append", 0, 0, 0}, + {"delete", 1, 0, 0}, + {"verbose", 0, 0, 0}, + {"create", 0, 0, 0}, + {"file", 1, 0, 0}, + {0, 0, 0, 0} + }; + + c = getopt_long (argc, argv, "abc:d:0123456789", + long_options, &option_index); + if (c == EOF) + break; + + switch (c) + { + case 0: + printf ("option %s", long_options[option_index].name); + if (optarg) + printf (" with arg %s", optarg); + printf ("\n"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (digit_optind != 0 && digit_optind != this_option_optind) + printf ("digits occur in two different argv-elements.\n"); + digit_optind = this_option_optind; + printf ("option %c\n", c); + break; + + case 'a': + printf ("option a\n"); + break; + + case 'b': + printf ("option b\n"); + break; + + case 'c': + printf ("option c with value `%s'\n", optarg); + break; + + case 'd': + printf ("option d with value `%s'\n", optarg); + break; + + case '?': + break; + + default: + printf ("?? getopt returned character code 0%o ??\n", c); + } + } + + if (optind < argc) + { + printf ("non-option ARGV-elements: "); + while (optind < argc) + printf ("%s ", argv[optind++]); + printf ("\n"); + } + + exit (0); +} + +#endif /* TEST */ diff --git a/gnu/usr.bin/bc/lib/number.c b/gnu/usr.bin/bc/lib/number.c new file mode 100644 index 00000000000..469d44c8b19 --- /dev/null +++ b/gnu/usr.bin/bc/lib/number.c @@ -0,0 +1,1572 @@ +/* number.c: Implements arbitrary precision numbers. */ + +/* This file is part of GNU bc. + Copyright (C) 1991, 1992, 1993, 1994, 1997, 1998 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License , or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + You may contact the author by: + e-mail: phil@cs.wwu.edu + us-mail: Philip A. Nelson + Computer Science Department, 9062 + Western Washington University + Bellingham, WA 98226-9062 + +*************************************************************************/ + +#include "bcdefs.h" +#include "proto.h" +#include "global.h" + +/* Storage used for special numbers. */ +bc_num _zero_; +bc_num _one_; +bc_num _two_; + + +/* "Frees" a bc_num NUM. Actually decreases reference count and only + frees the storage if reference count is zero. */ + +void +free_num (num) + bc_num *num; +{ + if (*num == NULL) return; + (*num)->n_refs--; + if ((*num)->n_refs == 0) free(*num); + *num = NULL; +} + + +/* new_num allocates a number and sets fields to known values. */ + +bc_num +new_num (length, scale) + int length, scale; +{ + bc_num temp; + + temp = (bc_num) malloc (sizeof(bc_struct)+length+scale); + if (temp == NULL) out_of_memory (); + temp->n_sign = PLUS; + temp->n_len = length; + temp->n_scale = scale; + temp->n_refs = 1; + temp->n_value[0] = 0; + return temp; +} + + +/* Intitialize the number package! */ + +void +init_numbers () +{ + _zero_ = new_num (1,0); + _one_ = new_num (1,0); + _one_->n_value[0] = 1; + _two_ = new_num (1,0); + _two_->n_value[0] = 2; +} + + +/* Make a copy of a number! Just increments the reference count! */ + +bc_num +copy_num (num) + bc_num num; +{ + num->n_refs++; + return num; +} + + +/* Initialize a number NUM by making it a copy of zero. */ + +void +init_num (num) + bc_num *num; +{ + *num = copy_num (_zero_); +} + + +/* Convert an integer VAL to a bc number NUM. */ + +void +int2num (num, val) + bc_num *num; + int val; +{ + char buffer[30]; + char *bptr, *vptr; + int ix = 1; + char neg = 0; + + /* Sign. */ + if (val < 0) + { + neg = 1; + val = -val; + } + + /* Get things going. */ + bptr = buffer; + *bptr++ = val % BASE; + val = val / BASE; + + /* Extract remaining digits. */ + while (val != 0) + { + *bptr++ = val % BASE; + val = val / BASE; + ix++; /* Count the digits. */ + } + + /* Make the number. */ + free_num (num); + *num = new_num (ix, 0); + if (neg) (*num)->n_sign = MINUS; + + /* Assign the digits. */ + vptr = (*num)->n_value; + while (ix-- > 0) + *vptr++ = *--bptr; +} + + +/* Convert a number NUM to a long. The function returns only the integer + part of the number. For numbers that are too large to represent as + a long, this function returns a zero. This can be detected by checking + the NUM for zero after having a zero returned. */ + +long +num2long (num) + bc_num num; +{ + long val; + char *nptr; + int index; + + /* Extract the int value, ignore the fraction. */ + val = 0; + nptr = num->n_value; + for (index=num->n_len; (index>0) && (val<=(LONG_MAX/BASE)); index--) + val = val*BASE + *nptr++; + + /* Check for overflow. If overflow, return zero. */ + if (index>0) val = 0; + if (val < 0) val = 0; + + /* Return the value. */ + if (num->n_sign == PLUS) + return (val); + else + return (-val); +} + + +/* The following are some math routines for numbers. */ +_PROTOTYPE(static int _do_compare, (bc_num n1, bc_num n2, int use_sign, + int ignore_last)); +_PROTOTYPE(static void _rm_leading_zeros, (bc_num num)); +_PROTOTYPE(static bc_num _do_add, (bc_num n1, bc_num n2, int scale_min)); +_PROTOTYPE(static bc_num _do_sub, (bc_num n1, bc_num n2, int scale_min)); +_PROTOTYPE(static void _one_mult, (unsigned char *num, int size, int digit, + unsigned char *result)); + + + +/* Compare two bc numbers. Return value is 0 if equal, -1 if N1 is less + than N2 and +1 if N1 is greater than N2. If USE_SIGN is false, just + compare the magnitudes. */ + +static int +_do_compare (n1, n2, use_sign, ignore_last) + bc_num n1, n2; + int use_sign; + int ignore_last; +{ + char *n1ptr, *n2ptr; + int count; + + /* First, compare signs. */ + if (use_sign && n1->n_sign != n2->n_sign) + { + if (n1->n_sign == PLUS) + return (1); /* Positive N1 > Negative N2 */ + else + return (-1); /* Negative N1 < Positive N1 */ + } + + /* Now compare the magnitude. */ + if (n1->n_len != n2->n_len) + { + if (n1->n_len > n2->n_len) + { + /* Magnitude of n1 > n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (1); + else + return (-1); + } + else + { + /* Magnitude of n1 < n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (-1); + else + return (1); + } + } + + /* If we get here, they have the same number of integer digits. + check the integer part and the equal length part of the fraction. */ + count = n1->n_len + MIN (n1->n_scale, n2->n_scale); + n1ptr = n1->n_value; + n2ptr = n2->n_value; + + while ((count > 0) && (*n1ptr == *n2ptr)) + { + n1ptr++; + n2ptr++; + count--; + } + if (ignore_last && count == 1 && n1->n_scale == n2->n_scale) + return (0); + if (count != 0) + { + if (*n1ptr > *n2ptr) + { + /* Magnitude of n1 > n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (1); + else + return (-1); + } + else + { + /* Magnitude of n1 < n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (-1); + else + return (1); + } + } + + /* They are equal up to the last part of the equal part of the fraction. */ + if (n1->n_scale != n2->n_scale) + if (n1->n_scale > n2->n_scale) + { + for (count = n1->n_scale-n2->n_scale; count>0; count--) + if (*n1ptr++ != 0) + { + /* Magnitude of n1 > n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (1); + else + return (-1); + } + } + else + { + for (count = n2->n_scale-n1->n_scale; count>0; count--) + if (*n2ptr++ != 0) + { + /* Magnitude of n1 < n2. */ + if (!use_sign || n1->n_sign == PLUS) + return (-1); + else + return (1); + } + } + + /* They must be equal! */ + return (0); +} + + +/* This is the "user callable" routine to compare numbers N1 and N2. */ + +int +bc_compare (n1, n2) + bc_num n1, n2; +{ + return _do_compare (n1, n2, TRUE, FALSE); +} + + +/* In some places we need to check if the number NUM is zero. */ + +char +is_zero (num) + bc_num num; +{ + int count; + char *nptr; + + /* Quick check. */ + if (num == _zero_) return TRUE; + + /* Initialize */ + count = num->n_len + num->n_scale; + nptr = num->n_value; + + /* The check */ + while ((count > 0) && (*nptr++ == 0)) count--; + + if (count != 0) + return FALSE; + else + return TRUE; +} + + +/* In some places we need to check if the number is negative. */ + +char +is_neg (num) + bc_num num; +{ + return num->n_sign == MINUS; +} + + +/* For many things, we may have leading zeros in a number NUM. + _rm_leading_zeros just moves the data to the correct + place and adjusts the length. */ + +static void +_rm_leading_zeros (num) + bc_num num; +{ + int bytes; + char *dst, *src; + + /* Do a quick check to see if we need to do it. */ + if (*num->n_value != 0) return; + + /* The first "digit" is 0, find the first non-zero digit in the second + or greater "digit" to the left of the decimal place. */ + bytes = num->n_len; + src = num->n_value; + while (bytes > 1 && *src == 0) src++, bytes--; + num->n_len = bytes; + bytes += num->n_scale; + dst = num->n_value; + while (bytes-- > 0) *dst++ = *src++; + +} + + +/* Perform addition: N1 is added to N2 and the value is + returned. The signs of N1 and N2 are ignored. + SCALE_MIN is to set the minimum scale of the result. */ + +static bc_num +_do_add (n1, n2, scale_min) + bc_num n1, n2; + int scale_min; +{ + bc_num sum; + int sum_scale, sum_digits; + char *n1ptr, *n2ptr, *sumptr; + int carry, n1bytes, n2bytes; + int count; + + /* Prepare sum. */ + sum_scale = MAX (n1->n_scale, n2->n_scale); + sum_digits = MAX (n1->n_len, n2->n_len) + 1; + sum = new_num (sum_digits, MAX(sum_scale, scale_min)); + + /* Zero extra digits made by scale_min. */ + if (scale_min > sum_scale) + { + sumptr = (char *) (sum->n_value + sum_scale + sum_digits); + for (count = scale_min - sum_scale; count > 0; count--) + *sumptr++ = 0; + } + + /* Start with the fraction part. Initialize the pointers. */ + n1bytes = n1->n_scale; + n2bytes = n2->n_scale; + n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1); + n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1); + sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1); + + /* Add the fraction part. First copy the longer fraction.*/ + if (n1bytes != n2bytes) + { + if (n1bytes > n2bytes) + while (n1bytes>n2bytes) + { *sumptr-- = *n1ptr--; n1bytes--;} + else + while (n2bytes>n1bytes) + { *sumptr-- = *n2ptr--; n2bytes--;} + } + + /* Now add the remaining fraction part and equal size integer parts. */ + n1bytes += n1->n_len; + n2bytes += n2->n_len; + carry = 0; + while ((n1bytes > 0) && (n2bytes > 0)) + { + *sumptr = *n1ptr-- + *n2ptr-- + carry; + if (*sumptr > (BASE-1)) + { + carry = 1; + *sumptr -= BASE; + } + else + carry = 0; + sumptr--; + n1bytes--; + n2bytes--; + } + + /* Now add carry the longer integer part. */ + if (n1bytes == 0) + { n1bytes = n2bytes; n1ptr = n2ptr; } + while (n1bytes-- > 0) + { + *sumptr = *n1ptr-- + carry; + if (*sumptr > (BASE-1)) + { + carry = 1; + *sumptr -= BASE; + } + else + carry = 0; + sumptr--; + } + + /* Set final carry. */ + if (carry == 1) + *sumptr += 1; + + /* Adjust sum and return. */ + _rm_leading_zeros (sum); + return sum; +} + + +/* Perform subtraction: N2 is subtracted from N1 and the value is + returned. The signs of N1 and N2 are ignored. Also, N1 is + assumed to be larger than N2. SCALE_MIN is the minimum scale + of the result. */ + +static bc_num +_do_sub (n1, n2, scale_min) + bc_num n1, n2; + int scale_min; +{ + bc_num diff; + int diff_scale, diff_len; + int min_scale, min_len; + char *n1ptr, *n2ptr, *diffptr; + int borrow, count, val; + + /* Allocate temporary storage. */ + diff_len = MAX (n1->n_len, n2->n_len); + diff_scale = MAX (n1->n_scale, n2->n_scale); + min_len = MIN (n1->n_len, n2->n_len); + min_scale = MIN (n1->n_scale, n2->n_scale); + diff = new_num (diff_len, MAX(diff_scale, scale_min)); + + /* Zero extra digits made by scale_min. */ + if (scale_min > diff_scale) + { + diffptr = (char *) (diff->n_value + diff_len + diff_scale); + for (count = scale_min - diff_scale; count > 0; count--) + *diffptr++ = 0; + } + + /* Initialize the subtract. */ + n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1); + n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1); + diffptr = (char *) (diff->n_value + diff_len + diff_scale -1); + + /* Subtract the numbers. */ + borrow = 0; + + /* Take care of the longer scaled number. */ + if (n1->n_scale != min_scale) + { + /* n1 has the longer scale */ + for (count = n1->n_scale - min_scale; count > 0; count--) + *diffptr-- = *n1ptr--; + } + else + { + /* n2 has the longer scale */ + for (count = n2->n_scale - min_scale; count > 0; count--) + { + val = - *n2ptr-- - borrow; + if (val < 0) + { + val += BASE; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + } + + /* Now do the equal length scale and integer parts. */ + + for (count = 0; count < min_len + min_scale; count++) + { + val = *n1ptr-- - *n2ptr-- - borrow; + if (val < 0) + { + val += BASE; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + + /* If n1 has more digits then n2, we now do that subtract. */ + if (diff_len != min_len) + { + for (count = diff_len - min_len; count > 0; count--) + { + val = *n1ptr-- - borrow; + if (val < 0) + { + val += BASE; + borrow = 1; + } + else + borrow = 0; + *diffptr-- = val; + } + } + + /* Clean up and return. */ + _rm_leading_zeros (diff); + return diff; +} + + +/* Here is the full add routine that takes care of negative numbers. + N1 is added to N2 and the result placed into RESULT. SCALE_MIN + is the minimum scale for the result. */ + +void +bc_add (n1, n2, result, scale_min) + bc_num n1, n2, *result; + int scale_min; +{ + bc_num sum; + int cmp_res; + int res_scale; + + if (n1->n_sign == n2->n_sign) + { + sum = _do_add (n1, n2, scale_min); + sum->n_sign = n1->n_sign; + } + else + { + /* subtraction must be done. */ + cmp_res = _do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */ + switch (cmp_res) + { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + sum = _do_sub (n2, n1, scale_min); + sum->n_sign = n2->n_sign; + break; + case 0: + /* They are equal! return zero with the correct scale! */ + res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); + sum = new_num (1, res_scale); + memset (sum->n_value, 0, res_scale+1); + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + sum = _do_sub (n1, n2, scale_min); + sum->n_sign = n1->n_sign; + } + } + + /* Clean up and return. */ + free_num (result); + *result = sum; +} + + +/* Here is the full subtract routine that takes care of negative numbers. + N2 is subtracted from N1 and the result placed in RESULT. SCALE_MIN + is the minimum scale for the result. */ + +void +bc_sub (n1, n2, result, scale_min) + bc_num n1, n2, *result; + int scale_min; +{ + bc_num diff; + int cmp_res; + int res_scale; + + if (n1->n_sign != n2->n_sign) + { + diff = _do_add (n1, n2, scale_min); + diff->n_sign = n1->n_sign; + } + else + { + /* subtraction must be done. */ + cmp_res = _do_compare (n1, n2, FALSE, FALSE); /* Compare magnitudes. */ + switch (cmp_res) + { + case -1: + /* n1 is less than n2, subtract n1 from n2. */ + diff = _do_sub (n2, n1, scale_min); + diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS); + break; + case 0: + /* They are equal! return zero! */ + res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale)); + diff = new_num (1, res_scale); + memset (diff->n_value, 0, res_scale+1); + break; + case 1: + /* n2 is less than n1, subtract n2 from n1. */ + diff = _do_sub (n1, n2, scale_min); + diff->n_sign = n1->n_sign; + break; + } + } + + /* Clean up and return. */ + free_num (result); + *result = diff; +} + + +/* The multiply routine. N2 time N1 is put int PROD with the scale of + the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)). + */ + +void +bc_multiply (n1, n2, prod, scale) + bc_num n1, n2, *prod; + int scale; +{ + bc_num pval; /* For the working storage. */ + char *n1ptr, *n2ptr, *pvptr; /* Work pointers. */ + char *n1end, *n2end; /* To the end of n1 and n2. */ + + int indx; + int len1, len2, total_digits; + long sum; + int full_scale, prod_scale; + int toss; + + /* Initialize things. */ + len1 = n1->n_len + n1->n_scale; + len2 = n2->n_len + n2->n_scale; + total_digits = len1 + len2; + full_scale = n1->n_scale + n2->n_scale; + prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale))); + toss = full_scale - prod_scale; + pval = new_num (total_digits-full_scale, prod_scale); + pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + n1end = (char *) (n1->n_value + len1 - 1); + n2end = (char *) (n2->n_value + len2 - 1); + pvptr = (char *) (pval->n_value + total_digits - toss - 1); + sum = 0; + + /* Here are the loops... */ + for (indx = 0; indx < toss; indx++) + { + n1ptr = (char *) (n1end - MAX(0, indx-len2+1)); + n2ptr = (char *) (n2end - MIN(indx, len2-1)); + while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) + sum += *n1ptr-- * *n2ptr++; + sum = sum / BASE; + } + for ( ; indx < total_digits-1; indx++) + { + n1ptr = (char *) (n1end - MAX(0, indx-len2+1)); + n2ptr = (char *) (n2end - MIN(indx, len2-1)); + while ((n1ptr >= n1->n_value) && (n2ptr <= n2end)) + sum += *n1ptr-- * *n2ptr++; + *pvptr-- = sum % BASE; + sum = sum / BASE; + } + *pvptr-- = sum; + + /* Assign to prod and clean up the number. */ + free_num (prod); + *prod = pval; + _rm_leading_zeros (*prod); + if (is_zero (*prod)) + (*prod)->n_sign = PLUS; +} + + +/* Some utility routines for the divide: First a one digit multiply. + NUM (with SIZE digits) is multiplied by DIGIT and the result is + placed into RESULT. It is written so that NUM and RESULT can be + the same pointers. */ + +static void +_one_mult (num, size, digit, result) + unsigned char *num; + int size, digit; + unsigned char *result; +{ + int carry, value; + unsigned char *nptr, *rptr; + + if (digit == 0) + memset (result, 0, size); + else + { + if (digit == 1) + memcpy (result, num, size); + else + { + /* Initialize */ + nptr = (unsigned char *) (num+size-1); + rptr = (unsigned char *) (result+size-1); + carry = 0; + + while (size-- > 0) + { + value = *nptr-- * digit + carry; + *rptr-- = value % BASE; + carry = value / BASE; + } + + if (carry != 0) *rptr = carry; + } + } +} + + +/* The full division routine. This computes N1 / N2. It returns + 0 if the division is ok and the result is in QUOT. The number of + digits after the decimal point is SCALE. It returns -1 if division + by zero is tried. The algorithm is found in Knuth Vol 2. p237. */ + +int +bc_divide (n1, n2, quot, scale) + bc_num n1, n2, *quot; + int scale; +{ + bc_num qval; + unsigned char *num1, *num2; + unsigned char *ptr1, *ptr2, *n2ptr, *qptr; + int scale1, val; + unsigned int len1, len2, scale2, qdigits, extra, count; + unsigned int qdig, qguess, borrow, carry; + unsigned char *mval; + char zero; + unsigned int norm; + + /* Test for divide by zero. */ + if (is_zero (n2)) return -1; + + /* Test for divide by 1. If it is we must truncate. */ + if (n2->n_scale == 0) + { + if (n2->n_len == 1 && *n2->n_value == 1) + { + qval = new_num (n1->n_len, scale); + qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS); + memset (&qval->n_value[n1->n_len],0,scale); + memcpy (qval->n_value, n1->n_value, + n1->n_len + MIN(n1->n_scale,scale)); + free_num (quot); + *quot = qval; + } + } + + /* Set up the divide. Move the decimal point on n1 by n2's scale. + Remember, zeros on the end of num2 are wasted effort for dividing. */ + scale2 = n2->n_scale; + n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1; + while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--; + + len1 = n1->n_len + scale2; + scale1 = n1->n_scale - scale2; + if (scale1 < scale) + extra = scale - scale1; + else + extra = 0; + num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2); + if (num1 == NULL) out_of_memory(); + memset (num1, 0, n1->n_len+n1->n_scale+extra+2); + memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale); + + len2 = n2->n_len + scale2; + num2 = (unsigned char *) malloc (len2+1); + if (num2 == NULL) out_of_memory(); + memcpy (num2, n2->n_value, len2); + *(num2+len2) = 0; + n2ptr = num2; + while (*n2ptr == 0) + { + n2ptr++; + len2--; + } + + /* Calculate the number of quotient digits. */ + if (len2 > len1+scale) + { + qdigits = scale+1; + zero = TRUE; + } + else + { + zero = FALSE; + if (len2>len1) + qdigits = scale+1; /* One for the zero integer part. */ + else + qdigits = len1-len2+scale+1; + } + + /* Allocate and zero the storage for the quotient. */ + qval = new_num (qdigits-scale,scale); + memset (qval->n_value, 0, qdigits); + + /* Allocate storage for the temporary storage mval. */ + mval = (unsigned char *) malloc (len2+1); + if (mval == NULL) out_of_memory (); + + /* Now for the full divide algorithm. */ + if (!zero) + { + /* Normalize */ + norm = 10 / ((int)*n2ptr + 1); + if (norm != 1) + { + _one_mult (num1, len1+scale1+extra+1, norm, num1); + _one_mult (n2ptr, len2, norm, n2ptr); + } + + /* Initialize divide loop. */ + qdig = 0; + if (len2 > len1) + qptr = (unsigned char *) qval->n_value+len2-len1; + else + qptr = (unsigned char *) qval->n_value; + + /* Loop */ + while (qdig <= len1+scale-len2) + { + /* Calculate the quotient digit guess. */ + if (*n2ptr == num1[qdig]) + qguess = 9; + else + qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr; + + /* Test qguess. */ + if (n2ptr[1]*qguess > + (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + + num1[qdig+2]) + { + qguess--; + /* And again. */ + if (n2ptr[1]*qguess > + (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10 + + num1[qdig+2]) + qguess--; + } + + /* Multiply and subtract. */ + borrow = 0; + if (qguess != 0) + { + *mval = 0; + _one_mult (n2ptr, len2, qguess, mval+1); + ptr1 = (unsigned char *) num1+qdig+len2; + ptr2 = (unsigned char *) mval+len2; + for (count = 0; count < len2+1; count++) + { + val = (int) *ptr1 - (int) *ptr2-- - borrow; + if (val < 0) + { + val += 10; + borrow = 1; + } + else + borrow = 0; + *ptr1-- = val; + } + } + + /* Test for negative result. */ + if (borrow == 1) + { + qguess--; + ptr1 = (unsigned char *) num1+qdig+len2; + ptr2 = (unsigned char *) n2ptr+len2-1; + carry = 0; + for (count = 0; count < len2; count++) + { + val = (int) *ptr1 + (int) *ptr2-- + carry; + if (val > 9) + { + val -= 10; + carry = 1; + } + else + carry = 0; + *ptr1-- = val; + } + if (carry == 1) *ptr1 = (*ptr1 + 1) % 10; + } + + /* We now know the quotient digit. */ + *qptr++ = qguess; + qdig++; + } + } + + /* Clean up and return the number. */ + qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS ); + if (is_zero (qval)) qval->n_sign = PLUS; + _rm_leading_zeros (qval); + free_num (quot); + *quot = qval; + + /* Clean up temporary storage. */ + free (mval); + free (num1); + free (num2); + + return 0; /* Everything is OK. */ +} + + +/* Division *and* modulo for numbers. This computes both NUM1 / NUM2 and + NUM1 % NUM2 and puts the results in QUOT and REM, except that if QUOT + is NULL then that store will be omitted. + */ + +int +bc_divmod (num1, num2, quot, rem, scale) + bc_num num1, num2, *quot, *rem; + int scale; +{ + bc_num quotient; + bc_num temp; + int rscale; + + /* Check for correct numbers. */ + if (is_zero (num2)) return -1; + + /* Calculate final scale. */ + rscale = MAX (num1->n_scale, num2->n_scale+scale); + init_num (&temp); + + /* Calculate it. */ + bc_divide (num1, num2, &temp, scale); + if (quot) + quotient = copy_num(temp); + bc_multiply (temp, num2, &temp, rscale); + bc_sub (num1, temp, rem, rscale); + free_num (&temp); + + if (quot) + { + free_num (quot); + *quot = quotient; + } + + return 0; /* Everything is OK. */ +} + + +/* Modulo for numbers. This computes NUM1 % NUM2 and puts the + result in RESULT. */ + +int +bc_modulo (num1, num2, result, scale) + bc_num num1, num2, *result; + int scale; +{ + return bc_divmod (num1, num2, NULL, result, scale); +} + + +/* Raise BASE to the EXPO power, reduced modulo MOD. The result is + placed in RESULT. If a EXPO is not an integer, + only the integer part is used. */ + +int +bc_raisemod (base, expo, mod, result, scale) + bc_num base, expo, mod, *result; + int scale; +{ + bc_num power, exponent, parity, temp; + int rscale; + + /* Check for correct numbers. */ + if (is_zero(mod)) return -1; + if (is_neg(expo)) return -1; + + /* Set initial values. */ + power = copy_num (base); + exponent = copy_num (expo); + temp = copy_num (_one_); + init_num (&parity); + + /* Check the base for scale digits. */ + if (base->n_scale != 0) + rt_warn ("non-zero scale in base"); + + /* Check the exponent for scale digits. */ + if (exponent->n_scale != 0) + { + rt_warn ("non-zero scale in exponent"); + bc_divide (exponent, _one_, &exponent, 0); /*truncate */ + } + + /* Check the modulus for scale digits. */ + if (mod->n_scale != 0) + rt_warn ("non-zero scale in modulus"); + + /* Do the calculation. */ + rscale = MAX(scale, base->n_scale); + while ( !is_zero(exponent) ) + { + (void) bc_divmod (exponent, _two_, &exponent, &parity, 0); + if ( !is_zero(parity) ) + { + bc_multiply (temp, power, &temp, rscale); + (void) bc_modulo (temp, mod, &temp, scale); + } + + bc_multiply (power, power, &power, rscale); + (void) bc_modulo (power, mod, &power, scale); + } + + /* Assign the value. */ + free_num (&power); + free_num (&exponent); + free_num (result); + *result = temp; + return 0; /* Everything is OK. */ +} + + +/* Raise NUM1 to the NUM2 power. The result is placed in RESULT. + Maximum exponent is LONG_MAX. If a NUM2 is not an integer, + only the integer part is used. */ + +void +bc_raise (num1, num2, result, scale) + bc_num num1, num2, *result; + int scale; +{ + bc_num temp, power; + long exponent; + int rscale; + char neg; + + /* Check the exponent for scale digits and convert to a long. */ + if (num2->n_scale != 0) + rt_warn ("non-zero scale in exponent"); + exponent = num2long (num2); + if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0)) + rt_error ("exponent too large in raise"); + + /* Special case if exponent is a zero. */ + if (exponent == 0) + { + free_num (result); + *result = copy_num (_one_); + return; + } + + /* Other initializations. */ + if (exponent < 0) + { + neg = TRUE; + exponent = -exponent; + rscale = scale; + } + else + { + neg = FALSE; + rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale)); + } + + /* Set initial value of temp. */ + power = copy_num (num1); + while ((exponent & 1) == 0) + { + bc_multiply (power, power, &power, rscale); + exponent = exponent >> 1; + } + temp = copy_num (power); + exponent = exponent >> 1; + + + /* Do the calculation. */ + while (exponent > 0) + { + bc_multiply (power, power, &power, rscale); + if ((exponent & 1) == 1) + bc_multiply (temp, power, &temp, rscale); + exponent = exponent >> 1; + } + + /* Assign the value. */ + if (neg) + { + bc_divide (_one_, temp, result, rscale); + free_num (&temp); + } + else + { + free_num (result); + *result = temp; + } + free_num (&power); +} + +/* In some places we need to check if the number NUM is zero. */ + +char +is_near_zero (num, scale) + bc_num num; + int scale; +{ + int count; + char *nptr; + + /* Initialize */ + count = num->n_len + scale; + nptr = num->n_value; + + /* The check */ + while ((count > 0) && (*nptr++ == 0)) count--; + + if (count != 0 && (count != 1 || *--nptr != 1)) + return FALSE; + else + return TRUE; +} + +/* Take the square root NUM and return it in NUM with SCALE digits + after the decimal place. */ + +int +bc_sqrt (num, scale) + bc_num *num; + int scale; +{ + int rscale, cmp_res, done; + int cscale; + bc_num guess, guess1, point5, diff; + + /* Initial checks. */ + cmp_res = bc_compare (*num, _zero_); + if (cmp_res < 0) + return 0; /* error */ + else + { + if (cmp_res == 0) + { + free_num (num); + *num = copy_num (_zero_); + return 1; + } + } + cmp_res = bc_compare (*num, _one_); + if (cmp_res == 0) + { + free_num (num); + *num = copy_num (_one_); + return 1; + } + + /* Initialize the variables. */ + rscale = MAX (scale, (*num)->n_scale); + init_num (&guess); + init_num (&guess1); + init_num (&diff); + point5 = new_num (1,1); + point5->n_value[1] = 5; + + + /* Calculate the initial guess. */ + if (cmp_res < 0) + { + /* The number is between 0 and 1. Guess should start at 1. */ + guess = copy_num (_one_); + cscale = (*num)->n_scale; + } + else + { + /* The number is greater than 1. Guess should start at 10^(exp/2). */ + int2num (&guess,10); + + int2num (&guess1,(*num)->n_len); + bc_multiply (guess1, point5, &guess1, 0); + guess1->n_scale = 0; + bc_raise (guess, guess1, &guess, 0); + free_num (&guess1); + cscale = 3; + } + + /* Find the square root using Newton's algorithm. */ + done = FALSE; + while (!done) + { + free_num (&guess1); + guess1 = copy_num (guess); + bc_divide (*num, guess, &guess, cscale); + bc_add (guess, guess1, &guess, 0); + bc_multiply (guess, point5, &guess, cscale); + bc_sub (guess, guess1, &diff, cscale+1); + if (is_near_zero (diff, cscale)) + if (cscale < rscale+1) + cscale = MIN (cscale*3, rscale+1); + else + done = TRUE; + } + + /* Assign the number and clean up. */ + free_num (num); + bc_divide (guess,_one_,num,rscale); + free_num (&guess); + free_num (&guess1); + free_num (&point5); + free_num (&diff); + return 1; +} + + +/* The following routines provide output for bcd numbers package + using the rules of POSIX bc for output. */ + +/* This structure is used for saving digits in the conversion process. */ +typedef struct stk_rec { + long digit; + struct stk_rec *next; +} stk_rec; + +/* The reference string for digits. */ +char ref_str[] = "0123456789ABCDEF"; + + +/* A special output routine for "multi-character digits." Exactly + SIZE characters must be output for the value VAL. If SPACE is + non-zero, we must output one space before the number. OUT_CHAR + is the actual routine for writing the characters. */ + +void +out_long (val, size, space, out_char) + long val; + int size, space; +#ifdef __STDC__ + void (*out_char)(int); +#else + void (*out_char)(); +#endif +{ + char digits[40]; + int len, ix; + + if (space) (*out_char) (' '); + sprintf (digits, "%ld", val); + len = strlen (digits); + while (size > len) + { + (*out_char) ('0'); + size--; + } + for (ix=0; ix < len; ix++) + (*out_char) (digits[ix]); +} + +/* Output of a bcd number. NUM is written in base O_BASE using OUT_CHAR + as the routine to do the actual output of the characters. */ + +void +out_num (num, o_base, out_char) + bc_num num; + int o_base; +#ifdef __STDC__ + void (*out_char)(int); +#else + void (*out_char)(); +#endif +{ + char *nptr; + int index, fdigit, pre_space; + stk_rec *digits, *temp; + bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit; + + /* The negative sign if needed. */ + if (num->n_sign == MINUS) (*out_char) ('-'); + + /* Output the number. */ + if (is_zero (num)) + (*out_char) ('0'); + else + if (o_base == 10) + { + /* The number is in base 10, do it the fast way. */ + nptr = num->n_value; + if (num->n_len > 1 || *nptr != 0) + for (index=num->n_len; index>0; index--) + (*out_char) (BCD_CHAR(*nptr++)); + else + nptr++; + + if (std_only && is_zero (num)) + (*out_char) ('0'); + + /* Now the fraction. */ + if (num->n_scale > 0) + { + (*out_char) ('.'); + for (index=0; index<num->n_scale; index++) + (*out_char) (BCD_CHAR(*nptr++)); + } + } + else + { + /* special case ... */ + if (std_only && is_zero (num)) + (*out_char) ('0'); + + /* The number is some other base. */ + digits = NULL; + init_num (&int_part); + bc_divide (num, _one_, &int_part, 0); + init_num (&frac_part); + init_num (&cur_dig); + init_num (&base); + bc_sub (num, int_part, &frac_part, 0); + /* Make the INT_PART and FRAC_PART positive. */ + int_part->n_sign = PLUS; + frac_part->n_sign = PLUS; + int2num (&base, o_base); + init_num (&max_o_digit); + int2num (&max_o_digit, o_base-1); + + + /* Get the digits of the integer part and push them on a stack. */ + while (!is_zero (int_part)) + { + bc_modulo (int_part, base, &cur_dig, 0); + temp = (stk_rec *) malloc (sizeof(stk_rec)); + if (temp == NULL) out_of_memory(); + temp->digit = num2long (cur_dig); + temp->next = digits; + digits = temp; + bc_divide (int_part, base, &int_part, 0); + } + + /* Print the digits on the stack. */ + if (digits != NULL) + { + /* Output the digits. */ + while (digits != NULL) + { + temp = digits; + digits = digits->next; + if (o_base <= 16) + (*out_char) (ref_str[ (int) temp->digit]); + else + out_long (temp->digit, max_o_digit->n_len, 1, out_char); + free (temp); + } + } + + /* Get and print the digits of the fraction part. */ + if (num->n_scale > 0) + { + (*out_char) ('.'); + pre_space = 0; + t_num = copy_num (_one_); + while (t_num->n_len <= num->n_scale) { + bc_multiply (frac_part, base, &frac_part, num->n_scale); + fdigit = num2long (frac_part); + int2num (&int_part, fdigit); + bc_sub (frac_part, int_part, &frac_part, 0); + if (o_base <= 16) + (*out_char) (ref_str[fdigit]); + else { + out_long (fdigit, max_o_digit->n_len, pre_space, out_char); + pre_space = 1; + } + bc_multiply (t_num, base, &t_num, 0); + } + free_num (&t_num); + } + + /* Clean up. */ + free_num (&int_part); + free_num (&frac_part); + free_num (&base); + free_num (&cur_dig); + free_num (&max_o_digit); + } +} + +#if DEBUG > 0 + +/* Debugging procedures. Some are just so one can call them from the + debugger. */ + +/* p_n prints the number NUM in base 10. */ + +void +p_n (num) + bc_num num; +{ + out_num (num, 10, out_char); +} + + +/* p_b prints a character array as if it was a string of bcd digits. */ +void +p_v (name, num, len) + char *name; + unsigned char *num; + int len; +{ + int i; + printf ("%s=", name); + for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i])); + printf ("\n"); +} + + +/* Convert strings to bc numbers. Base 10 only.*/ + +void +str2num (num, str, scale) + bc_num *num; + char *str; + int scale; +{ + int digits, strscale; + char *ptr, *nptr; + char zero_int; + + /* Prepare num. */ + free_num (num); + + /* Check for valid number and count digits. */ + ptr = str; + digits = 0; + strscale = 0; + zero_int = FALSE; + if ( (*ptr == '+') || (*ptr == '-')) ptr++; /* Sign */ + while (*ptr == '0') ptr++; /* Skip leading zeros. */ + while (isdigit(*ptr)) ptr++, digits++; /* digits */ + if (*ptr == '.') ptr++; /* decimal point */ + while (isdigit(*ptr)) ptr++, strscale++; /* digits */ + if ((*ptr != '\0') || (digits+strscale == 0)) + { + *num = copy_num (_zero_); + return; + } + + /* Adjust numbers and allocate storage and initialize fields. */ + strscale = MIN(strscale, scale); + if (digits == 0) + { + zero_int = TRUE; + digits = 1; + } + *num = new_num (digits, strscale); + + /* Build the whole number. */ + ptr = str; + if (*ptr == '-') + { + (*num)->n_sign = MINUS; + ptr++; + } + else + { + (*num)->n_sign = PLUS; + if (*ptr == '+') ptr++; + } + while (*ptr == '0') ptr++; /* Skip leading zeros. */ + nptr = (*num)->n_value; + if (zero_int) + { + *nptr++ = 0; + digits = 0; + } + for (;digits > 0; digits--) + *nptr++ = CH_VAL(*ptr++); + + + /* Build the fractional part. */ + if (strscale > 0) + { + ptr++; /* skip the decimal point! */ + for (;strscale > 0; strscale--) + *nptr++ = CH_VAL(*ptr++); + } +} + +/* Convert a numbers to a string. Base 10 only.*/ + +char +*num2str (num) + bc_num num; +{ + char *str, *sptr; + char *nptr; + int index, signch; + + /* Allocate the string memory. */ + signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */ + if (num->n_scale > 0) + str = (char *) malloc (num->n_len + num->n_scale + 2 + signch); + else + str = (char *) malloc (num->n_len + 1 + signch); + if (str == NULL) out_of_memory(); + + /* The negative sign if needed. */ + sptr = str; + if (signch) *sptr++ = '-'; + + /* Load the whole number. */ + nptr = num->n_value; + for (index=num->n_len; index>0; index--) + *sptr++ = BCD_CHAR(*nptr++); + + /* Now the fraction. */ + if (num->n_scale > 0) + { + *sptr++ = '.'; + for (index=0; index<num->n_scale; index++) + *sptr++ = BCD_CHAR(*nptr++); + } + + /* Terminate the string and return it! */ + *sptr = '\0'; + return (str); +} +#endif diff --git a/gnu/usr.bin/bc/lib/vfprintf.c b/gnu/usr.bin/bc/lib/vfprintf.c new file mode 100644 index 00000000000..78edd359a77 --- /dev/null +++ b/gnu/usr.bin/bc/lib/vfprintf.c @@ -0,0 +1,31 @@ +/* vfprintf.c -- this was provided for minix. It may not + work on any other system. */ + +#include "config.h" +#ifndef HAVE_VPRINTF +#ifndef HAVE_DOPRINT +# error need vfprintf() or doprint() +#else + +#ifdef HAVE_LIB_H +#include <lib.h> +#endif +#ifdef HAVE_STDARG_H +#include <stdarg.h> +#endif +#ifdef HAVE_STDIO_H +#include <stdio.h> +#endif + +int vfprintf(file, format, argp) +FILE *file; +_CONST char *format; +va_list argp; +{ + _doprintf(file, format, argp); + if (testflag(file, PERPRINTF)) fflush(file); + return 0; +} + +#endif /* HAVE_DOPRINT */ +#endif /* !HAVE_VFPRINTF */ diff --git a/gnu/usr.bin/bc/missing b/gnu/usr.bin/bc/missing new file mode 100644 index 00000000000..e4b838ca924 --- /dev/null +++ b/gnu/usr.bin/bc/missing @@ -0,0 +1,134 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison touch file \`y.tab.c' + makeinfo touch the output file + yacc touch file \`y.tab.c'" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + touch config.h.in + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + your modified any \`.y' file. For being effective, your + modifications might require the \`Bison' package. Grab it from + any GNU archive site." + touch y.tab.c + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. It should be needed only if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/gnu/usr.bin/bc/mkinstalldirs b/gnu/usr.bin/bc/mkinstalldirs new file mode 100644 index 00000000000..cc8783edce3 --- /dev/null +++ b/gnu/usr.bin/bc/mkinstalldirs @@ -0,0 +1,36 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Last modified: 1994-03-25 +# Public domain + +errstatus=0 + +for file in ${1+"$@"} ; do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d in ${1+"$@"} ; do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + mkdir "$pathcomp" > /dev/null 2>&1 || lasterr=$? + fi + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/gnu/usr.bin/bc/stamp-h.in b/gnu/usr.bin/bc/stamp-h.in new file mode 100644 index 00000000000..9788f70238c --- /dev/null +++ b/gnu/usr.bin/bc/stamp-h.in @@ -0,0 +1 @@ +timestamp |