diff options
author | Michael Brown | 2013-08-01 15:39:58 +0200 |
---|---|---|
committer | Michael Brown | 2013-08-01 15:39:58 +0200 |
commit | c70d4cb1b39eae7b026d34575431fe8a54c65998 (patch) | |
tree | d7105390abdf7e2ba972c5f0c21aa4a63ef3f42b | |
parent | [script] Allow commands following a script label (diff) | |
download | ipxe-c70d4cb1b39eae7b026d34575431fe8a54c65998.tar.gz ipxe-c70d4cb1b39eae7b026d34575431fe8a54c65998.tar.xz ipxe-c70d4cb1b39eae7b026d34575431fe8a54c65998.zip |
[settings] Introduce the generalised concept of a numeric setting
Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r-- | src/arch/i386/interface/vmware/guestinfo.c | 2 | ||||
-rw-r--r-- | src/core/settings.c | 587 | ||||
-rw-r--r-- | src/include/ipxe/settings.h | 45 | ||||
-rw-r--r-- | src/tests/settings_test.c | 91 |
4 files changed, 542 insertions, 183 deletions
diff --git a/src/arch/i386/interface/vmware/guestinfo.c b/src/arch/i386/interface/vmware/guestinfo.c index 8ce363aa..7fa41b86 100644 --- a/src/arch/i386/interface/vmware/guestinfo.c +++ b/src/arch/i386/interface/vmware/guestinfo.c @@ -114,7 +114,7 @@ static int guestinfo_fetch_type ( struct settings *settings, settings, &command[9] /* Skip "info-get " */, info ); /* Parse GuestInfo value according to type */ - ret = type->parse ( info, data, len ); + ret = setting_parse ( type, info, data, len ); if ( ret < 0 ) { DBGC ( settings, "GuestInfo %p could not parse \"%s\" as %s: " "%s\n", settings, info, type->name, strerror ( ret ) ); diff --git a/src/core/settings.c b/src/core/settings.c index 76d7f6a6..889e1078 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -850,15 +850,14 @@ int fetch_ipv4_setting ( struct settings *settings, struct setting *setting, /** * Extract numeric value of setting * + * @v is_signed Treat value as a signed integer * @v raw Raw setting data * @v len Length of raw setting data - * @ret signed_value Value, when interpreted as a signed integer - * @ret unsigned_value Value, when interpreted as an unsigned integer + * @ret value Numeric value * @ret len Length of setting, or negative error */ -static int numeric_setting_value ( const void *raw, size_t len, - signed long *signed_value, - unsigned long *unsigned_value ) { +static int numeric_setting_value ( int is_signed, const void *raw, size_t len, + unsigned long *value ) { const uint8_t *unsigned_bytes = raw; const int8_t *signed_bytes = raw; int is_negative; @@ -871,29 +870,26 @@ static int numeric_setting_value ( const void *raw, size_t len, /* Convert to host-ordered longs */ is_negative = ( len && ( signed_bytes[0] < 0 ) ); - *signed_value = ( is_negative ? -1L : 0 ); - *unsigned_value = 0; + *value = ( ( is_signed && is_negative ) ? -1L : 0 ); for ( i = 0 ; i < len ; i++ ) { byte = unsigned_bytes[i]; - *signed_value = ( ( *signed_value << 8 ) | byte ); - *unsigned_value = ( ( *unsigned_value << 8 ) | byte ); + *value = ( ( *value << 8 ) | byte ); } return len; } /** - * Fetch value of signed integer setting + * Fetch value of numeric setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch * @v value Integer value to fill in * @ret len Length of setting, or negative error */ -int fetch_int_setting ( struct settings *settings, struct setting *setting, - long *value ) { - unsigned long dummy; - long tmp; +int fetch_numeric_setting ( struct settings *settings, struct setting *setting, + unsigned long *value, int is_signed ) { + unsigned long tmp; int len; /* Avoid returning uninitialised data on error */ @@ -905,7 +901,22 @@ int fetch_int_setting ( struct settings *settings, struct setting *setting, return len; /* Extract numeric value */ - return numeric_setting_value ( &tmp, len, value, &dummy ); + return numeric_setting_value ( is_signed, &tmp, len, value ); +} + +/** + * Fetch value of signed integer setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v value Integer value to fill in + * @ret len Length of setting, or negative error + */ +int fetch_int_setting ( struct settings *settings, struct setting *setting, + long *value ) { + + return fetch_numeric_setting ( settings, setting, + ( ( unsigned long * ) value ), 1 ); } /** @@ -918,20 +929,8 @@ int fetch_int_setting ( struct settings *settings, struct setting *setting, */ int fetch_uint_setting ( struct settings *settings, struct setting *setting, unsigned long *value ) { - signed long dummy; - long tmp; - int len; - /* Avoid returning uninitialised data on error */ - *value = 0; - - /* Fetch raw (network-ordered, variable-length) setting */ - len = fetch_setting ( settings, setting, &tmp, sizeof ( tmp ) ); - if ( len < 0 ) - return len; - - /* Extract numeric value */ - return numeric_setting_value ( &tmp, len, &dummy, value ); + return fetch_numeric_setting ( settings, setting, value, 0 ); } /** @@ -942,9 +941,9 @@ int fetch_uint_setting ( struct settings *settings, struct setting *setting, * @ret value Setting value, or zero */ long fetch_intz_setting ( struct settings *settings, struct setting *setting ){ - long value; + unsigned long value; - fetch_int_setting ( settings, setting, &value ); + fetch_numeric_setting ( settings, setting, &value, 1 ); return value; } @@ -959,7 +958,7 @@ unsigned long fetch_uintz_setting ( struct settings *settings, struct setting *setting ) { unsigned long value; - fetch_uint_setting ( settings, setting, &value ); + fetch_numeric_setting ( settings, setting, &value, 0 ); return value; } @@ -1028,11 +1027,87 @@ int setting_cmp ( struct setting *a, struct setting *b ) { */ /** + * Format setting value as a string + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +int setting_format ( struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ) { + + /* Sanity check */ + if ( ! type->format ) + return -ENOTSUP; + + return type->format ( type, raw, raw_len, buf, len ); +} + +/** + * Parse formatted string to setting value + * + * @v type Setting type + * @v value Formatted setting value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ +int setting_parse ( struct setting_type *type, const char *value, + void *buf, size_t len ) { + + /* Sanity check */ + if ( ! type->parse ) + return -ENOTSUP; + + return type->parse ( type, value, buf, len ); +} + +/** + * Convert setting value to number + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @ret value Numeric value + * @ret rc Return status code + */ +int setting_numerate ( struct setting_type *type, const void *raw, + size_t raw_len, unsigned long *value ) { + + /* Sanity check */ + if ( ! type->numerate ) + return -ENOTSUP; + + return type->numerate ( type, raw, raw_len, value ); +} + +/** + * Convert number to setting value + * + * @v type Setting type + * @v value Numeric value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ +int setting_denumerate ( struct setting_type *type, unsigned long value, + void *buf, size_t len ) { + + /* Sanity check */ + if ( ! type->denumerate ) + return -ENOTSUP; + + return type->denumerate ( type, value, buf, len ); +} + +/** * Fetch formatted value of setting * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch - * @v type Settings type * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error @@ -1052,10 +1127,10 @@ int fetchf_setting ( struct settings *settings, struct setting *setting, /* Sanity check */ assert ( setting->type != NULL ); - assert ( setting->type->format != NULL ); /* Format setting */ - if ( ( ret = setting->type->format ( raw, raw_len, buf, len ) ) < 0 ) + if ( ( ret = setting_format ( setting->type, raw, raw_len, buf, + len ) ) < 0 ) goto err_format; err_format: @@ -1069,7 +1144,6 @@ int fetchf_setting ( struct settings *settings, struct setting *setting, * * @v settings Settings block, or NULL to search all blocks * @v setting Setting to fetch - * @v type Settings type * @v value Buffer to allocate and fill with formatted value * @ret len Length of formatted value, or negative error * @@ -1122,13 +1196,12 @@ int storef_setting ( struct settings *settings, struct setting *setting, /* Sanity check */ assert ( setting->type != NULL ); - assert ( setting->type->parse != NULL ); /* Get raw value length */ - raw_len = setting->type->parse ( value, NULL, 0 ); + raw_len = setting_parse ( setting->type, value, NULL, 0 ); if ( raw_len < 0 ) { rc = raw_len; - goto err_parse_len; + goto err_raw_len; } /* Allocate buffer for raw value */ @@ -1139,7 +1212,89 @@ int storef_setting ( struct settings *settings, struct setting *setting, } /* Parse formatted value */ - check_len = setting->type->parse ( value, raw, raw_len ); + check_len = setting_parse ( setting->type, value, raw, raw_len ); + assert ( check_len == raw_len ); + + /* Store raw value */ + if ( ( rc = store_setting ( settings, setting, raw, raw_len ) ) != 0 ) + goto err_store; + + err_store: + free ( raw ); + err_alloc_raw: + err_raw_len: + return rc; +} + +/** + * Fetch numeric value of setting + * + * @v settings Settings block, or NULL to search all blocks + * @v setting Setting to fetch + * @v value Numeric value to fill in + * @ret rc Return status code + */ +int fetchn_setting ( struct settings *settings, struct setting *setting, + unsigned long *value ) { + void *raw; + int raw_len; + int rc; + + /* Fetch raw value */ + raw_len = fetch_setting_copy ( settings, setting, &raw ); + if ( raw_len < 0 ) { + rc = raw_len; + goto err_fetch_copy; + } + + /* Sanity check */ + assert ( setting->type != NULL ); + + /* Numerate setting */ + if ( ( rc = setting_numerate ( setting->type, raw, raw_len, + value ) ) < 0 ) + goto err_numerate; + + err_numerate: + free ( raw ); + err_fetch_copy: + return rc; +} + +/** + * Store numeric value of setting + * + * @v settings Settings block + * @v setting Setting + * @v value Numeric value + * @ret rc Return status code + */ +int storen_setting ( struct settings *settings, struct setting *setting, + unsigned long value ) { + void *raw; + int raw_len; + int check_len; + int rc; + + /* Sanity check */ + assert ( setting->type != NULL ); + + /* Get raw value length */ + raw_len = setting_denumerate ( setting->type, value, NULL, 0 ); + if ( raw_len < 0 ) { + rc = raw_len; + goto err_raw_len; + } + + /* Allocate buffer for raw value */ + raw = malloc ( raw_len ); + if ( ! raw ) { + rc = -ENOMEM; + goto err_alloc_raw; + } + + /* Denumerate value */ + check_len = setting_denumerate ( setting->type, value, raw, raw_len ); assert ( check_len == raw_len ); /* Store raw value */ @@ -1149,7 +1304,7 @@ int storef_setting ( struct settings *settings, struct setting *setting, err_store: free ( raw ); err_alloc_raw: - err_parse_len: + err_raw_len: return rc; } @@ -1326,12 +1481,14 @@ int setting_name ( struct settings *settings, struct setting *setting, /** * Parse string setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ -static int parse_string_setting ( const char *value, void *buf, size_t len ) { +static int parse_string_setting ( struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { size_t raw_len = strlen ( value ); /* Exclude terminating NUL */ /* Copy string to buffer */ @@ -1345,13 +1502,15 @@ static int parse_string_setting ( const char *value, void *buf, size_t len ) { /** * Format string setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_string_setting ( const void *raw, size_t raw_len, char *buf, +static int format_string_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { /* Copy string to buffer, and terminate */ @@ -1373,13 +1532,14 @@ struct setting_type setting_type_string __setting_type = { /** * Parse URI-encoded string setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ -static int parse_uristring_setting ( const char *value, void *buf, - size_t len ) { +static int parse_uristring_setting ( struct setting_type *type __unused, + const char *value, void *buf, size_t len ){ char tmp[ len + 1 /* NUL */ ]; size_t raw_len; @@ -1397,13 +1557,15 @@ static int parse_uristring_setting ( const char *value, void *buf, /** * Format URI-encoded string setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_uristring_setting ( const void *raw, size_t raw_len, +static int format_uristring_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { char tmp[ raw_len + 1 /* NUL */ ]; @@ -1425,12 +1587,14 @@ struct setting_type setting_type_uristring __setting_type = { /** * Parse IPv4 address setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ -static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) { +static int parse_ipv4_setting ( struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { struct in_addr ipv4; /* Parse IPv4 address */ @@ -1448,13 +1612,15 @@ static int parse_ipv4_setting ( const char *value, void *buf, size_t len ) { /** * Format IPv4 address setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_ipv4_setting ( const void *raw, size_t raw_len, char *buf, +static int format_ipv4_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { const struct in_addr *ipv4 = raw; @@ -1471,28 +1637,100 @@ struct setting_type setting_type_ipv4 __setting_type = { }; /** - * Parse integer setting value + * Integer setting type indices * - * @v value Formatted setting value + * These indexes are defined such that (1<<index) gives the width of + * the integer, in bytes. + */ +enum setting_type_int_index { + SETTING_TYPE_INT8 = 0, + SETTING_TYPE_INT16 = 1, + SETTING_TYPE_INT32 = 2, +}; + +/** + * Integer setting type names + * + * These names exist as a static array in order to allow the type's + * integer size and signedness to be determined from the type's name. + * Note that there are no separate entries for the signed integer + * types: the name pointers simply point to the second character of + * the relevant string. + */ +static const char setting_type_int_name[][8] = { + [SETTING_TYPE_INT8] = "uint8", + [SETTING_TYPE_INT16] = "uint16", + [SETTING_TYPE_INT32] = "uint32", +}; + +/** + * Get unsigned integer setting type name + * + * @v index Integer setting type index + * @ret name Setting type name + */ +#define SETTING_TYPE_UINT_NAME( index ) setting_type_int_name[index] + +/** + * Get signed integer setting type name + * + * @v index Integer setting type index + * @ret name Setting type name + */ +#define SETTING_TYPE_INT_NAME( index ) ( setting_type_int_name[index] + 1 ) + +/** + * Get integer setting type index + * + * @v type Setting type + * @ret index Integer setting type index + */ +static unsigned int setting_type_int_index ( struct setting_type *type ) { + + return ( ( type->name - setting_type_int_name[0] ) / + sizeof ( setting_type_int_name[0] ) ); +} + +/** + * Get integer setting type width + * + * @v type Setting type + * @ret index Integer setting type width + */ +static unsigned int setting_type_int_width ( struct setting_type *type ) { + + return ( 1 << setting_type_int_index ( type ) ); +} + +/** + * Get integer setting type signedness + * + * @v type Setting type + * @ret is_signed Integer setting type is signed + */ +static int setting_type_int_is_signed ( struct setting_type *type ) { + return ( ( type->name - setting_type_int_name[0] ) & 1 ); +} + +/** + * Convert number to setting value + * + * @v type Setting type + * @v value Numeric value * @v buf Buffer to contain raw value * @v len Length of buffer - * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_int_setting ( const char *value, void *buf, size_t len, - unsigned int size ) { +static int denumerate_int_setting ( struct setting_type *type, + unsigned long value, void *buf, + size_t len ) { + unsigned int size = setting_type_int_width ( type ); union { uint32_t num; uint8_t bytes[4]; } u; - char *endp; - - /* Parse value */ - u.num = htonl ( strtoul ( value, &endp, 0 ) ); - if ( *endp ) - return -EINVAL; - /* Copy to buffer */ + u.num = htonl ( value ); if ( len > size ) len = size; memcpy ( buf, &u.bytes[ sizeof ( u ) - size ], len ); @@ -1501,64 +1739,69 @@ static int parse_int_setting ( const char *value, void *buf, size_t len, } /** - * Parse 8-bit integer setting value + * Convert setting value to number * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @v size Integer size, in bytes - * @ret len Length of raw value, or negative error + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v value Numeric value to fill in + * @ret rc Return status code */ -static int parse_int8_setting ( const char *value, void *buf, size_t len ) { - return parse_int_setting ( value, buf, len, sizeof ( uint8_t ) ); -} +static int numerate_int_setting ( struct setting_type *type, + const void *raw, size_t raw_len, + unsigned long *value ) { + int is_signed = setting_type_int_is_signed ( type ); + int check_len; -/** - * Parse 16-bit integer setting value - * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @v size Integer size, in bytes - * @ret len Length of raw value, or negative error - */ -static int parse_int16_setting ( const char *value, void *buf, size_t len ) { - return parse_int_setting ( value, buf, len, sizeof ( uint16_t ) ); + /* Extract numeric value */ + check_len = numeric_setting_value ( is_signed, raw, raw_len, value ); + if ( check_len < 0 ) + return check_len; + assert ( check_len == ( int ) raw_len ); + + return 0; } /** - * Parse 32-bit integer setting value + * Parse integer setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer - * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_int32_setting ( const char *value, void *buf, size_t len ) { - return parse_int_setting ( value, buf, len, sizeof ( uint32_t ) ); +static int parse_int_setting ( struct setting_type *type, const char *value, + void *buf, size_t len ) { + char *endp; + unsigned long num_value; + + /* Parse value */ + num_value = strtoul ( value, &endp, 0 ); + if ( *endp ) + return -EINVAL; + + return type->denumerate ( type, num_value, buf, len ); } /** * Format signed integer setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_int_setting ( const void *raw, size_t raw_len, char *buf, - size_t len ) { - signed long value; - unsigned long dummy; - int check_len; +static int format_int_setting ( struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ) { + unsigned long value; + int ret; /* Extract numeric value */ - check_len = numeric_setting_value ( raw, raw_len, &value, &dummy ); - if ( check_len < 0 ) - return check_len; - assert ( check_len == ( int ) raw_len ); + if ( ( ret = type->numerate ( type, raw, raw_len, &value ) ) < 0 ) + return ret; /* Format value */ return snprintf ( buf, len, "%ld", value ); @@ -1567,82 +1810,90 @@ static int format_int_setting ( const void *raw, size_t raw_len, char *buf, /** * Format unsigned integer setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_uint_setting ( const void *raw, size_t raw_len, char *buf, - size_t len ) { - signed long dummy; +static int format_uint_setting ( struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ) { unsigned long value; - int check_len; + int ret; /* Extract numeric value */ - check_len = numeric_setting_value ( raw, raw_len, &dummy, &value ); - if ( check_len < 0 ) - return check_len; - assert ( check_len == ( int ) raw_len ); + if ( ( ret = type->numerate ( type, raw, raw_len, &value ) ) < 0 ) + return ret; /* Format value */ return snprintf ( buf, len, "%#lx", value ); } +/** + * Define a signed integer setting type + * + * @v index Integer setting type index + * @ret type Setting type + */ +#define SETTING_TYPE_INT( index ) { \ + .name = SETTING_TYPE_INT_NAME ( index ), \ + .parse = parse_int_setting, \ + .format = format_int_setting, \ + .denumerate = denumerate_int_setting, \ + .numerate = numerate_int_setting, \ +} + +/** + * Define an unsigned integer setting type + * + * @v index Integer setting type index + * @ret type Setting type + */ +#define SETTING_TYPE_UINT( index ) { \ + .name = SETTING_TYPE_UINT_NAME ( index ), \ + .parse = parse_int_setting, \ + .format = format_uint_setting, \ + .denumerate = denumerate_int_setting, \ + .numerate = numerate_int_setting, \ +} + /** A signed 8-bit integer setting type */ -struct setting_type setting_type_int8 __setting_type = { - .name = "int8", - .parse = parse_int8_setting, - .format = format_int_setting, -}; +struct setting_type setting_type_int8 __setting_type = + SETTING_TYPE_INT ( SETTING_TYPE_INT8 ); /** A signed 16-bit integer setting type */ -struct setting_type setting_type_int16 __setting_type = { - .name = "int16", - .parse = parse_int16_setting, - .format = format_int_setting, -}; +struct setting_type setting_type_int16 __setting_type = + SETTING_TYPE_INT ( SETTING_TYPE_INT16 ); /** A signed 32-bit integer setting type */ -struct setting_type setting_type_int32 __setting_type = { - .name = "int32", - .parse = parse_int32_setting, - .format = format_int_setting, -}; +struct setting_type setting_type_int32 __setting_type = + SETTING_TYPE_INT ( SETTING_TYPE_INT32 ); /** An unsigned 8-bit integer setting type */ -struct setting_type setting_type_uint8 __setting_type = { - .name = "uint8", - .parse = parse_int8_setting, - .format = format_uint_setting, -}; +struct setting_type setting_type_uint8 __setting_type = + SETTING_TYPE_UINT ( SETTING_TYPE_INT8 ); /** An unsigned 16-bit integer setting type */ -struct setting_type setting_type_uint16 __setting_type = { - .name = "uint16", - .parse = parse_int16_setting, - .format = format_uint_setting, -}; +struct setting_type setting_type_uint16 __setting_type = + SETTING_TYPE_UINT ( SETTING_TYPE_INT16 ); /** An unsigned 32-bit integer setting type */ -struct setting_type setting_type_uint32 __setting_type = { - .name = "uint32", - .parse = parse_int32_setting, - .format = format_uint_setting, -}; +struct setting_type setting_type_uint32 __setting_type = + SETTING_TYPE_UINT ( SETTING_TYPE_INT32 ); /** * Format hex string setting value * + * @v delimiter Byte delimiter * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer - * @v delimiter Byte delimiter * @ret len Length of formatted value, or negative error */ -static int format_hex_setting ( const void *raw, size_t raw_len, char *buf, - size_t len, const char *delimiter ) { +static int format_hex_setting ( const char *delimiter, const void *raw, + size_t raw_len, char *buf, size_t len ) { const uint8_t *bytes = raw; int used = 0; unsigned int i; @@ -1660,40 +1911,46 @@ static int format_hex_setting ( const void *raw, size_t raw_len, char *buf, /** * Parse hex string setting value (using colon delimiter) * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_hex_setting ( const char *value, void *buf, size_t len ) { +static int parse_hex_setting ( struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { return hex_decode ( value, ':', buf, len ); } /** * Format hex string setting value (using colon delimiter) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_hex_colon_setting ( const void *raw, size_t raw_len, +static int format_hex_colon_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { - return format_hex_setting ( raw, raw_len, buf, len, ":" ); + return format_hex_setting ( ":", raw, raw_len, buf, len ); } /** * Parse hex string setting value (using hyphen delimiter) * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_hex_hyphen_setting ( const char *value, void *buf, +static int parse_hex_hyphen_setting ( struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { return hex_decode ( value, '-', buf, len ); } @@ -1701,43 +1958,48 @@ static int parse_hex_hyphen_setting ( const char *value, void *buf, /** * Format hex string setting value (using hyphen delimiter) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_hex_hyphen_setting ( const void *raw, size_t raw_len, +static int format_hex_hyphen_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { - return format_hex_setting ( raw, raw_len, buf, len, "-" ); + return format_hex_setting ( "-", raw, raw_len, buf, len ); } /** * Parse hex string setting value (using no delimiter) * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @v size Integer size, in bytes * @ret len Length of raw value, or negative error */ -static int parse_hex_raw_setting ( const char *value, void *buf, - size_t len ) { +static int parse_hex_raw_setting ( struct setting_type *type __unused, + const char *value, void *buf, size_t len ) { return hex_decode ( value, 0, buf, len ); } /** * Format hex string setting value (using no delimiter) * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_hex_raw_setting ( const void *raw, size_t raw_len, +static int format_hex_raw_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { - return format_hex_setting ( raw, raw_len, buf, len, "" ); + return format_hex_setting ( "", raw, raw_len, buf, len ); } /** A hex-string setting (colon-delimited) */ @@ -1762,28 +2024,17 @@ struct setting_type setting_type_hexraw __setting_type = { }; /** - * Parse UUID setting value - * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @ret len Length of raw value, or negative error - */ -static int parse_uuid_setting ( const char *value __unused, - void *buf __unused, size_t len __unused ) { - return -ENOTSUP; -} - -/** * Format UUID setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf, +static int format_uuid_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { const union uuid *uuid = raw; @@ -1798,40 +2049,27 @@ static int format_uuid_setting ( const void *raw, size_t raw_len, char *buf, /** UUID setting type */ struct setting_type setting_type_uuid __setting_type = { .name = "uuid", - .parse = parse_uuid_setting, .format = format_uuid_setting, }; /** - * Parse PCI bus:dev.fn setting value - * - * @v value Formatted setting value - * @v buf Buffer to contain raw value - * @v len Length of buffer - * @ret len Length of raw value, or negative error - */ -static int parse_busdevfn_setting ( const char *value __unused, - void *buf __unused, size_t len __unused ) { - return -ENOTSUP; -} - -/** * Format PCI bus:dev.fn setting value * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ -static int format_busdevfn_setting ( const void *raw, size_t raw_len, char *buf, +static int format_busdevfn_setting ( struct setting_type *type __unused, + const void *raw, size_t raw_len, char *buf, size_t len ) { - signed long dummy; unsigned long busdevfn; int check_len; /* Extract numeric value */ - check_len = numeric_setting_value ( raw, raw_len, &dummy, &busdevfn ); + check_len = numeric_setting_value ( 0, raw, raw_len, &busdevfn ); if ( check_len < 0 ) return check_len; assert ( check_len == ( int ) raw_len ); @@ -1844,7 +2082,6 @@ static int format_busdevfn_setting ( const void *raw, size_t raw_len, char *buf, /** PCI bus:dev.fn setting type */ struct setting_type setting_type_busdevfn __setting_type = { .name = "busdevfn", - .parse = parse_busdevfn_setting, .format = format_busdevfn_setting, }; diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index c7287ebb..d1666e1d 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -185,24 +185,47 @@ struct setting_type { * This is the name exposed to the user (e.g. "string"). */ const char *name; - /** Parse formatted setting value + /** Parse formatted string to setting value * + * @v type Setting type * @v value Formatted setting value * @v buf Buffer to contain raw value * @v len Length of buffer * @ret len Length of raw value, or negative error */ - int ( * parse ) ( const char *value, void *buf, size_t len ); - /** Format setting value + int ( * parse ) ( struct setting_type *type, const char *value, + void *buf, size_t len ); + /** Format setting value as a string * + * @v type Setting type * @v raw Raw setting value * @v raw_len Length of raw setting value * @v buf Buffer to contain formatted value * @v len Length of buffer * @ret len Length of formatted value, or negative error */ - int ( * format ) ( const void *raw, size_t raw_len, char *buf, - size_t len ); + int ( * format ) ( struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ); + /** Convert number to setting value + * + * @v type Setting type + * @v value Numeric value + * @v buf Buffer to contain raw value + * @v len Length of buffer + * @ret len Length of raw value, or negative error + */ + int ( * denumerate ) ( struct setting_type *type, unsigned long value, + void *buf, size_t len ); + /** Convert setting value to number + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v value Numeric value to fill in + * @ret rc Return status code + */ + int ( * numerate ) ( struct setting_type *type, const void *raw, + size_t raw_len, unsigned long *value ); }; /** Configuration setting type table */ @@ -308,6 +331,14 @@ extern int parse_setting_name ( char *name, get_child_settings_t get_child, struct setting *setting ); extern int setting_name ( struct settings *settings, struct setting *setting, char *buf, size_t len ); +extern int setting_format ( struct setting_type *type, const void *raw, + size_t raw_len, char *buf, size_t len ); +extern int setting_parse ( struct setting_type *type, const char *value, + void *buf, size_t len ); +extern int setting_numerate ( struct setting_type *type, const void *raw, + size_t raw_len, unsigned long *value ); +extern int setting_denumerate ( struct setting_type *type, unsigned long value, + void *buf, size_t len ); extern int fetchf_setting ( struct settings *settings, struct setting *setting, char *buf, size_t len ); extern int fetchf_setting_copy ( struct settings *settings, @@ -315,6 +346,10 @@ extern int fetchf_setting_copy ( struct settings *settings, extern int storef_setting ( struct settings *settings, struct setting *setting, const char *value ); +extern int fetchn_setting ( struct settings *settings, struct setting *setting, + unsigned long *value ); +extern int storen_setting ( struct settings *settings, struct setting *setting, + unsigned long value ); extern char * expand_settings ( const char *string ); extern struct setting_type setting_type_string __setting_type; diff --git a/src/tests/settings_test.c b/src/tests/settings_test.c index 42957c7d..670d549b 100644 --- a/src/tests/settings_test.c +++ b/src/tests/settings_test.c @@ -82,12 +82,63 @@ FILE_LICENCE ( GPL2_OR_LATER ); len = fetchf_setting ( settings, setting, actual, \ sizeof ( actual ) ); \ DBGC ( settings, "Fetched %s \"%s\" from:\n", \ - (setting)->type->name, formatted ); \ + (setting)->type->name, actual ); \ DBGC_HDA ( settings, 0, raw, sizeof ( raw ) ); \ ok ( len == ( int ) ( sizeof ( actual ) - 1 ) ); \ ok ( strcmp ( actual, formatted ) == 0 ); \ } while ( 0 ) +/** + * Report a numeric-store test result + * + * @v settings Settings block + * @v setting Setting + * @v numeric Numeric value + * @v raw_array Expected raw value + */ +#define storen_ok( settings, setting, numeric, raw_array ) do { \ + const uint8_t expected[] = raw_array; \ + uint8_t actual[ sizeof ( expected ) ]; \ + int len; \ + \ + ok ( storen_setting ( settings, setting, numeric ) == 0 ); \ + len = fetch_setting ( settings, setting, actual, \ + sizeof ( actual ) ); \ + if ( len >= 0 ) { \ + DBGC ( settings, "Stored %s %#lx, got:\n", \ + (setting)->type->name, \ + ( unsigned long ) numeric ); \ + DBGC_HDA ( settings, 0, actual, len ); \ + } else { \ + DBGC ( settings, "Stored %s %#lx, got error %s\n", \ + (setting)->type->name, \ + ( unsigned long ) numeric, strerror ( len ) ); \ + } \ + ok ( len == ( int ) sizeof ( actual ) ); \ + ok ( memcmp ( actual, expected, sizeof ( actual ) ) == 0 ); \ + } while ( 0 ) + +/** + * Report a numeric-fetch test result + * + * @v settings Settings block + * @v setting Setting + * @v raw_array Raw array + * @v numeric Expected numeric value + */ +#define fetchn_ok( settings, setting, raw_array, numeric ) do { \ + const uint8_t raw[] = raw_array; \ + unsigned long actual; \ + \ + ok ( store_setting ( settings, setting, raw, \ + sizeof ( raw ) ) == 0 ); \ + ok ( fetchn_setting ( settings, setting, &actual ) == 0 ); \ + DBGC ( settings, "Fetched %s %#lx from:\n", \ + (setting)->type->name, actual ); \ + DBGC_HDA ( settings, 0, raw, sizeof ( raw ) ); \ + ok ( actual == ( unsigned long ) numeric ); \ + } while ( 0 ) + /** Test generic settings block */ struct generic_settings test_generic_settings = { .settings = { @@ -216,7 +267,7 @@ static void settings_test_exec ( void ) { fetchf_ok ( &test_settings, &test_ipv4_setting, RAW ( 212, 13, 204, 60 ), "212.13.204.60" ); - /* Integer setting types */ + /* Integer setting types (as formatted strings) */ storef_ok ( &test_settings, &test_int8_setting, "54", RAW ( 54 ) ); storef_ok ( &test_settings, &test_int8_setting, @@ -256,6 +307,42 @@ static void settings_test_exec ( void ) { fetchf_ok ( &test_settings, &test_uint32_setting, RAW ( 0xf2, 0x37, 0xb2, 0x18 ), "0xf237b218" ); + /* Integer setting types (as numeric values) */ + storen_ok ( &test_settings, &test_int8_setting, + 72, RAW ( 72 ) ); + storen_ok ( &test_settings, &test_int8_setting, + 0xabcd, RAW ( 0xcd ) ); + fetchn_ok ( &test_settings, &test_int8_setting, + RAW ( 0xfe ), -2 ); + storen_ok ( &test_settings, &test_uint8_setting, + 84, RAW ( 84 ) ); + fetchn_ok ( &test_settings, &test_uint8_setting, + RAW ( 0xfe ), 0xfe ); + storen_ok ( &test_settings, &test_int16_setting, + 0x87bd, RAW ( 0x87, 0xbd ) ); + fetchn_ok ( &test_settings, &test_int16_setting, + RAW ( 0x3d, 0x14 ), 0x3d14 ); + fetchn_ok ( &test_settings, &test_int16_setting, + RAW ( 0x80 ), -128 ); + storen_ok ( &test_settings, &test_uint16_setting, + 1, RAW ( 0x00, 0x01 ) ); + fetchn_ok ( &test_settings, &test_uint16_setting, + RAW ( 0xbd, 0x87 ), 0xbd87 ); + fetchn_ok ( &test_settings, &test_uint16_setting, + RAW ( 0x80 ), 0x0080 ); + storen_ok ( &test_settings, &test_int32_setting, + 0x0812bfd2, RAW ( 0x08, 0x12, 0xbf, 0xd2 ) ); + fetchn_ok ( &test_settings, &test_int32_setting, + RAW ( 0x43, 0x87, 0x91, 0xb4 ), 0x438791b4 ); + fetchn_ok ( &test_settings, &test_int32_setting, + RAW ( 0xff, 0xff, 0xfe ), -2 ); + storen_ok ( &test_settings, &test_uint32_setting, + 0xb5927ab8, RAW ( 0xb5, 0x92, 0x7a, 0xb8 ) ); + fetchn_ok ( &test_settings, &test_uint32_setting, + RAW ( 0x98, 0xab, 0x41, 0x81 ), 0x98ab4181 ); + fetchn_ok ( &test_settings, &test_uint32_setting, + RAW ( 0xff, 0xff, 0xfe ), 0x00fffffe ); + /* "hex" setting type */ storef_ok ( &test_settings, &test_hex_setting, "08:12:f5:22:90:1b:4b:47:a8:30:cb:4d:67:4c:d6:76", |