/* Primitives package */
#include "copyright.h"
#include "config.h"
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#include "db.h"
#include "mcp.h"
#include "inst.h"
#include "externs.h"
#include "match.h"
#include "interface.h"
#include "params.h"
#include "tune.h"
#include "fbstrings.h"
#include "interp.h"
#include "mcpgui.h"
#include "array.h"
#include "mufevent.h"
static struct inst *oper1, *oper2, *oper3, *oper4;
static int result;
struct mcp_muf_context {
dbref prog;
};
void
muf_mcp_context_cleanup(void *context)
{
struct mcp_muf_context* mmc = (struct mcp_muf_context*)context;
free(mmc);
}
void
muf_mcp_callback(McpFrame * mfr, McpMesg * mesg, McpVer version, void *context)
{
struct mcp_muf_context* mmc = (struct mcp_muf_context*)context;
dbref obj = mmc->prog;
struct mcp_binding *ptr;
McpArg *arg;
char *pkgname = mesg->package;
char *msgname = mesg->mesgname;
dbref user;
int descr;
descr = mcpframe_to_descr(mfr);
user = mcpframe_to_user(mfr);
for (ptr = PROGRAM_MCPBINDS(obj); ptr; ptr = ptr->next) {
if (ptr->pkgname && ptr->msgname) {
if (!string_compare(ptr->pkgname, pkgname)) {
if (!string_compare(ptr->msgname, msgname)) {
break;
}
}
}
}
if (ptr) {
struct frame *tmpfr;
stk_array *argarr;
struct inst argname, argval, argpart;
tmpfr = interp(descr, user, getloc(user), obj, -1, PREEMPT, STD_REGUID, 0);
if (tmpfr) {
oper1 = tmpfr->argument.st + --tmpfr->argument.top;
CLEAR(oper1);
argarr = new_array_dictionary();
for (arg = mesg->args; arg; arg = arg->next) {
if (!arg->value) {
argval.type = PROG_STRING;
argval.data.string = NULL;
} else if (!arg->value->next) {
argval.type = PROG_STRING;
argval.data.string = alloc_prog_string(arg->value->value);
} else {
McpArgPart *partptr;
int count = 0;
argname.type = PROG_INTEGER;
argval.type = PROG_ARRAY;
argval.data.array =
new_array_packed(mcp_mesg_arg_linecount(mesg, arg->name));
for (partptr = arg->value; partptr; partptr = partptr->next) {
argname.data.number = count++;
argpart.type = PROG_STRING;
argpart.data.string = alloc_prog_string(partptr->value);
array_setitem(&argval.data.array, &argname, &argpart);
CLEAR(&argpart);
}
}
argname.type = PROG_STRING;
argname.data.string = alloc_prog_string(arg->name);
array_setitem(&argarr, &argname, &argval);
CLEAR(&argname);
CLEAR(&argval);
}
push(tmpfr->argument.st, &(tmpfr->argument.top), PROG_INTEGER, MIPSCAST & descr);
push(tmpfr->argument.st, &(tmpfr->argument.top), PROG_ARRAY, MIPSCAST argarr);
tmpfr->pc = ptr->addr;
interp_loop(user, obj, tmpfr, 0);
}
}
}
struct mcpevent_context {
int pid;
};
void
mcpevent_context_cleanup(void *context)
{
struct mcpevent_context* mec = (struct mcpevent_context*)context;
free(mec);
}
void
muf_mcp_event_callback(McpFrame * mfr, McpMesg * mesg, McpVer version, void *context)
{
struct mcpevent_context* mec = (struct mcpevent_context*)context;
int destpid = mec->pid;
struct frame* destfr = timequeue_pid_frame(destpid);
int descr = mcpframe_to_descr(mfr);
char *pkgname = mesg->package;
char *msgname = mesg->mesgname;
McpArg *arg;
if (destfr) {
char buf[BUFFER_LEN];
stk_array *argarr;
stk_array *contarr;
struct inst argname, argval, argpart;
argarr = new_array_dictionary();
for (arg = mesg->args; arg; arg = arg->next) {
if (!arg->value) {
argval.type = PROG_ARRAY;
argval.data.array = NULL;
} else {
McpArgPart *partptr;
int count = 0;
argname.type = PROG_INTEGER;
argval.type = PROG_ARRAY;
argval.data.array =
new_array_packed(mcp_mesg_arg_linecount(mesg, arg->name));
for (partptr = arg->value; partptr; partptr = partptr->next) {
argname.data.number = count++;
argpart.type = PROG_STRING;
argpart.data.string = alloc_prog_string(partptr->value);
array_setitem(&argval.data.array, &argname, &argpart);
CLEAR(&argpart);
}
}
argname.type = PROG_STRING;
argname.data.string = alloc_prog_string(arg->name);
array_setitem(&argarr, &argname, &argval);
CLEAR(&argname);
CLEAR(&argval);
}
contarr = new_array_dictionary();
array_set_strkey_intval(&contarr, "descr", descr);
array_set_strkey_strval(&contarr, "package", pkgname);
array_set_strkey_strval(&contarr, "message", msgname);
argname.type = PROG_STRING;
argname.data.string = alloc_prog_string("args");
argval.type = PROG_ARRAY;
argval.data.array = argarr;
array_setitem(&contarr, &argname, &argval);
CLEAR(&argname);
CLEAR(&argval);
argval.type = PROG_ARRAY;
argval.data.array = contarr;
if (msgname && *msgname) {
snprintf(buf, sizeof(buf), "MCP.%.128s-%.128s", pkgname, msgname);
} else {
snprintf(buf, sizeof(buf), "MCP.%.128s", pkgname);
}
muf_event_add(destfr, buf, &argval, 0);
CLEAR(&argval);
}
}
int
stuff_dict_in_mesg(stk_array* arr, McpMesg* msg)
{
struct inst argname, *argval;
char buf[64];
int result;
result = array_first(arr, &argname);
while (result) {
if (argname.type != PROG_STRING) {
CLEAR(&argname);
return -1;
}
if (!argname.data.string || !*argname.data.string->data) {
CLEAR(&argname);
return -2;
}
argval = array_getitem(arr, &argname);
switch (argval->type) {
case PROG_ARRAY:{
struct inst subname, *subval;
int contd = array_first(argval->data.array, &subname);
mcp_mesg_arg_remove(msg, argname.data.string->data);
while (contd) {
subval = array_getitem(argval->data.array, &subname);
switch (subval->type) {
case PROG_STRING:
mcp_mesg_arg_append(msg, argname.data.string->data,
DoNullInd(subval->data.string));
break;
case PROG_INTEGER:
snprintf(buf, sizeof(buf), "%d", subval->data.number);
mcp_mesg_arg_append(msg, argname.data.string->data, buf);
break;
case PROG_OBJECT:
snprintf(buf, sizeof(buf), "#%d", subval->data.number);
mcp_mesg_arg_append(msg, argname.data.string->data, buf);
break;
case PROG_FLOAT:
snprintf(buf, sizeof(buf), "%.15g", subval->data.fnumber);
mcp_mesg_arg_append(msg, argname.data.string->data, buf);
break;
default:
CLEAR(&argname);
return -3;
}
contd = array_next(argval->data.array, &subname);
}
break;
}
case PROG_STRING:
mcp_mesg_arg_remove(msg, argname.data.string->data);
mcp_mesg_arg_append(msg, argname.data.string->data,
DoNullInd(argval->data.string));
break;
case PROG_INTEGER:
snprintf(buf, sizeof(buf), "%d", argval->data.number);
mcp_mesg_arg_remove(msg, argname.data.string->data);
mcp_mesg_arg_append(msg, argname.data.string->data, buf);
break;
case PROG_OBJECT:
snprintf(buf, sizeof(buf), "#%d", argval->data.number);
mcp_mesg_arg_remove(msg, argname.data.string->data);
mcp_mesg_arg_append(msg, argname.data.string->data, buf);
break;
case PROG_FLOAT:
snprintf(buf, sizeof(buf), "%.15g", argval->data.fnumber);
mcp_mesg_arg_remove(msg, argname.data.string->data);
mcp_mesg_arg_append(msg, argname.data.string->data, buf);
break;
default:
CLEAR(&argname);
return -4;
}
result = array_next(arr, &argname);
}
return 0;
}
void
prim_mcp_register(PRIM_PROTOTYPE)
{
char *pkgname;
McpVer vermin, vermax;
struct mcp_muf_context *mmc;
CHECKOP(3);
oper3 = POP();
oper2 = POP();
oper1 = POP();
/* oper1 oper2 oper3 */
/* pkgstr minver maxver */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("Package name string expected. (1)");
if (oper2->type != PROG_FLOAT)
abort_interp("Floating point minimum version number expected. (2)");
if (oper3->type != PROG_FLOAT)
abort_interp("Floating point maximum version number expected. (3)");
if (!oper1->data.string || !*oper1->data.string->data)
abort_interp("Package name cannot be a null string. (1)");
pkgname = oper1->data.string->data;
vermin.vermajor = (int) oper2->data.fnumber;
vermin.verminor = (int) (oper2->data.fnumber * 1000) % 1000;
vermax.vermajor = (int) oper3->data.fnumber;
vermax.verminor = (int) (oper3->data.fnumber * 1000) % 1000;
mmc = (struct mcp_muf_context*)malloc(sizeof(struct mcp_muf_context));
mmc->prog = program;
mcp_package_register(pkgname, vermin, vermax, muf_mcp_callback, (void *) mmc, muf_mcp_context_cleanup);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
}
void
prim_mcp_register_event(PRIM_PROTOTYPE)
{
char *pkgname;
McpVer vermin, vermax;
struct mcpevent_context *mec;
CHECKOP(3);
oper3 = POP();
oper2 = POP();
oper1 = POP();
/* oper1 oper2 oper3 */
/* pkgstr minver maxver */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("Package name string expected. (1)");
if (oper2->type != PROG_FLOAT)
abort_interp("Floating point minimum version number expected. (2)");
if (oper3->type != PROG_FLOAT)
abort_interp("Floating point maximum version number expected. (3)");
if (!oper1->data.string || !*oper1->data.string->data)
abort_interp("Package name cannot be a null string. (1)");
pkgname = oper1->data.string->data;
vermin.vermajor = (int) oper2->data.fnumber;
vermin.verminor = (int) (oper2->data.fnumber * 1000) % 1000;
vermax.vermajor = (int) oper3->data.fnumber;
vermax.verminor = (int) (oper3->data.fnumber * 1000) % 1000;
mec = (struct mcpevent_context*)malloc(sizeof(struct mcpevent_context));
mec->pid = fr->pid;
mcp_package_register(pkgname, vermin, vermax, muf_mcp_event_callback, (void *)mec, mcpevent_context_cleanup);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
}
void
prim_mcp_supports(PRIM_PROTOTYPE)
{
char *pkgname;
int descr;
McpVer ver;
McpFrame *mfr;
double fver;
CHECKOP(2);
oper2 = POP();
oper1 = POP();
/* oper1 oper2 */
/* descr pkgstr */
if (oper1->type != PROG_INTEGER)
abort_interp("Integer descriptor number expected. (1)");
if (oper2->type != PROG_STRING)
abort_interp("Package name string expected. (2)");
if (!oper2->data.string || !*oper2->data.string->data)
abort_interp("Package name cannot be a null string. (2)");
pkgname = oper2->data.string->data;
descr = oper1->data.number;
fver = 0.0;
mfr = descr_mcpframe(descr);
if (mfr) {
ver = mcp_frame_package_supported(mfr, pkgname);
fver = ver.vermajor + (ver.verminor / 1000.0);
}
CLEAR(oper1);
CLEAR(oper2);
PushFloat(fver);
}
void
prim_mcp_bind(PRIM_PROTOTYPE)
{
char *pkgname, *msgname;
struct mcp_binding *ptr;
CHECKOP(3);
oper3 = POP();
oper2 = POP();
oper1 = POP();
/* oper1 oper2 oper3 */
/* pkgstr msgstr address */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("Package name string expected. (1)");
if (oper2->type != PROG_STRING)
abort_interp("Message name string expected. (2)");
if (oper3->type != PROG_ADD)
abort_interp("Function address expected. (3)");
if (!oper1->data.string || !*oper1->data.string->data)
abort_interp("Package name cannot be a null string. (1)");
if (oper3->data.addr->progref >= db_top ||
oper3->data.addr->progref < 0 || (Typeof(oper3->data.addr->progref) != TYPE_PROGRAM)) {
abort_interp("Invalid address. (3)");
}
if (program != oper3->data.addr->progref) {
abort_interp("Destination address outside current program. (3)");
}
pkgname = oper1->data.string->data;
msgname = oper2->data.string ? oper2->data.string->data : "";
for (ptr = PROGRAM_MCPBINDS(program); ptr; ptr = ptr->next) {
if (ptr->pkgname && ptr->msgname) {
if (!string_compare(ptr->pkgname, pkgname)) {
if (!string_compare(ptr->msgname, msgname)) {
break;
}
}
}
}
if (!ptr) {
ptr = (struct mcp_binding *) malloc(sizeof(struct mcp_binding));
ptr->pkgname = (char *) malloc(strlen(pkgname) + 1);
strcpy(ptr->pkgname, pkgname);
ptr->msgname = (char *) malloc(strlen(msgname) + 1);
strcpy(ptr->msgname, msgname);
ptr->next = PROGRAM_MCPBINDS(program);
PROGRAM_SET_MCPBINDS(program, ptr);
}
ptr->addr = oper3->data.addr->data;
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
}
void
prim_mcp_send(PRIM_PROTOTYPE)
{
char *pkgname, *msgname;
int descr;
McpFrame *mfr;
stk_array *arr;
CHECKOP(4);
oper3 = POP();
oper2 = POP();
oper1 = POP();
oper4 = POP();
/* oper4 oper1 oper2 oper3 */
/* descr pkgstr msgstr argsarray */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper4->type != PROG_INTEGER)
abort_interp("Integer descriptor number expected. (1)");
if (oper1->type != PROG_STRING)
abort_interp("Package name string expected. (2)");
if (!oper1->data.string || !*oper1->data.string->data)
abort_interp("Package name cannot be a null string. (2)");
if (oper2->type != PROG_STRING)
abort_interp("Message name string expected. (3)");
if (oper3->type != PROG_ARRAY)
abort_interp("Arguments dictionary expected. (4)");
pkgname = oper1->data.string->data;
msgname = oper2->data.string ? oper2->data.string->data : "";
arr = oper3->data.array;
descr = oper4->data.number;
mfr = descr_mcpframe(descr);
if (mfr) {
McpMesg msg;
McpVer ver = mcp_frame_package_supported(mfr, pkgname);
if (ver.verminor == 0 && ver.vermajor == 0)
abort_interp("MCP package not supported by that descriptor.");
mcp_mesg_init(&msg, pkgname, msgname);
result = stuff_dict_in_mesg(arr, &msg);
if (result) {
mcp_mesg_clear(&msg);
switch (result) {
case -1:
abort_interp("Args dictionary can only have string keys. (4)");
break;
case -2:
abort_interp("Args dictionary cannot have a null string key. (4)");
break;
case -3:
abort_interp("Unsupported value type in list value. (4)");
break;
case -4:
abort_interp("Unsupported value type in args dictionary. (4)");
break;
}
}
mcp_frame_output_mesg(mfr, &msg);
mcp_mesg_clear(&msg);
}
CLEAR(oper1);
CLEAR(oper2);
}
void
fbgui_muf_event_cb(GUI_EVENT_CB_ARGS)
{
char buf[BUFFER_LEN];
const char *name;
struct frame *fr = (struct frame *) context;
struct inst temp;
struct inst temp1;
struct inst temp2;
stk_array *nu;
int i;
int lines;
nu = new_array_dictionary();
name = GuiValueFirst(dlogid);
while (name) {
lines = gui_value_linecount(dlogid, name);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string(name);
temp2.type = PROG_ARRAY;
temp2.data.array = new_array_packed(lines);
for (i = 0; i < lines; i++) {
struct inst temp3;
array_data temp4;
temp3.type = PROG_INTEGER;
temp3.data.number = i;
temp4.type = PROG_STRING;
temp4.data.string = alloc_prog_string(gui_value_get(dlogid, name, i));
array_setitem(&temp2.data.array, &temp3, &temp4);
CLEAR(&temp3);
CLEAR(&temp4);
}
array_setitem(&nu, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
name = GuiValueNext(dlogid, name);
}
temp.type = PROG_ARRAY;
temp.data.array = new_array_dictionary();
array_set_strkey_intval(&temp.data.array, "dismissed", did_dismiss);
array_set_strkey_intval(&temp.data.array, "descr", descr);
array_set_strkey_strval(&temp.data.array, "dlogid", dlogid);
array_set_strkey_strval(&temp.data.array, "id", id);
array_set_strkey_strval(&temp.data.array, "event", event);
temp2.type = PROG_ARRAY;
temp2.data.array = nu;
array_set_strkey(&temp.data.array, "values", &temp2);
CLEAR(&temp2);
lines = mcp_mesg_arg_linecount(msg, "data");
if (lines > 0) {
temp2.type = PROG_ARRAY;
temp2.data.array = new_array_packed(lines);
for (i = 0; i < lines; i++) {
struct inst temp3;
array_data temp4;
temp3.type = PROG_INTEGER;
temp3.data.number = i;
temp4.type = PROG_STRING;
temp4.data.string = alloc_prog_string(mcp_mesg_arg_getline(msg, "data", i));
array_setitem(&temp2.data.array, &temp3, &temp4);
CLEAR(&temp4);
}
array_set_strkey(&temp.data.array, "data", &temp2);
CLEAR(&temp2);
}
/*
if (did_dismiss) {
muf_dlog_remove(fr, dlogid);
}
*/
snprintf(buf, sizeof(buf), "GUI.%s", dlogid);
muf_event_add(fr, buf, &temp, 0);
CLEAR(&temp);
}
void
fbgui_muf_error_cb(GUI_ERROR_CB_ARGS)
{
char buf[BUFFER_LEN];
struct frame *fr = (struct frame *) context;
struct inst temp;
temp.type = PROG_ARRAY;
temp.data.array = new_array_dictionary();
array_set_strkey_intval(&temp.data.array, "descr", descr);
array_set_strkey_strval(&temp.data.array, "dlogid", dlogid);
if (id) {
array_set_strkey_strval(&temp.data.array, "id", id);
}
array_set_strkey_strval(&temp.data.array, "errcode", errcode);
array_set_strkey_strval(&temp.data.array, "errtext", errtext);
snprintf(buf, sizeof(buf), "GUI.%s", dlogid);
muf_event_add(fr, buf, &temp, 0);
CLEAR(&temp);
}
void
prim_gui_available(PRIM_PROTOTYPE)
{
McpVer ver;
double fver;
CHECKOP(1);
oper1 = POP(); /* descr */
if (oper1->type != PROG_INTEGER)
abort_interp("Integer descriptor number expected. (1)");
ver = GuiVersion(oper1->data.number);
fver = ver.vermajor + (ver.verminor / 1000.0);
CLEAR(oper1);
PushFloat(fver);
}
void
prim_gui_dlog_create(PRIM_PROTOTYPE)
{
const char *dlogid = NULL;
char *title = NULL;
char *wintype = NULL;
stk_array *arr = NULL;
McpMesg msg;
McpFrame *mfr;
CHECKOP(4);
oper4 = POP(); /* arr args */
oper3 = POP(); /* str title */
oper2 = POP(); /* str type */
oper1 = POP(); /* int descr */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_INTEGER)
abort_interp("Integer descriptor number expected. (1)");
if (!GuiSupported(oper1->data.number))
abort_interp("The MCP GUI package is not supported for this connection.");
if (oper2->type != PROG_STRING)
abort_interp("Window type string expected. (3)");
if (oper3->type != PROG_STRING)
abort_interp("Window title string expected. (3)");
if (oper4->type != PROG_ARRAY)
abort_interp("Window options array expected. (4)");
title = oper3->data.string ? oper3->data.string->data : "";
wintype = oper2->data.string ? oper2->data.string->data : "simple";
arr = oper4->data.array;
mfr = descr_mcpframe(oper1->data.number);
if (!mfr)
abort_interp("Invalid descriptor number. (1)");
dlogid = gui_dlog_alloc(oper1->data.number, fbgui_muf_event_cb,
fbgui_muf_error_cb, fr);
mcp_mesg_init(&msg, GUI_PACKAGE, "dlog-create");
mcp_mesg_arg_append(&msg, "title", title);
result = stuff_dict_in_mesg(arr, &msg);
if (result) {
mcp_mesg_clear(&msg);
switch (result) {
case -1:
abort_interp("Args dictionary can only have string keys. (4)");
break;
case -2:
abort_interp("Args dictionary cannot have a null string key. (4)");
break;
case -3:
abort_interp("Unsupported value type in list value. (4)");
break;
case -4:
abort_interp("Unsupported value type in args dictionary. (4)");
break;
}
}
mcp_mesg_arg_remove(&msg, "type");
mcp_mesg_arg_append(&msg, "type", wintype);
mcp_mesg_arg_remove(&msg, "dlogid");
mcp_mesg_arg_append(&msg, "dlogid", dlogid);
mcp_frame_output_mesg(mfr, &msg);
mcp_mesg_clear(&msg);
muf_dlog_add(fr, dlogid);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
CLEAR(oper4);
PushString(dlogid);
}
void
prim_gui_dlog_show(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("String dialog ID expected.");
if (!oper1->data.string || !oper1->data.string->data[0])
abort_interp("Invalid dialog ID.");
result = GuiShow(oper1->data.string->data);
if (result == EGUINOSUPPORT)
abort_interp("GUI not available. Internal error.");
if (result == EGUINODLOG)
abort_interp("Invalid dialog ID.");
CLEAR(oper1);
}
void
prim_gui_dlog_close(PRIM_PROTOTYPE)
{
CHECKOP(1);
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("String dialog ID expected.");
if (!oper1->data.string || !oper1->data.string->data[0])
abort_interp("Invalid dialog ID.");
result = GuiClose(oper1->data.string->data);
if (result == EGUINOSUPPORT)
abort_interp("Internal error: GUI not available.");
if (result == EGUINODLOG)
abort_interp("Invalid dialog ID.");
muf_dlog_remove(fr, oper1->data.string->data);
CLEAR(oper1);
}
void
prim_gui_ctrl_create(PRIM_PROTOTYPE)
{
int vallines = 0;
char **vallist = NULL;
char *dlogid = NULL;
char *ctrlid = NULL;
char *ctrltype = NULL;
char *valname = NULL;
stk_array *arr;
McpMesg msg;
McpFrame *mfr;
int descr;
int i;
char cmdname[64];
CHECKOP(4);
oper4 = POP(); /* dict args */
oper3 = POP(); /* str ctrlid */
oper2 = POP(); /* str type */
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("Dialog ID string expected. (1)");
if (!oper1->data.string || !oper1->data.string->data[0])
abort_interp("Invalid dialog ID. (1)");
if (oper2->type != PROG_STRING)
abort_interp("Control type string expected. (2)");
if (!oper2->data.string || !oper2->data.string->data[0])
abort_interp("Invalid control type. (2)");
if (oper3->type != PROG_STRING)
abort_interp("Control ID string expected. (3)");
if (oper4->type != PROG_ARRAY)
abort_interp("Dictionary of arguments expected. (4)");
dlogid = oper1->data.string->data;
ctrltype = oper2->data.string->data;
ctrlid = oper3->data.string ? oper3->data.string->data : NULL;
arr = oper4->data.array;
descr = gui_dlog_get_descr(dlogid);
mfr = descr_mcpframe(descr);
if (!mfr)
abort_interp("No such dialog currently exists. (1)");
if (!GuiSupported(descr))
abort_interp("Internal error: The given dialog's descriptor doesn't support the GUI package. (1)");
snprintf(cmdname, sizeof(cmdname), "ctrl-%.55s", ctrltype);
mcp_mesg_init(&msg, GUI_PACKAGE, cmdname);
result = stuff_dict_in_mesg(arr, &msg);
if (result) {
mcp_mesg_clear(&msg);
switch (result) {
case -1:
abort_interp("Args dictionary can only have string keys. (4)");
break;
case -2:
abort_interp("Args dictionary cannot have a null string key. (4)");
break;
case -3:
abort_interp("Unsupported value type in list value. (4)");
break;
case -4:
abort_interp("Unsupported value type in args dictionary. (4)");
break;
}
}
vallines = mcp_mesg_arg_linecount(&msg, "value");
valname = mcp_mesg_arg_getline(&msg, "valname", 0);
if (!valname || !*valname) {
valname = ctrlid;
}
if (valname && vallines > 0) {
vallist = (char**)malloc(sizeof(char*) * vallines);
for (i = 0; i < vallines; i++)
vallist[i] = mcp_mesg_arg_getline(&msg, "value", i);
gui_value_set_local(dlogid, valname, vallines, (const char**)vallist);
free(vallist);
}
mcp_mesg_arg_remove(&msg, "dlogid");
mcp_mesg_arg_append(&msg, "dlogid", dlogid);
mcp_mesg_arg_remove(&msg, "id");
mcp_mesg_arg_append(&msg, "id", ctrlid);
mcp_frame_output_mesg(mfr, &msg);
mcp_mesg_clear(&msg);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
CLEAR(oper4);
}
void
prim_gui_ctrl_command(PRIM_PROTOTYPE)
{
char *dlogid = NULL;
char *ctrlid = NULL;
char *ctrlcmd = NULL;
stk_array *arr;
McpMesg msg;
McpFrame *mfr;
int descr;
CHECKOP(4);
oper4 = POP(); /* dict args */
oper2 = POP(); /* str command */
oper3 = POP(); /* str ctrlid */
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("Dialog ID string expected. (1)");
if (!oper1->data.string || !*oper1->data.string->data)
abort_interp("Non-null dialog ID string expected. (1)");
if (oper3->type != PROG_STRING)
abort_interp("Control ID string expected. (2)");
if (!oper3->data.string || !*oper3->data.string->data)
abort_interp("Non-null control ID string expected. (2)");
if (oper2->type != PROG_STRING)
abort_interp("Control command string expected. (3)");
if (!oper2->data.string || !*oper2->data.string->data)
abort_interp("Non-null control command string expected. (3)");
if (oper4->type != PROG_ARRAY)
abort_interp("Dictionary of arguments expected. (4)");
dlogid = oper1->data.string->data;
ctrlcmd = oper2->data.string->data;
ctrlid = oper3->data.string ? oper3->data.string->data : NULL;
arr = oper4->data.array;
descr = gui_dlog_get_descr(dlogid);
mfr = descr_mcpframe(descr);
if (!mfr)
abort_interp("No such dialog currently exists. (1)");
if (!GuiSupported(descr))
abort_interp("Internal error: The given dialog's descriptor doesn't support the GUI package. (1)");
mcp_mesg_init(&msg, GUI_PACKAGE, "ctrl-command");
result = stuff_dict_in_mesg(arr, &msg);
if (result) {
mcp_mesg_clear(&msg);
switch (result) {
case -1:
abort_interp("Args dictionary can only have string keys. (4)");
break;
case -2:
abort_interp("Args dictionary cannot have a null string key. (4)");
break;
case -3:
abort_interp("Unsupported value type in list value. (4)");
break;
case -4:
abort_interp("Unsupported value type in args dictionary. (4)");
break;
}
}
mcp_mesg_arg_remove(&msg, "dlogid");
mcp_mesg_arg_append(&msg, "dlogid", dlogid);
mcp_mesg_arg_remove(&msg, "id");
mcp_mesg_arg_append(&msg, "id", ctrlid);
mcp_mesg_arg_remove(&msg, "command");
mcp_mesg_arg_append(&msg, "command", ctrlcmd);
mcp_frame_output_mesg(mfr, &msg);
mcp_mesg_clear(&msg);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
CLEAR(oper4);
}
void
prim_gui_value_set(PRIM_PROTOTYPE)
{
int count;
int i;
char buf[BUFFER_LEN];
char *name;
char *dlogid;
char *value;
char **valarray;
struct inst temp1;
array_data *temp2;
CHECKOP(3);
oper3 = POP(); /* str value */
oper2 = POP(); /* str ctrlid */
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper3->type != PROG_STRING && oper3->type != PROG_ARRAY)
abort_interp("String or string list control value expected. (3)");
if (oper2->type != PROG_STRING)
abort_interp("String control ID expected. (2)");
if (!oper2->data.string || !oper2->data.string->data[0])
abort_interp("Invalid dialog ID. (2)");
if (oper1->type != PROG_STRING)
abort_interp("String dialog ID expected. (1)");
if (!oper1->data.string || !oper1->data.string->data[0])
abort_interp("Invalid dialog ID. (1)");
dlogid = oper1->data.string->data;
name = oper2->data.string->data;
if (oper3->type == PROG_STRING) {
count = 1;
valarray = (char **) malloc(sizeof(char *) * count);
value = oper3->data.string ? oper3->data.string->data : "";
valarray[0] = (char *) malloc(sizeof(char) * strlen(value) + 1);
strcpy(valarray[0], value);
} else {
count = array_count(oper3->data.array);
valarray = (char **) malloc(sizeof(char *) * count);
for (i = 0; i < count; i++) {
temp1.type = PROG_INTEGER;
temp1.data.number = i;
temp2 = array_getitem(oper3->data.array, &temp1);
if (!temp2) {
break;
}
switch (temp2->type) {
case PROG_STRING:
value = DoNullInd(temp2->data.string);
break;
case PROG_INTEGER:
snprintf(buf, sizeof(buf), "%d", temp2->data.number);
value = buf;
break;
case PROG_OBJECT:
snprintf(buf, sizeof(buf), "#%d", temp2->data.number);
value = buf;
break;
case PROG_FLOAT:
snprintf(buf, sizeof(buf), "%.15g", temp2->data.fnumber);
value = buf;
break;
default:
while (i-- > 0) {
free(valarray[i]);
}
free(valarray);
abort_interp("Unsupported value type in list value. (3)");
}
valarray[i] = (char *) malloc(sizeof(char) * strlen(value) + 1);
strcpy(valarray[i], value);
}
}
GuiSetVal(dlogid, name, count, (const char**)valarray);
while (count-- > 0) {
free(valarray[count]);
}
free(valarray);
CLEAR(oper1);
CLEAR(oper2);
CLEAR(oper3);
}
void
prim_gui_values_get(PRIM_PROTOTYPE)
{
const char *name;
char *dlogid;
stk_array *nu;
struct inst temp1;
array_data temp2;
CHECKOP(1);
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("String dialog ID expected.");
if (!oper1->data.string || !oper1->data.string->data[0])
abort_interp("Invalid dialog ID.");
dlogid = oper1->data.string->data;
nu = new_array_dictionary();
name = GuiValueFirst(oper1->data.string->data);
while (name) {
int i;
int lines = gui_value_linecount(dlogid, name);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string(name);
temp2.type = PROG_ARRAY;
temp2.data.array = new_array_packed(lines);
for (i = 0; i < lines; i++) {
struct inst temp3;
array_data temp4;
temp3.type = PROG_INTEGER;
temp3.data.number = i;
temp4.type = PROG_STRING;
temp4.data.string = alloc_prog_string(gui_value_get(dlogid, name, i));
array_setitem(&temp2.data.array, &temp3, &temp4);
CLEAR(&temp3);
CLEAR(&temp4);
}
array_setitem(&nu, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
name = GuiValueNext(dlogid, name);
}
CLEAR(oper1);
PushArrayRaw(nu);
}
void
prim_gui_value_get(PRIM_PROTOTYPE)
{
char *dlogid;
char *ctrlid;
stk_array *nu;
struct inst temp1;
array_data temp2;
int lines;
int i;
CHECKOP(2);
oper2 = POP(); /* str ctrlid */
oper1 = POP(); /* str dlogid */
if (mlev < tp_mcp_muf_mlev)
abort_interp("Permission denied.");
if (oper1->type != PROG_STRING)
abort_interp("String dialog ID expected. (1)");
if (!oper1->data.string || !*oper1->data.string->data)
abort_interp("Non-null string dialog ID expected. (1)");
if (oper2->type != PROG_STRING)
abort_interp("String control ID expected. (2)");
if (!oper2->data.string || !*oper2->data.string->data)
abort_interp("Non-null string control ID expected. (2)");
dlogid = oper1->data.string->data;
ctrlid = oper2->data.string->data;
lines = gui_value_linecount(dlogid, ctrlid);
nu = new_array_packed(lines);
for (i = 0; i < lines; i++) {
temp1.type = PROG_INTEGER;
temp1.data.number = i;
temp2.type = PROG_STRING;
temp2.data.string = alloc_prog_string(gui_value_get(dlogid, ctrlid, i));
array_setitem(&nu, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
}
CLEAR(oper1);
CLEAR(oper2);
PushArrayRaw(nu);
}