483 lines
11 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_exec_c[] = "$Id$";
#endif
#include <zephyr/mit-copyright.h>
/****************************************************************************/
/* */
/* Module containing code to execute a program: */
/* */
/****************************************************************************/
#include <zephyr/zephyr.h>
#include "new_memory.h"
#include "node.h"
#include "exec.h"
#include "eval.h"
#include "buffer.h"
#include "port.h"
#include "variables.h"
#include "notice.h"
#ifdef CMU_ZWGCPLUS
#include "plus.h"
#endif
static int exec_subtree(Node *);
static int exec_fields(Node *);
/****************************************************************************/
/* */
/* Utility subroutines: */
/* */
/****************************************************************************/
static string
eval_exprlist_to_string(Node *exprlist)
{
string result = string_Copy("");
string temp;
int first_time = 1;
for (; exprlist; exprlist=exprlist->next) {
if (!first_time)
result = string_Concat2(result, " ");
else
first_time = 0;
temp = eval_expr(exprlist);
result = string_Concat2(result, temp);
free(temp);
}
return(result);
}
static char **
eval_exprlist_to_args(Node *exprlist)
{
char **result = (char **)malloc(sizeof(char *));
int argc = 0;
for (; exprlist; exprlist=exprlist->next) {
result[argc] = eval_expr(exprlist);
argc++;
result = (char **)realloc(result, (argc+1)*sizeof(char *));
}
result[argc] = NULL;
return(result);
}
static void
free_args(char **args)
{
char **p;
for (p=args; *p; p++) {
free(*p);
}
free(args);
}
/****************************************************************************/
/* */
/* Subroutines to handle each particular statement type: */
/* */
/****************************************************************************/
#define NOBREAK 0
#define BREAK 1
#define EXIT 2
/*ARGSUSED*/
static int
exec_noop(Node *node)
{
return(NOBREAK);
}
/*ARGSUSED*/
static int
exec_break(Node *node)
{
return(BREAK);
}
/*ARGSUSED*/
static int
exec_exit(Node *node)
{
return(EXIT);
}
static int
exec_set(Node *node)
{
var_set_variable_then_free_value(node->d.nodes.first->d.string_constant,
eval_expr(node->d.nodes.second));
return(NOBREAK);
}
static int
exec_execport(Node *node)
{
string name = eval_expr(node->d.nodes.first);
char **argv = eval_exprlist_to_args(node->d.nodes.second);
create_subprocess_port(name, argv);
free(name);
free_args(argv);
return(NOBREAK);
}
static int
exec_appendport(Node *node)
{
string name, filename;
name = eval_expr(node->d.nodes.first);
filename = eval_expr(node->d.nodes.second);
create_file_append_port(name, filename);
free(name);
free(filename);
return(NOBREAK);
}
static int
exec_inputport(Node *node)
{
string name, filename;
name = eval_expr(node->d.nodes.first);
filename = eval_expr(node->d.nodes.second);
create_file_input_port(name, filename);
free(name);
free(filename);
return(NOBREAK);
}
static int
exec_outputport(Node *node)
{
string name, filename;
name = eval_expr(node->d.nodes.first);
filename = eval_expr(node->d.nodes.second);
create_file_output_port(name, filename);
free(name);
free(filename);
return(NOBREAK);
}
static int
exec_closeinput(Node *node)
{
string name;
name = eval_expr(node->d.nodes.first);
close_port_input(name);
free(name);
return(NOBREAK);
}
static int
exec_closeoutput(Node *node)
{
string name;
name = eval_expr(node->d.nodes.first);
close_port_output(name);
free(name);
return(NOBREAK);
}
static int
exec_closeport(Node *node)
{
string name;
name = eval_expr(node->d.nodes.first);
close_port_input(name);
close_port_output(name);
free(name);
return(NOBREAK);
}
static int
exec_put(Node *node)
{
string name, temp;
if (node->d.nodes.second)
temp = eval_exprlist_to_string(node->d.nodes.second);
else
temp = string_Copy(buffer_to_string());
if (node->d.nodes.first) {
name = eval_expr(node->d.nodes.first);
write_on_port(name, temp, strlen(temp));
free(name);
} else
write_on_port(var_get_variable("output_driver"), temp, strlen(temp));
free(temp);
return(NOBREAK);
}
static int
exec_print(Node *node)
{
string temp;
temp = eval_exprlist_to_string(node->d.nodes.first);
append_buffer(temp);
free(temp);
return(NOBREAK);
}
/*ARGSUSED*/
static int
exec_clearbuf(Node *node)
{
clear_buffer();
return(NOBREAK);
}
static int
exec_case(Node *node)
{
string constant,temp;
Node *match, *cond;
int equal_p;
constant = string_Downcase(eval_expr(node->d.nodes.first));
for (match=node->d.nodes.second; match; match=match->next) {
cond = match->d.nodes.first;
if (!cond) { /* default case */
free(constant);
return(exec_subtree(match->d.nodes.second));
}
for (; cond; cond=cond->next) {
temp = string_Downcase(eval_expr(cond));
equal_p = string_Eq(constant, temp);
free(temp);
if (equal_p) {
free(constant);
return(exec_subtree(match->d.nodes.second));
}
}
}
free(constant);
return(NOBREAK);
}
static int
exec_while(Node *node)
{
int continue_code = NOBREAK;
while (eval_bool_expr(node->d.nodes.first)) {
continue_code = exec_subtree(node->d.nodes.second);
if (continue_code != NOBREAK)
break;
}
if (continue_code == BREAK)
continue_code = NOBREAK;
return(continue_code);
}
static int
exec_if(Node *node)
{
Node *conds;
for (conds=node->d.nodes.first; conds; conds=conds->next)
if (eval_bool_expr(conds->d.nodes.first))
return(exec_subtree(conds->d.nodes.second));
return(NOBREAK);
}
static int
exec_exec(Node *node)
{
int pid;
char **argv = eval_exprlist_to_args(node->d.nodes.first);
pid = fork();
if (pid == -1) {
fprintf(stderr, "zwgc: error while attempting to fork: ");
perror("");
} else if (pid == 0) { /* in child */
execvp(argv[0], argv);
fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]);
perror("");
_exit(errno);
}
free_args(argv);
return(NOBREAK);
}
static struct _Opstuff {
int (*exec)(Node *);
} const opstuff[] = {
{ exec_noop }, /* string_constant */
{ exec_noop }, /* varref */
{ exec_noop }, /* varname */
{ exec_noop }, /* not */
{ exec_noop }, /* plus */
{ exec_noop }, /* and */
{ exec_noop }, /* or */
{ exec_noop }, /* eq */
{ exec_noop }, /* neq */
{ exec_noop }, /* regeq */
{ exec_noop }, /* regneq */
{ exec_noop }, /* buffer */
{ exec_noop }, /* substitute */
{ exec_noop }, /* protect */
{ exec_noop }, /* verbatim */
{ exec_noop }, /* stylestrip */
{ exec_noop }, /* getenv */
{ exec_noop }, /* upcase */
{ exec_noop }, /* downcase */
{ exec_noop }, /* zvar */
{ exec_noop }, /* get */
{ exec_noop }, /* lany */
{ exec_noop }, /* rany */
{ exec_noop }, /* lbreak */
{ exec_noop }, /* rbreak */
{ exec_noop }, /* lspan */
{ exec_noop }, /* rspan */
{ exec_noop }, /* noop statement */
{ exec_set },
{ exec_fields },
{ exec_print },
{ exec_clearbuf },
{ exec_appendport },
{ exec_execport },
{ exec_inputport },
{ exec_outputport },
{ exec_put },
{ exec_closeinput },
{ exec_closeoutput },
{ exec_closeport },
{ exec_exec },
{ exec_if },
{ exec_case },
{ exec_while },
{ exec_break },
{ exec_exit },
{ exec_noop }, /* if */
{ exec_noop }, /* elseif */
{ exec_noop }, /* else */
{ exec_noop }, /* matchlist */
{ exec_noop }, /* default */
};
static int
exec_subtree(Node *node)
{
int retval = NOBREAK;
for (; node; node=node->next) {
retval = (opstuff[node->opcode].exec)(node);
if (retval != NOBREAK)
return(retval);
}
return(NOBREAK);
}
/***************************************************************************/
static char *notice_fields;
static int notice_fields_length = 0;
static int number_of_fields = 0;
static int
exec_fields(Node *node)
{
for (node=node->d.nodes.first; node; node=node->next) {
var_set_variable_then_free_value(node->d.string_constant,
get_next_field(&notice_fields,
&notice_fields_length));
if (number_of_fields)
number_of_fields--;
}
var_set_variable_to_number("number_of_fields", number_of_fields);
return(NOBREAK);
}
void
exec_process_packet(Node *program,
ZNotice_t *notice)
{
#ifdef CMU_ZWGCPLUS
set_stored_notice(notice);
#endif
notice_fields = notice->z_message;
notice_fields_length = notice->z_message_len;
var_set_number_variables_to_fields(notice_fields, notice_fields_length);
number_of_fields = count_nulls(notice_fields, notice_fields_length)+1;
/* workaround for bug in old zwrite */
if (notice_fields[notice_fields_length-1] == '\0')
number_of_fields--;
var_set_variable_to_number("number_of_fields", number_of_fields);
clear_buffer();
(void)exec_subtree(program);
#ifdef CMU_ZWGCPLUS
plus_queue_notice(notice);
plus_window_deletions(notice); /* OOPS */
set_stored_notice(NULL);
#endif
}