1452 lines
38 KiB
C
1452 lines
38 KiB
C
#ifndef lint
|
|
#ifdef sccs
|
|
static char sccsid[] = "@(#)defaults.c 1.1 94/10/31";
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
* Copyright (c) 1985, 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* This file contains routines for reading in and accessing a defaults
|
|
* database. Any errors are printed on the console as warning messeges.
|
|
*/
|
|
|
|
/*
|
|
* Overview of data structures:
|
|
*
|
|
* All of the relevent data structures are stored in a defaults object.
|
|
* The defaults object contains two hash tables. The symbols hash table
|
|
* is used to cannoncalize (sp?) strings. Every time a string (symbol)
|
|
* is encountered, it is looked up in the symbols hash table to get a
|
|
* unique pointer to a string. This means that two symbols can be tested
|
|
* for equality by simply comparing their pointers. The second hash table
|
|
* is the nodes hash table. The nodes hash table is indexed by a name,
|
|
* where a name is a null-terminated list of symbol pointers
|
|
* (i.e. ["CShell", "Path", "Help", NULL]). The nodes are threaded together
|
|
* so that each node knows its parent, eldest child, and next youngest
|
|
* sibling. In addition, each node has a name (i.e. the null-terminated
|
|
* list of string pointers) and a string value.
|
|
*/
|
|
|
|
#include <stdio.h> /* Standard I/O library */
|
|
#include <pwd.h> /* Password file stuff */
|
|
#include <sys/types.h> /* Get u_long defined for dir.h */
|
|
#include <sys/dir.h> /* Directory access routines */
|
|
#include <sys/stat.h> /* File status information */
|
|
#include <sunwindow/sun.h> /* Define True, False, etc... */
|
|
#include <sunwindow/hash.h> /* Hash table definitions */
|
|
#include <sunwindow/parse.h> /* Parsing routine */
|
|
#include <strings.h>
|
|
#include <sunwindow/defaults.h>
|
|
#include <sunwindow/defaults_impl.h>
|
|
|
|
|
|
|
|
#define HUGE_STRING 10000 /* Huge strings for Warren Teitelman */
|
|
|
|
#define getchr(fp) ((int)getc(fp)) /* Simplify character at a time debugging */
|
|
#define ungetchr ungetc /* Simplify character at a time debugging */
|
|
|
|
/* Use following instead of standard strdup to localize VM accesses */
|
|
#define defaults_strdup(str) (strcpy(hash_get_memory((unsigned) strlen(str) + 1), str))
|
|
|
|
typedef int (*INT_FUNC)();
|
|
typedef char (*CHAR_FUNC)();
|
|
|
|
|
|
|
|
/* Global variables: */
|
|
Defaults defaults; /* = NULL; Global defaults object */
|
|
|
|
/* Exported routine definitions. */
|
|
#include <sunwindow/defaults.h> /* Defaults routines */
|
|
|
|
/*
|
|
* chr_digit(chr) returns True if CHr is a valid digit.
|
|
*/
|
|
#define chr_digit(chr) ((Bool)(('0' <= chr) && (chr <= '9')))
|
|
|
|
/*
|
|
* chr_letter(chr) returns True if Chr is a valid letter.
|
|
*/
|
|
#define chr_letter(chr) ((Bool)((' ' < chr) && (chr <= '~') && (chr != '/')))
|
|
|
|
|
|
/* Internally used routines: */
|
|
|
|
void clear_status();
|
|
void defaults_create();
|
|
long *get_data();
|
|
char *getlogindir();
|
|
void name_cat();
|
|
Name name_copy();
|
|
Bool name_equal();
|
|
int name_hash();
|
|
int name_parse();
|
|
void name_quick_parse();
|
|
char *name_unparse();
|
|
Node node_create();
|
|
void node_delete();
|
|
void node_delete_private();
|
|
Node node_find_name();
|
|
Node node_lookup_name();
|
|
Node node_lookup_path();
|
|
Node path_lookup();
|
|
Bool read();
|
|
void read_lazy();
|
|
void read_master();
|
|
void read_master_database();
|
|
void read_master_database1();
|
|
void read_private_database();
|
|
char *slash_append();
|
|
Symbol symbol_copy();
|
|
Bool symbol_equal();
|
|
int symbol_hash();
|
|
Symbol symbol_lookup();
|
|
void warn();
|
|
|
|
/* Externally used routines: */
|
|
extern char *hash_get_memory();
|
|
extern char *getlogin();
|
|
extern char *getenv();
|
|
extern struct passwd *getpwnam();
|
|
extern struct passwd *getpwuid();
|
|
extern char *malloc();
|
|
|
|
/*****************************************************************/
|
|
/* Exported routines: */
|
|
/*****************************************************************/
|
|
|
|
/*
|
|
* NOTE: Any returned string pointers should be considered temporary at best.
|
|
* If you want to hang onto the data, make your own private copy of the string!
|
|
*/
|
|
|
|
/*
|
|
* defaults_exists(path_name, status) will return TRUE if Path_Name exists
|
|
* in the database.
|
|
*/
|
|
Bool
|
|
defaults_exists(path_name, status)
|
|
char *path_name; /* Node name to test for existence */
|
|
int *status; /* Status flag */
|
|
{
|
|
clear_status(status);
|
|
return (Bool)(node_lookup_path(path_name, False, status) != NULL);
|
|
}
|
|
|
|
/*
|
|
* defaults_get_boolean(path_name, default, status) will lookup Path_Name
|
|
* in the defaults database and return TRUE if the value is "True", "Yes",
|
|
* "On", "Enabled", "Set", "Activated", or "1". FALSE will be returned if
|
|
* the value is "False", "No", "Off", "Disabled", "Reset", "Cleared",
|
|
* "Deactivated", or "0". If the value is none of the above, a warning
|
|
* message will be displayed and Default will be returned.
|
|
*/
|
|
Bool
|
|
defaults_get_boolean(path_name, default_bool, status)
|
|
char *path_name; /* Path name */
|
|
Bool default_bool; /* Default value */
|
|
int *status; /* Status flag */
|
|
{
|
|
static Defaults_pairs bools[] = {
|
|
"True", (int)True,
|
|
"False", (int)False,
|
|
"Yes", (int)True,
|
|
"No", (int)False,
|
|
"On", (int)True,
|
|
"Off", (int)False,
|
|
"Enabled", (int)True,
|
|
"Disabled", (int)False,
|
|
"Set", (int)True,
|
|
"Reset", (int)False,
|
|
"Cleared", (int)False,
|
|
"Activated", (int)True,
|
|
"Deactivated", (int)False,
|
|
"1", (int)True,
|
|
"0", (int)False,
|
|
NULL, -1,
|
|
};
|
|
char *string_value; /* String value */
|
|
register Bool value; /* Value to return */
|
|
|
|
clear_status(status);
|
|
string_value = defaults_get_string(path_name, (char *)NULL, status);
|
|
if (string_value == NULL){
|
|
return default_bool;
|
|
}
|
|
value = (Bool)defaults_lookup(string_value, bools);
|
|
if ((int)value == -1){
|
|
warn("%s is '%s'; which is an unrecognized boolean value",
|
|
path_name, string_value);
|
|
value = default_bool;
|
|
}
|
|
#ifdef TESTDEFAULTS
|
|
if (defaults->database_dir && value != default_bool) {
|
|
defaults->errors = 0;
|
|
warn("%s: .d=%d .c=%d", path_name, value, default_bool);
|
|
}
|
|
#endif
|
|
return value;
|
|
}
|
|
|
|
/*
|
|
* defaults_get_character(path_name, default, status) will lookup Path_Name in
|
|
* the defaults database and return the resulting character value.
|
|
* Default will be returned if any error occurs.
|
|
*/
|
|
int
|
|
defaults_get_character(path_name, default_character, status)
|
|
char *path_name; /* Full database node path name */
|
|
char default_character; /* Default return value */
|
|
int *status; /* Status flag */
|
|
{
|
|
Node node; /* Resulting node */
|
|
|
|
clear_status(status);
|
|
node = path_lookup(path_name, status);
|
|
if (node == NULL)
|
|
return default_character;
|
|
if (strlen(node->value) != 1){
|
|
warn("%s -- More than one character in character constant",
|
|
path_name);
|
|
return default_character;
|
|
}
|
|
#ifdef TESTDEFAULTS
|
|
if (defaults->database_dir && node->value[0] != default_character) {
|
|
defaults->errors = 0;
|
|
warn("%s: .d=%c .c=%c", path_name, node->value[0], default_character);
|
|
}
|
|
#endif
|
|
return node->value[0];
|
|
}
|
|
|
|
/*
|
|
* defaults_get_child(path_name, status) will return a pointer to the simple
|
|
* name assoicated with the first child of Path_Name. NULL will be returned,
|
|
* if Path_Name does not exist or if Path_Name does not have a first child.
|
|
*/
|
|
char *
|
|
defaults_get_child(path_name, status)
|
|
char *path_name; /* Full name of parent node */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Node from database */
|
|
|
|
clear_status(status);
|
|
/* Find the node child. */
|
|
node = node_lookup_path(path_name, False, status);
|
|
if (node == NULL)
|
|
return NULL;
|
|
node = node->child;
|
|
while ((node != NULL) && (node->deleted))
|
|
node = node->next;
|
|
return (node == NULL) ? NULL : node->name[name_length(node->name) - 1];
|
|
}
|
|
|
|
/*
|
|
* defaults_get_default(path_name, default, status) will return the value
|
|
* associated with Path_Name prior to being overridden by the clients private
|
|
* database. Default is returned if any error occurs.
|
|
*/
|
|
char *
|
|
defaults_get_default(path_name, default_value, status)
|
|
char *path_name; /* Full name of node */
|
|
char *default_value; /* Default node name */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Node from database */
|
|
|
|
clear_status(status);
|
|
node = path_lookup(path_name, status);
|
|
if (node == NULL)
|
|
return default_value;
|
|
return node->default_value;
|
|
}
|
|
|
|
/*
|
|
* defaults_get_enum(path_name, pairs, status) will lookup the value associated
|
|
* with Path_Name and scan the Pairs table and return the associated value.
|
|
* If no match, can be found an error will be generated and the value
|
|
* associated with last entry (i.e. the NULL entry) will be returned. See,
|
|
* defaults_lookup().
|
|
*/
|
|
int
|
|
defaults_get_enum(path_name, pairs, status)
|
|
char *path_name; /* Full database path name */
|
|
Defaults_pairs *pairs; /* Pairs table */
|
|
int *status; /* Status flag */
|
|
{
|
|
return defaults_lookup(defaults_get_string(path_name, (char *)NULL, status),
|
|
pairs);
|
|
}
|
|
|
|
/*
|
|
* defaults_get_enumeration(path_name, default, status) will lookup
|
|
* "Path_Name/VALUE(Path_Name)" in the defaults database and return the
|
|
* resulting string value. Default will be returned if any error occurs.
|
|
*/
|
|
char *
|
|
defaults_get_enumeration(path_name, default_enumeration, status)
|
|
char *path_name; /* Full database node name */
|
|
char *default_enumeration; /* Default enumerate name */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Resulting node */
|
|
char name[MAX_STRING]; /* Temporary name */
|
|
register char *name_pointer; /* Name pointer */
|
|
register Node temp_node; /* Temporary node */
|
|
|
|
clear_status(status);
|
|
node = path_lookup(path_name, status);
|
|
if (node == NULL)
|
|
return default_enumeration;
|
|
name_pointer = name;
|
|
(void)strcpy(name_pointer, path_name);
|
|
(void)strcat(name_pointer, SEP_STR);
|
|
(void)strcat(name_pointer, "$Enumeration");
|
|
temp_node = node_lookup_path(name_pointer, True, status);
|
|
if (temp_node == NULL){
|
|
warn("%s is not an enumeration type", path_name);
|
|
return default_enumeration;
|
|
}
|
|
(void)strcpy(name_pointer, path_name);
|
|
(void)strcat(name_pointer, SEP_STR);
|
|
(void)strcat(name_pointer, node->value);
|
|
temp_node = node_lookup_path(name_pointer, True, status);
|
|
if (temp_node == NULL)
|
|
{
|
|
warn("%s is not a valid enumeration value for %s",
|
|
node->value, path_name);
|
|
return default_enumeration;
|
|
}
|
|
#ifdef TESTDEFAULTS
|
|
if (defaults->database_dir
|
|
&& temp_node->value && default_enumeration
|
|
&& strcmp(temp_node->value, default_enumeration) != 0) {
|
|
defaults->errors = 0;
|
|
warn("%s: .d=%s .c=%s", path_name, temp_node->value, default_enumeration);
|
|
}
|
|
#endif
|
|
return temp_node->value;
|
|
}
|
|
|
|
/*
|
|
* defaults_get_integer(path_name, default, status) will lookup Path_Name in
|
|
* the defaults database and return the resulting integer value.
|
|
* Default will be returned if any error occurs.
|
|
*/
|
|
int
|
|
defaults_get_integer(path_name, default_integer, status)
|
|
char *path_name; /* Full database node name */
|
|
int default_integer; /* Default return value */
|
|
int *status; /* Status flag */
|
|
{
|
|
register char chr; /* Temporary character */
|
|
Bool error; /* TRUE => an error has occurred */
|
|
Bool negative; /* TRUE => Negative number */
|
|
register Node node; /* Resulting node */
|
|
register int number; /* Resultant value */
|
|
register char *pointer; /* Pointer into value */
|
|
|
|
/* Lookup the node */
|
|
clear_status(status);
|
|
node = path_lookup(path_name, status);
|
|
if (node == NULL)
|
|
return default_integer;
|
|
|
|
/* Convert string into integer (with error chacking) */
|
|
error = False;
|
|
pointer = node->value;
|
|
negative = False;
|
|
number = 0;
|
|
chr = *pointer++;
|
|
if (chr == '-'){
|
|
negative = True;
|
|
chr = *pointer++;
|
|
}
|
|
if (chr == '\0')
|
|
error = True;
|
|
while (chr != '\0'){
|
|
if ((chr < '0') || (chr > '9')){
|
|
error = True;
|
|
break;
|
|
}
|
|
number = number * 10 + chr - '0';
|
|
chr = *pointer++;
|
|
}
|
|
if (error){
|
|
warn("%s contains an incorrect integer", path_name);
|
|
return default_integer;
|
|
}
|
|
if (negative)
|
|
number = -number;
|
|
#ifdef TESTDEFAULTS
|
|
if (defaults->database_dir && number != default_integer) {
|
|
defaults->errors = 0;
|
|
warn("%s: .d=%d .c=%d", path_name, number, default_integer);
|
|
}
|
|
#endif
|
|
return number;
|
|
}
|
|
|
|
/*
|
|
* defaults_get_integer_check(path_name, default, mininum, maximum, status)
|
|
* will lookup Path_Name in the defaults database and return the resulting
|
|
* integer value. If the value in the database is not between Minimum and
|
|
* Maximum (inclusive), an error message will be printed. Default will be
|
|
* returned if any error occurs.
|
|
*/
|
|
int
|
|
defaults_get_integer_check(path_name, default_int, minimum, maximum, status)
|
|
char *path_name; /* Full path name of node */
|
|
int default_int; /* Default return value */
|
|
int minimum; /* Minimum value */
|
|
int maximum; /* Maximum value */
|
|
int *status; /* Status flag */
|
|
{
|
|
int value; /* Return value */
|
|
|
|
clear_status(status);
|
|
value = defaults_get_integer(path_name, default_int, status);
|
|
if ((minimum <= value) && (value <= maximum))
|
|
return value;
|
|
else {
|
|
warn("The value of %s is %d which is not between %d and %d",
|
|
path_name, value, minimum, maximum);
|
|
return default_int;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* defaults_get_sibling(path_name, status) will return a pointer to the simple
|
|
* name assoicated with the next sibling of Path_Name. NULL will be returned,
|
|
* if Path_Name does not exist or if Path_Name does not have an
|
|
* next sibling.
|
|
*/
|
|
char *
|
|
defaults_get_sibling(path_name, status)
|
|
char *path_name; /* Full name of parent node */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Node from database */
|
|
|
|
clear_status(status);
|
|
node = node_lookup_path(path_name, False, status);
|
|
if (node == NULL){
|
|
warn("Could not find '%s'", path_name);
|
|
return NULL;
|
|
}
|
|
do node = node->next;
|
|
while ((node != NULL) && node->deleted);
|
|
return (node == NULL) ? NULL : node->name[name_length(node->name) - 1];
|
|
}
|
|
|
|
/*
|
|
* defaults_get_string(path_name, default, status) will lookup and return the
|
|
* string value assocatied with Path_Name in the defaults database.
|
|
* Default will be returned if any error occurs.
|
|
*/
|
|
char *
|
|
defaults_get_string(path_name, default_string, status)
|
|
char *path_name; /* Full database node name */
|
|
char *default_string; /* Default return value */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Resulting node */
|
|
|
|
clear_status(status);
|
|
node = path_lookup(path_name, status);
|
|
#ifdef TESTDEFAULTS
|
|
if (defaults->database_dir && node != NULL
|
|
&& node->value && default_string
|
|
&& strcmp(node->value, default_string) != 0) {
|
|
defaults->errors = 0;
|
|
warn("%s: .d=%s .c=%s", path_name, node->value, default_string);
|
|
}
|
|
#endif
|
|
return (node == NULL) ? default_string : node->value;
|
|
}
|
|
|
|
/*
|
|
* initializes (reads in) the defaults database. defaults_init() will read in
|
|
* the user's private database, i.e., .defaults file, and then read in the
|
|
* master database as well if the value of /Defaults/Read_Defaults_Database
|
|
* is True. defaults_init(True) will read in the master database regardless.
|
|
*/
|
|
void
|
|
defaults_init(read_defaults_database)
|
|
int read_defaults_database;
|
|
{
|
|
if (defaults == NULL){
|
|
defaults_create();
|
|
read_private_database();
|
|
if (read_defaults_database &&
|
|
defaults_get_boolean("/Defaults/Read_Defaults_Database",
|
|
True, (int *)NULL)) {
|
|
read_master_database();
|
|
}
|
|
defaults->test_mode =
|
|
defaults_get_boolean("/Defaults/Test_Mode",
|
|
False, (int *)NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* defaults_lookup(name, pairs) will linearly scan the Pairs data structure
|
|
* looking for Name. The value associated with Name will be returned.
|
|
* If Name can not be found in Pairs, the value assoicated with NULL will
|
|
* be returned. (The Pairs data structure must be terminated with NULL.)
|
|
*/
|
|
int
|
|
defaults_lookup(name, pairs)
|
|
register char *name; /* Name to look up */
|
|
register Defaults_pairs *pairs; /* Default */
|
|
{
|
|
register Defaults_pairs *pair; /* Current pair */
|
|
|
|
for (pair = pairs; pair->name != NULL; pair++){
|
|
if (name == NULL)
|
|
continue;
|
|
if (symbol_equal(name, pair->name))
|
|
break;
|
|
}
|
|
return pair->value;
|
|
}
|
|
|
|
/*
|
|
* defaults_reread(path_name, status) will reread the portion of the database
|
|
* associated with Path_Name.
|
|
*/
|
|
/*ARGSUSED*/
|
|
void
|
|
defaults_reread(path_name, status)
|
|
char *path_name; /* Path name to reread */
|
|
int *status; /* Status flag */
|
|
{
|
|
#ifdef WILL_IMPLEMENT
|
|
Symbol name[MAX_NAME]; /* Temporary name */
|
|
register Symbol *name_pointer; /* Name pointer */
|
|
register Node node; /* Parent node */
|
|
#endif
|
|
|
|
defaults = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* clear_status(status) will clear the status flag if it is non-NULL.
|
|
*/
|
|
void
|
|
clear_status(status)
|
|
int *status; /* Status flag */
|
|
{
|
|
if (status != NULL)
|
|
warn("Somebody passed a non-NULL status code");
|
|
}
|
|
|
|
|
|
/*
|
|
* defaults_create() will intialize the global defaults object.
|
|
*/
|
|
void
|
|
defaults_create()
|
|
{
|
|
Symbol name[1]; /* Empty name */
|
|
register Defaults new_defaults; /* New defaults object */
|
|
extern Hash hash_create();
|
|
|
|
/* Create hash tables. */
|
|
new_defaults = (Defaults)hash_get_memory(sizeof *defaults);
|
|
defaults = new_defaults;
|
|
new_defaults->database_dir = NULL;
|
|
new_defaults->errors = 0;
|
|
new_defaults->nodes = hash_create(250,
|
|
NULL, (CHAR_FUNC)name_equal, name_hash, (INT_FUNC)NULL, NULL, (INT_FUNC)NULL, 7);
|
|
new_defaults->prefix = NULL;
|
|
new_defaults->private_dir = NULL;
|
|
new_defaults->root = node_create();
|
|
new_defaults->symbols = (Hash)hash_create(250,
|
|
NULL, (CHAR_FUNC)symbol_equal, symbol_hash, (INT_FUNC)NULL, NULL, (INT_FUNC)NULL, 7);
|
|
new_defaults->test_mode = False;
|
|
name[0] = NULL;
|
|
(void)hash_insert((Hash)new_defaults->nodes, (caddr_t)name_copy(name), (caddr_t)new_defaults->root);
|
|
}
|
|
|
|
/*
|
|
* get_data(size) will get size words of memory.
|
|
*/
|
|
static long *
|
|
get_data(size)
|
|
int size; /* Number of words to allocate */
|
|
{
|
|
long *data; /* Pointer to beginning of data */
|
|
|
|
data = (long *)hash_get_memory(size<<2); /* Machine dependent! */
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
* name_cat(dest_name, source_name) will concatonate Source_Name onto the
|
|
* end of Dest_Name.
|
|
*/
|
|
static void
|
|
name_cat(dest_name, source_name)
|
|
Symbol *dest_name; /* Destination name */
|
|
Symbol *source_name; /* Source name */
|
|
{
|
|
name_move(dest_name + name_length(dest_name), source_name);
|
|
}
|
|
|
|
/*
|
|
* name_copy(name) will make and return a copy of Name.
|
|
*/
|
|
Name
|
|
name_copy(name)
|
|
Name name; /* Name to copy */
|
|
{
|
|
Name new; /* New name */
|
|
|
|
new = (Name)get_data(name_length(name) + 1);
|
|
name_move(new, name);
|
|
return new;
|
|
}
|
|
|
|
/*
|
|
* name_equal(name1, name2) will return True if Name1 equals Name2.
|
|
*/
|
|
static Bool
|
|
name_equal(name1, name2)
|
|
register Name name1; /* First name */
|
|
register Name name2; /* Second name */
|
|
{
|
|
register Symbol symbol1; /* Symbol from first name */
|
|
register Symbol symbol2; /* Symbol from second name */
|
|
|
|
while (True){
|
|
symbol1 = *name1++;
|
|
symbol2 = *name2++;
|
|
if (symbol1 != symbol2)
|
|
return False;
|
|
if (symbol1 == NULL)
|
|
return True;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* name_hash(name) will return a hash of Name.
|
|
*/
|
|
static int
|
|
name_hash(name)
|
|
register Name name; /* Name to hash */
|
|
{
|
|
register Symbol symbol; /* Symbol from name */
|
|
register int hash; /* Hash value */
|
|
|
|
hash = 0;
|
|
do { symbol = *name++;
|
|
hash += (int)symbol;
|
|
} while (symbol != NULL);
|
|
return hash;
|
|
}
|
|
|
|
/*
|
|
* name_length(name) will return the number of symbols in Name.
|
|
*/
|
|
int
|
|
name_length(name)
|
|
register Name name; /* Name to return length of */
|
|
{
|
|
register int length; /* Length of name */
|
|
|
|
length = 0;
|
|
while (*name++ != NULL)
|
|
length++;
|
|
return length;
|
|
}
|
|
|
|
/*
|
|
* name_move(dest, source) will the name Source over to the name Dest.
|
|
*/
|
|
static int
|
|
name_move(dest, source)
|
|
register Name dest; /* Destination name */
|
|
register Name source; /* Source Name */
|
|
{
|
|
while (*source != NULL)
|
|
*dest++ = *source++;
|
|
*dest = NULL;
|
|
}
|
|
|
|
/*
|
|
* name_parse(in_file, symbols, default_name, name) will parse a node name
|
|
* read from In_File into its component symbols and store the resulting
|
|
* parts into Name. Default symbols will be read from Default_Name. The
|
|
* symbol hash table is Symbols. The number of simple node names in the full
|
|
* node name will be returned. 0 will be returned on an error.
|
|
*/
|
|
/*ARGSUSED*/
|
|
static int
|
|
name_parse(in_file, symbols, default_name, name)
|
|
register FILE *in_file; /* Input file */
|
|
Hash symbols; /* Symbol hash table */
|
|
Name default_name; /* Default name */
|
|
register Name name; /* Place to store resultant name */
|
|
{
|
|
register int chr; /* Temporary character */
|
|
register int default_size; /* Size of default name */
|
|
register Bool fully; /* TRUE => fully specified node name */
|
|
register char *symbol; /* Current symbol */
|
|
register int size; /* Number of parts in name */
|
|
char temp[MAX_STRING]; /* Temporary symbol name */
|
|
|
|
size = 0;
|
|
chr = parse_whitespace(in_file);
|
|
fully = (Bool)(chr == SEP_CHR);
|
|
if (fully){
|
|
/* Fully specified node name. */
|
|
(void) getchr(in_file); /* Dispose of leading '/' */
|
|
/* Process leading default_names. */
|
|
while (True){
|
|
chr = getchr(in_file);
|
|
if (chr != SEP_CHR)
|
|
break;
|
|
if (*default_name == NULL){
|
|
(void)strcpy(temp, SEP_STR);
|
|
(void)strcat(temp, SEP_STR);
|
|
warn("No default available for '%s'", temp);
|
|
*name = NULL;
|
|
return size;
|
|
}
|
|
*name++ = *default_name++;
|
|
size++;
|
|
}
|
|
(void)ungetchr(chr, in_file);
|
|
} else {
|
|
/* Partially specified node name. */
|
|
/* Copy over as many default_names as are available. */
|
|
default_size = 0;
|
|
while (*default_name != NULL){
|
|
*name++ = *default_name++;
|
|
default_size++;
|
|
}
|
|
}
|
|
|
|
/* Process each simple node name. */
|
|
while (chr_letter(chr) || chr_digit(chr)){
|
|
if (parse_symbol(in_file, &temp[0]) == NULL)
|
|
return 0;
|
|
symbol = symbol_lookup(&temp[0]);
|
|
*name++ = symbol;
|
|
size++;
|
|
if (fully){
|
|
*default_name++ = symbol;
|
|
*default_name = NULL;
|
|
}
|
|
chr = getchr(in_file);
|
|
if ((chr == ' ') || (chr == '\t') ||
|
|
(chr == '\n') || (chr == EOF))
|
|
break;
|
|
if (chr == SEP_CHR){
|
|
chr = getchr(in_file);
|
|
(void)ungetchr(chr, in_file);
|
|
}
|
|
else {
|
|
warn("'%c' found in node name", chr);
|
|
break;
|
|
}
|
|
}
|
|
(void)ungetchr(chr, in_file);
|
|
*name = NULL;
|
|
if (size > 0)
|
|
size += default_size;
|
|
return size;
|
|
}
|
|
|
|
/*
|
|
* name_quick_parse(path_name, name) will quickly parse Path_Name and store
|
|
* the result into Name.
|
|
*/
|
|
void
|
|
name_quick_parse(path_name, name)
|
|
char *path_name; /* Full name string */
|
|
Name name; /* Place to store parsed name */
|
|
{
|
|
register char chr; /* Temporary character */
|
|
register char *full_pointer; /* Pointer into full name */
|
|
register Name name_pointer; /* Pointer into name */
|
|
char temp[MAX_STRING]; /* Temporary name */
|
|
register char *temp_pointer; /* Pointer into temporary name */
|
|
|
|
/* Build up the name. */
|
|
full_pointer = path_name;
|
|
if (*full_pointer++ != SEP_CHR){
|
|
warn("'%s' does not start with '%c'.", path_name, SEP_CHR);
|
|
name[0] = NULL;
|
|
return;
|
|
}
|
|
name_pointer = name;
|
|
while (True){
|
|
temp_pointer = &temp[0];
|
|
while (True){
|
|
chr = *full_pointer++;
|
|
if ((chr == SEP_CHR) || (chr == '\0'))
|
|
break;
|
|
if (chr_letter(chr) || chr_digit(chr))
|
|
*temp_pointer++ = chr;
|
|
else {
|
|
warn("'%c' is not permitted in %s",
|
|
chr, path_name);
|
|
name[0] = NULL;
|
|
return;
|
|
}
|
|
}
|
|
*temp_pointer = '\0';
|
|
*name_pointer++ = symbol_lookup(&temp[0]);
|
|
if (chr == '\0')
|
|
break;
|
|
}
|
|
*name_pointer = NULL;
|
|
}
|
|
|
|
/*
|
|
* name_unparse(name, data) will write the string corresponding to Name
|
|
* into Data. If Data is NULL, a new string will be allocated.
|
|
*/
|
|
char *
|
|
name_unparse(name, data)
|
|
register Name name; /* Name to unparse */
|
|
register char *data; /* Data to unparse */
|
|
{
|
|
register int size; /* Size of string */
|
|
register Name temp; /* Temporary name */
|
|
|
|
if (name == NULL){
|
|
if (data == NULL)
|
|
data = hash_get_memory(2);
|
|
(void)strcpy(data, SEP_STR);
|
|
return data;
|
|
}
|
|
if (data == NULL){
|
|
size = 0;
|
|
temp = name;
|
|
while (*temp != NULL)
|
|
size += strlen(*temp++) + 1;
|
|
data = hash_get_memory(size + 1);
|
|
}
|
|
data[0] = '\0';
|
|
while (*name != NULL){
|
|
(void)strcat(data, SEP_STR);
|
|
(void)strcat(data, *name++);
|
|
}
|
|
return data;
|
|
}
|
|
|
|
/*
|
|
* node_create() will create and return an empty node.
|
|
*/
|
|
static Node
|
|
node_create()
|
|
{
|
|
register Node node; /* New node */
|
|
|
|
node = (Node)hash_get_memory(sizeof *node);
|
|
node->child = NULL;
|
|
node->default_value = DEFAULTS_UNDEFINED;
|
|
node->deleted = False;
|
|
node->file = False;
|
|
node->name = NULL;
|
|
node->next = NULL;
|
|
node->parent = NULL;
|
|
node->private = False;
|
|
node->value = DEFAULTS_UNDEFINED;
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* node_delete(node) will cause Node and its descendentes to be "deleted".
|
|
* The nodes will only be marked as deleted. No storage will be deallocated.
|
|
*/
|
|
void
|
|
node_delete(node)
|
|
register Node node; /* Node to delete */
|
|
{
|
|
node->deleted = True;
|
|
for (node = node->child; node != NULL; node = node->next)
|
|
node_delete(node);
|
|
}
|
|
|
|
/*
|
|
* node_delete_private(node) will cause Node and its descendentes to be
|
|
* "deleted". The nodes will only be marked as deleted. No storage will be
|
|
* deallocated.
|
|
*/
|
|
void
|
|
node_delete_private(node)
|
|
register Node node; /* Node to delete */
|
|
{
|
|
|
|
if (node->private)
|
|
node->deleted = True;
|
|
for (node = node->child; node != NULL; node = node->next)
|
|
node_delete_private(node);
|
|
}
|
|
|
|
/*
|
|
* node_find_name(name, multiple, status) will return the node associated with
|
|
* Name from the defaults database. The important side effect of this routine
|
|
* is that it makes for sure that all the nodes between Name and the root node
|
|
* both exist and are properly threaded together. If Multiple is TRUE,
|
|
* multiple lookups will be performed to prefixes.
|
|
*/
|
|
/*ARGSUSED*/
|
|
Node
|
|
node_find_name(name, multiple, status)
|
|
register Name name; /* Name to lookup/enter */
|
|
Bool multiple; /* TRUE => multiple prefix lookups */
|
|
int *status; /* Status flag */
|
|
{
|
|
register int length; /* Name length */
|
|
register Node next; /* Next node at same level */
|
|
register Node node; /* Node that is looked up */
|
|
char path_name[MAX_STRING]; /* Path name */
|
|
Node parent; /* Parent node */
|
|
Symbol symbol; /* Node symbol */
|
|
|
|
if (status != NULL){
|
|
(void)name_unparse(name, path_name);
|
|
warn("Status is non-NULL in %s", path_name);
|
|
}
|
|
|
|
if (defaults == NULL)
|
|
defaults_init(True);
|
|
|
|
if (defaults->test_mode)
|
|
return NULL;
|
|
|
|
/* The root node is special. */
|
|
if (name[0] == NULL)
|
|
return defaults->root;
|
|
|
|
/* Just return it if it is already in the Nodes table. */
|
|
read_lazy(name);
|
|
node = (Node)hash_lookup(defaults->nodes, (caddr_t)name);
|
|
if (node != NULL){
|
|
node->deleted = False;
|
|
return node;
|
|
}
|
|
|
|
/* Get the parent node. */
|
|
length = name_length(name);
|
|
symbol = name[length - 1];
|
|
name[length - 1] = NULL;
|
|
parent = node_find_name(name, False, status);
|
|
name[length - 1] = symbol;
|
|
|
|
/* Create the new node. */
|
|
node = node_create();
|
|
name = name_copy(name);
|
|
node->name = name;
|
|
node->parent = parent;
|
|
|
|
/* Thread this node onto the end of the parent next list. */
|
|
next = parent->child;
|
|
if (next == NULL)
|
|
parent->child = node;
|
|
else {
|
|
while (next->next != NULL)
|
|
next = next->next;
|
|
next->next = node;
|
|
}
|
|
|
|
/* Insert the node into the Nodes hash table. */
|
|
(void)hash_insert(defaults->nodes, name, node);
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* node_lookup_name(name, multiple, status) will lookup Name in the defaults
|
|
* database and return the associated node. If Path_Name is not in the
|
|
* database, NULL will be returned.
|
|
*/
|
|
Node
|
|
node_lookup_name(name, multiple, status)
|
|
register Name name; /* Name to lookup */
|
|
Bool multiple; /* TRUE => multiple lookups */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Resultant node */
|
|
char path_name[MAX_STRING]; /* Path name string */
|
|
Symbol temp[MAX_NAME]; /* Temporay name */
|
|
|
|
if (defaults == NULL)
|
|
defaults_init(True);
|
|
if (status != NULL){
|
|
(void)name_unparse(name, path_name);
|
|
warn("Status non-NULL in %s", path_name);
|
|
}
|
|
|
|
if (defaults->test_mode)
|
|
return NULL;
|
|
|
|
read_lazy(name);
|
|
if (multiple && (defaults->prefix != NULL)){
|
|
temp[0] = NULL;
|
|
name_cat(temp, defaults->prefix);
|
|
name_cat(temp, name);
|
|
node = (Node)hash_lookup(defaults->nodes, temp);
|
|
if ((node != NULL) && (!node->deleted))
|
|
return node;
|
|
}
|
|
node = (Node)hash_lookup(defaults->nodes, name);
|
|
if ((node != NULL) && (!node->deleted))
|
|
return node;
|
|
else return NULL;
|
|
}
|
|
|
|
/*
|
|
* node_lookup_path(path_name, multiple, status) will lookup Path_name in the
|
|
* defaults database and return the associated node. If Path_Name is not in
|
|
* the database, NULL will be returned.
|
|
*/
|
|
Node
|
|
node_lookup_path(path_name, multiple, status)
|
|
char *path_name; /* Full path name */
|
|
Bool multiple; /* TRUE => multiple lookups */
|
|
int *status; /* Status flag */
|
|
{
|
|
Symbol name[MAX_NAME]; /* Node name */
|
|
|
|
if (defaults == NULL)
|
|
defaults_init(True);
|
|
if (strcmp(path_name, SEP_STR) == 0)
|
|
return defaults->root;
|
|
name_quick_parse(path_name, name);
|
|
return node_lookup_name(name, multiple, status);
|
|
}
|
|
|
|
|
|
/*
|
|
* path_lookup(path_name, status) will lookup Path_Name in the defaults
|
|
* database and return the associated node. If Path_Name is not in the
|
|
* database, a warning message will be printed on the console and NULL will
|
|
* be returned.
|
|
*/
|
|
Node
|
|
path_lookup(path_name, status)
|
|
char *path_name; /* Full name */
|
|
int *status; /* Status flag */
|
|
{
|
|
register Node node; /* Resultant node */
|
|
|
|
node = node_lookup_path(path_name, True, status);
|
|
if (node == NULL && defaults->database_dir)
|
|
warn("'%s' is not in defaults database", path_name);
|
|
return node;
|
|
}
|
|
|
|
/*
|
|
* read(file_name, prefix, private) will read in data into the defaults
|
|
* database from the file File_Name. Only path names that begin with Prefix
|
|
* will be read into the database. If Private is True, the file being read
|
|
* corresponds to a private database file. True will be returned if File_Name
|
|
* could not be opened. Otherwise, False will be returned.
|
|
*/
|
|
static Bool
|
|
read(file_name, prefix, private)
|
|
char *file_name; /* File name to read */
|
|
Name prefix; /* Prefix path that must match first */
|
|
Bool private; /* TRUE => mark nodes as private */
|
|
{
|
|
register int chr; /* Temporary character */
|
|
Symbol default_name[MAX_NAME];/* Default name */
|
|
Bool error; /* TRUE => error has occured */
|
|
char huge[HUGE_STRING]; /* Huge string for W. Teitelman */
|
|
register FILE *in_file; /* Input file name */
|
|
register int line; /* Current line number */
|
|
Symbol name[MAX_NAME]; /* Full name of node */
|
|
register Name name_pointer; /* Pointer into name */
|
|
register Node node; /* Node associated with name */
|
|
register Name prefix_pointer; /* Pointer into prefix */
|
|
Hash symbols; /* String table */
|
|
char temp[MAX_STRING];/* Temporary symbol */
|
|
char *value; /* Node value */
|
|
int version; /* Version number */
|
|
|
|
in_file = fopen(file_name, "r");
|
|
if (in_file == NULL)
|
|
return True;
|
|
line = 1;
|
|
|
|
/* Make sure the version number is correct. */
|
|
error = False;
|
|
if (parse_symbol(in_file, temp) == NULL)
|
|
error = True;
|
|
else { version = parse_int(in_file, &error);
|
|
(void)parse_eol(in_file);
|
|
}
|
|
if (error || !symbol_equal(temp, VERSION_TAG)){
|
|
warn("Line 1 in %s is not a correctly formatted defaults file",
|
|
file_name);
|
|
(void)fclose(in_file);
|
|
return False;
|
|
}
|
|
if (version != VERSION_NUMBER){
|
|
warn("Line 1 in %s has version number %d rather than %d",
|
|
file_name, version, VERSION_NUMBER);
|
|
(void)fclose(in_file);
|
|
return False;
|
|
}
|
|
if (defaults == NULL)
|
|
defaults_init(True);
|
|
symbols = defaults->symbols;
|
|
default_name[0] = NULL;
|
|
while (True){
|
|
/* Dispatch on first printing character. */
|
|
chr = parse_whitespace(in_file);
|
|
if ((chr == '\n') || (chr == ';')){
|
|
(void)parse_eol(in_file);
|
|
line++;
|
|
continue;
|
|
}
|
|
if (chr == EOF)
|
|
break;
|
|
|
|
/* Grab the name */
|
|
if (name_parse(in_file, symbols, default_name, name) == 0){
|
|
warn("Could not parse a node name on line %d from %s",
|
|
line, file_name);
|
|
(void)parse_eol(in_file);
|
|
line++;
|
|
continue;
|
|
}
|
|
|
|
/* See whether name matches prefix. */
|
|
name_pointer = name;
|
|
prefix_pointer = prefix;
|
|
while (*prefix_pointer == *name_pointer){
|
|
prefix_pointer++;
|
|
name_pointer++;
|
|
}
|
|
if (*prefix_pointer != NULL){
|
|
/* Prefix does not match. */
|
|
(void)parse_eol(in_file);
|
|
line++;
|
|
continue;
|
|
}
|
|
|
|
/* Prefix matches, so look up node and enter value. */
|
|
node = node_find_name(name, False, (int *)NULL);
|
|
if (node == NULL){
|
|
/* This really should not happen. */
|
|
(void)name_unparse(name, temp);
|
|
warn("Problem entering '%s' into database on line %d",
|
|
temp, line);
|
|
(void)parse_eol(in_file);
|
|
line++;
|
|
break;
|
|
}
|
|
chr = parse_whitespace(in_file);
|
|
value = NULL;
|
|
if (chr == '\n')
|
|
value = DEFAULTS_UNDEFINED;
|
|
else if (chr == '"'){
|
|
value = parse_string(in_file, huge, HUGE_STRING);
|
|
if (value != NULL)
|
|
value = defaults_strdup(huge);
|
|
}
|
|
if (value == NULL){
|
|
(void)name_unparse(name, temp);
|
|
warn("%s Could not be assigned a value", temp);
|
|
value = "";
|
|
}
|
|
if (private){
|
|
node->private = True;
|
|
node->value = value;
|
|
} else {
|
|
node->default_value = value;
|
|
if (!node->private)
|
|
node->value = value;
|
|
}
|
|
(void)parse_eol(in_file);
|
|
line++;
|
|
}
|
|
(void)fclose(in_file);
|
|
return False;
|
|
}
|
|
|
|
/*
|
|
* read_lazy(name) will cause all the nodes associated with Name to be read
|
|
* in, if they have not already been read in.
|
|
*/
|
|
static void
|
|
read_lazy(name)
|
|
Name name; /* Name to use */
|
|
{
|
|
register Node node; /* Temporary node */
|
|
Symbol temp_name[2]; /* Temporary name */
|
|
|
|
temp_name[0] = name[0];
|
|
temp_name[1] = NULL;
|
|
node = (Node)hash_lookup(defaults->nodes, temp_name);
|
|
if ((node != NULL) && (node->file))
|
|
read_master(name[0]);
|
|
}
|
|
|
|
/*
|
|
* read_master(file_name) will read in File_Name from the master database.
|
|
*/
|
|
void
|
|
read_master(file_name)
|
|
char *file_name; /* File name to read in */
|
|
{
|
|
register Node node; /* Database node */
|
|
char name[MAX_STRING]; /* Temporary file name */
|
|
Symbol prefix[2]; /* Empty prefix */
|
|
|
|
if (defaults->database_dir == NULL)
|
|
return;
|
|
prefix[0] = symbol_lookup(file_name);
|
|
prefix[1] = NULL;
|
|
node = (Node)hash_lookup(defaults->nodes, prefix);
|
|
if (node != NULL)
|
|
node->file = False;
|
|
|
|
/* Read from private database. */
|
|
if (defaults->private_dir != NULL){
|
|
(void)strcpy(name, defaults->private_dir);
|
|
(void)strcat(name, file_name);
|
|
(void)strcat(name, ".d");
|
|
prefix[0] = NULL;
|
|
if (!read(name, prefix, False))
|
|
return;
|
|
}
|
|
|
|
/* Read from master database. */
|
|
(void)strcpy(name, defaults->database_dir);
|
|
(void)strcat(name, file_name);
|
|
(void)strcat(name, ".d");
|
|
prefix[0] = NULL;
|
|
if (read(name, prefix, False))
|
|
warn("Could not open database file '%s'", name);
|
|
}
|
|
|
|
/*
|
|
* read_master_database() will find the master database directory and enter
|
|
* nodes into the database for each file in the master database directory.
|
|
*/
|
|
void
|
|
read_master_database()
|
|
{
|
|
char *database_dir; /* Database directory name */
|
|
Node node; /* Current node */
|
|
char *private_dir; /* Private database directory */
|
|
|
|
/* Find the defaults directory. */
|
|
database_dir = defaults->database_dir;
|
|
if (database_dir == NULL){
|
|
node = node_lookup_path("/Defaults/Directory", True, (int *)NULL);
|
|
if (node == NULL)
|
|
database_dir = "/usr/lib/defaults/";
|
|
else database_dir = slash_append(node->value);
|
|
defaults->database_dir = database_dir;
|
|
}
|
|
read_master_database1(database_dir);
|
|
|
|
/* Find the private defaults directory. */
|
|
private_dir = defaults->private_dir;
|
|
if (private_dir == NULL){
|
|
node = node_lookup_path("/Defaults/Private_Directory",
|
|
True, (int *)NULL);
|
|
if (node == NULL)
|
|
private_dir = NULL;
|
|
else private_dir = slash_append(node->value);
|
|
defaults->private_dir = private_dir;
|
|
}
|
|
if (private_dir != NULL)
|
|
read_master_database1(private_dir);
|
|
}
|
|
|
|
/*
|
|
* read_master_database1(dir_name) will read in the *.d file names contained
|
|
* in the Dir_Name directory.
|
|
*/
|
|
static void
|
|
read_master_database1(dir_name)
|
|
char *dir_name; /* Directory name */
|
|
{
|
|
register DIR *dir; /* Default directory */
|
|
register struct direct *dir_entry; /* Directory entry */
|
|
Symbol name[MAX_NAME]; /* Name to create */
|
|
register Node node; /* Current node */
|
|
register char *pointer; /* Pointer into file name */
|
|
int size; /* Size of string */
|
|
char symbol[MAX_STRING]; /* Temporary symbol */
|
|
|
|
dir = opendir(dir_name);
|
|
if (dir == NULL){
|
|
warn("Could not find defaults database directory %s\n", dir_name);
|
|
warn("Suppressing subsequent error messages.\n");
|
|
defaults->errors = 1000000; /* A big number */
|
|
return;
|
|
}
|
|
|
|
/* Scan the database for all the top level nodes. */
|
|
name[1] = NULL;
|
|
while (True){
|
|
dir_entry = readdir(dir);
|
|
if (dir_entry == NULL)
|
|
break;
|
|
pointer = dir_entry->d_name;
|
|
size = strlen(pointer);
|
|
if ((size < 3) || (strcmp(&pointer[size - 2], ".d") != 0))
|
|
continue;
|
|
(void)strcpy(symbol, pointer);
|
|
symbol[size - 2] = '\0';
|
|
name[0] = symbol_lookup(symbol);
|
|
node = node_lookup_name(name, False, (int *)NULL);
|
|
if (node == NULL)
|
|
node = node_find_name(name, False, (int *)NULL);
|
|
if (node == NULL)
|
|
warn("Could not create node '%s'\n");
|
|
else node->file = True;
|
|
}
|
|
closedir(dir);
|
|
}
|
|
|
|
/*
|
|
* read_private_database() will read in env var DEFAULTS_FILE
|
|
*/
|
|
void
|
|
read_private_database()
|
|
{
|
|
char file_name[MAX_STRING]; /* Local defaults file name */
|
|
Symbol prefix[1]; /* Empty prefix */
|
|
char *temp;
|
|
|
|
file_name[0] = '0';
|
|
if ((temp = getenv("DEFAULTS_FILE")) != NULL) {
|
|
(void)strcpy(file_name, temp);
|
|
} else {
|
|
if ((temp = getlogindir()) != NULL);
|
|
(void)strcpy(file_name, temp);
|
|
(void)strcat(file_name, "/.defaults");
|
|
}
|
|
prefix[0] = NULL;
|
|
read(file_name, prefix, True);
|
|
}
|
|
|
|
|
|
/*
|
|
* slash_append(text) will return make sure that Text has a slash ('/')
|
|
* on the end.
|
|
*/
|
|
char *
|
|
slash_append(text)
|
|
register char *text; /* String to append to */
|
|
{
|
|
char temp[MAX_STRING]; /* Maximum string length */
|
|
|
|
if (text[strlen(text) - 1] == '/')
|
|
return text;
|
|
(void)strcpy(temp, text);
|
|
(void)strcat(temp, "/");
|
|
return symbol_copy(temp);
|
|
}
|
|
|
|
|
|
/*
|
|
* symbol_copy(symbol) will make and return a copy of Symbol.
|
|
*/
|
|
char *
|
|
symbol_copy(symbol)
|
|
char *symbol; /* Symbol to copy */
|
|
{
|
|
register char *new; /* New symbol */
|
|
|
|
new = hash_get_memory(strlen(symbol) + 1);
|
|
(void)strcpy(new, symbol);
|
|
return new;
|
|
}
|
|
|
|
/*
|
|
* symbol_equal(symbol1, symbol2) will return True if Symbol1 equals Symbol2.
|
|
*/
|
|
Bool
|
|
symbol_equal(symbol1, symbol2)
|
|
register char *symbol1; /* First symbol */
|
|
register char *symbol2; /* Second symbol */
|
|
{
|
|
register char chr1; /* Character from first symbol */
|
|
register char chr2; /* Character from second symbol */
|
|
|
|
while (True){
|
|
chr1 = *symbol1++;
|
|
if (('A' <= chr1) && (chr1 <= 'Z'))
|
|
chr1 += 'a' - 'A';
|
|
chr2 = *symbol2++;
|
|
if (('A' <= chr2) && (chr2 <= 'Z'))
|
|
chr2 += 'a' - 'A';
|
|
if (chr1 != chr2)
|
|
return False;
|
|
if (chr1 == '\0')
|
|
return True;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* symbol_hash(symbol) will return a hash of Symbol.
|
|
*/
|
|
static int
|
|
symbol_hash(symbol)
|
|
Symbol symbol; /* Symbol to hash */
|
|
{
|
|
register char chr; /* Character from symbol */
|
|
register int hash; /* Hash value */
|
|
|
|
hash = 0;
|
|
do { chr = *symbol++;
|
|
if (('A' <= chr) && (chr <= 'Z'))
|
|
chr += 'a' - 'A';
|
|
hash += chr;
|
|
} while (chr != '\0');
|
|
return hash;
|
|
}
|
|
|
|
/*
|
|
* symbol_lookup(symbol) will return the conical value for Symbol from
|
|
* the symbols hash table.
|
|
*/
|
|
Symbol
|
|
symbol_lookup(symbol)
|
|
Symbol symbol; /* Symbol to lookup */
|
|
{
|
|
register Symbol new; /* New symbol */
|
|
|
|
if (defaults == NULL)
|
|
defaults_init(True);
|
|
new = (char *)hash_lookup(defaults->symbols, (caddr_t)symbol);
|
|
if (new == NULL){
|
|
new = symbol_copy(symbol);
|
|
(void)hash_insert(defaults->symbols, (caddr_t)new, (caddr_t)new);
|
|
}
|
|
return new;
|
|
}
|
|
|
|
|
|
/*
|
|
* This is here only because this file seemed a convenient place
|
|
* to move some data into. The data came from defaults_put.c,
|
|
* which we want to compile using the `-R' switch. Therefore,
|
|
* that file cannot contain even the tiniest smidgen of data.
|
|
*/
|
|
Defaults_pairs warn_error_action[] = {
|
|
"Continue", 1,
|
|
"Abort", 2,
|
|
"Suppress", 3,
|
|
NULL, 1,
|
|
};
|