568 lines
12 KiB
C
568 lines
12 KiB
C
/* $Header$ */
|
||
/*
|
||
* Xgraph Parameters
|
||
*
|
||
* This file contains routines for setting and retrieving
|
||
* various X style display parameters for xgraph.
|
||
*
|
||
* $Log$
|
||
* Revision 1.1 2004-01-25 09:00:49 pnenzi
|
||
*
|
||
* Added xgraph plotting program.
|
||
*
|
||
* Revision 1.2 1999/12/08 19:32:41 heideman
|
||
* strcasecmp portability fix
|
||
*
|
||
* Revision 1.1.1.1 1999/12/03 23:15:52 heideman
|
||
* xgraph-12.0
|
||
*
|
||
*/
|
||
#ifndef lint
|
||
static char rcsid[] = "$Id$";
|
||
|
||
#endif
|
||
|
||
#include <ctype.h>
|
||
#include <stdio.h>
|
||
#include "st.h"
|
||
#include "params.h"
|
||
#include "hard_devices.h"
|
||
#include "xgraph.h" /* for string.h */
|
||
|
||
/* For use by convenience macros */
|
||
params param_temp,
|
||
*param_temp_ptr;
|
||
XColor param_null_color =
|
||
{0, 0, 0, 0, 0, 0};
|
||
param_style param_null_style =
|
||
{STYLE, 0, (char *) 0};
|
||
|
||
static st_table *param_table = (st_table *) 0;
|
||
|
||
typedef struct param_full_defn {
|
||
param_types type;
|
||
char *text_form;
|
||
params *real_form;
|
||
} param_full;
|
||
|
||
|
||
#define ISO_FONT "*-*-%s-medium-r-normal-*-*-%d-*-*-*-*-iso8859-*"
|
||
static Display *param_disp;
|
||
static Colormap param_cmap;
|
||
static int param_scrn;
|
||
|
||
static void free_resource();
|
||
static params *resolve_entry();
|
||
static int strihash();
|
||
static int do_color();
|
||
static int do_font();
|
||
static int do_style();
|
||
static int do_bool();
|
||
|
||
#define DEF_INT "0"
|
||
#define DEF_STR ""
|
||
#define DEF_FONT "fixed"
|
||
#define DEF_PIXEL "black"
|
||
#define DEF_STYLE "1"
|
||
#define DEF_BOOL "false"
|
||
#define DEF_DBL "0.0"
|
||
|
||
#define DEF_MAX_FONT 1024
|
||
#define DEF_MAX_NAMES 10
|
||
|
||
#define DUP(str) \
|
||
strcpy((char *) Malloc((unsigned) (strlen(str)+1)), (str))
|
||
|
||
|
||
void
|
||
param_init(disp, cmap)
|
||
Display *disp; /* X Connection */
|
||
Colormap cmap; /* Colormap for colors */
|
||
|
||
/*
|
||
* Initializes parameter package. The display and colormap arguments
|
||
* are used to resolve font and pixel values.
|
||
*/
|
||
{
|
||
param_table = st_init_table(stricmp, strihash);
|
||
if (disp != NULL) {
|
||
param_disp = disp;
|
||
param_cmap = cmap;
|
||
/* This could also be a parameter for greater generality */
|
||
param_scrn = DefaultScreen(disp);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void
|
||
param_set(name, type, val)
|
||
char *name; /* Name of parameter */
|
||
param_types type; /* Type */
|
||
char *val; /* Text form for value */
|
||
|
||
/*
|
||
* Sets the parameter with the given name to have the type
|
||
* `type' and the text value `value'. This will be evaluated
|
||
* to its full form the first time it is referenced using
|
||
* param_get(). If it is already filled, the old value
|
||
* will be reclaimed.
|
||
*/
|
||
{
|
||
param_full *entry;
|
||
|
||
if (!param_table) {
|
||
(void) fprintf(stderr, "Parameter table not initialized\n");
|
||
return;
|
||
}
|
||
if (st_lookup(param_table, name, (char **) &entry)) {
|
||
if (entry->real_form)
|
||
free_resource(entry->real_form);
|
||
entry->real_form = (params *) 0;
|
||
}
|
||
else {
|
||
entry = (param_full *) Malloc(sizeof(param_full));
|
||
entry->text_form = (char *) 0;
|
||
entry->real_form = (params *) 0;
|
||
(void) st_insert(param_table, DUP(name), (char *) entry);
|
||
}
|
||
entry->type = type;
|
||
if (entry->text_form)
|
||
(void) Free((char *) (entry->text_form));
|
||
entry->text_form = DUP(val);
|
||
}
|
||
|
||
|
||
void
|
||
param_reset(name, val)
|
||
char *name; /* Name of parameter */
|
||
char *val; /* Text form for value */
|
||
|
||
/*
|
||
* This routine sets the value of an existing parameter to a new
|
||
* value. The type of the parameter remains the same. Changes
|
||
* in type should be done by using param_set() directly.
|
||
*/
|
||
{
|
||
param_full *entry;
|
||
|
||
if (!param_table) {
|
||
(void) fprintf(stderr, "Parameter table not initialized\n");
|
||
return;
|
||
}
|
||
if (st_lookup(param_table, name, (char **) &entry))
|
||
param_set(name, entry->type, val);
|
||
else
|
||
(void) fprintf(stderr, "Cannot reset unknown parameter `%s'\n", name);
|
||
}
|
||
|
||
|
||
|
||
|
||
params *
|
||
param_get(name, val)
|
||
char *name; /* Name of parameter */
|
||
params *val; /* Result value */
|
||
|
||
/*
|
||
* Retrieves a value from the parameter table. The value
|
||
* is placed in `val'. If successful, the routine will
|
||
* return `val'. Otherwise, it will return zero.
|
||
*/
|
||
{
|
||
param_full *entry;
|
||
|
||
if (!param_table) {
|
||
(void) fprintf(stderr, "Parameter table not initialized\n");
|
||
return (params *) 0;
|
||
}
|
||
if (st_lookup(param_table, name, (char **) &entry)) {
|
||
if (!entry->real_form)
|
||
entry->real_form = resolve_entry(name, entry->type,
|
||
entry->text_form);
|
||
*val = *(entry->real_form);
|
||
return val;
|
||
}
|
||
else {
|
||
return (params *) 0;
|
||
}
|
||
}
|
||
|
||
|
||
static void
|
||
free_resource(val)
|
||
params *val; /* Value to free */
|
||
|
||
/*
|
||
* Reclaims a resource based on its type.
|
||
*/
|
||
{
|
||
switch (val->type) {
|
||
case INT:
|
||
case STR:
|
||
case BOOL:
|
||
case DBL:
|
||
/* No reclaimation necessary */
|
||
break;
|
||
case PIXEL:
|
||
if ((val->pixv.value.pixel != WhitePixel(param_disp, param_scrn)) &&
|
||
(val->pixv.value.pixel != BlackPixel(param_disp, param_scrn)))
|
||
XFreeColors(param_disp, param_cmap, &(val->pixv.value.pixel), 1, 0);
|
||
break;
|
||
case FONT:
|
||
XFreeFont(param_disp, val->fontv.value);
|
||
break;
|
||
case STYLE:
|
||
(void) Free(val->stylev.dash_list);
|
||
break;
|
||
}
|
||
(void) Free((char *) val);
|
||
}
|
||
|
||
|
||
|
||
static params *
|
||
resolve_entry(name, type, form)
|
||
char *name; /* Name of item for errors */
|
||
param_types type; /* What type of thing */
|
||
char *form; /* Textual form */
|
||
|
||
/*
|
||
* Allocates and returns an appropriate parameter structure
|
||
* by translating `form' into its native type as given by `type'.
|
||
* If it can't translate the given form, it will fall back onto
|
||
* the default.
|
||
*/
|
||
{
|
||
static char paramstr[] =
|
||
"Parameter %s: can't translate `%s' into a %s (defaulting to `%s')\n";
|
||
params *result = (params *) Malloc(sizeof(params));
|
||
|
||
result->type = type;
|
||
switch (type) {
|
||
case INT:
|
||
if (sscanf(form, "%d", &result->intv.value) != 1) {
|
||
(void) fprintf(stderr, paramstr, name, form, "integer", DEF_INT);
|
||
result->intv.value = atoi(DEF_INT);
|
||
}
|
||
break;
|
||
case STR:
|
||
result->strv.value = form;
|
||
break;
|
||
case PIXEL:
|
||
if (!do_color(form, &result->pixv.value)) {
|
||
(void) fprintf(stderr, paramstr, name, form, "color", DEF_PIXEL);
|
||
(void) do_color(DEF_PIXEL, &result->pixv.value);
|
||
}
|
||
break;
|
||
case FONT:
|
||
if (!do_font(form, &result->fontv.value)) {
|
||
(void) fprintf(stderr, paramstr, name, form, "font", DEF_FONT);
|
||
(void) do_font(DEF_FONT, &result->fontv.value);
|
||
}
|
||
break;
|
||
case STYLE:
|
||
if (!do_style(form, &result->stylev)) {
|
||
(void) fprintf(stderr, paramstr, name, form, "line style",
|
||
DEF_STYLE);
|
||
(void) do_style(DEF_STYLE, &result->stylev);
|
||
}
|
||
break;
|
||
case BOOL:
|
||
if (!do_bool(form, &result->boolv.value)) {
|
||
(void) fprintf(stderr, paramstr, name, form, "boolean flag",
|
||
DEF_BOOL);
|
||
(void) do_bool(DEF_BOOL, &result->boolv.value);
|
||
}
|
||
break;
|
||
case DBL:
|
||
if (sscanf(form, "%lf", &result->dblv.value) != 1) {
|
||
(void) fprintf(stderr, paramstr, name, form, "double", DEF_DBL);
|
||
result->dblv.value = atof(DEF_DBL);
|
||
}
|
||
break;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
static int
|
||
do_color(name, color)
|
||
char *name; /* Name for color */
|
||
XColor *color; /* Returned color */
|
||
|
||
/*
|
||
* Translates `name' into a color and attempts to get the pixel
|
||
* for the color using XAllocColor().
|
||
*/
|
||
{
|
||
int result = 1;
|
||
|
||
if (PM_INT("Output Device") == D_XWINDOWS) {
|
||
if (XParseColor(param_disp, param_cmap, name, color)) {
|
||
if (stricmp(name, "black") == 0) {
|
||
color->pixel = BlackPixel(param_disp, param_scrn);
|
||
XQueryColor(param_disp, param_cmap, color);
|
||
}
|
||
else if (stricmp(name, "white") == 0) {
|
||
color->pixel = WhitePixel(param_disp, param_scrn);
|
||
XQueryColor(param_disp, param_cmap, color);
|
||
}
|
||
else
|
||
result = XAllocColor(param_disp, param_cmap, color);
|
||
}
|
||
else
|
||
result = 0;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
|
||
|
||
static int
|
||
do_font(name, font_info)
|
||
char *name; /* Name of desired font */
|
||
XFontStruct **font_info; /* Returned font information */
|
||
|
||
/*
|
||
* This routine translates a font name into a font structure. The
|
||
* font name can be in two forms. The first form is <family>-<size>.
|
||
* The family is a family name (like helvetica) and the size is
|
||
* in points (like 12). If the font is not in this form, it
|
||
* is assumed to be a regular X font name specification and
|
||
* is looked up using the standard means.
|
||
*/
|
||
{
|
||
char name_copy[DEF_MAX_FONT],
|
||
query_spec[DEF_MAX_FONT];
|
||
char *font_family,
|
||
*font_size,
|
||
**font_list;
|
||
int font_size_value,
|
||
font_count,
|
||
i;
|
||
|
||
/* First attempt to interpret as font family/size */
|
||
if (PM_INT("Output Device") == D_XWINDOWS) {
|
||
(void) strcpy(name_copy, name);
|
||
if (font_size = index(name_copy, '-')) {
|
||
*font_size = '\0';
|
||
font_family = name_copy;
|
||
font_size++;
|
||
font_size_value = atoi(font_size);
|
||
if (font_size_value > 0) {
|
||
/*
|
||
* Still a little iffy -- what about weight and roman vs. other
|
||
*/
|
||
(void) sprintf(query_spec, ISO_FONT,
|
||
font_family, font_size_value * 10);
|
||
font_list = XListFonts(param_disp, query_spec,
|
||
DEF_MAX_NAMES, &font_count);
|
||
|
||
/* Load first one that you can */
|
||
for (i = 0; i < font_count; i++)
|
||
if (*font_info = XLoadQueryFont(param_disp, font_list[i]))
|
||
break;
|
||
if (*font_info)
|
||
return 1;
|
||
}
|
||
}
|
||
/* Assume normal font name */
|
||
return (int) (*font_info = XLoadQueryFont(param_disp, name));
|
||
}
|
||
}
|
||
|
||
|
||
static int
|
||
do_style(list, val)
|
||
char *list; /* List of ones and zeros */
|
||
param_style *val; /* Line style returned */
|
||
|
||
/*
|
||
* Translates a string representation of a dash specification into
|
||
* a form suitable for use in XSetDashes(). Assumes `list'
|
||
* is a null terminated string of ones and zeros.
|
||
*/
|
||
{
|
||
char *i,
|
||
*spot,
|
||
last_char;
|
||
int count;
|
||
|
||
for (i = list; *i; i++)
|
||
if ((*i != '0') && (*i != '1'))
|
||
break;
|
||
|
||
if (!*i) {
|
||
val->len = 0;
|
||
last_char = '\0';
|
||
for (i = list; *i; i++) {
|
||
if (*i != last_char) {
|
||
val->len += 1;
|
||
last_char = *i;
|
||
}
|
||
}
|
||
val->dash_list = (char *) Malloc((unsigned)
|
||
(sizeof(char) * val->len + 1));
|
||
last_char = *list;
|
||
spot = val->dash_list;
|
||
count = 0;
|
||
for (i = list; *i; i++) {
|
||
if (*i != last_char) {
|
||
*spot++ = (char) count;
|
||
last_char = *i;
|
||
count = 1;
|
||
}
|
||
else
|
||
count++;
|
||
}
|
||
*spot = (char) count;
|
||
return 1;
|
||
}
|
||
else {
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
|
||
static char *positive[] =
|
||
{"on", "yes", "true", "1", "affirmative", (char *) 0};
|
||
static char *negative[] =
|
||
{"off", "no", "false", "0", "negative", (char *) 0};
|
||
|
||
static int
|
||
do_bool(name, val)
|
||
char *name; /* String representation */
|
||
int *val; /* Returned value */
|
||
|
||
/*
|
||
* Translates a string representation into a suitable binary value.
|
||
* Can parse all kinds of interesting boolean type words.
|
||
*/
|
||
{
|
||
char **term;
|
||
|
||
for (term = positive; *term; term++) {
|
||
if (stricmp(name, *term) == 0)
|
||
break;
|
||
}
|
||
if (*term) {
|
||
*val = 1;
|
||
return 1;
|
||
}
|
||
for (term = negative; *term; term++)
|
||
if (stricmp(name, *term) == 0)
|
||
break;
|
||
|
||
if (*term) {
|
||
*val = 0;
|
||
return 1;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
|
||
|
||
/*ARGSUSED*/
|
||
static enum st_retval
|
||
dump_it(key, value, arg)
|
||
char *key,
|
||
*value,
|
||
*arg;
|
||
{
|
||
param_full *val = (param_full *) value;
|
||
|
||
(void) fprintf(stdout, "%s (", key);
|
||
switch (val->type) {
|
||
case INT:
|
||
(void) fprintf(stdout, "INT");
|
||
break;
|
||
case STR:
|
||
(void) fprintf(stdout, "STR");
|
||
break;
|
||
case PIXEL:
|
||
(void) fprintf(stdout, "PIXEL");
|
||
break;
|
||
case FONT:
|
||
(void) fprintf(stdout, "FONT");
|
||
break;
|
||
case STYLE:
|
||
(void) fprintf(stdout, "STYLE");
|
||
break;
|
||
case BOOL:
|
||
(void) fprintf(stdout, "BOOL");
|
||
break;
|
||
case DBL:
|
||
(void) fprintf(stdout, "DBL");
|
||
break;
|
||
}
|
||
(void) fprintf(stdout, ") = %s\n", val->text_form);
|
||
return ST_CONTINUE;
|
||
}
|
||
|
||
void
|
||
param_dump()
|
||
/*
|
||
* Dumps all of the parameter values to standard output.
|
||
*/
|
||
{
|
||
st_foreach(param_table, dump_it, (char *) 0);
|
||
}
|
||
|
||
|
||
|
||
#ifdef HAVE_STRCASECMP
|
||
int
|
||
stricmp(a, b)
|
||
char *a, *b;
|
||
{
|
||
return strcasecmp(a, b);
|
||
}
|
||
#else
|
||
int
|
||
stricmp(a, b)
|
||
register char *a,
|
||
*b;
|
||
|
||
/*
|
||
* This routine compares two strings disregarding case.
|
||
*/
|
||
{
|
||
register int value;
|
||
|
||
if ((a == (char *) 0) || (b == (char *) 0)) {
|
||
return a - b;
|
||
}
|
||
|
||
for ( /* nothing */ ;
|
||
((*a | *b) &&
|
||
!(value = ((isupper(*a) ? *a - 'A' + 'a' : *a) -
|
||
(isupper(*b) ? *b - 'A' + 'a' : *b))));
|
||
a++, b++)
|
||
/* Empty Body */ ;
|
||
|
||
return value;
|
||
}
|
||
|
||
#endif
|
||
|
||
static int
|
||
strihash(string, modulus)
|
||
register char *string;
|
||
int modulus;
|
||
|
||
/* Case insensitive computation */
|
||
{
|
||
register int val = 0;
|
||
register int c;
|
||
|
||
while ((c = *string++) != '\0') {
|
||
if (isupper(c))
|
||
c = tolower(c);
|
||
val = val * 997 + c;
|
||
}
|
||
|
||
return ((val < 0) ? -val : val) % modulus;
|
||
}
|