home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
200-299
/
ff280.lzh
/
Graph
/
graph.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-11-20
|
16KB
|
544 lines
/*
* GRAPH, Version 1.00 - 4 August 1989
*
* Copyright 1989, David Gay. All Rights Reserved.
* This software is freely redistrubatable.
*/
/* Main program */
#include <exec/types.h>
#include <libraries/dos.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "graph.h"
#include "file.h"
#include "object.h"
#include "uio.h"
#include "list.h"
#include "grph.h"
#include "user/eval.h"
#include "tracker.h"
#include <proto/exec.h>
#include <proto/dos.h>
/* Gadget ids for variables requester */
#define VARSLIST 2
#define VARSDEL 3
const char *eval_messages[] = {
"No error",
"Syntax error",
"Out of memory",
"Right bracket expected",
"Obsolete",
"Left bracket expected",
"Function not differentiable",
"Recursion detected",
"Result not numeric"
};
/* The various libraries used */
struct LayersBase *LayersBase;
extern struct DiskfontBase *DiskfontBase;
extern struct GfxBase *GfxBase;
extern struct IntuitionBase *IntuitionBase;
struct ArpBase *ArpBase;
list graph_list; /* List of graphs */
context vars; /* List of variables */
static int vars_saved = TRUE;
/* Used by variable requester */
static char var[VARLEN], val[EXPRLEN];
static struct Gadget *valg, *delg;
static struct ListInfo *var_info;
/* Inform objects that variable var has changed value. They may need to
recalculate */
static void check_vars(char *var)
{
struct graph *scan;
struct object *o;
/* Variables are global ==> for all graphs, all objects */
for (scan = first(&graph_list); succ(scan); scan = succ(scan))
for (o = first(&scan->o_list); succ(o); o = succ(o))
o->var_change(o, var);
}
/* Redraw all graphs (eg after variables have changed) */
static void draw_all(void)
{
struct graph *g;
for (g = first(&graph_list); succ(g); g = succ(g))
draw_graph(g, TRUE);
}
/* Load a graph from a file into a new graph. See file format. */
static void load_file(struct graph *from)
{
FILE *f;
char file[FILELEN];
if (getfile(file, "Load graph"))
if (f = fopen(file, "r"))
{
short tag;
if (READ(f, tag) && tag == GRAPH_TAG)
{
struct graph *g = load_graph(from, f);
if (g) add_head(&graph_list, g);
}
else
message(from, "File is not a graph", (char *)NULL);
fclose(f);
}
else
message(from, "Couldn't open file", file, (char *)NULL);
}
/* Save current graph to a file. See file format. */
/* TBD: Provide some default file name */
static void save_file(struct graph *g)
{
FILE *f;
char file[FILELEN];
if (getfile(file, "Save graph"))
if (f = fopen(file, "w"))
{
save_graph(g, f);
fclose(f);
}
else
message(g, "Couldn't open file", file, (char *)NULL);
}
/* Read variables from a file. See file format. This adds variables to the
current context, it doesn't eliminate the old ones. */
static void load_variables(struct graph *from)
{
FILE *f;
char file[FILELEN];
if (getfile(file, "Load variables"))
if (f = fopen(file, "r"))
{
short tag;
int ok = FALSE;
if (READ(f, tag) && tag == FILE_TAG) /* This is a variable file */
{
int done = FALSE;
ok = TRUE;
do /* Read all the file */
{
short tag;
if (READ(f, tag))
{
switch (tag)
{
case FILE_END:
done = TRUE;
break;
case VAR_TAG: /* Another variable */
{
char name[VARLEN], val[EXPRLEN];
if (READ(f, name) &&
READ(f, val) &&
READ(f, tag) && tag == VAR_END)
{
value vv = compile(val);
if (!vv || !set_var_name(name, vv))
message(from, "Failed to set variab
le(no memory ?)", (char *)NULL);
check_vars(name);
}
else
ok = FALSE;
}
break;
default:
ok = FALSE;
break;
}
}
else
ok = FALSE;
} while (!done && ok);
}
fclose(f);
if (!ok)
message(from, "File does not contain variables", (char *)NULL);
else draw_all();
}
else
message(from, "Couldn't open file", file, (char *)NULL);
}
/* Save variables. See file format. */
static void save_variables(struct graph *g)
{
FILE *f;
char file[FILELEN];
if (getfile(file, "Save variables"))
if (f = fopen(file, "w"))
{
short tag = FILE_TAG;
int ok = FALSE;
if (WRITE(f, tag))
{
tnode *var;
ok = TRUE;
/* For all variables */
for (var = first(&vars); ok && succ(var); var = succ(var))
{
short end = VAR_END;
char name[VARLEN], expr[EXPRLEN];
value vv = get_var_name(var->ln_Name);
name[VARLEN - 1] = '\0';
strncpy(name, var->ln_Name, VARLEN - 1);
if (vv) decompile(vv, expr, EXPRLEN);
else expr[0] = '\0';
tag = VAR_TAG;
ok = WRITE(f, tag) &&
WRITE(f, name) &&
WRITE(f, expr) &&
WRITE(f, end);
}
tag = FILE_END;
if (ok) ok = WRITE(f, tag);
}
fclose(f);
if (!ok) message(g, "Error writing file", (char *)NULL);
else vars_saved = TRUE;
}
else
message(g, "Couldn't open file", file, (char *)NULL);
}
/* Handle variable requester. Could it be cleaned up ??? */
int vars_handler(struct Gadget *gg, ULONG class, struct Requester *req, struct
graph *g)
{
int id = gg->GadgetID;
int change = FALSE; /* Has the list changed ? */
int actval = FALSE; /* Activate variable value gadget */
int actvar = FALSE; /* " " name " */
int refresh = FALSE; /* value & name gadgets have changed */
UWORD valpos, varpos;
struct Gadget *varg = ListStr(var_info); /* The lists string gadget */
if (gg == valg) /* Value gadget message, class is always GADGETUP */
{
valpos = RemoveGList(req->RWindow, valg, 1);
varpos = RemoveGList(req->RWindow, varg, 1);
refresh = TRUE;
strip(var); /* remove blanks */
strlwr(var);
if (*var)
{
value vv = compile(val), old;
if (eval_error != 0) /* Invalid value, allow correction */
{
DisplayBeep(req->RWindow->WScreen);
actval = TRUE;
}
else /* Try & set variable */
{
if (old = get_var_name(var)) free_expr(old);
else /* list changes, there will be an extra var */
change = TRUE;
check_vars(var);
if (!set_var_name(var, vv))
{
alert(g->io.win, "Couldn't create variable", NULL);
change = FALSE;
}
val[0] = var[0] = '\0';
actvar = TRUE;
}
}
else /* blank var name -- erase val */
{
DisplayBeep(req->RWindow->WScreen);
actvar = TRUE;
}
}
else if (id == VARSDEL) /* Delete selected */
{
value vv;
valpos = RemoveGList(req->RWindow, valg, 1);
varpos = RemoveGList(req->RWindow, varg, 1);
refresh = TRUE;
strip(var);
strlwr(var);
if (*var && (vv = get_var_name(var)))
{
free_expr(vv);
free_var_name(var);
change = TRUE;
check_vars(var);
}
var[0] = val[0] = '\0';
actvar = TRUE;
}
else if (id == VARSLIST) /* Something in list selected */
{
if (ModifyList(gg, req, req->RWindow, class == GADGETUP) != 0 && *var)
{ /* New value selected from list or typed, ie new name. Switch to va
lue gadget */
value vv;
valpos = RemoveGList(req->RWindow, valg, 1);
varpos = RemoveGList(req->RWindow, varg, 1);
refresh = TRUE;
strip(var);
if (!(vv = get_var_name(var)) || !decompile(vv, val, EXPRLEN)) val[
0] = '\0';
actval = TRUE;
}
}
else
return std_ghandler(gg, class, req, g);
/* Handle requester services */
if (refresh)
{
AddGList(req->RWindow, varg, varpos, 1, req);
AddGList(req->RWindow, valg, valpos, 1, req);
RefreshGList(valg, req->RWindow, req, 1);
RefreshGList(varg, req->RWindow, req, 1);
}
if (change) /* Variable list changed */
if (!ChangeList(var_info, &vars, req, req->RWindow))
{
EndRequest(req, req->RWindow);
/* Not enough memory ... */
actval = actvar = FALSE;
}
if (actval) ActivateGadget(valg, req->RWindow, req);
if (actvar) ActivateGadget(varg, req->RWindow, req);
vars_saved = FALSE;
return FALSE;
}
/* Setup variables requester */
void enter_vars(struct graph *g)
{
struct Requester *req;
struct Memory *m;
struct Gadget *gl = NULL;
if ((m = NewMemory()) &&
(req = InitReq(50, 20, 285, 126, m)) &&
SetReqBorder(req, 1, m) &&
AddIntuiText(&req->ReqText, "Edit variables", 86, 6, m) &&
(var_info = AddList(&gl, VARSLIST, "Variables", &vars, var, VARLEN, 0,
RELVERIFY, 20, 20, 160, 80, TRUE, m)) &&
(valg = AddText(&gl, VARSLIST, "Value", FALSE, val, EXPRLEN, TRUE, 0, R
ELVERIFY, 64, 110, 116, 10, TRUE, m)) &&
AddBox(&gl, TRUE, "Ok", 0, RELVERIFY | ENDGADGET, 200, 23, 65, 15, FALS
E, m) &&
AddBox(&gl, VARSDEL, "Delete", 0, RELVERIFY, 200, 86, 65, 15, FALSE, m)
)
{
var[0] = val[0] = '\0';
SetReqGadgets(req, gl);
DoRequest(req, g, vars_handler);
/* vars_handler called for every gadget event */
}
Free(m);
}
/* Create a new graph */
static struct graph *add_graph(struct graph *from)
{
struct graph *g = new_graph(from);
if (g) add_head(&graph_list, g);
return g;
}
/* Delete a graph, checking for save */
static void remove_graph(struct graph *g)
{
if (!g->saved) save_file(g);
remove(g);
delete_graph(g);
}
/* Global initialisation */
static int init(void)
{
if (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0))
if (DiskfontBase = (struct Library *)OpenLibrary("diskfont.library", 0)
)
if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.
library", 33))
if (LayersBase = (struct LayersBase *)OpenLibrary("layers.libra
ry", 33))
if (ArpBase = (struct ArpBase *)OpenLibrary("arp.library",
0))
{
new_list(&graph_list);
if (init_user() && init_grph() && add_graph(NULL))
if (init_expr())
{
init_context(&vars);
set_context(&vars);
return TRUE;
}
else alert(NULL, "Expression init failed", "No memo
ry ?");
}
else alert(NULL, "arp.library required", NULL);
else alert(NULL, "layers.library V1.2 required", NULL);
else alert(NULL, "intuition.library V1.2 required", NULL);
else alert(NULL, "diskfont.library required", NULL);
else alert(NULL, "graphics.library required", NULL);
return FALSE;
}
/* Free ALL resources ! */
static void clean_up(void)
{
struct graph *g, *next;
cleanup_expr();
cleanup_grph();
cleanup_user();
for (g = first(&graph_list); next = succ(g); g = next) remove_graph(g);
if (ArpBase) CloseLibrary((struct Library *)ArpBase);
if (LayersBase) CloseLibrary((struct Library *)LayersBase);
if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
if (DiskfontBase) CloseLibrary((struct Library *)DiskfontBase);
if (GfxBase) CloseLibrary((struct Library *)GfxBase);
#ifdef DEBUG
TrackerExitReport();
#endif
}
void main(int argc, char **argv)
{
struct cmd cmd;
int done = FALSE;
if (init())
do
switch ((cmd = next_command()).command)
{
case close:
done = succ(succ(first(&graph_list))) == NULL; /* one graph
left ? */
if (done && !vars_saved) save_variables(cmd.g);
remove_graph(cmd.g);
break;
case _new_graph:
add_graph(cmd.g);
break;
case _load_graph:
load_file(cmd.g);
break;
case _save_graph:
save_file(cmd.g);
break;
case print_graph:
prt_graph(cmd.g);
break;
case iff_graph:
iff_todisk(cmd.g);
break;
case save_vars:
save_variables(cmd.g);
break;
case load_vars:
load_variables(cmd.g);
break;
case quit:
if (!vars_saved) save_variables(cmd.g);
done = TRUE;
break;
case add_function:
select_object(cmd.g, add_object(cmd.g, new_function(cmd.g))
);
break;
case add_label:
add_object(cmd.g, (struct object *)new_label(cmd.g, cmd.dat
a.pt.x, cmd.data.pt.y));
break;
case del_object:
remove_object(cmd.g, cmd.data.o);
break;
case limits:
enter_limits(cmd.g);
break;
case axes:
enter_axes(cmd.g);
break;
case zoom:
zoom_in(cmd.g, cmd.data.zoom_in.x0, cmd.data.zoom_in.y0, cm
d.data.zoom_in.x1, cmd.data.zoom_in.y1);
break;
case zoom_out:
zoom_factor(cmd.g, cmd.data.zoom_out);
break;
case center:
center_graph(cmd.g, cmd.data.pt.x, cmd.data.pt.y);
break;
case edit:
{
struct Region *ref;
if (cmd.data.o->edit(cmd.data.o, &ref))
{
cmd.g->saved = FALSE;
refresh_graph(cmd.g, TRUE, ref);
}
}
break;
case improve:
refresh_graph(cmd.g, TRUE, cmd.data.o->improve(cmd.data.o))
;
break;
case edit_vars:
enter_vars(cmd.g);
draw_all();
break;
}
while (!done);
clean_up();
}