static struct arg_type_info * parse_lens(struct protolib *plib, struct locus *loc, char **str, struct param **extra_param, size_t param_num, int *ownp, int *forwardp) { int own_lens; struct lens *lens = name2lens(str, &own_lens); int has_args = 1; struct arg_type_info *info; if (lens != NULL) { eat_spaces(str); /* Octal lens gets special treatment, because of * backward compatibility. */ if (lens == &octal_lens && **str != '(') { has_args = 0; info = type_get_simple(ARGTYPE_INT); *ownp = 0; } else if (parse_char(loc, str, '(') < 0) { report_error(loc->filename, loc->line_no, "expected type argument after the lens"); return NULL; } } if (has_args) { eat_spaces(str); info = parse_type(plib, loc, str, extra_param, param_num, ownp, forwardp); if (info == NULL) { fail: if (own_lens && lens != NULL) lens_destroy(lens); return NULL; } } if (lens != NULL && has_args) { eat_spaces(str); parse_char(loc, str, ')'); } /* We can't modify shared types. Make a copy if we have a * lens. */ if (lens != NULL && unshare_type_info(loc, &info, ownp) < 0) goto fail; if (lens != NULL) { info->lens = lens; info->own_lens = own_lens; } return info; }
static struct arg_type_info * get_hidden_int(void) { static struct arg_type_info info, *pinfo = NULL; if (pinfo != NULL) return pinfo; info = *type_get_simple(ARGTYPE_INT); info.lens = &blind_lens; pinfo = &info; return pinfo; }
static struct arg_type_info * get_unknown_type(void) { static struct arg_type_info *ret = NULL; if (ret != NULL) return ret; static struct arg_type_info info; info = *type_get_simple(ARGTYPE_LONG); info.lens = &guess_lens; ret = &info; return ret; }
static int zero_callback_max(struct value *ret_value, struct value *lhs, struct value_dict *arguments, size_t max, void *data) { size_t i; for (i = 0; i < max; ++i) { struct value element; if (value_init_element(&element, lhs, i) < 0) return -1; int zero = value_is_zero(&element, arguments); value_destroy(&element); if (zero) break; } struct arg_type_info *long_type = type_get_simple(ARGTYPE_LONG); value_init_detached(ret_value, NULL, long_type, 0); value_set_word(ret_value, i); return 0; }
static struct arg_type_info * parse_nonpointer_type(struct protolib *plib, struct locus *loc, char **str, struct param **extra_param, size_t param_num, int *ownp, int *forwardp) { const char *orig_str = *str; enum arg_type type; if (parse_arg_type(str, &type) < 0) { struct arg_type_info *type; if (parse_alias(plib, loc, str, &type, ownp, extra_param, param_num) < 0) return NULL; else if (type != NULL) return type; *ownp = 0; if ((type = parse_typedef_name(plib, str)) == NULL) report_error(loc->filename, loc->line_no, "unknown type around '%s'", orig_str); return type; } /* For some types that's all we need. */ switch (type) { case ARGTYPE_VOID: case ARGTYPE_INT: case ARGTYPE_UINT: case ARGTYPE_LONG: case ARGTYPE_ULONG: case ARGTYPE_CHAR: case ARGTYPE_SHORT: case ARGTYPE_USHORT: case ARGTYPE_FLOAT: case ARGTYPE_DOUBLE: *ownp = 0; return type_get_simple(type); case ARGTYPE_ARRAY: case ARGTYPE_STRUCT: break; case ARGTYPE_POINTER: /* Pointer syntax is not based on keyword, so we * should never get this type. */ assert(type != ARGTYPE_POINTER); abort(); } struct arg_type_info *info = malloc(sizeof(*info)); if (info == NULL) { report_error(loc->filename, loc->line_no, "malloc: %s", strerror(errno)); return NULL; } *ownp = 1; if (type == ARGTYPE_ARRAY) { if (parse_array(plib, loc, str, info) < 0) { fail: free(info); return NULL; } } else { assert(type == ARGTYPE_STRUCT); if (parse_struct(plib, loc, str, info, forwardp) < 0) goto fail; } return info; }
/* Syntax: * enum (keyname[=value],keyname[=value],... ) * enum<type> (keyname[=value],keyname[=value],... ) */ static int parse_enum(struct protolib *plib, struct locus *loc, char **str, struct arg_type_info **retp, int *ownp) { /* Optional type argument. */ eat_spaces(str); if (**str == '[') { parse_char(loc, str, '['); eat_spaces(str); *retp = parse_nonpointer_type(plib, loc, str, NULL, 0, ownp, 0); if (*retp == NULL) return -1; if (!type_is_integral((*retp)->type)) { report_error(loc->filename, loc->line_no, "integral type required as enum argument"); fail: if (*ownp) { /* This also releases associated lens * if any was set so far. */ type_destroy(*retp); free(*retp); } return -1; } eat_spaces(str); if (parse_char(loc, str, ']') < 0) goto fail; } else { *retp = type_get_simple(ARGTYPE_INT); *ownp = 0; } /* We'll need to set the lens, so unshare. */ if (unshare_type_info(loc, retp, ownp) < 0) goto fail; eat_spaces(str); if (parse_char(loc, str, '(') < 0) goto fail; struct enum_lens *lens = malloc(sizeof(*lens)); if (lens == NULL) { report_error(loc->filename, loc->line_no, "malloc enum lens: %s", strerror(errno)); return -1; } lens_init_enum(lens); (*retp)->lens = &lens->super; (*retp)->own_lens = 1; long last_val = 0; while (1) { eat_spaces(str); if (**str == 0 || **str == ')') { parse_char(loc, str, ')'); return 0; } /* Field delimiter. XXX should we support the C * syntax, where the enumeration can end in pending * comma? */ if (lens_enum_size(lens) > 0) parse_char(loc, str, ','); eat_spaces(str); char *key = parse_ident(loc, str); if (key == NULL) { err: free(key); goto fail; } if (**str == '=') { ++*str; eat_spaces(str); if (parse_int(loc, str, &last_val) < 0) goto err; } struct value *value = malloc(sizeof(*value)); if (value == NULL) goto err; value_init_detached(value, NULL, *retp, 0); value_set_word(value, last_val); if (lens_enum_add(lens, key, 1, value, 1) < 0) goto err; last_val++; } return 0; }
static int parse_string(struct protolib *plib, struct locus *loc, char **str, struct arg_type_info **retp, int *ownp) { struct arg_type_info *info = NULL; struct expr_node *length; int own_length; if (isdigit(CTYPE_CONV(**str))) { /* string0 is string[retval], length is zero(retval) * stringN is string[argN], length is zero(argN) */ long l; if (parse_int(loc, str, &l) < 0 || check_int(loc, l) < 0) return -1; struct expr_node *length_arg = malloc(sizeof(*length_arg)); if (length_arg == NULL) return -1; if (l == 0) expr_init_named(length_arg, "retval", 0); else expr_init_argno(length_arg, l - 1); length = build_zero_w_arg(length_arg, 1); if (length == NULL) { expr_destroy(length_arg); free(length_arg); return -1; } own_length = 1; } else { eat_spaces(str); if (**str == '[') { (*str)++; eat_spaces(str); length = parse_argnum(loc, str, &own_length, 1); if (length == NULL) return -1; eat_spaces(str); parse_char(loc, str, ']'); } else if (**str == '(') { /* Usage of "string" as lens. */ ++*str; eat_spaces(str); info = parse_type(plib, loc, str, NULL, 0, ownp, NULL); if (info == NULL) return -1; length = NULL; own_length = 0; eat_spaces(str); parse_char(loc, str, ')'); } else { /* It was just a simple string after all. */ length = expr_node_zero(); own_length = 0; } } /* String is a pointer to array of chars. */ if (info == NULL) { struct arg_type_info *info1 = malloc(sizeof(*info1)); struct arg_type_info *info2 = malloc(sizeof(*info2)); if (info1 == NULL || info2 == NULL) { free(info1); free(info2); fail: if (own_length) { assert(length != NULL); expr_destroy(length); free(length); } return -1; } type_init_array(info2, type_get_simple(ARGTYPE_CHAR), 0, length, own_length); type_init_pointer(info1, info2, 1); info = info1; *ownp = 1; } /* We'll need to set the lens, so unshare. */ if (unshare_type_info(loc, &info, ownp) < 0) /* If unshare_type_info failed, it must have been as a * result of cloning attempt because *OWNP was 0. * Thus we don't need to destroy INFO. */ goto fail; info->lens = &string_lens; info->own_lens = 0; *retp = info; return 0; }
/* * Input: * argN : The value of argument #N, counting from 1 * eltN : The value of element #N of the containing structure * retval : The return value * N : The numeric value N */ static struct expr_node * parse_argnum(struct locus *loc, char **str, int *ownp, int zero) { struct expr_node *expr = malloc(sizeof(*expr)); if (expr == NULL) return NULL; if (isdigit(CTYPE_CONV(**str))) { long l; if (parse_int(loc, str, &l) < 0 || check_nonnegative(loc, l) < 0 || check_int(loc, l) < 0) goto fail; expr_init_const_word(expr, l, type_get_simple(ARGTYPE_LONG), 0); if (zero && wrap_in_zero(&expr) < 0) goto fail; *ownp = 1; return expr; } else { char *const name = parse_ident(loc, str); if (name == NULL) { fail_ident: free(name); goto fail; } int is_arg = strncmp(name, "arg", 3) == 0; if (is_arg || strncmp(name, "elt", 3) == 0) { long l; char *num = name + 3; if (parse_int(loc, &num, &l) < 0 || check_int(loc, l) < 0) goto fail_ident; if (is_arg) { if (l == 0) expr_init_named(expr, "retval", 0); else expr_init_argno(expr, l - 1); } else { struct expr_node *e_up = malloc(sizeof(*e_up)); struct expr_node *e_ix = malloc(sizeof(*e_ix)); if (e_up == NULL || e_ix == NULL) { free(e_up); free(e_ix); goto fail_ident; } expr_init_up(e_up, expr_self(), 0); struct arg_type_info *ti = type_get_simple(ARGTYPE_LONG); expr_init_const_word(e_ix, l - 1, ti, 0); expr_init_index(expr, e_up, 1, e_ix, 1); } } else if (strcmp(name, "retval") == 0) { expr_init_named(expr, "retval", 0); } else if (strcmp(name, "zero") == 0) { struct expr_node *ret = parse_zero(loc, str, ownp); if (ret == NULL) goto fail_ident; free(expr); free(name); return ret; } else { report_error(loc->filename, loc->line_no, "Unknown length specifier: '%s'", name); goto fail_ident; } if (zero && wrap_in_zero(&expr) < 0) goto fail_ident; free(name); *ownp = 1; return expr; } fail: free(expr); return NULL; }