diff options
author | Ted Lemon <source@isc.org> | 1999-03-25 21:59:36 +0000 |
---|---|---|
committer | Ted Lemon <source@isc.org> | 1999-03-25 21:59:36 +0000 |
commit | 6b4b0ec78df4172af74fcc99c45aaff961e7d22d (patch) | |
tree | 4e2a54195ee44679f64ad0dff89e4ec48ce6e0b3 | |
parent | ef1f37ed63e584b910646fd0270c365351198e8b (diff) | |
download | isc-dhcp-6b4b0ec78df4172af74fcc99c45aaff961e7d22d.tar.gz |
Support defining new option code names and formats.
-rw-r--r-- | common/parse.c | 272 |
1 files changed, 251 insertions, 21 deletions
diff --git a/common/parse.c b/common/parse.c index 6bf7030b..619d630e 100644 --- a/common/parse.c +++ b/common/parse.c @@ -22,7 +22,7 @@ #ifndef lint static char copyright[] = -"$Id: parse.c,v 1.17 1999/03/16 06:37:49 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; +"$Id: parse.c,v 1.18 1999/03/25 21:59:36 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -700,12 +700,13 @@ TIME parse_date (cfile) IDENTIFIER . IDENTIFIER */ -struct option *parse_option_name (cfile) +struct option *parse_option_name (cfile, allocate) FILE *cfile; + int allocate; { char *val; enum dhcp_token token; - char *vendor; + char *uname; struct universe *universe; struct option *option; @@ -716,10 +717,10 @@ struct option *parse_option_name (cfile) skip_to_semi (cfile); return (struct option *)0; } - vendor = malloc (strlen (val) + 1); - if (!vendor) - log_fatal ("no memory for vendor information."); - strcpy (vendor, val); + uname = malloc (strlen (val) + 1); + if (!uname) + log_fatal ("no memory for uname information."); + strcpy (uname, val); token = peek_token (&val, cfile); if (token == DOT) { /* Go ahead and take the DOT token... */ @@ -735,21 +736,21 @@ struct option *parse_option_name (cfile) } /* Look up the option name hash table for the specified - vendor. */ + uname. */ universe = ((struct universe *) hash_lookup (&universe_hash, - (unsigned char *)vendor, 0)); + (unsigned char *)uname, 0)); /* If it's not there, we can't parse the rest of the declaration. */ if (!universe) { - parse_warn ("no vendor named %s.", vendor); + parse_warn ("no option space named %s.", uname); skip_to_semi (cfile); return (struct option *)0; } } else { /* Use the default hash table, which contains all the standard dhcp option names. */ - val = vendor; + val = uname; universe = &dhcp_universe; } @@ -759,20 +760,249 @@ struct option *parse_option_name (cfile) /* If we didn't get an option structure, it's an undefined option. */ if (!option) { - if (val == vendor) + /* If we've been told to allocate, that means that this + (might) be an option code definition, so we'll create + an option structure just in case. */ + if (allocate) { + option = new_option ("parse_option_name"); + if (val == uname) + option -> name = val; + else { + free (uname); + option -> name = dmalloc (strlen (val) + 1, + "parse_option_name"); + if (!option -> name) + log_fatal ("no memory for option %s.%s", + universe -> name, val); + strcpy (option -> name, val); + } + option -> universe = universe; + option -> code = -1; + return option; + } + if (val == uname) parse_warn ("no option named %s", val); else - parse_warn ("no option named %s for vendor %s", - val, vendor); + parse_warn ("no option named %s in space %s", + val, uname); skip_to_semi (cfile); return (struct option *)0; } /* Free the initial identifier token. */ - free (vendor); + free (uname); return option; } +/* This is faked up to look good right now. Ideally, this should do a + recursive parse and allow arbitrary data structure definitions, but for + now it just allows you to specify a single type, an array of single types, + a sequence of types, or an array of sequences of types. + + ocd :== NUMBER EQUALS ocsd SEMI + + ocsd :== ocsd_type | + ocsd_type_sequence | + ARRAY OF ocsd_type | + ARRAY OF ocsd_type_sequence + + ocsd_type :== BOOLEAN | + INTEGER NUMBER | + SIGNED INTEGER NUMBER | + UNSIGNED INTEGER NUMBER | + IP-ADDRESS | + TEXT | + STRING + + ocsd_type_sequence :== LBRACE ocsd_types RBRACE + + ocsd_type :== ocsd_type | + ocsd_types ocsd_type */ + +int parse_option_code_definition (cfile, option) + FILE *cfile; + struct option *option; +{ + char *val; + enum dhcp_token token; + int arrayp = 0; + int recordp = 0; + int no_more_in_record = 0; + char tokbuf [128]; + int tokix = 0; + char type; + int code; + int is_signed; + + /* Parse the option code. */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("expecting option code number."); + skip_to_semi (cfile); + return 0; + } + option -> code = atoi (val); + + token = next_token (&val, cfile); + if (token != EQUAL) { + parse_warn ("expecting \"=\""); + skip_to_semi (cfile); + return 0; + } + + /* See if this is an array. */ + token = next_token (&val, cfile); + if (token == ARRAY) { + token = next_token (&val, cfile); + if (token != OF) { + parse_warn ("expecting \"of\"."); + skip_to_semi (cfile); + return 0; + } + arrayp = 1; + token = next_token (&val, cfile); + } + + if (token == LBRACE) { + recordp = 1; + token = next_token (&val, cfile); + } + + /* At this point we're expecting a data type. */ + next_type: + switch (token) { + case BOOLEAN: + type = 'f'; + break; + case INTEGER: + is_signed = 1; + parse_integer: + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("expecting number."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + switch (atoi (val)) { + case 8: + type = is_signed ? 'b' : 'B'; + break; + case 16: + type = is_signed ? 's' : 'S'; + break; + case 32: + type = is_signed ? 'l' : 'L'; + break; + default: + parse_warn ("%s bit precision is not supported.", val); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + break; + case SIGNED: + is_signed = 1; + parse_signed: + token = next_token (&val, cfile); + if (token != INTEGER) { + parse_warn ("expecting \"integer\" keyword."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + goto parse_integer; + case UNSIGNED: + is_signed = 0; + goto parse_signed; + + case IP_ADDRESS: + type = 'I'; + break; + case TEXT: + type = 't'; + no_arrays: + if (arrayp) { + parse_warn ("arrays of text strings not %s", + "yet supported."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + no_more_in_record = 1; + break; + case STRING: + type = 'X'; + goto no_arrays; + + default: + parse_warn ("unknown data type %s", val); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + + if (tokix == sizeof tokbuf) { + parse_warn ("too many types in record."); + skip_to_rbrace (cfile, recordp); + if (recordp) + skip_to_semi (cfile); + return 0; + } + tokbuf [tokix++] = type; + + if (recordp) { + token = next_token (&val, cfile); + if (token == COMMA) { + if (no_more_in_record) { + parse_warn ("%s must be at end of record.", + type == 't' ? "text" : "string"); + skip_to_rbrace (cfile, 1); + if (recordp) + skip_to_semi (cfile); + return 0; + } + token = next_token (&val, cfile); + goto next_type; + } + if (token != RBRACE) { + parse_warn ("expecting right brace."); + skip_to_rbrace (cfile, 1); + if (recordp) + skip_to_semi (cfile); + return 0; + } + } + if (!parse_semi (cfile)) { + parse_warn ("semicolon expected."); + skip_to_semi (cfile); + if (recordp) + skip_to_semi (cfile); + return 0; + } + option -> format = dmalloc (tokix + arrayp + 1, + "parse_option_code_definition"); + if (!option -> format) + log_fatal ("no memory for option format."); + memcpy (option -> format, tokbuf, tokix); + if (arrayp) + option -> format [tokix++] = 'A'; + option -> format [tokix] = 0; + if (option -> universe -> options [option -> code]) { + /* XXX Free the option, but we can't do that now because they + XXX may start out static. */ + } + option -> universe -> options [option -> code] = option; + add_hash (option -> universe -> hash, + (unsigned char *)option -> name, 0, (unsigned char *)option); + return 1; +} + /* * colon-seperated-hex-list :== NUMBER | * NUMBER COLON colon-seperated-hex-list @@ -929,7 +1159,7 @@ struct executable_statement *parse_executable_statement (cfile, lose) case SUPERSEDE: case OPTION: token = next_token (&val, cfile); - option = parse_option_name (cfile); + option = parse_option_name (cfile, 0); if (!option) { *lose = 1; return (struct executable_statement *)0; @@ -939,7 +1169,7 @@ struct executable_statement *parse_executable_statement (cfile, lose) case DEFAULT: token = next_token (&val, cfile); - option = parse_option_name (cfile); + option = parse_option_name (cfile, 0); if (!option) { *lose = 1; return (struct executable_statement *)0; @@ -949,7 +1179,7 @@ struct executable_statement *parse_executable_statement (cfile, lose) case PREPEND: token = next_token (&val, cfile); - option = parse_option_name (cfile); + option = parse_option_name (cfile, 0); if (!option) { *lose = 1; return (struct executable_statement *)0; @@ -959,7 +1189,7 @@ struct executable_statement *parse_executable_statement (cfile, lose) case APPEND: token = next_token (&val, cfile); - option = parse_option_name (cfile); + option = parse_option_name (cfile, 0); if (!option) { *lose = 1; return (struct executable_statement *)0; @@ -1225,7 +1455,7 @@ int parse_non_binary (expr, cfile, lose, context) if (!expression_allocate (expr, "parse_expression: EXISTS")) log_fatal ("can't allocate expression"); (*expr) -> op = expr_exists; - (*expr) -> data.option = parse_option_name (cfile); + (*expr) -> data.option = parse_option_name (cfile, 0); if (!(*expr) -> data.option) { *lose = 1; expression_dereference (expr, @@ -1336,7 +1566,7 @@ int parse_non_binary (expr, cfile, lose, context) if (!expression_allocate (expr, "parse_expression: OPTION")) log_fatal ("can't allocate expression"); (*expr) -> op = expr_option; - (*expr) -> data.option = parse_option_name (cfile); + (*expr) -> data.option = parse_option_name (cfile, 0); if (!(*expr) -> data.option) { *lose = 1; expression_dereference (expr, |