This incorporates Posix math support into ash. The Posix math support
was written by Aaron Lehmann <aaronl@vitelus.com> for busybox. This patch makes a few trivial changes to Aaron's code so that it can be used (in theory) by the other shells as well... -Erik
This commit is contained in:
parent
dc6647201d
commit
74bcd16425
2
Makefile
2
Makefile
@ -247,7 +247,7 @@ safe_read.c safe_strncpy.c syscalls.c syslog_msg_with_name.c time_string.c \
|
||||
trim.c unzip.c vdprintf.c verror_msg.c vperror_msg.c wfopen.c xfuncs.c \
|
||||
xgetcwd.c xreadlink.c xregcomp.c interface.c remove_file.c last_char_is.c \
|
||||
copyfd.c vherror_msg.c herror_msg.c herror_msg_and_die.c xgethostbyname.c \
|
||||
dirname.c make_directory.c create_icmp_socket.c
|
||||
dirname.c make_directory.c create_icmp_socket.c arith.c
|
||||
LIBBB_OBJS=$(patsubst %.c,$(LIBBB)/%.o, $(LIBBB_CSRC))
|
||||
LIBBB_CFLAGS = -I$(LIBBB)
|
||||
ifneq ($(strip $(BB_SRC_DIR)),)
|
||||
|
105
ash.c
105
ash.c
@ -51,9 +51,8 @@
|
||||
#define ASH_ALIAS
|
||||
|
||||
/* If you need ash to act as a full Posix shell, with full math
|
||||
* support, enable this. This option needs some work, since it
|
||||
* doesn't compile right now... */
|
||||
#undef ASH_MATH_SUPPORT
|
||||
* support, enable this. This adds a bit over 2k an x86 system. */
|
||||
#define ASH_MATH_SUPPORT
|
||||
|
||||
/* Getopts is used by shell procedures to parse positional parameters.
|
||||
* You probably want to leave this disabled, and use the busybox getopt
|
||||
@ -80,6 +79,7 @@
|
||||
#undef FNMATCH_BROKEN
|
||||
#undef GLOB_BROKEN
|
||||
#undef _GNU_SOURCE
|
||||
#undef __USE_GNU
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
@ -1562,8 +1562,10 @@ __lookupalias(const char *name) {
|
||||
#endif
|
||||
|
||||
#ifdef ASH_MATH_SUPPORT
|
||||
/* The generated file arith.c has been snipped. If you want this
|
||||
* stuff back in, feel free to add it to your own copy. */
|
||||
/* The generated file arith.c has been replaced with a custom hand
|
||||
* written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
|
||||
* This is now part of libbb, so that it can be used by all the shells
|
||||
* in busybox. */
|
||||
#define ARITH_NUM 257
|
||||
#define ARITH_LPAREN 258
|
||||
#define ARITH_RPAREN 259
|
||||
@ -1592,11 +1594,8 @@ __lookupalias(const char *name) {
|
||||
|
||||
static void expari (int);
|
||||
/* From arith.y */
|
||||
static int arith (const char *);
|
||||
static long ash_arith(const char *p);
|
||||
static int expcmd (int , char **);
|
||||
static void arith_lex_reset (void);
|
||||
static int yylex (void);
|
||||
|
||||
#endif
|
||||
|
||||
static char *trap[NSIG]; /* trap handler commands */
|
||||
@ -2173,52 +2172,22 @@ exverror(int cond, const char *msg, va_list ap)
|
||||
}
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
static void
|
||||
static void
|
||||
error(const char *msg, ...)
|
||||
#else
|
||||
static void
|
||||
error(va_alist)
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef __STDC__
|
||||
const char *msg;
|
||||
#endif
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, msg);
|
||||
#else
|
||||
va_start(ap);
|
||||
msg = va_arg(ap, const char *);
|
||||
#endif
|
||||
exverror(EXERROR, msg, ap);
|
||||
/* NOTREACHED */
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
static void
|
||||
exerror(int cond, const char *msg, ...)
|
||||
#else
|
||||
static void
|
||||
exerror(va_alist)
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef __STDC__
|
||||
int cond;
|
||||
const char *msg;
|
||||
#endif
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, msg);
|
||||
#else
|
||||
va_start(ap);
|
||||
cond = va_arg(ap, int);
|
||||
msg = va_arg(ap, const char *);
|
||||
#endif
|
||||
exverror(cond, msg, ap);
|
||||
/* NOTREACHED */
|
||||
va_end(ap);
|
||||
@ -4914,7 +4883,7 @@ expari(int flag)
|
||||
removerecordregions(begoff);
|
||||
if (quotes)
|
||||
rmescapes(p+2);
|
||||
result = arith(p+2);
|
||||
result = ash_arith(p+2);
|
||||
snprintf(p, 12, "%d", result);
|
||||
|
||||
while (*p++)
|
||||
@ -11952,13 +11921,7 @@ static void
|
||||
trace(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
#ifdef __STDC__
|
||||
va_start(va, fmt);
|
||||
#else
|
||||
char *fmt;
|
||||
va_start(va);
|
||||
fmt = va_arg(va, char *);
|
||||
#endif
|
||||
if (tracefile != NULL) {
|
||||
(void) vfprintf(tracefile, fmt, va);
|
||||
if (strchr(fmt, '\n'))
|
||||
@ -12657,7 +12620,6 @@ found:;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The "local" command.
|
||||
*/
|
||||
@ -12916,7 +12878,7 @@ findvar(struct var **vpp, const char *name)
|
||||
/*
|
||||
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
|
||||
* This file contains code for the times builtin.
|
||||
* $Id: ash.c,v 1.13 2001/07/26 05:58:40 russ Exp $
|
||||
* $Id: ash.c,v 1.14 2001/07/30 21:41:37 andersen Exp $
|
||||
*/
|
||||
static int timescmd (int argc, char **argv)
|
||||
{
|
||||
@ -12937,6 +12899,51 @@ static int timescmd (int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
#ifdef ASH_MATH_SUPPORT
|
||||
/* The exp(1) builtin. */
|
||||
int expcmd(int argc, char **argv)
|
||||
{
|
||||
const char *p;
|
||||
char *concat;
|
||||
char **ap;
|
||||
long i;
|
||||
|
||||
if (argc > 1) {
|
||||
p = argv[1];
|
||||
if (argc > 2) {
|
||||
/* concatenate arguments */
|
||||
STARTSTACKSTR(concat);
|
||||
ap = argv + 2;
|
||||
for (;;) {
|
||||
while (*p)
|
||||
STPUTC(*p++, concat);
|
||||
if ((p = *ap++) == NULL)
|
||||
break;
|
||||
STPUTC(' ', concat);
|
||||
}
|
||||
STPUTC('\0', concat);
|
||||
p = grabstackstr(concat);
|
||||
}
|
||||
} else
|
||||
p = "";
|
||||
|
||||
i = ash_arith(p);
|
||||
|
||||
printf("%ld\n", i);
|
||||
return (! i);
|
||||
}
|
||||
|
||||
static long ash_arith(const char *p)
|
||||
{
|
||||
long i = arith(p);
|
||||
if (i <0)
|
||||
error("arith: syntax error: \"%s\"\n", p);
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1989, 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
@ -212,6 +212,8 @@ char *xreadlink(const char *path);
|
||||
char *concat_path_file(const char *path, const char *filename);
|
||||
char *last_char_is(const char *s, int c);
|
||||
|
||||
extern long arith (const char *startbuf);
|
||||
|
||||
typedef struct file_headers_s {
|
||||
char *name;
|
||||
char *link_name;
|
||||
|
250
libbb/arith.c
Normal file
250
libbb/arith.c
Normal file
@ -0,0 +1,250 @@
|
||||
/* Copyright (c) 2001 Aaron Lehmann <aaronl@vitelus.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* This is my infix parser/evaluator. It is optimized for size, intended
|
||||
* as a replacement for yacc-based parsers. However, it may well be faster
|
||||
* than a comparable parser writen in yacc. The supported operators are
|
||||
* listed in #defines below. Parens, order of operations, and error handling
|
||||
* are supported. This code is threadsafe. */
|
||||
|
||||
/* To use the routine, call it with an expression string. It returns an
|
||||
* integer result. You will also need to define an "error" function
|
||||
* that takes printf arguments and _does not return_, or modify the code
|
||||
* to use another error mechanism. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "libbb.h"
|
||||
|
||||
typedef char operator;
|
||||
|
||||
#define tok_decl(prec,id) (((id)<<5)|(prec))
|
||||
#define PREC(op) ((op)&0x1F)
|
||||
|
||||
#define TOK_LPAREN tok_decl(0,0)
|
||||
|
||||
#define TOK_OR tok_decl(1,0)
|
||||
|
||||
#define TOK_AND tok_decl(2,0)
|
||||
|
||||
#define TOK_BOR tok_decl(3,0)
|
||||
|
||||
#define TOK_BXOR tok_decl(4,0)
|
||||
|
||||
#define TOK_BAND tok_decl(5,0)
|
||||
|
||||
#define TOK_EQ tok_decl(6,0)
|
||||
#define TOK_NE tok_decl(6,1)
|
||||
|
||||
#define TOK_LT tok_decl(7,0)
|
||||
#define TOK_GT tok_decl(7,1)
|
||||
#define TOK_GE tok_decl(7,2)
|
||||
#define TOK_LE tok_decl(7,3)
|
||||
|
||||
#define TOK_LSHIFT tok_decl(8,0)
|
||||
#define TOK_RSHIFT tok_decl(8,1)
|
||||
|
||||
#define TOK_ADD tok_decl(9,0)
|
||||
#define TOK_SUB tok_decl(9,1)
|
||||
|
||||
#define TOK_MUL tok_decl(10,0)
|
||||
#define TOK_DIV tok_decl(10,1)
|
||||
#define TOK_REM tok_decl(10,2)
|
||||
|
||||
#define UNARYPREC 14
|
||||
#define TOK_BNOT tok_decl(UNARYPREC,0)
|
||||
#define TOK_NOT tok_decl(UNARYPREC,1)
|
||||
#define TOK_UMINUS tok_decl(UNARYPREC,2)
|
||||
|
||||
#define TOK_NUM tok_decl(15,0)
|
||||
|
||||
#define ARITH_APPLY(op) arith_apply(op, numstack, &numstackptr)
|
||||
#define NUMPTR (*numstackptr)
|
||||
static short arith_apply(operator op, long *numstack, long **numstackptr)
|
||||
{
|
||||
if (NUMPTR == numstack) goto err;
|
||||
if (op == TOK_UMINUS)
|
||||
NUMPTR[-1] *= -1;
|
||||
else if (op == TOK_NOT)
|
||||
NUMPTR[-1] = !(NUMPTR[-1]);
|
||||
else if (op == TOK_BNOT)
|
||||
NUMPTR[-1] = ~(NUMPTR[-1]);
|
||||
|
||||
/* Binary operators */
|
||||
else {
|
||||
if (NUMPTR-1 == numstack) goto err;
|
||||
--NUMPTR;
|
||||
if (op == TOK_BOR)
|
||||
NUMPTR[-1] |= *NUMPTR;
|
||||
else if (op == TOK_OR)
|
||||
NUMPTR[-1] = *NUMPTR || NUMPTR[-1];
|
||||
else if (op == TOK_BAND)
|
||||
NUMPTR[-1] &= *NUMPTR;
|
||||
else if (op == TOK_AND)
|
||||
NUMPTR[-1] = NUMPTR[-1] && *NUMPTR;
|
||||
else if (op == TOK_EQ)
|
||||
NUMPTR[-1] = (NUMPTR[-1] == *NUMPTR);
|
||||
else if (op == TOK_NE)
|
||||
NUMPTR[-1] = (NUMPTR[-1] != *NUMPTR);
|
||||
else if (op == TOK_GE)
|
||||
NUMPTR[-1] = (NUMPTR[-1] >= *NUMPTR);
|
||||
else if (op == TOK_RSHIFT)
|
||||
NUMPTR[-1] >>= *NUMPTR;
|
||||
else if (op == TOK_LSHIFT)
|
||||
NUMPTR[-1] <<= *NUMPTR;
|
||||
else if (op == TOK_GT)
|
||||
NUMPTR[-1] = (NUMPTR[-1] > *NUMPTR);
|
||||
else if (op == TOK_LT)
|
||||
NUMPTR[-1] = (NUMPTR[-1] < *NUMPTR);
|
||||
else if (op == TOK_LE)
|
||||
NUMPTR[-1] = (NUMPTR[-1] <= *NUMPTR);
|
||||
else if (op == TOK_MUL)
|
||||
NUMPTR[-1] *= *NUMPTR;
|
||||
else if (op == TOK_DIV)
|
||||
NUMPTR[-1] /= *NUMPTR;
|
||||
else if (op == TOK_REM)
|
||||
NUMPTR[-1] %= *NUMPTR;
|
||||
else if (op == TOK_ADD)
|
||||
NUMPTR[-1] += *NUMPTR;
|
||||
else if (op == TOK_SUB)
|
||||
NUMPTR[-1] -= *NUMPTR;
|
||||
}
|
||||
return 0;
|
||||
err: return(1);
|
||||
}
|
||||
|
||||
extern long arith (const char *startbuf)
|
||||
{
|
||||
register char arithval;
|
||||
const char *expr = startbuf;
|
||||
|
||||
operator lasttok = TOK_MUL, op;
|
||||
size_t datasizes = strlen(startbuf);
|
||||
unsigned char prec;
|
||||
|
||||
long *numstack, *numstackptr;
|
||||
|
||||
operator *stack = alloca(datasizes * sizeof(operator)), *stackptr = stack;
|
||||
numstack = alloca((datasizes/2+1)*sizeof(long)), numstackptr = numstack;
|
||||
|
||||
while ((arithval = *expr)) {
|
||||
if (arithval == ' ' || arithval == '\n' || arithval == '\t')
|
||||
goto prologue;
|
||||
if ((unsigned)arithval-'0' <= 9) /* isdigit */ {
|
||||
*numstackptr++ = strtol(expr, (char **) &expr, 10);
|
||||
lasttok = TOK_NUM;
|
||||
continue;
|
||||
} if (arithval == '(') {
|
||||
*stackptr++ = TOK_LPAREN;
|
||||
lasttok = TOK_LPAREN;
|
||||
goto prologue;
|
||||
} if (arithval == ')') {
|
||||
lasttok = TOK_NUM;
|
||||
while (stackptr != stack) {
|
||||
op = *--stackptr;
|
||||
if (op == TOK_LPAREN)
|
||||
goto prologue;
|
||||
if(ARITH_APPLY(op)) goto err;
|
||||
}
|
||||
goto err; /* Mismatched parens */
|
||||
} if (arithval == '|') {
|
||||
if (*++expr == '|')
|
||||
op = TOK_OR;
|
||||
else {
|
||||
--expr;
|
||||
op = TOK_BOR;
|
||||
}
|
||||
} else if (arithval == '&') {
|
||||
if (*++expr == '&')
|
||||
op = TOK_AND;
|
||||
else {
|
||||
--expr;
|
||||
op = TOK_BAND;
|
||||
}
|
||||
} else if (arithval == '=') {
|
||||
if (*++expr != '=') goto err; /* Unknown token */
|
||||
op = TOK_EQ;
|
||||
} else if (arithval == '!') {
|
||||
if (*++expr == '=')
|
||||
op = TOK_NE;
|
||||
else {
|
||||
--expr;
|
||||
op = TOK_NOT;
|
||||
}
|
||||
} else if (arithval == '>') {
|
||||
switch (*++expr) {
|
||||
case '=':
|
||||
op = TOK_GE;
|
||||
break;
|
||||
case '>':
|
||||
op = TOK_RSHIFT;
|
||||
break;
|
||||
default:
|
||||
--expr;
|
||||
op = TOK_GT;
|
||||
}
|
||||
} else if (arithval == '<') {
|
||||
switch (*++expr) {
|
||||
case '=':
|
||||
op = TOK_LE;
|
||||
break;
|
||||
case '<':
|
||||
op = TOK_LSHIFT;
|
||||
break;
|
||||
default:
|
||||
--expr;
|
||||
op = TOK_LT;
|
||||
}
|
||||
} else if (arithval == '*')
|
||||
op = TOK_MUL;
|
||||
else if (arithval == '/')
|
||||
op = TOK_DIV;
|
||||
else if (arithval == '%')
|
||||
op = TOK_REM;
|
||||
else if (arithval == '+') {
|
||||
if (lasttok != TOK_NUM) goto prologue; /* Unary plus */
|
||||
op = TOK_ADD;
|
||||
} else if (arithval == '-')
|
||||
op = (lasttok == TOK_NUM) ? TOK_SUB : TOK_UMINUS;
|
||||
else if (arithval == '~')
|
||||
op = TOK_BNOT;
|
||||
else goto err; /* Unknown token */
|
||||
|
||||
prec = PREC(op);
|
||||
if (prec != UNARYPREC)
|
||||
while (stackptr != stack && PREC(stackptr[-1]) >= prec)
|
||||
if(ARITH_APPLY(*--stackptr)) goto err;
|
||||
*stackptr++ = op;
|
||||
lasttok = op;
|
||||
prologue: ++expr;
|
||||
} /* yay */
|
||||
|
||||
while (stackptr != stack)
|
||||
if(ARITH_APPLY(*--stackptr)) goto err;
|
||||
if (numstackptr != numstack+1) {
|
||||
err:
|
||||
return -1;
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
return *numstack;
|
||||
}
|
@ -212,6 +212,8 @@ char *xreadlink(const char *path);
|
||||
char *concat_path_file(const char *path, const char *filename);
|
||||
char *last_char_is(const char *s, int c);
|
||||
|
||||
extern long arith (const char *startbuf);
|
||||
|
||||
typedef struct file_headers_s {
|
||||
char *name;
|
||||
char *link_name;
|
||||
|
105
shell/ash.c
105
shell/ash.c
@ -51,9 +51,8 @@
|
||||
#define ASH_ALIAS
|
||||
|
||||
/* If you need ash to act as a full Posix shell, with full math
|
||||
* support, enable this. This option needs some work, since it
|
||||
* doesn't compile right now... */
|
||||
#undef ASH_MATH_SUPPORT
|
||||
* support, enable this. This adds a bit over 2k an x86 system. */
|
||||
#define ASH_MATH_SUPPORT
|
||||
|
||||
/* Getopts is used by shell procedures to parse positional parameters.
|
||||
* You probably want to leave this disabled, and use the busybox getopt
|
||||
@ -80,6 +79,7 @@
|
||||
#undef FNMATCH_BROKEN
|
||||
#undef GLOB_BROKEN
|
||||
#undef _GNU_SOURCE
|
||||
#undef __USE_GNU
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
@ -1562,8 +1562,10 @@ __lookupalias(const char *name) {
|
||||
#endif
|
||||
|
||||
#ifdef ASH_MATH_SUPPORT
|
||||
/* The generated file arith.c has been snipped. If you want this
|
||||
* stuff back in, feel free to add it to your own copy. */
|
||||
/* The generated file arith.c has been replaced with a custom hand
|
||||
* written implementation written by Aaron Lehmann <aaronl@vitelus.com>.
|
||||
* This is now part of libbb, so that it can be used by all the shells
|
||||
* in busybox. */
|
||||
#define ARITH_NUM 257
|
||||
#define ARITH_LPAREN 258
|
||||
#define ARITH_RPAREN 259
|
||||
@ -1592,11 +1594,8 @@ __lookupalias(const char *name) {
|
||||
|
||||
static void expari (int);
|
||||
/* From arith.y */
|
||||
static int arith (const char *);
|
||||
static long ash_arith(const char *p);
|
||||
static int expcmd (int , char **);
|
||||
static void arith_lex_reset (void);
|
||||
static int yylex (void);
|
||||
|
||||
#endif
|
||||
|
||||
static char *trap[NSIG]; /* trap handler commands */
|
||||
@ -2173,52 +2172,22 @@ exverror(int cond, const char *msg, va_list ap)
|
||||
}
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
static void
|
||||
static void
|
||||
error(const char *msg, ...)
|
||||
#else
|
||||
static void
|
||||
error(va_alist)
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef __STDC__
|
||||
const char *msg;
|
||||
#endif
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, msg);
|
||||
#else
|
||||
va_start(ap);
|
||||
msg = va_arg(ap, const char *);
|
||||
#endif
|
||||
exverror(EXERROR, msg, ap);
|
||||
/* NOTREACHED */
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __STDC__
|
||||
static void
|
||||
exerror(int cond, const char *msg, ...)
|
||||
#else
|
||||
static void
|
||||
exerror(va_alist)
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
#ifndef __STDC__
|
||||
int cond;
|
||||
const char *msg;
|
||||
#endif
|
||||
va_list ap;
|
||||
#ifdef __STDC__
|
||||
va_start(ap, msg);
|
||||
#else
|
||||
va_start(ap);
|
||||
cond = va_arg(ap, int);
|
||||
msg = va_arg(ap, const char *);
|
||||
#endif
|
||||
exverror(cond, msg, ap);
|
||||
/* NOTREACHED */
|
||||
va_end(ap);
|
||||
@ -4914,7 +4883,7 @@ expari(int flag)
|
||||
removerecordregions(begoff);
|
||||
if (quotes)
|
||||
rmescapes(p+2);
|
||||
result = arith(p+2);
|
||||
result = ash_arith(p+2);
|
||||
snprintf(p, 12, "%d", result);
|
||||
|
||||
while (*p++)
|
||||
@ -11952,13 +11921,7 @@ static void
|
||||
trace(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
#ifdef __STDC__
|
||||
va_start(va, fmt);
|
||||
#else
|
||||
char *fmt;
|
||||
va_start(va);
|
||||
fmt = va_arg(va, char *);
|
||||
#endif
|
||||
if (tracefile != NULL) {
|
||||
(void) vfprintf(tracefile, fmt, va);
|
||||
if (strchr(fmt, '\n'))
|
||||
@ -12657,7 +12620,6 @@ found:;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The "local" command.
|
||||
*/
|
||||
@ -12916,7 +12878,7 @@ findvar(struct var **vpp, const char *name)
|
||||
/*
|
||||
* Copyright (c) 1999 Herbert Xu <herbert@debian.org>
|
||||
* This file contains code for the times builtin.
|
||||
* $Id: ash.c,v 1.13 2001/07/26 05:58:40 russ Exp $
|
||||
* $Id: ash.c,v 1.14 2001/07/30 21:41:37 andersen Exp $
|
||||
*/
|
||||
static int timescmd (int argc, char **argv)
|
||||
{
|
||||
@ -12937,6 +12899,51 @@ static int timescmd (int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
#ifdef ASH_MATH_SUPPORT
|
||||
/* The exp(1) builtin. */
|
||||
int expcmd(int argc, char **argv)
|
||||
{
|
||||
const char *p;
|
||||
char *concat;
|
||||
char **ap;
|
||||
long i;
|
||||
|
||||
if (argc > 1) {
|
||||
p = argv[1];
|
||||
if (argc > 2) {
|
||||
/* concatenate arguments */
|
||||
STARTSTACKSTR(concat);
|
||||
ap = argv + 2;
|
||||
for (;;) {
|
||||
while (*p)
|
||||
STPUTC(*p++, concat);
|
||||
if ((p = *ap++) == NULL)
|
||||
break;
|
||||
STPUTC(' ', concat);
|
||||
}
|
||||
STPUTC('\0', concat);
|
||||
p = grabstackstr(concat);
|
||||
}
|
||||
} else
|
||||
p = "";
|
||||
|
||||
i = ash_arith(p);
|
||||
|
||||
printf("%ld\n", i);
|
||||
return (! i);
|
||||
}
|
||||
|
||||
static long ash_arith(const char *p)
|
||||
{
|
||||
long i = arith(p);
|
||||
if (i <0)
|
||||
error("arith: syntax error: \"%s\"\n", p);
|
||||
return i;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1989, 1991, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
|
Loading…
Reference in New Issue
Block a user