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;
|
|||
|
|
}
|