301 lines
7.5 KiB
C
301 lines
7.5 KiB
C
/* This file is part of the Project Athena Zephyr Notification System.
|
|
* It is one of the source files comprising zwgc, the Zephyr WindowGram
|
|
* client.
|
|
*
|
|
* Created by: Marc Horowitz <marc@athena.mit.edu>
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright (c) 1989 by the Massachusetts Institute of Technology.
|
|
* For copying and distribution information, see the file
|
|
* "mit-copyright.h".
|
|
*/
|
|
|
|
#include <sysdep.h>
|
|
|
|
#if (!defined(lint) && !defined(SABER))
|
|
static const char rcsid_eval_c[] = "$Id$";
|
|
#endif
|
|
|
|
#include <zephyr/mit-copyright.h>
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Code to evaluate an expression: */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
#include <zephyr/zephyr.h>
|
|
#include "new_memory.h"
|
|
#include "node.h"
|
|
#include "eval.h"
|
|
#include "substitute.h"
|
|
#include "port.h"
|
|
#include "buffer.h"
|
|
#include "regexp.h"
|
|
#include "formatter.h"
|
|
#include "text_operations.h"
|
|
#include "zwgc.h"
|
|
#include "variables.h"
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Code to deal with string/boolean conversion: */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* Internal Routine:
|
|
*
|
|
* int string_to_bool(string str)
|
|
* Effects: Returns true iff the string str represents true.
|
|
* True is represented by any string which is equal to
|
|
* "true" when case is disregraded.
|
|
*/
|
|
|
|
#define string_to_bool(str) (!strcasecmp(str,"true"))
|
|
|
|
/*
|
|
* Internal Routine:
|
|
*
|
|
* string bool_to_string(int bool)
|
|
* Effects: Returns a string representive for the C boolean bool.
|
|
* (In C, true == non-zero) I.e.,
|
|
* string_to_bool(bool_to_string(x)) == !!x.
|
|
* The string returned is on the heap & must be freed
|
|
* eventually.
|
|
*/
|
|
|
|
static string
|
|
bool_to_string(int bool)
|
|
{
|
|
return(bool ? string_Copy("TRUE") : string_Copy("FALSE"));
|
|
}
|
|
|
|
/*
|
|
* int eval_bool_expr(Node *expr)
|
|
* Modifies: dict
|
|
* Requires: expr is a proper expression or NULL. (see node.c)
|
|
* Effects: Evaluates expr to its boolean value which is returned.
|
|
* NULL is defined to have the boolean value true.
|
|
*/
|
|
|
|
int
|
|
eval_bool_expr(Node *expr)
|
|
{
|
|
string temp;
|
|
int result;
|
|
|
|
if (!expr)
|
|
return(1);
|
|
|
|
temp = eval_expr(expr);
|
|
result = string_to_bool(temp);
|
|
free(temp);
|
|
|
|
return(result);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* */
|
|
/* Code to evaluate an expression: */
|
|
/* */
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* string eval_expr(Node *expr)
|
|
* Modifies: dict
|
|
* Requires: expr is a proper expression (NOT NULL). (see node.c)
|
|
* Effects: Evaluates expr to its string value which is returned.
|
|
* The returned string is on the heap and must be freed
|
|
* eventually.
|
|
*/
|
|
|
|
string
|
|
eval_expr(Node *expr)
|
|
{
|
|
int opcode = expr->opcode;
|
|
int bool_result = 0;
|
|
string first, second;
|
|
char *result = NULL;
|
|
string *text_ptr;
|
|
|
|
/*
|
|
* Dispatch based on the opcode of the top node in the expression:
|
|
*/
|
|
switch (opcode) {
|
|
case STRING_CONSTANT_OPCODE:
|
|
return(string_Copy(expr->d.string_constant));
|
|
|
|
case VARREF_OPCODE:
|
|
return(string_Copy(var_get_variable(expr->d.string_constant)));
|
|
|
|
case BUFFER_OPCODE:
|
|
return(string_Copy(buffer_to_string()));
|
|
|
|
/*
|
|
* Handle unary expressions:
|
|
*/
|
|
case NOT_OPCODE:
|
|
case SUBSTITUTE_OPCODE:
|
|
case PROTECT_OPCODE:
|
|
case VERBATIM_OPCODE:
|
|
case STYLESTRIP_OPCODE:
|
|
case GETENV_OPCODE:
|
|
case UPCASE_OPCODE:
|
|
case DOWNCASE_OPCODE:
|
|
case ZVAR_OPCODE:
|
|
case GET_OPCODE:
|
|
first = eval_expr(expr->d.nodes.first);
|
|
|
|
switch (opcode) {
|
|
case NOT_OPCODE:
|
|
result = bool_to_string(! string_to_bool(first));
|
|
break;
|
|
|
|
case SUBSTITUTE_OPCODE:
|
|
result = substitute(var_get_variable, first);
|
|
break;
|
|
|
|
case PROTECT_OPCODE:
|
|
result=protect(first);
|
|
break;
|
|
|
|
case VERBATIM_OPCODE:
|
|
return(verbatim(first,0));
|
|
|
|
case STYLESTRIP_OPCODE:
|
|
return(stylestrip(first));
|
|
|
|
case GETENV_OPCODE:
|
|
result = getenv(first);
|
|
if (!result)
|
|
result = string_Copy("");
|
|
else
|
|
result = string_Copy(result);
|
|
break;
|
|
|
|
case UPCASE_OPCODE:
|
|
return(string_Upcase(first));
|
|
|
|
case DOWNCASE_OPCODE:
|
|
return(string_Downcase(first));
|
|
|
|
case ZVAR_OPCODE:
|
|
result = ZGetVariable(first);
|
|
if (!result)
|
|
result = string_Copy("");
|
|
else
|
|
result = string_Copy(result);
|
|
break;
|
|
|
|
case GET_OPCODE:
|
|
result = read_from_port(first);
|
|
break;
|
|
}
|
|
free(first);
|
|
break;
|
|
|
|
/*
|
|
* Handle binary operators:
|
|
*/
|
|
case PLUS_OPCODE:
|
|
case AND_OPCODE:
|
|
case OR_OPCODE:
|
|
case EQ_OPCODE:
|
|
case NEQ_OPCODE:
|
|
case REGEQ_OPCODE:
|
|
case REGNEQ_OPCODE:
|
|
first = eval_expr(expr->d.nodes.first);
|
|
second = eval_expr(expr->d.nodes.second);
|
|
|
|
switch (opcode) {
|
|
case PLUS_OPCODE:
|
|
result = string_Concat(first, second);
|
|
free(first);
|
|
free(second);
|
|
return(result);
|
|
|
|
case AND_OPCODE:
|
|
bool_result = string_to_bool(first) && string_to_bool(second);
|
|
break;
|
|
|
|
case OR_OPCODE:
|
|
bool_result = string_to_bool(first) || string_to_bool(second);
|
|
break;
|
|
|
|
case EQ_OPCODE:
|
|
bool_result = string_Eq(first, second);
|
|
break;
|
|
|
|
case NEQ_OPCODE:
|
|
bool_result = string_Neq(first, second);
|
|
break;
|
|
|
|
case REGEQ_OPCODE:
|
|
bool_result = ed_regexp_match_p(first, second);
|
|
break;
|
|
|
|
case REGNEQ_OPCODE:
|
|
bool_result = !ed_regexp_match_p(first, second);
|
|
break;
|
|
}
|
|
free(first);
|
|
free(second);
|
|
result = bool_to_string(bool_result);
|
|
break;
|
|
|
|
/*
|
|
* Handle text-manipulation operators:
|
|
*/
|
|
case LANY_OPCODE: case RANY_OPCODE:
|
|
case LBREAK_OPCODE: case RBREAK_OPCODE:
|
|
case LSPAN_OPCODE: case RSPAN_OPCODE:
|
|
first = eval_expr(expr->d.nodes.first);
|
|
second = eval_expr(expr->d.nodes.second);
|
|
text_ptr = &first;
|
|
|
|
switch (opcode) {
|
|
case LANY_OPCODE:
|
|
result = lany(text_ptr, second);
|
|
break;
|
|
|
|
case RANY_OPCODE:
|
|
result = rany(text_ptr, second);
|
|
break;
|
|
|
|
case LBREAK_OPCODE:
|
|
result = lbreak(text_ptr, string_to_character_class(second));
|
|
break;
|
|
|
|
case RBREAK_OPCODE:
|
|
result = rbreak(text_ptr, string_to_character_class(second));
|
|
break;
|
|
|
|
case LSPAN_OPCODE:
|
|
result = lspan(text_ptr, string_to_character_class(second));
|
|
break;
|
|
|
|
case RSPAN_OPCODE:
|
|
result = rspan(text_ptr, string_to_character_class(second));
|
|
break;
|
|
}
|
|
|
|
if (expr->d.nodes.first->opcode == VARREF_OPCODE)
|
|
var_set_variable(expr->d.nodes.first->d.string_constant, first);
|
|
free(first);
|
|
free(second);
|
|
break;
|
|
|
|
#ifdef DEBUG
|
|
default:
|
|
printf("zwgc: internal error: attempt to evaluate the following non-expression:\n"); fflush(stdout);
|
|
node_display(expr);
|
|
printf("\n\n");
|
|
exit(2);
|
|
#endif
|
|
}
|
|
|
|
return(result);
|
|
}
|