Code Search for Developers
 
 
  

expr.c from openap at Krugle


Show expr.c syntax highlighted

/* vi: set sw=4 ts=4: */
/*
 * Mini expr implementation for busybox
 *
 * based on GNU expr Mike Parker.
 * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
 *
 * Busybox modifications 
 * Copyright (c) 2000  Edward Betts <edward@debian.org>.
 *
 * this program is free software; you can redistribute it and/or modify
 * it under the terms of the gnu general public license as published by
 * the free software foundation; either version 2 of the license, or
 * (at your option) any later version.
 *
 * this program is distributed in the hope that it will be useful,
 * but without any warranty; without even the implied warranty of
 * merchantability or fitness for a particular purpose. see the gnu
 * general public license for more details.
 *
 * you should have received a copy of the gnu general public license
 * along with this program; if not, write to the free software
 * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
 *
 */

/* This program evaluates expressions.  Each token (operator, operand,
 * parenthesis) of the expression must be a seperate argument.  The
 * parser used is a reasonably general one, though any incarnation of
 * it is language-specific.  It is especially nice for expressions.
 *
 * No parse tree is needed; a new node is evaluated immediately.
 * One function can handle multiple operators all of equal precedence,
 * provided they all associate ((x op x) op x). */

/* no getopt needed */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <regex.h>
#include <sys/types.h>
#include "busybox.h"


/* The kinds of value we can have.  */
enum valtype {
	integer,
	string
};
typedef enum valtype TYPE;

/* A value is.... */
struct valinfo {
	TYPE type;			/* Which kind. */
	union {				/* The value itself. */
		int i;
		char *s;
	} u;
};
typedef struct valinfo VALUE;

/* The arguments given to the program, minus the program name.  */
static char **args;

static VALUE *docolon (VALUE *sv, VALUE *pv);
static VALUE *eval (void);
static VALUE *int_value (int i);
static VALUE *str_value (char *s);
static int nextarg (char *str);
static int null (VALUE *v);
static int toarith (VALUE *v);
static void freev (VALUE *v);
static void tostring (VALUE *v);

int expr_main (int argc, char **argv)
{
	VALUE *v;

	if (argc == 1) {
		error_msg_and_die("too few arguments");
	}

	args = argv + 1;

	v = eval ();
	if (*args)
		error_msg_and_die ("syntax error");

	if (v->type == integer)
		printf ("%d\n", v->u.i);
	else
		puts (v->u.s);

	exit (null (v));
}

/* Return a VALUE for I.  */

static VALUE *int_value (int i)
{
	VALUE *v;

	v = xmalloc (sizeof(VALUE));
	v->type = integer;
	v->u.i = i;
	return v;
}

/* Return a VALUE for S.  */

static VALUE *str_value (char *s)
{
	VALUE *v;

	v = xmalloc (sizeof(VALUE));
	v->type = string;
	v->u.s = strdup (s);
	return v;
}

/* Free VALUE V, including structure components.  */

static void freev (VALUE *v)
{
	if (v->type == string)
		free (v->u.s);
	free (v);
}

/* Return nonzero if V is a null-string or zero-number.  */

static int null (VALUE *v)
{
	switch (v->type) {
		case integer:
			return v->u.i == 0;
		case string:
			return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
		default:
			abort ();
	}
}

/* Coerce V to a string value (can't fail).  */

static void tostring (VALUE *v)
{
	char *temp;

	if (v->type == integer) {
		temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
		sprintf (temp, "%d", v->u.i);
		v->u.s = temp;
		v->type = string;
	}
}

/* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */

static int toarith (VALUE *v)
{
	int i;

	switch (v->type) {
		case integer:
			return 1;
		case string:
			i = 0;
			/* Don't interpret the empty string as an integer.  */
			if (v->u.s == 0)
				return 0;
			i = atoi(v->u.s);
			free (v->u.s);
			v->u.i = i;
			v->type = integer;
			return 1;
		default:
			abort ();
	}
}

/* Return nonzero if the next token matches STR exactly.
   STR must not be NULL.  */

static int
nextarg (char *str)
{
	if (*args == NULL)
		return 0;
	return strcmp (*args, str) == 0;
}

/* The comparison operator handling functions.  */

#define cmpf(name, rel)					\
static int name (l, r) VALUE *l; VALUE *r;		\
{							\
	if (l->type == string || r->type == string) {		\
		tostring (l);				\
		tostring (r);				\
		return strcmp (l->u.s, r->u.s) rel 0;	\
	}						\
	else						\
		return l->u.i rel r->u.i;		\
}
 cmpf (less_than, <)
 cmpf (less_equal, <=)
 cmpf (equal, ==)
 cmpf (not_equal, !=)
 cmpf (greater_equal, >=)
 cmpf (greater_than, >)

#undef cmpf

/* The arithmetic operator handling functions.  */

#define arithf(name, op)			\
static						\
int name (l, r) VALUE *l; VALUE *r;		\
{						\
  if (!toarith (l) || !toarith (r))		\
    error_msg_and_die ("non-numeric argument");	\
  return l->u.i op r->u.i;			\
}

#define arithdivf(name, op)			\
static int name (l, r) VALUE *l; VALUE *r;		\
{						\
  if (!toarith (l) || !toarith (r))		\
    error_msg_and_die ( "non-numeric argument");	\
  if (r->u.i == 0)				\
    error_msg_and_die ( "division by zero");		\
  return l->u.i op r->u.i;			\
}

 arithf (plus, +)
 arithf (minus, -)
 arithf (multiply, *)
 arithdivf (divide, /)
 arithdivf (mod, %)

#undef arithf
#undef arithdivf

/* Do the : operator.
   SV is the VALUE for the lhs (the string),
   PV is the VALUE for the rhs (the pattern).  */

static VALUE *docolon (VALUE *sv, VALUE *pv)
{
	VALUE *v;
	const char *errmsg;
	struct re_pattern_buffer re_buffer;
	struct re_registers re_regs;
	int len;

	tostring (sv);
	tostring (pv);

	if (pv->u.s[0] == '^') {
		fprintf (stderr, "\
warning: unportable BRE: `%s': using `^' as the first character\n\
of a basic regular expression is not portable; it is being ignored",
		pv->u.s);
	}

	len = strlen (pv->u.s);
	memset (&re_buffer, 0, sizeof (re_buffer));
	memset (&re_regs, 0, sizeof (re_regs));
	re_buffer.allocated = 2 * len;
	re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
	re_buffer.translate = 0;
	re_syntax_options = RE_SYNTAX_POSIX_BASIC;
	errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
	if (errmsg) {
		error_msg_and_die("%s", errmsg);
	}

	len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
	if (len >= 0) {
		/* Were \(...\) used? */
		if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
			sv->u.s[re_regs.end[1]] = '\0';
			v = str_value (sv->u.s + re_regs.start[1]);
		}
		else
			v = int_value (len);
	}
	else {
		/* Match failed -- return the right kind of null.  */
		if (re_buffer.re_nsub > 0)
			v = str_value ("");
		else
			v = int_value (0);
	}
	free (re_buffer.buffer);
	return v;
}

/* Handle bare operands and ( expr ) syntax.  */

static VALUE *eval7 (void)
{
	VALUE *v;

	if (!*args)
		error_msg_and_die ( "syntax error");

	if (nextarg ("(")) {
		args++;
		v = eval ();
		if (!nextarg (")"))
			error_msg_and_die ( "syntax error");
			args++;
			return v;
		}

	if (nextarg (")"))
		error_msg_and_die ( "syntax error");

	return str_value (*args++);
}

/* Handle match, substr, index, length, and quote keywords.  */

static VALUE *eval6 (void)
{
	VALUE *l, *r, *v, *i1, *i2;

	if (nextarg ("quote")) {
		args++;
		if (!*args)
			error_msg_and_die ( "syntax error");
		return str_value (*args++);
	}
	else if (nextarg ("length")) {
		args++;
		r = eval6 ();
		tostring (r);
		v = int_value (strlen (r->u.s));
		freev (r);
		return v;
	}
	else if (nextarg ("match")) {
		args++;
		l = eval6 ();
		r = eval6 ();
		v = docolon (l, r);
		freev (l);
		freev (r);
		return v;
	}
	else if (nextarg ("index")) {
		args++;
		l = eval6 ();
		r = eval6 ();
		tostring (l);
		tostring (r);
		v = int_value (strcspn (l->u.s, r->u.s) + 1);
		if (v->u.i == (int) strlen (l->u.s) + 1)
			v->u.i = 0;
		freev (l);
		freev (r);
		return v;
	}
	else if (nextarg ("substr")) {
		args++;
		l = eval6 ();
		i1 = eval6 ();
		i2 = eval6 ();
		tostring (l);
		if (!toarith (i1) || !toarith (i2)
			|| i1->u.i > (int) strlen (l->u.s)
			|| i1->u.i <= 0 || i2->u.i <= 0)
		v = str_value ("");
		else {
			v = xmalloc (sizeof(VALUE));
			v->type = string;
			v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
				l->u.s + i1->u.i - 1, i2->u.i);
				v->u.s[i2->u.i] = 0;
		}
		freev (l);
		freev (i1);
		freev (i2);
		return v;
	}
	else
		return eval7 ();
}

/* Handle : operator (pattern matching).
   Calls docolon to do the real work.  */

static VALUE *eval5 (void)
{
	VALUE *l, *r, *v;

	l = eval6 ();
	while (nextarg (":")) {
		args++;
		r = eval6 ();
		v = docolon (l, r);
		freev (l);
		freev (r);
		l = v;
	}
	return l;
}

/* Handle *, /, % operators.  */

static VALUE *eval4 (void)
{
	VALUE *l, *r;
	int (*fxn) (), val;

	l = eval5 ();
	while (1) {
		if (nextarg ("*"))
			fxn = multiply;
		else if (nextarg ("/"))
			fxn = divide;
		else if (nextarg ("%"))
			fxn = mod;
		else
			return l;
		args++;
		r = eval5 ();
		val = (*fxn) (l, r);
		freev (l);
		freev (r);
		l = int_value (val);
	}
}

/* Handle +, - operators.  */

static VALUE *eval3 (void)
{
	VALUE *l, *r;
	int (*fxn) (), val;

	l = eval4 ();
	while (1) {
		if (nextarg ("+"))
			fxn = plus;
		else if (nextarg ("-"))
			fxn = minus;
		else
			return l;
		args++;
		r = eval4 ();
		val = (*fxn) (l, r);
		freev (l);
		freev (r);
		l = int_value (val);
	}
}

/* Handle comparisons.  */

static VALUE *eval2 (void)
{
	VALUE *l, *r;
	int (*fxn) (), val;

	l = eval3 ();
	while (1) {
		if (nextarg ("<"))
			fxn = less_than;
		else if (nextarg ("<="))
			fxn = less_equal;
		else if (nextarg ("=") || nextarg ("=="))
			fxn = equal;
		else if (nextarg ("!="))
			fxn = not_equal;
		else if (nextarg (">="))
			fxn = greater_equal;
		else if (nextarg (">"))
			fxn = greater_than;
		else
			return l;
		args++;
		r = eval3 ();
		toarith (l);
		toarith (r);
		val = (*fxn) (l, r);
		freev (l);
		freev (r);
		l = int_value (val);
	}
}

/* Handle &.  */

static VALUE *eval1 (void)
{
	VALUE *l, *r;

	l = eval2 ();
	while (nextarg ("&")) {
		args++;
		r = eval2 ();
		if (null (l) || null (r)) {
			freev (l);
			freev (r);
			l = int_value (0);
		}
		else
			freev (r);
	}
	return l;
}

/* Handle |.  */

static VALUE *eval (void)
{
	VALUE *l, *r;

	l = eval1 ();
	while (nextarg ("|")) {
		args++;
		r = eval1 ();
		if (null (l)) {
			freev (l);
			l = r;
		}
		else
			freev (r);
	}
	return l;
}




See more files for this project here

openap

OpenAP is the complete distribution of open-source software that is required to produce a fully 802.11b compliant wireless access point. OpenAP is also a platform on which developers and hobbyists may realize their ideas. Since the build environment and s

Project homepage: http://savannah.nongnu.org/projects/openap
Programming language(s): Assembly,C
License: gpl2

  bootfloppy/
  debian/
  docs/
  facility/
  kernel-patches/
  libbb/
  pwd_grp/
  scripts/
  tests/
  .indent.pro
  AUTHORS
  Changelog
  Config.h
  INSTALL
  LICENSE
  Makefile
  README
  TODO
  adjtimex.c
  applets.c
  applets.h
  ar.c
  ash.c
  basename.c
  busybox.c
  busybox.h
  busybox.mkll
  busybox.sh
  busybox.spec
  cat.c
  chgrp.c
  chmod.c
  chown.c
  chroot.c
  chvt.c
  clear.c
  cmdedit.c
  cmdedit.h
  cmp.c
  cp.c
  cpio.c
  cut.c
  date.c
  dc.c
  dd.c
  deallocvt.c
  df.c
  dirname.c
  dmesg.c
  dos2unix.c
  dpkg.c
  dpkg_deb.c
  du.c
  dumpkmap.c
  dutmp.c
  echo.c
  env.c
  expr.c
  fbset.c
  fdflush.c
  find.c
  free.c
  freeramdisk.c
  fsck_minix.c
  getopt.c
  grep.c
  gunzip.c
  gzip.c
  halt.c
  head.c
  hostid.c
  hostname.c
  hush.c
  id.c
  ifconfig.c
  init.c
  insmod.c
  install.sh
  kill.c
  klogd.c
  lash.c
  length.c
  ln.c
  loadacm.c
  loadfont.c
  loadkmap.c
  logger.c
  logname.c
  logread.c
  ls.c
  lsmod.c
  makedevs.c
  md5sum.c
  mk_loop_h.sh
  mkdir.c
  mkfifo.c
  mkfs_minix.c
  mknod.c
  mkswap.c
  mktemp.c
  modprobe.c
  more.c
  mount.c
  msh.c
  mt.c
  mv.c