483 lines
11 KiB
C
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(¬ice_fields,
|
|
¬ice_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
|
|
}
|