diff options
author | andreas <andreas@FreeBSD.org> | 1998-04-29 21:53:01 +0000 |
---|---|---|
committer | andreas <andreas@FreeBSD.org> | 1998-04-29 21:53:01 +0000 |
commit | 0ec6169bea8adb8ddbf8f9ce363f6e1803f88621 (patch) | |
tree | 1529c15b522fa7bd199b5491bc88817aefc9b779 /contrib/bc/dc | |
download | FreeBSD-src-0ec6169bea8adb8ddbf8f9ce363f6e1803f88621.zip FreeBSD-src-0ec6169bea8adb8ddbf8f9ce363f6e1803f88621.tar.gz |
Import GNU bc 1.04
PR: 4183
Diffstat (limited to 'contrib/bc/dc')
-rw-r--r-- | contrib/bc/dc/Makefile.am | 10 | ||||
-rw-r--r-- | contrib/bc/dc/Makefile.in | 250 | ||||
-rw-r--r-- | contrib/bc/dc/array.c | 108 | ||||
-rw-r--r-- | contrib/bc/dc/dc-proto.h | 83 | ||||
-rw-r--r-- | contrib/bc/dc/dc-regdef.h | 40 | ||||
-rw-r--r-- | contrib/bc/dc/dc.c | 173 | ||||
-rw-r--r-- | contrib/bc/dc/dc.h | 78 | ||||
-rw-r--r-- | contrib/bc/dc/eval.c | 646 | ||||
-rw-r--r-- | contrib/bc/dc/misc.c | 177 | ||||
-rw-r--r-- | contrib/bc/dc/numeric.c | 536 | ||||
-rw-r--r-- | contrib/bc/dc/stack.c | 457 | ||||
-rw-r--r-- | contrib/bc/dc/string.c | 208 |
12 files changed, 2766 insertions, 0 deletions
diff --git a/contrib/bc/dc/Makefile.am b/contrib/bc/dc/Makefile.am new file mode 100644 index 0000000..4de00ab --- /dev/null +++ b/contrib/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/contrib/bc/dc/Makefile.in b/contrib/bc/dc/Makefile.in new file mode 100644 index 0000000..44faf94 --- /dev/null +++ b/contrib/bc/dc/Makefile.in @@ -0,0 +1,250 @@ +# Makefile.in generated automatically by automake 1.1n from Makefile.am + +# Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + + +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 + +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 = true +PRE_INSTALL = true +POST_INSTALL = true +NORMAL_UNINSTALL = true +PRE_UNINSTALL = true +POST_UNINSTALL = true +CC = @CC@ +LEX = @LEX@ +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) $(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) + +default: all + +.SUFFIXES: +.SUFFIXES: .c .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu dc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + 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) $(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + $(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +.c.o: + $(COMPILE) -c $< + +mostlyclean-compile: + rm -f *.o 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) + here=`pwd` && cd $(srcdir) && mkid -f$$here/ID $(SOURCES) $(HEADERS) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + done; \ + test -z "$(ETAGS_ARGS)$(SOURCES)$(HEADERS)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $(SOURCES) $(HEADERS) -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 + +all: $(PROGRAMS) $(HEADERS) Makefile + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install +installdirs: + $(mkinstalldirs) $(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 + 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: default 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/contrib/bc/dc/array.c b/contrib/bc/dc/array.c new file mode 100644 index 0000000..2fc1b7e --- /dev/null +++ b/contrib/bc/dc/array.c @@ -0,0 +1,108 @@ +/* + * implement arrays for dc + * + * 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. + */ + +/* 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; +}; +typedef struct dc_array dc_array; + +/* I can find no reason not to place arrays in their own namespace... */ +static dc_array *dc_array_register[DC_REGCOUNT]; + + +/* initialize the arrays to their initial values */ +void +dc_array_init DC_DECLVOID() +{ + int i; + + for (i=0; i<DC_REGCOUNT; ++i) + dc_array_register[i] = NULL; +} + +/* 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 +{ + dc_array *cur; + dc_array *prev=NULL; + dc_array *newentry; + + array_id = regmap(array_id); + cur = dc_array_register[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_array_register[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 +{ + dc_array *cur; + + for (cur=dc_array_register[regmap(array_id)]; cur; cur=cur->next) + if (cur->Index == Index) + return dc_dup(cur->value); + return dc_int2data(0); +} diff --git a/contrib/bc/dc/dc-proto.h b/contrib/bc/dc/dc-proto.h new file mode 100644 index 0000000..5aa9bc7 --- /dev/null +++ b/contrib/bc/dc/dc-proto.h @@ -0,0 +1,83 @@ +/* + * prototypes of all externally visible dc functions + * + * Copyright (C) 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, 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 void dc_array_set DC_PROTO((int, int, dc_data)); +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_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_boolean, dc_boolean)); +extern void dc_out_str DC_PROTO((dc_str, dc_boolean, dc_boolean)); +extern void dc_print DC_PROTO((dc_data, int)); +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_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_boolean)); +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_boolean)); +extern int dc_tell_scale DC_PROTO((dc_num, dc_boolean)); +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/contrib/bc/dc/dc-regdef.h b/contrib/bc/dc/dc-regdef.h new file mode 100644 index 0000000..129d0ae --- /dev/null +++ b/contrib/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/contrib/bc/dc/dc.c b/contrib/bc/dc/dc.c new file mode 100644 index 0000000..85da40f --- /dev/null +++ b/contrib/bc/dc/dc.c @@ -0,0 +1,173 @@ +/* + * implement the "dc" Desk Calculator language. + * + * Copyright (C) 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, 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 @\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 ( !(input=fopen(filename, "r")) ) { + fprintf(stderr, "Could not open file "); + perror(filename); + exit(EXIT_FAILURE); + } + if (dc_evalfile(input)) + exit(EXIT_FAILURE); + 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, '/'); + dc_math_init(); + dc_string_init(); + dc_register_init(); + dc_array_init(); + + while ((c = getopt_long(argc, argv, "hVe:", 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) { + if (strcmp(argv[optind], "-") == 0) { + if (dc_evalfile(stdin)) + return EXIT_FAILURE; + } else { + 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/contrib/bc/dc/dc.h b/contrib/bc/dc/dc.h new file mode 100644 index 0000000..eeac77b --- /dev/null +++ b/contrib/bc/dc/dc.h @@ -0,0 +1,78 @@ +/* + * Header file for dc routines + * + * Copyright (C) 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, 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_FALSE, DC_TRUE} dc_boolean; + + +/* 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/contrib/bc/dc/eval.c b/contrib/bc/dc/eval.c new file mode 100644 index 0000000..cac4cb1 --- /dev/null +++ b/contrib/bc/dc/eval.c @@ -0,0 +1,646 @@ +/* + * evaluate the dc language, from a FILE* or a string + * + * Copyright (C) 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, 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_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_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 + */ +static dc_status +dc_func DC_DECLARG((c, peekc)) + int c DC_DECLSEP + int peekc 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) + 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) + 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) + 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 */ + 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_TRUE); + dc_free_num(&datum.v.number); + }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_TRUE); + 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_TRUE); + 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 '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_TRUE); + 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 */ + if (dc_top_of_stack(&datum) == DC_SUCCESS) + dc_print(datum, dc_obase); + break; + case 'q': /* quit two levels of evaluation, posibly exiting program */ + unwind_depth = 2; + 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': /* print the value popped off of top-of-stack; + * do not add a trailing newline + */ + if (dc_pop(&datum) == DC_SUCCESS){ + if (datum.dc_type == DC_STRING) + dc_out_str(datum.v.string, DC_FALSE, DC_TRUE); + else if (datum.dc_type == DC_NUMBER) + dc_out_num(datum.v.number, dc_obase, DC_FALSE, DC_TRUE); + 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_TRUE); + if (unwind_depth > 0) + return DC_QUIT; + 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_TRUE); + 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_TRUE); + 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_TRUE))); + 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_TRUE); + 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_TRUE); + 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; + + 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; + switch (dc_func(c, peekc)){ + 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_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; + 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; + switch (dc_func(c, peekc)){ + 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_EOF_ERROR: + fprintf(stderr, "%s: unexpected EOF\n", progname); + return DC_FAIL; + } + } + return DC_SUCCESS; +} diff --git a/contrib/bc/dc/misc.c b/contrib/bc/dc/misc.c new file mode 100644 index 0000000..8c360ca --- /dev/null +++ b/contrib/bc/dc/misc.c @@ -0,0 +1,177 @@ +/* + * misc. functions for the "dc" Desk Calculator language. + * + * Copyright (C) 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, 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)) + dc_data value DC_DECLSEP + int obase DC_DECLEND +{ + if (value.dc_type == DC_NUMBER) { + dc_out_num(value.v.number, obase, DC_TRUE, DC_FALSE); + } else if (value.dc_type == DC_STRING) { + dc_out_str(value.v.string, DC_TRUE, DC_FALSE); + } 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/contrib/bc/dc/numeric.c b/contrib/bc/dc/numeric.c new file mode 100644 index 0000000..ec19344 --- /dev/null +++ b/contrib/bc/dc/numeric.c @@ -0,0 +1,536 @@ +/* + * interface dc to the bc numeric routines + * + * Copyright (C) 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, 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> +#include "bcdefs.h" +#include "proto.h" +#include "global.h" +#include "dc.h" +#include "dc-proto.h" + +/* 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 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 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_flag is true then deallocate the value after use. + */ +int +dc_num2int DC_DECLARG((value, discard_flag)) + dc_num value DC_DECLSEP + dc_boolean discard_flag DC_DECLEND +{ + long result; + + result = num2long(CastNum(value)); + if (discard_flag) + 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_flag is true then deallocate the value after use. + */ +int +dc_tell_scale DC_DECLARG((value, discard_flag)) + dc_num value DC_DECLSEP + dc_boolean discard_flag DC_DECLEND +{ + int kscale; + + kscale = CastNum(value)->n_scale; + if (discard_flag) + 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 is true, terminate output with a '\n'; + * if discard_flag is true then deallocate the value after use + */ +void +dc_out_num DC_DECLARG((value, obase, newline, discard_flag)) + dc_num value DC_DECLSEP + int obase DC_DECLSEP + dc_boolean newline DC_DECLSEP + dc_boolean discard_flag DC_DECLEND +{ + out_num(CastNum(value), obase, out_char); + if (newline) + out_char('\n'); + if (discard_flag) + dc_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/contrib/bc/dc/stack.c b/contrib/bc/dc/stack.c new file mode 100644 index 0000000..c8cd195 --- /dev/null +++ b/contrib/bc/dc/stack.c @@ -0,0 +1,457 @@ +/* + * implement stack functions for dc + * + * Copyright (C) 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, 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_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->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); + 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; + 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; + 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_flag is true, 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_flag)) + dc_data value DC_DECLSEP + dc_boolean discard_flag DC_DECLEND +{ + int length; + + if (value.dc_type == DC_NUMBER){ + length = dc_numlen(value.v.number); + if (discard_flag == DC_TRUE) + dc_free_num(&value.v.number); + } else if (value.dc_type == DC_STRING) { + length = dc_strlen(value.v.string); + if (discard_flag == DC_TRUE) + 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); +} diff --git a/contrib/bc/dc/string.c b/contrib/bc/dc/string.c new file mode 100644 index 0000000..35bc263 --- /dev/null +++ b/contrib/bc/dc/string.c @@ -0,0 +1,208 @@ +/* + * implement string functions for dc + * + * Copyright (C) 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, 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_boolean newline DC_DECLSEP + dc_boolean discard_flag DC_DECLEND +{ + fwrite(value->s_ptr, value->s_len, sizeof *value->s_ptr, stdout); + if (newline == DC_TRUE) + printf("\n"); + if (discard_flag == DC_TRUE) + 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 */ +} |