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;
}
Beispiel #4
0
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;
}