2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-30 22:05:23 +00:00

Make option state support more general.

This commit is contained in:
Ted Lemon
1999-04-05 15:40:59 +00:00
parent 0d252fd9bf
commit c9605ddb0b

View File

@@ -22,7 +22,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: options.c,v 1.37 1999/03/16 05:50:35 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; "$Id: options.c,v 1.38 1999/04/05 15:40:59 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#define DHCP_OPTION_DATA #define DHCP_OPTION_DATA
@@ -40,8 +40,11 @@ int parse_options (packet)
int i; int i;
struct option_cache *op = (struct option_cache *)0; struct option_cache *op = (struct option_cache *)0;
/* Initially, zero all option pointers. */ /* Allocate a new option state. */
memset (&packet -> options, 0, sizeof (packet -> options)); if (!option_state_allocate (&packet -> options, "parse_options")) {
packet -> options_valid = 0;
return 0;
}
/* If we don't see the magic cookie, there's nothing to parse. */ /* If we don't see the magic cookie, there's nothing to parse. */
if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) { if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
@@ -59,7 +62,7 @@ int parse_options (packet)
/* If we parsed a DHCP Option Overload option, parse more /* If we parsed a DHCP Option Overload option, parse more
options out of the buffer(s) containing them. */ options out of the buffer(s) containing them. */
if (packet -> options_valid && if (packet -> options_valid &&
(op = lookup_option (packet -> options.dhcp_hash, (op = lookup_option (&dhcp_universe, packet -> options,
DHO_DHCP_OPTION_OVERLOAD))) { DHO_DHCP_OPTION_OVERLOAD))) {
if (op -> data.data [0] & 1) { if (op -> data.data [0] & 1) {
if (!parse_option_buffer if (!parse_option_buffer
@@ -95,7 +98,7 @@ int parse_option_buffer (packet, buffer, length)
struct buffer *bp = (struct buffer *)0; struct buffer *bp = (struct buffer *)0;
if (!buffer_allocate (&bp, length, "parse_option_buffer")) { if (!buffer_allocate (&bp, length, "parse_option_buffer")) {
log_error ("parse_option_buffer: no memory for option buffer."); log_error ("no memory for option buffer.");
return 0; return 0;
} }
memcpy (bp -> data, buffer, length); memcpy (bp -> data, buffer, length);
@@ -114,9 +117,8 @@ int parse_option_buffer (packet, buffer, length)
/* If the length is outrageous, the options are bad. */ /* If the length is outrageous, the options are bad. */
if (offset + len + 2 > length) { if (offset + len + 2 > length) {
log_error ("Option %s length %d overflows input buffer.", log_error ("Client option %s (%d) larger than buffer.",
dhcp_options [code].name, dhcp_options [code].name, len);
len);
buffer_dereference (&bp, "parse_option_buffer"); buffer_dereference (&bp, "parse_option_buffer");
return 0; return 0;
} }
@@ -126,7 +128,7 @@ int parse_option_buffer (packet, buffer, length)
if (code == DHO_DHCP_AGENT_OPTIONS) { if (code == DHO_DHCP_AGENT_OPTIONS) {
if (!parse_agent_information_option if (!parse_agent_information_option
(packet, len, buffer + offset + 2)) { (packet, len, buffer + offset + 2)) {
log_error ("malformed agent information option."); log_error ("bad agent information option.");
buffer_dereference (&bp, buffer_dereference (&bp,
"parse_option_buffer"); "parse_option_buffer");
return 0; return 0;
@@ -134,8 +136,8 @@ int parse_option_buffer (packet, buffer, length)
} else { } else {
if (!option_cache_allocate (&op, if (!option_cache_allocate (&op,
"parse_option_buffer")) { "parse_option_buffer")) {
log_error ("Can't allocate storage for option %s.", log_error ("No memory for option %s.",
dhcp_options [code].name); dhcp_options [code].name);
buffer_dereference (&bp, buffer_dereference (&bp,
"parse_option_buffer"); "parse_option_buffer");
return 0; return 0;
@@ -161,7 +163,7 @@ int parse_option_buffer (packet, buffer, length)
op -> option = &dhcp_options [code]; op -> option = &dhcp_options [code];
/* Now store the option. */ /* Now store the option. */
save_option (packet -> options.dhcp_hash, op); save_option (&dhcp_universe, packet -> options, op);
/* And let go of our reference. */ /* And let go of our reference. */
option_cache_dereference (&op, option_cache_dereference (&op,
@@ -196,7 +198,7 @@ int parse_agent_information_option (packet, len, data)
dmalloc (op [1] + 1 + sizeof *t, dmalloc (op [1] + 1 + sizeof *t,
"parse_agent_information_option"); "parse_agent_information_option");
if (!t) if (!t)
log_fatal ("can't allocate space for option tag data."); log_fatal ("no memory for option tag data.");
/* Link it in at the tail of the list. */ /* Link it in at the tail of the list. */
t -> next = (struct option_tag *)0; t -> next = (struct option_tag *)0;
@@ -215,7 +217,8 @@ int parse_agent_information_option (packet, len, data)
log_fatal ("can't allocate space for agent option structure."); log_fatal ("can't allocate space for agent option structure.");
/* Find the tail of the list. */ /* Find the tail of the list. */
for (tail = &packet -> options.agent_options; for (tail = ((struct agent_options **)
&packet -> options -> universes [agent_universe.index]);
*tail; tail = &((*tail) -> next)) *tail; tail = &((*tail) -> next))
; ;
*tail = a; *tail = a;
@@ -230,13 +233,12 @@ int parse_agent_information_option (packet, len, data)
three seperate buffers if needed. This allows us to cons up a set three seperate buffers if needed. This allows us to cons up a set
of vendor options using the same routine. */ of vendor options using the same routine. */
int cons_options (inpacket, outpacket, mms, options, int cons_options (inpacket, outpacket,
agent_options, overload, terminate, bootpp, prl) mms, options, overload, terminate, bootpp, prl)
struct packet *inpacket; struct packet *inpacket;
struct dhcp_packet *outpacket; struct dhcp_packet *outpacket;
int mms; int mms;
struct option_state *options; struct option_state *options;
struct agent_options *agent_options;
int overload; /* Overload flags that may be set. */ int overload; /* Overload flags that may be set. */
int terminate; int terminate;
int bootpp; int bootpp;
@@ -253,7 +255,7 @@ int cons_options (inpacket, outpacket, mms, options,
int i; int i;
struct option_cache *op; struct option_cache *op;
struct data_string ds; struct data_string ds;
pair pp; pair pp, *hash;
memset (&ds, 0, sizeof ds); memset (&ds, 0, sizeof ds);
@@ -262,10 +264,10 @@ int cons_options (inpacket, outpacket, mms, options,
one in the packet. */ one in the packet. */
if (!mms && inpacket && if (!mms && inpacket &&
(op = lookup_option (inpacket -> options.dhcp_hash, (op = lookup_option (&dhcp_universe, inpacket -> options,
DHO_DHCP_MAX_MESSAGE_SIZE))) { DHO_DHCP_MAX_MESSAGE_SIZE))) {
evaluate_option_cache (&ds, inpacket, evaluate_option_cache (&ds, inpacket,
&inpacket -> options, op); inpacket -> options, op);
if (ds.len >= sizeof (u_int16_t)) if (ds.len >= sizeof (u_int16_t))
mms = getUShort (ds.data); mms = getUShort (ds.data);
data_string_forget (&ds, "cons_options"); data_string_forget (&ds, "cons_options");
@@ -322,8 +324,8 @@ int cons_options (inpacket, outpacket, mms, options,
/* Now just tack on the list of all the options we have, /* Now just tack on the list of all the options we have,
and any duplicates will be eliminated. */ and any duplicates will be eliminated. */
for (i = 0; i < OPTION_HASH_SIZE; i++) { for (i = 0; i < OPTION_HASH_SIZE; i++) {
for (pp = options -> dhcp_hash [i]; hash = options -> universes [dhcp_universe.index];
pp; pp = pp -> cdr) { for (pp = hash [i]; pp; pp = pp -> cdr) {
op = (struct option_cache *)(pp -> car); op = (struct option_cache *)(pp -> car);
if (priority_len < PRIORITY_COUNT) if (priority_len < PRIORITY_COUNT)
priority_list [priority_len++] = priority_list [priority_len++] =
@@ -409,14 +411,17 @@ int cons_options (inpacket, outpacket, mms, options,
/* We tack any agent options onto the end of the packet after /* We tack any agent options onto the end of the packet after
we've put it together. */ we've put it together. */
if (agent_options) { if (options -> universe_count > agent_universe.index &&
options -> universes [agent_universe.index]) {
int len = 0; int len = 0;
struct agent_options *a; struct agent_options *a;
struct option_tag *o; struct option_tag *o;
/* Cycle through the options, appending them to the /* Cycle through the options, appending them to the
buffer. */ buffer. */
for (a = options -> agent_options; a; a = a -> next) { for (a = ((struct agent_options *)
options -> universes [agent_universe.index]);
a; a = a -> next) {
if (agentix + a -> length + 3 + DHCP_FIXED_LEN <= if (agentix + a -> length + 3 + DHCP_FIXED_LEN <=
dhcp_max_agent_option_packet_length) { dhcp_max_agent_option_packet_length) {
outpacket -> options [agentix++] outpacket -> options [agentix++]
@@ -491,7 +496,7 @@ int store_options (buffer, buflen, options, priority_list, priority_len,
int length; int length;
/* If no data is available for this option, skip it. */ /* If no data is available for this option, skip it. */
if (!(oc = lookup_option (options -> dhcp_hash, code))) { if (!(oc = lookup_option (&dhcp_universe, options, code))) {
continue; continue;
} }
@@ -595,7 +600,7 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
/* Figure out the size of the data. */ /* Figure out the size of the data. */
for (i = 0; dhcp_options [code].format [i]; i++) { for (i = 0; dhcp_options [code].format [i]; i++) {
if (!numhunk) { if (!numhunk) {
log_error ("%s: Excess information in format string: %s\n", log_error ("%s: Extra codes in format string: %s\n",
dhcp_options [code].name, dhcp_options [code].name,
&(dhcp_options [code].format [i])); &(dhcp_options [code].format [i]));
break; break;
@@ -718,7 +723,8 @@ char *pretty_print_option (code, data, len, emit_commas, emit_quotes)
strcpy (op, *dp++ ? "true" : "false"); strcpy (op, *dp++ ? "true" : "false");
break; break;
default: default:
log_error ("Unexpected format code %c", fmtbuf [j]); log_error ("Unexpected format code %c",
fmtbuf [j]);
} }
op += strlen (op); op += strlen (op);
if (j + 1 < numelem && comma != ':') if (j + 1 < numelem && comma != ':')
@@ -753,20 +759,21 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
tp.haddr = hfrom; tp.haddr = hfrom;
if (packet -> hlen > sizeof packet -> chaddr) { if (packet -> hlen > sizeof packet -> chaddr) {
log_info ("Discarding packet with bogus hardware address length."); log_info ("Discarding packet with bogus hlen.");
return; return;
} }
if (!parse_options (&tp)) { if (!parse_options (&tp)) {
option_state_dereference (&tp.options); if (tp.options)
option_state_dereference (&tp.options, "do_packet");
return; return;
} }
if (tp.options_valid && if (tp.options_valid &&
(op = lookup_option (tp.options.dhcp_hash, (op = lookup_option (&dhcp_universe, tp.options,
DHO_DHCP_MESSAGE_TYPE))) { DHO_DHCP_MESSAGE_TYPE))) {
struct data_string dp; struct data_string dp;
memset (&dp, 0, sizeof dp); memset (&dp, 0, sizeof dp);
evaluate_option_cache (&dp, &tp, &tp.options, op); evaluate_option_cache (&dp, &tp, tp.options, op);
if (dp.len > 0) if (dp.len > 0)
tp.packet_type = dp.data [0]; tp.packet_type = dp.data [0];
else else
@@ -779,46 +786,57 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
else else
bootp (&tp); bootp (&tp);
option_state_dereference (&tp.options); option_state_dereference (&tp.options, "do_packet");
} }
int dhcp_option_lookup (result, options, code) int hashed_option_get (result, universe, options, code)
struct data_string *result; struct data_string *result;
struct universe *universe;
struct option_state *options; struct option_state *options;
int code; int code;
{ {
struct option_cache *oc; struct option_cache *oc;
if (!(oc = lookup_option (options -> dhcp_hash, code))) if (!universe -> lookup_func)
return 0;
oc = ((*universe -> lookup_func)
(universe, options -> universes [universe -> index], code));
if (!oc)
return 0; return 0;
if (!evaluate_option_cache (result, (struct packet *)0, options, oc)) if (!evaluate_option_cache (result, (struct packet *)0, options, oc))
return 0; return 0;
return 1; return 1;
} }
int agent_suboption_lookup (result, options, code) int agent_option_get (result, universe, options, code)
struct data_string *result; struct data_string *result;
struct universe *universe;
struct option_state *options; struct option_state *options;
int code; int code;
{ {
struct agent_options *ao; struct agent_options *ao;
struct option_tag *t; struct option_tag *t;
/* Make sure there's agent option state. */
if (universe -> index >= options -> universe_count ||
!(options -> universes [universe -> index]))
return 0;
ao = (struct agent_options *)options -> universes [universe -> index];
/* Find the last set of agent options and consider it definitive. */ /* Find the last set of agent options and consider it definitive. */
for (ao = options -> agent_options; ao -> next; ao = ao -> next) for (; ao -> next; ao = ao -> next)
; ;
if (ao) { if (ao) {
for (t = ao -> first; t; t = t -> next) { for (t = ao -> first; t; t = t -> next) {
if (t -> data [0] == code) { if (t -> data [0] == code) {
result -> len = t -> data [1]; result -> len = t -> data [1];
if (!buffer_allocate (&result -> buffer, if (!(buffer_allocate
result -> len + 1, (&result -> buffer, result -> len + 1,
"agent_suboption_lookup" "agent_suboption_get"))) {
)) {
result -> len = 0; result -> len = 0;
buffer_dereference buffer_dereference
(&result -> buffer, (&result -> buffer,
"agent_suboption_lookup"); "agent_suboption_get");
return 0; return 0;
} }
result -> data = &result -> buffer -> data [0]; result -> data = &result -> buffer -> data [0];
@@ -833,34 +851,9 @@ int agent_suboption_lookup (result, options, code)
return 0; return 0;
} }
int server_option_lookup (result, options, code) void hashed_option_set (universe, options, option, op)
struct data_string *result; struct universe *universe;
struct option_state *options; struct option_state *options;
int code;
{
return 0;
}
void dhcp_option_set (options, option, op)
struct option_state *options;
struct option_cache *option;
enum statement_op op;
{
struct option_cache *thecache;
do_option_set (options -> dhcp_hash, option, op);
}
void server_option_set (options, option, op)
struct option_state *options;
struct option_cache *option;
enum statement_op op;
{
do_option_set (options -> server_hash, option, op);
}
static void do_option_set (hash, option, op)
pair *hash;
struct option_cache *option; struct option_cache *option;
enum statement_op op; enum statement_op op;
{ {
@@ -876,22 +869,24 @@ static void do_option_set (hash, option, op)
break; break;
case default_option_statement: case default_option_statement:
oc = lookup_option (hash, option -> option -> code); oc = lookup_option (universe, options,
option -> option -> code);
if (oc) if (oc)
break; break;
save_option (hash, option); save_option (universe, options, option);
break; break;
case supersede_option_statement: case supersede_option_statement:
/* Install the option, replacing any existing version. */ /* Install the option, replacing any existing version. */
save_option (hash, option); save_option (universe, options, option);
break; break;
case append_option_statement: case append_option_statement:
case prepend_option_statement: case prepend_option_statement:
oc = lookup_option (hash, option -> option -> code); oc = lookup_option (universe, options,
option -> option -> code);
if (!oc) { if (!oc) {
save_option (hash, option); save_option (universe, options, option);
break; break;
} }
/* If it's not an expression, make it into one. */ /* If it's not an expression, make it into one. */
@@ -928,18 +923,40 @@ static void do_option_set (hash, option, op)
} }
} }
noc -> option = oc -> option; noc -> option = oc -> option;
save_option (hash, noc); save_option (universe, options, noc);
option_cache_dereference (&noc, "do_option_set"); option_cache_dereference (&noc, "do_option_set");
break; break;
} }
} }
struct option_cache *lookup_option (hash, code) struct option_cache *lookup_option (universe, options, code)
pair *hash; struct universe *universe;
struct option_state *options;
int code;
{
if (universe -> lookup_func)
return (*universe -> lookup_func) (universe, options, code);
else
log_error ("can't look up options in %s space.",
universe -> name);
return (struct option_cache *)0;
}
struct option_cache *lookup_hashed_option (universe, options, code)
struct universe *universe;
struct option_state *options;
int code; int code;
{ {
int hashix; int hashix;
pair bptr; pair bptr;
pair *hash;
/* Make sure there's a hash table. */
if (universe -> index >= options -> universe_count ||
!(options -> universes [universe -> index]))
return (struct option_cache *)0;
hash = options -> universes [universe -> index];
hashix = ((code & 31) + ((code >> 5) & 31)) % 17; hashix = ((code & 31) + ((code >> 5) & 31)) % 17;
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) { for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
@@ -950,49 +967,101 @@ struct option_cache *lookup_option (hash, code)
return (struct option_cache *)0; return (struct option_cache *)0;
} }
void save_option (hash, oc) void save_option (universe, options, oc)
pair *hash; struct universe *universe;
struct option_state *options;
struct option_cache *oc;
{
if (universe -> save_func)
(*universe -> save_func) (universe, options, oc);
else
log_error ("can't store options in %s space.",
universe -> name);
}
void save_hashed_option (universe, options, oc)
struct universe *universe;
struct option_state *options;
struct option_cache *oc; struct option_cache *oc;
{ {
int hashix; int hashix;
pair bptr; pair bptr;
pair *hash = options -> universes [universe -> index];
/* Try to find an existing option matching the new one. */ /* Compute the hash. */
hashix = ((oc -> option -> code & 31) + hashix = ((oc -> option -> code & 31) +
((oc -> option -> code >> 5) & 31)) % 17; ((oc -> option -> code >> 5) & 31)) % 17;
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
if (((struct option_cache *)(bptr -> car)) -> option -> code ==
oc -> option -> code)
break;
}
/* If we find one, dereference it and put the new one in its place. */ /* If there's no hash table, make one. */
if (bptr) { if (!hash) {
option_cache_dereference ((struct option_cache **)&bptr -> car, hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash,
"save_option"); "save_hashed_options");
option_cache_reference ((struct option_cache **)&bptr -> car, if (!hash) {
oc, "save_option"); log_error ("no memory to store %s.%s",
} else { universe -> name, oc -> option -> name);
/* Otherwise, just put the new one at the head of the list. */ return;
bptr = new_pair ("save_option"); }
if (!bptr) { memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
log_error ("No memory for option_cache reference."); options -> universes [universe -> index] = (VOIDPTR)hash;
} else {
/* Try to find an existing option matching the new one. */
for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
if (((struct option_cache *)
(bptr -> car)) -> option -> code ==
oc -> option -> code)
break;
}
/* If we find one, dereference it and put the new one
in its place. */
if (bptr) {
option_cache_dereference
((struct option_cache **)&bptr -> car,
"save_option");
option_cache_reference
((struct option_cache **)&bptr -> car,
oc, "save_option");
return; return;
} }
bptr -> cdr = hash [hashix];
bptr -> car = 0;
option_cache_reference ((struct option_cache **)&bptr -> car,
oc, "save_option");
hash [hashix] = bptr;
} }
/* Otherwise, just put the new one at the head of the list. */
bptr = new_pair ("save_option");
if (!bptr) {
log_error ("No memory for option_cache reference.");
return;
}
bptr -> cdr = hash [hashix];
bptr -> car = 0;
option_cache_reference ((struct option_cache **)&bptr -> car,
oc, "save_option");
hash [hashix] = bptr;
} }
void delete_option (hash, code) void delete_option (universe, options, code)
pair *hash; struct universe *universe;
struct option_state *options;
int code;
{
if (universe -> delete_func)
(*universe -> delete_func) (universe, options, code);
else
log_error ("can't delete options from %s space.",
universe -> name);
}
void delete_hashed_option (universe, options, code)
struct universe *universe;
struct option_state *options;
int code; int code;
{ {
int hashix; int hashix;
pair bptr, prev = (pair)0; pair bptr, prev = (pair)0;
pair *hash = options -> universes [universe -> index];
/* There may not be any options in this space. */
if (!hash)
return;
/* Try to find an existing option matching the new one. */ /* Try to find an existing option matching the new one. */
hashix = ((code & 31) + hashix = ((code & 31) +
@@ -1023,7 +1092,8 @@ int option_cache_dereference (ptr, name)
char *name; char *name;
{ {
if (!ptr || !*ptr) { if (!ptr || !*ptr) {
log_error ("Null pointer in option_cache_dereference: %s", name); log_error ("Null pointer in option_cache_dereference: %s",
name);
abort (); abort ();
} }
@@ -1041,3 +1111,150 @@ int option_cache_dereference (ptr, name)
return 1; return 1;
} }
int hashed_option_state_dereference (universe, state)
struct universe *universe;
struct option_state *state;
{
pair *heads;
pair cp, next;
int i;
/* Get the pointer to the array of hash table bucket heads. */
heads = (pair *)(state -> universes [universe -> index]);
if (!heads)
return 0;
/* For each non-null head, loop through all the buckets dereferencing
the attached option cache structures and freeing the buckets. */
for (i = 0; i < OPTION_HASH_SIZE; i++) {
for (cp = heads [i]; cp; cp = next) {
next = cp -> cdr;
option_cache_dereference
((struct option_cache **)&cp -> car,
"option_state_dereference");
free_pair (cp, "hashed_option_state_dereference");
}
}
dfree (heads, "hashed_option_state_dereference");
state -> universes [universe -> index] = (void *)0;
return 1;
}
int agent_option_state_dereference (universe, state)
struct universe *universe;
struct option_state *state;
{
struct agent_options *a, *na;
struct option_tag *ot, *not;
if (universe -> index >= state -> universe_count ||
!state -> universes [universe -> index])
return 0;
/* We can also release the agent options, if any... */
for (a = (struct agent_options *)(state -> universes
[universe -> index]); a; a = na) {
na = a -> next;
for (ot = a -> first; ot; ot = not) {
not = ot -> next;
free (ot);
}
}
dfree (state -> universes [universe -> index],
"agent_option_state_dereference");
state -> universes [universe -> index] = (void *)0;
return 1;
}
int store_option (result, universe, oc)
struct data_string *result;
struct universe *universe;
struct option_cache *oc;
{
struct data_string d1, d2;
memset (&d1, 0, sizeof d1);
memset (&d2, 0, sizeof d2);
if (evaluate_option_cache (&d2, (struct packet *)0,
(struct option_state *)0, oc)) {
if (!buffer_allocate (&d1.buffer,
(result -> len +
universe -> length_size +
universe -> tag_size +
d2.len), "store_option")) {
data_string_forget (result, "store_option");
data_string_forget (&d2, "store_option");
return 0;
}
d1.data = &d1.buffer -> data [0];
if (result -> len)
memcpy (d1.data, result -> data, result -> len);
d1.len = result -> len;
(*universe -> store_tag) (&d1.data [d1.len],
oc -> option -> code);
d1.len += universe -> tag_size;
(*universe -> store_length) (&d1.data [d1.len], d2.len);
d1.len += universe -> length_size;
memcpy (&d1.data [d1.len], d2.data, d2.len);
d1.len += d2.len;
data_string_forget (&d2, "store_option");
data_string_forget (result, "store_option");
data_string_copy (result, &d1, "store_option");
data_string_forget (&d1, "store_option");
return 1;
}
return 0;
}
int option_space_encapsulate (result, options, name)
struct data_string *result;
struct option_state *options;
struct data_string *name;
{
struct universe *u;
u = (struct universe *)hash_lookup (&universe_hash,
name -> data, name -> len);
if (!u) {
log_error ("unknown option space %s.", name -> data);
return 0;
}
if (u -> encapsulate)
return (*u -> encapsulate) (result, options, u);
log_error ("encapsulation requested for %s with no support.",
name -> data);
return 0;
}
int hashed_option_space_encapsulate (result, options, universe)
struct data_string *result;
struct option_state *options;
struct universe *universe;
{
pair p, *hash;
int status;
int i;
if (universe -> index >= options -> universe_count)
return 0;
hash = options -> universes [universe -> index];
if (!hash)
return 0;
status = 0;
for (i = 0; i < OPTION_HASH_SIZE; i++) {
for (p = hash [i]; p; p = p -> cdr) {
if (store_option (result, universe,
(struct option_cache *)p -> car))
status = 1;
}
}
return status;
}