|
Packit |
70b277 |
/*
|
|
Packit |
70b277 |
* evaluate the dc language, from a FILE* or a string
|
|
Packit |
70b277 |
*
|
|
Packit |
70b277 |
* Copyright (C) 1994, 1997, 1998, 2000, 2003, 2005, 2006, 2008, 2010, 2012-2017
|
|
Packit |
70b277 |
* Free Software Foundation, Inc.
|
|
Packit |
70b277 |
*
|
|
Packit |
70b277 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
70b277 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
70b277 |
* the Free Software Foundation; either version 3, or (at your option)
|
|
Packit |
70b277 |
* any later version.
|
|
Packit |
70b277 |
*
|
|
Packit |
70b277 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
70b277 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
70b277 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
70b277 |
* GNU General Public License for more details.
|
|
Packit |
70b277 |
*
|
|
Packit |
70b277 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
70b277 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
70b277 |
*
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* This is the only module which knows about the dc input language */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#include "config.h"
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
#include <stdio.h>
|
|
Packit |
70b277 |
#ifdef HAVE_STRING_H
|
|
Packit |
70b277 |
# include <string.h> /* memchr */
|
|
Packit |
70b277 |
#else
|
|
Packit |
70b277 |
# ifdef HAVE_MEMORY_H
|
|
Packit |
70b277 |
# include <memory.h> /* memchr, maybe */
|
|
Packit |
70b277 |
# else
|
|
Packit |
70b277 |
# ifdef HAVE_STRINGS_H
|
|
Packit |
70b277 |
# include <strings.h> /* memchr, maybe */
|
|
Packit |
70b277 |
# endif
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
#include <signal.h>
|
|
Packit |
70b277 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
70b277 |
# include <unistd.h>
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
#include "dc.h"
|
|
Packit |
70b277 |
#include "dc-proto.h"
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
typedef enum {DC_FALSE, DC_TRUE} dc_boolean;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
typedef enum {
|
|
Packit |
70b277 |
DC_OKAY = DC_SUCCESS, /* no further intervention needed for this command */
|
|
Packit |
70b277 |
DC_EATONE, /* caller needs to eat the lookahead char */
|
|
Packit |
70b277 |
DC_EVALREG, /* caller needs to eval the string named by `peekc' */
|
|
Packit |
70b277 |
DC_EVALTOS, /* caller needs to eval the string on top of the stack */
|
|
Packit |
70b277 |
DC_QUIT, /* quit out of unwind_depth levels of evaluation */
|
|
Packit |
70b277 |
DC_INT, /* caller needs to parse a dc_num from input stream */
|
|
Packit |
70b277 |
DC_STR, /* caller needs to parse a dc_str from input stream */
|
|
Packit |
70b277 |
DC_SYSTEM, /* caller needs to run a system() on next input line */
|
|
Packit |
70b277 |
DC_COMMENT, /* caller needs to skip to the next input line */
|
|
Packit |
70b277 |
DC_NEGCMP, /* caller needs to re-call dc_func() with `negcmp' set */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
DC_EOF_ERROR /* unexpected end of input; abort current eval */
|
|
Packit |
70b277 |
} dc_status;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
static int dc_ibase=10; /* input base, 2 <= dc_ibase <= DC_IBASE_MAX */
|
|
Packit |
70b277 |
static int dc_obase=10; /* output base, 2 <= dc_obase */
|
|
Packit |
70b277 |
static int dc_scale=0; /* scale (see user documentaton) */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* for Quitting evaluations */
|
|
Packit |
70b277 |
static int unwind_depth=0;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* for handling SIGINT properly */
|
|
Packit |
70b277 |
static volatile sig_atomic_t interrupt_seen=0;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* if true, active Quit will not exit program */
|
|
Packit |
70b277 |
static dc_boolean unwind_noexit=DC_FALSE;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/*
|
|
Packit |
70b277 |
* Used to synchronize lookahead on stdin for '?' command.
|
|
Packit |
70b277 |
* If set to EOF then lookahead is used up.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
static int stdin_lookahead=EOF;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* forward reference */
|
|
Packit |
70b277 |
static int evalstr(dc_data *string);
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* input_fil and input_str are passed as arguments to dc_getnum */
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* used by the input_* functions: */
|
|
Packit |
70b277 |
static FILE *input_fil_fp;
|
|
Packit |
70b277 |
static const char *input_str_string;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Since we have a need for two characters of pushback, and
|
|
Packit |
70b277 |
* ungetc() only guarantees one, we place the second pushback here
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
static int input_pushback;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* passed as an argument to dc_getnum */
|
|
Packit |
70b277 |
static int
|
|
Packit |
70b277 |
input_fil DC_DECLVOID()
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (input_pushback != EOF){
|
|
Packit |
70b277 |
int c = input_pushback;
|
|
Packit |
70b277 |
input_pushback = EOF;
|
|
Packit |
70b277 |
return c;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
return getc(input_fil_fp);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* passed as an argument to dc_getnum */
|
|
Packit |
70b277 |
static int
|
|
Packit |
70b277 |
input_str DC_DECLVOID()
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
if (*input_str_string == '\0')
|
|
Packit |
70b277 |
return EOF;
|
|
Packit |
70b277 |
return *(const unsigned char *)input_str_string++;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* takes a string and evals it; frees the string when done */
|
|
Packit |
70b277 |
/* Wrapper around evalstr to avoid duplicating the free call
|
|
Packit |
70b277 |
* at all possible return points.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
static int
|
|
Packit |
70b277 |
dc_eval_and_free_str DC_DECLARG((string))
|
|
Packit |
70b277 |
dc_data *string DC_DECLEND
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
dc_status status;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
status = evalstr(string);
|
|
Packit |
70b277 |
if (string->dc_type == DC_STRING)
|
|
Packit |
70b277 |
dc_free_str(&string->v.string);
|
|
Packit |
70b277 |
return status;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* notice when an interrupt event happens */
|
|
Packit |
70b277 |
static void
|
|
Packit |
70b277 |
dc_trap_interrupt DC_DECLARG((signo))
|
|
Packit |
70b277 |
int signo DC_DECLEND
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
signal(signo, dc_trap_interrupt);
|
|
Packit |
70b277 |
interrupt_seen = 1;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* step pointer past next end-of-line (or to end-of-string) */
|
|
Packit |
70b277 |
static const char *
|
|
Packit |
70b277 |
skip_past_eol DC_DECLARG((strptr, strend))
|
|
Packit |
70b277 |
const char *strptr DC_DECLSEP
|
|
Packit |
70b277 |
const char *strend DC_DECLEND
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
const char *p = memchr(strptr, '\n', (size_t)(strend-strptr));
|
|
Packit |
70b277 |
if (p != NULL)
|
|
Packit |
70b277 |
return p+1;
|
|
Packit |
70b277 |
return strend;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* dc_func does the grunt work of figuring out what each input
|
|
Packit |
70b277 |
* character means; used by both dc_evalstr and dc_evalfile
|
|
Packit |
70b277 |
*
|
|
Packit |
70b277 |
* c -> the "current" input character under consideration
|
|
Packit |
70b277 |
* peekc -> the lookahead input character
|
|
Packit |
70b277 |
* negcmp -> negate comparison test (for <,=,> commands)
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
static dc_status
|
|
Packit |
70b277 |
dc_func DC_DECLARG((c, peekc, negcmp))
|
|
Packit |
70b277 |
int c DC_DECLSEP
|
|
Packit |
70b277 |
int peekc DC_DECLSEP
|
|
Packit |
70b277 |
int negcmp DC_DECLEND
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
dc_data datum;
|
|
Packit |
70b277 |
int tmpint;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
switch (c){
|
|
Packit |
70b277 |
case '_': case '.':
|
|
Packit |
70b277 |
case '0': case '1': case '2': case '3':
|
|
Packit |
70b277 |
case '4': case '5': case '6': case '7':
|
|
Packit |
70b277 |
case '8': case '9': case 'A': case 'B':
|
|
Packit |
70b277 |
case 'C': case 'D': case 'E': case 'F':
|
|
Packit |
70b277 |
return DC_INT;
|
|
Packit |
70b277 |
case ' ':
|
|
Packit |
70b277 |
case '\t':
|
|
Packit |
70b277 |
case '\n':
|
|
Packit |
70b277 |
/* standard command separators */
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case '+': /* add top two stack elements */
|
|
Packit |
70b277 |
dc_binop(dc_add, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '-': /* subtract top two stack elements */
|
|
Packit |
70b277 |
dc_binop(dc_sub, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '*': /* multiply top two stack elements */
|
|
Packit |
70b277 |
dc_binop(dc_mul, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '/': /* divide top two stack elements */
|
|
Packit |
70b277 |
dc_binop(dc_div, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '%':
|
|
Packit |
70b277 |
/* take the remainder from division of the top two stack elements */
|
|
Packit |
70b277 |
dc_binop(dc_rem, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '~':
|
|
Packit |
70b277 |
/* Do division on the top two stack elements. Return the
|
|
Packit |
70b277 |
* quotient as next-to-top of stack and the remainder as
|
|
Packit |
70b277 |
* top-of-stack.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
dc_binop2(dc_divrem, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '|':
|
|
Packit |
70b277 |
/* Consider the top three elements of the stack as (base, exp, mod),
|
|
Packit |
70b277 |
* where mod is top-of-stack, exp is next-to-top, and base is
|
|
Packit |
70b277 |
* second-from-top. Mod must be non-zero, exp must be non-negative,
|
|
Packit |
70b277 |
* and all three must be integers. Push the result of raising
|
|
Packit |
70b277 |
* base to the exp power, reduced modulo mod. If we had base in
|
|
Packit |
70b277 |
* register b, exp in register e, and mod in register m then this
|
|
Packit |
70b277 |
* is conceptually equivalent to "lble^lm%", but it is implemented
|
|
Packit |
70b277 |
* in a more efficient manner, and can handle arbritrarily large
|
|
Packit |
70b277 |
* values for exp.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
dc_triop(dc_modexp, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '^': /* exponientiation of the top two stack elements */
|
|
Packit |
70b277 |
dc_binop(dc_exp, dc_scale);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case '<':
|
|
Packit |
70b277 |
/* eval register named by peekc if
|
|
Packit |
70b277 |
* less-than holds for top two stack elements
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if ( (dc_cmpop() < 0) == (negcmp==0) )
|
|
Packit |
70b277 |
return DC_EVALREG;
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case '=':
|
|
Packit |
70b277 |
/* eval register named by peekc if
|
|
Packit |
70b277 |
* equal-to holds for top two stack elements
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if ( (dc_cmpop() == 0) == (negcmp==0) )
|
|
Packit |
70b277 |
return DC_EVALREG;
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case '>':
|
|
Packit |
70b277 |
/* eval register named by peekc if
|
|
Packit |
70b277 |
* greater-than holds for top two stack elements
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if ( (dc_cmpop() > 0) == (negcmp==0) )
|
|
Packit |
70b277 |
return DC_EVALREG;
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case '?': /* read a line from standard-input and eval it */
|
|
Packit |
70b277 |
if (stdin_lookahead != EOF){
|
|
Packit |
70b277 |
ungetc(stdin_lookahead, stdin);
|
|
Packit |
70b277 |
stdin_lookahead = EOF;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
datum = dc_readstring(stdin, '\n', '\n');
|
|
Packit |
70b277 |
if (ferror(stdin))
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
return DC_EVALTOS;
|
|
Packit |
70b277 |
case '[': /* read to balancing ']' into a dc_str */
|
|
Packit |
70b277 |
return DC_STR;
|
|
Packit |
70b277 |
case '!': /* read to newline and call system() on resulting string */
|
|
Packit |
70b277 |
if (peekc == '<' || peekc == '=' || peekc == '>')
|
|
Packit |
70b277 |
return DC_NEGCMP;
|
|
Packit |
70b277 |
return DC_SYSTEM;
|
|
Packit |
70b277 |
case '#': /* comment; skip remainder of current line */
|
|
Packit |
70b277 |
return DC_COMMENT;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'a': /* Convert top of stack to an ascii character. */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
char tmps;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER){
|
|
Packit |
70b277 |
tmps = (char) dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
}else if (datum.dc_type == DC_STRING){
|
|
Packit |
70b277 |
tmps = *dc_str2charp(datum.v.string);
|
|
Packit |
70b277 |
dc_free_str(&datum.v.string);
|
|
Packit |
70b277 |
}else{
|
|
Packit |
70b277 |
dc_garbage("at top of stack", -1);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
dc_push(dc_makestring(&tmps, 1));
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'c': /* clear whole stack */
|
|
Packit |
70b277 |
dc_clear_stack();
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'd': /* duplicate the datum on the top of stack */
|
|
Packit |
70b277 |
if (dc_top_of_stack(&datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_push(dc_dup(datum));
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'f': /* print list of all stack items */
|
|
Packit |
70b277 |
dc_printall(dc_obase);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'i': /* set input base to value on top of stack */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = 0;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
if (2 <= tmpint && tmpint <= DC_IBASE_MAX)
|
|
Packit |
70b277 |
dc_ibase = tmpint;
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: input base must be a number \
|
|
Packit |
70b277 |
between 2 and %d (inclusive)\n",
|
|
Packit |
70b277 |
progname, DC_IBASE_MAX);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'k': /* set scale to value on top of stack */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = -1;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
if ( ! (tmpint >= 0) )
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: scale must be a nonnegative number\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
dc_scale = tmpint;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'l': /* "load" -- push value on top of register stack named
|
|
Packit |
70b277 |
* by peekc onto top of evaluation stack; does not
|
|
Packit |
70b277 |
* modify the register stack
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if (dc_register_get(peekc, &datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case 'n': /* print the value popped off of top-of-stack;
|
|
Packit |
70b277 |
* do not add a trailing newline
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_print(datum, dc_obase, DC_NONL, DC_TOSS);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'o': /* set output base to value on top of stack */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = 0;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
if ( ! (tmpint > 1) )
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: output base must be a number greater than 1\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
dc_obase = tmpint;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'p': /* print the datum on the top of stack,
|
|
Packit |
70b277 |
* with a trailing newline
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (dc_top_of_stack(&datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_print(datum, dc_obase, DC_WITHNL, DC_KEEP);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'q': /* quit two levels of evaluation, posibly exiting program */
|
|
Packit |
70b277 |
unwind_depth = 1; /* the return below is the first level of returns */
|
|
Packit |
70b277 |
unwind_noexit = DC_FALSE;
|
|
Packit |
70b277 |
return DC_QUIT;
|
|
Packit |
70b277 |
case 'r': /* rotate (swap) the top two elements on the stack */
|
|
Packit |
70b277 |
dc_stack_rotate(2);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 's': /* "store" -- replace top of register stack named
|
|
Packit |
70b277 |
* by peekc with the value popped from the top
|
|
Packit |
70b277 |
* of the evaluation stack
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_register_set(peekc, datum);
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case 'v': /* replace top of stack with its square root */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
dc_num tmpnum;
|
|
Packit |
70b277 |
if (datum.dc_type != DC_NUMBER){
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: square root of nonnumeric attempted\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
}else if (dc_sqrt(datum.v.number, dc_scale, &tmpnum) == DC_SUCCESS){
|
|
Packit |
70b277 |
dc_free_num(&datum.v.number);
|
|
Packit |
70b277 |
datum.v.number = tmpnum;
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'x': /* eval the datum popped from top of stack */
|
|
Packit |
70b277 |
return DC_EVALTOS;
|
|
Packit |
70b277 |
case 'z': /* push the current stack depth onto the top of stack */
|
|
Packit |
70b277 |
dc_push(dc_int2data(dc_tell_stackdepth()));
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case 'I': /* push the current input base onto the stack */
|
|
Packit |
70b277 |
dc_push(dc_int2data(dc_ibase));
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'K': /* push the current scale onto the stack */
|
|
Packit |
70b277 |
dc_push(dc_int2data(dc_scale));
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'L': /* pop a value off of register stack named by peekc
|
|
Packit |
70b277 |
* and push it onto the evaluation stack
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if (dc_register_pop(peekc, &datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case 'O': /* push the current output base onto the stack */
|
|
Packit |
70b277 |
dc_push(dc_int2data(dc_obase));
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'P':
|
|
Packit |
70b277 |
/* Pop the value off the top of a stack. If it is
|
|
Packit |
70b277 |
* a number, dump out the integer portion of its
|
|
Packit |
70b277 |
* absolute value as a "base UCHAR_MAX+1" byte stream;
|
|
Packit |
70b277 |
* if it is a string, just print it.
|
|
Packit |
70b277 |
* In either case, do not append a trailing newline.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
dc_dump_num(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
else if (datum.dc_type == DC_STRING)
|
|
Packit |
70b277 |
dc_out_str(datum.v.string, DC_TOSS);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
dc_garbage("at top of stack", -1);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
fflush(stdout);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'Q': /* quit out of top-of-stack nested evals;
|
|
Packit |
70b277 |
* pops value from stack;
|
|
Packit |
70b277 |
* does not exit program (stops short if necessary)
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
unwind_depth = 0;
|
|
Packit |
70b277 |
unwind_noexit = DC_TRUE;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
unwind_depth = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
if (unwind_depth-- > 0)
|
|
Packit |
70b277 |
return DC_QUIT;
|
|
Packit |
70b277 |
unwind_depth = 0; /* paranoia */
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: Q command requires a number >= 1\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'R': /* pop a value off of the evaluation stack,;
|
|
Packit |
70b277 |
* rotate the top remaining stack elements that many
|
|
Packit |
70b277 |
* places forward (negative numbers mean rotate
|
|
Packit |
70b277 |
* backward).
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = 0;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
dc_stack_rotate(tmpint);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'S': /* pop a value off of the evaluation stack
|
|
Packit |
70b277 |
* and push it onto the register stack named by peekc
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_register_push(peekc, datum);
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case 'X': /* replace the number on top-of-stack with its scale factor */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = 0;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_tell_scale(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
dc_push(dc_int2data(tmpint));
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case 'Z': /* replace the datum on the top-of-stack with its length */
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS)
|
|
Packit |
70b277 |
dc_push(dc_int2data(dc_tell_length(datum, DC_TOSS)));
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case ':': /* store into array */
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = -1;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
if (tmpint < 0)
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: array index must be a nonnegative integer\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
dc_array_set(peekc, tmpint, datum);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
case ';': /* retreive from array */
|
|
Packit |
70b277 |
if (peekc == EOF)
|
|
Packit |
70b277 |
return DC_EOF_ERROR;
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
tmpint = -1;
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER)
|
|
Packit |
70b277 |
tmpint = dc_num2int(datum.v.number, DC_TOSS);
|
|
Packit |
70b277 |
if (tmpint < 0)
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: array index must be a nonnegative integer\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
else
|
|
Packit |
70b277 |
dc_push(dc_array_get(peekc, tmpint));
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
return DC_EATONE;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
default: /* What did that user mean? */
|
|
Packit |
70b277 |
fprintf(stderr, "%s: ", progname);
|
|
Packit |
70b277 |
dc_show_id(stdout, c, " unimplemented\n");
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
return DC_OKAY;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* takes a string and evals it */
|
|
Packit |
70b277 |
static int
|
|
Packit |
70b277 |
evalstr DC_DECLARG((string))
|
|
Packit |
70b277 |
dc_data *string DC_DECLEND
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
const char *s;
|
|
Packit |
70b277 |
const char *end;
|
|
Packit |
70b277 |
const char *p;
|
|
Packit |
70b277 |
size_t len;
|
|
Packit |
70b277 |
int c;
|
|
Packit |
70b277 |
int peekc;
|
|
Packit |
70b277 |
int count;
|
|
Packit |
70b277 |
int negcmp;
|
|
Packit |
70b277 |
int next_negcmp = 0;
|
|
Packit |
70b277 |
int tail_depth = 1; /* how much tail recursion is active */
|
|
Packit |
70b277 |
dc_data evalstr;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
if (string->dc_type != DC_STRING){
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: eval called with non-string argument\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
return DC_OKAY;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
interrupt_seen = 0;
|
|
Packit |
70b277 |
s = dc_str2charp(string->v.string);
|
|
Packit |
70b277 |
end = s + dc_strlen(string->v.string);
|
|
Packit |
70b277 |
while (s < end && interrupt_seen==0){
|
|
Packit |
70b277 |
c = *(const unsigned char *)s++;
|
|
Packit |
70b277 |
peekc = EOF;
|
|
Packit |
70b277 |
if (s < end)
|
|
Packit |
70b277 |
peekc = *(const unsigned char *)s;
|
|
Packit |
70b277 |
negcmp = next_negcmp;
|
|
Packit |
70b277 |
next_negcmp = 0;
|
|
Packit |
70b277 |
switch (dc_func(c, peekc, negcmp)){
|
|
Packit |
70b277 |
case DC_OKAY:
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_EATONE:
|
|
Packit |
70b277 |
if (peekc != EOF)
|
|
Packit |
70b277 |
++s;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_EVALREG:
|
|
Packit |
70b277 |
/*commands which return this guarantee that peekc!=EOF*/
|
|
Packit |
70b277 |
++s;
|
|
Packit |
70b277 |
if (dc_register_get(peekc, &evalstr) != DC_SUCCESS)
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
dc_push(evalstr);
|
|
Packit |
70b277 |
/*@fallthrough@*/
|
|
Packit |
70b277 |
case DC_EVALTOS:
|
|
Packit |
70b277 |
/*skip trailing whitespace to assist tail-recursion detection*/
|
|
Packit |
70b277 |
while (s
|
|
Packit |
70b277 |
if (*s++ == '#')
|
|
Packit |
70b277 |
s = skip_past_eol(s, end);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
if (dc_pop(&evalstr) == DC_SUCCESS){
|
|
Packit |
70b277 |
if (evalstr.dc_type == DC_NUMBER){
|
|
Packit |
70b277 |
dc_push(evalstr);
|
|
Packit |
70b277 |
}else if (evalstr.dc_type != DC_STRING){
|
|
Packit |
70b277 |
dc_garbage("at top of stack", -1);
|
|
Packit |
70b277 |
}else if (s == end){
|
|
Packit |
70b277 |
/*handle tail recursion*/
|
|
Packit |
70b277 |
dc_free_str(&string->v.string);
|
|
Packit |
70b277 |
*string = evalstr;
|
|
Packit |
70b277 |
s = dc_str2charp(string->v.string);
|
|
Packit |
70b277 |
end = s + dc_strlen(string->v.string);
|
|
Packit |
70b277 |
++tail_depth;
|
|
Packit |
70b277 |
}else if (dc_eval_and_free_str(&evalstr) == DC_QUIT){
|
|
Packit |
70b277 |
if (unwind_depth > 0){
|
|
Packit |
70b277 |
--unwind_depth;
|
|
Packit |
70b277 |
return DC_QUIT;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
return DC_OKAY;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_QUIT:
|
|
Packit |
70b277 |
if (unwind_depth >= tail_depth){
|
|
Packit |
70b277 |
unwind_depth -= tail_depth;
|
|
Packit |
70b277 |
return DC_QUIT;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
/*adjust tail recursion accounting and continue*/
|
|
Packit |
70b277 |
tail_depth -= unwind_depth;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case DC_INT:
|
|
Packit |
70b277 |
input_str_string = s - 1;
|
|
Packit |
70b277 |
dc_push(dc_getnum(input_str, dc_ibase, &peekc));
|
|
Packit |
70b277 |
s = input_str_string;
|
|
Packit |
70b277 |
if (peekc != EOF)
|
|
Packit |
70b277 |
--s;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_STR:
|
|
Packit |
70b277 |
count = 1;
|
|
Packit |
70b277 |
for (p=s; p<end && count>0; ++p)
|
|
Packit |
70b277 |
if (*p == ']')
|
|
Packit |
70b277 |
--count;
|
|
Packit |
70b277 |
else if (*p == '[')
|
|
Packit |
70b277 |
++count;
|
|
Packit |
70b277 |
len = (size_t) (p - s);
|
|
Packit |
70b277 |
dc_push(dc_makestring(s, (count==0 ? len-1 : len)));
|
|
Packit |
70b277 |
s = p;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_SYSTEM:
|
|
Packit |
70b277 |
s = dc_system(s);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_COMMENT:
|
|
Packit |
70b277 |
s = skip_past_eol(s, end);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_NEGCMP:
|
|
Packit |
70b277 |
next_negcmp = 1;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case DC_EOF_ERROR:
|
|
Packit |
70b277 |
if (ferror(stdin)) {
|
|
Packit |
70b277 |
fprintf(stderr, "%s: ", progname);
|
|
Packit |
70b277 |
perror("error reading stdin");
|
|
Packit |
70b277 |
return DC_FAIL;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
fprintf(stderr, "%s: unexpected EOS\n", progname);
|
|
Packit |
70b277 |
return DC_OKAY;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
return DC_OKAY;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* wrapper around evalstr, to handle top-level QUIT requests correctly*/
|
|
Packit |
70b277 |
int
|
|
Packit |
70b277 |
dc_evalstr(dc_data *string)
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
switch (evalstr(string)) {
|
|
Packit |
70b277 |
case DC_OKAY:
|
|
Packit |
70b277 |
return DC_SUCCESS;
|
|
Packit |
70b277 |
case DC_QUIT:
|
|
Packit |
70b277 |
if (unwind_noexit != DC_TRUE)
|
|
Packit |
70b277 |
return DC_FAIL;
|
|
Packit |
70b277 |
return DC_SUCCESS;
|
|
Packit |
70b277 |
default:
|
|
Packit |
70b277 |
return DC_FAIL;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* This is the main function of the whole DC program.
|
|
Packit |
70b277 |
* Reads the file described by fp, calls dc_func to do
|
|
Packit |
70b277 |
* the dirty work, and takes care of dc_func's shortcomings.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
int
|
|
Packit |
70b277 |
dc_evalfile DC_DECLARG((fp))
|
|
Packit |
70b277 |
FILE *fp DC_DECLEND
|
|
Packit |
70b277 |
{
|
|
Packit |
70b277 |
int c;
|
|
Packit |
70b277 |
int peekc;
|
|
Packit |
70b277 |
int negcmp;
|
|
Packit |
70b277 |
int next_negcmp = 0;
|
|
Packit |
70b277 |
typedef void (*handler_t)(int);
|
|
Packit |
70b277 |
handler_t sigint_handler = dc_trap_interrupt;
|
|
Packit |
70b277 |
handler_t sigint_default = signal(SIGINT, SIG_IGN);
|
|
Packit |
70b277 |
dc_data datum;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/* Signals are awkward: we want to allow interactive users
|
|
Packit |
70b277 |
* to break out of long running macros, but otherwise we
|
|
Packit |
70b277 |
* prefer that SIGINT not be given any special treatment.
|
|
Packit |
70b277 |
* Sometimes "no special treatment" means to continue to
|
|
Packit |
70b277 |
* *ignore* the signal, but usually it means to kill the program.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
signal(SIGINT, sigint_default);
|
|
Packit |
70b277 |
#ifdef HAVE_UNISTD_H
|
|
Packit |
70b277 |
/* don't trap SIGINT if we can tell that we are not reading from a tty */
|
|
Packit |
70b277 |
if ( ! isatty(fileno(fp)) )
|
|
Packit |
70b277 |
sigint_handler = sigint_default;
|
|
Packit |
70b277 |
#endif
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
stdin_lookahead = EOF;
|
|
Packit |
70b277 |
for (c=getc(fp); c!=EOF; c=peekc){
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
/*
|
|
Packit |
70b277 |
* The following if() is the only place where ``stdin_lookahead''
|
|
Packit |
70b277 |
* might be set to other than EOF:
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
if (fp == stdin)
|
|
Packit |
70b277 |
stdin_lookahead = peekc;
|
|
Packit |
70b277 |
/*
|
|
Packit |
70b277 |
* In the switch(), cases which naturally update peekc
|
|
Packit |
70b277 |
* (unconditionally) do not have to update or reference
|
|
Packit |
70b277 |
* stdin_lookahead; other functions use the predicate:
|
|
Packit |
70b277 |
* stdin_lookahead != peekc && fp == stdin
|
|
Packit |
70b277 |
* to recognize the case where:
|
|
Packit |
70b277 |
* a) stdin_lookahead == EOF (stdin and peekc are not in sync)
|
|
Packit |
70b277 |
* b) peekc != EOF (resync is possible)
|
|
Packit |
70b277 |
* c) fp == stdin (resync is relevant)
|
|
Packit |
70b277 |
* The whole stdin_lookahead complication arises because the
|
|
Packit |
70b277 |
* '?' command may be invoked from an arbritrarily deeply
|
|
Packit |
70b277 |
* nested dc_evalstr(), '?' reads exclusively from stdin,
|
|
Packit |
70b277 |
* and this winds up making peekc invalid when fp==stdin.
|
|
Packit |
70b277 |
*/
|
|
Packit |
70b277 |
negcmp = next_negcmp;
|
|
Packit |
70b277 |
next_negcmp = 0;
|
|
Packit |
70b277 |
signal(SIGINT, sigint_handler);
|
|
Packit |
70b277 |
switch (dc_func(c, peekc, negcmp)){
|
|
Packit |
70b277 |
case DC_OKAY:
|
|
Packit |
70b277 |
if (stdin_lookahead != peekc && fp == stdin)
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_EATONE:
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_EVALREG:
|
|
Packit |
70b277 |
/*commands which send us here shall guarantee that peekc!=EOF*/
|
|
Packit |
70b277 |
c = peekc;
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
stdin_lookahead = peekc;
|
|
Packit |
70b277 |
if (dc_register_get(c, &datum) != DC_SUCCESS)
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
/*@fallthrough@*/
|
|
Packit |
70b277 |
case DC_EVALTOS:
|
|
Packit |
70b277 |
if (stdin_lookahead != peekc && fp == stdin)
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
if (dc_pop(&datum) == DC_SUCCESS){
|
|
Packit |
70b277 |
if (datum.dc_type == DC_NUMBER){
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
}else if (datum.dc_type == DC_STRING){
|
|
Packit |
70b277 |
if (dc_eval_and_free_str(&datum) == DC_QUIT){
|
|
Packit |
70b277 |
if (unwind_noexit != DC_TRUE)
|
|
Packit |
70b277 |
goto reset_and_exit_quit;
|
|
Packit |
70b277 |
fprintf(stderr, "%s: Q command argument exceeded \
|
|
Packit |
70b277 |
string execution depth\n", progname);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}else{
|
|
Packit |
70b277 |
dc_garbage("at top of stack", -1);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_QUIT:
|
|
Packit |
70b277 |
if (unwind_noexit != DC_TRUE)
|
|
Packit |
70b277 |
goto reset_and_exit_quit;
|
|
Packit |
70b277 |
fprintf(stderr,
|
|
Packit |
70b277 |
"%s: Q command argument exceeded string execution depth\n",
|
|
Packit |
70b277 |
progname);
|
|
Packit |
70b277 |
if (stdin_lookahead != peekc && fp == stdin)
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case DC_INT:
|
|
Packit |
70b277 |
input_fil_fp = fp;
|
|
Packit |
70b277 |
input_pushback = c;
|
|
Packit |
70b277 |
ungetc(peekc, fp);
|
|
Packit |
70b277 |
dc_push(dc_getnum(input_fil, dc_ibase, &peekc));
|
|
Packit |
70b277 |
if (ferror(fp))
|
|
Packit |
70b277 |
goto error_fail;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_STR:
|
|
Packit |
70b277 |
ungetc(peekc, fp);
|
|
Packit |
70b277 |
datum = dc_readstring(fp, '[', ']');
|
|
Packit |
70b277 |
if (ferror(fp))
|
|
Packit |
70b277 |
goto error_fail;
|
|
Packit |
70b277 |
dc_push(datum);
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_SYSTEM:
|
|
Packit |
70b277 |
ungetc(peekc, fp);
|
|
Packit |
70b277 |
datum = dc_readstring(fp, '\n', '\n');
|
|
Packit |
70b277 |
if (ferror(fp))
|
|
Packit |
70b277 |
goto error_fail;
|
|
Packit |
70b277 |
(void)dc_system(dc_str2charp(datum.v.string));
|
|
Packit |
70b277 |
dc_free_str(&datum.v.string);
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_COMMENT:
|
|
Packit |
70b277 |
while (peekc!=EOF && peekc!='\n')
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
if (peekc != EOF)
|
|
Packit |
70b277 |
peekc = getc(fp);
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
case DC_NEGCMP:
|
|
Packit |
70b277 |
next_negcmp = 1;
|
|
Packit |
70b277 |
break;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
case DC_EOF_ERROR:
|
|
Packit |
70b277 |
if (ferror(fp))
|
|
Packit |
70b277 |
goto error_fail;
|
|
Packit |
70b277 |
fprintf(stderr, "%s: unexpected EOF\n", progname);
|
|
Packit |
70b277 |
goto reset_and_exit_fail;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
if (interrupt_seen)
|
|
Packit |
70b277 |
fprintf(stderr, "\nInterrupt!\n");
|
|
Packit |
70b277 |
interrupt_seen = 0;
|
|
Packit |
70b277 |
signal(SIGINT, sigint_default);
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
if (!ferror(fp))
|
|
Packit |
70b277 |
goto reset_and_exit_success;
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
error_fail:
|
|
Packit |
70b277 |
fprintf(stderr, "%s: ", progname);
|
|
Packit |
70b277 |
perror("error reading input");
|
|
Packit |
70b277 |
return DC_FAIL;
|
|
Packit |
70b277 |
reset_and_exit_quit:
|
|
Packit |
70b277 |
reset_and_exit_fail:
|
|
Packit |
70b277 |
signal(SIGINT, sigint_default);
|
|
Packit |
70b277 |
return DC_FAIL;
|
|
Packit |
70b277 |
reset_and_exit_success:
|
|
Packit |
70b277 |
signal(SIGINT, sigint_default);
|
|
Packit |
70b277 |
return DC_SUCCESS;
|
|
Packit |
70b277 |
}
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
|
|
Packit |
70b277 |
/*
|
|
Packit |
70b277 |
* Local Variables:
|
|
Packit |
70b277 |
* mode: C
|
|
Packit |
70b277 |
* tab-width: 4
|
|
Packit |
70b277 |
* End:
|
|
Packit |
70b277 |
* vi: set ts=4 :
|
|
Packit |
70b277 |
*/
|